在执行任何升级代码前,请务必完整备份你的 MuOnline 数据库!数据无价!
第一步:创建 97D 转 103H 的核心转换函数
USE MuOnline;
GO
-- 如果函数已存在则先删除
IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[dbo].[fn_UpgradeItem_97D_to_103H]') AND xtype IN (N'FN', N'IF', N'TF'))
DROP FUNCTION [dbo].[fn_UpgradeItem_97D_to_103H]
GO
CREATE FUNCTION [dbo].[fn_UpgradeItem_97D_to_103H]
(
@OldItems VARBINARY(MAX)
)
RETURNS VARBINARY(MAX)
AS
BEGIN
-- 如果传入数据为空,直接返回空
IF @OldItems IS NULL RETURN NULL;
DECLARE @NewItems VARBINARY(MAX) = 0x;
DECLARE @ItemCount INT = DATALENGTH(@OldItems) / 10; -- 97D每件物品占10字节
DECLARE @i INT = 0;
DECLARE @OldItem BINARY(10);
DECLARE @NewItem BINARY(16);
-- 循环处理每一个物品格
WHILE @i < @ItemCount
BEGIN
-- 截取当前格子的10字节(97D)物品代码
SET @OldItem = SUBSTRING(@OldItems, (@i * 10) + 1, 10);
-- 如果是 FF FF... FF (空物品格)
IF @OldItem = 0xFFFFFFFFFFFFFFFFFFFF
BEGIN
-- 转换为103H的16字节空物品格
SET @NewItem = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
END
ELSE
BEGIN
-- 解析 97D 的字节
DECLARE @Byte1 INT = CAST(SUBSTRING(@OldItem, 1, 1) AS INT);
DECLARE @Byte8 INT = CAST(SUBSTRING(@OldItem, 8, 1) AS INT);
-- 解析小编号 (97D 第1字节的后5位)
DECLARE @ItemIndex INT = @Byte1 & 31;
-- 解析大类编号 (97D 第1字节的前3位)
DECLARE @Category INT = (@Byte1 / 32) & 7;
-- 判断卓越属性位是否包含了防具大类标识 (如果是+80(即128),则大类需要+8)
IF (@Byte8 & 128) > 0
BEGIN
SET @Category = @Category + 8;
END
-- 清除卓越位中的大类标识,保留原本的卓越属性和追16属性(&127)
DECLARE @NewByte8 INT = @Byte8 & 127;
-- 组装 103H 的大类位 (放在新格式的第10字节的高位, 乘以16)
DECLARE @NewByte10 INT = @Category * 16;
-- 拼接 103H 的 16 字节格式
SET @NewItem =
CAST(@ItemIndex AS BINARY(1)) + -- [1-2位] 物品序号
SUBSTRING(@OldItem, 2, 1) + -- [3-4位] 等级,幸运,技能,追加
SUBSTRING(@OldItem, 3, 1) + -- [5-6位] 耐久度
SUBSTRING(@OldItem, 4, 4) + -- [7-14位] 物品流水序列号
CAST(@NewByte8 AS BINARY(1)) + -- [15-16位] 卓越属性及追12以上标志
0x00 + -- [17-18位] 17位为0, 18位套装位(97d无套装,默认00)
CAST(@NewByte10 AS BINARY(1)) + -- [19-20位] 19位物品大类, 20位380属性
0x00 + -- [21-22位] 强化属性/再生属性(老物品没有,默认00)
0xFFFFFFFFFF; -- [23-32位] 镶嵌孔(老物品无孔,默认FFFFFFFFFF)
END
-- 将转换好的 16 字节追加到新的库存二进制串中
SET @NewItems = @NewItems + @NewItem;
SET @i = @i + 1;
END
RETURN @NewItems;
END
GO
第二步:执行数据升级更新
USE MuOnline;
GO
PRINT '开始升级玩家背包 (Character.Inventory)...';
UPDATE Character
SET Inventory = [dbo].[fn_UpgradeItem_97D_to_103H](Inventory)
WHERE Inventory IS NOT NULL
AND DATALENGTH(Inventory) % 10 = 0
AND DATALENGTH(Inventory) % 16 <> 0; -- 确保只升级旧格式
PRINT '玩家背包升级完成!';
PRINT '开始升级玩家仓库 (warehouse.Items)...';
-- 97D 的仓库刚好是 120 个格子 × 10 字节 = 1200 字节
UPDATE warehouse
SET Items = [dbo].[fn_UpgradeItem_97D_to_103H](Items)
WHERE Items IS NOT NULL
AND DATALENGTH(Items) = 1200;
PRINT '玩家仓库升级完成!';
-- 如果你有扩展仓库表,同样处理
IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[dbo].[ExtWarehouse]') AND xtype='U')
BEGIN
PRINT '开始升级扩展仓库 (ExtWarehouse.Items)...';
EXEC('
UPDATE ExtWarehouse
SET Items = [dbo].[fn_UpgradeItem_97D_to_103H](Items)
WHERE Items IS NOT NULL
AND DATALENGTH(Items) = 1200;
');
PRINT '扩展仓库升级完成!';
END
GO
在 103H(第四季)中,玩家 Inventory 的 108 个格子分布如下:
身上装备: 12格 × 16字节 = 192字节
玩家包裹: 64格 × 16字节 = 1024字节
个人商店: 32格 × 16字节 = 512字节
总计: 192 + 1024 + 512 = 1728字节
因为 97D 没有个人商店,这就导致在 103H 客户端里个人商店区域出现波刃剑
修复方案:保留前 1216 字节(身上的装备 + 背包里的物品),将最后 512 字节(个人商店)全部强制替换为 0xFF(空位)
USE MuOnline;
GO
PRINT '开始修复所有玩家的背包/个人商店数据...';
-- 声明 512 字节的纯净无孔 FF 空位数据(32格个人商店)
DECLARE @EmptyStore BINARY(512);
SET @EmptyStore = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
-- 核心逻辑:
-- 1. 已经变成1728的:截掉乱码尾巴,换成干净的@EmptyStore
-- 2. 只有1216的:保留原有,直接追加@EmptyStore,使其达到标准的1728
UPDATE Character
SET Inventory = CAST(SUBSTRING(Inventory, 1, 1216) AS VARBINARY(1216)) + @EmptyStore
WHERE Inventory IS NOT NULL
AND DATALENGTH(Inventory) >= 1216;
PRINT '个人商店数据修复完成!';
GO