void OnGetData(GetDataEventArgs e) { if (!e.Handled) { using (var reader = new BinaryReader(new MemoryStream(e.Msg.readBuffer, e.Index, e.Length))) { switch (e.MsgID) { case PacketTypes.SignNew: { reader.ReadInt16(); int x = reader.ReadInt16(); int y = reader.ReadInt16(); string text = reader.ReadString(); Task.Factory.StartNew(() => ModSign(x, y, e.Msg.whoAmI, text)); e.Handled = true; } break; case PacketTypes.SignRead: { int x = reader.ReadInt16(); int y = reader.ReadInt16(); Task.Factory.StartNew(() => GetSign(x, y, e.Msg.whoAmI)); e.Handled = true; } break; case PacketTypes.Tile: { byte action = reader.ReadByte(); int x = reader.ReadInt16(); int y = reader.ReadInt16(); ushort type = reader.ReadUInt16(); if (x < 0 || y < 0 || x >= Main.maxTilesX || y >= Main.maxTilesY) { return; } if (action == 0 && type == 0) { if (Sign.Nearby(x, y)) { Task.Factory.StartNew(() => KillSign(x, y, e.Msg.whoAmI)); e.Handled = true; } } else if (action == 1 && (type == 55 || type == 85)) { if (TShock.Regions.CanBuild(x, y, TShock.Players[e.Msg.whoAmI])) { WorldGen.PlaceSign(x, y, type); NetMessage.SendData(17, -1, e.Msg.whoAmI, "", 1, x, y, type); if (Main.tile[x, y].frameY != 0) { y--; } if (Main.tile[x, y].frameX % 36 != 0) { x--; } Task.Factory.StartNew(() => PlaceSign(x, y, e.Msg.whoAmI)); e.Handled = true; } } } break; } } } }
void ModSign(int x, int y, int plr, string text) { Sign sign = null; using (QueryResult reader = Database.QueryReader("SELECT Account, Flags, ID, Password FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", x, y, Main.worldID)) { if (reader.Read()) { sign = new Sign { Account = reader.Get <string>("Account"), Flags = (SignFlags)reader.Get <int>("Flags"), HashedPassword = reader.Get <string>("Password"), ID = reader.Get <int>("ID") }; } } var info = Infos[plr]; var player = TShock.Players[plr]; if (sign != null) { Console.WriteLine("IsRegion: {0}", sign.IsRegion); bool isFree = String.IsNullOrEmpty(sign.Account); bool isOwner = sign.Account == player.UserAccountName || player.Group.HasPermission("infsigns.admin.editall"); bool isRegion = sign.IsRegion && TShock.Regions.CanBuild(x, y, player); if (!isFree && !isOwner && !isRegion) { if (String.IsNullOrEmpty(sign.HashedPassword)) { player.SendErrorMessage("This sign is protected."); return; } else if (TShock.Utils.HashPassword(info.Password) != sign.HashedPassword) { player.SendErrorMessage("This sign is password protected."); return; } else { player.SendSuccessMessage("Sign unlocked."); info.Password = ""; } } Database.Query("UPDATE Signs SET Text = @0 WHERE ID = @1", text, sign.ID); byte[] raw = null; using (var writer = new BinaryWriter(new MemoryStream())) { writer.Write((short)0); writer.Write((byte)47); writer.Write((short)(info.SignIndex ? 1 : 0)); writer.Write((short)x); writer.Write((short)y); writer.Write(sign.Text); short length = (short)writer.BaseStream.Position; writer.BaseStream.Position = 0; writer.Write(length); raw = ((MemoryStream)writer.BaseStream).ToArray(); } foreach (var info2 in Infos.Where(i => i.X == info.X && i.Y == info.Y && i != info)) { raw[2] = (byte)(info2.SignIndex ? 1 : 0); TShock.Players[info2.Index].SendRawData(raw); } } }
void GetSign(int x, int y, int plr) { Sign sign = null; using (QueryResult reader = Database.QueryReader("SELECT Account, Flags, ID, Text FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", x, y, Main.worldID)) { if (reader.Read()) { sign = new Sign { Account = reader.Get <string>("Account"), Flags = (SignFlags)reader.Get <int>("Flags"), ID = reader.Get <int>("ID"), Text = reader.Get <string>("Text") }; } } var info = Infos[plr]; var player = TShock.Players[plr]; if (sign != null) { switch (info.Action) { case SignAction.Info: player.SendInfoMessage("X: {0} Y: {1} Account: {2} Region: {3}", x, y, sign.Account ?? "N/A", sign.IsRegion); break; case SignAction.Protect: if (!String.IsNullOrEmpty(sign.Account)) { player.SendErrorMessage("This sign is protected."); break; } Database.Query("UPDATE Signs SET Account = @0 WHERE ID = @1", player.UserAccountName, sign.ID); player.SendInfoMessage("This sign is now protected."); break; case SignAction.SetPassword: if (String.IsNullOrEmpty(sign.Account)) { player.SendErrorMessage("This sign is not protected."); break; } if (sign.Account != player.UserAccountName && !player.Group.HasPermission("infsigns.admin.editall")) { player.SendErrorMessage("This sign is not yours."); break; } if (String.Equals(info.Password, "remove", StringComparison.CurrentCultureIgnoreCase)) { Database.Query("UPDATE Signs SET Password = NULL WHERE ID = @0", sign.ID); player.SendSuccessMessage("This sign is no longer password protected."); } else { Database.Query("UPDATE Signs SET Password = @0 WHERE ID = @1", TShock.Utils.HashPassword(info.Password), sign.ID); player.SendSuccessMessage("This sign is now password protected with password '{0}'.", info.Password); } break; case SignAction.TogglePublic: if (String.IsNullOrEmpty(sign.Account)) { player.SendErrorMessage("This sign is not protected."); break; } if (sign.Account != player.UserAccountName && !player.Group.HasPermission("infsigns.admin.editall")) { player.SendErrorMessage("This sign is not yours."); break; } Database.Query("UPDATE Signs SET Flags = (~(Flags & 1)) & (Flags | 1) WHERE ID = @0", sign.ID); player.SendInfoMessage("This sign is no{0} public.", sign.IsRegion ? " longer" : "w"); break; case SignAction.ToggleRegion: if (String.IsNullOrEmpty(sign.Account)) { player.SendErrorMessage("This sign is not protected."); break; } if (sign.Account != player.UserAccountName && !player.Group.HasPermission("infsigns.admin.editall")) { player.SendErrorMessage("This sign is not yours."); break; } Database.Query("UPDATE Signs SET Flags = (~(Flags & 2)) & (Flags | 2) WHERE ID = @0", sign.ID); player.SendInfoMessage("This sign is no{0} region shared.", sign.IsRegion ? " longer" : "w"); break; case SignAction.Unprotect: if (String.IsNullOrEmpty(sign.Account)) { player.SendErrorMessage("This sign is not protected."); break; } if (sign.Account != player.UserAccountName && !player.Group.HasPermission("infsigns.admin.editall")) { player.SendErrorMessage("This sign is not yours."); break; } Database.Query("UPDATE Signs SET Account = NULL, Flags = 0, Password = NULL WHERE ID = @0", sign.ID); player.SendInfoMessage("This sign is now unprotected."); break; default: sign.Text = sign.Text.Replace("\0", ""); using (var writer = new BinaryWriter(new MemoryStream())) { writer.Write((short)0); writer.Write((byte)47); writer.Write((short)(info.SignIndex ? 1 : 0)); writer.Write((short)x); writer.Write((short)y); writer.Write(sign.Text); short length = (short)writer.BaseStream.Position; writer.BaseStream.Position = 0; writer.Write(length); player.SendRawData(((MemoryStream)writer.BaseStream).ToArray()); } info.SignIndex = !info.SignIndex; info.X = x; info.Y = y; break; } info.Action = SignAction.None; } }
void KillSign(int x, int y, int plr) { TSPlayer player = TShock.Players[plr]; bool[] attached = new bool[4]; bool[] attachedNext = new bool[4]; var positions = new List <Point>(); if (Main.tile[x, y].IsSign()) { if (TryKillSign(Sign.GetSign(x, y).X, Sign.GetSign(x, y).Y, plr)) { WorldGen.KillTile(x, y); TSPlayer.All.SendTileSquare(x, y, 3); return; } else { player.SendErrorMessage("This sign is protected."); player.SendTileSquare(x, y, 5); return; } } else { if (TileValid(x - 1, y) && Main.tile[x - 1, y].IsSign()) { positions.Add(Sign.GetSign(x - 1, y)); } if (TileValid(x + 1, y) && Main.tile[x + 1, y].IsSign()) { positions.Add(Sign.GetSign(x + 1, y)); } if (TileValid(x, y - 1) && Main.tile[x, y - 1].IsSign()) { positions.Add(Sign.GetSign(x, y - 1)); } if (TileValid(x, y + 1) && Main.tile[x, y + 1].IsSign()) { positions.Add(Sign.GetSign(x, y + 1)); } foreach (Point p in positions) { attached[0] = TileValid(p.X, p.Y + 2) && Main.tile[p.X, p.Y + 2].IsSolid() && TileValid(p.X + 1, p.Y + 2) && Main.tile[p.X + 1, p.Y + 2].IsSolid(); attached[1] = TileValid(p.X, p.Y - 1) && Main.tile[p.X, p.Y - 1].IsSolid() && TileValid(p.X + 1, p.Y - 1) && Main.tile[p.X + 1, p.Y - 1].IsSolid(); attached[2] = TileValid(p.X - 1, p.Y) && Main.tile[p.X - 1, p.Y].IsSolid() && TileValid(p.X - 1, p.Y + 1) && Main.tile[p.X - 1, p.Y + 1].IsSolid(); attached[3] = TileValid(p.X + 2, p.Y) && Main.tile[p.X + 2, p.Y].IsSolid() && TileValid(p.X + 2, p.Y + 1) && Main.tile[p.X + 2, p.Y + 1].IsSolid(); bool prev = Main.tile[x, y].active(); Main.tile[x, y].active(false); attachedNext[0] = TileValid(p.X, p.Y + 2) && Main.tile[p.X, p.Y + 2].IsSolid() && TileValid(p.X + 1, p.Y + 2) && Main.tile[p.X + 1, p.Y + 2].IsSolid(); attachedNext[1] = TileValid(p.X, p.Y - 1) && Main.tile[p.X, p.Y - 1].IsSolid() && TileValid(p.X + 1, p.Y - 1) && Main.tile[p.X + 1, p.Y - 1].IsSolid(); attachedNext[2] = TileValid(p.X - 1, p.Y) && Main.tile[p.X - 1, p.Y].IsSolid() && TileValid(p.X - 1, p.Y + 1) && Main.tile[p.X - 1, p.Y + 1].IsSolid(); attachedNext[3] = TileValid(p.X + 2, p.Y) && Main.tile[p.X + 2, p.Y].IsSolid() && TileValid(p.X + 2, p.Y + 1) && Main.tile[p.X + 2, p.Y + 1].IsSolid(); Main.tile[x, y].active(prev); if (attached.Count(b => b) > 1 || attached.Count(b => b) == attachedNext.Count(b => b)) { continue; } if (TryKillSign(p.X, p.Y, plr)) { WorldGen.KillTile(p.X, p.Y); TSPlayer.All.SendTileSquare(p.X, p.Y, 3); } else { player.SendErrorMessage("This sign is protected."); player.SendTileSquare(x, y, 5); } } } }
void OnGetData(GetDataEventArgs e) { if (!e.Handled) { switch (e.MsgID) { case PacketTypes.SignNew: { int X = BitConverter.ToInt32(e.Msg.readBuffer, e.Index + 2); int Y = BitConverter.ToInt32(e.Msg.readBuffer, e.Index + 6); string text = Encoding.UTF8.GetString(e.Msg.readBuffer, e.Index + 10, e.Length - 11); ModSign(X, Y, e.Msg.whoAmI, text); e.Handled = true; } break; case PacketTypes.SignRead: { int X = BitConverter.ToInt32(e.Msg.readBuffer, e.Index); int Y = BitConverter.ToInt32(e.Msg.readBuffer, e.Index + 4); GetSign(X, Y, e.Msg.whoAmI); e.Handled = true; } break; case PacketTypes.Tile: { int X = BitConverter.ToInt32(e.Msg.readBuffer, e.Index + 1); int Y = BitConverter.ToInt32(e.Msg.readBuffer, e.Index + 5); if (X < 0 || Y < 0 || X >= Main.maxTilesX || Y >= Main.maxTilesY) { return; } if (e.Msg.readBuffer[e.Index] == 0 && Main.tile[X, Y].IsSign()) { if (SignHit != null) { Sign sign = null; var signPos = Sign.GetSign(X, Y); using (QueryResult reader = Database.QueryReader("SELECT Account, Text FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", signPos.X, signPos.Y, Main.worldID)) { if (reader.Read()) { sign = new Sign { account = reader.Get <string>("Account"), text = reader.Get <string>("Text") } } ; } if (sign != null) { SignEventArgs signargs = new SignEventArgs(X, Y, sign.text, sign.account); SignHit(signargs); } } } if (e.Msg.readBuffer[e.Index] == 0 && e.Msg.readBuffer[e.Index + 9] == 0) { if (Sign.Nearby(X, Y)) { KillSign(X, Y, e.Msg.whoAmI); e.Handled = true; } } else if (e.Msg.readBuffer[e.Index] == 1 && (e.Msg.readBuffer[e.Index + 9] == 55 || e.Msg.readBuffer[e.Index + 9] == 85)) { if (TShock.Regions.CanBuild(X, Y, TShock.Players[e.Msg.whoAmI])) { WorldGen.PlaceSign(X, Y, e.Msg.readBuffer[e.Index + 9]); if (Main.tile[X, Y].frameY != 0) { Y--; } if (Main.tile[X, Y].frameX % 36 != 0) { X--; } PlaceSign(X, Y, e.Msg.whoAmI); e.Handled = true; } } } break; } } } void OnInitialize() { Commands.ChatCommands.Add(new Command("maintenance", ConvertSigns, "convsigns")); Commands.ChatCommands.Add(new Command("protectsign", Deselect, "scset")); Commands.ChatCommands.Add(new Command("showsigninfo", Info, "sinfo")); Commands.ChatCommands.Add(new Command("protectsign", Protect, "sset")); Commands.ChatCommands.Add(new Command("protectsign", Unprotect, "sunset")); switch (TShock.Config.StorageType.ToLower()) { case "mysql": string[] host = TShock.Config.MySqlHost.Split(':'); Database = new MySqlConnection() { ConnectionString = string.Format("Server={0}; Port={1}; Database={2}; Uid={3}; Pwd={4};", host[0], host.Length == 1 ? "3306" : host[1], TShock.Config.MySqlDbName, TShock.Config.MySqlUsername, TShock.Config.MySqlPassword) }; break; case "sqlite": string sql = Path.Combine(TShock.SavePath, "signs.sqlite"); Database = new SqliteConnection(string.Format("uri=file://{0},Version=3", sql)); break; } SqlTableCreator sqlcreator = new SqlTableCreator(Database, Database.GetSqlType() == SqlType.Sqlite ? (IQueryBuilder) new SqliteQueryCreator() : new MysqlQueryCreator()); sqlcreator.EnsureExists(new SqlTable("Signs", new SqlColumn("X", MySqlDbType.Int32), new SqlColumn("Y", MySqlDbType.Int32), new SqlColumn("Account", MySqlDbType.Text), new SqlColumn("Text", MySqlDbType.Text), new SqlColumn("WorldID", MySqlDbType.Int32))); } void OnLeave(int index) { Action[index] = SignAction.NONE; SignNum[index] = false; } void GetSign(int X, int Y, int plr) { Sign sign = null; using (QueryResult reader = Database.QueryReader("SELECT Account, Text FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", X, Y, Main.worldID)) { if (reader.Read()) { sign = new Sign { account = reader.Get <string>("Account"), text = reader.Get <string>("Text") }; } } TSPlayer player = TShock.Players[plr]; if (sign != null) { switch (Action[plr]) { case SignAction.INFO: player.SendMessage(string.Format("X: {0} Y: {1} Account: {2}", X, Y, sign.account == "" ? "N/A" : sign.account), Color.Yellow); break; case SignAction.PROTECT: if (sign.account != "") { player.SendMessage("This sign is protected.", Color.Red); break; } Database.Query("UPDATE Signs SET Account = @0 WHERE X = @1 AND Y = @2 AND WorldID = @3", player.UserAccountName, X, Y, Main.worldID); player.SendMessage("This sign is now protected."); break; case SignAction.UNPROTECT: if (sign.account == "") { player.SendMessage("This sign is not protected.", Color.Red); break; } if (sign.account != player.UserAccountName && !player.Group.HasPermission("removesignprotection")) { player.SendMessage("This sign is not yours.", Color.Red); break; } Database.Query("UPDATE Signs SET Account = '' WHERE X = @0 AND Y = @1 AND WorldID = @2", X, Y, Main.worldID); player.SendMessage("This sign is now unprotected."); break; default: if (sign.text.Length > 0 && sign.text[sign.text.Length - 1] == '\0') { sign.text = sign.text.Substring(0, sign.text.Length - 1); } byte[] utf8 = Encoding.UTF8.GetBytes(sign.text); byte[] raw = new byte[15 + utf8.Length]; Buffer.BlockCopy(BitConverter.GetBytes(utf8.Length + 11), 0, raw, 0, 4); if (SignNum[plr]) { raw[5] = 1; } raw[4] = 47; Buffer.BlockCopy(BitConverter.GetBytes(X), 0, raw, 7, 4); Buffer.BlockCopy(BitConverter.GetBytes(Y), 0, raw, 11, 4); Buffer.BlockCopy(utf8, 0, raw, 15, utf8.Length); SignNum[plr] = !SignNum[plr]; SignEventArgs signargs = new SignEventArgs(X, Y, sign.text, sign.account); if (SignRead != null) { SignRead(signargs); } if (!signargs.Handled) { player.SendRawData(raw); } break; } Action[plr] = SignAction.NONE; } } void KillSign(int X, int Y, int plr) { TSPlayer player = TShock.Players[plr]; bool[] attached = new bool[4]; bool[] attachedNext = new bool[4]; List <Point> positions = new List <Point>(); if (Main.tile[X, Y].IsSign()) { positions.Add(Sign.GetSign(X, Y)); if (TryKillSign(positions[0].X, positions[0].Y, plr)) { WorldGen.KillTile(X, Y); TSPlayer.All.SendTileSquare(X, Y, 3); } else { player.SendMessage("This sign is protected.", Color.Red); player.SendTileSquare(X, Y, 5); } } else { if (Main.tile.Valid(X - 1, Y) && Main.tile[X - 1, Y].IsSign()) { positions.Add(Sign.GetSign(X - 1, Y)); } if (Main.tile.Valid(X + 1, Y) && Main.tile[X + 1, Y].IsSign()) { positions.Add(Sign.GetSign(X + 1, Y)); } if (Main.tile.Valid(X, Y - 1) && Main.tile[X, Y - 1].IsSign()) { positions.Add(Sign.GetSign(X, Y - 1)); } if (Main.tile.Valid(X, Y + 1) && Main.tile[X, Y + 1].IsSign()) { positions.Add(Sign.GetSign(X, Y + 1)); } bool killTile = true; foreach (Point p in positions) { attached[0] = Main.tile.Valid(p.X, p.Y + 2) && Main.tile[p.X, p.Y + 2].IsSolid() && Main.tile.Valid(p.X + 1, p.Y + 2) && Main.tile[p.X + 1, p.Y + 2].IsSolid(); attached[1] = Main.tile.Valid(p.X, p.Y - 1) && Main.tile[p.X, p.Y - 1].IsSolid() && Main.tile.Valid(p.X + 1, p.Y - 1) && Main.tile[p.X + 1, p.Y - 1].IsSolid(); attached[2] = Main.tile.Valid(p.X - 1, p.Y) && Main.tile[p.X - 1, p.Y].IsSolid() && Main.tile.Valid(p.X - 1, p.Y + 1) && Main.tile[p.X - 1, p.Y + 1].IsSolid(); attached[3] = Main.tile.Valid(p.X + 2, p.Y) && Main.tile[p.X + 2, p.Y].IsSolid() && Main.tile.Valid(p.X + 2, p.Y + 1) && Main.tile[p.X + 2, p.Y + 1].IsSolid(); bool prev = Main.tile[X, Y].active; Main.tile[X, Y].active = false; attachedNext[0] = Main.tile.Valid(p.X, p.Y + 2) && Main.tile[p.X, p.Y + 2].IsSolid() && Main.tile.Valid(p.X + 1, p.Y + 2) && Main.tile[p.X + 1, p.Y + 2].IsSolid(); attachedNext[1] = Main.tile.Valid(p.X, p.Y - 1) && Main.tile[p.X, p.Y - 1].IsSolid() && Main.tile.Valid(p.X + 1, p.Y - 1) && Main.tile[p.X + 1, p.Y - 1].IsSolid(); attachedNext[2] = Main.tile.Valid(p.X - 1, p.Y) && Main.tile[p.X - 1, p.Y].IsSolid() && Main.tile.Valid(p.X - 1, p.Y + 1) && Main.tile[p.X - 1, p.Y + 1].IsSolid(); attachedNext[3] = Main.tile.Valid(p.X + 2, p.Y) && Main.tile[p.X + 2, p.Y].IsSolid() && Main.tile.Valid(p.X + 2, p.Y + 1) && Main.tile[p.X + 2, p.Y + 1].IsSolid(); Main.tile[X, Y].active = prev; if (attached.Count(b => b) > 1 || attached.Count(b => b) == attachedNext.Count(b => b)) { continue; } if (TryKillSign(p.X, p.Y, plr)) { WorldGen.KillTile(p.X, p.Y); TSPlayer.All.SendTileSquare(p.X, p.Y, 3); } else { player.SendMessage("This sign is protected.", Color.Red); player.SendTileSquare(X, Y, 5); killTile = false; } } if (killTile) { WorldGen.KillTile(X, Y); TSPlayer.All.SendTileSquare(X, Y, 1); } } } void ModSign(int X, int Y, int plr, string text) { Sign sign = null; using (QueryResult reader = Database.QueryReader("SELECT Account FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", X, Y, Main.worldID)) { if (reader.Read()) { sign = new Sign { account = reader.Get <string>("Account") }; } } TSPlayer player = TShock.Players[plr]; if (sign != null) { if (sign.account != player.UserAccountName && sign.account != "" && !player.Group.HasPermission("editallsigns")) { player.SendMessage("This sign is protected.", Color.Red); } else { SignEventArgs signargs = new SignEventArgs(X, Y, sign.text, sign.account); if (SignEdit != null) { SignEdit(signargs); } if (signargs.Handled) { player.SendMessage("Another plugin is preventing the sign to be edited.", Color.Red); } else { Database.Query("UPDATE Signs SET Text = @0 WHERE X = @1 AND Y = @2 AND WorldID = @3", text, X, Y, Main.worldID); } } } } void PlaceSign(int X, int Y, int plr) { TSPlayer player = TShock.Players[plr]; Database.Query("INSERT INTO Signs (X, Y, Account, Text, WorldID) VALUES (@0, @1, @2, '', @3)", X, Y, player.IsLoggedIn ? player.UserAccountName : "", Main.worldID); Main.sign[999] = null; } bool TryKillSign(int X, int Y, int plr) { Sign sign = null; using (QueryResult reader = Database.QueryReader("SELECT Account, Text FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", X, Y, Main.worldID)) { if (reader.Read()) { sign = new Sign { account = reader.Get <string>("Account"), text = reader.Get <string>("Text") }; } } if (sign != null) { if (sign.account != TShock.Players[plr].UserAccountName && sign.account != "") { return(false); } else { if (SignKill != null) { SignEventArgs signargs = new SignEventArgs(X, Y, sign.text, sign.account); SignKill(signargs); if (signargs.Handled) { return(false); } } } } Database.Query("DELETE FROM Signs WHERE X = @0 AND Y = @1 AND WorldID = @2", X, Y, Main.worldID); return(true); } void ConvertSigns(CommandArgs e) { Database.Query("DELETE FROM Signs WHERE WorldID = @0", Main.worldID); int converted = 0; foreach (Terraria.Sign s in Main.sign) { if (s != null) { Database.Query("INSERT INTO Signs (X, Y, Text, WorldID) VALUES (@0, @1, @2, @3)", s.x, s.y, s.text, Main.worldID); converted++; } } e.Player.SendMessage("Converted " + converted + " signs."); } void Deselect(CommandArgs e) { Action[e.Player.Index] = SignAction.NONE; e.Player.SendMessage("Stopped selecting a sign."); } void Info(CommandArgs e) { Action[e.Player.Index] = SignAction.INFO; e.Player.SendMessage("Read a sign to get its info."); } void Protect(CommandArgs e) { Action[e.Player.Index] = SignAction.PROTECT; e.Player.SendMessage("Read a sign to protect it."); } void Unprotect(CommandArgs e) { Action[e.Player.Index] = SignAction.UNPROTECT; e.Player.SendMessage("Read a sign to unprotect it."); } }