97D的物品代码(20位十六进制)升级103H物品代码(32位十六进制)

在执行任何升级代码前,请务必完整备份你的 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