PSO2SERVER/Server/Logger.cs

367 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using PSO2SERVER.Protocol.Packets;
namespace PSO2SERVER
{
/// <summary>
/// Wrapper for Console's Write and WriteLine functions to add coloring as well as integrate it into the Console System
/// and add dumping to a log file.
/// </summary>
public static class Logger
{
private static readonly StreamWriter Writer = new StreamWriter("SERVER.log", true);
public static bool VerbosePackets = false;
private static void AddLine(ConsoleColor color, string text)
{
// Return if we don't have a ConsoleSystem created yet
if (ServerApp.ConsoleSystem == null) return;
ServerApp.ConsoleSystem.AddLine(color, text);
}
public static void Write(string text, params object[] args)
{
AddLine(ConsoleColor.White, string.Format(text, args));
WriteFile(text, args);
}
public static void WriteObj(object obj)
{
if (obj == null)
{
WriteError("无法分析空的对象.");
return;
}
Type objType = obj.GetType();
Write($"当前分析对象: {objType.FullName}");
// Use reflection to get all public fields of the object
var fields = objType.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in fields)
{
var value = field.GetValue(obj);
// 检查值的类型并转换为十六进制字符串
string hex;
switch (value)
{
case byte b:
hex = b.ToString("X2"); // 2-digit hex for byte
break;
case short s:
hex = s.ToString("X4"); // 4-digit hex for short
break;
case int i:
hex = i.ToString("X8"); // 8-digit hex for int
break;
case long l:
hex = l.ToString("X16"); // 16-digit hex for long
break;
case uint ui:
hex = ui.ToString("X8"); // 8-digit hex for uint
break;
default:
hex = value.ToString(); // Default: fallback to regular ToString
break;
}
Write($"{field.Name}: {value} - 0x{hex}");
}
}
public static void WriteSend(string text, params object[] args)
{
AddLine(ConsoleColor.Green, string.Format(text, args));
WriteFile(text, args);
}
public static void WriteRecv(string text, params object[] args)
{
AddLine(ConsoleColor.Yellow, string.Format(text, args));
WriteFile(text, args);
}
public static void WriteInternal(string text, params object[] args)
{
AddLine(ConsoleColor.Cyan, string.Format(text, args));
WriteFile(text, args);
}
public static void WriteCommand(Client client, string text, params object[] args)
{
if (client == null)
{
AddLine(ConsoleColor.Green, string.Format(text, args));
WriteFile(text, args);
}
else
WriteClient(client, text, args);
}
public static void WriteClient(Client client, string text, params object[] args)
{
var message = string.Format(text, args).Replace('\\', '/');
var packet = new SystemMessagePacket(message, SystemMessagePacket.MessageType.SystemMessage);
client.SendPacket(packet);
}
public static void WriteWarning(string text, params object[] args)
{
AddLine(ConsoleColor.Yellow, string.Format(text, args));
WriteFile(text, args);
}
public static void WriteError(string text, params object[] args)
{
AddLine(ConsoleColor.Red, string.Format(text, args));
WriteFile(text, args);
}
public static void WriteException(string message, Exception ex)
{
var text = string.Empty;
text += string.Format("[ERR] {0} - {1}: {2}", message, ex.GetType(), ex);
if (ex.InnerException != null)
text += string.Format("\n[ERR] Inner Exception: {0}", ex.InnerException);
WriteFile(text);
AddLine(ConsoleColor.Red, text);
}
public static void WriteUnkHex(string text, byte[] array)
{
AddLine(ConsoleColor.Red, text);
// Calculate lines
var lines = 0;
for (var i = 0; i < array.Length; i++)
if ((i % 16) == 0)
lines++;
for (var i = 0; i < lines; i++)
{
var hexString = string.Empty;
// Address
hexString += string.Format("{0:X8} ", i * 16);
// Bytes
for (var j = 0; j < 16; j++)
{
if (j + (i * 16) >= array.Length)
break;
// Append the hex byte with an extra space for every 8 bytes
if (j % 8 == 0 && j > 0)
hexString += ' ';
hexString += string.Format("{0:X2} ", array[j + (i * 16)]);
}
// Spacing
while (hexString.Length < 16 * 4)
hexString += ' ';
// ASCII
for (var j = 0; j < 16; j++)
{
if (j + (i * 16) >= array.Length)
break;
var asciiChar = (char)array[j + (i * 16)];
if (asciiChar == (char)0x00)
asciiChar = '.';
hexString += asciiChar;
}
// Strip off unnecessary stuff
hexString = hexString.Replace('\a', ' '); // Alert beeps
hexString = hexString.Replace('\n', ' '); // Newlines
hexString = hexString.Replace('\r', ' '); // Carriage returns
hexString = hexString.Replace('\\', ' '); // Escape break
AddLine(ConsoleColor.Red, hexString);
WriteFile(hexString);
}
}
public static void WriteHex(string text, byte[] array)
{
AddLine(ConsoleColor.DarkCyan, text);
// Calculate lines
var lines = 0;
for (var i = 0; i < array.Length; i++)
if ((i % 16) == 0)
lines++;
for (var i = 0; i < lines; i++)
{
var hexString = string.Empty;
// Address
hexString += string.Format("{0:X8} ", i * 16);
// Bytes
for (var j = 0; j < 16; j++)
{
if (j + (i * 16) >= array.Length)
break;
// Append the hex byte with an extra space for every 8 bytes
if (j % 8 == 0 && j > 0)
hexString += ' ';
hexString += string.Format("{0:X2} ", array[j + (i * 16)]);
}
// Spacing
while (hexString.Length < 16 * 4)
hexString += ' ';
// ASCII
for (var j = 0; j < 16; j++)
{
if (j + (i * 16) >= array.Length)
break;
var asciiChar = (char)array[j + (i * 16)];
if (asciiChar == (char)0x00)
asciiChar = '.';
hexString += asciiChar;
}
// Strip off unnecessary stuff
hexString = hexString.Replace('\a', ' '); // Alert beeps
hexString = hexString.Replace('\n', ' '); // Newlines
hexString = hexString.Replace('\r', ' '); // Carriage returns
hexString = hexString.Replace('\\', ' '); // Escape break
AddLine(ConsoleColor.White, hexString);
WriteFile(hexString);
}
}
public static void WriteFile(string text, params object[] args)
{
if (args.Length > 0)
Writer.WriteLine(DateTime.Now + " - " + text, args);
else
Writer.WriteLine(DateTime.Now + " - " + text);
// Later we should probably only flush once every PosX amount of lines or on some other condition
Writer.Flush();
}
public static void WriteHeader()
{
Writer.WriteLine();
Writer.WriteLine("--------------------------------------------------");
Writer.WriteLine("\t\t" + DateTime.Now);
Writer.WriteLine("--------------------------------------------------");
}
// 方法:打印结构体的二进制数据
public static void WriteStructBinary(string text, object obj)
{
var byteArray = StructToByteArray(obj);
WriteHex(text, byteArray);
}
// 将结构体转换为字节数组
public static byte[] StructToByteArray(object obj)
{
int size = Marshal.SizeOf(obj);
byte[] byteArray = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(obj, ptr, false);
Marshal.Copy(ptr, byteArray, 0, size);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
return byteArray;
}
// 用于将不同类型的值转换为字节流的方法
public static byte[] ConvertToByteArray(object value)
{
if (value == null)
{
return new byte[0]; // 如果 value 为 null返回空字节数组
}
if (value is byte b)
{
return new byte[] { b }; // byte 转为字节数组
}
else if (value is short s)
{
return BitConverter.GetBytes(s); // short 转为字节数组
}
else if (value is int i)
{
return BitConverter.GetBytes(i); // int 转为字节数组
}
else if (value is long l)
{
return BitConverter.GetBytes(l); // long 转为字节数组
}
else if (value is float f)
{
return BitConverter.GetBytes(f); // float 转为字节数组
}
else if (value is double d)
{
return BitConverter.GetBytes(d); // double 转为字节数组
}
else if (value is string str)
{
return Encoding.UTF8.GetBytes(str); // string 转为字节数组
}
else if (value is bool bval)
{
return BitConverter.GetBytes(bval); // bool 转为字节数组
}
else if (value is decimal dec)
{
return BitConverter.GetBytes(decimal.ToDouble(dec)); // decimal 转为字节数组
}
else
{
return SerializeObject(value); // 对象(如自定义类)转为字节数组
}
}
// 如果是自定义对象,使用二进制序列化转为字节流
public static byte[] SerializeObject(object value)
{
using (var memoryStream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, value); // 将对象序列化
return memoryStream.ToArray(); // 获取字节流
}
}
}
}