完善客户端登录系统信息保存

This commit is contained in:
Longfeng Qin 2024-12-03 13:10:49 +08:00
parent 75380c1a81
commit 98ee7ff349
19 changed files with 158 additions and 82 deletions

View File

@ -277,7 +277,7 @@ namespace PSO2SERVER
// SpawnClone
var spawnClone = new ConsoleCommand(SpawnClone, "spawnclone");
spawnClone.Arguments.Add(new ConsoleCommandArgument("Username", false));
spawnClone.Arguments.Add(new ConsoleCommandArgument("Account Name", false));
spawnClone.Arguments.Add(new ConsoleCommandArgument("Accounts Name", false));
spawnClone.Arguments.Add(new ConsoleCommandArgument("X", false));
spawnClone.Arguments.Add(new ConsoleCommandArgument("Y", false));
spawnClone.Arguments.Add(new ConsoleCommandArgument("Z", false));

View File

@ -48,15 +48,27 @@ namespace PSO2SERVER.Database
public string VideoInfo { get; set; }
}
public class PlayerSystemInfo
public class AccountSystemInfo
{
[Key]
public int PlayerId { get; set; }
public int id { get; set; }
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 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 NPC
@ -160,8 +172,9 @@ namespace PSO2SERVER.Database
[DbConfigurationType(typeof(MySqlEFConfiguration))]
public class ServerEf : DbContext
{
public DbSet<ServerInfo> ServerInfos { get; set; }
public DbSet<Account> Account { get; set; }
public DbSet<ServerInfo> ServerInfoes { get; set; }
public DbSet<Account> Accounts { get; set; }
public DbSet<AccountSystemInfo> AccountSystemInfoes { get; set; }
public DbSet<Character> Characters { get; set; }
public DbSet<Teleport> Teleports { get; set; }
public DbSet<NPC> NPCs { get; set; }
@ -190,14 +203,14 @@ namespace PSO2SERVER.Database
Logger.WriteInternal("[DBC] 执行数据库脚本 {0}", f);
Database.ExecuteSqlCommand(File.ReadAllText(f));
}
var revision = ServerInfos.Find("Revision");
var revision = ServerInfoes.Find("Revision");
if (revision == null)
{
revision = new ServerInfo { Info = "Revision", Setting = "0" };
ServerInfos.Add(revision);
ServerInfoes.Add(revision);
//TODO Possibly move this somewhere else?
Database.ExecuteSqlCommand("ALTER TABLE Account AUTO_INCREMENT=10000000");
Database.ExecuteSqlCommand("ALTER TABLE Accounts AUTO_INCREMENT=10000000");
}
SaveChanges();

View File

@ -31,13 +31,13 @@ namespace PSO2SERVER.Protocol.Handlers
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
// Set Account ID
// Set Accounts ID
//var setPlayerId = new PacketWriter();
//setPlayerId.WriteAccountHeader((uint)context._account.AccountId);
//context.SendPacket(0x06, 0x00, 0, setPlayerId.ToArray());
context.SendPacket(new SetAccountIDPacket(context._account.AccountId));
// Spawn Account
// Spawn Accounts
new CharacterSpawn().HandlePacket(context, flags, data, position, size);
}

View File

@ -37,7 +37,7 @@ namespace PSO2SERVER.Protocol.Handlers
if (c == context || c.Character == null || c.CurrentZone != context.CurrentZone)
continue;
//PacketWriter output = new PacketWriter();
//output.WriteStruct(new ObjectHeader((uint)context._account.AccountId, ObjectType.Account));
//output.WriteStruct(new ObjectHeader((uint)context._account.AccountId, ObjectType.Accounts));
//output.WriteStruct(preformer);
//output.Write(preData);
//output.WriteAscii(command, 0x4315, 0x7A);

View File

