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
85 lines
2.6 KiB
GDScript
85 lines
2.6 KiB
GDScript
# Dialogs (P1) —— 基于 UiManager 的通用弹窗:confirm / alert / input。
|
||
#
|
||
# var dlg := preload("res://ui/dialogs.gd").new(ui_manager) # ui_manager: UiManager
|
||
# dlg.confirm("确定要删除吗?", func(): do_delete())
|
||
# dlg.alert("已保存")
|
||
# dlg.input("输入名字", func(t): rename(t), "默认值")
|
||
#
|
||
# 走 UiManager.open(root, modal=true):ESC / 取消 关闭,回调只在确认时触发。
|
||
extends RefCounted
|
||
|
||
var ui: CanvasLayer # UiManager
|
||
|
||
func _init(ui_manager: CanvasLayer) -> void:
|
||
ui = ui_manager
|
||
|
||
func alert(text: String, on_close: Callable = Callable()) -> void:
|
||
var d := _panel(320, 130)
|
||
_label(d, text, 20, 24, 280)
|
||
_button(d, "确定", 130, 88, func():
|
||
ui.close(d)
|
||
if on_close.is_valid(): on_close.call())
|
||
ui.open(d, true)
|
||
|
||
func confirm(text: String, on_ok: Callable, on_cancel: Callable = Callable()) -> void:
|
||
var d := _panel(340, 140)
|
||
_label(d, text, 20, 22, 300)
|
||
_button(d, "确定", 60, 96, func():
|
||
ui.close(d)
|
||
if on_ok.is_valid(): on_ok.call())
|
||
_button(d, "取消", 190, 96, func():
|
||
ui.close(d)
|
||
if on_cancel.is_valid(): on_cancel.call())
|
||
ui.open(d, true)
|
||
|
||
func input(prompt: String, on_submit: Callable, default_text := "") -> void:
|
||
var d := _panel(360, 150)
|
||
_label(d, prompt, 20, 18, 320)
|
||
var le := LineEdit.new()
|
||
le.text = default_text
|
||
le.position = Vector2(20, 52)
|
||
le.size = Vector2(320, 28)
|
||
d.add_child(le)
|
||
_button(d, "确定", 70, 104, func():
|
||
var t := le.text
|
||
ui.close(d)
|
||
if on_submit.is_valid(): on_submit.call(t))
|
||
_button(d, "取消", 200, 104, func(): ui.close(d))
|
||
le.grab_focus()
|
||
ui.open(d, true)
|
||
|
||
# --- 小工具 ---------------------------------------------------------------
|
||
|
||
func _panel(w: int, h: int) -> Control:
|
||
var p := Panel.new()
|
||
p.custom_minimum_size = Vector2(w, h)
|
||
p.size = Vector2(w, h)
|
||
p.position = Vector2((1920 - w) / 2.0, (1080 - h) / 2.0)
|
||
var sb := StyleBoxFlat.new()
|
||
sb.bg_color = Color(0.11, 0.12, 0.15, 0.97)
|
||
sb.border_color = Color(0.4, 0.36, 0.28)
|
||
sb.set_border_width_all(1)
|
||
sb.set_corner_radius_all(4)
|
||
p.add_theme_stylebox_override("panel", sb)
|
||
p.set_meta("is_titlebar", true) # 整块可拖
|
||
return p
|
||
|
||
func _label(parent: Control, text: String, x: int, y: int, w: int) -> Label:
|
||
var l := Label.new()
|
||
l.text = text
|
||
l.position = Vector2(x, y)
|
||
l.size = Vector2(w, 0)
|
||
l.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||
l.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
parent.add_child(l)
|
||
return l
|
||
|
||
func _button(parent: Control, text: String, x: int, y: int, on_press: Callable) -> Button:
|
||
var b := Button.new()
|
||
b.text = text
|
||
b.position = Vector2(x, y)
|
||
b.size = Vector2(90, 26)
|
||
b.pressed.connect(on_press)
|
||
parent.add_child(b)
|
||
return b
|