hy-farm/godot/FarmGodot/scripts/ui/game_scene_bootstrap.gd
2026-05-29 19:54:56 +08:00

448 lines
20 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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,
}