using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Timers; using Timer = System.Timers.Timer; using PSO2SERVER.Database; using PSO2SERVER.Models; using PSO2SERVER.Object; using PSO2SERVER.Protocol; using PSO2SERVER.Protocol.Packets; using PSO2SERVER.Zone; using Org.BouncyCastle.Tls; namespace PSO2SERVER { public delegate void ConsoleCommandDelegate(string[] args, int length, string full, Client client); public class ConsoleCommandArgument { public ConsoleCommandArgument(string name, bool optional) { Name = name; Optional = optional; } public string Name { get; set; } public bool Optional { get; set; } } public class ConsoleCommand { public ConsoleCommand(ConsoleCommandDelegate cmd, params string[] cmdNames) { if (cmdNames == null || cmdNames.Length < 1) throw new NotSupportedException(); Command = cmd; Names = new List(cmdNames); Arguments = new List(); } public ConsoleCommandDelegate Command { get; set; } public List Names { get; set; } public List Arguments { get; set; } public string Help { get; set; } public bool Run(string[] args, int length, string full, Client client) { try { Command(args, length, full, client); } catch (IndexOutOfRangeException ex) { Logger.WriteException("无效指令参数", ex); return false; } catch (Exception ex) { Logger.WriteException("指令错误", ex); return false; } return true; } } /// /// Handles commands and drawing/updating the console /// public class ConsoleSystem { private readonly object _consoleLock = new object(); private readonly List _controlKeys = new List { ConsoleKey.Backspace, ConsoleKey.Enter, ConsoleKey.UpArrow, ConsoleKey.DownArrow, ConsoleKey.LeftArrow, ConsoleKey.RightArrow, ConsoleKey.Home, ConsoleKey.End, ConsoleKey.Delete }; private const string Prompt = "[CMD]> "; private string _commandLine = string.Empty; private int _commandIndex; private int _commandRowInConsole; private readonly List _history = new List(); private int _historyIndex; private int _lastDrawnCommandLineSize; private int _maxCommandLineSize = -1; public Thread Thread; public List Commands = new List(); private ConsoleKeyInfo _key; // ReSharper disable once InconsistentNaming public Timer timer; public ConsoleSystem() { Console.Title = ServerApp.ServerName; Console.CursorVisible = true; SetSize(80, 24); timer = new Timer(1000); timer.Elapsed += TimerRefresh; timer.Start(); CreateCommands(); } public int Width { get; private set; } public int Height { get; private set; } public void SetSize(int width, int height) { Width = width; Height = height; _maxCommandLineSize = width - Prompt.Length; Console.SetWindowSize(width, height); } public void AddLine(ConsoleColor color, string text) { lock (_consoleLock) { BlankDrawnCommandLine(); var useColors = ServerApp.Config.UseConsoleColors; var saveColor = Console.ForegroundColor; Console.SetCursorPosition(0, _commandRowInConsole); if (useColors) Console.ForegroundColor = color; Console.WriteLine(text); if (useColors) Console.ForegroundColor = saveColor; Console.WriteLine(); _commandRowInConsole = Console.CursorTop - 1; RefreshCommandLine(); FixCursorPosition(); } } private void BlankDrawnCommandLine() { if (_lastDrawnCommandLineSize > 0) { Console.SetCursorPosition(0, _commandRowInConsole); for (int i = 0; i < _lastDrawnCommandLineSize; i++) Console.Write(' '); _lastDrawnCommandLineSize = 0; } } private void RefreshCommandLine() { BlankDrawnCommandLine(); Console.SetCursorPosition(0, _commandRowInConsole); Console.Write(Prompt); Console.Write(_commandLine); _lastDrawnCommandLineSize = Prompt.Length + _commandLine.Length; } private void FixCursorPosition() { Console.SetCursorPosition(Prompt.Length + _commandIndex, _commandRowInConsole); } private string AssembleInfoBar() { if (ServerApp.Instance != null && ServerApp.Instance.Server != null) { var clients = ServerApp.Instance.Server.Clients.Count; float usage = Process.GetCurrentProcess().PrivateMemorySize64 / 1024 / 1024; var time = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString(); return string.Format("当前玩家: {0} | 实时内存: {1} MB | {2}", clients, usage, time); } return "正在初始化..."; } private void TimerRefresh(object sender, ElapsedEventArgs e) { lock (_consoleLock) { Console.Title = ServerApp.ServerName + " - " + AssembleInfoBar(); } } public static void StartThread() { while (true) { try { ServerApp.ConsoleSystem.CheckInput(); } catch (ThreadInterruptedException ex) { Logger.WriteException("Thread inturrupted", ex); } catch (ThreadStateException ex) { Logger.WriteException("Thread state error", ex); } catch (Exception ex) { Logger.WriteException(string.Empty, ex); } } } public void CreateCommands() { // Help var help = new ConsoleCommand(Help, "help") { Help = "显示服务端所有指令帮助" }; Commands.Add(help); // Config var config = new ConsoleCommand(Config, "config", "c"); config.Arguments.Add(new ConsoleCommandArgument("Save | Load | List | Option Name", false)); config.Arguments.Add(new ConsoleCommandArgument("Value", true)); config.Help = "Set a configuration variable to the specified value"; Commands.Add(config); // Clear var clearLog = new ConsoleCommand(ClearLog, "clear", "cls") { Help = "Clears the current log buffer" }; Commands.Add(clearLog); // Echo var echo = new ConsoleCommand(Echo, "echo") { Help = "Echo the given text back into the Console" }; echo.Arguments.Add(new ConsoleCommandArgument("text", false)); Commands.Add(echo); var lua = new ConsoleCommand(RunLUA, "lua"); lua.Arguments.Add(new ConsoleCommandArgument("user", true)); lua.Arguments.Add(new ConsoleCommandArgument("lua", false)); Commands.Add(lua); // Announce var announce = new ConsoleCommand(Announce, "announce", "a"); announce.Arguments.Add(new ConsoleCommandArgument("Message", false)); announce.Help = "Sends a message to all connected players"; Commands.Add(announce); // ClearPlayers var clearPlayers = new ConsoleCommand(ClearPlayers, "clearplayers", "cp"); clearPlayers.Arguments.Add(new ConsoleCommandArgument("Exempt Username", true)); clearPlayers.Help = "Disconnects all players from the server"; Commands.Add(clearPlayers); // 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("X", false)); spawnClone.Arguments.Add(new ConsoleCommandArgument("Y", false)); spawnClone.Arguments.Add(new ConsoleCommandArgument("Z", false)); spawnClone.Help = "Spawns a clone of your character"; Commands.Add(spawnClone); // SendPacket var sendPacket = new ConsoleCommand(SendPacket, "sendpacket", "sendp"); sendPacket.Arguments.Add(new ConsoleCommandArgument("Name", false)); sendPacket.Arguments.Add(new ConsoleCommandArgument("Type", false)); sendPacket.Arguments.Add(new ConsoleCommandArgument("SubType", false)); sendPacket.Arguments.Add(new ConsoleCommandArgument("Flags", false)); sendPacket.Arguments.Add(new ConsoleCommandArgument("Data ...", false)); sendPacket.Help = "Sends a packet to a client"; Commands.Add(sendPacket); // SendPacketFile var sendPacketFile = new ConsoleCommand(SendPacketFile, "sendpacketfile", "sendpf"); sendPacketFile.Arguments.Add(new ConsoleCommandArgument("Username", false)); sendPacketFile.Arguments.Add(new ConsoleCommandArgument("Filename", false)); sendPacketFile.Help = "Sends the specified file's contents as a packet"; Commands.Add(sendPacketFile); // SendPacketDirectory var sendPacketDirectory = new ConsoleCommand(SendPacketDirectory, "sendpacketdirectory", "sendpd"); sendPacketDirectory.Arguments.Add(new ConsoleCommandArgument("Username", false)); sendPacketDirectory.Arguments.Add(new ConsoleCommandArgument("Dirname", false)); sendPacketDirectory.Help = "Sends the specified directory's contents as a packet"; Commands.Add(sendPacketDirectory); // SendPacketDirectory Slow var sendPacketDirectorySlow = new ConsoleCommand(SendPacketDirectorySlow, "sendpacketdirectoryslow", "sendpds"); sendPacketDirectorySlow.Arguments.Add(new ConsoleCommandArgument("Username", false)); sendPacketDirectorySlow.Arguments.Add(new ConsoleCommandArgument("Dirname", false)); sendPacketDirectorySlow.Arguments.Add(new ConsoleCommandArgument("Sleeptime", false)); sendPacketDirectorySlow.Help = "Sends the specified directory's contents as a packet (With delay between packets)"; Commands.Add(sendPacketDirectorySlow); var teleportPlayer = new ConsoleCommand(TeleportPlayer, "teleportplayer", "tp"); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("RotX", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("RotY", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("RotZ", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("RotW", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("PosX", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("PosY", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("PosZ", false)); teleportPlayer.Arguments.Add(new ConsoleCommandArgument("Username", true)); teleportPlayer.Help = "Teleports a player to the given position."; Commands.Add(teleportPlayer); var teleportPlayer2 = new ConsoleCommand(TeleportPlayer_POS, "teleportplayerpos", "tpp"); teleportPlayer2.Arguments.Add(new ConsoleCommandArgument("PosX", false)); teleportPlayer2.Arguments.Add(new ConsoleCommandArgument("PosY", false)); teleportPlayer2.Arguments.Add(new ConsoleCommandArgument("PosZ", false)); teleportPlayer2.Arguments.Add(new ConsoleCommandArgument("Username", true)); teleportPlayer2.Help = "Teleports a player to the given position. (pos only)"; Commands.Add(teleportPlayer2); var changeThezone = new ConsoleCommand(ChangeArea, "areachange", "map"); changeThezone.Arguments.Add(new ConsoleCommandArgument("username", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("zoneID", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("mapNumber", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("flags", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("seed", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("sizeX", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("sizeY", false)); changeThezone.Arguments.Add(new ConsoleCommandArgument("templateNum", false)); teleportPlayer.Help = "Spawns you elsewhere."; Commands.Add(changeThezone); var SpawnObjectCommand = new ConsoleCommand(SpawnObject, "spawnobject", "sobj"); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("username", true)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("objectName", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("entityID", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("RotX", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("RotY", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("RotZ", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("RotW", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("PosX", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("PosY", false)); SpawnObjectCommand.Arguments.Add(new ConsoleCommandArgument("PosZ", false)); SpawnObjectCommand.Help = "Spawns an object. (Does not contain object arguments/flags."; Commands.Add(SpawnObjectCommand); var ImportNPC = new ConsoleCommand(ImportNPCs, "importnpc"); ImportNPC.Arguments.Add(new ConsoleCommandArgument("zone", false)); ImportNPC.Arguments.Add(new ConsoleCommandArgument("npcfolder", false)); ImportNPC.Help = "Imports a folder of NPC spawn packets into the database."; Commands.Add(ImportNPC); var ImportObject = new ConsoleCommand(ImportObjects, "importobjects"); ImportObject.Arguments.Add(new ConsoleCommandArgument("zone", false)); ImportObject.Arguments.Add(new ConsoleCommandArgument("objectfolder", false)); ImportObject.Help = "Imports a folder of object spawn packets into the database."; Commands.Add(ImportObject); var tellLoc = new ConsoleCommand(TellPosition, "pos") { Help = "Tells you your current location. (Need to be a client to use this.)" }; Commands.Add(tellLoc); // Exit var exit = new ConsoleCommand(Exit, "exit", "quit") { Help = "关闭PSO2服务器" }; Commands.Add(exit); } public void CheckInput() { // Read key _key = Console.ReadKey(true); // Check to make sure this is a valid key to append to the command line var validKey = _controlKeys.All(controlKey => _key.Key != controlKey); // Append key to the command line if (validKey && (_commandLine.Length + 1) < _maxCommandLineSize) { _commandLine = _commandLine.Insert(_commandIndex, _key.KeyChar.ToString()); _commandIndex++; } // Backspace if (_key.Key == ConsoleKey.Backspace && _commandLine.Length > 0 && _commandIndex > 0) { _commandLine = _commandLine.Remove(_commandIndex - 1, 1); _commandIndex--; } // Cursor movement if (_key.Key == ConsoleKey.LeftArrow && _commandLine.Length > 0 && _commandIndex > 0) _commandIndex--; if (_key.Key == ConsoleKey.RightArrow && _commandLine.Length > 0 && _commandIndex <= _commandLine.Length - 1) _commandIndex++; if (_key.Key == ConsoleKey.Home) _commandIndex = 0; if (_key.Key == ConsoleKey.End) _commandIndex = _commandLine.Length; // History if (_key.Key == ConsoleKey.UpArrow && _history.Count > 0) { _historyIndex--; if (_historyIndex < 0) _historyIndex = _history.Count - 1; _commandLine = _history[_historyIndex]; _commandIndex = _history[_historyIndex].Length; } if (_key.Key == ConsoleKey.DownArrow && _history.Count > 0) { _historyIndex++; if (_historyIndex > _history.Count - 1) _historyIndex = 0; _commandLine = _history[_historyIndex]; _commandIndex = _history[_historyIndex].Length; } // Run Command if (_key.Key == ConsoleKey.Enter) { var valid = false; // Stop if the command line is blank if (string.IsNullOrEmpty(_commandLine)) Logger.WriteWarning("[CMD] 未指定指令"); else { // Iterate commands foreach (var command in Commands) { var full = _commandLine; var args = full.Split(' '); if (command.Names.Any(name => args[0].ToLower() == name.ToLower())) { command.Run(args, args.Length, full, null); valid = true; } if (valid) break; } if (!valid) Logger.WriteError("[CMD] {0} - 指令未找到", _commandLine.Split(' ')[0].Trim('\r')); // Add the command line to history and wipe it _history.Add(_commandLine); _historyIndex = _history.Count; _commandLine = string.Empty; } _commandIndex = 0; } lock (_consoleLock) { RefreshCommandLine(); FixCursorPosition(); } } #region Command Handlers // TODO: Use that fancy popup box when sending help to a client private void Help(string[] args, int length, string full, Client client) { Logger.WriteCommand(client, "[CMD] 指令帮助菜单"); foreach (var command in Commands) { if (command.Help != string.Empty) { var help = string.Empty; // Name help += command.Names[0]; // Arguments if (command.Arguments.Count > 0) foreach (var argument in command.Arguments) if (argument.Optional) help += " [" + argument.Name + "]"; else help += " <" + argument.Name + ">"; // Seperator help += " - "; // Help help += command.Help + " "; // Aliases if (command.Names.Count > 1) { help += "[aliases: "; for (var i = 1; i < command.Names.Count; i++) if (i == command.Names.Count - 1) help += command.Names[i]; else help += command.Names[i] + ", "; help += "]"; } // Log it Logger.WriteCommand(client, "[CMD] {0}", help); } } } private void Echo(string[] args, int length, string full, Client client) { var echo = string.Empty; for (var i = 1; i < args.Length; i++) echo += args[i]; Logger.WriteCommand(client, "[CMD] " + echo); } private void Announce(string[] args, int length, string full, Client client) { var message = full.Split('"')[1].Split('"')[0].Trim('\"'); var messagePacket = new SystemMessagePacket(message, SystemMessagePacket.MessageType.GoldenTicker); foreach (var c in Server.Instance.Clients) { if (c.Character == null) continue; c.SendPacket(messagePacket); } Logger.WriteCommand(client, "[CMD] 发送公告至所有玩家"); } private void ClearLog(string[] args, int length, string full, Client client) { // What do, how do we deal with this now --Ninji } private void Config(string[] args, int length, string full, Client client) { var fields = ServerApp.Config.GetType().GetFields(); var field = fields.FirstOrDefault(o => o.Name == args[1]); switch (args[1].ToLower()) { case "save": ServerApp.Config.Save(); break; case "load": ServerApp.Config.Load(); break; case "list": Logger.WriteCommand(client, "[CMD] 设置选项"); foreach (var f in fields) Logger.WriteCommand(client, "[CMD] {0} = {1}", f.Name, f.GetValue(ServerApp.Config)); break; default: // Set a config option if (args.Length < 3) Logger.WriteCommand(client, "[CMD] Too few arguments"); else if (field != null) { var value = args[2].Contains('\"') ? full.Split('"')[1].Split('"')[0].Trim('\"') : args[2]; if (!ServerApp.Config.SetField(args[1], value)) Logger.WriteCommand(client, "[CMD] Config option {0} could not be changed to {1}", args[1], value); else { Logger.WriteCommand(client, "[CMD] Config option {0} changed to {1}", args[1], value); ServerApp.Config.SettingsChanged(); } } else Logger.WriteCommand(client, "[CMD] Config option {0} not found", args[1]); break; } } private void Exit(string[] args, int length, string full, Client client) { Environment.Exit(0); } private void ClearPlayers(string[] args, int length, string full, Client client) { // Temporary haxifications to pull your own connection var id = -1; var foundPlayer = false; if (args.Length > 1) { var name = args[1]; // Find the player id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteCommand(client, "[CMD] Could not find user " + name); return; } } for (var i = 0; i < ServerApp.Instance.Server.Clients.Count; i++) { if (id > -1 && i == id) continue; // This is probably not the right way to do this ServerApp.Instance.Server.Clients[i].Socket.Close(); Logger.WriteCommand(client, "[CMD] Logged out user " + ServerApp.Instance.Server.Clients[i]._account.Username); } Logger.WriteCommand(client, "[CMD] Logged out all players successfully"); } private void SpawnClone(string[] args, int length, string full, Client client) { // Temporary haxifications to pull your own connection var name = args[1].Trim('\"'); var playerName = args[2].Trim('\"'); var x = float.Parse(args[3]); var y = float.Parse(args[4]); var z = float.Parse(args[5]); if (client == null) { var foundPlayer = false; // Find the player var id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteError("[CMD] Could not find user " + name); return; } client = ServerApp.Instance.Server.Clients[id]; } // Default coordinates if (x == 0) x = -0.417969f; if (y == 0) y = 0.000031f; if (z == 0) z = 134.375f; var fakePlayer = new Account { Username = name, Nickname = playerName, AccountId = (12345678 + new Random().Next()) }; var fakeChar = new Character { CharacterID = 12345678 + new Random().Next(), Account = fakePlayer, Name = playerName, Looks = client.Character.Looks, Jobs = client.Character.Jobs }; var fakePacket = new CharacterSpawnPacket(fakeChar, new PSOLocation(0f, 1f, 0f, 0f, x, y, z), false) { }; client.SendPacket(fakePacket); Logger.WriteCommand(client, "[CMD] 克隆 {0} 玩家名称 {1} 生成", name, playerName); } private void SendPacket(string[] args, int length, string full, Client client) { var name = args[1].Trim('\"'); var type = byte.Parse(args[2]); var subType = byte.Parse(args[3]); var flags = byte.Parse(args[4]); var data = new byte[args.Length - 5]; var foundPlayer = false; // Find the player var id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteCommand(client, "[CMD] 无法找到 " + name); return; } if (args.Length >= 5) { var packetSize = 4; while (++packetSize < args.Length) data[packetSize - 5] = byte.Parse(args[packetSize]); } // Send packet ServerApp.Instance.Server.Clients[id].SendPacket(type, subType, flags, data); Logger.WriteCommand(client, "[CMD] Sent packet {0:X}-{1:X} with flags {2} to {3}", type, subType, flags, name); } private void SendPacketDirectory(string[] args, int length, string full, Client client) { var name = args[1].Trim('\"'); var dirname = args[2].Trim('\"'); var foundPlayer = false; // Find the player var id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteCommand(client, "[CMD] Could not find user " + name); return; } // Pull packets from the specified directory var packetList = Directory.GetFiles(dirname); Array.Sort(packetList); foreach (var path in packetList) { var index = -1; var data = File.ReadAllBytes(path); var packet = new byte[data.Length - 8]; // Strip the header out while (++index < data.Length - 8) packet[index] = data[index + 8]; // Send packet ServerApp.Instance.Server.Clients[id].SendPacket(data[4], data[5], data[6], packet); Logger.WriteCommand(client, "[CMD] Sent contents of {0} as packet {1:X}-{2:X} with flags {3} to {4}", path, data[4], data[5], data[6], name); } } private void SendPacketDirectorySlow(string[] args, int length, string full, Client client) { var name = args[1].Trim('\"'); var dirname = args[2].Trim('\"'); var delay = Int32.Parse(args[3]); var foundPlayer = false; // Find the player var id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteCommand(client, "[CMD] Could not find user " + name); return; } // Pull packets from the specified directory var packetList = Directory.GetFiles(dirname); Array.Sort(packetList); foreach (var path in packetList) { var index = -1; var data = File.ReadAllBytes(path); var packet = new byte[data.Length - 8]; // Strip the header out while (++index < data.Length - 8) packet[index] = data[index + 8]; // Send packet ServerApp.Instance.Server.Clients[id].SendPacket(data[4], data[5], data[6], packet); Logger.WriteCommand(client, "[CMD] Sent contents of {0} as packet {1:X}-{2:X} with flags {3} to {4}", path, data[4], data[5], data[6], name); Thread.Sleep(delay); } } private void SendPacketFile(string[] args, int length, string full, Client client) { var name = args[1].Trim('\"'); var filename = args[2].Trim('\"'); var foundPlayer = false; // Find the player var id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteError("[CMD] Could not find user " + name); return; } // Pull packet from the specified file var index = -1; var data = File.ReadAllBytes(filename); var packet = new byte[data.Length - 8]; // Strip the header out while (++index < data.Length - 8) packet[index] = data[index + 8]; // Send packet ServerApp.Instance.Server.Clients[id].SendPacket(data[4], data[5], data[6], packet); Logger.WriteCommand(client, "[CMD] Sent contents of {0} as packet {1:X}-{2:X} with flags {3} to {4}", filename, data[4], data[5], data[6], name); } private void TeleportPlayer(string[] args, int length, string full, Client client) { var foundPlayer = false; var id = 0; if (client != null) { id = client._account.AccountId; foundPlayer = true; } else { var name = args[8].Trim('\"'); Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; client = ServerApp.Instance.Server.Clients[id]; } // Couldn't find the username if (!foundPlayer) { Logger.WriteError("[CMD] Could not find user."); return; } PSOLocation destination = new PSOLocation(float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3]), float.Parse(args[4]), float.Parse(args[5]), float.Parse(args[6]), float.Parse(args[7])); client.SendPacket(new TeleportTransferPacket(ObjectManager.Instance.getObjectByID("lobby", 443), destination)); } private void TeleportPlayer_POS(string[] args, int length, string full, Client client) { var foundPlayer = false; var id = 0; if (client != null) { id = client._account.AccountId; foundPlayer = true; } else { var name = args[4].Trim('\"'); Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; client = ServerApp.Instance.Server.Clients[id]; } // Couldn't find the username if (!foundPlayer) { Logger.WriteError("[CMD] Could not find user."); return; } PSOLocation destination = new PSOLocation(0f, 1f, 0f, 0f, float.Parse(args[1]), float.Parse(args[2]), float.Parse(args[3])); client.SendPacket(new TeleportTransferPacket(ObjectManager.Instance.getObjectByID("lobby", 443), destination)); } private void ChangeArea(string[] args, int length, string full, Client client) { var name = args[1].Trim('\"'); var foundPlayer = false; var id = Helper.FindPlayerByUsername(name); if (id != -1) foundPlayer = true; // Couldn't find the username if (!foundPlayer) { Logger.WriteError("[CMD] 未找到玩家 " + name); return; } Client context = ServerApp.Instance.Server.Clients[id]; Map dstMap; if (!ZoneManager.Instance.InstanceExists(String.Format("tpinstance_{0}_{1}", Int32.Parse(args[3]), Int32.Parse(args[8])))) { dstMap = new Map("tpmap", Int32.Parse(args[3]), Int32.Parse(args[8]), (Map.MapType)Int32.Parse(args[2]), (Map.MapFlags)Int32.Parse(args[4])) { GenerationArgs = new Map.GenParam() { seed = UInt32.Parse(args[5]), xsize = UInt32.Parse(args[6]), ysize = UInt32.Parse(args[7]) } }; ZoneManager.Instance.NewInstance(String.Format("tpinstance_{0}", Int32.Parse(args[3])), dstMap); } else { dstMap = ZoneManager.Instance.MapFromInstance("tpmap", String.Format("tpinstance_{0}_{1}", Int32.Parse(args[3]), Int32.Parse(args[8]))); } dstMap.SpawnClient(context, dstMap.GetDefaultLocation()); PSOLocation destination = new PSOLocation(float.Parse(args[2]), float.Parse(args[3]), float.Parse(args[4]), float.Parse(args[5]), float.Parse(args[6]), float.Parse(args[7]), float.Parse(args[8])); ServerApp.Instance.Server.Clients[id].SendPacket(new TeleportTransferPacket(ObjectManager.Instance.getObjectByID("lobby", 443), destination)); context.SendPacket(new ObjectSpawnPacket(ObjectManager.Instance.getObjectByID(443))); var objects = ObjectManager.Instance.GetObjectsForZone("casino"); foreach (var obj in objects) { context.SendPacket(new ObjectSpawnPacket(obj)); } context.SendPacket(new UnlockControlsPacket()); } private void SpawnObject(string[] args, int length, string full, Client client) { if(client == null) { var id = Helper.FindPlayerByUsername(args[1]); if (id == -1) return; client = ServerApp.Instance.Server.Clients[id]; } else { string[] newargs = new string[args.Length + 1]; newargs[0] = ""; newargs[1] = ""; Array.Copy(args, 1, newargs, 2, 9); args = newargs; } PSOObject obj = new PSOObject { Name = args[2], Header = new ObjectHeader((uint)Int32.Parse(args[3]), ObjectType.Object), Position = new PSOLocation(float.Parse(args[4]), float.Parse(args[5]), float.Parse(args[6]), float.Parse(args[7]), float.Parse(args[8]), float.Parse(args[9]), float.Parse(args[10])), Things = new PSOObject.PSOObjectThing[0] }; client.SendPacket(new ObjectSpawnPacket(obj)); } private void RunLUA(string[] args, int length, string full, Client client) { if (client == null) { var id = Helper.FindPlayerByUsername(args[1]); if (id == -1) return; client = ServerApp.Instance.Server.Clients[id]; } else { string[] newargs = new string[args.Length + 1]; newargs[0] = ""; newargs[1] = ""; Array.Copy(args, 1, newargs, 2, args.Length - 1); args = newargs; } PacketWriter luaPacket = new PacketWriter(); luaPacket.Write((UInt16)1); luaPacket.Write((UInt16)1); luaPacket.WriteAscii(String.Join(" ", args, 2, args.Length - 2), 0xD975, 0x2F); client.SendPacket(0x10, 0x3, 0x4, luaPacket.ToArray()); } //private void ImportNPCs(string[] args, int length, string full, Client client) //{ // string zone = args[1]; // string folder = args[2]; // var packetList = Directory.GetFiles(folder); // Array.Sort(packetList); // List newNPCs = new List(); // foreach (var path in packetList) // { // var data = File.ReadAllBytes(path); // PacketReader reader = new PacketReader(data); // PacketHeader header = reader.ReadStruct(); // if (header.Type != 0x8 || header.Subtype != 0xC) // { // Logger.WriteWarning("[WRN] File {0} not an NPC spawn packet, skipping.", path); // continue; // } // NPC newNPC = new NPC // { // EntityID = (int)reader.ReadStruct().ID // }; // var pos = reader.ReadEntityPosition(); // newNPC.RotX = pos.RotX; // newNPC.RotY = pos.RotY; // newNPC.RotZ = pos.RotZ; // newNPC.RotW = pos.RotW; // newNPC.PosX = pos.PosX; // newNPC.PosY = pos.PosY; // newNPC.PosZ = pos.PosZ; // reader.ReadInt16(); // newNPC.NPCName = reader.ReadFixedLengthAscii(0x20); // newNPC.ZoneName = zone; // newNPCs.Add(newNPC); // Logger.WriteInternal("[NPC] Adding new NPC {0} to the database for zone {1}", newNPC.NPCName, zone); // } // using (var db = new ServerEf()) // { // db.NPCs.AddRange(newNPCs); // db.SaveChanges(); // } //} private void ImportNPCs(string[] args, int length, string full, Client client) { string zone = args[1]; string folder = args[2]; var packetList = Directory.GetFiles(folder).OrderBy(f => f).ToList(); var newNPCs = new List(); foreach (var path in packetList) { var data = File.ReadAllBytes(path); var reader = new PacketReader(data); var header = reader.ReadStruct(); if (header.Type != 0x8 || header.Subtype != 0xC) { Logger.WriteWarning($"[WRN] File {path} not an NPC spawn packet, skipping."); continue; } var npc = new NPC { EntityID = (int)reader.ReadStruct().ID, PosX = reader.ReadEntityPosition().PosX, PosY = reader.ReadEntityPosition().PosY, PosZ = reader.ReadEntityPosition().PosZ, RotX = reader.ReadEntityPosition().RotX, RotY = reader.ReadEntityPosition().RotY, RotZ = reader.ReadEntityPosition().RotZ, RotW = reader.ReadEntityPosition().RotW, NPCName = reader.ReadFixedLengthAscii(0x20), ZoneName = zone }; reader.ReadInt16(); // Assuming this read is necessary newNPCs.Add(npc); Logger.WriteInternal($"[NPC] Adding new NPC {npc.NPCName} to the database for zone {zone}"); } using (var db = new ServerEf()) { db.NPCs.AddRange(newNPCs); db.SaveChanges(); } } private void ImportObjects(string[] args, int length, string full, Client client) { string zone = args[1]; string folder = args[2]; var packetList = Directory.GetFiles(folder); Array.Sort(packetList); List newObjects = new List(); foreach (var path in packetList) { var data = File.ReadAllBytes(path); PacketReader reader = new PacketReader(data); PacketHeader header = reader.ReadStruct(); if (header.Type != 0x8 || header.Subtype != 0xB) { Logger.WriteWarning("[WRN] File {0} not an Object spawn packet, skipping.", path); continue; } GameObject newObj = new GameObject { ObjectID = (int)reader.ReadStruct().ID }; var pos = reader.ReadEntityPosition(); newObj.RotX = pos.RotX; newObj.RotY = pos.RotY; newObj.RotZ = pos.RotZ; newObj.RotW = pos.RotW; newObj.PosX = pos.PosX; newObj.PosY = pos.PosY; newObj.PosZ = pos.PosZ; reader.ReadInt16(); newObj.ObjectName = reader.ReadFixedLengthAscii(0x2C); var objHeader = reader.ReadStruct(); // Seems to always be blank... if (objHeader.ID != 0) Logger.WriteWarning("[OBJ] It seems object {0} has a nonzero objHeader! ({1}) Investigate.", newObj.ObjectName, objHeader.ID); newObj.ZoneName = zone; var thingCount = reader.ReadUInt32(); newObj.ObjectFlags = new byte[thingCount * 4]; for (int i = 0; i < thingCount; i++) { Buffer.BlockCopy(BitConverter.GetBytes(reader.ReadUInt32()), 0, newObj.ObjectFlags, i * 4, 4); // This should work } newObjects.Add(newObj); Logger.WriteInternal("[OBJ] Adding new Object {0} to the database for zone {1}", newObj.ObjectName, zone); } using (var db = new ServerEf()) { db.GameObjects.AddRange(newObjects); db.SaveChanges(); } } private void TellPosition(string[] args, int length, string full, Client client) { if (client == null) { Logger.WriteError("[CMD] You need to be a client to run this command!"); } else { Logger.WriteCommand(client, "[CMD] {0}", client.CurrentLocation.ToString()); } } #endregion } }