1.2.0 更新日志
约 3810 字大约 13 分钟
更新日志
2025-01-26
1. 加密系统更新
使用基于 C++ 语言的加密算法,用于加密模型和缓存。并以更安全的方式实现,大幅提高安全性;
设计了新的模型格式以承载加密模型。现在加密的模型文件不再直接包含 json 源文件,而是转换为 YSM 专有的格式。即使被破解也很难还原出模型源文件,更不能重新导入 Blockbench;
设计了加密的网络协议,用于服务端与客户端之间的模型同步,提高服务端模型的安全性;
增加了模组自身的校验,任何对模组本身的修改都会导致无法正常使用。
因为新版加密系统使用了 C++,所以无法在 ARM 架构的设备上运行,比如大部分手机用户。
旧版加密虽然已经不安全,但由于缓存加密的更新和网络协议加密,只要旧版加密模型仅放在服务端,并且服主可信,那么它仍然是安全的;
在加密模型文件的头部添加了一段描述文本,用 windows 自带的记事本打开即可看到模型的简略信息。也可用于辨别旧版和新版加密模型。(win7 系统下可能乱码,建议用 VSCode 等更专业的工具查看)。由于新版加密模型有自校验,在加密模型上二次修改这些文本将导致整个模型文件都无法被 YSM 加载。
2. 性能与安全性优化
客户端
重写渲染器,大幅提高帧数,同时降低了额外玩家渲染的开销 #21;(在 optifine 下可能有渲染错误,打开设置中的“兼容渲染器”即可解决)
提高模型加载速度,首次加载模型不再阻塞主线程,不会拖慢进入游戏的时间;
修复了内存泄露,不会玩得越久越卡 #23;
不使用 Java 自带的序列化库,不再受 Pipe Bleeding 远程代码执行漏洞的影响。
缩放为 0 的块不再渲染
服务端
- 支持限制 YSM 在同步模型期间的带宽占用,默认为 5 Mbps,可防止同步模型期间吃满带宽影响正常游戏;
- 降低同步模型期间的内存占用。配合带宽限制,能使额外的内存占用始终保持在一个较低的水平;
- 支持修改服务端重载模型的并发数。如果是以 YSM 模组为主体的服务器,可以适当提高并发数以降低重载模型的耗时,最好不要高于 CPU 核心数;
- 当重命名服务端模型,或把模型在 custom 和 auth 目录之间移动,重载时不再需要重新同步整个模型至客户端;
- 现在只能由服务端发起模型同步,降低了空包攻击的影响 #20;
- 当服务端删除了某个模型,重载后客户端也会删除对应的模型缓存;
3. Bug 与兼容性修正
- 单人游戏不开作弊也能执行 /ysm 指令;
- 现在重复播放
Extra、Swing、Hold、Use
动画能够生效了 - 即使玩家停止挥动,播放的
Swing
也会在一直播放到完毕。所以模型作者可以制作更长时间的攻击动画。 - 兼容简单飞机与沉浸飞机,以及原理相似的同类模组;
- 手部动画的组分为实际的左手动作和右手动作
- 十字弓动画正常播放,不再和 Hold 动画冲突
- 能够兼容拔刀剑的渲染(需要模型作者提供名为
LeftWaistLocator
,RightWaistLocator
的组) - 能够兼容 Carry On 模组的动作渲染(新增名为
carryon.animation.json
动画文件) - 使用单独的
info.json
文件记录模型作者信息,避免 Blockbench 修改模型时导致信息丢失 - 不再替换
Corpse
、Taterzens
等模组的实体模型 #28; - 修复多人游戏下不显示他人原版模型皮肤的问题;(没错,这是客户端的问题)
- 未安装 YSM 的客户端可以加入有 YSM 的服务器,反之亦然。
math.atan(value)
与math.atan2(y,x)
无法使用- 修复
query.player_level, ysm.first_person_mod_hide, query.yaw_speed
等变量数值问题 - 修复第一人称模组相关 molang 变量与 oculus 的兼容问题
- 修复玩家移动时还能播放轮盘动画的问题
4. 功能更新
杂项
现在能够自定义射出的箭的模型了。模型和材质文件名分别为固定的
arrow.json
和arrow.png
,动画文件名为arrow.animation.json
(可选)。更多细节可参考内置的默认模型;重载模型时如果有模型加载失败,会随重载指令的结果反馈失败的原因;
模型切换界面可以再次按下快捷键关闭窗口
模型切换界面搜索框,点击框外能够取消聚焦
添加可以同步到客户端的配置,能够禁用模型切换功能
现在 Hold,Swing 动画也能用冒号开头的内置分类了,内置分类现在可以区分:剑,铲,盾,锄,斧,投掷药水
模型可以添加 free 字段,添加后此模型即使放入 Auth 文件夹,也会显示为非授权模型
修正动画示例界面按钮文字溢出问题
动画系统
- 支持更多插值类型:如平滑,步帧等
- 降低 Extra 动画的优先级至低于 Parallel 动画;
- 更换 Molang 引擎,支持更多语法特性和更便利的调试方式,添加更多 Molang 变量。
5. Molang 系统更新
① 新增语法特性支持
② 与基岩版的差异
- 未初始化的变量为 null 值,可以用空值合并运算符识别,参与数值类计算时被视为 0 或 false;
- 结构体不支持嵌套;
- 玩家在切换模型、重生、传送至部分维度、退出重进以及其他类似操作后将清空所有变量存储。
③ 指令
/ysmclient molang execute <expr>
在本地玩家身上执行 molang 表达式,并输出结果至聊天框。
(仅单人游戏有效)
/ysmclient molang watch add pre/post <name> <expr>
向自定义调试屏幕添加 molang 表达式,会实时计算和更新;
pre 意为在动画更新前执行,post 在动画更新后执行。
(按两次 alt + B 才能进入自定义调试屏幕)
/ysmclient molang watch remove <name>
/ysmclient molang watch clear
管理自定义调试屏幕上的条目。
/ysm molang execute <player> <expr>
在指定玩家身上执行 molang;多人游戏下可用,需要管理员权限。
(不会输出执行结果)
④ 函数和变量
roaming
变量
以 v.roaming.xxx
格式书写的变量(不能简写为 v.r.xxx
)可以在切换维度、重生、退出重进后恢复。也能在玩家之间同步会,并且会跟随服务端的 cap 写入存档。
但是此变量有一些限制:
- 一个模型最多有 16 个
roaming
变量 - 变量名称的字符数不能大于 16
- 变量只能存储
float
query.debug_output()
- 描述:输出消息至聊天框,仅在动画调试模式下有效;
- 参数:任意类型,任意数量;
- 返回值:null 。
例:query.debug_output('喵', 1, 2, 3)
聊天框显示: 喵123
返回:null
math.min_angle()
- 描述:计算指定角度在 [-180, 180) 内的等效角度;
例:math.min_angle(780)
返回:60
query.cape_flap_amount
- 描述:获取披风飘起的程度,即使玩家没穿披风也有效;
- 返回值:0 - 1 的数值。0 为完全垂下,1 完全飘起。
例:q.cape_flap_amount
返回:0.35
query.position()
- 描述:获取实体所处的位置坐标;
- 参数:0-2 的整数,分别指的 X、Y、Z 分量;
- 返回值:玩家位置坐标的指定分量;
例:q.position(1)
(获取玩家位置的 Y 坐标)
返回:1003.23
query.position_delta()
- 描述:获取实体的位置坐标自上次更新动画以来的差值,与帧率有关;
- 参数/返回值:0-2 的整数,分别指坐标差值的 X、Y、Z 分量;
- 返回值:玩家位置坐标差值的指定分量。
例1:q.position_delta(0)
(获取玩家位置差值的 X 分量)
例1返回:-0.076
例2:
v.time0 > 0 && q.life_time - v.time0 > 0 ? (v.speed_x = (q.position_delta(0) - v.x0) / (q.life_time - v.time0));
v.x0 = q.position_delta(0);
v.time0 = q.life_time;
return v.speed_x;
例2返回:19.03
ysm.in_ground
- 描述:判断箭矢是否掉在地上
- 返回:布尔值
例:ysm.in_ground
返回:true
ysm.on_ground_time
- 描述:获取箭矢在地上躺了多久
- 返回:整数,单位为 tick
ysm.is_spectral_arrow
- 描述:判断箭矢是否为光灵箭
- 返回:布尔值
ysm.projectile_owner
- 描述:获取发射该箭矢的玩家实体
- 返回:玩家实体,可以使用“箭头表达式”查询其属性
例:v.flame_level ?? (v.flame_level = ysm.projectile_owner->ysm.equipped_enchantment_level('Mainhand', 'minecraft:flame'))
解释:将该表达式写在箭矢动画中任意 parallel 动画的指令关键帧的第一帧,能在箭矢射出时获取玩家主手的弓的火矢附魔等级,并存储在 v.flame_level 变量中。不会重复执行。
返回:0
ysm.delta_movement_length
- 描述:获取箭矢在两 Tick 之间的位移长度,可以用来判断速度;
- 返回:数值类型的位移长度。
Tips:如果速度异常,尝试安装 Fast Projectile Fix。
ysm.texture_name
- 描述:获取玩家正在使用的材质名称;
- 返回值:字符串类型的材质名称,含扩展名;
例1:ysm.texture_name
例1返回:'blue.png'
例2:ysm.texture_name == 'blue.png'
例2返回:true
ysm.mod_version()
- 描述:获取客户端安装的指定模组的版本;
- 参数:字符串类型的模组 id(注意不是模组名称);
- 返回:若已安装该模组则返回版本号字符串,否则返回 null。
例:ysm.mod_version('tac')
返回:'0.3.10.5'
ysm.dump_mods
- 描述:输出已安装的模组信息至聊天框,仅在动画调试模式下有效;
- 返回:null
ysm.dimension_name
- 描述:获取当前维度;
- 返回:字符串类型的维度 id。
例:ysm.dimension_name
返回:'twilightforest:twilightforest'
(暮色森林)
ysm.biome_category
注意!这个变量仅在 1.16.5 和 1.18.2 可以使用
- 描述:获取玩家所处群系的类别;
- 返回:字符串类型的群系类别。
例:ysm.biome_category == 'forest'
返回:true
群系类别(1.16.5) | |
---|---|
taiga | 针叶林 |
extreme_hills | 风袭丘陵 |
jungle | 丛林 |
mesa | 恶地 |
plains | 平原 |
savanna | 热带草原 |
icy | 冰系群系 |
beach | 沙滩 |
forest | 森林 |
ocean | 海洋 |
desert | 沙漠 |
river | 河流 |
swamp | 沼泽 |
mushroom | 蘑菇岛 |
nether | 下界 |
the_end | 末地 |
ysm.weather
- 描述:获取当前天气;
- 返回:0:晴天,1:雨或雪,2:雷雨或暴雪。
例:ysm.weather
返回:1
Tips:下雨还是下雪取决于当前群系以及所处高度,或静谧四季之类的模组;
ysm.is_open_air
- 描述:判断玩家是否处于露天区域;
- 返回:布尔值
Tips:能帮助判断是否正在淋雪,而 q.is_in_water_or_rain
不能。
query.equipped_item_all_tags()
- 描述:判断玩家装备物品是否包含指定的所有物品标签;
- 参数①:字符串类型的玩家装备槽,参考 基岩版文档,注意区分大小写;
- 参数②......:任意数量的字符串类型物品标签;
- 返回:布尔值
例:query.equipped_item_all_tags('Mainhand', 'minecraft:tools', 'minecraft:swords')
返回:true
query.equipped_item_any_tag()
- 描述:判断玩家装备物品是否包含指定的物品标签中的任意一个;
- 参数①:字符串类型的玩家装备槽,参考 基岩版文档,注意区分大小写;
- 参数②......:任意数量的字符串类型物品标签;
- 返回:布尔值
query.is_item_name_any()
- 描述:判断玩家装备物品 id 是否为指定的物品 id 中的任意一个;
- 参数:任意数量的字符串类型物品 id;
- 返回:布尔值
例:q.is_item_name_any('Mainhand', 'cooked_beef')
(熟牛排)
返回:true
ysm.equipped_enchantment_level()
- 返回值:整数类型的附魔等级。如果附魔不存在,则返回 0。
例:ysm.equipped_enchantment_level('Mainhand', 'minecraft:mending')
(获取主手物品经验修补等级)
返回:1
ysm.dump_equipped_item()
- 描述:输出玩家已装备物品的信息至聊天框,仅在动画调试模式下有效;
- 参数①:字符串类型的玩家装备槽,参考 基岩版文档,注意区分大小写;
- 返回:null
ysm.relative_block_name()
- 描述:获取玩家附近某个方块的 id;
- 参数①②③:以玩家为中心的目标方块的相对位置坐标;
- 返回:字符串类型的方块 id。
例:ysm.relative_block_name(0, -1, 0)
(玩家脚下的方块)
返回:'minecraft:sand'
query.relative_block_has_all_tags()
- 描述:判断玩家附近某个方块是否包含所有指定的所有方块标签;
- 参数①②③:以玩家为中心的目标方块的相对位置坐标;
- 参数④......:任意数量的字符串类型的方块标签;
- 返回:布尔值。
例:q.relative_block_has_all_tags(0, -0.5, 0, 'minecraft:sand', 'minecraft:enderman_holdable')
返回:true
query.relative_block_has_any_tag()
- 描述:判断玩家附近某个方块是否包含指定的方块标签中的任意一个;
- 参数①②③:以玩家为中心的目标方块的相对位置坐标;
- 参数④......:任意数量的字符串类型的方块标签;
- 返回:布尔值。
ysm.dump_relative_block
- 描述:输出玩家附近某个方块的信息至聊天框,仅在动画调试模式下有效;
- 参数①②③:目标方块的以玩家为中心的相对位置坐标;
- 返回:null
ysm.effect_level()
- 描述:获取玩家或箭矢上附加的药水效果等级;
- 参数①:字符串类型的药水 id;
- 返回:数值类型的药水效果等级。如果不存在,则返回 0 。
例:ysm.effect_level('minecraft:regeneration')
(获取目标附加的生命恢复效果的等级)
返回:0
(目标没有这个效果)
ysm.dump_effects
- 描述:输出玩家附加的药水效果的信息至聊天框,仅在动画调试模式下有效;
- 返回:null
query.biome_has_all_tags
由于 1.16 版本没有群系标签,所以该函数只是个占位符,用以维持向前兼容性。
只能在 1.18 以上的版本可用。
query.biome_has_any_tags
也是占位符。只能在 1.18 以上的版本可用。
⑤ 自定义箭矢可用的 molang 符号
(大多数是从玩家那边继承过来的,未必都有意义)
ysm.effect_level
ysm.texture_name
ysm.weather
ysm.dimension_name
ysm.relative_block_name
ysm.mod_version
ysm.dump_effects
ysm.dump_mods
ysm.dump_relative_block
ysm.is_passenger
ysm.is_sleep
ysm.is_sneak
ysm.biome_category
ysm.on_ground_time
ysm.in_ground
ysm.projectile_owner
ysm.delta_movement_length
ysm.is_spectral_arrow
ysm.is_open_air
q.debug_output
q.relative_block_has_all_tags
q.relative_block_has_any_tag
q.position
q.position_delta
q.actor_count
q.anim_time
q.life_time
q.moon_phase
q.time_of_day
q.time_stamp
q.body_x_rotation
q.body_y_rotation
q.yaw_speed
q.cardinal_facing_2d
q.distance_from_camera
q.equipment_count
q.eye_target_x_rotation
q.eye_target_y_rotation
q.ground_speed
q.modified_distance_moved
q.vertical_speed
q.walk_distance
q.has_rider
q.is_first_person
q.is_in_water
q.is_in_water_or_rain
q.is_on_fire
q.is_on_ground
q.is_riding
q.is_sneaking
q.is_spectator
q.is_sprinting
q.is_swimming