@ -31,7 +31,7 @@ namespace PSO2SERVER.Protocol.Handlers
srcObj = new PSOObject
{
Header = srcObject,
Name = "Account"
Name = "Accounts"
};
}
else
@ -53,7 +53,7 @@ namespace PSO2SERVER.Protocol.Handlers
if (teleporterEndpoint == null)
{
Logger.WriteError("[OBJ] Teleporter for {0} in {1} does not contain a destination!", srcObj.Header.ID, "lobby");
// Teleport Account to default point
// Teleport Accounts to default point
context.SendPacket(new TeleportTransferPacket(srcObj, new PSOLocation(0f, 1f, 0f, -0.000031f, -0.417969f, 0.000031f, 134.375f)));
// Unhide player
context.SendPacket(new ObjectActionPacket(dstObject, srcObject, new ObjectHeader(), new ObjectHeader(), "Forwarded"));
@ -70,7 +70,7 @@ namespace PSO2SERVER.Protocol.Handlers
PosY = teleporterEndpoint.PosY,
PosZ = teleporterEndpoint.PosZ,
};
// Teleport Account
// Teleport Accounts
context.SendPacket(new TeleportTransferPacket(srcObj, endpointLocation));
// Unhide player
context.SendPacket(new ObjectActionPacket(dstObject, srcObject, new ObjectHeader(), new ObjectHeader(), "Forwarded"));

View File

@ -23,7 +23,7 @@ namespace PSO2SERVER.Protocol.Handlers
if (c == context || c.Character == null || c.CurrentZone != context.CurrentZone)
continue;
//PacketWriter writer = new PacketWriter();
//writer.WriteStruct(new ObjectHeader((uint)c._account.AccountId, ObjectType.Account));
//writer.WriteStruct(new ObjectHeader((uint)c._account.AccountId, ObjectType.Accounts));
//writer.WriteStruct(actor);
//writer.Write(rest);

View File

@ -101,7 +101,7 @@ namespace PSO2SERVER.Protocol.Handlers
// What am I doing here even
using (var db = new ServerEf())
{
var users = from u in db.Account
var users = from u in db.Accounts
where u.Username.ToLower().Equals(Username.ToLower())
select u;
@ -141,7 +141,7 @@ namespace PSO2SERVER.Protocol.Handlers
// Since we can't display the Nickname prompt yet, just default it to the username
SettingsIni = File.ReadAllText(ServerApp.ServerSettingsKey)
};
db.Account.Add(user);
db.Accounts.Add(user);
db.SaveChanges();
//context.SendPacket(0x11, 0x1e, 0x0, new byte[0x44]); // Request Nickname

View File

@ -95,7 +95,7 @@ namespace PSO2SERVER.Protocol.Handlers
// Assign character to player
context.Character = newCharacter;
// Set Account ID
// Set Accounts ID
context.SendPacket(new CharacterCreateResponsePacket(CharacterCreateResponsePacket.CharacterCreationStatus.Success, (uint)context._account.AccountId));
}

View File

@ -11,6 +11,8 @@ namespace PSO2SERVER.Protocol.Handlers
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data);
var reader = new PacketReader(data, position, size);
var clientTime = reader.ReadUInt64();

View File

