PSO2SERVER/Server/Models/PSO2Item.cs
Longfeng Qin 37106641a7 物品读取修正
移除部分DEBUG信息
2024-12-11 02:24:51 +08:00

418 lines
11 KiB
C#

using PSO2SERVER.Protocol;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using static PSO2SERVER.Models.CharacterStruct;
namespace PSO2SERVER.Models
{
[StructLayout(LayoutKind.Sequential)]
public unsafe struct ShortItemId
{
public byte ItemType;
public byte Id;
public ushort Subid;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct ItemId
{
public ushort ItemType;
public ushort Id;
public ushort Unk3;
public ushort Subid;
}
[StructLayout(LayoutKind.Explicit)]
public struct Items
{
[FieldOffset(0)]
public PSO2ItemWeapon Weapon;
[FieldOffset(0)]
public PSO2ItemClothing Clothing;
[FieldOffset(0)]
public PSO2ItemConsumable Consumable;
[FieldOffset(0)]
public PSO2ItemCamo Camo;
[FieldOffset(0)]
public PSO2ItemUnit Unit;
[FieldOffset(0)]
public byte[] Unknown;
[FieldOffset(0)]
public PSO2ItemNone None;
}
[StructLayout(LayoutKind.Sequential)]
public struct PSO2Items
{
public ulong uuid;
public ItemId id;
public Items data;
public byte[] ToByteArray()
{
using (var pkt = new PacketWriter())
{
pkt.Write(uuid);
pkt.WriteStruct(id);
pkt.WriteStruct(data);
return pkt.ToArray();
}
}
// 从字节流转换为结构体
public static PSO2Items FromByteArray(byte[] byteArray)
{
using (var reader = new PacketReader(byteArray))
{
PSO2Items items = new PSO2Items
{
uuid = reader.ReadUInt64(),
id = reader.ReadStruct<ItemId>(),
data = reader.ReadStruct<Items>()
};
return items;
}
}
public ulong GetGUID()
{
return uuid;
}
public void SetGUID(ulong guid)
{
uuid = guid;
}
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemNone
{
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemWeapon
{
public byte flags;
public byte element;
public byte force;
public byte grind;
public byte grindPercent;
public byte unknown1;
public short unknown2;
public fixed short affixes[8];
public uint potential;
public byte extend;
public byte unknown3;
public ushort unknown4;
public uint unknown5;
public uint unknown6;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemClothing
{
public ushort flags;
public fixed byte unk1[0x14];
public HSVColor Color;
public fixed byte unk2[0xA];
public ushort Unk3;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemConsumable
{
public ushort flags;
public fixed byte unk1[0x24];
public ushort amount;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemCamo
{
public byte unk1;
public byte unk2;
public byte unk3;
public fixed byte unk4[0x24];
public byte unk5;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemUnit
{
public byte flags;
public byte EnhLevel;
public byte EnhPercent;
public byte Unk1;
// 使用 fixed 数组来存储附加信息
public fixed ushort Affixes[8]; // Item affix IDs (0 to 4095)
public fixed byte unk4[0x7];
public uint Potential;
// 使用 fixed 数组来存储未知字段
public fixed byte Unk2[4];
public uint Unk3;
public ushort Unk4;
public ushort Unk5;
// 提供访问固定数组的属性
public Span<ushort> AffixSpan
{
get
{
fixed (ushort* p = Affixes)
{
return new Span<ushort>(p, 8);
}
}
}
}
public struct Campaign
{
/// Campaign ID.
public uint Id; // 对应 Rust 的 u32
/// Start timestamp.
public TimeSpan StartDate; // 对应 Rust 的 Duration
/// End timestamp.
public TimeSpan EndDate; // 对应 Rust 的 Duration
/// Campaign title (固定长度 0x3E).
public const int TitleLength = 0x3E;
public byte[] titleBytes;
public string Title
{
get => Encoding.ASCII.GetString(titleBytes).TrimEnd('\0');
set
{
titleBytes = new byte[TitleLength];
byte[] valueBytes = Encoding.ASCII.GetBytes(value);
Array.Copy(valueBytes, titleBytes, Math.Min(valueBytes.Length, TitleLength));
}
}
/// Campaign conditions (固定长度 0x102).
public const int ConditionsLength = 0x102;
public byte[] conditionsBytes;
public string Conditions
{
get => Encoding.ASCII.GetString(conditionsBytes).TrimEnd('\0');
set
{
conditionsBytes = new byte[ConditionsLength];
byte[] valueBytes = Encoding.ASCII.GetBytes(value);
Array.Copy(valueBytes, conditionsBytes, Math.Min(valueBytes.Length, ConditionsLength));
}
}
// 从数据流中读取 Campaign
public static Campaign FromStream(Stream stream)
{
using (BinaryReader reader = new BinaryReader(stream, Encoding.ASCII, true))
{
Campaign campaign = new Campaign
{
Id = reader.ReadUInt32(),
StartDate = TimeSpan.FromTicks(reader.ReadInt64()),
EndDate = TimeSpan.FromTicks(reader.ReadInt64()),
};
campaign.titleBytes = reader.ReadBytes(TitleLength);
campaign.conditionsBytes = reader.ReadBytes(ConditionsLength);
return campaign;
}
}
// 将 Campaign 写入数据流
public void WriteToStream(Stream stream)
{
using (BinaryWriter writer = new BinaryWriter(stream, Encoding.ASCII, true))
{
writer.Write(Id);
writer.Write(StartDate.Ticks);
writer.Write(EndDate.Ticks);
writer.Write(titleBytes);
writer.Write(conditionsBytes);
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct NamedId
{
public string Name { get; set; }
public ItemId Id { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct CampaignItemDefinition
{
/// <summary>
/// Campaign ID.
/// </summary>
public uint CampaignId; // Equivalent to u32
/// <summary>
/// Number of items in the following array.
/// </summary>
public uint ItemAmount; // Equivalent to u32
/// <summary>
/// Campaign items.
/// </summary>
public List<CampaignItem> Items; // Using List instead of fixed-size array
}
[StructLayout(LayoutKind.Sequential)]
public struct CampaignItem
{
/// <summary>
/// Item ID.
/// </summary>
public ItemId Id; // Assuming ItemId is a type, use it as-is
/// <summary>
/// Item amount.
/// </summary>
public uint Amount; // Equivalent to u32
/// <summary>
/// Unknown field.
/// </summary>
public uint Unk; // Equivalent to u32
}
[StructLayout(LayoutKind.Sequential)]
public struct StorageInfo
{
/// <summary>
/// Total space in the storage.
/// </summary>
public uint TotalSpace; // Equivalent to u32
/// <summary>
/// Used space in the storage.
/// </summary>
public uint UsedSpace; // Equivalent to u32
/// <summary>
/// Storage ID.
/// </summary>
public byte StorageId; // Equivalent to u8
/// <summary>
/// Storage type (?).
/// </summary>
public byte StorageType; // Equivalent to u8
/// <summary>
/// Is the storage locked (?).
/// </summary>
public byte IsLocked; // Equivalent to u8
/// <summary>
/// Is the storage enabled (?).
/// </summary>
public byte IsEnabled; // Equivalent to u8
}
[StructLayout(LayoutKind.Sequential)]
public struct MaterialStorageItem
{
/// <summary>
/// Item category.
/// </summary>
public ushort Id; // Equivalent to u16
/// <summary>
/// Item ID.
/// </summary>
public ushort Subid; // Equivalent to u16
/// <summary>
/// Item amount.
/// </summary>
public ushort Amount; // Equivalent to u16
/// <summary>
/// Unknown field.
/// </summary>
public ushort Unk4; // Equivalent to u16
}
[StructLayout(LayoutKind.Sequential)]
public struct UUIDAmount
{
public ulong Uuid { get; set; }
public ushort Amount { get; set; }
public ushort Unk { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct EquipedItem
{
public PSO2Items Item { get; set; }
public uint Unk { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct MoveStorageItemRequest
{
public ulong Uuid { get; set; }
public byte Amount { get; set; }
public byte Unk { get; set; }
public ushort StorageId { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct NewStorageItem
{
public PSO2Items Item { get; set; }
public uint StorageId { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct NewInventoryItem
{
public PSO2Items Item { get; set; }
public ushort Amount { get; set; }
public ushort IsNew { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct UpdatedItem
{
public ulong Uuid { get; set; }
public uint NewAmount { get; set; }
public uint StorageId { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct UpdatedInventoryItem
{
public ulong Uuid { get; set; }
public ushort NewAmount { get; set; }
public ushort Moved { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public struct UpdatedStorageItem
{
public ulong Uuid { get; set; }
public ushort NewAmount { get; set; }
public ushort Moved { get; set; }
public uint StorageId { get; set; }
}
}