Implement 40250 classic client port
This commit is contained in:
+57
-5
@@ -58,6 +58,10 @@ const AtlasUI = preload("res://ui/atlas_ui.gd")
|
||||
const WorldTime = preload("res://world/world_time.gd")
|
||||
const Weather = preload("res://fx/weather.gd")
|
||||
|
||||
# 龙魂是协议兼容层的一部分,但龙魂 40250 服务器没有这个功能。
|
||||
# 保留 DragonSoulUI / ds_refine 代码供后续兼容,当前客户端不创建入口、不消费背包右键。
|
||||
const ENABLE_DRAGON_SOUL := false
|
||||
|
||||
var client: Node
|
||||
var world: Node
|
||||
var player: Node3D
|
||||
@@ -110,6 +114,8 @@ var _sun: DirectionalLight3D
|
||||
var _env: Environment
|
||||
var _env_from_msenv := false # true = 用 Metin2World 从 .msenv 建的 Sun/WorldEnv
|
||||
var _pending_shoot_skill := 0
|
||||
var _guild_invite_dialog: ConfirmationDialog
|
||||
var _gift_dialog: AcceptDialog
|
||||
|
||||
func setup(m2client: Node, assets_root: String,
|
||||
map_path: String = "OutdoorA1/metin2_map_a1") -> void:
|
||||
@@ -144,6 +150,7 @@ func setup(m2client: Node, assets_root: String,
|
||||
add_child(net_world)
|
||||
net_world.world = world
|
||||
net_world.setup(client, _mount)
|
||||
net_world.set_local_node(player)
|
||||
|
||||
hud = Hud.new()
|
||||
if _map_loaded():
|
||||
@@ -221,6 +228,8 @@ func setup(m2client: Node, assets_root: String,
|
||||
fx.spawn(name, host, true) # GC_SPECIFIC_EFFECT
|
||||
elif special >= 0 and skill_fx:
|
||||
skill_fx.spawn_special(special, host)) # GC_SPECIAL_EFFECT 内建 id
|
||||
if client.has_signal("gift_available"):
|
||||
client.gift_available.connect(_on_gift_available)
|
||||
|
||||
# 任务 / NPC(P7)—— 对话窗自动弹,J 键任务日志
|
||||
quest_dialog = QuestDialog.new()
|
||||
@@ -319,12 +328,17 @@ func setup(m2client: Node, assets_root: String,
|
||||
add_child(guild_ui)
|
||||
guild_ui.setup(client, ui, skill_table)
|
||||
guild_ui.mark_image_provider = _guild_mark_upload_image
|
||||
if client.has_signal("guild_invite_ask"):
|
||||
client.guild_invite_ask.connect(_on_guild_invite)
|
||||
refine_ui = RefineUI.new()
|
||||
add_child(refine_ui)
|
||||
refine_ui.setup(client, ui, proto)
|
||||
dragon_soul_ui = DragonSoulUI.new()
|
||||
add_child(dragon_soul_ui)
|
||||
dragon_soul_ui.setup(client, ui, proto)
|
||||
if ENABLE_DRAGON_SOUL:
|
||||
dragon_soul_ui = DragonSoulUI.new()
|
||||
add_child(dragon_soul_ui)
|
||||
dragon_soul_ui.setup(client, ui, proto)
|
||||
else:
|
||||
dragon_soul_ui = null
|
||||
await _yield()
|
||||
if inventory and "context_consumer" in inventory:
|
||||
inventory.context_consumer = _on_inv_context
|
||||
@@ -393,6 +407,42 @@ func _guild_mark_upload_image() -> Image:
|
||||
img.set_pixel(x, y, Color(0.8, 0.2, 0.2) if (x + y) % 2 == 0 else Color(0.9, 0.85, 0.3))
|
||||
return img
|
||||
|
||||
func _on_guild_invite(guild_id: int, guild_name: String) -> void:
|
||||
if _guild_invite_dialog and is_instance_valid(_guild_invite_dialog):
|
||||
_guild_invite_dialog.queue_free()
|
||||
_guild_invite_dialog = ConfirmationDialog.new()
|
||||
_guild_invite_dialog.title = "公会邀请"
|
||||
_guild_invite_dialog.dialog_text = "加入公会“%s”?" % guild_name
|
||||
_guild_invite_dialog.ok_button_text = "加入"
|
||||
_guild_invite_dialog.cancel_button_text = "拒绝"
|
||||
ui.add_child(_guild_invite_dialog)
|
||||
_guild_invite_dialog.confirmed.connect(func():
|
||||
client.guild_answer_invite(guild_id, true)
|
||||
_guild_invite_dialog.queue_free())
|
||||
_guild_invite_dialog.canceled.connect(func():
|
||||
client.guild_answer_invite(guild_id, false)
|
||||
_guild_invite_dialog.queue_free())
|
||||
_guild_invite_dialog.popup_centered()
|
||||
|
||||
func _on_gift_available() -> void:
|
||||
# 40250's Gift_Show has no corresponding claim packet in the shipped
|
||||
# PythonNetworkStream. Keep the server notification visible instead of
|
||||
# silently consuming it; any reward data remains owned by the gift UI/backend.
|
||||
if ui == null:
|
||||
return
|
||||
if _gift_dialog and is_instance_valid(_gift_dialog):
|
||||
_gift_dialog.popup_centered()
|
||||
return
|
||||
_gift_dialog = AcceptDialog.new()
|
||||
_gift_dialog.title = "礼物"
|
||||
_gift_dialog.dialog_text = "有新的礼物可查看。"
|
||||
_gift_dialog.ok_button_text = "知道了"
|
||||
ui.add_child(_gift_dialog)
|
||||
_gift_dialog.confirmed.connect(func():
|
||||
if is_instance_valid(_gift_dialog):
|
||||
_gift_dialog.queue_free())
|
||||
_gift_dialog.popup_centered()
|
||||
|
||||
# .msa MotionEventData 分派(对齐 GameLib/RaceMotionData EMotionEventType):
|
||||
# 1 EFFECT / 10 EFFECT_TO_TARGET → 挂特效;2 SCREEN_WAVING → 震屏;
|
||||
# 3 SCREEN_FLASHING → 屏闪;5 SOUND / 有 sound 字段 → 3D 音;6 FLY / 9 WARP → 钩子。
|
||||
@@ -470,7 +520,7 @@ func _on_inv_context(window: int, cell: int) -> bool:
|
||||
if safebox_ui and safebox_ui.is_open():
|
||||
safebox_ui.deposit(window, cell)
|
||||
return true
|
||||
if dragon_soul_ui and dragon_soul_ui.is_open():
|
||||
if ENABLE_DRAGON_SOUL and dragon_soul_ui and dragon_soul_ui.is_open():
|
||||
dragon_soul_ui.add_cell(window, cell)
|
||||
return true
|
||||
return false
|
||||
@@ -494,7 +544,7 @@ func _unhandled_input(e: InputEvent) -> void:
|
||||
friend_ui.toggle()
|
||||
elif e.keycode == KEY_G and guild_ui:
|
||||
guild_ui.toggle()
|
||||
elif e.keycode == KEY_L and dragon_soul_ui:
|
||||
elif e.keycode == KEY_L and ENABLE_DRAGON_SOUL and dragon_soul_ui:
|
||||
dragon_soul_ui.toggle()
|
||||
elif e.keycode == KEY_M and atlas_ui:
|
||||
atlas_ui.toggle()
|
||||
@@ -572,6 +622,8 @@ func set_player_model(node: Node3D) -> void:
|
||||
player = node
|
||||
cam.target = node
|
||||
pc.player = node
|
||||
if net_world and net_world.has_method("set_local_node"):
|
||||
net_world.set_local_node(node)
|
||||
old.queue_free()
|
||||
|
||||
# --- internals -------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user