448 lines
20 KiB
GDScript
448 lines
20 KiB
GDScript
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,
|
||
}
|