@ -1,8 +1,7 @@
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.IO;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using PSO2SERVER.Database;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
@ -12,60 +11,122 @@ namespace PSO2SERVER.Protocol.Handlers
[PacketHandlerAttr(0x11, 0x2D)]
class SystemInformation : PacketHandler
{
public struct SystemInformationPacket
{
public string CpuInfo { get; set; }
public string VideoInfo { get; set; }
public ulong Vram { get; set; }
public ulong TotalRam { get; set; }
public uint Unk1 { get; set; }
public uint 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 ulong TotalDiskSpace { get; set; }
public ulong FreeDiskSpace { get; set; }
}
SystemInformationPacket pkt = new SystemInformationPacket();
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
var reader = new PacketReader(data, position, size);
var cpu_info = reader.ReadAscii(0x883D, 0x9F);
var video_info = reader.ReadAscii(0x883D, 0x9F);
//reader.BaseStream.Seek(8, SeekOrigin.Current);
//var vram = reader.ReadAscii(0x883D, 0x9F);
//var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
//Logger.WriteHex(info, data);
//var windows_version = reader.ReadAscii(0x6C, 190);
pkt.CpuInfo = reader.ReadAscii(0x883D, 0x9F);
pkt.VideoInfo = reader.ReadAscii(0x883D, 0x9F);
pkt.Vram = reader.ReadUInt64();
pkt.TotalRam = reader.ReadUInt64();
pkt.Unk1 = reader.ReadUInt32();
pkt.Unk2 = reader.ReadUInt32();
pkt.WindowsVersion = reader.ReadUtf16(0x883D, 0x9F);
pkt.WindowSize = reader.ReadAscii(0x883D, 0x9F);
pkt.AudioDevices = reader.ReadUtf16(0x883D, 0x9F);
pkt.Unk4 = reader.ReadUtf16(0x883D, 0x9F);
pkt.VideoDriver = reader.ReadUtf16(0x883D, 0x9F);
pkt.TotalDiskSpace = reader.ReadUInt64();
pkt.FreeDiskSpace = reader.ReadUInt64();
// 打印日志
//Logger.Write(
// "System Info: Vram={0}GB, TotalRam={1}GB, WindowsVersion={2}, CpuInfo={3}, VideoInfo={4}, AudioDevices={5}, WindowSize={6}, VideoDriver={7}, Unk1={8}, Unk2={9}, Unk4={10}, TotalDiskSpace={11}GB, FreeDiskSpace={12}GB",
// (pkt.Vram / (1024 * 1024 * 1024)),
// (pkt.TotalRam / (1024 * 1024 * 1024)),
// pkt.WindowsVersion,
// pkt.CpuInfo,
// pkt.VideoInfo,
// pkt.AudioDevices,
// pkt.WindowSize,
// pkt.VideoDriver,
// pkt.Unk1,
// pkt.Unk2,
// pkt.Unk4,
// (pkt.TotalDiskSpace / (1024 * 1024 * 1024)),
// (pkt.FreeDiskSpace / (1024 * 1024 * 1024))
//);
//Logger.Write("Setting 内容: " + windows_version);
// 尝试将数据保存到数据库
SaveSystemInfoToDatabase(context);
}
using (var db = new ServerEf())
private void SaveSystemInfoToDatabase(Client context)
{
try
{
try
using (var db = new ServerEf())
{
var player = db.Account.FirstOrDefault(w => w.AccountId == context._account.AccountId);
if (player == null)
// 创建新的 AccountSystemInfo 对象
var acsinfo = new AccountSystemInfo
{
Logger.WriteError("未找到 AccountId: {0}", context._account.AccountId);
return;
}
AccountId = context._account.AccountId,
Username = context._account.Username,
CpuInfo = pkt.CpuInfo,
VideoInfo = pkt.VideoInfo,
Vram = (long)pkt.Vram,
TotalRam = (long)pkt.TotalRam,
Unk1 = (int)pkt.Unk1,
Unk2 = (int)pkt.Unk2,
WindowsVersion = pkt.WindowsVersion,
WindowSize = pkt.WindowSize,
AudioDevices = pkt.AudioDevices,
Unk4 = pkt.Unk4,
VideoDriver = pkt.VideoDriver,
TotalDiskSpace = (long)pkt.TotalDiskSpace,
FreeDiskSpace = (long)pkt.FreeDiskSpace
};
if (!string.IsNullOrWhiteSpace(cpu_info))
// 使用事务来确保原子性
using (var dbContextTransaction = db.Database.BeginTransaction())
{
player.CpuInfo = cpu_info;
try
{
// 将记录保存到数据库
db.AccountSystemInfoes.Add(acsinfo);
db.SaveChanges();
dbContextTransaction.Commit(); // 提交事务
Logger.Write("系统信息已成功保存到数据库: AccountId={0}, Username={1}", context._account.AccountId, context._account.Username);
}
catch (DbUpdateException dbEx)
{
dbContextTransaction.Rollback(); // 回滚事务
Logger.WriteError("数据库更新时发生异常: {0}", dbEx.Message);
Logger.WriteError("详细信息: {0}", dbEx.InnerException?.Message);
}
catch (Exception ex)
{
dbContextTransaction.Rollback(); // 回滚事务
Logger.WriteError("系统信息保存时发生异常: {0}", ex.Message);
Logger.WriteError("详细信息: {0}", ex.InnerException?.Message);
}
}
if (!string.IsNullOrWhiteSpace(video_info))
{
player.VideoInfo = video_info;
}
// 保存更改并捕获可能的异常
db.SaveChanges();
}
catch (DbUpdateException dbEx)
{
Logger.WriteError("数据库更新时发生异常: {0}", dbEx.Message);
// 处理数据库更新错误
}
catch (Exception ex)
{
Logger.WriteError("构建数据包时发生异常: {0}", ex.Message);
// 处理其他异常情况
}
}
//context.SendPacket(new LoadSettingsPacket(context._account.AccountId));
catch (Exception ex)
{
Logger.WriteError("保存系统信息到数据库时发生未知错误: {0}", ex.Message);
Logger.WriteError("详细信息: {0}", ex.InnerException?.Message);
}
}
}
}

