diff --git a/AIClient/Assets/AOT/Scripts/Boot/BootContext.cs b/AIClient/Assets/AOT/Scripts/Boot/BootContext.cs index 3f7ae64..effffc8 100644 --- a/AIClient/Assets/AOT/Scripts/Boot/BootContext.cs +++ b/AIClient/Assets/AOT/Scripts/Boot/BootContext.cs @@ -14,6 +14,8 @@ namespace AOT.Boot public ResourcePackage Package; public string HttpBase; public string WsUrlTemplate; + /// CDN version.json 下发的维护/公告文案(可空)。 + public string Notice; public string BuildWsUrl(string pid, string token = null) { diff --git a/AIClient/Assets/AOT/Scripts/Patch/PatchRunner.cs b/AIClient/Assets/AOT/Scripts/Patch/PatchRunner.cs index ba803ff..424cea1 100644 --- a/AIClient/Assets/AOT/Scripts/Patch/PatchRunner.cs +++ b/AIClient/Assets/AOT/Scripts/Patch/PatchRunner.cs @@ -76,6 +76,7 @@ namespace AOT.Patch PackageName = _settings.PackageName, HttpBase = _settings.HttpBase, WsUrlTemplate = _settings.WsUrlTemplate, + Notice = version.notice ?? string.Empty, }; #if UNITY_EDITOR diff --git a/AIClient/Assets/Bundles/UI/Prefab/UI_MainHUD.prefab b/AIClient/Assets/Bundles/UI/Prefab/UI_MainHUD.prefab new file mode 100644 index 0000000..7603255 --- /dev/null +++ b/AIClient/Assets/Bundles/UI/Prefab/UI_MainHUD.prefab @@ -0,0 +1,1008 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &460797603982996346 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7730827228363657464} + - component: {fileID: 2334139040100248130} + - component: {fileID: 3869050331437791704} + m_Layer: 5 + m_Name: Txt_Pid + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7730827228363657464 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 460797603982996346} + 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: 2242128005828497145} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 32, y: 12} + m_SizeDelta: {x: -64, y: 36} + m_Pivot: {x: 0, y: 0} +--- !u!222 &2334139040100248130 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 460797603982996346} + m_CullTransparentMesh: 1 +--- !u!114 &3869050331437791704 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 460797603982996346} + 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: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: pid=- + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_sharedMaterial: {fileID: 5611925709654428781, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 0.41960785, g: 0.47843137, b: 0.5803922, 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: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 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 &2139845303954628944 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2242128005828497145} + - component: {fileID: 5759702587571134512} + - component: {fileID: 5359430117706543608} + m_Layer: 5 + m_Name: Panel_Top + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2242128005828497145 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2139845303954628944} + 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: 4186877448492237329} + - {fileID: 7730827228363657464} + m_Father: {fileID: 8677056097743690897} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -48} + m_SizeDelta: {x: -48, y: 120} + m_Pivot: {x: 0.5, y: 1} +--- !u!222 &5759702587571134512 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2139845303954628944} + m_CullTransparentMesh: 1 +--- !u!114 &5359430117706543608 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2139845303954628944} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 4f287db2d8305124496d081b76d27108, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &2663585961588924483 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5193014396614657597} + - component: {fileID: 7276666803253700227} + - component: {fileID: 3952976191023965998} + - component: {fileID: 6665361437463121796} + m_Layer: 5 + m_Name: Btn_Reconnect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5193014396614657597 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2663585961588924483} + 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: 285556268111638460} + - {fileID: 9016108391211242120} + m_Father: {fileID: 662179378109749861} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 20} + m_SizeDelta: {x: 280, y: 72} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &7276666803253700227 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2663585961588924483} + m_CullTransparentMesh: 1 +--- !u!114 &3952976191023965998 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2663585961588924483} + 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: 2bd3ecd2b48fb48439ae100de6dfbc17, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &6665361437463121796 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2663585961588924483} + 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: 2 + 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: 21300000, guid: a5202d3917469b2459b40752425c86c7, type: 3} + 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: 3952976191023965998} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &3013483319344693606 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9016108391211242120} + - component: {fileID: 4873998901801764110} + - component: {fileID: 8764072142772560960} + m_Layer: 5 + m_Name: Img_Refresh + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9016108391211242120 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3013483319344693606} + 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: 5193014396614657597} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 18, y: 0} + m_SizeDelta: {x: 40, y: 40} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &4873998901801764110 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3013483319344693606} + m_CullTransparentMesh: 1 +--- !u!114 &8764072142772560960 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3013483319344693606} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: b74192f47f43f1b4482456ff01660fa2, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &4897643613311026605 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 285556268111638460} + - component: {fileID: 5206747687785316839} + - component: {fileID: 5602179459981010253} + - component: {fileID: 5807937397560875847} + m_Layer: 5 + m_Name: Txt_ReconnectBtn + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &285556268111638460 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4897643613311026605} + 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: 5193014396614657597} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5206747687785316839 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4897643613311026605} + m_CullTransparentMesh: 1 +--- !u!114 &5602179459981010253 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4897643613311026605} + 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: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\u7ACB\u5373\u91CD\u8FDE" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_sharedMaterial: {fileID: 5611925709654428781, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 0.9647059, g: 0.972549, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 30 + m_fontSizeBase: 30 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + 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!114 &5807937397560875847 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4897643613311026605} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3} + m_Name: + m_EditorClassIdentifier: + m_EffectColor: {r: 0.0627451, g: 0.1254902, b: 0.2, a: 0.6666667} + m_EffectDistance: {x: 1, y: -1} + m_UseGraphicAlpha: 1 +--- !u!1 &5195829611681316965 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8677056097743690897} + - component: {fileID: 5797074032734061021} + - component: {fileID: 8741096623280260221} + - component: {fileID: 4865469745670512880} + m_Layer: 5 + m_Name: UI_MainHUD + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8677056097743690897 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5195829611681316965} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2242128005828497145} + - {fileID: 662179378109749861} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!223 &5797074032734061021 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5195829611681316965} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 100 + m_TargetDisplay: 0 +--- !u!114 &8741096623280260221 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5195829611681316965} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1080, y: 1920} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!114 &4865469745670512880 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5195829611681316965} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!1 &5732501102358565599 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 383972731224049858} + - component: {fileID: 602880114330251131} + - component: {fileID: 3752665336687601317} + m_Layer: 5 + m_Name: Txt_Reconnect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &383972731224049858 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5732501102358565599} + 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: 662179378109749861} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.45} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -4} + m_SizeDelta: {x: -56, y: -24} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &602880114330251131 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5732501102358565599} + m_CullTransparentMesh: 1 +--- !u!114 &3752665336687601317 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5732501102358565599} + 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: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\u7F51\u7EDC\u5DF2\u65AD\u5F00\uFF0C\u6B63\u5728\u91CD\u8FDE\u2026" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_sharedMaterial: {fileID: 5611925709654428781, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 0.2, g: 0.2509804, b: 0.36862746, 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: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 28 + m_fontSizeBase: 28 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 0 + m_fontSizeMax: 0 + 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_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + 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 &6318453500659261406 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4186877448492237329} + - component: {fileID: 1280054712357709747} + - component: {fileID: 8891591731888126757} + m_Layer: 5 + m_Name: Txt_Status + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4186877448492237329 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6318453500659261406} + 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: 2242128005828497145} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -12} + m_SizeDelta: {x: -64, y: -56} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1280054712357709747 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6318453500659261406} + m_CullTransparentMesh: 1 +--- !u!114 &8891591731888126757 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6318453500659261406} + 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: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\u8FDE\u63A5\u4E2D\u2026" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_sharedMaterial: {fileID: 5611925709654428781, guid: 458a790a87124264e89ea7794a185fd7, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 0.3529412, g: 0.27450982, 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: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 30 + m_fontSizeBase: 30 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 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 &8911644127381137875 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 662179378109749861} + - component: {fileID: 5641305213948438559} + - component: {fileID: 1120346803213727709} + m_Layer: 5 + m_Name: Panel_Reconnect + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &662179378109749861 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8911644127381137875} + 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: 383972731224049858} + - {fileID: 5193014396614657597} + m_Father: {fileID: 8677056097743690897} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0} + m_AnchorMax: {x: 0.5, y: 0} + m_AnchoredPosition: {x: 0, y: 160} + m_SizeDelta: {x: 920, y: 160} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &5641305213948438559 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8911644127381137875} + m_CullTransparentMesh: 1 +--- !u!114 &1120346803213727709 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8911644127381137875} + 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: de28225333fbda148ad489f59ba551d2, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 diff --git a/AIClient/Assets/Bundles/UI/Prefab/UI_MainHUD.prefab.meta b/AIClient/Assets/Bundles/UI/Prefab/UI_MainHUD.prefab.meta new file mode 100644 index 0000000..e982cec --- /dev/null +++ b/AIClient/Assets/Bundles/UI/Prefab/UI_MainHUD.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f09133b5784dac24eaf495f342e7344e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/HotUpdate/Scripts/Entry.cs b/AIClient/Assets/HotUpdate/Scripts/Entry.cs index 27738d4..eef323e 100644 --- a/AIClient/Assets/HotUpdate/Scripts/Entry.cs +++ b/AIClient/Assets/HotUpdate/Scripts/Entry.cs @@ -1,7 +1,7 @@ using AOT.Boot; +using HotUpdate.Gameplay; using HotUpdate.Net; using UnityEngine; -using UnityEngine.UI; namespace HotUpdate { @@ -23,8 +23,6 @@ namespace HotUpdate public sealed class HotUpdateBootstrap : MonoBehaviour { BootContext _ctx; - GameNet _net; - Text _hud; public void Bind(BootContext ctx) { @@ -34,53 +32,14 @@ namespace HotUpdate void Start() { Debug.Log($"[HotUpdate] Bootstrap ready. CDN={_ctx?.CdnRoot}"); - EnsureHud(); - // M3:示例角色(与网络并行,不依赖 WS) - var spawner = gameObject.AddComponent(); - spawner.Bind(_ctx); - spawner.Spawn(); + var net = gameObject.AddComponent(); + net.Bind(_ctx); - _net = gameObject.AddComponent(); - _net.Bind(_ctx); - _net.OnStatus += s => - { - if (_hud != null) _hud.text = s; - }; - _net.OnWsReady += () => - { - if (_hud != null) - _hud.text = $"WS OK pid={_net.Session?.Pid} | MaleExplorer"; - Debug.Log($"[HotUpdate] M2 WS ready pid={_net.Session?.Pid}"); - }; - _net.StartGuestSession(); - } + var gameplay = gameObject.AddComponent(); + gameplay.Bind(_ctx, net); - void EnsureHud() - { - var canvasGo = new GameObject("NetHud"); - canvasGo.transform.SetParent(transform, false); - var canvas = canvasGo.AddComponent(); - canvas.renderMode = RenderMode.ScreenSpaceOverlay; - canvas.sortingOrder = 200; - var scaler = canvasGo.AddComponent(); - scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; - scaler.referenceResolution = new Vector2(1080, 1920); - canvasGo.AddComponent(); - - var textGo = new GameObject("Status"); - textGo.transform.SetParent(canvasGo.transform, false); - _hud = textGo.AddComponent(); - _hud.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); - _hud.fontSize = 28; - _hud.color = Color.white; - _hud.alignment = TextAnchor.LowerCenter; - var rt = textGo.GetComponent(); - rt.anchorMin = new Vector2(0.05f, 0.08f); - rt.anchorMax = new Vector2(0.95f, 0.16f); - rt.offsetMin = Vector2.zero; - rt.offsetMax = Vector2.zero; - _hud.text = "net…"; + net.StartGuestSession(); } } } diff --git a/AIClient/Assets/HotUpdate/Scripts/Gameplay.meta b/AIClient/Assets/HotUpdate/Scripts/Gameplay.meta new file mode 100644 index 0000000..4ea97d4 --- /dev/null +++ b/AIClient/Assets/HotUpdate/Scripts/Gameplay.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e3ffadd6f9ceffd42afecebdd7ac5f22 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/HotUpdate/Scripts/Gameplay/GameplayBootstrap.cs b/AIClient/Assets/HotUpdate/Scripts/Gameplay/GameplayBootstrap.cs new file mode 100644 index 0000000..0d68641 --- /dev/null +++ b/AIClient/Assets/HotUpdate/Scripts/Gameplay/GameplayBootstrap.cs @@ -0,0 +1,125 @@ +using AOT.Boot; +using HotUpdate.Net; +using HotUpdate.UI; +using UnityEngine; + +namespace HotUpdate.Gameplay +{ + /// + /// M4 玩法骨架:挂 HUD、角色、网络状态;处理公告与断线重连提示。 + /// + public sealed class GameplayBootstrap : MonoBehaviour + { + BootContext _ctx; + GameNet _net; + MainHudView _hud; + ConfirmDialogView _dialog; + bool _maintenanceLock; + + public void Bind(BootContext ctx, GameNet net) + { + _ctx = ctx; + _net = net; + } + + void Start() + { + EnsureUi(); + WireNet(); + MaybeShowBootNotice(); + + var spawner = gameObject.AddComponent(); + spawner.Bind(_ctx); + spawner.Spawn(); + } + + void EnsureUi() + { + var uiRoot = new GameObject("UiRoot"); + DontDestroyOnLoad(uiRoot); + var mgr = uiRoot.AddComponent(); + mgr.Init(uiRoot.transform, new UiPrefabLoader()); + + var hudGo = mgr.Open(MainHudView.PrefabName); + _hud = hudGo != null ? hudGo.GetComponent() : null; + if (_hud == null && hudGo != null) + _hud = hudGo.AddComponent(); + _hud?.Bind(); + _hud?.SetStatus("启动中…"); + if (_hud != null) + _hud.OnReconnectClicked += () => _net?.RequestReconnect(); + + var dlgGo = mgr.Open(ConfirmDialogView.PrefabName); + if (dlgGo != null) + { + dlgGo.SetActive(false); + _dialog = dlgGo.GetComponent(); + if (_dialog == null) _dialog = dlgGo.AddComponent(); + _dialog.Bind(); + } + } + + void WireNet() + { + if (_net == null) return; + _net.OnStatus += s => _hud?.SetStatus(s); + _net.OnAuthed += session => _hud?.SetPid(session != null ? session.Pid : 0); + _net.OnWsReady += () => + { + if (_maintenanceLock) return; + _hud?.ShowReconnect(false); + _hud?.SetStatus("已连接"); + }; + _net.OnWsDisconnected += reason => + { + if (_maintenanceLock) return; + _hud?.ShowReconnect(true, $"网络已断开({reason}),正在重连…"); + }; + _net.OnReconnecting += attempt => + { + if (_maintenanceLock) return; + _hud?.ShowReconnect(true, $"正在重连…(第 {attempt} 次)"); + }; + _net.OnMaintenance += msg => + { + _maintenanceLock = true; + _hud?.ShowReconnect(false); + _hud?.SetStatus("服务器维护中"); + _dialog?.Show("维护公告", string.IsNullOrEmpty(msg) ? "服务器维护中,请稍后再试。" : msg); + }; + _net.OnWsMessage += TryHandleProtocol; + } + + void MaybeShowBootNotice() + { + if (_ctx == null || string.IsNullOrEmpty(_ctx.Notice)) return; + _dialog?.Show("公告", _ctx.Notice); + } + + void TryHandleProtocol(string json) + { + if (string.IsNullOrEmpty(json)) return; + // 轻量解析,避免引入完整 JSON 库依赖 + if (json.IndexOf("\"op\":\"maintenance\"", System.StringComparison.Ordinal) >= 0 || + json.IndexOf("\"op\": \"maintenance\"", System.StringComparison.Ordinal) >= 0) + { + var msg = ExtractJsonString(json, "message"); + _net?.NotifyMaintenance(msg); + } + } + + static string ExtractJsonString(string json, string key) + { + var token = $"\"{key}\""; + var i = json.IndexOf(token, System.StringComparison.Ordinal); + if (i < 0) return null; + i = json.IndexOf(':', i); + if (i < 0) return null; + i = json.IndexOf('"', i + 1); + if (i < 0) return null; + var j = json.IndexOf('"', i + 1); + if (j < 0) return null; + return json.Substring(i + 1, j - i - 1); + } + } +} diff --git a/AIClient/Assets/HotUpdate/Scripts/Gameplay/GameplayBootstrap.cs.meta b/AIClient/Assets/HotUpdate/Scripts/Gameplay/GameplayBootstrap.cs.meta new file mode 100644 index 0000000..82edeb1 --- /dev/null +++ b/AIClient/Assets/HotUpdate/Scripts/Gameplay/GameplayBootstrap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad4b87bb9c63c5c47a24a609988b37b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/HotUpdate/Scripts/HotUpdate.Runtime.asmdef b/AIClient/Assets/HotUpdate/Scripts/HotUpdate.Runtime.asmdef index 697bf76..a9d1d2d 100644 --- a/AIClient/Assets/HotUpdate/Scripts/HotUpdate.Runtime.asmdef +++ b/AIClient/Assets/HotUpdate/Scripts/HotUpdate.Runtime.asmdef @@ -4,7 +4,8 @@ "references": [ "AOT.Runtime", "YooAsset", - "UnityEngine.UI" + "UnityEngine.UI", + "Unity.TextMeshPro" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/AIClient/Assets/HotUpdate/Scripts/Net/GameNet.cs b/AIClient/Assets/HotUpdate/Scripts/Net/GameNet.cs index 400c0b7..79c2305 100644 --- a/AIClient/Assets/HotUpdate/Scripts/Net/GameNet.cs +++ b/AIClient/Assets/HotUpdate/Scripts/Net/GameNet.cs @@ -6,7 +6,7 @@ using UnityEngine; namespace HotUpdate.Net { /// - /// 登录 → WS 连接编排。 + /// 登录 → WS 连接编排(含指数退避重连与维护公告)。 /// public sealed class GameNet : MonoBehaviour { @@ -21,9 +21,14 @@ namespace HotUpdate.Net public event Action OnWsReady; public event Action OnStatus; public event Action OnWsMessage; + public event Action OnWsDisconnected; + public event Action OnReconnecting; + public event Action OnMaintenance; BootContext _boot; bool _started; + bool _maintenance; + bool _everConnected; public void Bind(BootContext boot) { @@ -35,7 +40,6 @@ namespace HotUpdate.Net if (!string.IsNullOrEmpty(_boot.WsUrlTemplate)) { - // 旧模板只有 pid 时补上 token var tpl = _boot.WsUrlTemplate; if (!tpl.Contains("{token}")) { @@ -54,11 +58,37 @@ namespace HotUpdate.Net StartCoroutine(RunGuestFlow()); } + /// UI「立即重连」:重置退避并马上再连。 + public void RequestReconnect() + { + if (_maintenance || Session == null || !Session.IsValid) return; + SetStatus("手动重连…"); + if (Socket != null) + { + Socket.AutoReconnect = true; + Socket.ForceReconnect(); + } + else + StartCoroutine(ConnectWs()); + } + + public void NotifyMaintenance(string message) + { + if (_maintenance) return; + _maintenance = true; + if (Socket != null) + { + Socket.AutoReconnect = false; + Socket.Close(); + } + SetStatus("maintenance"); + OnMaintenance?.Invoke(message ?? "服务器维护中"); + } + IEnumerator RunGuestFlow() { SetStatus("auth…"); var deviceId = DeviceId.GetOrCreate(); - // 服务器要求 username/password;编辑器自动账号 var username = $"guest_{deviceId}"; var password = $"pw_{deviceId}"; @@ -89,6 +119,7 @@ namespace HotUpdate.Net IEnumerator ConnectWs() { + if (_maintenance) yield break; if (Session == null || !Session.IsValid) { SetStatus("no session"); @@ -99,14 +130,13 @@ namespace HotUpdate.Net Socket?.Dispose(); Socket = new WsClient(); Socket.AutoReconnect = true; - Socket.OnConnected += () => + Socket.OnConnected += HandleConnected; + Socket.OnDisconnected += HandleDisconnected; + Socket.OnReconnecting += attempt => { - SetStatus("ws connected"); - OnWsReady?.Invoke(); - // 应用层握手(服务端当前可无响应,保留扩展) - Socket.SendText($"{{\"op\":\"hello\",\"proto\":1,\"app\":\"{_boot?.AppVersion}\",\"res\":\"{_boot?.ResVersion}\",\"pid\":{Session.Pid}}}"); + SetStatus($"ws reconnecting #{attempt}"); + OnReconnecting?.Invoke(attempt); }; - Socket.OnDisconnected += reason => SetStatus($"ws down: {reason}"); Socket.OnMessage += msg => { Debug.Log($"[GameNet] << {msg}"); @@ -116,7 +146,6 @@ namespace HotUpdate.Net var url = Session.BuildWsUrl(WsUrlTemplate); Socket.Connect(url); - // 等待最多 15s float t = 0f; while (t < 15f && Socket.State != WsState.Connected && Socket.State != WsState.Disconnected) { @@ -132,6 +161,28 @@ namespace HotUpdate.Net SetStatus($"ws state={Socket.State}"); } + void HandleConnected() + { + if (_maintenance) return; + SetStatus(_everConnected ? "ws reconnected" : "ws connected"); + _everConnected = true; + SendHello(); + OnWsReady?.Invoke(); + } + + void HandleDisconnected(string reason) + { + SetStatus($"ws down: {reason}"); + OnWsDisconnected?.Invoke(reason ?? "closed"); + } + + void SendHello() + { + if (Socket == null || Session == null) return; + Socket.SendText( + $"{{\"op\":\"hello\",\"proto\":1,\"app\":\"{_boot?.AppVersion}\",\"res\":\"{_boot?.ResVersion}\",\"pid\":{Session.Pid}}}"); + } + void Update() { Socket?.Tick(); diff --git a/AIClient/Assets/HotUpdate/Scripts/Net/WsClient.cs b/AIClient/Assets/HotUpdate/Scripts/Net/WsClient.cs index abbcc3b..b450bdc 100644 --- a/AIClient/Assets/HotUpdate/Scripts/Net/WsClient.cs +++ b/AIClient/Assets/HotUpdate/Scripts/Net/WsClient.cs @@ -38,6 +38,7 @@ namespace HotUpdate.Net public event Action OnConnected; public event Action OnDisconnected; public event Action OnMessage; + public event Action OnReconnecting; public bool AutoReconnect { get; set; } = true; public float KeepAliveSeconds { get; set; } = 20f; @@ -50,6 +51,20 @@ namespace HotUpdate.Net _ = ConnectInternalAsync(); } + /// 立刻断开并重新连接(重置退避计数)。 + public void ForceReconnect() + { + if (string.IsNullOrEmpty(_url)) return; + _manualClose = false; + AutoReconnect = true; + _reconnectAttempt = 0; + SafeCancel(); + try { _ws?.Dispose(); } catch { /* ignore */ } + _ws = null; + State = WsState.Disconnected; + _ = ConnectInternalAsync(); + } + public void SendText(string text) { if (string.IsNullOrEmpty(text)) return; @@ -119,6 +134,7 @@ namespace HotUpdate.Net _reconnectAttempt++; int delayMs = Math.Min(30000, 1000 * (1 << Math.Min(5, _reconnectAttempt))); Debug.Log($"[WsClient] reconnect in {delayMs}ms attempt={_reconnectAttempt}"); + OnReconnecting?.Invoke(_reconnectAttempt); try { await Task.Delay(delayMs, CancellationToken.None); diff --git a/AIClient/Assets/HotUpdate/Scripts/UI.meta b/AIClient/Assets/HotUpdate/Scripts/UI.meta new file mode 100644 index 0000000..d3a6112 --- /dev/null +++ b/AIClient/Assets/HotUpdate/Scripts/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a790887f85681a4a84ab4e02373106a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/HotUpdate/Scripts/UI/ConfirmDialogView.cs b/AIClient/Assets/HotUpdate/Scripts/UI/ConfirmDialogView.cs new file mode 100644 index 0000000..91d4343 --- /dev/null +++ b/AIClient/Assets/HotUpdate/Scripts/UI/ConfirmDialogView.cs @@ -0,0 +1,77 @@ +using System; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +namespace HotUpdate.UI +{ + /// + /// UI_ConfirmDialog:公告 / 维护 / 通用确认。 + /// + public sealed class ConfirmDialogView : MonoBehaviour + { + public const string PrefabName = "UI_ConfirmDialog"; + + TextMeshProUGUI _title; + TextMeshProUGUI _message; + Button _ok; + Button _cancel; + Button _close; + Action _onOk; + Action _onCancel; + + public void Bind() + { + _title = FindTmp("Txt_Title"); + _message = FindTmp("Txt_Message"); + _ok = FindBtn("Btn_Ok"); + _cancel = FindBtn("Btn_Cancel"); + _close = FindBtn("Btn_Close"); + + Wire(_ok, () => { _onOk?.Invoke(); Hide(); }); + Wire(_cancel, () => { _onCancel?.Invoke(); Hide(); }); + Wire(_close, () => { _onCancel?.Invoke(); Hide(); }); + } + + public void Show( + string title, + string message, + Action onOk = null, + Action onCancel = null, + bool showCancel = false) + { + if (_title != null) _title.text = title ?? string.Empty; + if (_message != null) _message.text = message ?? string.Empty; + _onOk = onOk; + _onCancel = onCancel; + if (_cancel != null) _cancel.gameObject.SetActive(showCancel); + gameObject.SetActive(true); + } + + public void Hide() + { + gameObject.SetActive(false); + } + + static void Wire(Button btn, Action action) + { + if (btn == null) return; + btn.onClick.RemoveAllListeners(); + btn.onClick.AddListener(() => action?.Invoke()); + } + + TextMeshProUGUI FindTmp(string name) + { + foreach (var c in GetComponentsInChildren(true)) + if (c.name == name) return c; + return null; + } + + Button FindBtn(string name) + { + foreach (var c in GetComponentsInChildren