class_name GameSceneBootstrap extends RefCounted # GameScene 的组合根: # - 只负责 new 服务/状态/规则/UI 面板并完成依赖注入。 # - 业务运行时不要在这里写逻辑;新增功能应先落到 service/state/domain/ui/panels 对应模块。 # - 返回 Dictionary 是为了兼容当前主场景字段,后续可逐步替换成显式场景上下文对象。 const ApiClientScript := preload("res://scripts/services/api_client.gd") const GameConfigCatalogScript := preload("res://scripts/core/game_config_catalog.gd") const AtlasTextureCacheScript := preload("res://scripts/resources/atlas_texture_cache.gd") const PlayerStateScript := preload("res://scripts/state/player_state.gd") const FarmStateScript := preload("res://scripts/state/farm_state.gd") const InventoryStateScript := preload("res://scripts/state/inventory_state.gd") const PlayerInventoryFacadeScript := preload("res://scripts/state/player_inventory_facade.gd") const CropPhaseRulesScript := preload("res://scripts/domain/rules/crop_phase_rules.gd") const LandActionRulesScript := preload("res://scripts/domain/rules/land_action_rules.gd") const FarmMapperScript := preload("res://scripts/domain/mappers/farm_mapper.gd") const InventoryMapperScript := preload("res://scripts/domain/mappers/inventory_mapper.gd") const FarmApiScript := preload("res://scripts/services/farm_api.gd") const InventoryApiScript := preload("res://scripts/services/inventory_api.gd") const BuildingApiScript := preload("res://scripts/services/building_api.gd") const ShopApiScript := preload("res://scripts/services/shop_api.gd") const WarehouseApiScript := preload("res://scripts/services/warehouse_api.gd") const DealApiScript := preload("res://scripts/services/deal_api.gd") const FriendApiScript := preload("res://scripts/services/friend_api.gd") const InteractionApiScript := preload("res://scripts/services/interaction_api.gd") const ActivityApiScript := preload("res://scripts/services/activity_api.gd") const PetApiScript := preload("res://scripts/services/pet_api.gd") const PayApiScript := preload("res://scripts/services/pay_api.gd") const FarmControllerScript := preload("res://scripts/farm/farm_controller.gd") const FriendVisitControllerScript := preload("res://scripts/farm/friend_visit_controller.gd") const GameSceneContextScript := preload("res://scripts/ui/game_scene_context.gd") const IconTextureProviderScript := preload("res://scripts/ui/common/icon_texture_provider.gd") const TextureProviderScript := preload("res://scripts/ui/common/texture_provider.gd") const UiBuilderScript := preload("res://scripts/ui/common/ui_builder.gd") const GameScenePanelRouterScript := preload("res://scripts/ui/game_scene_panel_router.gd") const ShopPanelScript := preload("res://scripts/ui/panels/shop_panel.gd") const WarehousePanelScript := preload("res://scripts/ui/panels/warehouse_panel.gd") const FriendPanelScript := preload("res://scripts/ui/panels/friend_panel.gd") const BuildingPanelScript := preload("res://scripts/ui/panels/building_panel.gd") const LogPanelScript := preload("res://scripts/ui/panels/log_panel.gd") const NoticePanelScript := preload("res://scripts/ui/panels/notice_panel.gd") const LevelGiftPanelScript := preload("res://scripts/ui/panels/level_gift_panel.gd") const OnlineGiftPanelScript := preload("res://scripts/ui/panels/online_gift_panel.gd") const PayPanelScript := preload("res://scripts/ui/panels/pay_panel.gd") const GoldExchangePanelScript := preload("res://scripts/ui/panels/gold_exchange_panel.gd") const MarketPanelScript := preload("res://scripts/ui/panels/market_panel.gd") const SignPanelScript := preload("res://scripts/ui/panels/sign_panel.gd") const LotteryPanelScript := preload("res://scripts/ui/panels/lottery_panel.gd") const PetPanelScript := preload("res://scripts/ui/panels/pet_panel.gd") const PlayerInfoPanelScript := preload("res://scripts/ui/panels/player_info_panel.gd") func setup(options: Dictionary) -> Dictionary: # owner 是唯一持有 Godot 节点生命周期的对象,其它 RefCounted 模块只通过回调访问场景。 var owner := options.get("owner") as Node var player_data: Dictionary = options.get("player_data", {}) var panel_screen_size: Vector2 = options.get("panel_screen_size", Vector2(640.0, 960.0)) var constants: Dictionary = options.get("constants", {}) var paths: Dictionary = options.get("paths", {}) var textures: Dictionary = options.get("textures", {}) var panel_router = GameScenePanelRouterScript.new() panel_router.setup({ "owner": owner, "callbacks": { "hide_selection_ui": Callable(owner, "_hide_selection_ui"), "set_scene_hit_layers_enabled": Callable(owner, "_set_scene_hit_layers_enabled"), "refresh_store_house": Callable(owner, "_refresh_store_house"), "is_operation_in_progress": Callable(owner, "_is_operation_in_progress"), }, }) var game_config = GameConfigCatalogScript.new() var api_client = ApiClientScript.new() if owner != null: # HTTPRequest 需要挂到场景树;其它纯逻辑模块保持 RefCounted,减少节点数量。 owner.add_child(api_client) var atlas_cache = AtlasTextureCacheScript.new() var icon_texture_provider = IconTextureProviderScript.new() var texture_provider = TextureProviderScript.new() texture_provider.setup(atlas_cache, options.get("atlas_paths", {}), null, icon_texture_provider) var ui_builder = UiBuilderScript.new() ui_builder.setup({ "owner": owner, "panel_screen_size": panel_screen_size, "font": options.get("font"), "fonts": options.get("fonts", {}), "texture_provider": texture_provider, "close_modal_callback": Callable(panel_router, "close_modal_panel"), "get_item_icon_texture": Callable(texture_provider, "item_icon"), "get_item_icon_id": Callable(owner, "_item_icon_id"), }) var player_state = PlayerStateScript.new() player_state.setup(player_data, game_config) var farm_state = FarmStateScript.new() var inventory_state = InventoryStateScript.new() var crop_phase_rules = CropPhaseRulesScript.new(game_config) var land_action_rules = LandActionRulesScript.new(crop_phase_rules) var farm_mapper = FarmMapperScript.new(game_config, crop_phase_rules) var inventory_mapper = InventoryMapperScript.new(game_config) var farm_api = FarmApiScript.new(api_client) var inventory_api = InventoryApiScript.new(api_client) var building_api = BuildingApiScript.new(api_client) var shop_api = ShopApiScript.new(api_client) var warehouse_api = WarehouseApiScript.new(api_client) var deal_api = DealApiScript.new(api_client) var friend_api = FriendApiScript.new(api_client) var interaction_api = InteractionApiScript.new(api_client) var activity_api = ActivityApiScript.new(api_client) var pet_api = PetApiScript.new(api_client) var pay_api = PayApiScript.new(api_client) var inventory_facade = PlayerInventoryFacadeScript.new() inventory_facade.setup({ "player_state": player_state, "inventory_state": inventory_state, "inventory_mapper": inventory_mapper, "inventory_api": inventory_api, "game_config": game_config, "item_id_gem": int(constants.get("item_id_gem", 105001)), "item_id_gold": int(constants.get("item_id_gold", 105002)), "item_id_stone": int(constants.get("item_id_stone", 201000)), "item_id_steel": int(constants.get("item_id_steel", 201001)), "callbacks": { # Facade 只通知主场景同步和局部重绘,不直接持有具体面板节点。 "inventory_changed": Callable(owner, "_sync_inventory_from_facade"), "render_player": Callable(owner, "_render_player"), "should_render_bag": Callable(owner, "_should_render_bag"), "render_bag": Callable(owner, "_render_bag"), "should_render_warehouse": Callable(panel_router, "should_render_warehouse"), "render_warehouse": Callable(panel_router, "render_warehouse_tab"), }, }) var context = GameSceneContextScript.new() context.setup({ "owner": owner, "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "player_state": player_state, "inventory_facade": inventory_facade, "panel_router": panel_router, "constants": constants, }) var panel_callbacks: Dictionary = options.get("panel_callbacks", {}) if panel_callbacks.is_empty(): panel_callbacks = context.legacy_callbacks() var farm_controller = FarmControllerScript.new() farm_controller.setup({ "farm_api": farm_api, "farm_mapper": farm_mapper, "disease_type_bug": int(constants.get("disease_type_bug", 1)), "disease_type_grass": int(constants.get("disease_type_grass", 2)), "disease_type_water": int(constants.get("disease_type_water", 0)), "item_id_bug_killer": int(constants.get("item_id_bug_killer", 108001)), "item_id_grass_killer": int(constants.get("item_id_grass_killer", 109001)), "callbacks": { # FarmController 只处理土地后端操作;选中位置、UI 隐藏和经验变化仍由主场景提供。 "selected_position": Callable(owner, "_get_selected_position"), "token": Callable(owner, "_token"), "land_data": Callable(owner, "_get_land_data"), "is_operation_in_progress": Callable(owner, "_is_operation_in_progress"), "set_operation_in_progress": Callable(owner, "_set_operation_in_progress"), "apply_land_data": Callable(owner, "_apply_land_data"), "decrease_seed_item": Callable(owner, "_decrease_seed_item"), "decrease_fertilizer_item": Callable(owner, "_decrease_fertilizer_item"), "decrease_warehouse_item": Callable(owner, "_decrease_warehouse_item"), "hide_bag_panel": Callable(owner, "_hide_bag_panel"), "hide_land_light": Callable(owner, "_hide_land_light"), "hide_selection_ui": Callable(owner, "_hide_selection_ui"), "render_lands": Callable(owner, "_render_lands"), "refresh_store_house": Callable(owner, "_refresh_store_house"), "add_player_exp": Callable(owner, "_add_player_exp"), "add_reward_items": Callable(owner, "_add_reward_items"), "show_plant_tip": Callable(owner, "_show_plant_tip"), "show_toast": Callable(owner, "_show_toast"), "response_status_text": Callable(owner, "_response_status_text"), }, }) var friend_visit_controller = FriendVisitControllerScript.new() friend_visit_controller.setup({ "interaction_api": interaction_api, "game_config": game_config, "crop_phase_rules": crop_phase_rules, "callbacks": { "selected_position": Callable(owner, "_get_selected_position"), "token": Callable(owner, "_token"), "player_id": Callable(owner, "_player_id"), "visited_friend_id": Callable(owner, "_current_visited_friend_id"), "land_data": Callable(owner, "_get_land_data"), "is_visiting_friend": Callable(owner, "_is_visiting_friend"), "is_operation_in_progress": Callable(owner, "_is_operation_in_progress"), "set_operation_in_progress": Callable(owner, "_set_operation_in_progress"), "enter_friend_farm": Callable(owner, "_enter_friend_farm"), "apply_land_data": Callable(owner, "_apply_land_data"), "decrease_player_currency": Callable(owner, "_decrease_player_currency"), "add_reward_items": Callable(owner, "_add_reward_items"), "hide_selection_ui": Callable(owner, "_hide_selection_ui"), "render_lands": Callable(owner, "_render_lands"), "show_toast": Callable(owner, "_show_toast"), "response_data": Callable(owner, "_response_data"), "response_status_text": Callable(owner, "_response_status_text"), }, }) var modules := { # 主场景按键名接收模块,避免在 game_scene.gd 中继续散落 preload/new。 "game_config": game_config, "api_client": api_client, "atlas_cache": atlas_cache, "texture_provider": texture_provider, "ui_builder": ui_builder, "context": context, "player_state": player_state, "farm_state": farm_state, "inventory_state": inventory_state, "player_inventory_facade": inventory_facade, "crop_phase_rules": crop_phase_rules, "land_action_rules": land_action_rules, "farm_mapper": farm_mapper, "inventory_mapper": inventory_mapper, "farm_api": farm_api, "inventory_api": inventory_api, "building_api": building_api, "shop_api": shop_api, "warehouse_api": warehouse_api, "deal_api": deal_api, "friend_api": friend_api, "interaction_api": interaction_api, "activity_api": activity_api, "pet_api": pet_api, "pay_api": pay_api, "farm_controller": farm_controller, "friend_visit_controller": friend_visit_controller, "panel_router": panel_router, } var panel_views := _create_panel_views({ "owner": owner, "ui_builder": ui_builder, "texture_provider": texture_provider, "context": context, "game_config": game_config, "farm_mapper": farm_mapper, "building_api": building_api, "shop_api": shop_api, "warehouse_api": warehouse_api, "deal_api": deal_api, "friend_api": friend_api, "activity_api": activity_api, "pet_api": pet_api, "pay_api": pay_api, "panel_screen_size": panel_screen_size, "constants": constants, "paths": paths, "textures": textures, "callbacks": panel_callbacks, }) panel_router.set_panel_views(panel_views) modules.merge(panel_views, true) return modules func _create_panel_views(options: Dictionary) -> Dictionary: # 面板创建统一收敛在这里,保证所有 PanelModule 使用同一套 UIBuilder、TextureProvider 和 callbacks。 var callbacks: Dictionary = options.get("callbacks", {}) var panel_screen_size: Vector2 = options.get("panel_screen_size", Vector2(640.0, 960.0)) var constants: Dictionary = options.get("constants", {}) var paths: Dictionary = options.get("paths", {}) var textures: Dictionary = options.get("textures", {}) var owner = options.get("owner") var ui_builder = options.get("ui_builder") var texture_provider = options.get("texture_provider") var game_config = options.get("game_config") var activity_api = options.get("activity_api") var context = options.get("context") var shop_panel = ShopPanelScript.new() shop_panel.setup({ "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "shop_api": options.get("shop_api"), "get_item_icon_texture": Callable(texture_provider, "item_icon"), "context": context, "callbacks": callbacks, }) var warehouse_panel = WarehousePanelScript.new() warehouse_panel.setup({ "owner": owner, "ui_builder": ui_builder, "texture_provider": texture_provider, "warehouse_api": options.get("warehouse_api"), "get_item_icon_texture": Callable(texture_provider, "item_icon"), "panel_screen_size": panel_screen_size, "capacity": int(constants.get("ware_capacity", 32)), "item_type_fruit": int(constants.get("item_type_fruit", 2)), "item_type_seed": int(constants.get("item_type_seed", 1)), "item_type_props": int(constants.get("item_type_props", 3)), "context": context, "callbacks": callbacks, }) var friend_panel = FriendPanelScript.new() friend_panel.setup({ "ui_builder": ui_builder, "texture_provider": texture_provider, "friend_api": options.get("friend_api"), "page_size": int(constants.get("friend_page_size", 7)), "context": context, "callbacks": callbacks, }) var building_panel = BuildingPanelScript.new() building_panel.setup({ "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "building_api": options.get("building_api"), "farm_mapper": options.get("farm_mapper"), "get_item_icon_texture": Callable(texture_provider, "item_icon"), "panel_screen_size": panel_screen_size, "max_farm_level": int(constants.get("max_farm_level", 12)), "land_count": int(constants.get("land_count", 12)), "context": context, "callbacks": callbacks, }) var log_panel = LogPanelScript.new() log_panel.setup({ "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "activity_api": activity_api, "panel_screen_size": panel_screen_size, "log_item_bg_texture": textures.get("log_item_bg"), "context": context, "callbacks": callbacks, }) var notice_panel = NoticePanelScript.new() # 活动类面板大多只需要 activity_api + 通用 UI 依赖,使用 _panel_options 降低重复注入。 notice_panel.setup(_panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context)) var level_gift_panel = LevelGiftPanelScript.new() level_gift_panel.setup(_panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context)) var online_gift_panel = OnlineGiftPanelScript.new() var online_options := _panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context) online_options["owner"] = owner online_gift_panel.setup(online_options) var pay_panel = PayPanelScript.new() pay_panel.setup({ "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "pay_api": options.get("pay_api"), "panel_screen_size": panel_screen_size, "context": context, "callbacks": callbacks, }) var gold_exchange_panel = GoldExchangePanelScript.new() gold_exchange_panel.setup(_panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context)) var market_panel = MarketPanelScript.new() var market_options := _panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context) market_options["owner"] = owner market_options["deal_api"] = options.get("deal_api") market_panel.setup(market_options) var sign_panel = SignPanelScript.new() var sign_options := _panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context) sign_options["pay_bg_path"] = paths.get("pay_bg", "") sign_panel.setup(sign_options) var lottery_panel = LotteryPanelScript.new() var lottery_options := _panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size, callbacks, context) lottery_options["owner"] = owner lottery_options["pay_bg_path"] = paths.get("pay_bg", "") lottery_panel.setup(lottery_options) var pet_panel = PetPanelScript.new() pet_panel.setup({ "owner": owner, "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "pet_api": options.get("pet_api"), "shop_api": options.get("shop_api"), "panel_screen_size": panel_screen_size, "dog_food_item_ids": constants.get("dog_food_item_ids", []), "context": context, "callbacks": callbacks, }) var player_info_panel = PlayerInfoPanelScript.new() player_info_panel.setup({ "owner": owner, "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "farm_api": options.get("farm_api"), "panel_screen_size": panel_screen_size, "context": context, "callbacks": callbacks, }) return { # 返回值名称与 game_scene.gd 的字段保持一一对应,便于后续逐个迁移调用点。 "shop_panel_view": shop_panel, "warehouse_panel_view": warehouse_panel, "friend_panel_view": friend_panel, "building_panel_view": building_panel, "log_panel_view": log_panel, "notice_panel_view": notice_panel, "level_gift_panel_view": level_gift_panel, "online_gift_panel_view": online_gift_panel, "pay_panel_view": pay_panel, "gold_exchange_panel_view": gold_exchange_panel, "market_panel_view": market_panel, "sign_panel_view": sign_panel, "lottery_panel_view": lottery_panel, "pet_panel_view": pet_panel, "player_info_panel_view": player_info_panel, } func _panel_options(ui_builder, texture_provider, game_config, activity_api, panel_screen_size: Vector2, callbacks: Dictionary, context = null) -> Dictionary: # 简单活动面板共享的最小依赖集合;需要额外资源路径或 owner 时再在调用处追加。 return { "ui_builder": ui_builder, "texture_provider": texture_provider, "game_config": game_config, "activity_api": activity_api, "panel_screen_size": panel_screen_size, "context": context, "callbacks": callbacks, }