356 lines
11 KiB
C#
356 lines
11 KiB
C#
using System;
|
||
using System.ComponentModel.DataAnnotations;
|
||
using System.ComponentModel.DataAnnotations.Schema;
|
||
using System.Data.Entity;
|
||
using System.IO;
|
||
using System.Runtime.InteropServices;
|
||
using MySql.Data.EntityFramework;
|
||
using PSO2SERVER.Models;
|
||
using PSO2SERVER.Protocol;
|
||
using static PSO2SERVER.Models.CharacterStruct;
|
||
|
||
namespace PSO2SERVER.Database
|
||
{
|
||
public class Account
|
||
{
|
||
[Key]
|
||
public int AccountId { get; set; }
|
||
|
||
public string Username { get; set; }
|
||
public string Password { get; set; }
|
||
public string Nickname { get; set; }
|
||
public string SettingsIni { get; set; }
|
||
public int TextLang { get; set; }
|
||
public int VoiceLang { get; set; }
|
||
public int TextLang2 { get; set; }
|
||
public int LangLang { get; set; }
|
||
public string LanguageCode { get; set; }
|
||
public int IsGM { get; set; }
|
||
public int PacketType { get; set; }
|
||
public string PSNID { get; set; }
|
||
}
|
||
|
||
public class AccountNetInterFace
|
||
{
|
||
[Key]
|
||
public int id { get; set; }
|
||
|
||
public int AccountId { get; set; }
|
||
|
||
public string Username { get; set; }
|
||
public int State { get; set; }
|
||
public string Mac { get; set; }
|
||
}
|
||
public class AccountSystemInfo
|
||
{
|
||
[Key]
|
||
public int id { get; set; }
|
||
|
||
public int AccountId { get; set; }
|
||
|
||
public string Username { get; set; }
|
||
public string CpuInfo { get; set; }
|
||
public string VideoInfo { get; set; }
|
||
public long Vram { get; set; }
|
||
public long TotalRam { get; set; }
|
||
public int Unk1 { get; set; }
|
||
public int Unk2 { get; set; }
|
||
public string WindowsVersion { get; set; }
|
||
public string WindowSize { get; set; }
|
||
public string AudioDevices { get; set; }
|
||
public string Unk4 { get; set; }
|
||
public string VideoDriver { get; set; }
|
||
public long TotalDiskSpace { get; set; }
|
||
public long FreeDiskSpace { get; set; }
|
||
}
|
||
|
||
public class Character
|
||
{
|
||
// Probably more info than this
|
||
[Key, Column(Order = 1)]
|
||
public int CharacterID { get; set; }
|
||
|
||
[Key, Column(Order = 2)]
|
||
public int AccountID { get; set; }
|
||
public int Unk1 { get; set; }
|
||
public int VoiceType { get; set; }
|
||
public short Unk2 { get; set; }
|
||
public short VoicePitch { get; set; }
|
||
|
||
public string Name { get; set; }
|
||
|
||
public LooksParam Looks { get; set; }
|
||
|
||
public byte[] LooksBinary
|
||
{
|
||
get
|
||
{
|
||
PacketWriter w = new PacketWriter();
|
||
w.WriteStruct(Looks);
|
||
return w.ToArray();
|
||
}
|
||
|
||
set
|
||
{
|
||
Looks = Helper.ByteArrayToStructure<LooksParam>(value);
|
||
}
|
||
}
|
||
|
||
public int Unk3 { get; set; }
|
||
|
||
public JobParam Jobs { get; set; }
|
||
|
||
public byte[] JobsBinary
|
||
{
|
||
get
|
||
{
|
||
PacketWriter w = new PacketWriter();
|
||
w.WriteStruct(Jobs);
|
||
return w.ToArray();
|
||
}
|
||
|
||
set
|
||
{
|
||
Jobs = Helper.ByteArrayToStructure<JobParam>(value);
|
||
}
|
||
}
|
||
|
||
public byte[] Unk4 { get; set; } = new byte[148];
|
||
|
||
public byte[] Fulldata { get; set; }
|
||
|
||
public PSO2Items[] EquipedItems { get; set; } = new PSO2Items[10];
|
||
|
||
public byte[] EquipedItemsBinary
|
||
{
|
||
get
|
||
{
|
||
PacketWriter w = new PacketWriter();
|
||
foreach (var item in EquipedItems)
|
||
{
|
||
w.WriteStruct(item);
|
||
}
|
||
return w.ToArray();
|
||
}
|
||
|
||
set
|
||
{
|
||
// 每个PSO2Items的大小(包含uuid、ItemId、Items)
|
||
int itemSize = Marshal.SizeOf(typeof(PSO2Items));
|
||
|
||
// 计算字节数组中包含多少个PSO2Items对象
|
||
int itemCount = value.Length / itemSize;
|
||
|
||
// 创建一个新的数组来存储这些对象
|
||
EquipedItems = new PSO2Items[itemCount];
|
||
|
||
// 逐个反序列化
|
||
for (int i = 0; i < itemCount; i++)
|
||
{
|
||
// 提取对应的字节块
|
||
byte[] itemBytes = new byte[itemSize];
|
||
Array.Copy(value, i * itemSize, itemBytes, 0, itemSize);
|
||
|
||
// 使用Helper.ByteArrayToStructure来反序列化每个PSO2Items对象
|
||
EquipedItems[i] = Helper.ByteArrayToStructure<PSO2Items>(itemBytes);
|
||
}
|
||
}
|
||
}
|
||
|
||
public uint Playe_time { get; set; }
|
||
|
||
public byte[] BuildCharacterByteArray()
|
||
{
|
||
PacketWriter writer = new PacketWriter();
|
||
|
||
// 序列化字段:CharacterID, AccountID, Unk1, VoiceType, Unk2, VoicePitch
|
||
writer.Write((uint)CharacterID);
|
||
writer.Write((uint)AccountID);
|
||
writer.Write((uint)Unk1);
|
||
writer.Write((uint)VoiceType);
|
||
writer.Write((ushort)Unk2);
|
||
writer.Write(VoicePitch);
|
||
|
||
// 序列化 name (假设固定长度字符串16个字节,UTF-16 编码)
|
||
writer.WriteFixedLengthUtf16(Name, 0x10);
|
||
|
||
// 序列化 Looks
|
||
writer.WriteStruct(Looks);
|
||
|
||
// 序列化 Unk3
|
||
writer.Write((uint)Unk3);
|
||
|
||
// 序列化 Jobs
|
||
writer.WriteStruct(Jobs);
|
||
|
||
// 序列化 Unk4
|
||
writer.WriteBytes(0, 148);
|
||
|
||
// 最后返回字节流
|
||
return writer.ToArray();
|
||
}
|
||
|
||
public virtual Account Account { get; set; }
|
||
}
|
||
|
||
public class NPC
|
||
{
|
||
[Key, Column(Order = 1)]
|
||
public int EntityID { get; set; }
|
||
[Key, Column(Order = 2)]
|
||
public string ZoneName { get; set; }
|
||
|
||
public string NPCName { get; set; }
|
||
|
||
public float RotX { get; set; }
|
||
public float RotY { get; set; }
|
||
public float RotZ { get; set; }
|
||
public float RotW { get; set; }
|
||
|
||
public float PosX { get; set; }
|
||
public float PosY { get; set; }
|
||
public float PosZ { get; set; }
|
||
public int is_active { get; set; }
|
||
}
|
||
|
||
public class GameObject
|
||
{
|
||
[Key, Column(Order = 1)]
|
||
public int ObjectID { get; set; }
|
||
[Key, Column(Order = 2)]
|
||
public string ZoneName { get; set; }
|
||
|
||
public string ObjectName { get; set; }
|
||
|
||
public byte[] ObjectFlags { get; set; }
|
||
|
||
public float RotX { get; set; }
|
||
public float RotY { get; set; }
|
||
public float RotZ { get; set; }
|
||
public float RotW { get; set; }
|
||
|
||
public float PosX { get; set; }
|
||
public float PosY { get; set; }
|
||
public float PosZ { get; set; }
|
||
}
|
||
|
||
public class ServerInfo
|
||
{
|
||
[Key, MaxLength(255)]
|
||
public string Info { get; set; }
|
||
|
||
public string Setting { get; set; }
|
||
}
|
||
|
||
public class Teleport
|
||
{
|
||
[Key, Column(Order = 1)]
|
||
public string ZoneName { get; set; }
|
||
|
||
[Key, Column(Order = 2)]
|
||
public int ObjectID { get; set; }
|
||
|
||
public float RotX { get; set; }
|
||
public float RotY { get; set; }
|
||
public float RotZ { get; set; }
|
||
public float RotW { get; set; }
|
||
|
||
public float PosX { get; set; }
|
||
public float PosY { get; set; }
|
||
public float PosZ { get; set; }
|
||
}
|
||
|
||
[DbConfigurationType(typeof(MySqlEFConfiguration))]
|
||
public class ServerEf : DbContext
|
||
{
|
||
public DbSet<Account> Accounts { get; set; }
|
||
public DbSet<AccountNetInterFace> AccountsNetInterFaces { get; set; }
|
||
public DbSet<AccountSystemInfo> AccountsSystemInfoes { get; set; }
|
||
public DbSet<Character> Characters { get; set; }
|
||
public DbSet<GameObject> GameObjects { get; set; }
|
||
public DbSet<NPC> NPCs { get; set; }
|
||
public DbSet<ServerInfo> ServerInfoes { get; set; }
|
||
public DbSet<Teleport> Teleports { get; set; }
|
||
|
||
public ServerEf()
|
||
: base(
|
||
string.Format("server={0};port={1};database={2};username={3};password={4}",
|
||
ServerApp.Config.DatabaseAddress,
|
||
ServerApp.Config.DatabasePort,
|
||
ServerApp.Config.DatabaseName,
|
||
ServerApp.Config.DatabaseUsername,
|
||
ServerApp.Config.DatabasePassword)
|
||
)
|
||
{
|
||
}
|
||
|
||
public void SetupDB()
|
||
{
|
||
try
|
||
{
|
||
foreach (
|
||
var f in
|
||
Directory.EnumerateFiles(Directory.GetCurrentDirectory() + "/Resources/sql/scripts/", "*.sql"))
|
||
{
|
||
Logger.WriteInternal("[DBC] 执行数据库脚本 {0}", f);
|
||
Database.ExecuteSqlCommand(File.ReadAllText(f));
|
||
}
|
||
var revision = ServerInfoes.Find("Revision");
|
||
if (revision == null)
|
||
{
|
||
revision = new ServerInfo { Info = "Revision", Setting = "0" };
|
||
ServerInfoes.Add(revision);
|
||
|
||
//TODO Possibly move this somewhere else?
|
||
Database.ExecuteSqlCommand("ALTER TABLE Accounts AUTO_INCREMENT=10000000");
|
||
}
|
||
SaveChanges();
|
||
|
||
Logger.WriteInternal("[DBC] 加载数据集修订的数据库 {0}", revision.Setting);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logger.WriteException("数据库异常", ex);
|
||
}
|
||
}
|
||
|
||
public bool TestDatabaseConnection2()
|
||
{
|
||
try
|
||
{
|
||
using (var context = new ServerEf())
|
||
{
|
||
// 执行一个简单的查询来测试数据库连接
|
||
context.Database.ExecuteSqlCommand("SELECT 1");
|
||
|
||
Logger.WriteInternal("[DBT] 数据库连接成功。");
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logger.WriteException("数据库连接异常", ex);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public bool TestDatabaseConnection()
|
||
{
|
||
try
|
||
{
|
||
using (var context = new ServerEf())
|
||
{
|
||
context.Database.Initialize(force: false);
|
||
|
||
Logger.WriteInternal("[DBT] 数据库连接成功。");
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Logger.WriteException("数据库连接异常", ex);
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
} |