View File

@ -40,7 +40,7 @@ namespace PSO2SERVER.Protocol.Handlers
// {
// var character = db.Characters.FirstOrDefault(c => c.AccountID == charId);
// if (character == null || character.Account == null || character.Account.AccountId != context._account.AccountId)
// if (character == null || character.Accounts == null || character.Accounts.AccountId != context._account.AccountId)
// {
// Logger.WriteError("数据库中未找到 {0} 角色ID {1} ({2})"
// , context._account.Username

View File

@ -34,7 +34,7 @@ namespace PSO2SERVER.Protocol.Handlers
using (var db = new ServerEf())
{
// 先检测角色是否存在
var existingAccount = db.Account.Where(c => c.AccountId == context._account.AccountId).ToList();
var existingAccount = db.Accounts.Where(c => c.AccountId == context._account.AccountId).ToList();
if (existingAccount.Count > 0)
{
// 更新角色名字字段

View File

@ -20,7 +20,7 @@ namespace PSO2SERVER.Protocol.Handlers
{
try
{
var player = db.Account.FirstOrDefault(w => w.AccountId == context._account.AccountId);
var player = db.Accounts.FirstOrDefault(w => w.AccountId == context._account.AccountId);
if (player == null)
{
Logger.WriteError("未找到 AccountId: {0}", context._account.AccountId);

View File

@ -43,7 +43,7 @@ namespace PSO2SERVER.Protocol.Packets
{
var writer = new PacketWriter();
// Account header
// Accounts header
writer.WriteAccountHeader((uint)_character.Account.AccountId);
// Spawn position
@ -85,12 +85,12 @@ namespace PSO2SERVER.Protocol.Packets
jobParam.subClass = ClassType.Phantom;
jobParam.entries.Luster.level = 100;
writer.WriteStruct(jobParam);
writer.WriteBytes(0, 148);
writer.WriteFixedLengthUtf16(_character.Account.Nickname, 16);
writer.WriteBytes(0, 116);
writer.Write((uint)0); // 0x204
writer.Write(IsGM); // gmflag?
//writer.WriteFixedLengthUtf16(_character.Account.Nickname, 16);
for (var i = 0; i < 0x60; i++)
writer.Write((byte)0);

View File

@ -98,7 +98,7 @@ namespace PSO2SERVER.Protocol.Packets
entries[i].nickname = players[i].Account.Nickname;
entries[i].char_name = players[i].Name;
//writer.WriteUtf16(players[i].Name, 0xD863, 0xA9);
//writer.WriteUtf16(players[i].Account.Nickname, 0xD863, 0xA9);
//writer.WriteUtf16(players[i].Accounts.Nickname, 0xD863, 0xA9);
entries[i].level = (byte)players[i].Jobs.entries.hunter.level;
entries[i].sublevel = (byte)players[i].Jobs.entries.hunter.level2;
entries[i].mainClass = players[i].Jobs.mainClass;
@ -119,7 +119,7 @@ namespace PSO2SERVER.Protocol.Packets
// xor: 0xD863, sub: 0xA9
PacketWriter writer = new PacketWriter();
writer.WriteStruct(party_object);
writer.WriteStruct(leader); // Account receiving the thing
writer.WriteStruct(leader); // Accounts receiving the thing
writer.Write(people_amount); // Likely partymembercount
for (int i = 0; i < 4; i++)
{
@ -152,9 +152,9 @@ namespace PSO2SERVER.Protocol.Packets
//for(int i = 0; i < players.Length; i++)
//{
// PartyEntry pe = new PartyEntry();
// writer.WriteStruct(new ObjectHeader((uint)players[i].Account.AccountId, ObjectType.Player)); // Header of player
// writer.WriteStruct(new ObjectHeader((uint)players[i].Accounts.AccountId, ObjectType.Player)); // Header of player
// writer.WriteUtf16(players[i].Name, 0xD863, 0xA9);
// writer.WriteUtf16(players[i].Account.Nickname, 0xD863, 0xA9);
// writer.WriteUtf16(players[i].Accounts.Nickname, 0xD863, 0xA9);
// writer.Write((byte)players[i].Jobs.entries.hunter.level); // Active class level
// writer.Write((byte)players[i].Jobs.entries.hunter.level2); // idk
// writer.Write((byte)players[i].Jobs.mainClass); // idk

View File

@ -18,7 +18,7 @@ namespace PSO2SERVER.Protocol.Packets
{
var writer = new PacketWriter();
writer.Write((byte) 1); // Always 1?
writer.Write((byte) 1); // Always 1? 可能是公会ID uint 涵盖下面3字节
// Padding? Or the above is actually a uint
for (var i = 0; i < 3; i++)
@ -39,7 +39,7 @@ namespace PSO2SERVER.Protocol.Packets
for (var i = 0; i < 36; i++)
writer.Write((byte) 0);
// Account name
// Accounts name
writer.WriteFixedLengthUtf16(_character.Name, 16);
// Unknown?
@ -48,7 +48,7 @@ namespace PSO2SERVER.Protocol.Packets
// Team Name
// We don't actually have team names anywhere, just dump a test here
writer.WriteFixedLengthUtf16("Sancaros", 16);
writer.WriteFixedLengthUtf16("TEAMNAME", 16);
// Unknown
// Somewhere in here is likely a Team ID
@ -60,7 +60,7 @@ namespace PSO2SERVER.Protocol.Packets
public override PacketHeader GetHeader()
{
return new PacketHeader(0x1C, 0x1F, (byte)0);
return new PacketHeader(0x1C, 0x1F, PacketFlags.None);
}
#endregion

View File

@ -8,9 +8,9 @@ namespace PSO2SERVER.Protocol.Packets
{
public class AccountFlagsPacket : Packet
{
// Account flags (0x400 bytes)
// Accounts flags (0x400 bytes)
public List<byte> Flags { get; set; }
// Account parameters (0x100 bytes)
// Accounts parameters (0x100 bytes)
public List<uint> Params { get; set; }
public AccountFlagsPacket()

View File

@ -27,7 +27,7 @@ namespace PSO2SERVER.Protocol.Packets
try
{
// 使用 FirstOrDefault 以避免异常
var player = db.Account.FirstOrDefault(w => w.AccountId == _PlayerId);
var player = db.Accounts.FirstOrDefault(w => w.AccountId == _PlayerId);
if (player == null)
{

View File

@ -110,7 +110,7 @@ namespace PSO2SERVER.Zone
{
//PacketWriter writer = new PacketWriter();
//writer.WriteStruct(new ObjectHeader(3, ObjectType.Map));
//writer.WriteStruct(new ObjectHeader((uint)c._account.AccountId, ObjectType.Account));
//writer.WriteStruct(new ObjectHeader((uint)c._account.AccountId, ObjectType.Accounts));
//writer.Write(0x1); // 8 Zeros
//writer.Write(0); // 8 Zeros
//writer.Write(~(uint)Type); // F4 FF FF FF
@ -190,8 +190,8 @@ namespace PSO2SERVER.Zone
foreach (Client other in Clients)
{
//PacketWriter writer = new PacketWriter();
//writer.WriteStruct(new ObjectHeader((uint)other._account.AccountId, ObjectType.Account));
//writer.WriteStruct(new ObjectHeader((uint)c._account.AccountId, ObjectType.Account));
//writer.WriteStruct(new ObjectHeader((uint)other._account.AccountId, ObjectType.Accounts));
//writer.WriteStruct(new ObjectHeader((uint)c._account.AccountId, ObjectType.Accounts));
//other.SendPacket(0x4, 0x3B, 0x40, writer.ToArray());
other.SendPacket(new DespawnPlayerPacket(other._account.AccountId, c._account.AccountId));
}