Files
mtgodot-poc/project/app_lifecycle.gd
T
shenandClaude Sonnet 5 47baf6c0c6 Metin2 game client (P0–P11) + mobile asset pipeline
Networked client on the existing Godot 4.7 + libgr2 renderer:
- net: m2dev wire protocol (libsodium KX + XChaCha20), auth/select/game
  phases, EntityStore world model, ~all GC/CG headers. char create/delete,
  private shop / mall / cube, SHOP_GC_START_EX, guild, party (+ CG_PARTY_SET_STATE),
  quests, dragon soul, refine, safebox, exchange.
- UI: in-game windows migrated 1:1 from the reference uiscript/root .py —
  char status (/stat), inventory+equipment, select-item ([SELECT_ITEM] quest
  token), system-option + game-option + ESC system menu, private-shop 39-grid,
  party info board, shop tabs, atlas, minimap, quickbar, chat, …
- EterGrnLib polish: GR2 material blend/two-sided, LOD crossfade, motion-event
  dispatch, contact shadow, ray-AABB picking, weapon grip pre-transform.

Portable asset IO (A1) — all extension/libgr2/formats/mtproto reads routed
through godot::FileAccess (res:// PCK works on iOS/Android); standalone-lib
*_path() kept for the non-Godot CTests. AssetResolver + PropertyRegistry
switched to a baked index (bake_asset_index.gd) instead of std::filesystem.

Mobile builds: build-{android,ios}.sh, export-android.sh, pack-assets.sh,
gen-debug-keystore.sh. Assets ship as a zip mounted at runtime by
project/asset_pack.gd (adb push now; HTTP download is a drop-in later).

ctest 10/10, 34 GDScript suites, macOS/iOS/Android all build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013EJxkHiNKS4kybHS3XKyAJ
2026-08-31 20:02:12 +09:00

86 lines
2.8 KiB
GDScript
Raw 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.
# AppLifecycle (F5) —— 移动端应用生命周期集中处理。
#
# 把 SceneTree 转发来的 MainLoop 通知收成信号,并做默认动作:后台时暂停游戏
# 逻辑 / 降帧 / 停 BGM,恢复时还原;iOS 内存告警时广播让各缓存自清。渲染上下文
# 丢失(Android Vulkan surface)由 Godot 自己重建,我们持有的 GPU 资源都由
# RenderingServer 托管,无需干预。
#
# 用法:
# var life := preload("res://app_lifecycle.gd").new()
# add_child(life) # 越早越好(autoload 亦可)
# life.bind(m2client, audio) # 可选:自动接常见消费方
# life.paused.connect(_on_bg); life.resumed.connect(_on_fg)
extends Node
signal paused # 进入后台(NOTIFICATION_APPLICATION_PAUSED
signal resumed # 回到前台
signal focus_changed(focused: bool)
signal memory_warning # iOS 内存压力
signal back_requested # Android 返回键
signal close_requested # 窗口关闭请求(桌面)
## 后台时是否 get_tree().paused = true(默认开;纯观战/录像可关)
var pause_tree_on_background := true
## 后台时把 max_fps 压到这个值省电(0 = 不改)
var background_max_fps := 8
var _bound_client: Node
var _bound_audio: Node
var _saved_max_fps := 0
var _bg := false
func _ready() -> void:
# 通知在暂停树时也要能收到
process_mode = Node.PROCESS_MODE_ALWAYS
func bind(m2client: Node = null, audio: Node = null) -> void:
_bound_client = m2client
_bound_audio = audio
func is_backgrounded() -> bool:
return _bg
func _notification(what: int) -> void:
match what:
NOTIFICATION_APPLICATION_PAUSED:
_enter_background()
NOTIFICATION_APPLICATION_RESUMED:
_exit_background()
NOTIFICATION_APPLICATION_FOCUS_IN, NOTIFICATION_WM_WINDOW_FOCUS_IN:
focus_changed.emit(true)
NOTIFICATION_APPLICATION_FOCUS_OUT, NOTIFICATION_WM_WINDOW_FOCUS_OUT:
focus_changed.emit(false)
NOTIFICATION_OS_MEMORY_WARNING:
memory_warning.emit()
NOTIFICATION_WM_GO_BACK_REQUEST:
back_requested.emit()
NOTIFICATION_WM_CLOSE_REQUEST:
close_requested.emit()
func _enter_background() -> void:
if _bg:
return
_bg = true
if background_max_fps > 0:
_saved_max_fps = Engine.max_fps
Engine.max_fps = background_max_fps
if _bound_audio and _bound_audio.has_method("stop_bgm"):
_bound_audio.stop_bgm()
if _bound_client and _bound_client.has_method("suspend"):
_bound_client.suspend()
if pause_tree_on_background:
get_tree().paused = true
paused.emit()
func _exit_background() -> void:
if not _bg:
return
_bg = false
if pause_tree_on_background:
get_tree().paused = false
if background_max_fps > 0:
Engine.max_fps = _saved_max_fps
if _bound_client and _bound_client.has_method("resume"):
_bound_client.resume()
resumed.emit()