context: /*
  	Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCForge)
  	
  	Dual-licensed under the	Educational Community License, Version 2.0 and
  	the GNU General Public License, Version 3 (the "Licenses"); you may
  	not use this file except in compliance with the Licenses. You may
  	obtain a copy of the Licenses at
  	
  	http://www.opensource.org/licenses/ecl2.php
  	http://www.gnu.org/licenses/gpl-3.0.html
  	
  	Unless required by applicable law or agreed to in writing,
  	software distributed under the Licenses are distributed on an "AS IS"
  	BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
  	or implied. See the Licenses for the specific language governing
  	permissions and limitations under the Licenses.
  */
  using System;
  using System.Threading;
  using System.Net;
  using System.Net.Sockets;
  using System.Collections.Generic;
  using System.IO.Compression;
  using System.IO;
  using System.Text.RegularExpressions;
  using System.Security.Cryptography;
  using System.Data;
  using System.Linq;
  
  namespace MCForge
  {
      public sealed partial class Player : IDisposable
      {
          public static List<Player> players = new List<Player>();
          public static Dictionary<string, string> left = new Dictionary<string, string>();
          public static List<Player> connections = new List<Player>(Server.players);
          System.Timers.Timer muteTimer = new System.Timers.Timer(1000);
          public static List<string> emoteList = new List<string>();
          public List<string> listignored = new List<string>();
          public List<string> mapgroups = new List<string>();
          public static List<string> globalignores = new List<string>();
          public static int totalMySQLFailed = 0;
          public static byte number { get { return (byte)players.Count; } }
          static System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
          static MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
          public static List<Player> totalplayers = new List<Player>();
          public static string lastMSG = "";
  
          public static bool storeHelp = false;
          public static string storedHelp = "";
  
          Socket socket;
          System.Timers.Timer timespent = new System.Timers.Timer(1000);
          System.Timers.Timer loginTimer = new System.Timers.Timer(1000);
          public System.Timers.Timer pingTimer = new System.Timers.Timer(2000);
          System.Timers.Timer extraTimer = new System.Timers.Timer(22000);
          public System.Timers.Timer afkTimer = new System.Timers.Timer(2000);
          public int afkCount = 0;
          public DateTime afkStart;
  
          public bool megaBoid = false;
          public bool cmdTimer = false;
  
          byte[] buffer = new byte[0];
          byte[] tempbuffer = new byte[0xFF];
          public bool disconnected = false;
          public string time;
          public string name;
          public string realName;
          public int warn = 0;
          public byte id;
          public int userID = -1;
          public string ip;
          public string color;
          public Group group;
          public bool hidden = false;
          public bool painting = false;
          public bool muted = false;
          public bool jailed = false;
          public bool invincible = false;
          public string prefix = "";
          public string title = "";
          public string titlecolor;
          public int TotalMessagesSent = 0;
          public int passtries = 0;
          public int ponycount = 0;
          public int rdcount = 0;
          public bool hasreadrules = false;
  
  
  
          //Pyramid Code
  
          public int pyramidx1;
          public int pyramidx2;
          public int pyramidy1;
          public int pyramidy2;
          public int pyramidz1;
          public int pyramidz2;
          public string pyramidblock;
          public int pyramidtotal;
          public int pyramidtotal2;
          public bool pyramidsilent = false;
  
          public bool deleteMode = false;
          public bool ignorePermission = false;
          public bool ignoreGrief = false;
          public bool parseSmiley = true;
          public bool smileySaved = true;
          public bool opchat = false;
          public bool adminchat = false;
          public bool onWhitelist = false;
          public bool whisper = false;
          public string whisperTo = "";
          public bool ignoreglobal = false;
  
          public string storedMessage = "";
  
          public bool trainGrab = false;
          public bool onTrain = false;
          public bool allowTnt = true;
  
          public bool frozen = false;
          public string following = "";
          public string possess = "";
  
          // Only used for possession.
          //Using for anything else can cause unintended effects!
          public bool canBuild = true;
  
          public int money = 0;
          public long overallBlocks = 0;
  
          public int loginBlocks = 0;
  
          public DateTime timeLogged;
          public DateTime firstLogin;
          public int totalLogins = 0;
          public int totalKicked = 0;
          public int overallDeath = 0;
  
          public string savedcolor = "";
  
          public bool staticCommands = false;
  
          public DateTime ZoneSpam;
          public bool ZoneCheck = false;
          public bool zoneDel = false;
  
          public Thread commThread;
          public bool commUse = false;
  
          public bool aiming;
          public bool isFlying = false;
  
          public bool joker = false;
          public bool adminpen = false;
  
          public bool voice = false;
          public string voicestring = "";
          public int consecutivemessages = 0;
  
          //CTF
          public Team team;
          public Team hasflag;
          public string CTFtempcolor;
          public string CTFtempprefix;
          public bool carryingFlag;
          public bool spawning = false;
          public bool teamchat = false;
          public int health = 100;
  
          //Countdown
          public bool playerofcountdown = false;
          public bool incountdown = false;
          public ushort countdowntempx;
          public ushort countdowntempz;
          public bool countdownsettemps = false;
  
          //Zombie
          public bool referee = false;
          public string Original = "";
          public int blockCount = 50;
          public bool voted = false;
          public int blocksStacked = 0;
          public int infectThisRound = 0;
          public int lastYblock = 0;
          public int lastXblock = 0;
          public int lastZblock = 0;
          public ushort lastXpos = 0;
          public ushort lastZpos = 0;
          public bool infected = false;
          public bool aka = false;
          public bool flipHead = true;
          public int playersInfected = 1;
          public int NoClipcount = 0;
          public bool goingToLevel = false;
  
          //Copy
          public List<CopyPos> CopyBuffer = new List<CopyPos>();
          public struct CopyPos { public ushort x, y, z; public byte type; }
          public bool copyAir = false;
          public int[] copyoffset = new int[3] { 0, 0, 0 };
          public ushort[] copystart = new ushort[3] { 0, 0, 0 };
  
          //Undo
          public struct UndoPos { public ushort x, y, z; public byte type, newtype; public string mapName; public DateTime timePlaced; }
          public List<UndoPos> UndoBuffer = new List<UndoPos>();
          public List<UndoPos> RedoBuffer = new List<UndoPos>();
  
  
          public bool showPortals = false;
          public bool showMBs = false;
  
          public string prevMsg = "";
  
          //Block Change variable holding
          public int[] BcVar;
  
  
          //Movement
          public ushort oldBlock = 0;
          public ushort deathCount = 0;
          public byte deathBlock;
  
          //Games
          public DateTime lastDeath = DateTime.Now;
  
          public byte BlockAction = 0;  //0-Nothing 1-solid 2-lava 3-water 4-active_lava 5 Active_water 6 OpGlass 7 BluePort 8 OrangePort
          public byte modeType = 0;
          public byte[] bindings = new byte[128];
          public string[] cmdBind = new string[10];
          public string[] messageBind = new string[10];
          public string lastCMD = "";
  
          public Level level = Server.mainLevel;
          public bool Loading = true;     //True if player is loading a map.
          public ushort[] lastClick = new ushort[3] { 0, 0, 0 };
  
          public ushort[] pos = new ushort[3] { 0, 0, 0 };
          ushort[] oldpos = new ushort[3] { 0, 0, 0 };
          ushort[] basepos = new ushort[3] { 0, 0, 0 };
          public byte[] rot = new byte[2] { 0, 0 };
          byte[] oldrot = new byte[2] { 0, 0 };
  
          // grief/spam detection
          public static int spamBlockCount = 200;
          public static int spamBlockTimer = 5;
          Queue<DateTime> spamBlockLog = new Queue<DateTime>(spamBlockCount);
  
          public static int spamChatCount = 3;
          public static int spamChatTimer = 4;
          Queue<DateTime> spamChatLog = new Queue<DateTime>(spamChatCount);
  
          // CmdVoteKick
          public VoteKickChoice voteKickChoice = VoteKickChoice.HasntVoted;
  
          // Extra storage for custom commands
          public ExtrasCollection Extras = new ExtrasCollection();
  
          //Chatrooms
          public string Chatroom;
          public List<string> spyChatRooms = new List<string>();
          public DateTime lastchatroomglobal = new DateTime();
  
          //Waypoints
          public List<Waypoint.WP> Waypoints = new List<Waypoint.WP>();
  
          public bool loggedIn = false;
  
          private Player()
          {
              //Only necessary for a "flatcopy".
  
          }
  
          public static string CheckPlayerStatus(Player p)
          {
              if (p.hidden)
                  return "hidden";
              if (Server.afkset.Contains(p.name))
                  return "afk";
              return "active";
          }
  
          public bool CheckIfInsideBlock(Player p)
          {
              if (goingToLevel)
              {
                  return false;
              }
              int px = p.pos[0] / 32;
              int py = p.pos[1] / 32;
              int pz = p.pos[2] / 32;
              ushort x, y, z;
              x = (ushort)px;
              y = (ushort)py;
              z = (ushort)pz;
              y = (ushort)Math.Round((decimal)(((y * 32) + 4) / 32));
  
              byte b = this.level.GetTile(x, (ushort)((int)y - 1), z);
              byte b1 = this.level.GetTile(x, (ushort)((int)y - 2), z);
  
              if (!Block.Walkthrough(b) && !Block.Walkthrough(b1))
              {
                  return true;
              }
              else
              {
                  return false;
              }
          }
  
          //This is so that plugin devs can declare a player without needing a socket..
          //They would still have to do p.Dispose()..
          public Player(string playername) { name = playername; }
  
          public Player(Socket s)
          {
              try
              {
                  socket = s;
                  ip = socket.RemoteEndPoint.ToString().Split(':')[0];
                  Server.s.Log(ip + " connected to the server.");
  
                  for (byte i = 0; i < 128; ++i) bindings[i] = i;
  
                  socket.BeginReceive(tempbuffer, 0, tempbuffer.Length, SocketFlags.None, new AsyncCallback(Receive), this);
                  timespent.Elapsed += delegate
                  {
                      if (!Loading)
                      {
                          try
                          {
                              int Days = Convert.ToInt32(time.Split(' ')[0]);
                              int Hours = Convert.ToInt32(time.Split(' ')[1]);
                              int Minutes = Convert.ToInt32(time.Split(' ')[2]);
                              int Seconds = Convert.ToInt32(time.Split(' ')[3]);
                              Seconds++;
                              if (Seconds >= 60)
                              {
                                  Minutes++;
                                  Seconds = 0;
                              }
                              if (Minutes >= 60)
                              {
                                  Hours++;
                                  Minutes = 0;
                              }
                              if (Hours >= 24)
                              {
                                  Days++;
                                  Hours = 0;
                              }
                              time = "" + Days + " " + Hours + " " + Minutes + " " + Seconds;
                          }
                          catch { time = "0 0 0 1"; }
                      }
                  };
                  timespent.Start();
                  loginTimer.Elapsed += delegate
                  {
                      if (!Loading)
                      {
                          loginTimer.Stop();
                          if (File.Exists("text/welcome.txt"))
                          {
                              try
                              {
                                  using (StreamReader wm = File.OpenText("text/welcome.txt"))
                                  {
                                      List<string> welcome = new List<string>();
                                      while (!wm.EndOfStream)
                                          welcome.Add(wm.ReadLine());
                                      foreach (string w in welcome)
                                          SendMessage(w);
                                  }
                              }
                              catch { }
                          }
                          else
                          {
                              Server.s.Log("Could not find Welcome.txt. Using default.");
                              File.WriteAllText("text/welcome.txt", "Welcome to my server!");
                          }
                          extraTimer.Start();
                          loginTimer.Dispose();
                      }
                  }; loginTimer.Start();
  
                  pingTimer.Elapsed += delegate { SendPing(); };
                  pingTimer.Start();
  
                  extraTimer.Elapsed += delegate
                  {
                      extraTimer.Stop();
  
                      try
                      {
                          if (!Group.Find("Nobody").commands.Contains("inbox") && !Group.Find("Nobody").commands.Contains("send"))
                          {
                              DataTable Inbox = MySQL.fillData("SELECT * FROM `Inbox" + name + "`", true);
  
                              SendMessage("&cYou have &f" + Inbox.Rows.Count + Server.DefaultColor + " &cmessages in /inbox");
                              Inbox.Dispose();
                          }
                      }
                      catch { }
                      if (Server.updateTimer.Interval > 1000) SendMessage("Lowlag mode is currently &aON.");
                      try
                      {
                          if (!Group.Find("Nobody").commands.Contains("pay") && !Group.Find("Nobody").commands.Contains("give") && !Group.Find("Nobody").commands.Contains("take")) SendMessage("You currently have &a" + money + Server.DefaultColor + " " + Server.moneys);
                      }
                      catch { }
                      SendMessage("You have modified &a" + overallBlocks + Server.DefaultColor + " blocks!");
                      if (players.Count == 1)
                          SendMessage("There is currently &a" + players.Count + " player online.");
                      else
                          SendMessage("There are currently &a" + players.Count + " players online.");
                      try
                      {
                          if (!Group.Find("Nobody").commands.Contains("award") && !Group.Find("Nobody").commands.Contains("awards") && !Group.Find("Nobody").commands.Contains("awardmod")) SendMessage("You have " + Awards.awardAmount(name) + " awards.");
                      }
                      catch { }
                      try { Gui.Window.thisWindow.UpdatePlyersListBox(); }
                      catch { }
                      extraTimer.Dispose();
                  };
  
                  afkTimer.Elapsed += delegate
                  {
                      if (name == "") return;
  
                      if (Server.afkset.Contains(name))
                      {
                          afkCount = 0;
                          if (Server.afkkick > 0 && group.Permission < LevelPermission.Operator)
                              if (afkStart.AddMinutes(Server.afkkick) < DateTime.Now)
                                  Kick("Auto-kick, AFK for " + Server.afkkick + " minutes");
                          if ((oldpos[0] != pos[0] || oldpos[1] != pos[1] || oldpos[2] != pos[2]) && (oldrot[0] != rot[0] || oldrot[1] != rot[1]))
                              Command.all.Find("afk").Use(this, "");
                      }
                      else
                      {
                          if (oldpos[0] == pos[0] && oldpos[1] == pos[1] && oldpos[2] == pos[2] && oldrot[0] == rot[0] && oldrot[1] == rot[1])
                              afkCount++;
                          else
                              afkCount = 0;
  
                          if (afkCount > Server.afkminutes * 30)
                          {
                              if (this != null && !this.name.Equals(""))
                              {
                                  Command.all.Find("afk").Use(this, "auto: Not moved for " + Server.afkminutes + " minutes");
                                  afkCount = 0;
                              }
                          }
                      }
                  };
                  if (Server.afkminutes > 0) afkTimer.Start();
  
                  connections.Add(this);
              }
              catch (Exception e) { Kick("Login failed!"); Server.ErrorLog(e); }
          }
  
          public void save()
          {
              string commandString =
                  "UPDATE Players SET IP='" + ip + "'" +
                  ", LastLogin='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "'" +
                  ", totalLogin=" + totalLogins +
                  ", totalDeaths=" + overallDeath +
                  ", Money=" + money +
                  ", totalBlocks=" + overallBlocks + " + " + loginBlocks +
                  ", totalKicked=" + totalKicked +
                  ", TimeSpent='" + time +
                  "' WHERE Name='" + name + "'";
  
              MySQL.executeQuery(commandString);
  
              try
              {
                  if (!smileySaved)
                  {
                      if (parseSmiley)
                          emoteList.RemoveAll(s => s == name);
                      else
                          emoteList.Add(name);
  
                      File.WriteAllLines("text/emotelist.txt", emoteList.ToArray());
                      smileySaved = true;
                  }
              }
              catch (Exception e)
              {
                  Server.ErrorLog(e);
              }
          }
  
          #region == INCOMING ==
          static void Receive(IAsyncResult result)
          {
              //    Server.s.Log(result.AsyncState.ToString());
              Player p = (Player)result.AsyncState;
              if (p.disconnected || p.socket == null)
                  return;
              try
              {
                  int length = p.socket.EndReceive(result);
                  if (length == 0) { p.Disconnect(); return; }
  
                  byte[] b = new byte[p.buffer.Length + length];
                  Buffer.BlockCopy(p.buffer, 0, b, 0, p.buffer.Length);
                  Buffer.BlockCopy(p.tempbuffer, 0, b, p.buffer.Length, length);
  
                  p.buffer = p.HandleMessage(b);
                  p.socket.BeginReceive(p.tempbuffer, 0, p.tempbuffer.Length, SocketFlags.None,
                                        new AsyncCallback(Receive), p);
              }
              catch (SocketException e)
              {
                  p.Disconnect();
              }
              catch (ObjectDisposedException e)
              {
                  // Player is no longer connected, socket was closed
                  // Mark this as disconnected and remove them from active connection list
                  p.disconnected = true;
                  if (connections.Contains(p))
                  {
                      connections.Remove(p);
                  }
              }
              catch (Exception e)
              {
                  Server.ErrorLog(e);
                  p.Kick("Error!");
              }
          }
          byte[] HandleMessage(byte[] buffer)
          {
              try
              {
                  int length = 0; byte msg = buffer[0];
                  // Get the length of the message by checking the first byte
                  switch (msg)
                  {
                      case 0:
                          length = 130;
                          break; // login
                      case 5:
                          if (!loggedIn)
                              goto default;
                          length = 8;
                          break; // blockchange
                      case 8:
                          if (!loggedIn)
                              goto default;
                          length = 9;
                          break; // input
                      case 13:
                          if (!loggedIn)
                              goto default;
                          length = 65;
                          break; // chat
                      default:
                          Kick("Unhandled message id \"" + msg + "\"!");
                          return new byte[0];
                  }
                  if (buffer.Length > length)
                  {
                      byte[] message = new byte[length];
                      Buffer.BlockCopy(buffer, 1, message, 0, length);
  
                      byte[] tempbuffer = new byte[buffer.Length - length - 1];
                      Buffer.BlockCopy(buffer, length + 1, tempbuffer, 0, buffer.Length - length - 1);
  
                      buffer = tempbuffer;
  
                      // Thread thread = null; 
                      switch (msg)
                      {
                          case 0:
                              HandleLogin(message);
                              break;
                          case 5:
                              if (!loggedIn)
                                  break;
                              HandleBlockchange(message);
                              break;
                          case 8:
                              if (!loggedIn)
                                  break;
                              HandleInput(message);
                              break;
                          case 13:
                              if (!loggedIn)
                                  break;
                              HandleChat(message);
                              break;
                      }
                      //thread.Start((object)message);
                      if (buffer.Length > 0)
                          buffer = HandleMessage(buffer);
                      else
                          return new byte[0];
                  }
              }
              catch (Exception e)
              {
                  Server.ErrorLog(e);
              }
              return buffer;
          }
          void HandleLogin(byte[] message)
          {
              try
              {
                  //byte[] message = (byte[])m;
                  if (loggedIn)
                      return;
  
                  byte version = message[0];
                  name = enc.GetString(message, 1, 64).Trim();
                  string verify = enc.GetString(message, 65, 32).Trim();
                  byte type = message[129];
                  try
                  {
                      Server.TempBan tBan = Server.tempBans.Find(tB => tB.name.ToLower() == name.ToLower());
                      if (tBan.allowedJoin < DateTime.Now)
                      {
                          Server.tempBans.Remove(tBan);
                      }
                      else
                      {
                          Kick("You're still banned (temporary ban)!");
                      }
                  }
                  catch { }
  
                  // Whitelist check.
                  if (Server.useWhitelist)
                  {
                      if (Server.verify)
                      {
                          if (Server.whiteList.Contains(name))
                          {
                              onWhitelist = true;
                          }
                      }
                      else
                      {
                          // Verify Names is off.  Gotta check the hard way.
                          DataTable ipQuery = MySQL.fillData("SELECT Name FROM Players WHERE IP = '" + ip + "'");
  
                          if (ipQuery.Rows.Count > 0)
                          {
                              if (ipQuery.Rows.Contains(name) && Server.whiteList.Contains(name))
                              {
                                  onWhitelist = true;
                              }
                          }
                          ipQuery.Dispose();
                      }
                  }
  
                  if (File.Exists("ranks/ignore/" + this.name + ".txt"))
                  {
                      try
                      {
                          string[] checklines = File.ReadAllLines("ranks/ignore/" + this.name + ".txt");
                          foreach (string checkline in checklines)
                          {
                              this.listignored.Add(checkline);
                          }
                          File.Delete("ranks/ignore/" + this.name + ".txt");
                      }
                      catch
                      {
                          Server.s.Log("Failed to load ignore list for: " + this.name);
                      }
                  }
  
                  if (File.Exists("ranks/ignore/GlobalIgnore.xml"))
                  {
                      try
                      {
                          string[] searchxmls = File.ReadAllLines("ranks/ignore/GlobalIgnore.xml");
                          foreach (string searchxml in searchxmls)
                          {
                              globalignores.Add(searchxml);
                          }
                          foreach (string ignorer in globalignores)
                          {
                              Player foundignore = Player.Find(ignorer);
                              foundignore.ignoreglobal = true;
                          }
                          File.Delete("ranks/ignore/GlobalIgnore.xml");
                      }
                      catch
                      {
                          Server.s.Log("Failed to load global ignore list!");
                      }
                  }
                  totalplayers.Add(this);
  
  
  
                  if (Server.bannedIP.Contains(ip))
                  {
                      if (Server.useWhitelist)
                      {
                          if (!onWhitelist)
                          {
                              Kick(Server.customBanMessage);
                              return;
                          }
                      }
                      else
                      {
                          Kick(Server.customBanMessage);
                          return;
                      }
                  }
                  //if (connections.Count >= 5) { Kick("Too many connections!"); return; }
  
                  if (Group.findPlayerGroup(name) == Group.findPerm(LevelPermission.Banned))
                  {
                      if (Server.useWhitelist)
                      {
                          if (!onWhitelist)
                          {
                              Kick(Server.customBanMessage);
                              return;
                          }
                      }
                      else
                      {
                          Kick(Server.customBanMessage);
                          return;
                      }
                  }
                  if (Player.players.Count >= Server.players && !IPInPrivateRange(ip)) { Kick("Server full!"); return; }
                  // Code for limiting no. of guests
                  if (Group.findPlayerGroup(name) == Group.findPerm(LevelPermission.Guest))
                  {
                      // Check to see how many guests we have
                      int currentNumOfGuests = Player.players.Count(pl => pl.group.Permission == LevelPermission.Guest);
                      if (currentNumOfGuests >= Server.maxGuests)
                      {
                          GlobalMessageOps("Guest " + this.name + " couldn't log in - too many guests.");
                          Server.s.Log("Guest " + this.name + " couldn't log in - too many guests.");
                          Kick("Server has reached max number of guests");
                          return;
                      }
                  }
                  if (version != Server.version) { Kick("Wrong version!"); return; }
                  if (name.Length > 16 || !ValidName(name)) { Kick("Illegal name!"); return; }
  
                  if (Server.verify)
                  {
                      if (verify == "--" || verify !=
                          BitConverter.ToString(md5.ComputeHash(enc.GetBytes(Server.salt + name)))
                          .Replace("-", "").ToLower().TrimStart('0'))
                      {
                          if (!IPInPrivateRange(ip))
                          {
                              Kick("Login failed! Try again."); return;
                          }
                      }
                  }
  
                  foreach (Player p in players)
                  {
                      if (p.name == name)
                      {
                          if (Server.verify)
                          {
                              p.Kick("Someone logged in as you!"); break;
                          }
                          else { Kick("Already logged in!"); return; }
                      }
                  }
  
                  try { left.Remove(name.ToLower()); }
                  catch { }
  
                  group = Group.findPlayerGroup(name);
  
                  SendMotd();
                  SendMap();
                  Loading = true;
  
                  if (disconnected) return;
  
                  loggedIn = true;
                  id = FreeId();
  
                  players.Add(this);
                  connections.Remove(this);
  
                  Server.s.PlayerListUpdate();
  
                  //Test code to show when people come back with different accounts on the same IP
                  string temp = "Lately known as:";
                  bool found = false;
                  if (ip != "127.0.0.1")
                  {
                      foreach (KeyValuePair<string, string> prev in left)
                      {
                          if (prev.Value == ip)
                          {
                              found = true;
                              temp += " " + prev.Key;
                          }
                      }
                      if (found)
                      {
                          if (this.group.Permission < Server.adminchatperm || Server.adminsjoinsilent == false)
                          {
                              GlobalMessageOps(temp);
                              //IRCBot.Say(temp, true);       //Tells people in op channel on IRC
                          }
  
                          Server.s.Log(temp);
                      }
                  }
              }
              catch (Exception e)
              {
                  Server.ErrorLog(e);
                  Player.GlobalMessage("An error occurred: " + e.Message);
              }
  
              DataTable playerDb = MySQL.fillData("SELECT * FROM Players WHERE Name='" + name + "'");
  
              if (playerDb.Rows.Count == 0)
              {
                  this.prefix = "";
                  this.time = "0 0 0 1";
                  this.titlecolor = "";
                  this.color = group.color;
                  this.money = 0;
                  this.firstLogin = DateTime.Now;
                  this.totalLogins = 1;
                  this.totalKicked = 0;
                  this.overallDeath = 0;
                  this.overallBlocks = 0;
  
                  this.timeLogged = DateTime.Now;
                  SendMessage("Welcome " + name + "! This is your first visit.");
  
                  MySQL.executeQuery("INSERT INTO Players (Name, IP, FirstLogin, LastLogin, totalLogin, Title, totalDeaths, Money, totalBlocks, totalKicked, TimeSpent)" +
                      "VALUES ('" + name + "', '" + ip + "', '" + firstLogin.ToString("yyyy-MM-dd HH:mm:ss") + "', '" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "', " + totalLogins +
                      ", '" + prefix + "', " + overallDeath + ", " + money + ", " + loginBlocks + ", " + totalKicked + ", '" + time + "')");
  
              }
              else
              {
                  totalLogins = int.Parse(playerDb.Rows[0]["totalLogin"].ToString()) + 1;
                  time = playerDb.Rows[0]["TimeSpent"].ToString();
                  userID = int.Parse(playerDb.Rows[0]["ID"].ToString());
                  firstLogin = DateTime.Parse(playerDb.Rows[0]["firstLogin"].ToString());
                  timeLogged = DateTime.Now;
                  if (playerDb.Rows[0]["Title"].ToString().Trim() != "")
                  {
                      string parse = playerDb.Rows[0]["Title"].ToString().Trim().Replace("[", "");
                      title = parse.Replace("]", "");
                  }
                  if (playerDb.Rows[0]["title_color"].ToString().Trim() != "")
                  {
                      titlecolor = c.Parse(playerDb.Rows[0]["title_color"].ToString().Trim());
                  }
                  else
                  {
                      titlecolor = "";
                  }
                  if (playerDb.Rows[0]["color"].ToString().Trim() != "")
                  {
                      color = c.Parse(playerDb.Rows[0]["color"].ToString().Trim());
                  }
                  else
                  {
                      color = group.color;
                  }
                  SetPrefix();
                  overallDeath = int.Parse(playerDb.Rows[0]["TotalDeaths"].ToString());
                  overallBlocks = long.Parse(playerDb.Rows[0]["totalBlocks"].ToString().Trim());
                  money = int.Parse(playerDb.Rows[0]["Money"].ToString());
                  totalKicked = int.Parse(playerDb.Rows[0]["totalKicked"].ToString());
                  SendMessage("Welcome back " + color + prefix + name + Server.DefaultColor + "! You've been here " + totalLogins + " times!");
                  if (Server.muted.Contains(name))
                  {
                      muted = true;
                      GlobalMessage(name + " is still muted from the last time they went offline.");
                  }
              }
              playerDb.Dispose();
              if (PlayerConnect != null)
                  PlayerConnect(this);
              if (Server.devs.Contains(this.name.ToLower()))
              {
                  if (color == Group.standard.color)
                  {
                      color = "&9";
                  }
                  if (prefix == "")
                  {
                      title = "Dev";
                  }
                  SetPrefix();
              }
              if (Server.server_owner != "" && Server.server_owner.ToLower().Contains(this.name.ToLower()))
              {
                  if (color == Group.standard.color)
                  {
                      color = "&c";
                  }
                  if (prefix == "")
                  {
                      title = "Owner";
                  }
                  SetPrefix();
              }
  
              try
              {
                  ushort x = (ushort)((0.5 + level.spawnx) * 32);
                  ushort y = (ushort)((1 + level.spawny) * 32);
                  ushort z = (ushort)((0.5 + level.spawnz) * 32);
                  pos = new ushort[3] { x, y, z }; rot = new byte[2] { level.rotx, level.roty };
  
                  GlobalSpawn(this, x, y, z, rot[0], rot[1], true);
                  foreach (Player p in players)
                  {
                      if (p.level == level && p != this && !p.hidden)
                      {
                          if (Server.ZombieModeOn && !this.aka)
                          {
                              if (Server.infection)
                              {
                                  p.hidden = false;
                                  p.color = c.red;
                                  SendSpawn(p.id, c.red + "Undeaad", p.pos[0], p.pos[1], p.pos[2], p.rot[0], p.rot[1]);
                              }
                              else if (p.referee)
                              {
                                  p.hidden = true;
                              }
                              else
                              {
                                  p.hidden = false;
                                  p.color = p.group.color;
                                  SendSpawn(p.id, p.color + p.name, p.pos[0], p.pos[1], p.pos[2], p.rot[0], p.rot[1]);
                              }
                          }
                          else
                          {
                              p.hidden = false;
                              p.color = p.group.color;
                              SendSpawn(p.id, p.color + p.name, p.pos[0], p.pos[1], p.pos[2], p.rot[0], p.rot[1]);
                          }
                          //SendSpawn(p.id, p.color + p.name, p.pos[0], p.pos[1], p.pos[2], p.rot[0], p.rot[1]);
                      }
                  }
                  foreach (PlayerBot pB in PlayerBot.playerbots)
                  {
                      if (pB.level == level)
                          SendSpawn(pB.id, pB.color + pB.name, pB.pos[0], pB.pos[1], pB.pos[2], pB.rot[0], pB.rot[1]);
                  }
              }
              catch (Exception e)
              {
                  Server.ErrorLog(e);
                  Server.s.Log("Error spawning player \"" + name + "\"");
              }
  
              Loading = false;
  
              string text = enc.GetString(message, 1, 64).Trim();
              text = text.Trim('\0');
              if (text.Truncate(6) == "/womid")
              {
                  HandleChat(message);
              }
  
              if (Server.verifyadmins == true)
              {
                  if (this.group.Permission >= Server.verifyadminsrank)
                  {
                      adminpen = true;
                  }
              }
              if (emoteList.Contains(name)) parseSmiley = false;
              if (!Directory.Exists("text/login"))
              {
                  Directory.CreateDirectory("text/login");
              }
              if (!Directory.Exists("text/infect"))
              {
                  Directory.CreateDirectory("text/infect");
              }
              if (!File.Exists("text/login/" + this.name + ".txt"))
              {
                  File.WriteAllText("text/login/" + this.name + ".txt", "joined the server.");
              }
              if (Server.agreetorulesonentry == true)
              {
                  if (!File.Exists("ranks/agreed.txt"))
                  {
                      File.WriteAllText("ranks/agreed.txt", "");
                  }
                  var agreed = File.ReadAllText("ranks/agreed.txt");
                  if (this.group.Permission == LevelPermission.Guest)
                  {
                      if (!agreed.Contains(this.name.ToLower()))
                      {
                          SendMessage("&9You must read the &c/rules&9 and &c/agree&9 to them before you can build and use commands!");
                          jailed = true;
                      }
                  }
              }
              if (this.group.Permission < Server.adminchatperm || Server.adminsjoinsilent == false)
              {
                  GlobalChat(this, "&a+ " + this.color + this.prefix + this.name + Server.DefaultColor + " " + File.ReadAllText("text/login/" + this.name + ".txt"), false);
                  //IRCBot.Say(this.name + " has joined the server.");
              }
              if (this.group.Permission >= Server.adminchatperm && Server.adminsjoinsilent == true)
              {
                  this.hidden = true;
                  this.adminchat = true;
              }
              if (Server.verifyadmins == true)
              {
                  if (this.group.Permission >= Server.verifyadminsrank)
                  {
                      if (!Directory.Exists("extra/passwords") || !File.Exists("extra/passwords/" + this.name + ".xml"))
                      {
                          this.SendMessage("&cPlease set your admin verification password with &a/setpass [Password]!");
                      }
                      else
                      {
                          this.SendMessage("&cPlease complete admin verification with &a/pass [Password]!");
                      }
                  }
              }
              Server.s.Log(name + " [" + ip + "] has joined the server.");
              if (Server.notifyOnJoinLeave)
              {
                  Server.PopupNotify(name + " [" + ip + "] has joined the server.");
              }
              this.Original = this.name;
              this.NoClipcount = 0;
              if (Server.infection == true)
              {
                  CmdZombieGame.infect.Add(this);
                  CmdZombieGame.players.Remove(this);
                  this.infected = true;
                  this.color = c.red;
                  Player.GlobalDie(this, false);
                  Player.GlobalSpawn(this, this.pos[0], this.pos[1], this.pos[2], this.rot[0], this.rot[1], false);
              }
          }
  
          public void SetPrefix()
          {
              prefix = (title == "") ? "" : (titlecolor == "") ? "[" + title + "] " : "[" + titlecolor + title + color + "] ";
          }
  
          void HandleBlockchange(byte[] message)
          {
              int section = 0;
              try
              {
                  //byte[] message = (byte[])m;
                  if (!loggedIn)
                      return;
                  if (CheckBlockSpam())
                      return;
  
                  section++;
                  ushort x = NTHO(message, 0);
                  ushort y = NTHO(message, 2);
                  ushort z = NTHO(message, 4);
                  byte action = message[6];
                  byte type = message[7];
  
                  if (action == 1 && Server.ZombieModeOn && Server.noPillaring)
                  {
                      if (!referee)
                      {
                          if (lastYblock == y - 1 && lastXblock == x && lastZblock == z)
                          {
                              blocksStacked++;
                          }
                          else
                          {
                              blocksStacked = 0;
                          }
                          if (blocksStacked == 2)
                          {
                              SendMessage("You are pillaring! Stop before you get kicked!");
                          }
                          if (blocksStacked == 4)
                          {
                              Command.all.Find("kick").Use(null, Original + " No pillaring allowed!");
                          }
                      }
                  }
  
                  lastYblock = y;
                  lastXblock = x;
                  lastZblock = z;
  
                  manualChange(x, y, z, action, type);
              }
              catch (Exception e)
              {
                  // Don't ya just love it when the server tattles?
                  GlobalMessageOps(name + " has triggered a block change error");
                  Server.ErrorLog(e);
              }
          }
          public void manualChange(ushort x, ushort y, ushort z, byte action, byte type)
          {
              if (type > 49)
              {
                  Kick("Unknown block type!");
                  return;
              }
  
              byte b = level.GetTile(x, y, z);
              if (b == Block.Zero) { return; }
              if (jailed) { SendBlockchange(x, y, z, b); return; }
              if (level.name.Contains("Museum " + Server.DefaultColor) && Blockchange == null)
              {
                  return;
              }
  
              if (!deleteMode)
              {
                  string info = level.foundInfo(x, y, z);
                  if (info.Contains("wait")) { return; }
              }
  
              if (!canBuild)
              {
                  SendBlockchange(x, y, z, b);
                  return;
              }
  
              if (Server.verifyadmins == true)
              {
                  if (this.adminpen == true)
                  {
                      SendBlockchange(x, y, z, b);
                      this.SendMessage("&cYou must use &a/pass [Password]&c to verify!");
                      return;
                  }
              }
  
              Player p2 = Player.Find(name);
              bool shouldIStop = false;
              players.ForEach(delegate(Player p)
              {
                  if (p.level == level)
                  {
                      if ((p.pos[0] / 32) == x && (p.pos[1] / 32) == (y + 2) && (p.pos[2] / 32) == z && p.name != name && (action == 0 && !this.painting))
                      {
                          if ((p2.infected && !p.infected) || (!p2.infected && p.infected))
                          {
                              SendBlockchange(x, y, z, b);
                              GlobalMessageOps(c.lime + name + " just spleefed " + p.name + "!");
                              Player.SendMessage(p2, c.lime + "You are " + c.red + "NOT " + c.lime + "allowed to spleef someone on the other team!");
                              shouldIStop = true;
                              return;
                          }
                      }
                  }
              });
              if (shouldIStop)
                  return;
  
              if (Server.ZombieModeOn && (action == 1 || (action == 0 && this.painting)))
              {
                  if (blockCount == 0)
                  {
                      if (!referee)
                      {
                          SendMessage("You have no blocks left.");
                          SendBlockchange(x, y, z, b); return;
                      }
                  }
  
                  if (!referee)
                  {
                      blockCount--;
                      if (blockCount == 40 || blockCount == 30 || blockCount == 20 || blockCount <= 10 && blockCount >= 0)
                      {
                          SendMessage("Blocks Left: " + c.maroon + blockCount + Server.DefaultColor);
                      }
                  }
              }
  
              if (this.level.name.ToLower() == "race" && this.level.name.ToLower() == "inferno_con_el_diablo")
              {
                  SendMessage("You cannot build on this map!");
                  SendBlockchange(x, y, z, b); return;
              }
  
              Level.BlockPos bP;
              bP.name = name;
              bP.TimePerformed = DateTime.Now;
              bP.x = x; bP.y = y; bP.z = z;
              bP.type = type;
  
              lastClick[0] = x;
              lastClick[1] = y;
              lastClick[2] = z;
              //bool test2 = false;
              if (Blockchange != null)
              {
                  if (Blockchange.Method.ToString().IndexOf("AboutBlockchange") == -1 && !level.name.Contains("Museum " + Server.DefaultColor))
                  {
                      bP.deleted = true;
                      level.blockCache.Add(bP);
                  }
  
                  Blockchange(this, x, y, z, type);
                  return;
              }
              if (PlayerBlockChange != null)
              {
                  PlayerBlockChange(this, x, y, z, type);
                  if (cancelBlock)
                  {
                      cancelBlock = false;
                      return;
                  }
              }
  
              if (group.Permission == LevelPermission.Banned) return;
              if (group.Permission == LevelPermission.Guest)
              {
                  int Diff = 0;
  
                  Diff = Math.Abs((int)(pos[0] / 32) - x);
  
gt:                 Diff += Math.Abs((int)(pos[1] / 32) - y);