Complete remaining client gap features

This commit is contained in:
shenlei
2026-09-04 13:25:05 +09:00
parent 13ccb8d02d
commit 9a4a044da5
47 changed files with 6667 additions and 140 deletions
+117
View File
@@ -0,0 +1,117 @@
# damage_effect —— §8.8 / §5.4 头顶伤害飘字「是否 / 如何显示」1:1:
# CInstanceBase::AddDamageEffect + ProcessDamage 的分类(DODGE|BLOCK -> MISS、
# self -> "damage_"、nontarget -> 不渲染、target -> "target_"+ 数字逐位拆分 +
# CPythonSystem::IsShowDamage / SetShowDamageFlag 门。
# (与 name_color.gd / text_tail.gd / chat_tail.gd / name_show.gd 同一套纯静态镜像套路。)
#
# REF40250 ClientVS22 source/ 为唯一基线):
# UserInterface/InstanceBase.h:300 enum DamageFlag { NORMAL 1<<0, POISON 1<<1, DODGE 1<<2, BLOCK 1<<3, PENETRATE 1<<4, CRITICAL 1<<5 }
# UserInterface/Packet.h:1943 TPacketGCDamageInfo { BYTE header; DWORD dwVID; BYTE flag; int damage; }
# UserInterface/PythonNetworkStreamPhaseGame.cpp:2401 RecvDamageInfoPacket
# pInstTarget = GetInstancePtr(dwVID)bSelf = (pInstTarget == MainInstance)
# bTarget = (pInstTarget == m_pInstTarget)damage >= 0 才 AddDamageEffect< 0 记 TraceError
# UserInterface/InstanceBaseEffect.cpp:87 AddDamageEffect:仅当 IsShowDamage() 才 push m_DamageQueue{bSelf,bTarget,damage,flag}
# UserInterface/InstanceBaseEffect.cpp:100 ProcessDamageInstanceBase.cpp:1910 每帧调一次):
# 每帧 pop_front 一条;
# (flag & DODGE) || (flag & BLOCK) -> bSelf ? EFFECT_DAMAGE_MISS : EFFECT_DAMAGE_TARGETMISSreturn
# (flag & CRITICAL) -> 该 build CreateEffect 被注释掉,落到普通数字(无独立暴击视觉)
# POISON 分支整段注释掉
# bSelf -> strDamageType="damage_"EFFECT_DAMAGE_SELFDAMAGE / SELFDAMAGE2 交替(m_bDamageEffectType 每次取反)
# !bTarget -> strDamageType="nontarget_"EFFECT_DAMAGE_NOT_TARGET 后 **return(不渲染)**
# else -> strDamageType="target_"EFFECT_DAMAGE_TARGET
# while(damage>0)num=damage%10; damage/=10; index 0..7>7 TraceError break);
# 贴图 "d:/ymir work/effect/affect/damagevalue/<type><num>.dds"
# 水平偏移 FONT_WIDTH(30)*index(相机右方向,matTrans._41 = -(FONT_WIDTH*index)
# UserInterface/PythonSystem.cpp:308 m_Config.bShowDamage = true(默认)
# UserInterface/PythonSystem.cpp:337 IsShowDamage() -> m_Config.bShowDamage
# UserInterface/PythonSystem.cpp:342 SetShowDamageFlag(iFlag) -> bShowDamage = (iFlag == 1)
# UserInterface/PythonSystem.cpp:451 config "SHOW_DAMAGE" -> atoi(value) == 1
# UserInterface/PythonSystem.cpp:537 save "SHOW_DAMAGE %d"(仅当 == 0,即非默认时落盘)
# UserInterface/PythonSystemModule.cpp:192/219 systemSetShowDamageFlag / systemIsShowDamage
# root/uigameoption.py __OnClickShowDamageOn/OffButton -> systemSetting.SetShowDamageFlag(...)
#
# seam ⑪:参考端每位数字是一张 damagevalue/<type><digit>.dds 贴图做的 CEffectManager 特效,
# 在相机右方向按 FONT_WIDTH*index 像素铺开;本移植 net_world 用一块 billboard Label3D 直接写
# str(amount)(无 damagevalue dds 图集 / 无逐位特效 / 无相机右向像素铺排),MISS 写 "MISS"。
# self 的 SELFDAMAGE/SELFDAMAGE2 交替本移植退化成落字水平抖动符号交替(仅存在感,无双特效资源)。
# 暴击在该 40250 build 参考端本就无独立视觉,这里也不再放大 / 变色(与 <=112 的占位实现相比是回归对齐)。
# 另:参考端 m_DamageQueue 是「每个实例一条」,ProcessDamage 每帧每实例 pop 一条;本移植是
# net_world 一条全局队列每帧 pop 一条 —— 同一帧多个 VID 同时受击时会分帧显示。
extends RefCounted
# CInstanceBase::DamageFlag
const DAMAGE_NORMAL := 1 << 0
const DAMAGE_POISON := 1 << 1
const DAMAGE_DODGE := 1 << 2
const DAMAGE_BLOCK := 1 << 3
const DAMAGE_PENETRATE := 1 << 4
const DAMAGE_CRITICAL := 1 << 5
const SHOW_DAMAGE_DEFAULT := true # m_Config.bShowDamage 默认
const CFG_KEY := "SHOW_DAMAGE" # PythonSystem 配置行 / 存盘键
const FONT_WIDTH := 30 # ProcessDamage 逐位水平像素步进
const MAX_DIGITS := 8 # index > 7 -> break
enum Kind { MISS, DIGITS }
# AddDamageEffect:仅当 IsShowDamage() 才入队
static func should_queue(show_damage: bool) -> bool:
return show_damage
# SetShowDamageFlag(int iFlag): m_Config.bShowDamage = iFlag == 1
static func show_damage_from_flag(flag: int) -> bool:
return flag == 1
# config "SHOW_DAMAGE" 行:atoi(value) == 1
static func show_damage_from_cfg(value: Variant) -> bool:
return int(value) == 1
# RecvDamageInfoPacketbSelf = 目标实例是主角
static func is_self(vid: int, main_vid: int) -> bool:
return vid != 0 and vid == main_vid
# RecvDamageInfoPacketbTarget = 目标实例是当前目标框 VID
static func is_target(vid: int, target_vid: int) -> bool:
return vid != 0 and vid == target_vid
# RecvDamageInfoPacketdamage < 0 记 TraceError 不处理
static func valid_amount(amount: int) -> bool:
return amount >= 0
# ProcessDamage 分类。返回:
# {"kind": Kind, "type": String("damage_"/"target_"/"nontarget_"), "show": bool, "self": bool}
# show == false 只有一种来源:非 self 且非 target 的数字伤害(ProcessDamage 里 return,不渲染)。
static func classify(flag: int, b_self: bool, b_target: bool) -> Dictionary:
if (flag & DAMAGE_DODGE) != 0 or (flag & DAMAGE_BLOCK) != 0:
# EFFECT_DAMAGE_MISSself/ EFFECT_DAMAGE_TARGETMISS(其它)
return {"kind": Kind.MISS, "type": "damage_" if b_self else "target_", "show": true, "self": b_self}
if b_self:
return {"kind": Kind.DIGITS, "type": "damage_", "show": true, "self": true}
if not b_target:
return {"kind": Kind.DIGITS, "type": "nontarget_", "show": false, "self": false}
return {"kind": Kind.DIGITS, "type": "target_", "show": true, "self": false}
# while(damage>0){ num=damage%10; damage/=10; } —— 低位在前,最多 8 位(index>7 break)。
# damage <= 0 不产出任何位(与参考 while 一致)。
static func digits(damage: int) -> Array:
var out: Array = []
var d := damage
if d <= 0:
return out
var index := 0
while d > 0:
if index > MAX_DIGITS - 1:
break
out.append(d % 10)
d = d / 10
index += 1
return out
# 第 index 位数字相对锚点的水平像素偏移(相机右方向)。
static func digit_offset_px(index: int) -> float:
return float(FONT_WIDTH * index)
# ProcessDamage 的 self 特效交替:m_bDamageEffectType==false -> SELFDAMAGE(0),否则 SELFDAMAGE2(1)
# 每次自伤后取反。返回本次用的槽位(0/1)。
static func self_damage_slot(toggle_state: bool) -> int:
return 1 if toggle_state else 0