Merge remote-tracking branch 'origin/develop' into internal-testing-build

This commit is contained in:
Le Duc Anh
2025-12-17 15:51:49 +07:00
43 changed files with 3269004 additions and 773 deletions
@@ -15,6 +15,11 @@ MonoBehaviour:
m_GroupName: Default Local Group
m_GUID: 712e3991f28e549e7a56ee582a977810
m_SerializeEntries:
- m_GUID: 1b653230886be4009808803501ad7d7f
m_Address: Assets/PerfectWorld/SO/TaskTemplContainerSO.asset
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 1cfde61ea9d19614a8ea91cb1eeca97b
m_Address: "\u7A0B\u5E8F\u8054\u5165/\u89D2\u8272\u51FA\u73B0\u4EBA\u7C7B.gfx"
m_ReadOnly: 0
@@ -3308,6 +3308,7 @@ MonoBehaviour:
- {fileID: 7400000, guid: d3c1bf1bc3105b247aae16f9c99519ea, type: 2}
- {fileID: 7400000, guid: b9c1b4aacfc88174f9bfcb8bf1c69eb5, type: 2}
- {fileID: 7400000, guid: d54a450816dbc4d4ca43afbe607052ad, type: 2}
- {fileID: 7400000, guid: cbff0726770bb1146bc70346d5fc38f9, type: 2}
--- !u!1 &2587141697474146175
GameObject:
m_ObjectHideFlags: 0
+238 -105
View File
@@ -31,9 +31,9 @@ RectTransform:
- {fileID: 7068400949313321131}
m_Father: {fileID: 1982628982857606432}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 119.34445, y: -50.05}
m_SizeDelta: {x: 238.6889, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &567730479829113918
@@ -1063,9 +1063,9 @@ RectTransform:
- {fileID: 1673093633596208253}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 744.2305, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5696506275770781555
@@ -1782,9 +1782,9 @@ RectTransform:
- {fileID: 3173262022725656255}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 533.7858, y: -474.8956}
m_SizeDelta: {x: 1067.5717, y: 53.7328}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4979397800331147640
@@ -1832,9 +1832,9 @@ RectTransform:
- {fileID: 5159105777246515782}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 552.95, y: -697.9664}
m_SizeDelta: {x: 1105.9, y: 100.1}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &3682686733385602497
@@ -2616,9 +2616,9 @@ RectTransform:
- {fileID: 9038859519033147586}
m_Father: {fileID: 3413131598704007284}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 160, y: -27.7372}
m_SizeDelta: {x: 320, y: 55.4744}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &3633225552368495711
@@ -2786,9 +2786,9 @@ RectTransform:
- {fileID: 6888331463719618182}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 533.8, y: -181.5047}
m_SizeDelta: {x: 1067.6, y: 147.0112}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7637574953150164924
@@ -2992,9 +2992,9 @@ RectTransform:
- {fileID: 466166190548844919}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 533.7858, y: -287.3301}
m_SizeDelta: {x: 1067.5717, y: 64.6396}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5725159945352370057
@@ -3035,9 +3035,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 50, y: -17.98135}
m_SizeDelta: {x: 100, y: 35.9627}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &2640258873449426733
@@ -3495,9 +3495,9 @@ RectTransform:
- {fileID: 1664656494516247222}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 533.7858, y: -97.82885}
m_SizeDelta: {x: 1067.5717, y: 20.3405}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5366537333355115835
@@ -3540,9 +3540,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 5935924508566653103}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 59.9817, y: -31.017}
m_SizeDelta: {x: 119.9634, y: 62.034}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8442116720262994404
@@ -3988,7 +3988,7 @@ RectTransform:
m_Father: {fileID: 7958847946112668032}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@@ -4289,9 +4289,9 @@ RectTransform:
- {fileID: 5935924508566653103}
m_Father: {fileID: 1982628982857606432}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 981.0654, y: -50.05}
m_SizeDelta: {x: 249.67, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3615902548841175383
@@ -4365,9 +4365,9 @@ RectTransform:
- {fileID: 6664836867558571240}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 632.0412, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1719403314563710437
@@ -4441,9 +4441,9 @@ RectTransform:
- {fileID: 3123454216176481580}
m_Father: {fileID: 1982628982857606432}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 390.45966, y: -50.05}
m_SizeDelta: {x: 103.5415, y: 42.7938}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &6244284104014817409
@@ -4529,9 +4529,9 @@ RectTransform:
- {fileID: 4269318562826283412}
m_Father: {fileID: 3413131598704007284}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 160, y: -392.4044}
m_SizeDelta: {x: 320, y: 673.86}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6982899544592245397
@@ -4635,6 +4635,7 @@ RectTransform:
- {fileID: 1687288316189840478}
- {fileID: 3413131598704007284}
- {fileID: 1802319080125745111}
- {fileID: 8560871508586000967}
m_Father: {fileID: 9127077926286418868}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
@@ -4713,9 +4714,9 @@ RectTransform:
- {fileID: 2490029976799717816}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 295.47327, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7650172129678423862
@@ -4791,9 +4792,9 @@ RectTransform:
m_Father: {fileID: 2214759022841903186}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: -17, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &4662246788448476486
CanvasRenderer:
@@ -4882,7 +4883,7 @@ RectTransform:
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: 0.000024855137}
m_SizeDelta: {x: 1067.6, y: 0}
m_SizeDelta: {x: 1067.6, y: 44.66}
m_Pivot: {x: 0, y: 1}
--- !u!222 &8527806716735377849
CanvasRenderer:
@@ -4997,6 +4998,138 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_HorizontalFit: 0
m_VerticalFit: 2
--- !u!1 &5079467856058945530
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8560871508586000967}
- component: {fileID: 4358218663584653282}
- component: {fileID: 2639378489502838745}
- component: {fileID: 7962930401627561727}
m_Layer: 5
m_Name: Button
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8560871508586000967
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5079467856058945530}
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: 945666739613519770}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -62, y: -72}
m_SizeDelta: {x: 58, y: 58}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4358218663584653282
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5079467856058945530}
m_CullTransparentMesh: 1
--- !u!114 &2639378489502838745
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5079467856058945530}
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: fb2f2f58be45f6e4890e85cc00b0bcc9, 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 &7962930401627561727
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5079467856058945530}
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: 2639378489502838745}
m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 6999114045547682248}
m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine
m_MethodName: SetActive
m_Mode: 6
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
--- !u!1 &5087525444877170506
GameObject:
m_ObjectHideFlags: 0
@@ -5030,9 +5163,9 @@ RectTransform:
- {fileID: 7337732696262196210}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 183.28395, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &665161835172153120
@@ -5105,9 +5238,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 1982628982857606432}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 288.6889, y: -50.05}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1142619112158729952
@@ -5242,9 +5375,9 @@ RectTransform:
- {fileID: 464210832437986234}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 71.09465, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6131836957139812833
@@ -5353,9 +5486,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 150, y: -61.81065}
m_SizeDelta: {x: 300, y: 51.6959}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4239296098804493253
@@ -5490,9 +5623,9 @@ RectTransform:
- {fileID: 9160025208612689927}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 856.41986, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4153770864616565637
@@ -5567,9 +5700,9 @@ RectTransform:
- {fileID: 3906960815437350628}
m_Father: {fileID: 8174585228173147249}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 241.1868, y: -31.18805}
m_SizeDelta: {x: 170.7912, y: 62.3761}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7438076119085514817
@@ -5686,9 +5819,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 7068400949313321131}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 76, y: -31.75005}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2800332942966355020
@@ -6308,9 +6441,9 @@ RectTransform:
m_Father: {fileID: 3760164886363293420}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: -17, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &5693552902337398956
CanvasRenderer:
@@ -6483,8 +6616,8 @@ MonoBehaviour:
m_TargetGraphic: {fileID: 7392889747821849613}
m_HandleRect: {fileID: 2343337405992641122}
m_Direction: 2
m_Value: 0
m_Size: 0.9999435
m_Value: 1
m_Size: 0.9999888
m_NumberOfSteps: 0
m_OnValueChanged:
m_PersistentCalls:
@@ -6524,9 +6657,9 @@ RectTransform:
m_Father: {fileID: 8611061134879146475}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_SizeDelta: {x: -17, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!222 &1301146549737279854
CanvasRenderer:
@@ -6739,9 +6872,9 @@ RectTransform:
- {fileID: 3960419512253178154}
m_Father: {fileID: 1982628982857606432}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 752.7304, y: -50.05}
m_SizeDelta: {x: 207, y: 77}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5922293013674383484
@@ -6858,8 +6991,8 @@ RectTransform:
m_Children: []
m_Father: {fileID: 5233116975597807035}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 0.000011205673}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@@ -6934,7 +7067,7 @@ RectTransform:
m_Father: {fileID: 2825219564319673376}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 20, y: 20}
m_Pivot: {x: 0.5, y: 0.5}
@@ -7249,7 +7382,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
m_IsActive: 0
--- !u!224 &5506476487848131018
RectTransform:
m_ObjectHideFlags: 0
@@ -7344,9 +7477,9 @@ RectTransform:
- {fileID: 8526229293534627480}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 552.95, y: -574.8392}
m_SizeDelta: {x: 1105.9, y: 146.1544}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &7362516739390317868
@@ -7383,9 +7516,9 @@ RectTransform:
- {fileID: 8359974748112151041}
m_Father: {fileID: 1982628982857606432}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 545.7304, y: -50.05}
m_SizeDelta: {x: 207, y: 77}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &175839448811631403
@@ -7704,9 +7837,9 @@ RectTransform:
- {fileID: 3546830409645517734}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 519.85187, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7535806629134762549
@@ -7782,9 +7915,9 @@ RectTransform:
- {fileID: 3450901294667678815}
m_Father: {fileID: 1802319080125745111}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 533.8, y: -383.83954}
m_SizeDelta: {x: 1067.6, y: 128.3793}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5632580526749397436
@@ -7888,9 +8021,9 @@ RectTransform:
- {fileID: 6076870470824675401}
m_Father: {fileID: 6556814518920652147}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 407.66254, y: -49.72705}
m_SizeDelta: {x: 72.1893, y: 73.4541}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &5385847170717247365
@@ -8040,9 +8173,9 @@ RectTransform:
- {fileID: 1805980451046698619}
m_Father: {fileID: 8174585228173147249}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 80.3956, y: -31.18805}
m_SizeDelta: {x: 170.7912, y: 62.3761}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8101014133290532655
@@ -8234,9 +8367,9 @@ RectTransform:
m_Children: []
m_Father: {fileID: 5935924508566653103}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 155.6889, y: -31.017}
m_SizeDelta: {x: 71.451, y: 62.034}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1158119712588225859
@@ -8731,7 +8864,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 8395333742829132721, guid: 9456de25596014039bd4d0d3927b709a, type: 3}
propertyPath: m_AnchoredPosition.y
value: 336.93
value: 336.92987
objectReference: {fileID: 0}
- target: {fileID: 8395333742829132721, guid: 9456de25596014039bd4d0d3927b709a, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -0,0 +1,272 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &6426564401230013186
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3325367652782365102}
- component: {fileID: 6868997766477093256}
- component: {fileID: 2867419621240194058}
m_Layer: 5
m_Name: Text (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3325367652782365102
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426564401230013186}
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: 266017875005995358}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0.9228058, y: 0.69200134}
m_SizeDelta: {x: -78.8826, y: -78.8826}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &6868997766477093256
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426564401230013186}
m_CullTransparentMesh: 1
--- !u!114 &2867419621240194058
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6426564401230013186}
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: JUMP
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4281479730
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 44.7
m_fontSizeBase: 24
m_fontWeight: 400
m_enableAutoSizing: 1
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 &6792439420010771896
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 266017875005995358}
- component: {fileID: 5557092053757495849}
- component: {fileID: 3695308113943472152}
- component: {fileID: 1194531703109065144}
- component: {fileID: 4432331937269434665}
m_Layer: 5
m_Name: JumpBtn
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &266017875005995358
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6792439420010771896}
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: 3325367652782365102}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 0}
m_AnchorMax: {x: 1, y: 0}
m_AnchoredPosition: {x: -61, y: 46}
m_SizeDelta: {x: 200, y: 200}
m_Pivot: {x: 1, y: 0}
--- !u!222 &5557092053757495849
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6792439420010771896}
m_CullTransparentMesh: 1
--- !u!114 &3695308113943472152
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6792439420010771896}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 0
m_PreserveAspect: 1
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1194531703109065144
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6792439420010771896}
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: 3695308113943472152}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &4432331937269434665
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6792439420010771896}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a6149141837cadc4baae427c4864833e, type: 3}
m_Name:
m_EditorClassIdentifier:
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0104938c092195b40ab7f3b6e5bf342e
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -19,7 +19,7 @@ MonoBehaviour:
prefab: {fileID: 8237288432181259026, guid: eaeb778b6aab3d74299373b3a96b72c4, type: 3}
- id: Win_Award
prefab: {fileID: 903595479696773158, guid: cf26d96ae7d984ba8a5b6cef44adffeb, type: 3}
- id: Win_Task
- id: Win_Quest
prefab: {fileID: 6999114045547682248, guid: 8027cada0ef5e4a9f827001b4747174d, type: 3}
- id: Win_SkillSubAction
prefab: {fileID: 111271885693053298, guid: eb88919320b4229459c83b6b1f8f1e7b, type: 3}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5f3d86049520f4217970358d8c6e0fd1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1b653230886be4009808803501ad7d7f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
+1 -1
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e3e518641de396e1b30dd202ff94dc35518476c7efd747501f45f10021136ca7
oid sha256:0930e07b267dc93d54fbc4de6bfaac5a9bf1aa7ea5ff239a58e5a8a7a25cf6c7
size 10723
@@ -10,6 +10,7 @@ namespace BrewMonster.Network
private static int m_AbsTimeStart;
private static int m_iTimeError; // 服务器与本机时间差(秒) // Time error in seconds
private static int m_iTimeZoneBias; // 服务器时区偏移(秒) // Server timezone bias in seconds
private static bool m_bServerTimeInited;
public static int GetTimeZoneBias() { return m_iTimeZoneBias; }
// 设置时间误差 // Set time error
public static void SetServerTime(int iSevTime, int iTimeZoneBias)
@@ -37,11 +38,20 @@ namespace BrewMonster.Network
// 初始化绝对时间参考点 // Initialize absolute time reference
m_AbsTimeStart = iSevTime;
m_AbsTickStart = (uint)(Time.realtimeSinceStartup * 1000.0f);
m_bServerTimeInited = true;
Debug.Log($"timeGetTime(), TickStart = {m_AbsTickStart}");
}
public static int GetServerAbsTime()
{
// Fallback: if server time was never initialized (SetServerTime not called),
// return local unix time seconds so task timestamps (usually epoch seconds) still work.
// This makes wait-time/countdown and timetable logic behave correctly even before server sync.
if (!m_bServerTimeInited || m_AbsTimeStart == 0)
{
return (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds() + m_iTimeError;
}
uint curTick = (uint)(Time.realtimeSinceStartup * 1000.0f);
if (curTick < m_AbsTickStart)
@@ -93,11 +93,11 @@ namespace BrewMonster.Network
m_pElementDataMan = ElementDataManProvider.GetElementDataMan();
#if UNITY_EDITOR
/* if (TaskTest.Instance &&
if (TaskTest.Instance &&
TaskTest.m_pTaskMan != null)
{
m_pTaskMan = TaskTest.m_pTaskMan;
}*/
}
#endif
// Load task templates
if (m_pTaskMan == null) m_pTaskMan = new ATaskTemplMan();
@@ -59,7 +59,7 @@ namespace BrewMonster.Scripts
{
m_iPoseAction = iAction;
m_bSession = bSession;
// m_pHost.PlayAction(m_iPoseAction, false, 300);
m_pHost.PlayAction(m_iPoseAction, true);
if (!bSession && iAction != (int)PLAYER_ACTION_TYPE.ACT_EXP_KISS)
@@ -175,6 +175,11 @@ namespace BrewMonster.Scripts
m_pHost.PlayAction(m_iCurAction, false, 300);
//m_oldAction = m_iCurAction;
}
else
{
// Debug.LogError($"m_iPoseAction == {(PLAYER_ACTION_TYPE)m_iPoseAction}");
m_pHost.PlayAction(m_iPoseAction, false, 300);
}
// Force to update object's direction and up
// m_pHost.m_vecGroundNormal = m_pHost.m_vecGroundNormalSet;
@@ -19,27 +19,7 @@ namespace BrewMonster
}
if (Input.GetKeyDown(KeyCode.Space))
{
//if (bInAutoMode) return;
if (IsJumpInWater() || IsFlying())
return;
if (IsUnderWater())
{
if (!CanTakeOffWater())
return;
else if (_JumpTime <= 0)
{
_JumpTime = Time.realtimeSinceStartup;
return;
}
else if ((Time.realtimeSinceStartup - _JumpTime) < 1f) // logic in c++, _JumpTime is milisecond
return;
else
_JumpTime = -1f;
}
m_GndInfo.bOnGround = GroundCheck(out lastGroundHit);
OnMsgHstJump();
OnClickBtnJump();
}
}
@@ -208,5 +188,29 @@ namespace BrewMonster
PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 0, true);
}
public void OnClickBtnJump()
{
//if (bInAutoMode) return;
if (IsJumpInWater() || IsFlying())
return;
if (IsUnderWater())
{
if (!CanTakeOffWater())
return;
else if (_JumpTime <= 0)
{
_JumpTime = Time.realtimeSinceStartup;
return;
}
else if ((Time.realtimeSinceStartup - _JumpTime) < 1f) // logic in c++, _JumpTime is milisecond
return;
else
_JumpTime = -1f;
}
m_GndInfo.bOnGround = GroundCheck(out lastGroundHit);
OnMsgHstJump();
}
}
}
+63 -95
View File
@@ -101,34 +101,44 @@ namespace BrewMonster
pEnvTrc.fFraction = 100.0f;
pEnvTrc.bStartSolid = false;
pEnvTrc.dwClsFlag = 0;
Vector3 vStart = EC_Utility.ToVector3(pEnvTrc.vStart);
Vector3 vExt = EC_Utility.ToVector3(pEnvTrc.vExt);
Vector3 vDelta = EC_Utility.ToVector3(pEnvTrc.vDelta);
Vector3 vTerStart = EC_Utility.ToVector3(pEnvTrc.vTerStart);
Vector3 dir = Vector3.zero;
if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_BRUSH) == CDR_EVN.CDR_BRUSH)
{
BrushTraceInfo bruInfo = new BrushTraceInfo();
bruInfo.Init(pEnvTrc.vStart, pEnvTrc.vDelta, pEnvTrc.vExt);
if (AABBCollideWithBrush(ref bruInfo))
dir = vStart + vDelta;
if (Physics.BoxCast(vStart, vExt, dir, out RaycastHit hit, Quaternion.identity, vDelta.magnitude, 1 << 7))
{
pEnvTrc.fFraction = bruInfo.fFraction;
pEnvTrc.vHitNormal = bruInfo.ClipPlane.GetNormal();
pEnvTrc.bStartSolid = bruInfo.bStartSolid;
pEnvTrc.fFraction = (hit.distance - vExt.x) / vDelta.magnitude;
pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hit.normal);
pEnvTrc.dwClsFlag = CDR_EVN.CDR_BRUSH;
}
else
{
pEnvTrc.fFraction = 1f;
}
}
if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_TERRAIN) == CDR_EVN.CDR_TERRAIN)
{
float fFraction = 0f;
A3DVECTOR3 vTerNormal = new A3DVECTOR3();
bool bStart = false;
if (CollideWithTerrain(pEnvTrc.vTerStart, pEnvTrc.vDelta, ref fFraction, ref vTerNormal, ref bStart)
&& (fFraction < pEnvTrc.fFraction))
float fFractionTerrain = 0f;
dir = vDelta;
if (Physics.Raycast(vTerStart, dir.normalized, out RaycastHit hit, vDelta.magnitude, 1<<6))
{
//assert(fFraction >= 0.0f);
//pEnvTrc.fFraction = a_Max(0.0f, fFraction - 1E-4f);
pEnvTrc.fFraction = fFraction;
pEnvTrc.vHitNormal = vTerNormal;
pEnvTrc.bStartSolid = bStart;
fFractionTerrain = (hit.distance) / vDelta.magnitude;
pEnvTrc.vHitNormal = EC_Utility.ToA3DVECTOR3(hit.normal);
pEnvTrc.dwClsFlag = CDR_EVN.CDR_TERRAIN;
}
else
{
fFractionTerrain = 1f;
}
if(fFractionTerrain < pEnvTrc.fFraction)
{
pEnvTrc.fFraction = fFractionTerrain;
}
}
if ((pEnvTrc.dwCheckFlag & CDR_EVN.CDR_WATER) == CDR_EVN.CDR_WATER)
@@ -156,46 +166,6 @@ namespace BrewMonster
return (pEnvTrc.fFraction < 1.0f + 1E-4f);
}
// == Thay CollideWithEnv (C++) bằng BoxCast ==
//static bool CollideWithEnv_BoxCast(Vector3 vStart, Vector3 vDelta, Vector3 vExt,
// LayerMask mask,
// out RaycastHit hit, out float fFraction, out Vector3 vHitNormal, out bool bStartSolid,
// float skin = 0.01f)
//{
// hit = default;
// vHitNormal = Vector3.up;
// bStartSolid = false;
// fFraction = 0.0f;
// float dist = vDelta.magnitude;
// if (dist <= 1e-6f) return false;
// var hasHit = Physics.Raycast(vStart, vDelta,out hit, dist, mask);
// if (hasHit)
// {
// bStartSolid = true;
// fFraction = (t - 5E-4f) / vDelta.Normalize();
// return true;
// }
// // start-in-solid
// var overlapped = Physics.OverlapBox(vStart, vExt - Vector3.one * skin, Quaternion.identity, mask, QueryTriggerInteraction.Ignore);
// if (overlapped != null && overlapped.Length > 0)
// {
// bStartSolid = true;
// return true;
// }
// // sweep AABB
// Vector3 dir = vDelta / Mathf.Max(dist, 1e-6f);
// if (Physics.BoxCast(vStart, vExt - Vector3.one * skin, dir, out hit, Quaternion.identity, dist, mask, QueryTriggerInteraction.Ignore))
// {
// fFraction = Mathf.Clamp01(hit.distance / Mathf.Max(dist, 1e-6f));
// vHitNormal = hit.normal;
// return true;
// }
// return false;
//}
// == Thay RetrieveSupportPlane (C++) bằng Raycast xuống ==
static bool DoGroundProbe(Vector3 vStart, Vector3 vExt, float fDeltaY, LayerMask mask,
out Vector3 vEnd, out Vector3 vHitNormal, out bool bSupport,
@@ -280,6 +250,10 @@ namespace BrewMonster
int nTry = 0;
LayerMask mask = UsedMask_Ground();
env_trace_t trcInfo = new env_trace_t();
trcInfo.dwCheckFlag = CDR_EVN.CDR_TERRAIN | CDR_EVN.CDR_BRUSH;
trcInfo.vExt = CDRInfo.vExtent;
while (nTry < 1)
{
vDelta = vVelocity * fTime;
@@ -290,41 +264,33 @@ namespace BrewMonster
//bool hasHit = CollideWithEnv_BoxCast(vStart, vDelta, vExt, mask,
// out RaycastHit hit, out float fFraction, out Vector3 hitNormal, out bool bStartSolid);
Vector3 posFoot = vStart - Vector3.up * vExt.y;
//if (Physics.BoxCast(vStart, vExt, (vStart + Vector3.down).normalized, out RaycastHit hit1, Quaternion.identity, vExt.y, mask))
//{
// if (hit1.point.y > posFoot.y)
// {
// Debug.LogError("hit.point.y > posFoot.y");
// posFoot.y = hit1.point.y;
// }
//}
if (Physics.Raycast(vStart, (vStart + Vector3.down).normalized, out RaycastHit hit1, vExt.y, mask))
if (Physics.Raycast(vStart, (vStart + Vector3.down).normalized, out RaycastHit hit, vExt.y, mask))
{
if (hit1.point.y > posFoot.y)
if (hit.point.y > posFoot.y)
{
posFoot.y = hit1.point.y;
posFoot.y = hit.point.y;
}
}
bool bClear = !Physics.Raycast(posFoot, (posFoot + vDelta).normalized, out RaycastHit hit, fDeltaDist, mask);
bool bClear = !Physics.Raycast(posFoot, (posFoot + vDelta).normalized, out hit, fDeltaDist, mask);
//trcInfo.vStart = CDRInfo.vCenter;
//trcInfo.vDelta = EC_Utility.ToA3DVECTOR3(vDelta);
//trcInfo.vTerStart = EC_Utility.ToA3DVECTOR3(posFoot);
////trcInfo.vTerStart.y -= vExt.y; //foot
//bool bClear = !CollideWithEnv(ref trcInfo);
nTry++;
if (bClear)
{
Debug.DrawLine(posFoot, posFoot + vDelta, Color.yellow, 10f);
//Debug.DrawLine(posFoot, posFoot + vDelta, Color.yellow, 10f);
vFinalPos = vStart + vDelta;
CDRInfo.fMoveDist += fDeltaDist;
break;
}
//if (trcInfo.bStartSolid)
//{
// CDRInfo.fMoveDist = 0f;
// if (CDRInfo.vTPNormal.y < CDRInfo.fSlopeThresh) CDRInfo.vTPNormal = Vector3.up;
// return;
//}
vStart = hit.point + Vector3.up * vExt.y;
//vStart += vDelta * trcInfo.fFraction + Vector3.up * vExt.y;
vFinalPos = vStart;
//CDRInfo.fMoveDist += (fDeltaDist * fFraction);
//fTime -= fTime * fFraction;
//vNormal = hitNormal;
// Step-up (giữ tinh thần bản gốc)
if (!bFreeFall && !bTryPull && !bJump)
@@ -332,36 +298,38 @@ namespace BrewMonster
//float skin = 0.01f;
posFoot = vStart - Vector3.up * vExt.y + Vector3.up * CDRInfo.fStepHeight;
Vector3 vStartUp = new Vector3(0f, CDRInfo.fStepHeight, 0f);
//if (Physics.Raycast(vStart, (vStart + Vector3.down).normalized, out hit1, vExt.y, mask))
//{
// if (hit1.point.y > posFoot.y)
// {
// Debug.LogError("hit.point.y > posFoot.y");
// posFoot.y = hit1.point.y + CDRInfo.fStepHeight;
// }
//}
bPull = !Physics.Raycast(posFoot, (Vector3.up).normalized, out hit, CDRInfo.fStepHeight, mask);
//env_trace_t tmpInfo = new env_trace_t();
//tmpInfo.vStart = EC_Utility.ToA3DVECTOR3(vStart);
//tmpInfo.vDelta = new A3DVECTOR3(0.0f, CDRInfo.fStepHeight, 0.0f);
//tmpInfo.vExt = CDRInfo.vExtent;
////@note : need check terrain?? By Kuiwu[8/10/2005]
//tmpInfo.dwCheckFlag = CDR_EVN.CDR_BRUSH | CDR_EVN.CDR_TERRAIN;
//tmpInfo.vTerStart = EC_Utility.ToA3DVECTOR3(posFoot);
//bPull = !CollideWithEnv(ref tmpInfo);
if (bPull)
{
vStart += Vector3.up * CDRInfo.fStepHeight;
posFoot = vStart - Vector3.up * vExt.y;
//Vector3 vDelta2 = vVelocity;
bool bMove = !Physics.Raycast(posFoot, (posFoot + vVelocity).normalized, out hit, fDeltaDist, mask);
//tmpInfo.vStart = EC_Utility.ToA3DVECTOR3(vStart);
//tmpInfo.vDelta = EC_Utility.ToA3DVECTOR3(vDelta);
//tmpInfo.vTerStart = EC_Utility.ToA3DVECTOR3(posFoot);
//bool bMove = !CollideWithEnv(ref tmpInfo);
if (!bMove)
{
//vDelta2 *= frac2;
vFinalPos = hit.point + Vector3.up * vExt.y;
//vFinalPos = vStart + vDelta * tmpInfo.fFraction + Vector3.up * vExt.y;
}
else
{
Debug.DrawLine(vFinalPos, vFinalPos + vDelta, Color.red, 10f);
vFinalPos += vDelta;
}
//if (vDelta2.sqrMagnitude < (vExt.x * vExt.x * 4f))
//{
// vStart -= Vector3.up * CDRInfo.fStepHeight;
// bPull = false;
//}
}
bTryPull = true;
}
@@ -680,7 +648,7 @@ namespace BrewMonster
vFinalPos = new A3DVECTOR3(vStart);
int nTry = 0;
bool bClear = true;
env_trace_t trcInfo;
env_trace_t trcInfo = new env_trace_t();
trcInfo.bWaterSolid = true;
trcInfo.dwCheckFlag = CDR_EVN.CDR_TERRAIN | CDR_EVN.CDR_BRUSH | CDR_EVN.CDR_WATER;
trcInfo.vExt = vExt;
@@ -1841,9 +1841,6 @@ namespace CSNetwork.GPDataType
struct cmd_emote_action
{
public ushort action;
public ushort id;
public int expiretime;
public char flag;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
+43 -5
View File
@@ -7,11 +7,10 @@ using CSNetwork.GPDataType;
using ModelRenderer.Scripts.Common;
using PerfectWorld.Scripts.Managers;
using UnityEngine;
using UnityEngine.EventSystems;
namespace PerfectWorld.Scripts
{
public class CECMatter : CECObject, IPointerDownHandler
public class CECMatter : CECObject
{
// Matter information got from server
public struct INFO
@@ -93,10 +92,49 @@ namespace PerfectWorld.Scripts
return null;
}
public void OnPointerDown(PointerEventData eventData)
private new void Update()
{
Debug.Log($"CECMatter::OnPointerDown():: mid: {m_MatterInfo.mid}");
UnityGameSession.RequestPickupItem(m_MatterInfo.mid, m_MatterInfo.tid);
bool inputPressed = false;
Vector2 screenPosition = Vector2.zero;
// Check for touch input (mobile)
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
inputPressed = true;
screenPosition = touch.position;
}
}
// Check for mouse input (desktop)
else if (Input.GetMouseButtonDown(0))
{
inputPressed = true;
screenPosition = Input.mousePosition;
}
if (inputPressed)
{
Camera mainCamera = Camera.main;
if (mainCamera == null)
return;
Ray ray = mainCamera.ScreenPointToRay(screenPosition);
RaycastHit[] hits = Physics.RaycastAll(ray);
foreach (RaycastHit hit in hits)
{
if (hit.collider.gameObject == this.gameObject ||
hit.collider.transform.IsChildOf(this.transform))
{
Debug.Log($"CECMatter::RaycastHit():: mid: {m_MatterInfo.mid}");
UnityGameSession.RequestPickupItem(m_MatterInfo.mid, m_MatterInfo.tid);
break;
}
}
}
}
}
}
@@ -4,6 +4,7 @@ using BrewMonster.Scripts.Task;
namespace PerfectWorld.Scripts.Task
{
[Serializable]
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ATaskTemplFixedData
{
@@ -8,6 +8,8 @@ using System.Threading;
using CSNetwork.GPDataType;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace BrewMonster.Scripts.Task
{
@@ -83,6 +85,15 @@ namespace BrewMonster.Scripts.Task
public async UniTask<bool> LoadTasksFromPack(string szPackPath, bool bLoadDescript, Action<float> onProgress, CancellationToken token)
{
bool wasLoaded = await LoadTaskTemplFromSO();
if (wasLoaded)
{
BMLogger.Log($" [ATaskTemplMan] Loaded task templates from ScriptableObject.");
onProgress?.Invoke(1f);
return true;
}
// //TaskInterface::WriteLog(0, 0, 2, "LoadPack begin");
// BMLogger.Log("[Dat]- szPackPath: " + szPackPath);
// if (!File.Exists(szPackPath))
@@ -228,6 +239,85 @@ namespace BrewMonster.Scripts.Task
return true;
}
public bool LoadTasksFromPackNoAsyn(string szPackPath, bool bLoadDescript)
{
//TaskInterface::WriteLog(0, 0, 2, "LoadPack begin");
BMLogger.Log("[Dat]- szPackPath: " + szPackPath);
if (!File.Exists(szPackPath))
{
BMLogger.LogError("[Dat]- File not found: " + szPackPath);
return false;
}
long readBytes = 0;
FileStream fs = new FileStream(szPackPath, FileMode.Open, FileAccess.Read);
TASK_PACK_HEADER tph = AAssit.ReadFromBinaryOf<TASK_PACK_HEADER>(fs, ref readBytes);
if (tph.magic != TASK_PACK_MAGIC
|| tph.version != _task_templ_cur_version)
return false;
if (tph.item_count == 0) return true;
uint[] pOffs = new uint[tph.item_count];
g_ulNewCount++;
// fread(pOffs, sizeof(long), tph.item_count, fp);
// read File and prepare offset array before loading tasks
pOffs = AAssit.ReadArrayFromBinary<uint>(fs, (int)tph.item_count, ref readBytes);
Debug.Log((int)tph.item_count);
//BMLogger.Log($" [MH] Task File Lenght: {fs.Length}");
// for (int i = 2058; i < 2059; i++) //TODO: tph.item_count
Debug.Log($" Starting to load {tph.item_count} task templates...");
for (int i = 0; i < tph.item_count; i++)
{
// mvoe file pointer to task offset
fs.Seek(pOffs[i], SeekOrigin.Begin);
// BMLogger.Log(" [MH] Loading Task Templ at offset: " + pOffs[i]);
ATaskTempl pTempl = new ATaskTempl();
g_ulNewCount++;
// Debug.Log($"Task Index {i}: Attempting to load task template...");
if (!pTempl.LoadFromBinFile(fs))
{
CECTaskInterface.WriteLog(0, (int)pTempl.m_FixedData.m_ID, 0, "Cant Load Task");
// LOG_DELETE(pTempl);
continue;
}
AddOneTaskTempl(pTempl);
// TaskInterface::WriteLog(0, pTempl->m_ID, 2, "LoadTask");
}
Debug.Log($" Finished loading {m_TaskTemplMap.Count} task templates.");
// // char log[1024];
// // sprintf(log, "LoadTask, Count = %d", m_TaskTemplMap.size());
// // TaskInterface::WriteLog(0, 0, 2, log);
// //todo: check
// // LOG_DELETE_ARR(pOffs);
fs.Close();
#if !_TASK_CLIENT
UpdateTimeLimitCheckList();
#else
SortTasksCanSeekOut();
#endif
#if _ELEMENTCLIENT
// TODO: implement task error logging if needed
// _task_err.Release();
// _task_err.Init("Configs\\task_err.txt", true);
#endif
return true;
}
private static List<ATaskTempl> LoadTasksFromPack_Internal(string szPackPath, Action<float> onProgress, CancellationToken token)
{
long readBytes = 0;
@@ -983,7 +1073,25 @@ namespace BrewMonster.Scripts.Task
m_ulDynTasksDataSize = 0;
}
}
// void OnStorageData(TaskInterface* pTask, const void* data);
// 处理存储任务数据 // Handle storage task data
public void OnStorageData(TaskInterface pTask, byte[] data)
{
// Copy data directly to the storage buffer (equivalent to C++ memcpy operations)
// 直接将数据复制到存储缓冲区(等同于C++的memcpy操作)
if (pTask is CECTaskInterface cecTask)
{
cecTask.SetStorageTaskListBuffer(data);
}
else
{
// Fallback: read into struct (but won't persist without writing back)
// 后备方案:读取到结构体(但不写回则不会持久化)
StorageTaskList pLst = pTask.GetStorageTaskList();
pLst.ReadByte(data);
}
}
// void OnSpecialAward(const special_award* p,TaskInterface* pTask);
// void VerifyDynTasksPack(const char* szPath);
// const special_award* GetSpecialAward() const { return &m_SpecialAward; }
@@ -1131,7 +1239,9 @@ namespace BrewMonster.Scripts.Task
return false;
}
if (header.pack_size != data_size)
// Only check pack_size when reading full data, not when header_only is true
// When header_only is true, we only read the header, so pack_size will be larger than data_size
if (!header_only && header.pack_size != data_size)
{
// TaskInterface::WriteLog(0, 0, 0, "UnmarshalDynTasks, wrong header");
BMLogger.LogError($" [ATaskTemplMan] UnmarshalDynTasks, wrong header: pack_size {header.pack_size} != data_size {data_size}");
@@ -1261,6 +1371,60 @@ namespace BrewMonster.Scripts.Task
return true;
}
public async UniTask<bool> LoadTaskTemplFromSO()
{
const string addressKey = "Assets/PerfectWorld/SO/TaskTemplContainerSO.asset"; // set this to the real address
AsyncOperationHandle<TaskTemplContainerSO> handle = default;
try
{
handle = Addressables.LoadAssetAsync<TaskTemplContainerSO>(addressKey);
await handle.Task;
if (handle.Status != AsyncOperationStatus.Succeeded)
{
BMLogger.LogError($"[ATaskTemplMan] LoadTaskTemplFromSO failed: {handle.OperationException}");
return false;
}
var config = handle.Result;
if (config == null)
{
BMLogger.LogError("[ATaskTemplMan] LoadTaskTemplFromSO returned null result");
return false;
}
if(!config.LoadAllTasksOnValidate) return false;
var loadedTasks = config.TaskTemplates;
if (loadedTasks == null ||loadedTasks.Count == 0)
{
BMLogger.LogError("[ATaskTemplMan] LoadTaskTemplFromSO, no task templates found in SO");
return false;
}
for (int i = 0; i < loadedTasks.Count; i++)
{
AddOneTaskTempl(loadedTasks[i]);
g_ulNewCount++;
}
Debug.Log($"Finished loading {m_TaskTemplMap.Count} task templates.");
return true;
}
catch (Exception e)
{
BMLogger.LogError($"[ATaskTemplMan] LoadTaskTemplFromSO exception: {e}");
return false;
}
finally
{
if (handle.IsValid())
Addressables.Release(handle);
}
}
}
[ StructLayout(LayoutKind.Sequential, Pack = 1) ]
@@ -10,6 +10,7 @@ using CSNetwork;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using System;
namespace BrewMonster.Scripts.Task
{
@@ -437,6 +438,7 @@ namespace BrewMonster.Scripts.Task
pTaskMan.TaskLoadedCount > 100)
{
Debug.Log($" [TaskInterface] Using TaskTest loaded data with {pTaskMan.TaskLoadedCount} tasks.");
LoadingSceneController.Instance.ShowLoadingScene(false);
}
else
{
@@ -524,24 +526,7 @@ namespace BrewMonster.Scripts.Task
public void CheckPQEnterWorldInit()
{
return;
ActiveTaskList pList = GetActiveTaskList();
List<ActiveTaskEntry> aEntries = new List<ActiveTaskEntry>(pList.m_TaskEntries);
for(var i = 0; i < pList.m_uTaskCount; i++)
{
var CurEntry = aEntries[i];
if (CurEntry.m_ulTemplAddr == 0)
continue;
ATaskTempl pTempl = CurEntry.GetTempl();
if (pTempl == null || !pTempl.m_FixedData.m_bPQTask)
continue;
pTempl.IncValidCount();
// _notify_svr(this, TASK_CLT_NOTIFY_PQ_CHECK_INIT, CurEntry.m_ID);
}
// TODO: implement PQ enter-world init if needed
}
public static void WriteLog(int nPlayerId, int nTaskId, int nType, string szLog)
@@ -552,7 +537,6 @@ namespace BrewMonster.Scripts.Task
public bool IsDeliverLegal()
{
return !m_pHost.IsTrading() && m_pHost.GetBoothState() == 0 && !m_pHost.IsDead();
return true;
}
public int GetCommonItemCount(uint ulCommonItem)
@@ -1294,12 +1278,6 @@ namespace BrewMonster.Scripts.Task
// return pTempl.CheckPrerequisite(this, static_cast<ActiveTaskList*>(GetActiveTaskList()), GetCurTime(), true, true, false);
return pTempl.CheckPrerequisite(this, GetActiveTaskList(), GetCurTime(), true, true, false);
// if (!pTempl.CheckReachLevel(this)) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_BELOW_LEVEL;
// uint keyCheck = pTempl.CheckGlobalKeyValue(this, false);
// if (keyCheck != 0u) return keyCheck;
return 0u;
}
public bool CanDeliverCommonItem(uint ulTypes)
{
@@ -1371,8 +1349,7 @@ namespace BrewMonster.Scripts.Task
ActiveTaskList pLst = GetActiveTaskList();
uint ulCurTime = GetCurTime(); // 当前时间 // current time
ATaskTempl pTempl = null;
ActiveTaskEntry foundEntry = default;
bool hasFoundEntry = false;
int foundEntryIndex = -1; // Keep track of entry index like C++ code does
if (bActiveTask)
{
@@ -1383,8 +1360,7 @@ namespace BrewMonster.Scripts.Task
if (CurEntry.m_ID != ulTaskId || CurEntry.m_ulTemplAddr == 0) continue;
pTempl = CurEntry.GetTempl();
foundEntry = CurEntry;
hasFoundEntry = true;
foundEntryIndex = i; // Store index to access entry later
// 检查任务是否可以完成 // Check if task can be completed
if (pTempl != null && pTempl.CanFinishTask(this, CurEntry, ulCurTime))
@@ -1459,9 +1435,11 @@ namespace BrewMonster.Scripts.Task
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonsterId = mw.m_ulMonsterTemplId;
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersToKill = mw.m_ulMonsterNum;
if (bActiveTask && hasFoundEntry)
// Access the entry directly from the list using stored index, like C++ code does
if (bActiveTask && foundEntryIndex >= 0)
{
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersKilled = foundEntry.m_wMonsterNum[j];
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[foundEntryIndex];
pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersKilled = CurEntry.m_wMonsterNum[j];
}
ulMonsterCount++;
@@ -1488,9 +1466,11 @@ namespace BrewMonster.Scripts.Task
{
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersToKill = pw.m_ulPlayerNum;
if (bActiveTask && hasFoundEntry)
// Access the entry directly from the list using stored index, like C++ code does
if (bActiveTask && foundEntryIndex >= 0)
{
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersKilled = foundEntry.m_wMonsterNum[j];
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[foundEntryIndex];
pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersKilled = CurEntry.m_wMonsterNum[j];
}
pInfo.m_PlayerWanted[ulPlayerCount].m_Requirements = pw.m_Requirements;
@@ -1643,7 +1623,16 @@ namespace BrewMonster.Scripts.Task
public StorageTaskList GetStorageTaskList()
{
StorageTaskList ret = new StorageTaskList();
ret.ReadByte(m_pStorageTaskListBuf);
// Initialize arrays before use
ret.EnsureInitialized();
// Check if buffer is initialized before reading
if (m_pStorageTaskListBuf != null)
{
ret.ReadByte(m_pStorageTaskListBuf);
}
// If buffer is null, return empty/default StorageTaskList
// This can happen if Init() hasn't been called yet or failed
return ret;
}
@@ -1749,6 +1738,39 @@ namespace BrewMonster.Scripts.Task
ret.ReadFromBytes(m_pFinishedListBuf);
return ret;
}
// 记录任务完成/失败到已完成列表(用于前置任务/可重复接任务判断)
// English: Record task finish/fail into FinishedTaskList (used by prerequisite checks)
public void RecordFinishedTask(uint taskId, bool success)
{
if (m_pFinishedListBuf == null) return;
FinishedTaskList lst = new FinishedTaskList();
lst.ReadFromBytes(m_pFinishedListBuf);
lst.AddOneTask(taskId, success);
// Persist back into buffer
if (lst.m_Buf != null && lst.m_Buf.Length == m_pFinishedListBuf.Length)
{
global::System.Buffer.BlockCopy(lst.m_Buf, 0, m_pFinishedListBuf, 0, m_pFinishedListBuf.Length);
}
}
// Persist an updated FinishedTaskList back into the underlying buffer.
public void WriteFinishedTaskList(FinishedTaskList lst)
{
if (m_pFinishedListBuf == null) return;
if (lst.m_Buf == null || lst.m_Buf.Length != m_pFinishedListBuf.Length) return;
global::System.Buffer.BlockCopy(lst.m_Buf, 0, m_pFinishedListBuf, 0, m_pFinishedListBuf.Length);
}
// Reset role-based finish counter for a task when period rolls over (used by CheckDeliverTime).
public void ResetRoleFinishCount(uint taskId)
{
if (m_pFinishedListBuf == null) return;
FinishedTaskList lst = new FinishedTaskList();
lst.ReadFromBytes(m_pFinishedListBuf);
lst.ResetFinishCount(taskId);
WriteFinishedTaskList(lst);
}
public int GetPlayerId()
{
+44 -18
View File
@@ -17,6 +17,9 @@ namespace BrewMonster.Scripts.Task
private const uint FINISH_DLG_SHOWN_TIME = 3000; // TODO: Confirm correct value
private static uint s_finishDlgShownTime = 0;
// Throttle CHECK_FINISH notifications per task to avoid spamming the server every tick.
private static readonly System.Collections.Generic.Dictionary<uint, uint> s_lastCheckFinishAt = new();
public static void OnTaskCheckStatus(TaskInterface pTask)
{
@@ -77,7 +80,16 @@ namespace BrewMonster.Scripts.Task
// 绝对失效时间判断 // Absolute fail time check
if (pTempl.m_FixedData.m_bAbsFail)
{
// TODO: Time zone bias and 'task_tm.before' not ported; skipping precise comparison
// Mirror C++: if abs-fail time has passed, ask server to check/finish (will mark fail if needed).
long sec = ulCurTime - (long)(TaskInterface.GetTimeZoneBias() * 60);
if (sec < 0) sec = 0;
DateTime cur = DateTimeOffset.FromUnixTimeSeconds(sec).UtcDateTime;
if (pTempl.m_FixedData.m_tmAbsFailTime.before(cur))
{
pTempl.IncValidCount();
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
continue;
}
}
// 进入或离开区域导致失败 // Entering or leaving region causes failure
@@ -245,8 +257,8 @@ namespace BrewMonster.Scripts.Task
}
else
{
// TODO: UpdateTaskToConfirm not ported; implement confirmation UI/state if needed
UpdateTaskToConfirm(pTask, pTempl, bNeedServerCheck);
// Minimal behavior: for wait-time tasks, auto request server check when time is up.
UpdateTaskToConfirm(pTask, pTempl, CurEntry, bNeedServerCheck, ulCurTime);
}
}
}
@@ -295,10 +307,27 @@ namespace BrewMonster.Scripts.Task
ATaskTempl._notify_svr(pTask, uReason, uTaskID);
}
// 更新“待确认任务” // Update task to confirm
private static void UpdateTaskToConfirm(TaskInterface pTask, ATaskTempl pTempl, bool needServerCheck)
// 更新“待确认任务” / 最小实现:当客户端确认已满足完成条件时,发一次 CHECK_FINISH 给服务器(节流)
// English: Minimal port: when conditions are met client-side, send CHECK_FINISH once (throttled).
private static void UpdateTaskToConfirm(TaskInterface pTask, ATaskTempl pTempl, ActiveTaskEntry entry, bool needServerCheck, uint ulCurTime)
{
// TODO: Implement confirmation queue/UI if required by design
if (!needServerCheck || pTask == null || pTempl == null || entry == null) return;
// Only auto-check for wait-time tasks (the reported broken case).
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod != TaskCompletionMethod.enumTMWaitTime)
return;
if (entry.IsFinished()) return;
uint id = entry.m_ID;
if (id == 0) return;
if (s_lastCheckFinishAt.TryGetValue(id, out uint last) && ulCurTime <= last + 1)
return;
s_lastCheckFinishAt[id] = ulCurTime;
pTempl.IncValidCount();
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, (ushort)id);
}
// Handle server notification for task updates
@@ -383,18 +412,15 @@ namespace BrewMonster.Scripts.Task
// Handle storage data notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_STORAGE)
{
// TODO: StorageTaskList struct not defined; need to define or use alternative
// if (sz != Marshal.SizeOf<task_notify_base>() + Marshal.SizeOf<StorageTaskList>()) return;
// TODO: OnStorageData method not found in ATaskTemplMan; implement if needed
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
// if (pMan != null)
// {
// byte[] storageData = new byte[Marshal.SizeOf<StorageTaskList>()];
// Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), storageData, 0, storageData.Length);
// pMan.OnStorageData(pTask, storageData);
// }
// TODO: UpdateTaskUI static method not found; implement UI update if needed
// TaskInterface.UpdateTaskUI(pNotify.task, pNotify.reason);
if (sz != Marshal.SizeOf<task_notify_base>() + Marshal.SizeOf<StorageTaskList>()) return;
ATaskTemplMan pMan = GetTaskTemplMan();
if (pMan != null)
{
byte[] storageData = new byte[Marshal.SizeOf<StorageTaskList>()];
Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), storageData, 0, storageData.Length);
pMan.OnStorageData(pTask, storageData);
}
pTask.UpdateTaskUI(pNotify.task, pNotify.reason);
return;
}
// Handle special award notification
+236 -106
View File
@@ -24,20 +24,21 @@ namespace BrewMonster.Scripts.Task
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
public struct TaskFinishCountList
{
public static ushort m_uCount;
public ushort m_uCount;
public static TaskFinishCountEntry[] m_aList = new TaskFinishCountEntry[(uint)TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN];
public TaskFinishCountEntry[] m_aList;
public uint Search(uint ulID, ref uint ulTime)
{
for (ushort i = 0; i < TaskFinishCountList.m_uCount; i++)
if (m_aList == null) return 0u;
for (ushort i = 0; i < m_uCount; i++)
{
if (TaskFinishCountList.m_aList[i].m_uTaskId == (ushort)ulID)
if (m_aList[i].m_uTaskId == (ushort)ulID)
{
ulTime = TaskFinishCountList.m_aList[i].m_ulFinishTime;
return TaskFinishCountList.m_aList[i].m_ulFinishCount;
ulTime = m_aList[i].m_ulFinishTime;
return m_aList[i].m_ulFinishCount;
}
}
@@ -47,12 +48,17 @@ namespace BrewMonster.Scripts.Task
public void ResetAt(uint ulID)
{
for (ushort i = 0; i < m_uCount; i++)
if (m_aList[i].m_uTaskId == (ushort)ulID)
m_aList[i].m_ulFinishCount = 0;
{
if (m_aList != null && m_aList[i].m_uTaskId == (ushort)ulID)
m_aList[i].m_ulFinishCount = 0;
}
}
public void AddOrUpdate(uint ulID, uint ulFinishTime)
{
if (m_aList == null || m_aList.Length != TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN)
m_aList = new TaskFinishCountEntry[TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN];
for (ushort i = 0; i < m_uCount; i++)
{
if (m_aList[i].m_uTaskId == (ushort)ulID)
@@ -74,7 +80,7 @@ namespace BrewMonster.Scripts.Task
public void RemoveAll()
{
m_uCount = 0;
m_aList = new TaskFinishCountEntry[(uint)TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN];
m_aList = new TaskFinishCountEntry[TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN];
}
public bool IsValid() { return m_uCount <= TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN; }
@@ -104,6 +110,31 @@ namespace BrewMonster.Scripts.Task
return true;
}
// Persist list back into a buffer returned by TaskInterface.GetFinishedCntList().
// Layout: ushort count + TASK_FINISH_COUNT_MAX_LEN * TaskFinishCountEntry bytes
public void WriteToBuffer(byte[] data)
{
if (data == null) return;
int entrySize = Marshal.SizeOf<TaskFinishCountEntry>();
int expectedSize = 2 + entrySize * TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN;
if (data.Length < expectedSize) return;
Array.Copy(BitConverter.GetBytes(m_uCount), 0, data, 0, 2);
if (m_aList == null || m_aList.Length != TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN)
{
Array.Clear(data, 2, data.Length - 2);
return;
}
for (int i = 0; i < TaskInterfaceConstants.TASK_FINISH_COUNT_MAX_LEN; i++)
{
int offset = 2 + i * entrySize;
// TaskFinishCountEntry is blittable with Pack=1, use helper
byte[] entryBytes = GPDataTypeHelper.ToBytes(m_aList[i]);
Array.Copy(entryBytes, 0, data, offset, Math.Min(entryBytes.Length, entrySize));
}
}
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
@@ -148,7 +179,9 @@ namespace BrewMonster.Scripts.Task
// unsigned char m_BufData[TASK_DATA_BUF_MAX_LEN-sizeof(TASK_ENTRY_FIXED_DATA)];
public byte[] m_BufData = new byte[TaskInterfaceConstants.TASK_DATA_BUF_MAX_LEN - Marshal.SizeOf<TASK_ENTRY_FIXED_DATA>() ]; // Raw data buffer
// nsigned short m_wMonsterNum[MAX_MONSTER_WANTED];
public ushort[] m_wMonsterNum // Monster numbers
// 注意:这个属性返回的是拷贝数组,不能用 m_wMonsterNum[i] = x 来写入(不会回写到底层缓冲)
// English: This property returns a COPY. Do not mutate via m_wMonsterNum[i] = x (it won't persist).
public ushort[] m_wMonsterNum // Monster numbers (copy)
{
get
{
@@ -170,6 +203,21 @@ namespace BrewMonster.Scripts.Task
}
}
// 读取/写入怪物计数(直接回写到底层缓冲) // English: Get/set monster count (writes through to backing buffer)
public ushort GetMonsterNum(int index)
{
if (index < 0 || index >= TaskInterfaceConstants.MAX_MONSTER_WANTED) return 0;
return BitConverter.ToUInt16(m_BufData, index * 2);
}
public void SetMonsterNum(int index, ushort value)
{
if (index < 0 || index >= TaskInterfaceConstants.MAX_MONSTER_WANTED) return;
byte[] bytes = BitConverter.GetBytes(value);
m_BufData[index * 2] = bytes[0];
m_BufData[index * 2 + 1] = bytes[1];
}
public int m_iUsefulData1
{
get => BitConverter.ToInt32(m_BufData, TaskInterfaceConstants.MAX_MONSTER_WANTED * 2);
@@ -239,6 +287,7 @@ namespace BrewMonster.Scripts.Task
public bool IsContributionFinish() => (m_uState & (byte)TaskState.TASK_STATE_CONTRIBUTION_FINISH) != 0;
public void SetFinished() { m_uState |= (char)TaskState.TASK_STATE_FINISHED; }
public void SetSuccess() { m_uState |= (char)TaskState.TASK_STATE_SUCCESS; } // 设置成功标志 // English: Mark success flag
// void ClearFinished() { m_uState &= ~TASK_STATE_FINISHED; }
// void SetSuccess() { m_uState |= TASK_STATE_SUCCESS; }
public void ClearSuccess() { m_uState &= (char)~TaskState.TASK_STATE_SUCCESS; }
@@ -259,8 +308,15 @@ namespace BrewMonster.Scripts.Task
var man = BrewMonster.Network.EC_Game.GetTaskTemplateMan();
if (man != null)
{
var templ = man.GetTaskTemplByID(m_ID);
if (templ != null) return templ;
// NOTE: Some project configurations report an "ambiguous call" error for direct calls
// into ATaskTemplMan methods (likely due to duplicate symbols/assemblies). Use reflection
// here to keep compilation stable while still using the manager at runtime.
var mi = man.GetType().GetMethod("GetTaskTemplByID", new[] { typeof(uint) });
if (mi != null)
{
var templObj = mi.Invoke(man, new object[] { (uint)m_ID });
if (templObj is ATaskTempl templ) return templ;
}
}
}
catch { }
@@ -424,106 +480,157 @@ namespace BrewMonster.Scripts.Task
m_uUsedCount += pTempl.m_uDepth;
}
}
void RealignTask(ActiveTaskEntry pEntry, byte uReserve)
/// <summary>
/// Shift-based realign that matches original C++ ActiveTaskList::RealignTask.
/// It only adjusts indices in a controlled range instead of globally compacting the list.
/// This is critical for keeping Parent/Child/Sibling indices stable during subtask progression.
/// </summary>
public void RealignTask(ActiveTaskEntry pEntry, byte uReserve)
{
// TODO: implement RealignTask logic
// // unsigned char uCurIndex = static_cast<unsigned char>(pEntry - m_TaskEntries);
// byte uCurIndex = (byte)Array.IndexOf(m_TaskEntries, pEntry);
//
// uint ulCount = (uint)m_uTaskCount - uCurIndex; // ʣ
//
// if (ulCount == 0) return; // һ
//
// byte uEmptyCount = 0;
// for (int uEmpty = uCurIndex; uEmpty < TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN; uEmpty++)
// {
// if (m_TaskEntries[uEmpty].m_ID == 0)
// uEmptyCount++;
// else
// break;
// }
//
// if (uReserve == uEmptyCount) return;
//
// // ActiveTaskEntry* pSrc = pEntry + uEmptyCount;
// int pSrcIndex = uCurIndex + uEmptyCount;
// ActiveTaskEntry[] pSrc = new ActiveTaskEntry[ulCount];
// Array.Copy(m_TaskEntries, pSrcIndex, pSrc, 0, ulCount);
//
// // ActiveTaskEntry* pInsert = pEntry + uReserve;
// int pInsertIndex = uCurIndex + uReserve;
// ActiveTaskEntry[] pInsert = new ActiveTaskEntry[ulCount];
// Array.Copy(m_TaskEntries, pInsertIndex, pInsert, 0, ulCount);
//
// // move it
// // memmove(pInsert, pSrc, sizeof(ActiveTaskEntry) * ulCount);
// Array.Copy(pSrc, 0, m_TaskEntries, 0, ulCount);
//
// // clear reserve part
// ActiveTaskEntry[] pClearStart, pClearEnd;
// int pClearStartIndex = 0, pClearEndIndex = 0;
//
// // if (pInsert > pSrc) // C++ pointer compare
// if (pInsertIndex > pSrcIndex) // C# index compare
// {
// pClearStart = pSrc;
// pClearEnd = pInsert;
// }
// else
// {
// // pClearStart = pInsert + ulCount;
// pClearStartIndex = pInsertIndex + (int)ulCount;
// // pClearEnd = pSrc + ulCount;
// pClearEndIndex = pSrcIndex + (int)ulCount;
// }
//
// // while (pClearStart < pClearEnd)
// while (pClearStartIndex < pClearEndIndex)
// {
// pClearStart.m_ulTemplAddr = 0;
// pClearStart.m_ID = 0;
// pClearStart++;
// }
//
// // calc gap
// unsigned char uGap = static_cast<unsigned char>(pInsert - pSrc);
// unsigned long i = 0;
//
// for (; i < static_cast<unsigned long>(uCurIndex); i++)
// {
// // Parent, PrevСuCurIndex
// ActiveTaskEntry& CurEntry = m_TaskEntries[i];
//
// if(!CurEntry.m_ID)
// continue;
//
// if (CurEntry.m_ChildIndex != 0xff && CurEntry.m_ChildIndex >= uCurIndex)
// CurEntry.m_ChildIndex += uGap;
// if (CurEntry.m_NextSblIndex != 0xff && CurEntry.m_NextSblIndex >= uCurIndex)
// CurEntry.m_NextSblIndex += uGap;
// }
//
// for (i = 0; i < ulCount; i++)
// {
// ActiveTaskEntry& CurEntry = *(pInsert + i);
// if(!CurEntry.m_ID)
// continue;
//
// if (CurEntry.m_ParentIndex != 0xff && CurEntry.m_ParentIndex >= uCurIndex)
// CurEntry.m_ParentIndex += uGap;
// if (CurEntry.m_PrevSblIndex != 0xff && CurEntry.m_PrevSblIndex >= uCurIndex)
// CurEntry.m_PrevSblIndex += uGap;
// if (CurEntry.m_ChildIndex != 0xff)
// CurEntry.m_ChildIndex += uGap;
// if (CurEntry.m_NextSblIndex != 0xff)
// CurEntry.m_NextSblIndex += uGap;
// }
if (pEntry == null) return;
int uCurIndex = Array.IndexOf(m_TaskEntries, pEntry);
if (uCurIndex < 0) return;
RealignTaskAtIndex(uCurIndex, uReserve);
}
/// <summary>
/// Index-based variant used by deliver/award flows where the "slot" matters (C++ passes an entry pointer).
/// </summary>
public void RealignTaskAtIndex(int uCurIndex, byte uReserve)
{
if (uCurIndex < 0 || uCurIndex >= TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN) return;
int ulCount = m_uTaskCount - uCurIndex; // remaining entries from uCurIndex
if (ulCount == 0) return;
// Count consecutive empty entries starting from uCurIndex
int uEmptyCount = 0;
for (int uEmpty = uCurIndex; uEmpty < TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN; uEmpty++)
{
var e = m_TaskEntries[uEmpty];
if (e == null || e.m_ID == 0) uEmptyCount++;
else break;
}
if (uReserve == uEmptyCount) return;
int srcIndex = uCurIndex + uEmptyCount;
int insertIndex = uCurIndex + uReserve;
int uGap = insertIndex - srcIndex;
if (uGap == 0) return;
// Move the block [srcIndex, srcIndex + ulCount) -> [insertIndex, insertIndex + ulCount)
if (uGap > 0)
{
for (int i = ulCount - 1; i >= 0; i--)
m_TaskEntries[insertIndex + i] = m_TaskEntries[srcIndex + i];
}
else
{
for (int i = 0; i < ulCount; i++)
m_TaskEntries[insertIndex + i] = m_TaskEntries[srcIndex + i];
}
// Clear vacated slots
int clearStart, clearEnd;
if (insertIndex > srcIndex)
{
clearStart = srcIndex;
clearEnd = insertIndex;
}
else
{
clearStart = insertIndex + ulCount;
clearEnd = srcIndex + ulCount;
}
for (int i = clearStart; i < clearEnd; i++)
m_TaskEntries[i] = null;
// Adjust indices for entries before uCurIndex (child + next sibling that point into >= uCurIndex)
for (int i = 0; i < uCurIndex; i++)
{
var cur = m_TaskEntries[i];
if (cur == null || cur.m_ID == 0) continue;
if (cur.m_ChildIndex != 0xff && cur.m_ChildIndex >= uCurIndex)
cur.m_ChildIndex = (char)(cur.m_ChildIndex + uGap);
if (cur.m_NextSblIndex != 0xff && cur.m_NextSblIndex >= uCurIndex)
cur.m_NextSblIndex = (char)(cur.m_NextSblIndex + uGap);
}
// Adjust indices for moved entries (the inserted block)
for (int i = 0; i < ulCount; i++)
{
var cur = m_TaskEntries[insertIndex + i];
if (cur == null || cur.m_ID == 0) continue;
if (cur.m_ParentIndex != 0xff && cur.m_ParentIndex >= uCurIndex)
cur.m_ParentIndex = (char)(cur.m_ParentIndex + uGap);
if (cur.m_PrevSblIndex != 0xff && cur.m_PrevSblIndex >= uCurIndex)
cur.m_PrevSblIndex = (char)(cur.m_PrevSblIndex + uGap);
if (cur.m_ChildIndex != 0xff)
cur.m_ChildIndex = (char)(cur.m_ChildIndex + uGap);
if (cur.m_NextSblIndex != 0xff)
cur.m_NextSblIndex = (char)(cur.m_NextSblIndex + uGap);
}
RecountTaskCounters();
}
// 重新统计顶部任务计数与使用量 // English: Recount top task counters and used count
public void RecountTaskCounters()
{
m_uTopShowTaskCount = 0;
m_uTopHideTaskCount = 0;
m_uTitleTaskCount = 0;
m_uUsedCount = 0;
for (int i = 0; i < m_uTaskCount; i++)
{
var e = m_TaskEntries[i];
if (e == null || e.m_ID == 0) continue;
var templ = e.GetTempl();
if (templ == null) continue;
if (templ.m_pParent != null) continue;
if (templ.m_FixedData.m_bHidden) m_uTopHideTaskCount++;
else if (templ.m_FixedData.m_bDisplayInTitleTaskUI) m_uTitleTaskCount++;
else m_uTopShowTaskCount++;
// used count is an 8-bit field in the original packed header; clamp to byte range
int used = m_uUsedCount + templ.m_uDepth;
m_uUsedCount = (byte)Math.Clamp(used, 0, byte.MaxValue);
}
}
public void ClearTask(TaskInterface pTask, ActiveTaskEntry pEntry, bool bRemoveItem)
{
RecursiveClearTask(pTask, pEntry, bRemoveItem, true, true);
RealignTask(pEntry, 0);
}
// void ClearChildrenOf(TaskInterface* pTask, ActiveTaskEntry* pParent, bool bRemoveItem = true);
// 清除指定父节点的所有子任务(不清除父节点自身) // English: Clear all children of a parent entry (but keep the parent entry)
public void ClearChildrenOf(TaskInterface pTask, ActiveTaskEntry pParent, bool bRemoveItem = true)
{
if (pParent == null) return;
// Mirror C++: while parent has a first child, recursively clear that child subtree.
while (pParent.m_ChildIndex != 0xff)
{
int childIndex = (byte)pParent.m_ChildIndex;
if (childIndex < 0 || childIndex >= TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN) break;
var child = m_TaskEntries[childIndex];
if (child == null || child.m_ID == 0)
{
// Broken link: stop to avoid infinite loop
pParent.m_ChildIndex = (char)0xff;
break;
}
RecursiveClearTask(pTask, child, bRemoveItem, true, true);
}
}
void RecursiveClearTask(
TaskInterface pTask,
@@ -610,7 +717,6 @@ namespace BrewMonster.Scripts.Task
return null;
}
// void ClearChildrenOf(TaskInterface* pTask, ActiveTaskEntry* pParent, bool bRemoveItem = true);
// ActiveTaskEntry* GetEntry(unsigned long ulId)
// {
// for (unsigned char i = 0; i < m_uTaskCount; i++)
@@ -644,5 +750,29 @@ namespace BrewMonster.Scripts.Task
{
m_uMaxSimultaneousCount = true;
}
// 从列表中移除指定条目(并重新对齐列表) // English: Remove an entry from the list (and realign)
public void RemoveEntry(ActiveTaskEntry entry)
{
if (entry == null || entry.m_ID == 0) return;
// Best-effort unlink from sibling chain
if (entry.m_ParentIndex != 0xff)
{
if (entry.m_PrevSblIndex != 0xff && m_TaskEntries[entry.m_PrevSblIndex] != null)
m_TaskEntries[entry.m_PrevSblIndex].m_NextSblIndex = entry.m_NextSblIndex;
else if (m_TaskEntries[entry.m_ParentIndex] != null)
m_TaskEntries[entry.m_ParentIndex].m_ChildIndex = entry.m_NextSblIndex;
if (entry.m_NextSblIndex != 0xff && m_TaskEntries[entry.m_NextSblIndex] != null)
m_TaskEntries[entry.m_NextSblIndex].m_PrevSblIndex = entry.m_PrevSblIndex;
}
// Mark empty + decrement count, then realign from this slot.
entry.m_ulTemplAddr = 0;
entry.m_ID = 0;
if (m_uTaskCount > 0) m_uTaskCount--;
RealignTask(entry, 0);
}
};
}
File diff suppressed because it is too large Load Diff
@@ -100,8 +100,23 @@ namespace BrewMonster.Scripts.Task
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
public byte[] m_StoragesReceivePerDay;
// Initialize arrays if they are null
// In C++, arrays are automatically allocated on the stack, but in C# they need explicit initialization
public void EnsureInitialized()
{
if (m_Storages == null)
m_Storages = new ushort[TaskTemplConstants.TASK_STORAGE_COUNT * TaskTemplConstants.TASK_STORAGE_LEN];
if (m_StoragesTaskSetCount == null)
m_StoragesTaskSetCount = new ushort[TaskTemplConstants.TASK_STORAGE_COUNT];
if (m_StoragesRefreshTime == null)
m_StoragesRefreshTime = new uint[TaskTemplConstants.TASK_STORAGE_COUNT];
if (m_StoragesReceivePerDay == null)
m_StoragesReceivePerDay = new byte[TaskTemplConstants.TASK_STORAGE_COUNT];
}
public void RemoveAll()
{
EnsureInitialized();
for (int i = 0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
for (int j = 0; j < TaskTemplConstants.TASK_STORAGE_LEN; j++)
@@ -117,6 +132,11 @@ namespace BrewMonster.Scripts.Task
public void ReadByte(byte[] data)
{
if (data == null)
return;
EnsureInitialized();
int offset = 0;
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
@@ -227,37 +247,52 @@ namespace BrewMonster.Scripts.Task
[FieldOffset(8)]
public ulong m_ulRcvUpdateTime;
void AddRevNum() { m_ulReceiverNum++; }
public void AddRevNum() { m_ulReceiverNum++; }
void CheckRcvUpdateTime(uint ulCurTime, int nFrequency)
public void CheckRcvUpdateTime(uint ulCurTime, int nFrequency)
{
// TODO: implement time-based receiver number reset logic
// if (nFrequency == TaskCompletionMethod.enumTAFNormal || m_ulRcvUpdateTime == 0)
// return;
//
// tm tmCur = *localtime((time_t*)&ulCurTime);
// tm tmRcv = *localtime((time_t*)&m_ulRcvUpdateTime);
//
// if (nFrequency == enumTAFEachDay)
// {
// if (tmCur.tm_year != tmRcv.tm_year || tmCur.tm_yday != tmRcv.tm_yday)
// m_ulReceiverNum = 0;
// }
// else if (nFrequency == enumTAFEachWeek)
// {
// if (!_is_same_week(&tmCur, &tmRcv, ulCurTime, m_ulRcvUpdateTime))
// m_ulReceiverNum = 0;
// }
// else if (nFrequency == enumTAFEachMonth)
// {
// if (tmCur.tm_year != tmRcv.tm_year || tmCur.tm_mon != tmRcv.tm_mon)
// m_ulReceiverNum = 0;
// }
// else if (nFrequency == enumTAFEachYear)
// {
// if (tmCur.tm_year != tmRcv.tm_year)
// m_ulReceiverNum = 0;
// }
// C++ semantics: based on localtime() period boundaries, reset receiver count when period changes.
// Use the same "task local time" conversion as timetable (timezone bias path) so behavior is consistent.
if (nFrequency == (int)TaskAwardFreq.enumTAFNormal || m_ulRcvUpdateTime == 0)
return;
long curSec = ulCurTime - (long)(TaskInterface.GetTimeZoneBias() * 60);
if (curSec < 0) curSec = 0;
DateTime cur = DateTimeOffset.FromUnixTimeSeconds(curSec).UtcDateTime;
long rcvSec = (long)m_ulRcvUpdateTime - (long)(TaskInterface.GetTimeZoneBias() * 60);
if (rcvSec < 0) rcvSec = 0;
DateTime rcv = DateTimeOffset.FromUnixTimeSeconds(rcvSec).UtcDateTime;
bool reset = false;
if (nFrequency == (int)TaskAwardFreq.enumTAFEachDay)
{
reset = cur.Year != rcv.Year || cur.Month != rcv.Month || cur.Day != rcv.Day;
}
else if (nFrequency == (int)TaskAwardFreq.enumTAFEachWeek)
{
int curDow = (int)cur.DayOfWeek; // Sunday=0
int rcvDow = (int)rcv.DayOfWeek;
int curDiff = (curDow == 0) ? 6 : (curDow - 1); // Monday-start week
int rcvDiff = (rcvDow == 0) ? 6 : (rcvDow - 1);
DateTime curWeekStart = cur.Date.AddDays(-curDiff);
DateTime rcvWeekStart = rcv.Date.AddDays(-rcvDiff);
reset = curWeekStart != rcvWeekStart;
}
else if (nFrequency == (int)TaskAwardFreq.enumTAFEachMonth)
{
reset = cur.Year != rcv.Year || cur.Month != rcv.Month;
}
else if (nFrequency == (int)TaskAwardFreq.enumTAFEachYear)
{
reset = cur.Year != rcv.Year;
}
if (reset)
{
m_ulReceiverNum = 0;
m_ulRcvUpdateTime = ulCurTime;
}
}
}
@@ -436,8 +471,58 @@ namespace BrewMonster.Scripts.Task
public void AddOneTask(uint ulID, bool bSuccess)
{
// TODO: Implement logic to add one task (for future use)
//throw new NotImplementedException();
// 将任务写入已完成列表(按任务ID有序) // English: Insert/update into finished list (sorted by task id)
if (m_Buf == null || m_Buf.Length != TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE)
{
m_Buf = new byte[TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE];
}
var header = m_FnshHeader;
ushort count = header.m_uTaskCount;
if (count >= TaskInterfaceConstants.TASK_FINISHED_LIST_MAX_LEN) return;
int entrySize = Marshal.SizeOf<FnshedTaskEntry>(); // should be 4
int pos = GetTaskPos(ulID);
byte mask = (byte)(bSuccess ? 0 : 1);
if (pos >= 0)
{
// Update existing entry
int start = 4 + pos * entrySize;
// m_uTaskId
Array.Copy(BitConverter.GetBytes((ushort)ulID), 0, m_Buf, start, 2);
// m_Buf (mask + reserved bits)
m_Buf[start + 2] = (byte)((m_Buf[start + 2] & 0xFE) | (mask & 0x1));
// m_FnshedCount: keep at least 1
if (m_Buf[start + 3] == 0) m_Buf[start + 3] = 1;
return;
}
// Find insertion index to keep sorted order
int insert = 0;
for (; insert < count; insert++)
{
ushort existingId = BitConverter.ToUInt16(m_Buf, 4 + insert * entrySize);
if (ulID < existingId) break;
}
// Shift bytes to make room
int srcStart = 4 + insert * entrySize;
int bytesToMove = (count - insert) * entrySize;
if (bytesToMove > 0)
{
Buffer.BlockCopy(m_Buf, srcStart, m_Buf, srcStart + entrySize, bytesToMove);
}
// Write new entry
int dst = 4 + insert * entrySize;
Array.Copy(BitConverter.GetBytes((ushort)ulID), 0, m_Buf, dst, 2);
m_Buf[dst + 2] = (byte)(mask & 0x1); // reserved bits 0
m_Buf[dst + 3] = 1; // finish count
header.m_uTaskCount = (ushort)(count + 1);
m_FnshHeader = header;
}
public void RemoveTask(uint ulID)
@@ -461,22 +546,34 @@ namespace BrewMonster.Scripts.Task
public byte SearchTaskFinishCount(ulong ulID)
{
// TODO: Implement logic to search task finish count
//throw new NotImplementedException();
return 0;
int pos = GetTaskPos((uint)ulID);
if (pos < 0) return 0;
int entrySize = Marshal.SizeOf<FnshedTaskEntry>();
int start = 4 + pos * entrySize;
return m_Buf[start + 3]; // m_FnshedCount
}
public void ResetFinishCount(ulong ulID)
{
// TODO: Implement logic to reset finish count
//throw new NotImplementedException();
int pos = GetTaskPos((uint)ulID);
if (pos < 0) return;
int entrySize = Marshal.SizeOf<FnshedTaskEntry>();
int start = 4 + pos * entrySize;
m_Buf[start + 3] = 0;
}
public void AddForFinishCount(ulong ulID, bool bSuccess)
{
// TODO: Implement logic to add for finish count
//throw new NotImplementedException();
// 只用于计数:如果不存在则插入;如果存在则递增 m_FnshedCount
// English: Finish-count bookkeeping: insert if missing; otherwise increment m_FnshedCount.
AddOneTask((uint)ulID, bSuccess);
int pos = GetTaskPos((uint)ulID);
if (pos < 0) return;
int entrySize = Marshal.SizeOf<FnshedTaskEntry>();
int start = 4 + pos * entrySize;
byte cur = m_Buf[start + 3];
if (cur < byte.MaxValue) m_Buf[start + 3] = (byte)(cur + 1);
}
public void RemoveAll()
+159 -1
View File
@@ -873,6 +873,131 @@ namespace BrewMonster.Scripts.Task
{
return string.Format("{0}-{1}-{2} {3}:{4} (wday:{5})", year, month, day, hour, min, wday);
}
// ===== C++ task_tm time comparison helpers =====
// [中文] 对齐 C++ 的 task_tm::after/before 等比较逻辑(含“月/周/日”模式)
// [English] Parity with C++ task_tm::after/before and per-month/week/day variants
// C++: bool after(const tm* _tm) const
public bool after(DateTime t)
{
int ty = t.Year;
int tm = t.Month;
int td = t.Day;
int th = t.Hour;
int tmin = t.Minute;
if (year < ty) return false;
if (year > ty) return true;
if (month < tm) return false;
if (month > tm) return true;
if (day < td) return false;
if (day > td) return true;
if (hour < th) return false;
return hour > th || min > tmin;
}
// C++: bool before(const tm* _tm) const
public bool before(DateTime t)
{
int ty = t.Year;
int tm = t.Month;
int td = t.Day;
int th = t.Hour;
int tmin = t.Minute;
if (year > ty) return false;
if (year < ty) return true;
if (month > tm) return false;
if (month < tm) return true;
if (day > td) return false;
if (day < td) return true;
if (hour > th) return false;
return hour < th || min <= tmin;
}
// C++: bool after_per_month(const tm* _tm, bool bLastDay) const
public bool after_per_month(DateTime t, bool bLastDay)
{
int td = t.Day;
int th = t.Hour;
int tmin = t.Minute;
if (day < td) return false;
if (!bLastDay && day > td) return true;
if (hour < th) return false;
return hour > th || min > tmin;
}
// C++: bool before_per_month(const tm* _tm, bool bLastDay) const
public bool before_per_month(DateTime t, bool bLastDay)
{
int td = t.Day;
int th = t.Hour;
int tmin = t.Minute;
if (day < td) return true;
if (!bLastDay && day > td) return false;
if (hour > th) return false;
return hour < th || min <= tmin;
}
// task_week_map (C++): { 7,1,2,3,4,5,6 } with tm_wday Sunday=0
private static readonly int[] s_task_week_map = { 7, 1, 2, 3, 4, 5, 6 };
// C++: bool after_per_week(const tm* _tm) const
public bool after_per_week(DateTime t)
{
int w = s_task_week_map[(int)t.DayOfWeek];
if (wday < w) return false;
if (wday > w) return true;
int th = t.Hour;
int tmin = t.Minute;
if (hour < th) return false;
return hour > th || min > tmin;
}
// C++: bool before_per_week(const tm* _tm) const
public bool before_per_week(DateTime t)
{
int w = s_task_week_map[(int)t.DayOfWeek];
if (wday > w) return false;
if (wday < w) return true;
int th = t.Hour;
int tmin = t.Minute;
if (hour > th) return false;
return hour < th || min <= tmin;
}
// C++: bool after_per_day(const tm* _tm) const
public bool after_per_day(DateTime t)
{
int th = t.Hour;
int tmin = t.Minute;
if (hour < th) return false;
return hour > th || min > tmin;
}
// C++: bool before_per_day(const tm* _tm) const
public bool before_per_day(DateTime t)
{
int th = t.Hour;
int tmin = t.Minute;
if (hour > th) return false;
return hour < th || min <= tmin;
}
}
// Define task_team_member_info struct required by TEAM_MEM_WANTED
@@ -1444,6 +1569,35 @@ namespace BrewMonster.Scripts.Task
}
}
public bool IsValid() { return m_uCount <= TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN; }
// Persist this list back into the underlying buffer returned by TaskInterface.GetFinishedTimeList().
// Buffer layout: ushort count + TASK_FINISH_TIME_MAX_LEN * (ushort taskId + uint timeMark)
public void WriteToBuffer(byte[] data)
{
if (data == null) return;
int entrySize = sizeof(ushort) + sizeof(uint);
int expected = sizeof(ushort) + entrySize * TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN;
if (data.Length < expected) return;
int offset = 0;
Array.Copy(BitConverter.GetBytes(m_uCount), 0, data, offset, sizeof(ushort));
offset += sizeof(ushort);
if (m_aList == null || m_aList.Length != TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN)
{
// Keep buffer consistent even if list isn't initialized.
Array.Clear(data, offset, data.Length - offset);
return;
}
for (int i = 0; i < TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN; i++)
{
Array.Copy(BitConverter.GetBytes(m_aList[i].m_uTaskId), 0, data, offset, sizeof(ushort));
offset += sizeof(ushort);
Array.Copy(BitConverter.GetBytes(m_aList[i].m_ulTimeMark), 0, data, offset, sizeof(uint));
offset += sizeof(uint);
}
}
};
@@ -1486,8 +1640,10 @@ namespace BrewMonster.Scripts.Task
/// 任务模板类 // Task Template Class
/// include
/// </summary>
[Serializable]
public partial class ATaskTempl
{
[SerializeField]
public ATaskTemplFixedData m_FixedData;
public bool is_in_zone(ZONE_VERT _min, ZONE_VERT _max, float[] pos)
@@ -1690,6 +1846,8 @@ namespace BrewMonster.Scripts.Task
uint ulTopCount = 0;
byte uBudget = 0;
long lReputation = 0;
// Suppress unused warnings until RecursiveCalcAward is fully ported.
_ = ulCmnCount; _ = ulTskCount; _ = lReputation;
// 任务屏蔽检查 // Task forbid check
if (pTask.CheckTaskForbid(m_FixedData.m_ID)) return (uint)TaskInterfaceConstants.TASK_PREREQU_FAIL_TASK_FORBID;
@@ -4476,7 +4634,7 @@ namespace BrewMonster.Scripts.Task
return true;
}
public uint GetType() { return m_FixedData.m_ulType; }
public new uint GetType() { return m_FixedData.m_ulType; }
void Init()
{
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace BrewMonster.Scripts.Task
{
[ CreateAssetMenu(fileName = "TaskTemplContainerSO", menuName = "BrewMonster/Task/TaskTemplContainerSO")]
public class TaskTemplContainerSO : ScriptableObject
{
public const ulong TASK_PACK_MAGIC = 0x93858361;
public const ulong _task_templ_cur_version = 121;
[SerializeField] private bool _loadAllTasksOnValidate = false;
[SerializeField] private List<ATaskTempl> _taskTemplates = new List<ATaskTempl>();
public List<ATaskTempl> TaskTemplates { get { return _taskTemplates; } }
public int TaskLoadedCount;
public bool LoadAllTasksOnValidate => _loadAllTasksOnValidate;
private void OnValidate()
{
TaskLoadedCount = _taskTemplates ==null ? 0 : _taskTemplates.Count;
}
[ContextMenu(" Load All Tasks From Pack")]
public void LoadAllTasksFromPack()
{
string task_data_path = Path.Combine(Application.streamingAssetsPath, "data/tasks.data");
_taskTemplates = LoadTasksFromPack_Internal(task_data_path);
Debug.Log($"[TaskTemplContainerSO] Loaded {_taskTemplates.Count} task templates from pack.");
}
private static List<ATaskTempl> LoadTasksFromPack_Internal(string szPackPath)
{
long readBytes = 0;
var tasks = new List<ATaskTempl>();
using (var fs = new FileStream(
szPackPath,
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
TASK_PACK_HEADER tph =
AAssit.ReadFromBinaryOf<TASK_PACK_HEADER>(fs, ref readBytes);
if (tph.magic != TASK_PACK_MAGIC ||
tph.version != _task_templ_cur_version)
throw new Exception("Invalid task pack header");
if (tph.item_count == 0)
return tasks;
uint[] pOffs =
AAssit.ReadArrayFromBinary<uint>(fs, (int)tph.item_count, ref readBytes);
const float TASK_LOAD_WEIGHT = 0.8f;
for (int i = 0; i < tph.item_count; i++)
{
fs.Seek(pOffs[i], SeekOrigin.Begin);
ATaskTempl templ = new ATaskTempl();
if (!templ.LoadFromBinFile(fs))
continue;
tasks.Add(templ);
}
}
return tasks;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da89386b7a1d4c75b768f686888bac2a
timeCreated: 1765890592
+3 -2
View File
@@ -56,7 +56,7 @@ namespace BrewMonster.Scripts.Task
#if UNITY_EDITOR
if (Input.GetKeyDown(KeyCode.Q))
{
var dlgTaskGO = CECUIManager.Instance.GetInGameUIMan().GetDialog("Win_Task");
var dlgTaskGO = CECUIManager.Instance.GetInGameUIMan().GetDialog(CECUIHelper.DlgTaskName);
var dlgTask = (dlgTaskGO) as DlgTask;
if (dlgTask && !dlgTask.gameObject.activeInHierarchy)
{
@@ -129,8 +129,9 @@ namespace BrewMonster.Scripts.Task
m_pTaskMan = new ATaskTemplMan();
}
if (_cts == null) _cts = new CancellationTokenSource();
string path = Path.Combine(Application.streamingAssetsPath, "data/tasks.data");
WasLoadTaskData = await m_pTaskMan.LoadTasksFromPack(path, true,(x)=>{},_cts.Token);
WasLoadTaskData = m_pTaskMan.LoadTasksFromPackNoAsyn(path, true);
}
[ContextMenu("Test Size")]
+400 -54
View File
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using BrewMonster.Managers;
using BrewMonster.Scripts.Managers;
using BrewMonster.Network;
@@ -15,6 +16,7 @@ using PerfectWorld.Scripts.Task;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Unity.VisualScripting;
namespace BrewMonster.Scripts.Task.UI
{
@@ -135,14 +137,25 @@ namespace BrewMonster.Scripts.Task.UI
// [English] Task trace counter
private CECCounter m_TaskTraceCounter = new (); // CECCounter -> object placeholder
// ===== Time-gated task UI refresh (search list) =====
// Timetable/time-window tasks become available/unavailable as server time moves.
// The original C++ client periodically re-evaluates prerequisites; in this port we refresh the search list
// at a low frequency while the Search view is open so players can see time-gated tasks appear/disappear.
private uint _lastSearchRefreshMinuteKey = uint.MaxValue;
private uint _pendingReselectTaskId = 0;
// Active-task timer refresh (wait-time / time-limit / protect-time)
private float _nextActiveTimerUiRefreshAt = 0f;
#region Unity METHODS
private void OnEnable()
private new void OnEnable()
{
OnShowDialog();
OnCommand_havequest();
}
private void Awake()
private new void Awake()
{
EventBus.Subscribe<TaskItemClickEvent>(evt =>
{
@@ -357,6 +370,63 @@ namespace BrewMonster.Scripts.Task.UI
//
private bool Tick()
{
// Time-window task refresh: while in Search view, refresh the list when server time crosses a minute boundary.
// This is throttled to avoid rebuilding large task lists every frame.
if (m_iType == 1)
{
var host = GetHostPlayer();
var task = host != null ? host.GetTaskInterface() : null;
if (task != null)
{
uint now = task.GetCurTime();
uint minuteKey = now / 60u;
if (minuteKey != _lastSearchRefreshMinuteKey)
{
_lastSearchRefreshMinuteKey = minuteKey;
// Preserve current selection if any, so refreshing doesn't feel disruptive.
var curItem = m_pTv_Quest != null ? m_pTv_Quest.GetSelectedItem() : null;
_pendingReselectTaskId = (curItem != null) ? m_pTv_Quest.GetItemData(curItem) : 0u;
// Rebuild available task list according to current time-based prerequisites.
SearchForTask(-1);
// Restore selection best-effort (TaskTreeView selection is driven by EventBus).
if (_pendingReselectTaskId != 0u)
{
EventBus.Publish(new TaskItemClickEvent { Data = _pendingReselectTaskId });
}
}
}
}
// Active view: refresh selected task detail periodically so countdown UI updates in real time.
// (Wait-time tasks depend on m_ulTimePassed which changes with server time; without this, UI looks "stuck".)
if (m_iType == 0 && Time.unscaledTime >= _nextActiveTimerUiRefreshAt)
{
_nextActiveTimerUiRefreshAt = Time.unscaledTime + 0.5f; // 2 Hz is plenty for countdown text
var pTree = m_pTv_Quest;
var pItem = pTree != null ? pTree.GetSelectedItem() : null;
if (pItem != null && pTree.transform != pItem.transform.parent)
{
uint selectedTaskId = pTree.GetItemData(pItem);
if (selectedTaskId > 0)
{
var task = GetHostPlayer()?.GetTaskInterface();
if (task != null)
{
Task_State_info tsi = default;
task.GetTaskStateInfo(selectedTaskId, ref tsi, true);
if (tsi.m_ulWaitTime > 0 || tsi.m_ulTimeLimit > 0 || tsi.m_ulProtectTime > 0)
{
UpdateTask((int)selectedTaskId);
}
}
}
}
}
// if( m_szName == "Win_Quest" && IsShow() )
{
var pTree = m_pTv_Quest;
@@ -404,10 +474,12 @@ namespace BrewMonster.Scripts.Task.UI
// void RefreshTaskTrace();
public bool UpdateTask(int idTask = -1)
{
// if( m_szName != "Win_Quest" || m_iType != 0)
// {
// return true;
// }
// Only rebuild the list if viewing "Have Quest" (m_iType == 0)
// But always allow updating specific task details regardless of view type
if (idTask < 0 && m_iType != 0)
{
return true;
}
// ATaskTemplMan *pMan = GetGame()->GetTaskTemplateMan();
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
@@ -440,6 +512,7 @@ namespace BrewMonster.Scripts.Task.UI
ATaskTempl pTemp = pMan.GetTaskTemplByID((uint)idTask);
if (pTemp != null)
{
// Only update description and name if task changed
if( idTask != m_idLastTask )
{
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(GetTaskNameWithColor(pTemp)));
@@ -452,9 +525,11 @@ namespace BrewMonster.Scripts.Task.UI
m_pBtn_Abandon.interactable = pMan.CanGiveUpTask((uint)idTask);
// Get info
// Always refresh task state info to get latest progress data
// This ensures real-time updates when task progress changes
// When viewing "Have Quest" (m_iType == 0), tasks are active, so pass true to read kill counts
Task_State_info tsi = new Task_State_info();
pTask.GetTaskStateInfo((uint)idTask, ref tsi, false);
pTask.GetTaskStateInfo((uint)idTask, ref tsi, m_iType == 0);
// Clear first
strNewTextItem = "";
@@ -466,19 +541,19 @@ namespace BrewMonster.Scripts.Task.UI
int nANPC = (int)pTemp.GetAwardNPC();
UpdateAwardNPC(ref strNewTextItem, nANPC);
// Complete condition
// Complete condition - always refresh to show updated progress
UpdateCompleteCondition(ref strNewTextItem, ref strNewHintItem, tsi);
// Wanted Item
// Wanted Item - always refresh to show updated item counts
UpdateItemWanted(ref strNewTextItem, tsi, idTask);
// Treasure Map
UpdateTreasureMap(ref strNewTextItem);
// Task Confirm
// Task Confirm - always refresh to update button state
UpdateTaskConfirm(idTask, pTemp.m_FixedData.m_enumFinishType == (uint)TaskFinishType.enumTFTConfirm);
// Award
// Award - always refresh to show updated award preview
Task_Award_Preview award = default;
pTask.GetTaskAwardPreview((uint)idTask, ref award);
@@ -526,6 +601,8 @@ namespace BrewMonster.Scripts.Task.UI
// Guard: only handle search list when current UI type is 1 (search)
public bool SearchForTask(int idTask = -1)
{
// Only process search list when in search view (m_iType == 1)
// This prevents clearing the wrong list when updating
if (m_iType != 1)
{
return true;
@@ -647,10 +724,49 @@ namespace BrewMonster.Scripts.Task.UI
return true;
}
//
// //бɽѽ zhangyitian
// //бɽѽѽ zhangyitian
// When task updates, the available task list also needs to be updated, otherwise the available task list won't update
public bool UpdateQuestView()
{
return UpdateTask() && SearchForTask();
// Refresh the list for the current view type
// This ensures that when tasks are taken/completed/abandoned, the visible list is updated
bool result = true;
if (m_iType == 0)
{
// Refresh "Have Quest" list (taken tasks)
result = UpdateTask(-1);
}
else if (m_iType == 1)
{
// Refresh "Search Quest" list (available tasks)
result = SearchForTask(-1);
}
// Refresh the currently selected task details if one is selected
// This ensures task progress updates are reflected in real-time
var pTree = m_pTv_Quest;
var pItem = pTree?.GetSelectedItem();
if (pItem != null && pTree.transform != pItem.transform.parent)
{
uint selectedTaskId = pTree.GetItemData(pItem);
if (selectedTaskId > 0)
{
if (m_iType == 0)
{
// Refresh the selected task's details to show updated progress
UpdateTask((int)selectedTaskId);
}
else if (m_iType == 1)
{
// For search view, refresh the selected task
SearchForTask((int)selectedTaskId);
}
}
}
return result;
}
//
// bool IsPQTaskOrSubTask(int idTask);
@@ -724,7 +840,7 @@ namespace BrewMonster.Scripts.Task.UI
return default(T);
}
public CECHostPlayer GetHostPlayer()
public new CECHostPlayer GetHostPlayer()
{
if(EC_Game.GetGameRun() == null)
{
@@ -782,6 +898,52 @@ namespace BrewMonster.Scripts.Task.UI
child = child.m_pNextSibling;
}
}
// [中文] 仅插入“已接任务(Active)”中的子任务(基于 ActiveTaskList 的 Child/NextSbl 索引)
// [English] Insert only active subtasks (based on ActiveTaskList Child/NextSbl indices)
private void InsertActiveTaskChildren(TaskTreeViewItem pRoot, uint idTask)
{
var pTreeTask = m_pTv_Quest;
var pMan = EC_Game.GetTaskTemplateMan();
var pTask = GetHostPlayer()?.GetTaskInterface();
if (pTreeTask == null || pMan == null || pTask == null) return;
ActiveTaskList pList = pTask.GetActiveTaskList();
if (pList == null) return;
ActiveTaskEntry parentEntry = pList.GetEntry(idTask);
if (parentEntry == null) return;
char idx = parentEntry.m_ChildIndex;
while (idx != (char)0xff)
{
int childIndex = (byte)idx;
if (childIndex < 0 || childIndex >= TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN) break;
ActiveTaskEntry childEntry = pList.m_TaskEntries[childIndex];
if (childEntry == null || childEntry.m_ID == 0) break;
uint childId = childEntry.m_ID;
ATaskTempl childTempl = pMan.GetTaskTemplByID(childId);
string text = childTempl != null ? GetTaskNameWithColor(childTempl) : $"Task {childId}";
var pItem = pTreeTask.InsertItem(text, pRoot, null);
if (pItem != null)
{
pTreeTask.SetItemData(pItem, childId);
if ((int)childId == m_idSelTask)
{
if (m_pBtn_Abandon != null) m_pBtn_Abandon.interactable = true;
UpdateTask((int)childId);
}
// recurse into active children
InsertActiveTaskChildren(pItem, childId);
}
idx = childEntry.m_NextSblIndex;
}
}
private void SetTextItemText(string strNewTextItem, bool keepScrollPos, string strNewHintItem)
{
@@ -818,49 +980,52 @@ namespace BrewMonster.Scripts.Task.UI
// update task content in dialog (converted from C++)
private void UpdateBaseAward(Task_Award_Preview award)
{
// Ported from original C++: strTemp.Format(GetStringFromTable(3201), award.m_ulGold);
var sb = new System.Text.StringBuilder();
int colCount = 0;
const int col = 3;
int cellSpace = 50; // adjust as needed for spacing
void AppendWithSpacing(int stringId, string value)
{
var title = EC_Utility.FormatForTextMeshPro(GetStringFromTable(stringId));
var text = $"{title} {value}";
sb.Append( EC_Utility.FormatForTextMeshPro(text));
sb.Append(' ', Mathf.Abs(cellSpace - text.Length));
if ((++colCount) % col == 0) sb.Append("\n");
}
string strTemp;
if (award.m_ulGold > 0)
{
AppendWithSpacing(3201 , award.m_ulGold.ToString());
strTemp = Format(GetStringFromTable(3201), award.m_ulGold);
sb.Append(strTemp);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulExp > 0)
{
AppendWithSpacing(3202 , award.m_ulExp.ToString());
strTemp = Format(GetStringFromTable(3202), award.m_ulExp);
sb.Append(strTemp);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulSP > 0)
{
AppendWithSpacing(3203 , award.m_ulSP.ToString());
strTemp = Format(GetStringFromTable(3203), award.m_ulSP);
sb.Append(strTemp);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulRealmExp > 0)
{
AppendWithSpacing( 3207, award.m_ulRealmExp.ToString());
strTemp = Format(GetStringFromTable(3207), award.m_ulRealmExp);
sb.Append(strTemp);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_iForceContrib > 0)
{
AppendWithSpacing(3205, award.m_iForceContrib.ToString());
strTemp = Format(GetStringFromTable(3205), award.m_iForceContrib);
sb.Append(strTemp);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_iForceRepu > 0)
{
AppendWithSpacing(3206, award.m_iForceRepu.ToString());
strTemp = Format(GetStringFromTable(3206), award.m_iForceRepu);
sb.Append(strTemp);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (sb.Length > 0 && m_pTxt_BaseAward != null)
{
m_pTxt_BaseAward.text = sb.ToString();
m_pTxt_BaseAward.text = EC_Utility.FormatForTextMeshPro(sb.ToString());
m_pTxt_BaseAward.gameObject.SetActive(true);
}
}
@@ -937,7 +1102,7 @@ namespace BrewMonster.Scripts.Task.UI
sb.Append(szMsg);
string strTemp;
if (tsi.m_ulErrCode == TaskInterfaceConstants.TASK_AWARD_FAIL_LEVEL_CHECK)
strTemp = string.Format(GetStringFromTable(7637), tsi.m_ulPremLevelMin);
strTemp = Format(GetStringFromTable(7637), tsi.m_ulPremLevelMin);
else
strTemp = GetStringFromTable(807);
sb.Append(strTemp);
@@ -965,7 +1130,7 @@ namespace BrewMonster.Scripts.Task.UI
if (tsi.m_ulNPCToProtect > 0)
{
// Fallback text with NPC id; detailed name lookup omitted
sb.Append(string.Format(GetStringFromTable(257) ?? "Protect NPC: {0}", tsi.m_ulNPCToProtect));
sb.Append(Format(GetStringFromTable(257) ?? "Protect NPC: %d", tsi.m_ulNPCToProtect));
sb.Append(FormatTime((int)tsi.m_ulProtectTime, GetStringFromTable(258), 0));
int remain = System.Math.Max(0, (int)tsi.m_ulProtectTime - (int)tsi.m_ulTimePassed);
sb.Append(FormatTime(remain, GetStringFromTable(259), 0));
@@ -1206,7 +1371,7 @@ namespace BrewMonster.Scripts.Task.UI
// 金币需求
if (tsi.m_ulGoldWanted != 0)
{
string strTemp = string.Format(GetStringFromTable(7636), tsi.m_ulGoldWanted);
string strTemp = Format(GetStringFromTable(7636), tsi.m_ulGoldWanted);
strText += strTemp;
}
@@ -1218,10 +1383,10 @@ namespace BrewMonster.Scripts.Task.UI
string strColor = (iLevel < (int)tsi.m_ulReachReincarnation) ? "^ff0000" : "^00ff00";
if (iLevel < (int)tsi.m_ulReachReincarnation)
{
strHint += string.Format(GetStringFromTable(11144), iLevel);
strHint += Format(GetStringFromTable(11144), iLevel);
}
strText += strColor;
strText += string.Format(GetStringFromTable(11141), tsi.m_ulReachReincarnation);
strText += Format(GetStringFromTable(11141), tsi.m_ulReachReincarnation);
}
// Level requirement
@@ -1232,10 +1397,10 @@ namespace BrewMonster.Scripts.Task.UI
string strColor = (iLevel < (int)tsi.m_ulReachLevel) ? "^ff0000" : "^00ff00";
if (iLevel < (int)tsi.m_ulReachLevel)
{
strHint += string.Format(GetStringFromTable(11143), iLevel);
strHint += Format(GetStringFromTable(11143), iLevel);
}
strText += strColor;
strText += string.Format(GetStringFromTable(11140), tsi.m_ulReachLevel);
strText += Format(GetStringFromTable(11140), tsi.m_ulReachLevel);
}
// Realm requirement
@@ -1246,10 +1411,10 @@ namespace BrewMonster.Scripts.Task.UI
string strColor = (iLevel < (int)tsi.m_ulReachRealm) ? "^ff0000" : "^00ff00";
if (iLevel < (int)tsi.m_ulReachRealm)
{
strHint += string.Format(GetStringFromTable(11145), iLevel);
strHint += Format(GetStringFromTable(11145), iLevel);
}
strText += strColor;
strText += string.Format(GetStringFromTable(11142), (int)tsi.m_ulReachRealm);
strText += Format(GetStringFromTable(11142), (int)tsi.m_ulReachRealm);
}
}
@@ -1299,7 +1464,7 @@ namespace BrewMonster.Scripts.Task.UI
// Compose line: name and progress (gained/toGet)
// 组合文本:名称与进度(已获得/所需)
string strTemp = string.Format(GetStringFromTable(7625), itemName,
string strTemp = Format(GetStringFromTable(7625), itemName,
tsi.m_ItemsWanted[i].m_ulItemsGained,
tsi.m_ItemsWanted[i].m_ulItemsToGet);
@@ -1423,7 +1588,11 @@ namespace BrewMonster.Scripts.Task.UI
pItem.SetItemTextColor(GetTaskColor((int)ENUM_TASK_TYPE.enumTTLevel2));
// pTreeTask.SetItemHint(pItem, pTemp->GetSignature()); // TODO
pTreeTask.SetItemData(pItem, (uint)id);
InsertTaskChildren(pItem, (uint)id, true, pTemp.IsKeyTask());
// HaveQuest view: children should reflect ActiveTaskList, not template tree (otherwise they never disappear on completion)
if (m_iType == 0)
InsertActiveTaskChildren(pItem, (uint)id);
else
InsertTaskChildren(pItem, (uint)id, true, pTemp.IsKeyTask());
if( (int)id == m_idSelTask )
{
@@ -1464,29 +1633,206 @@ namespace BrewMonster.Scripts.Task.UI
string Format( string formatStr, params object[] args )
{
var newStr = "";
int argIndex = 0;
// Ported from original C++ ACString::Format() which uses vsprintf/vswprintf
// Original implementation: AString& AString::Format(const char* szFormat, ...) { vsprintf(m_pStr, szFormat, argList); }
// This converts printf-style format specifiers to C# format specifiers
if (string.IsNullOrEmpty(formatStr))
return formatStr;
// Process format string character by character to convert %d, %s, etc. to {0}, {1}, etc.
// This matches the original vsprintf behavior exactly
var sb = new System.Text.StringBuilder();
int paramIndex = 0;
for (int i = 0; i < formatStr.Length; i++)
{
if (formatStr[i] == '%' && i + 1 < formatStr.Length)
{
char formatSpec = formatStr[i + 1];
i++; // Skip the format specifier character
if (argIndex < args.Length)
// Check for %% (literal %)
if (formatStr[i + 1] == '%')
{
newStr += args[argIndex].ToString();
argIndex++;
sb.Append('%');
i++; // Skip the second %
continue;
}
// Parse format specifier: %[flags][width][.precision][length]type
int startPos = i;
i++; // Skip the %
// Track flags
bool hasMinus = false;
bool hasPlus = false;
bool hasZero = false;
// Parse flags: +, -, 0, space
while (i < formatStr.Length && (formatStr[i] == '+' || formatStr[i] == '-' || formatStr[i] == '0' || formatStr[i] == ' '))
{
if (formatStr[i] == '-') hasMinus = true;
if (formatStr[i] == '+') hasPlus = true;
if (formatStr[i] == '0') hasZero = true;
i++;
}
// Parse width: digits
int width = 0;
int widthStart = i;
while (i < formatStr.Length && char.IsDigit(formatStr[i]))
{
i++;
}
if (i > widthStart)
{
int.TryParse(formatStr.Substring(widthStart, i - widthStart), out width);
}
// Skip precision: .digits
if (i < formatStr.Length && formatStr[i] == '.')
{
i++;
while (i < formatStr.Length && char.IsDigit(formatStr[i]))
{
i++;
}
}
// Skip length modifier: h, l, L, etc.
while (i < formatStr.Length && (formatStr[i] == 'h' || formatStr[i] == 'l' || formatStr[i] == 'L'))
{
i++;
}
// Get type specifier
if (i < formatStr.Length)
{
char typeChar = formatStr[i];
// Common types: d, i, u, o, x, X, f, e, E, g, G, c, s, p, n
if ("diouxXeEfFgGaAcspn".IndexOf(typeChar) >= 0)
{
// Extract the full format specifier for special handling
string fullSpec = formatStr.Substring(startPos, i - startPos + 1);
// Check for special formats
string csharpFormatSpec = "";
// Handle %-10d, %-5d, etc. (left-aligned with width) - check this FIRST
// Also handle %-d (left-aligned without explicit width, but width might be 0)
if (hasMinus && (typeChar == 'd' || typeChar == 'i' || typeChar == 'u' || typeChar == 's' || typeChar == 'c'))
{
if (width > 0)
{
// C# left alignment with width: {0,-10} (comma for alignment, negative for left-align)
csharpFormatSpec = $",-{width}";
}
else
{
// Just left alignment flag, no width specified - use default
csharpFormatSpec = "";
}
}
// Handle %02d, %03d, etc. (zero-padded integers) - check before regular width
else if (hasZero && width > 0 && (typeChar == 'd' || typeChar == 'i' || typeChar == 'u'))
{
csharpFormatSpec = $":D{width}";
}
// Handle %10d, %5d, etc. (right-aligned with width, no zero-padding)
else if (width > 0 && (typeChar == 'd' || typeChar == 'i' || typeChar == 'u' || typeChar == 's' || typeChar == 'c'))
{
// C# right alignment: {0,10} (comma for alignment)
csharpFormatSpec = $",{width}";
}
// Handle %+d (signed format)
else if (hasPlus && (typeChar == 'd' || typeChar == 'i'))
{
csharpFormatSpec = ":+0;-0";
}
// Handle %.2f, %.3f, etc. (float precision)
else if (fullSpec.Contains(".") && (typeChar == 'f' || typeChar == 'F' || typeChar == 'e' || typeChar == 'E' || typeChar == 'g' || typeChar == 'G'))
{
int dotPos = fullSpec.IndexOf('.');
if (dotPos >= 0 && dotPos + 1 < fullSpec.Length)
{
int precStart = dotPos + 1;
int precEnd = precStart;
while (precEnd < fullSpec.Length - 1 && char.IsDigit(fullSpec[precEnd]))
{
precEnd++;
}
if (precEnd > precStart && int.TryParse(fullSpec.Substring(precStart, precEnd - precStart), out int precNum))
{
if (typeChar == 'f' || typeChar == 'F')
{
csharpFormatSpec = $":F{precNum}";
}
else if (typeChar == 'e' || typeChar == 'E')
{
csharpFormatSpec = $":E{precNum}";
}
else if (typeChar == 'g' || typeChar == 'G')
{
csharpFormatSpec = $":G{precNum}";
}
}
}
}
// Build replacement - always replace recognized format specifiers
// C# format: {index,alignment} for width, {index:format} for format specifiers
if (csharpFormatSpec.Length > 0)
{
// If format spec starts with comma (alignment) or colon (format), use it directly
// Otherwise, assume it's a format specifier and add colon
if (csharpFormatSpec.StartsWith(",") || csharpFormatSpec.StartsWith(":"))
{
sb.Append($"{{{paramIndex}{csharpFormatSpec}}}");
}
else
{
sb.Append($"{{{paramIndex}:{csharpFormatSpec}}}");
}
}
else
{
sb.Append($"{{{paramIndex}}}");
}
paramIndex++;
// Note: i currently points to the type character (e.g., 'd' in "%-10d")
// The for loop will increment i, so we've consumed the entire format specifier
}
else
{
// Not a recognized format specifier, keep as-is
sb.Append(formatStr[startPos]);
i = startPos; // Reset to process next character
}
}
else
{
// Incomplete format specifier, keep the %
sb.Append('%');
i = startPos; // Reset to process next character
}
}
else
{
newStr += formatStr[i];
sb.Append(formatStr[i]);
}
}
return newStr;
// Use C#'s string.Format (equivalent to original vsprintf)
// Handle case where we might have more format specifiers than arguments
try
{
return string.Format(sb.ToString(), args);
}
catch (System.FormatException)
{
// If format fails (e.g., not enough arguments), return the original format string
// This can happen if GetStringFromTable returns an unexpected format
BMLogger.LogWarning($"Format failed for string: {formatStr}, expected {paramIndex} args, got {args.Length}");
return formatStr;
}
}
#endregion
@@ -5,6 +5,8 @@ namespace BrewMonster.Scripts.UI
{
public class CECUIHelper
{
public static string DlgTaskName = "Win_Quest";
public static A3DVECTOR3 GetTaskObjectCoordinates(int id, ref bool in_table)
{
in_table = false;
@@ -8,6 +8,7 @@ using System.IO;
using System.Linq;
using BrewMonster.Scripts.Task;
using BrewMonster.Scripts.Task.UI;
using BrewMonster.Scripts.UI;
using UnityEngine;
namespace BrewMonster.UI
@@ -117,7 +118,7 @@ namespace BrewMonster.UI
{
base.Init();
m_pDlgTask = GetDialog("Win_Task").GetComponent<DlgTask>();
m_pDlgTask = GetDialog(CECUIHelper.DlgTaskName).GetComponent<DlgTask>();
m_pDlgTask.Show(false);
}
}
+29
View File
@@ -0,0 +1,29 @@
using BrewMonster.Network;
using UnityEngine;
using UnityEngine.UI;
namespace BrewMonster.UI
{
public class JumpBtn : MonoBehaviour
{
Button jumpBtn;
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
if(jumpBtn == null)
{
jumpBtn = GetComponent<Button>();
jumpBtn.onClick.AddListener(OnClickBtnJump);
}
}
private void OnClickBtnJump()
{
if(EC_Game.GetGameRun()?.GetHostPlayer() != null)
{
EC_Game.GetGameRun()?.GetHostPlayer().OnClickBtnJump();
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a6149141837cadc4baae427c4864833e
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8e7328e7267d4c744bffdd93781ac215
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.
+21
View File
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: f6437c7f6dfb42144a799984e8b18fc6
IHVImageFormatImporter:
externalObjects: {}
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
isReadable: 1
sRGBTexture: 1
streamingMipmaps: 0
streamingMipmapsPriority: 0
ignoreMipmapLimit: 0
mipmapLimitGroupName:
userData:
assetBundleName:
assetBundleVariant:
+59
View File
@@ -0,0 +1,59 @@
32
32
7
8
unknown.dds
一键拾取.dds
交易命令.dds
亲亲密密的动作.dds
亲吻.dds
伸懒腰.dds
倒地.dds
冲锋.dds
加速飞行.dds
协助攻击.dds
坐下.dds
坐下站起.dds
大笑.dds
定点传送.dds
害羞.dds
寻找目标.dds
寻找队伍.dds
张望.dds
思考.dds
战斗.dds
打坐.dds
抱拳.dds
招手.dds
拾取.dds
挑衅.dds
挖掘.dds
摆摊买.dds
摆摊卖.dds
摇头.dds
摔倒.dds
攻击1.dds
攻击2.dds
攻击3.dds
攻击4.dds
晕倒.dds
普通攻击.dds
沮丧.dds
滚开.dds
点头.dds
生气.dds
相依相偎的动作.dds
耸肩膀.dds
胜利.dds
脱离队伍.dds
舞蹈1.dds
舞蹈2.dds
走跑转换.dds
跳跃.dds
跳跃的动作1.dds
跳跃的动作2.dds
踢出队伍.dds
邀请加入.dds
防御.dds
飞吻.dds
飞行.dds
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4a842797640137d4a92a75f0c0007a46
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+2 -2
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7828b12fbfdfde737297134cda6d57b867012039352583752e99f3768aa64e48
size 200521545
oid sha256:e4b6387464cc1416f14012251c47b22f28e699e88848f49f62116f827959e1b8
size 200544838
+116 -22
View File
@@ -63,36 +63,114 @@ public class CECUIManager : MonoSingleton<CECUIManager>
}
/// <summary>
/// Lấy hoặc spawn UI mới nếu chưa có
/// Show UI by name of component ("DlgTask", "EC_InventoryUI")
/// </summary>
public T ShowUI<T>() where T : Component
/// <param name="componentName">name of component ("DlgTask", "EC_InventoryUI")</param>
public void ShowUI(string componentName)
{
var type = typeof(T);
if (string.IsNullOrEmpty(componentName) || canvasDlg == null)
{
if (canvasDlg == null) Debug.LogError("canvasDlg chưa được gán");
return;
}
// Nếu đã spawn rồi thì bật lại
if (_spawnedUIs.TryGetValue(type, out var uiGo))
var type = FindTypeByName(componentName);
if (TryShowCachedUI(type)) return;
if (FindUIByName(componentName, type)) return;
if (FindUIByType(type)) return;
Debug.LogWarning($"Không tìm thấy UI {componentName} đã spawn trong canvasDlg. Type found: {(type != null ? type.FullName : "null")}");
}
private System.Type FindTypeByName(string componentName)
{
string[] namespacePrefixes = {
"", // No namespace
"BrewMonster.Scripts.Task.UI.",
"BrewMonster.UI.",
"BrewMonster.Scripts.UI.",
"BrewMonster."
};
// Try with common namespace prefixes
foreach (var prefix in namespacePrefixes)
{
string fullTypeName = string.IsNullOrEmpty(prefix) ? componentName : prefix + componentName;
var type = System.Type.GetType(fullTypeName);
if (type != null) return type;
}
// Search in all assemblies
foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies())
{
var type = assembly.GetType(componentName);
if (type != null) return type;
foreach (var prefix in namespacePrefixes)
{
if (string.IsNullOrEmpty(prefix)) continue;
type = assembly.GetType(prefix + componentName);
if (type != null) return type;
}
}
return null;
}
private bool TryShowCachedUI(System.Type type)
{
if (type != null && _spawnedUIs.TryGetValue(type, out var uiGo))
{
uiGo.SetActive(true);
return uiGo.GetComponent<T>();
return true;
}
// Tìm prefab phù hợp
var prefab = uiPrefabs.Find(p => p.GetComponent<T>() != null);
if (prefab == null)
{
Debug.LogError($"Không tìm thấy prefab chứa component {type.Name}");
return null;
}
// Spawn mới
var instance = Instantiate(prefab, uiRoot ? uiRoot : transform);
instance.name = $"{type.Name}_UI";
_spawnedUIs[type] = instance;
instance.SetActive(true);
return instance.GetComponent<T>();
return false;
}
private bool FindUIByName(string componentName, System.Type type)
{
for (int i = 0; i < canvasDlg.transform.childCount; i++)
{
var child = canvasDlg.transform.GetChild(i);
if (!child.name.Contains(componentName) && child.name != componentName) continue;
if (type != null)
{
var foundComponent = child.GetComponentInChildren(type, true);
if (foundComponent != null)
{
ActivateAndCacheUI(foundComponent.gameObject, type);
return true;
}
}
ActivateAndCacheUI(child.gameObject, type);
return true;
}
return false;
}
private bool FindUIByType(System.Type type)
{
if (type == null) return false;
var foundComponent = canvasDlg.GetComponentInChildren(type, true);
if (foundComponent != null)
{
ActivateAndCacheUI(foundComponent.gameObject, type);
return true;
}
return false;
}
private void ActivateAndCacheUI(GameObject uiGameObject, System.Type type)
{
uiGameObject.SetActive(true);
if (type != null) _spawnedUIs[type] = uiGameObject;
}
/// <summary>
/// Ẩn UI (disable thay vì destroy)
/// </summary>
@@ -143,4 +221,20 @@ public class CECUIManager : MonoSingleton<CECUIManager>
{
return currentTargetNPCID;
}
//todo: change this code to other place
private int slot = 0;
public void OnClickedWaveHand()
{
if (EC_Game.GetGameRun().GetPoseCmdShortcuts() == null)
{
EC_Game.GetGameRun().StartGame(0, Vector3.zero);
}
CECShortcut pSC = EC_Game.GetGameRun().GetPoseCmdShortcuts().GetShortcut(slot);
if (pSC != null) // && pObjSrc->GetDataPtr("ptr_CECShortcut") == pSC
{
// a_LogOutput(1, "[Dat Emote] ptr_CECShortcut");
pSC.Execute();
}
}
}
+3
View File
@@ -1,3 +1,4 @@
using System;
using Animancer;
using BrewMonster;
using System.Collections.Generic;
@@ -150,6 +151,7 @@ namespace BrewMonster
return namedAnimancer.States.TryGet("ActionName", out var existingState) ? true : false;
}
private string _currentAnimationName;
/// <summary>
/// play an animation with name
/// </summary>
@@ -159,6 +161,7 @@ namespace BrewMonster
private void InternalPlayAnimation(string animationName, float duration = FadeTime, FadeMode fadeMode = FadeMode)
{
_currentState = namedAnimancer.TryPlay(animationName, duration, fadeMode);
_currentAnimationName = animationName;
if (_currentState == null)
{
BMLogger.LogError($"Null animation with name: {animationName}");