Merge pull request #545 from NyxStudios/1.2_terraria

Update to Terraria Protocol 1.2
This commit is contained in:
Lucas Nicodemus 2013-09-30 21:04:41 -07:00
commit 33e0627f9e
19 changed files with 994 additions and 674 deletions

View file

@ -24,7 +24,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using TShockAPI.PluginUpdater;
using Terraria; using Terraria;
using TShockAPI.DB; using TShockAPI.DB;
@ -186,7 +185,9 @@ namespace TShockAPI
add(Permissions.causeevents, Star, "star"); add(Permissions.causeevents, Star, "star");
add(Permissions.causeevents, Fullmoon, "fullmoon"); add(Permissions.causeevents, Fullmoon, "fullmoon");
add(Permissions.causeevents, Bloodmoon, "bloodmoon"); add(Permissions.causeevents, Bloodmoon, "bloodmoon");
add(Permissions.causeevents, Eclipse, "eclipse");
add(Permissions.causeevents, Invade, "invade"); add(Permissions.causeevents, Invade, "invade");
add(Permissions.causeevents, Rain, "rain");
add(Permissions.spawnboss, Eater, "eater"); add(Permissions.spawnboss, Eater, "eater");
add(Permissions.spawnboss, Eye, "eye"); add(Permissions.spawnboss, Eye, "eye");
add(Permissions.spawnboss, King, "king"); add(Permissions.spawnboss, King, "king");
@ -483,7 +484,7 @@ namespace TShockAPI
if (TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP) != Vector2.Zero) if (TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP) != Vector2.Zero)
{ {
Vector2 pos = TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP); Vector2 pos = TShock.RememberedPos.GetLeavePos(args.Player.Name, args.Player.IP);
args.Player.Teleport((int)pos.X, (int)pos.Y + 3); args.Player.Teleport((int)pos.X*16, (int)pos.Y *16 + 48);
} }
args.Player.LoginHarassed = false; args.Player.LoginHarassed = false;
@ -1259,7 +1260,6 @@ namespace TShockAPI
{ {
args.Player.SendInfoMessage("Starting plugin update process:"); args.Player.SendInfoMessage("Starting plugin update process:");
args.Player.SendInfoMessage("This may take a while, do not turn off the server!"); args.Player.SendInfoMessage("This may take a while, do not turn off the server!");
new PluginUpdaterThread(args.Player);
} }
private static void ManageRest(CommandArgs args) private static void ManageRest(CommandArgs args)
@ -1354,6 +1354,12 @@ namespace TShockAPI
TShock.Utils.Broadcast(string.Format("{0} turned on the blood moon.", args.Player.Name), Color.Green); TShock.Utils.Broadcast(string.Format("{0} turned on the blood moon.", args.Player.Name), Color.Green);
} }
private static void Eclipse(CommandArgs args)
{
TSPlayer.Server.SetEclipse(true);
TShock.Utils.Broadcast(string.Format("{0} has forced an Eclipse!", args.Player.Name), Color.Green);
}
private static void Invade(CommandArgs args) private static void Invade(CommandArgs args)
{ {
if (Main.invasionSize <= 0) if (Main.invasionSize <= 0)
@ -1635,7 +1641,7 @@ namespace TShockAPI
private static void Spawn(CommandArgs args) private static void Spawn(CommandArgs args)
{ {
if (args.Player.Teleport(Main.spawnTileX, Main.spawnTileY)) if (args.Player.Teleport(Main.spawnTileX*16, Main.spawnTileY*16))
args.Player.SendSuccessMessage("Teleported to the map's spawnpoint."); args.Player.SendSuccessMessage("Teleported to the map's spawnpoint.");
} }
@ -1643,14 +1649,31 @@ namespace TShockAPI
{ {
if (args.Parameters.Count < 1) if (args.Parameters.Count < 1)
{ {
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tp <player> "); args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /tp <player>");
args.Player.SendErrorMessage(" /tp <x> <y>");
return; return;
} }
if(args.Parameters.Count == 2)
{
float x, y;
if (float.TryParse(args.Parameters[0], out x) && float.TryParse(args.Parameters[1], out y))
{
args.Player.Teleport(x, y);
args.Player.SendSuccessMessage("Teleported!");
}
}
else
{
string plStr = String.Join(" ", args.Parameters); string plStr = String.Join(" ", args.Parameters);
var players = TShock.Utils.FindPlayer(plStr); var players = TShock.Utils.FindPlayer(plStr);
if (players.Count == 0) if (players.Count == 0)
args.Player.SendErrorMessage("Invalid player!"); {
args.Player.SendErrorMessage("Invalid user name.");
args.Player.SendErrorMessage("Proper syntax: /tp <player>");
args.Player.SendErrorMessage(" /tp <x> <y>");
}
else if (players.Count > 1) else if (players.Count > 1)
TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name));
else if (!players[0].TPAllow && !args.Player.Group.HasPermission(Permissions.tpall)) else if (!players[0].TPAllow && !args.Player.Group.HasPermission(Permissions.tpall))
@ -1662,7 +1685,7 @@ namespace TShockAPI
else else
{ {
var plr = players[0]; var plr = players[0];
if (args.Player.Teleport(plr.TileX, plr.TileY + 3)) if (args.Player.Teleport(plr.TileX * 16, plr.TileY * 16 + 48))
{ {
args.Player.SendSuccessMessage(string.Format("Teleported to {0}.", plr.Name)); args.Player.SendSuccessMessage(string.Format("Teleported to {0}.", plr.Name));
if (!args.Player.Group.HasPermission(Permissions.tphide)) if (!args.Player.Group.HasPermission(Permissions.tphide))
@ -1671,6 +1694,9 @@ namespace TShockAPI
} }
} }
}
private static void TPHere(CommandArgs args) private static void TPHere(CommandArgs args)
{ {
if (args.Parameters.Count < 1) if (args.Parameters.Count < 1)
@ -1688,7 +1714,7 @@ namespace TShockAPI
{ {
if (Main.player[i].active && (Main.player[i] != args.TPlayer)) if (Main.player[i].active && (Main.player[i] != args.TPlayer))
{ {
if (TShock.Players[i].Teleport(args.Player.TileX, args.Player.TileY + 3)) if (TShock.Players[i].Teleport(args.Player.TileX*16, args.Player.TileY*16 + 48))
TShock.Players[i].SendSuccessMessage(string.Format("You were teleported to {0}.", args.Player.Name) + "."); TShock.Players[i].SendSuccessMessage(string.Format("You were teleported to {0}.", args.Player.Name) + ".");
} }
} }
@ -1707,7 +1733,7 @@ namespace TShockAPI
else else
{ {
var plr = players[0]; var plr = players[0];
if (plr.Teleport(args.Player.TileX, args.Player.TileY + 3)) if (plr.Teleport(args.Player.TileX*16, args.Player.TileY*16 + 48))
{ {
plr.SendInfoMessage(string.Format("You were teleported to {0}.", args.Player.Name)); plr.SendInfoMessage(string.Format("You were teleported to {0}.", args.Player.Name));
args.Player.SendSuccessMessage(string.Format("You brought {0} here.", plr.Name)); args.Player.SendSuccessMessage(string.Format("You brought {0} here.", plr.Name));
@ -1851,7 +1877,7 @@ namespace TShockAPI
var plr = foundplr[0]; var plr = foundplr[0];
if (warp.WarpPos != Vector2.Zero) if (warp.WarpPos != Vector2.Zero)
{ {
if (plr.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3)) if (plr.Teleport((int)warp.WarpPos.X*16, (int)warp.WarpPos.Y*16 + 48))
{ {
plr.SendSuccessMessage(string.Format("{0} warped you to {1}.", args.Player.Name, warpName)); plr.SendSuccessMessage(string.Format("{0} warped you to {1}.", args.Player.Name, warpName));
args.Player.SendSuccessMessage(string.Format("You warped {0} to {1}.", plr.Name, warpName)); args.Player.SendSuccessMessage(string.Format("You warped {0} to {1}.", plr.Name, warpName));
@ -1869,7 +1895,7 @@ namespace TShockAPI
var warp = TShock.Warps.FindWarp(warpName); var warp = TShock.Warps.FindWarp(warpName);
if (warp.WarpPos != Vector2.Zero) if (warp.WarpPos != Vector2.Zero)
{ {
if (args.Player.Teleport((int)warp.WarpPos.X, (int)warp.WarpPos.Y + 3)) if (args.Player.Teleport((int)warp.WarpPos.X*16, (int)warp.WarpPos.Y*16 + 48))
args.Player.SendSuccessMessage("Warped to " + warpName + "."); args.Player.SendSuccessMessage("Warped to " + warpName + ".");
} }
else else
@ -2484,7 +2510,27 @@ namespace TShockAPI
} }
} }
//TODO: Come back here private static void Rain(CommandArgs args)
{
if (args.Parameters.Count != 1)
{
args.Player.SendErrorMessage("Invalid syntax! Proper syntax: /rain <stop/start>");
return;
}
switch (args.Parameters[0])
{
case "start":
Main.StartRain();
TSPlayer.All.SendInfoMessage(string.Format("{0} caused it to rain.", args.Player.Name));
break;
case "stop":
Main.StopRain();
TSPlayer.All.SendInfoMessage(string.Format("{0} ended the downpour.", args.Player.Name));
break;
}
}
private static void Slap(CommandArgs args) private static void Slap(CommandArgs args)
{ {
@ -2900,13 +2946,13 @@ namespace TShockAPI
// worth the effort as chances are very low that overwriting the wire for a few // worth the effort as chances are very low that overwriting the wire for a few
// nanoseconds will cause much trouble. // nanoseconds will cause much trouble.
Tile tile = Main.tile[boundaryPoint.X, boundaryPoint.Y]; Tile tile = Main.tile[boundaryPoint.X, boundaryPoint.Y];
bool oldWireState = tile.wire; bool oldWireState = tile.wire();
tile.wire = true; tile.wire(true);
try { try {
args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1); args.Player.SendTileSquare(boundaryPoint.X, boundaryPoint.Y, 1);
} finally { } finally {
tile.wire = oldWireState; tile.wire(oldWireState);
} }
} }
} }
@ -3027,7 +3073,7 @@ namespace TShockAPI
break; break;
} }
args.Player.Teleport(region.Area.Center.X, region.Area.Center.Y + 3); args.Player.Teleport(region.Area.Center.X*16, region.Area.Center.Y*16 + 48);
break; break;
} }
@ -3703,12 +3749,7 @@ namespace TShockAPI
playerToHeal = args.Player; playerToHeal = args.Player;
} }
Item heart = TShock.Utils.GetItemById(58); playerToHeal.Heal();
Item star = TShock.Utils.GetItemById(184);
for (int i = 0; i < 20; i++)
playerToHeal.GiveItem(heart.type, heart.name, heart.width, heart.height, heart.maxStack);
for (int i = 0; i < 10; i++)
playerToHeal.GiveItem(star.type, star.name, star.width, star.height, star.maxStack);
if (playerToHeal == args.Player) if (playerToHeal == args.Player)
{ {
args.Player.SendSuccessMessage("You just got healed!"); args.Player.SendSuccessMessage("You just got healed!");
@ -3829,7 +3870,7 @@ namespace TShockAPI
case "tree": case "tree":
for (int i = x - 1; i < x + 2; i++) for (int i = x - 1; i < x + 2; i++)
{ {
Main.tile[i, y].active = true; Main.tile[i, y].active(true);
Main.tile[i, y].type = 2; Main.tile[i, y].type = 2;
Main.tile[i, y].wall = 0; Main.tile[i, y].wall = 0;
} }
@ -3840,20 +3881,20 @@ namespace TShockAPI
case "epictree": case "epictree":
for (int i = x - 1; i < x + 2; i++) for (int i = x - 1; i < x + 2; i++)
{ {
Main.tile[i, y].active = true; Main.tile[i, y].active(true);
Main.tile[i, y].type = 2; Main.tile[i, y].type = 2;
Main.tile[i, y].wall = 0; Main.tile[i, y].wall = 0;
} }
Main.tile[x, y - 1].wall = 0; Main.tile[x, y - 1].wall = 0;
Main.tile[x, y - 1].liquid = 0; Main.tile[x, y - 1].liquid = 0;
Main.tile[x, y - 1].active = true; Main.tile[x, y - 1].active(true);
WorldGen.GrowEpicTree(x, y); WorldGen.GrowEpicTree(x, y);
name = "Epic Tree"; name = "Epic Tree";
break; break;
case "mushroom": case "mushroom":
for (int i = x - 1; i < x + 2; i++) for (int i = x - 1; i < x + 2; i++)
{ {
Main.tile[i, y].active = true; Main.tile[i, y].active(true);
Main.tile[i, y].type = 70; Main.tile[i, y].type = 70;
Main.tile[i, y].wall = 0; Main.tile[i, y].wall = 0;
} }
@ -3867,7 +3908,7 @@ namespace TShockAPI
name = "Cactus"; name = "Cactus";
break; break;
case "herb": case "herb":
Main.tile[x, y].active = true; Main.tile[x, y].active(true);
Main.tile[x, y].frameX = 36; Main.tile[x, y].frameX = 36;
Main.tile[x, y].type = 83; Main.tile[x, y].type = 83;
WorldGen.GrowAlch(x, y); WorldGen.GrowAlch(x, y);

View file

@ -124,7 +124,7 @@ namespace TShockAPI.DB
{ {
try try
{ {
return database.Query("INSERT INTO Bans (IP, Name, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4, @5);", ip, name, reason, banner, DateTime.Now.ToString("G"), expiration) != 0; return database.Query("INSERT INTO Bans (IP, Name, Reason, BanningUser, Date, Expiration) VALUES (@0, @1, @2, @3, @4, @5);", ip, name, reason, banner, DateTime.UtcNow.ToString("s"), expiration) != 0;
} }
catch (Exception ex) catch (Exception ex)
{ {

View file

@ -17,6 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
using System; using System;
using System.CodeDom.Compiler;
using System.Data; using System.Data;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -38,6 +39,7 @@ namespace TShockAPI.DB
new SqlColumn("Username", MySqlDbType.VarChar, 32) {Unique = true}, new SqlColumn("Username", MySqlDbType.VarChar, 32) {Unique = true},
new SqlColumn("Password", MySqlDbType.VarChar, 128), new SqlColumn("Password", MySqlDbType.VarChar, 128),
new SqlColumn("Usergroup", MySqlDbType.Text), new SqlColumn("Usergroup", MySqlDbType.Text),
new SqlColumn("Registered", MySqlDbType.Text),
new SqlColumn("LastAccessed", MySqlDbType.Text), new SqlColumn("LastAccessed", MySqlDbType.Text),
new SqlColumn("KnownIPs", MySqlDbType.Text) new SqlColumn("KnownIPs", MySqlDbType.Text)
); );
@ -60,8 +62,8 @@ namespace TShockAPI.DB
int ret; int ret;
try try
{ {
ret = database.Query("INSERT INTO Users (Username, Password, UserGroup) VALUES (@0, @1, @2);", user.Name, ret = database.Query("INSERT INTO Users (Username, Password, UserGroup, Registered) VALUES (@0, @1, @2, @3);", user.Name,
TShock.Utils.HashPassword(user.Password), user.Group); TShock.Utils.HashPassword(user.Password), user.Group, DateTime.UtcNow.ToString("s"));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -146,7 +148,7 @@ namespace TShockAPI.DB
{ {
try try
{ {
if (database.Query("UPDATE Users SET LastAccessed = @0, KnownIps = @1 WHERE Username = @2;", DateTime.Now.ToString("G"), user.KnownIps, user.Name) == 0) if (database.Query("UPDATE Users SET LastAccessed = @0, KnownIps = @1 WHERE Username = @2;", DateTime.UtcNow.ToString("s"), user.KnownIps, user.Name) == 0)
throw new UserNotExistException(user.Name); throw new UserNotExistException(user.Name);
} }
catch (Exception ex) catch (Exception ex)
@ -268,6 +270,7 @@ namespace TShockAPI.DB
user.Group = result.Get<string>("Usergroup"); user.Group = result.Get<string>("Usergroup");
user.Password = result.Get<string>("Password"); user.Password = result.Get<string>("Password");
user.Name = result.Get<string>("Username"); user.Name = result.Get<string>("Username");
user.Registered = result.Get<string>("Registered");
user.LastAccessed = result.Get<string>("LastAccessed"); user.LastAccessed = result.Get<string>("LastAccessed");
user.KnownIps = result.Get<string>("KnownIps"); user.KnownIps = result.Get<string>("KnownIps");
return user; return user;
@ -280,14 +283,16 @@ namespace TShockAPI.DB
public string Name { get; set; } public string Name { get; set; }
public string Password { get; set; } public string Password { get; set; }
public string Group { get; set; } public string Group { get; set; }
public string Registered { get; set; }
public string LastAccessed { get; set; } public string LastAccessed { get; set; }
public string KnownIps { get; set; } public string KnownIps { get; set; }
public User(string name, string pass, string group, string last, string known) public User(string name, string pass, string group, string registered, string last, string known)
{ {
Name = name; Name = name;
Password = pass; Password = pass;
Group = group; Group = group;
Registered = registered;
LastAccessed = last; LastAccessed = last;
KnownIps = known; KnownIps = known;
} }
@ -297,6 +302,7 @@ namespace TShockAPI.DB
Name = ""; Name = "";
Password = ""; Password = "";
Group = ""; Group = "";
Registered = "";
LastAccessed = ""; LastAccessed = "";
KnownIps = ""; KnownIps = "";
} }

View file

@ -78,17 +78,17 @@ namespace TShockAPI
/// <summary> /// <summary>
/// The Tile ID being edited. /// The Tile ID being edited.
/// </summary> /// </summary>
public byte Type { get; set; } public byte EditData { get; set; }
/// <summary> /// <summary>
/// The EditType. /// The EditType.
/// (KillTile = 0, PlaceTile = 1, KillWall = 2, PlaceWall = 3, KillTileNoItem = 4, PlaceWire = 5, KillWire = 6) /// (KillTile = 0, PlaceTile = 1, KillWall = 2, PlaceWall = 3, KillTileNoItem = 4, PlaceWire = 5, KillWire = 6)
/// </summary> /// </summary>
public byte EditType { get; set; } public EditAction Action { get; set; }
/// <summary> /// <summary>
/// Did the tile get destroyed successfully. /// Did the tile get destroyed successfully.
/// </summary> /// </summary>
public bool Fail { get; set; } public EditType editDetail { get; set; }
/// <summary> /// <summary>
/// Used when a tile is placed to denote a subtype of tile. (e.g. for tile id 21: Chest = 0, Gold Chest = 1) /// Used when a tile is placed to denote a subtype of tile. (e.g. for tile id 21: Chest = 0, Gold Chest = 1)
@ -100,7 +100,7 @@ namespace TShockAPI
/// TileEdit - called when a tile is placed or destroyed /// TileEdit - called when a tile is placed or destroyed
/// </summary> /// </summary>
public static HandlerList<TileEditEventArgs> TileEdit; public static HandlerList<TileEditEventArgs> TileEdit;
private static bool OnTileEdit(TSPlayer ply, int x, int y, byte type, byte editType, bool fail, byte style) private static bool OnTileEdit(TSPlayer ply, int x, int y, EditAction action, EditType editDetail, byte editData, byte style)
{ {
if (TileEdit == null) if (TileEdit == null)
return false; return false;
@ -110,9 +110,9 @@ namespace TShockAPI
Player = ply, Player = ply,
X = x, X = x,
Y = y, Y = y,
Type = type, Action = action,
EditType = editType, EditData = editData,
Fail = fail, editDetail = editDetail,
Style = style Style = style
}; };
TileEdit.Invoke(null, args); TileEdit.Invoke(null, args);
@ -443,13 +443,15 @@ namespace TShockAPI
/// Velocity of the player /// Velocity of the player
/// </summary> /// </summary>
public Vector2 Velocity { get; set; } public Vector2 Velocity { get; set; }
public byte Pulley { get; set; }
} }
/// <summary> /// <summary>
/// PlayerUpdate - When the player sends it's updated information to the server /// PlayerUpdate - When the player sends it's updated information to the server
/// </summary> /// </summary>
public static HandlerList<PlayerUpdateEventArgs> PlayerUpdate; public static HandlerList<PlayerUpdateEventArgs> PlayerUpdate;
private static bool OnPlayerUpdate(byte player, byte control, byte item, Vector2 position, Vector2 velocity) private static bool OnPlayerUpdate(byte player, byte control, byte item, Vector2 position, Vector2 velocity, byte pulley)
{ {
if (PlayerUpdate == null) if (PlayerUpdate == null)
return false; return false;
@ -461,16 +463,17 @@ namespace TShockAPI
Item = item, Item = item,
Position = position, Position = position,
Velocity = velocity, Velocity = velocity,
Pulley = pulley
}; };
PlayerUpdate.Invoke(null, args); PlayerUpdate.Invoke(null, args);
return args.Handled; return args.Handled;
} }
public static bool TSCheckNoclip(Vector2 Position, int Width, int Height) public static bool TSCheckNoclip(Vector2 Position, int Width, int Height)
{ {
int num = (int)(Position.X / 16f) - 1; int num = (int)(Position.X / 16f);
int num2 = (int)((Position.X + (float)Width) / 16f) + 2; int num2 = (int)((Position.X + (float)Width) / 16f);
int num3 = (int)(Position.Y / 16f) - 1; int num3 = (int)(Position.Y / 16f);
int num4 = (int)((Position.Y + (float)Height) / 16f) + 2; int num4 = (int)((Position.Y + (float)Height) / 16f);
if (num < 0) if (num < 0)
{ {
num = 0; num = 0;
@ -499,18 +502,20 @@ namespace TShockAPI
{ {
for (int j = num3; j < num4; j++) for (int j = num3; j < num4; j++)
{ {
if (Main.tile[i, j] != null && Main.tile[i, j].active && Main.tileSolid[(int)Main.tile[i, j].type] && !Main.tileSolidTop[(int)Main.tile[i, j].type] &&(((int)Main.tile[i,j].type !=53) && ((int)Main.tile[i,j].type !=112) && ((int)Main.tile[i,j].type !=116) && ((int)Main.tile[i,j].type !=123)) && !Main.tile[i,j].lava) if (Main.tile[i, j] == null || !Main.tile[i, j].active() || !Main.tileSolid[(int) Main.tile[i, j].type] || Main.tileSolidTop[(int) Main.tile[i, j].type] || (((int) Main.tile[i, j].type == 53) || ((int) Main.tile[i, j].type == 112) || ((int) Main.tile[i, j].type == 116) || ((int) Main.tile[i, j].type == 123)) || Main.tile[i, j].lava() || ((Main.tile[i, j].tileHeader2 & 16) == 16) || ((Main.tile[i, j].tileHeader2 & 32) == 32) || ((Main.tile[i, j].tileHeader & 32) == 32) || Main.tile[i, j].honey() || !Main.tileSolid[(int) Main.tile[i + 1, j].type] || !Main.tileSolid[(int) Main.tile[i - 1, j].type] || !Main.tileSolid[(int) Main.tile[i, j + 1].type] || !Main.tileSolid[(int) Main.tile[i, j - 1].type] || !Main.tileSolid[(int) Main.tile[i - 1, j - 1].type] || !Main.tileSolid[(int) Main.tile[i - 1, j + 1].type] || !Main.tileSolid[(int) Main.tile[i + 1, j - 1].type] || !Main.tileSolid[(int) Main.tile[i + 1, j + 1].type] || Main.tileSand[(int) Main.tile[i, j].type])
{ {
continue;
}
Vector2 vector; Vector2 vector;
vector.X = (float)(i * 16); vector.X = (float) (i*16);
vector.Y = (float)(j * 16); vector.Y = (float) (j*16);
if (Position.X + (float)Width > vector.X && Position.X < vector.X + 16f && Position.Y + (float)Height > vector.Y && Position.Y < vector.Y + 16f) if (Position.X + (float) Width > vector.X && Position.X < vector.X + 16f && Position.Y + (float) Height > vector.Y && Position.Y < vector.Y + 16f)
{ {
return true; return true;
} }
} }
} }
}
return false; return false;
} }
@ -628,20 +633,20 @@ namespace TShockAPI
/// </summary> /// </summary>
public int TileY { get; set; } public int TileY { get; set; }
/// <summary> /// <summary>
/// ??? /// Amount of liquid
/// </summary> /// </summary>
public byte Liquid { get; set;} public byte Amount { get; set;}
/// <summary> /// <summary>
/// True if lava /// Type of Liquid: 0=water, 1=lave, 2=honey
/// </summary> /// </summary>
public bool Lava { get; set; } public byte Type { get; set; }
} }
/// <summary> /// <summary>
/// LiquidSet - When ever a liquid is set /// LiquidSet - When ever a liquid is set
/// </summary> /// </summary>
public static HandlerList<LiquidSetEventArgs> LiquidSet; public static HandlerList<LiquidSetEventArgs> LiquidSet;
private static bool OnLiquidSet(int tilex, int tiley, byte liquid, bool lava) private static bool OnLiquidSet(int tilex, int tiley, byte amount, byte type)
{ {
if (LiquidSet == null) if (LiquidSet == null)
return false; return false;
@ -650,8 +655,8 @@ namespace TShockAPI
{ {
TileX = tilex, TileX = tilex,
TileY = tiley, TileY = tiley,
Liquid = liquid, Amount = amount,
Lava = lava, Type = type,
}; };
LiquidSet.Invoke(null, args); LiquidSet.Invoke(null, args);
return args.Handled; return args.Handled;
@ -919,6 +924,10 @@ namespace TShockAPI
/// </summary> /// </summary>
public byte Prefix { get; set; } public byte Prefix { get; set; }
/// <summary> /// <summary>
/// No Delay on pickup
/// </summary>
public bool NoDelay { get; set; }
/// <summary>
/// Item type /// Item type
/// </summary> /// </summary>
public short Type { get; set; } public short Type { get; set; }
@ -928,7 +937,7 @@ namespace TShockAPI
/// </summary> /// </summary>
public static HandlerList<ItemDropEventArgs> ItemDrop; public static HandlerList<ItemDropEventArgs> ItemDrop;
private static bool OnItemDrop(short id, Vector2 pos, Vector2 vel, byte stacks, byte prefix, short type) private static bool OnItemDrop(short id, Vector2 pos, Vector2 vel, byte stacks, byte prefix, bool noDelay, short type)
{ {
if (ItemDrop == null) if (ItemDrop == null)
return false; return false;
@ -940,6 +949,7 @@ namespace TShockAPI
Velocity = vel, Velocity = vel,
Stacks = stacks, Stacks = stacks,
Prefix = prefix, Prefix = prefix,
NoDelay = noDelay,
Type = type, Type = type,
}; };
ItemDrop.Invoke(null, args); ItemDrop.Invoke(null, args);
@ -1125,6 +1135,53 @@ namespace TShockAPI
return args.Handled; return args.Handled;
} }
/// <summary>
/// For use with a NPCStrike event
/// </summary>
public class TeleportEventArgs : HandledEventArgs
{
/// <summary>
/// ???
/// </summary>
public Int16 ID { get; set; }
/// <summary>
/// Flag is a bit field
/// if the first bit is set -> 0 = player, 1 = NPC
/// if the second bit is set, ignore this packet
/// if the third bit is set, style +1
/// if the fourth bit is set, style +1
/// </summary>
public byte Flag { get; set; }
/// <summary>
/// X Location
/// </summary>
public float X { get; set; }
/// <summary>
/// Y Location
/// </summary>
public float Y { get; set; }
}
/// <summary>
/// NPCStrike - Called when an NPC is attacked
/// </summary>
public static HandlerList<TeleportEventArgs> Teleport;
private static bool OnTeleport(Int16 id, byte f, float x, float y)
{
if (Teleport == null)
return false;
var args = new TeleportEventArgs
{
ID = id,
Flag = f,
X = x,
Y = y
};
Teleport.Invoke(null, args);
return args.Handled;
}
#endregion #endregion
public static void InitGetDataHandler() public static void InitGetDataHandler()
{ {
@ -1169,7 +1226,10 @@ namespace TShockAPI
{PacketTypes.PasswordSend, HandlePassword}, {PacketTypes.PasswordSend, HandlePassword},
{PacketTypes.ContinueConnecting2, HandleConnecting}, {PacketTypes.ContinueConnecting2, HandleConnecting},
{PacketTypes.ProjectileDestroy, HandleProjectileKill}, {PacketTypes.ProjectileDestroy, HandleProjectileKill},
{PacketTypes.SpawnBossorInvasion, HandleSpawnBoss} {PacketTypes.SpawnBossorInvasion, HandleSpawnBoss},
{PacketTypes.Teleport, HandleTeleport},
{PacketTypes.PaintTile, HandlePaintTile},
{PacketTypes.PaintWall, HandlePaintWall}
}; };
} }
@ -1251,7 +1311,7 @@ namespace TShockAPI
if (args.Player.FirstMaxHP == 0) if (args.Player.FirstMaxHP == 0)
args.Player.FirstMaxHP = max; args.Player.FirstMaxHP = max;
if (max > TShock.Config.MaxHealth && max > args.Player.FirstMaxHP) if ((max > TShock.Config.MaxHealth && max > args.Player.FirstMaxHP) && !args.Player.Group.HasPermission(Permissions.ignorestathackdetection))
{ {
TShock.Utils.ForceKick(args.Player, "Hacked Client Detected.", true); TShock.Utils.ForceKick(args.Player, "Hacked Client Detected.", true);
return false; return false;
@ -1262,6 +1322,11 @@ namespace TShockAPI
args.Player.PlayerData.maxHealth = max; args.Player.PlayerData.maxHealth = max;
} }
if (args.Player.Group.HasPermission(Permissions.godmode) && (cur < max))
{
args.Player.Heal(args.TPlayer.statLifeMax);
}
return false; return false;
} }
@ -1330,6 +1395,7 @@ namespace TShockAPI
private static bool HandleConnecting(GetDataHandlerArgs args) private static bool HandleConnecting(GetDataHandlerArgs args)
{ {
var user = TShock.Users.GetUserByName(args.Player.Name); var user = TShock.Users.GetUserByName(args.Player.Name);
if (user != null && !TShock.Config.DisableLoginBeforeJoin) if (user != null && !TShock.Config.DisableLoginBeforeJoin)
{ {
args.Player.RequiresPassword = true; args.Player.RequiresPassword = true;
@ -1543,10 +1609,10 @@ namespace TShockAPI
continue; continue;
} }
// Server now has a range check built in // Server now has a range check built in
/*if (TShock.CheckRangePermission(args.Player, realx, realy)) if (TShock.CheckRangePermission(args.Player, realx, realy))
{ {
continue; continue;
}*/ }
if ((tile.type == 128 && newtile.Type == 128) || (tile.type == 105 && newtile.Type == 105) || (tile.type == 139 && newtile.Type == 139)) if ((tile.type == 128 && newtile.Type == 128) || (tile.type == 105 && newtile.Type == 105) || (tile.type == 139 && newtile.Type == 139))
{ {
if (TShock.Config.EnableInsecureTileFixes) if (TShock.Config.EnableInsecureTileFixes)
@ -1673,16 +1739,39 @@ namespace TShockAPI
return true; return true;
} }
public enum EditAction
{
KillTile = 0,
PlaceTile,
KillWall,
PlaceWall,
KillTileNoItem,
PlaceWire,
KillWire,
PoundTile
}
public enum EditType
{
Fail = 0,
Type,
Slope,
}
private static bool HandleTile(GetDataHandlerArgs args) private static bool HandleTile(GetDataHandlerArgs args)
{ {
var type = args.Data.ReadInt8(); EditAction action = (EditAction)args.Data.ReadInt8();
var tileX = args.Data.ReadInt32(); var tileX = args.Data.ReadInt32();
var tileY = args.Data.ReadInt32(); var tileY = args.Data.ReadInt32();
var tiletype = args.Data.ReadInt8(); var editData = args.Data.ReadInt8();
var fail = tiletype == 1; EditType type = (action == EditAction.KillTile || action == EditAction.KillWall ||
action == EditAction.KillTileNoItem)
? EditType.Fail
: (action == EditAction.PlaceTile || action == EditAction.PlaceWall)
? EditType.Type
: EditType.Slope;
var style = args.Data.ReadInt8(); var style = args.Data.ReadInt8();
if (OnTileEdit(args.Player, tileX, tileY, tiletype, type, fail, style)) if (OnTileEdit(args.Player, tileX, tileY, action, type, editData, style))
return true; return true;
if (!TShock.Utils.TilePlacementValid(tileX, tileY)) if (!TShock.Utils.TilePlacementValid(tileX, tileY))
return false; return false;
@ -1767,62 +1856,64 @@ namespace TShockAPI
if (type == 0 && Main.tile[tileX, tileY].type != 127 && !Main.tileCut[Main.tile[tileX, tileY].type] && !rightClickKill.Contains(Main.tile[tileX, tileY].type)) if (type == 0 && Main.tile[tileX, tileY].type != 127 && !Main.tileCut[Main.tile[tileX, tileY].type] && !rightClickKill.Contains(Main.tile[tileX, tileY].type))
{ {
// If the tile is an axe tile and they aren't selecting an axe, they're hacking. // If the tile is an axe tile and they aren't selecting an axe, they're hacking.
if (Main.tileAxe[Main.tile[tileX, tileY].type] && selectedItem.axe == 0) if (Main.tileAxe[Main.tile[tileX, tileY].type] && (selectedItem.axe == 0 && selectedItem.explosive == 0 && args.Player.RecentFuse == 0))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
// If the tile is a hammer tile and they aren't selecting an hammer, they're hacking. // If the tile is a hammer tile and they aren't selecting an hammer, they're hacking.
else if (Main.tileHammer[Main.tile[tileX, tileY].type] && selectedItem.hammer == 0) else if (Main.tileHammer[Main.tile[tileX, tileY].type] && (selectedItem.hammer == 0 && selectedItem.explosive == 0 && args.Player.RecentFuse == 0))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
// If the tile is a pickaxe tile and they aren't selecting an pickaxe, they're hacking. // If the tile is a pickaxe tile and they aren't selecting an pickaxe, they're hacking.
else if ((!Main.tileAxe[Main.tile[tileX, tileY].type] && !Main.tileHammer[Main.tile[tileX, tileY].type]) && selectedItem.pick == 0) else if ((!Main.tileAxe[Main.tile[tileX, tileY].type] && !Main.tileHammer[Main.tile[tileX, tileY].type]) && (selectedItem.pick == 0 && selectedItem.explosive == 0 && args.Player.RecentFuse == 0))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
} }
else if (type == 2) else if (action == EditAction.KillWall)
{ {
// If they aren't selecting an hammer, they're hacking. // If they aren't selecting an hammer, they're hacking.
if (selectedItem.hammer == 0) if (selectedItem.hammer == 0 && selectedItem.explosive == 0 && args.Player.RecentFuse == 0)
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
} }
else if (type == 1 || type == 3) else if (action == EditAction.PlaceTile || action == EditAction.PlaceWall)
{ {
if (type == 1 && TShock.Config.PreventInvalidPlaceStyle && ((tiletype == 4 && style > 8) || if (action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle && ((editData == 4 && style > 11) ||
(tiletype == 13 && style > 4) || (tiletype == 15 && style > 1) || (tiletype == 21 && style > 6) || (editData == 13 && style > 4) || (editData == 15 && style > 17) || (editData == 21 && style > 22) ||
(tiletype == 82 && style > 5) || (tiletype == 91 && style > 3) || (tiletype == 105 && style > 42) || (editData == 82 && style > 5) || (editData == 91 && style > 21) || (editData == 105 && style > 49) ||
(tiletype == 135 && style > 3) || (tiletype == 139 && style > 12) || (tiletype == 144 && style > 2) || (editData == 135 && style > 6) || (editData == 139 && style > 27) || (editData == 144 && style > 2) ||
(tiletype == 149 && style > 2))) (editData == 149 && style > 2)))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
// If they aren't selecting the item which creates the tile or wall, they're hacking. // If they aren't selecting the item which creates the tile or wall, they're hacking.
if (tiletype != 127 && tiletype != (type == 1 ? selectedItem.createTile : selectedItem.createWall)) if (editData != 127 && editData != (action == EditAction.PlaceTile ? selectedItem.createTile : selectedItem.createWall))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
if (TShock.Itembans.ItemIsBanned(selectedItem.name, args.Player) || tiletype >= (type == 1 ? Main.maxTileSets : Main.maxWallTypes)) if (TShock.Itembans.ItemIsBanned(selectedItem.name, args.Player) || editData >= (action == EditAction.PlaceTile ? Main.maxTileSets : Main.maxWallTypes))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
if (type == 1 && (tiletype == 29 || tiletype == 97) && TShock.Config.ServerSideInventory && TShock.Config.DisablePiggybanksOnSSI) if (action == EditAction.PlaceTile && (editData == 29 || editData == 97) && TShock.Config.ServerSideInventory && TShock.Config.DisablePiggybanksOnSSI)
{ {
args.Player.SendMessage("You cannot place this tile because server side inventory is enabled.", Color.Red); args.Player.SendMessage("You cannot place this tile because server side inventory is enabled.", Color.Red);
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
if (type == 1 && tiletype == 21) if (action == EditAction.PlaceTile && editData == 21)
{ {
if (TShock.Utils.MaxChests()) if (TShock.Utils.MaxChests())
{ {
@ -1838,7 +1929,7 @@ namespace TShockAPI
} }
} }
} }
else if (type == 5) else if (action == EditAction.PlaceWire)
{ {
// If they aren't selecting the wrench, they're hacking. // If they aren't selecting the wrench, they're hacking.
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 509) if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 509)
@ -1847,7 +1938,7 @@ namespace TShockAPI
return true; return true;
} }
} }
else if (type == 6) else if (action == EditAction.KillWire)
{ {
// If they aren't selecting the wire cutter, they're hacking. // If they aren't selecting the wire cutter, they're hacking.
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 510) if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 510)
@ -1863,13 +1954,13 @@ namespace TShockAPI
return true; return true;
} }
if (TShock.CheckTilePermission(args.Player, tileX, tileY, tiletype, type)) if (TShock.CheckTilePermission(args.Player, tileX, tileY, editData, action))
{ {
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
if ((tiletype == 127 || Main.tileCut[tiletype]) && (type == 0 || type == 4)) if ((editData == 127 || Main.tileCut[editData]) && (action ==EditAction.KillTile || action == EditAction.KillTileNoItem))
{ {
return false; return false;
} }
@ -1900,26 +1991,103 @@ namespace TShockAPI
return true; return true;
} }
if ( ( type == 1 || type == 3 ) && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection)) if ( ( action == EditAction.PlaceTile || action == EditAction.PlaceWall ) && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection))
{ {
args.Player.TilePlaceThreshold++; args.Player.TilePlaceThreshold++;
var coords = new Vector2(tileX, tileY); var coords = new Vector2(tileX, tileY);
if (!args.Player.TilesCreated.ContainsKey(coords)) if (!args.Player.TilesCreated.ContainsKey(coords))
args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY].Data); args.Player.TilesCreated.Add(coords, Main.tile[tileX, tileY]);
} }
if ((type == 0 || type == 4 || type == 2) && Main.tileSolid[Main.tile[tileX, tileY].type] && if ((action == EditAction.KillTile || action == EditAction.KillTileNoItem || action == EditAction.KillWall) && Main.tileSolid[Main.tile[tileX, tileY].type] &&
!args.Player.Group.HasPermission(Permissions.ignorekilltiledetection)) !args.Player.Group.HasPermission(Permissions.ignorekilltiledetection))
{ {
args.Player.TileKillThreshold++; args.Player.TileKillThreshold++;
var coords = new Vector2(tileX, tileY); var coords = new Vector2(tileX, tileY);
if (!args.Player.TilesDestroyed.ContainsKey(coords)) if (!args.Player.TilesDestroyed.ContainsKey(coords))
args.Player.TilesDestroyed.Add(coords, Main.tile[tileX, tileY].Data); args.Player.TilesDestroyed.Add(coords, Main.tile[tileX, tileY]);
} }
return false; return false;
} }
/// <summary>
/// For use with a PaintTile event
/// </summary>
public class PaintTileEventArgs : HandledEventArgs
{
/// <summary>
/// X Location
/// </summary>
public Int32 X { get; set; }
/// <summary>
/// Y Location
/// </summary>
public Int32 Y { get; set; }
/// <summary>
/// Type
/// </summary>
public byte type { get; set; }
}
/// <summary>
/// NPCStrike - Called when an NPC is attacked
/// </summary>
public static HandlerList<PaintTileEventArgs> PaintTile;
private static bool OnPaintTile(Int32 x, Int32 y, byte t)
{
if (PaintTile == null)
return false;
var args = new PaintTileEventArgs
{
X = x,
Y = y,
type = t
};
PaintTile.Invoke(null, args);
return args.Handled;
}
/// <summary>
/// For use with a PaintWall event
/// </summary>
public class PaintWallEventArgs : HandledEventArgs
{
/// <summary>
/// X Location
/// </summary>
public Int32 X { get; set; }
/// <summary>
/// Y Location
/// </summary>
public Int32 Y { get; set; }
/// <summary>
/// Type
/// </summary>
public byte type { get; set; }
}
/// <summary>
/// Called When a wall is painted
/// </summary>
public static HandlerList<PaintWallEventArgs> PaintWall;
private static bool OnPaintWall(Int32 x, Int32 y, byte t)
{
if (PaintWall == null)
return false;
var args = new PaintWallEventArgs
{
X = x,
Y = y,
type = t
};
PaintWall.Invoke(null, args);
return args.Handled;
}
private static bool HandleTogglePvp(GetDataHandlerArgs args) private static bool HandleTogglePvp(GetDataHandlerArgs args)
{ {
byte id = args.Data.ReadInt8(); byte id = args.Data.ReadInt8();
@ -1987,13 +2155,19 @@ namespace TShockAPI
var item = args.Data.ReadInt8(); var item = args.Data.ReadInt8();
var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); var pos = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
if (OnPlayerUpdate(plr, control, item, pos, vel)) byte pulley = args.Data.ReadInt8();
if (OnPlayerUpdate(plr, control, item, pos, vel, pulley))
return true; return true;
if (item < 0 || item >= args.TPlayer.inventory.Length) if (item < 0 || item >= args.TPlayer.inventory.Length)
{ {
return true; return true;
} }
if (pulley > 2)
{
return true;
}
if (args.Player.LastNetPosition == Vector2.Zero) if (args.Player.LastNetPosition == Vector2.Zero)
{ {
return true; return true;
@ -2036,8 +2210,8 @@ namespace TShockAPI
args.Player.SendMessage("PvP is forced! Enable PvP or else you can't do anything!", args.Player.SendMessage("PvP is forced! Enable PvP or else you can't do anything!",
Color.Red); Color.Red);
} }
int lastTileX = (int) (args.Player.LastNetPosition.X/16f); var lastTileX = args.Player.LastNetPosition.X;
int lastTileY = (int) (args.Player.LastNetPosition.Y/16f); var lastTileY = args.Player.LastNetPosition.Y;
if (!args.Player.Teleport(lastTileX, lastTileY)) if (!args.Player.Teleport(lastTileX, lastTileY))
{ {
args.Player.Spawn(); args.Player.Spawn();
@ -2056,9 +2230,9 @@ namespace TShockAPI
TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip
&& !args.TPlayer.tongued) && !args.TPlayer.tongued)
{ {
int lastTileX = (int)(args.Player.LastNetPosition.X / 16f); var lastTileX = args.Player.LastNetPosition.X;
int lastTileY = (int)(args.Player.LastNetPosition.Y / 16f); var lastTileY = args.Player.LastNetPosition.Y;
if (!args.Player.Teleport(lastTileX, lastTileY + 3)) if (!args.Player.Teleport(lastTileX, lastTileY + 48))
{ {
args.Player.SendErrorMessage("You got stuck in a solid object, Sent to spawn point."); args.Player.SendErrorMessage("You got stuck in a solid object, Sent to spawn point.");
args.Player.Spawn(); args.Player.Spawn();
@ -2092,6 +2266,8 @@ namespace TShockAPI
args.TPlayer.controlRight = false; args.TPlayer.controlRight = false;
args.TPlayer.controlJump = false; args.TPlayer.controlJump = false;
args.TPlayer.controlUseItem = false; args.TPlayer.controlUseItem = false;
args.TPlayer.pulley = pulley != 0;
args.TPlayer.pulleyDir = pulley;
args.TPlayer.direction = -1; args.TPlayer.direction = -1;
if ((control & 1) == 1) if ((control & 1) == 1)
{ {
@ -2207,12 +2383,14 @@ namespace TShockAPI
} }
} }
// force all explosives server-side. // force all explosives server-side. -- DOES NOT WORK DUE TO LATENCY
if (hasPermission && (type == 28 || type == 29 || type == 37)) if (hasPermission && (type == 28 || type == 29 || type == 37))
{ {
args.Player.RemoveProjectile(ident, owner); // Denotes that the player has recently set a fuse - used for cheat detection.
Projectile.NewProjectile(pos.X, pos.Y, vel.X, vel.Y, type, dmg, knockback); args.Player.RecentFuse = 10;
return true; // args.Player.RemoveProjectile(ident, owner);
// Projectile.NewProjectile(pos.X, pos.Y, vel.X, vel.Y, type, dmg, knockback);
// return true;
} }
return false; return false;
@ -2291,11 +2469,12 @@ namespace TShockAPI
{ {
int tileX = args.Data.ReadInt32(); int tileX = args.Data.ReadInt32();
int tileY = args.Data.ReadInt32(); int tileY = args.Data.ReadInt32();
byte liquid = args.Data.ReadInt8(); byte amount = args.Data.ReadInt8();
bool lava = args.Data.ReadBoolean(); byte type = args.Data.ReadInt8();
if (OnLiquidSet(tileX, tileY, liquid, lava)) if (OnLiquidSet(tileX, tileY, amount, type))
return true; return true;
if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY) if (tileX < 0 || tileX >= Main.maxTilesX || tileY < 0 || tileY >= Main.maxTilesY)
return false; return false;
@ -2314,12 +2493,16 @@ namespace TShockAPI
if (!args.Player.Group.HasPermission(Permissions.ignoreliquidsetdetection)) if (!args.Player.Group.HasPermission(Permissions.ignoreliquidsetdetection))
{ {
args.Player.TileLiquidThreshold++; args.Player.TileLiquidThreshold+=amount;
} }
if (liquid != 0) if (amount != 0)
{ {
int bucket = 0; int bucket = -1;
if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206) if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 205)
{
bucket = 0;
}
else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 206)
{ {
bucket = 1; bucket = 1;
} }
@ -2327,8 +2510,12 @@ namespace TShockAPI
{ {
bucket = 2; bucket = 2;
} }
else if (args.TPlayer.inventory[args.TPlayer.selectedItem].type == 1128)
{
bucket = 3;
}
if(lava && bucket != 2) if (type == 1 && !(bucket == 2 || bucket == 0))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading lava without holding a lava bucket"); args.Player.Disable("Spreading lava without holding a lava bucket");
@ -2336,7 +2523,7 @@ namespace TShockAPI
return true; return true;
} }
if(lava && (!args.Player.Group.HasPermission(Permissions.usebanneditem) && if(type == 1 && (!args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player))) TShock.Itembans.ItemIsBanned("Lava Bucket", args.Player)))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
@ -2345,7 +2532,7 @@ namespace TShockAPI
return true; return true;
} }
if (!lava && bucket != 1) if (type == 0 && !(bucket == 1 || bucket == 0))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading water without holding a water bucket"); args.Player.Disable("Spreading water without holding a water bucket");
@ -2353,7 +2540,7 @@ namespace TShockAPI
return true; return true;
} }
if (!lava && (!args.Player.Group.HasPermission(Permissions.usebanneditem) && if (type == 0 && (!args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Water Bucket", args.Player))) TShock.Itembans.ItemIsBanned("Water Bucket", args.Player)))
{ {
args.Player.SendErrorMessage("You do not have permission to perform this action."); args.Player.SendErrorMessage("You do not have permission to perform this action.");
@ -2361,6 +2548,23 @@ namespace TShockAPI
args.Player.SendTileSquare(tileX, tileY); args.Player.SendTileSquare(tileX, tileY);
return true; return true;
} }
if (type == 2 &&!(bucket == 3 || bucket == 0))
{
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Spreading honey without holding a honey bucket");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
if (type == 2 && (!args.Player.Group.HasPermission(Permissions.usebanneditem) &&
TShock.Itembans.ItemIsBanned("Honey Bucket", args.Player)))
{
args.Player.SendErrorMessage("You do not have permission to perform this action.");
args.Player.Disable("Using banned honey bucket without permissions");
args.Player.SendTileSquare(tileX, tileY);
return true;
}
} }
if (TShock.CheckTilePermission(args.Player, tileX, tileY)) if (TShock.CheckTilePermission(args.Player, tileX, tileY))
@ -2631,13 +2835,14 @@ namespace TShockAPI
var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle()); var vel = new Vector2(args.Data.ReadSingle(), args.Data.ReadSingle());
var stacks = args.Data.ReadInt8(); var stacks = args.Data.ReadInt8();
var prefix = args.Data.ReadInt8(); var prefix = args.Data.ReadInt8();
var noDelay = args.Data.ReadBoolean();
var type = args.Data.ReadInt16(); var type = args.Data.ReadInt16();
if (OnItemDrop(id, pos, vel, stacks, prefix, type)) if (OnItemDrop(id, pos, vel, stacks, prefix, noDelay, type))
return true; return true;
// player is attempting to crash clients // player is attempting to crash clients
if (type < -24 || type >= Main.maxItemTypes) if (type < -48 || type >= Main.maxItemTypes)
{ {
return true; return true;
} }
@ -2737,6 +2942,11 @@ namespace TShockAPI
return true; return true;
} }
if (args.Player.Group.HasPermission(Permissions.godmode))
{
args.Player.Heal(args.TPlayer.statLifeMax);
}
return false; return false;
} }
@ -2939,5 +3149,96 @@ namespace TShockAPI
TShock.Utils.SendLogs(string.Format("{0} summoned {1}", args.Player.Name, boss), Color.PaleVioletRed, args.Player); TShock.Utils.SendLogs(string.Format("{0} summoned {1}", args.Player.Name, boss), Color.PaleVioletRed, args.Player);
return false; return false;
} }
private static bool HandlePaintTile(GetDataHandlerArgs args)
{
var x = args.Data.ReadInt32();
var y = args.Data.ReadInt32();
var t = args.Data.ReadInt8();
if (OnPaintTile(x, y, t))
return true;
if (!args.Player.Group.HasPermission(Permissions.canpaint))
{
args.Player.SendTileSquare(x, y);
return true;
}
return false;
}
private static bool HandlePaintWall(GetDataHandlerArgs args)
{
var x = args.Data.ReadInt32();
var y = args.Data.ReadInt32();
var t = args.Data.ReadInt8();
if (OnPaintTile(x, y, t))
return true;
if (!args.Player.Group.HasPermission(Permissions.canpaint))
{
args.Player.SendTileSquare(x, y);
return true;
}
return false;
}
private static bool HandleTeleport(GetDataHandlerArgs args)
{
var flag = args.Data.ReadInt8();
var id = args.Data.ReadInt16();
var x = args.Data.ReadSingle();
var y = args.Data.ReadSingle();
if (OnTeleport(id, flag, x, y))
return true;
byte style = 0;
var isNPC = false;
if ((flag & 1) == 1)
{
isNPC = true;
}
if ((flag & 2) != 2)
{
if ((flag & 4) == 4)
{
style++;
}
if ((flag & 8) == 8)
{
style++;
}
if (id > (isNPC ? 200 : 255))
{
return true;
}
if (Main.player[id] == null || TShock.Players[id] == null)
{
return true;
}
if (!isNPC && !args.Player.Group.HasPermission(Permissions.tp))
{
args.Player.SendErrorMessage("You do not have permission to teleport.");
Main.player[id].Teleport(new Vector2(Main.player[id].position.X, Main.player[id].position.Y), style);
NetMessage.SendData(65, -1, -1, "", 0, (float)id, Main.player[id].position.X, Main.player[id].position.Y, style);
return true;
}
if (!isNPC)
{
TShock.Players[id].Teleport(x, y, style);
}
}
return true;
}
} }
} }

View file

@ -31,9 +31,13 @@ namespace TShockAPI.Net
public short FrameY { get; set; } public short FrameY { get; set; }
public byte Wall { get; set; } public byte Wall { get; set; }
public byte Liquid { get; set; } public byte Liquid { get; set; }
public bool Lava { get; set; } public byte LiquidType { get; set; }
public bool Wire { get; set; } public bool Wire { get; set; }
public byte HalfBrick { get; set; }
public byte Actuator { get; set; }
public bool Inactive { get; set; }
public bool IsHalf { get; set; }
public bool IsActuator { get; set; }
public bool HasWall public bool HasWall
{ {
get { return Wall > 0; } get { return Wall > 0; }
@ -57,8 +61,10 @@ namespace TShockAPI.Net
FrameY = -1; FrameY = -1;
Wall = 0; Wall = 0;
Liquid = 0; Liquid = 0;
Lava = false;
Wire = false; Wire = false;
HalfBrick = 0;
Actuator = 0;
Inactive = false;
} }
public NetTile(Stream stream) public NetTile(Stream stream)
@ -71,7 +77,7 @@ namespace TShockAPI.Net
{ {
var flags = TileFlags.None; var flags = TileFlags.None;
if (Active) if ((Active) && (!Inactive))
flags |= TileFlags.Active; flags |= TileFlags.Active;
if (HasWall) if (HasWall)
@ -83,6 +89,17 @@ namespace TShockAPI.Net
if (Wire) if (Wire)
flags |= TileFlags.Wire; flags |= TileFlags.Wire;
if (IsHalf)
flags |= TileFlags.HalfBrick;
if (IsActuator)
flags |= TileFlags.Actuator;
if (Inactive)
{
flags |= TileFlags.Inactive;
}
stream.WriteInt8((byte) flags); stream.WriteInt8((byte) flags);
if (Active) if (Active)
@ -101,7 +118,7 @@ namespace TShockAPI.Net
if (HasLiquid) if (HasLiquid)
{ {
stream.WriteInt8(Liquid); stream.WriteInt8(Liquid);
stream.WriteBoolean(Lava); stream.WriteInt8(LiquidType);
} }
} }
@ -128,11 +145,23 @@ namespace TShockAPI.Net
if (flags.HasFlag(TileFlags.Liquid)) if (flags.HasFlag(TileFlags.Liquid))
{ {
Liquid = stream.ReadInt8(); Liquid = stream.ReadInt8();
Lava = stream.ReadBoolean(); LiquidType = stream.ReadInt8();
} }
if (flags.HasFlag(TileFlags.Wire)) if (flags.HasFlag(TileFlags.Wire))
Wire = true; Wire = true;
if (flags.HasFlag(TileFlags.HalfBrick))
IsHalf = true;
if (flags.HasFlag(TileFlags.Actuator))
IsActuator = true;
if (flags.HasFlag(TileFlags.Inactive))
{
Inactive = true;
Active = false;
}
} }
} }
@ -144,6 +173,9 @@ namespace TShockAPI.Net
Lighted = 2, Lighted = 2,
Wall = 4, Wall = 4,
Liquid = 8, Liquid = 8,
Wire = 16 Wire = 16,
HalfBrick = 32,
Actuator = 64,
Inactive = 128
} }
} }

View file

@ -25,7 +25,7 @@ namespace TShockAPI.Net
{ {
public override PacketTypes ID public override PacketTypes ID
{ {
get { return PacketTypes.ProjectileNew; } get{ return PacketTypes.ProjectileNew; }
} }
public short Index { get; set; } public short Index { get; set; }

View file

@ -24,7 +24,7 @@ using System.Text;
namespace TShockAPI.Net namespace TShockAPI.Net
{ {
[Flags] [Flags]
public enum WorldInfoFlag : byte public enum BossFlags : byte
{ {
None = 0, None = 0,
OrbSmashed = 1, OrbSmashed = 1,
@ -35,12 +35,25 @@ namespace TShockAPI.Net
DownedClown = 32 DownedClown = 32
} }
[Flags]
public enum BossFlags2 : byte
{
None = 0,
DownedMechBoss1 = 1,
DownedMechBoss2 = 2,
DownedMechBoss3 = 4,
DownedMechBossAny = 8,
CloudBg = 16,
Crimson = 32
}
public class WorldInfoMsg : BaseMsg public class WorldInfoMsg : BaseMsg
{ {
public int Time { get; set; } public int Time { get; set; }
public bool DayTime { get; set; } public bool DayTime { get; set; }
public byte MoonPhase { get; set; } public byte MoonPhase { get; set; }
public bool BloodMoon { get; set; } public bool BloodMoon { get; set; }
public bool Eclipse { get; set; }
public int MaxTilesX { get; set; } public int MaxTilesX { get; set; }
public int MaxTilesY { get; set; } public int MaxTilesY { get; set; }
public int SpawnX { get; set; } public int SpawnX { get; set; }
@ -48,7 +61,37 @@ namespace TShockAPI.Net
public int WorldSurface { get; set; } public int WorldSurface { get; set; }
public int RockLayer { get; set; } public int RockLayer { get; set; }
public int WorldID { get; set; } public int WorldID { get; set; }
public WorldInfoFlag WorldFlags { get; set; } public byte MoonType { get; set; }
public int TreeX0 { get; set; }
public int TreeX1 { get; set; }
public int TreeX2 { get; set; }
public byte TreeStyle0 { get; set; }
public byte TreeStyle1 { get; set; }
public byte TreeStyle2 { get; set; }
public byte TreeStyle3 { get; set; }
public int CaveBackX0 { get; set; }
public int CaveBackX1 { get; set; }
public int CaveBackX2 { get; set; }
public byte CaveBackStyle0 { get; set; }
public byte CaveBackStyle1 { get; set; }
public byte CaveBackStyle2 { get; set; }
public byte CaveBackStyle3 { get; set; }
public byte SetBG0 { get; set; }
public byte SetBG1 { get; set; }
public byte SetBG2 { get; set; }
public byte SetBG3 { get; set; }
public byte SetBG4 { get; set; }
public byte SetBG5 { get; set; }
public byte SetBG6 { get; set; }
public byte SetBG7 { get; set; }
public byte IceBackStyle { get; set; }
public byte JungleBackStyle { get; set; }
public byte HellBackStyle { get; set; }
public float WindSpeed { get; set; }
public byte NumberOfClouds { get; set; }
public BossFlags BossFlags { get; set; }
public BossFlags2 BossFlags2 { get; set; }
public float Rain { get; set; }
public string WorldName { get; set; } public string WorldName { get; set; }
public override PacketTypes ID public override PacketTypes ID
@ -62,6 +105,7 @@ namespace TShockAPI.Net
stream.WriteBoolean(DayTime); stream.WriteBoolean(DayTime);
stream.WriteInt8(MoonPhase); stream.WriteInt8(MoonPhase);
stream.WriteBoolean(BloodMoon); stream.WriteBoolean(BloodMoon);
stream.WriteBoolean(Eclipse);
stream.WriteInt32(MaxTilesX); stream.WriteInt32(MaxTilesX);
stream.WriteInt32(MaxTilesY); stream.WriteInt32(MaxTilesY);
stream.WriteInt32(SpawnX); stream.WriteInt32(SpawnX);
@ -69,7 +113,37 @@ namespace TShockAPI.Net
stream.WriteInt32(WorldSurface); stream.WriteInt32(WorldSurface);
stream.WriteInt32(RockLayer); stream.WriteInt32(RockLayer);
stream.WriteInt32(WorldID); stream.WriteInt32(WorldID);
stream.WriteInt8((byte) WorldFlags); stream.WriteByte(MoonType);
stream.WriteInt32(TreeX0);
stream.WriteInt32(TreeX1);
stream.WriteInt32(TreeX2);
stream.WriteByte(TreeStyle0);
stream.WriteByte(TreeStyle1);
stream.WriteByte(TreeStyle2);
stream.WriteByte(TreeStyle3);
stream.WriteInt32(CaveBackX0);
stream.WriteInt32(CaveBackX1);
stream.WriteInt32(CaveBackX2);
stream.WriteByte(CaveBackStyle0);
stream.WriteByte(CaveBackStyle1);
stream.WriteByte(CaveBackStyle2);
stream.WriteByte(CaveBackStyle3);
stream.WriteByte(SetBG0);
stream.WriteByte(SetBG1);
stream.WriteByte(SetBG2);
stream.WriteByte(SetBG3);
stream.WriteByte(SetBG4);
stream.WriteByte(SetBG5);
stream.WriteByte(SetBG6);
stream.WriteByte(SetBG7);
stream.WriteByte(IceBackStyle);
stream.WriteByte(JungleBackStyle);
stream.WriteByte(HellBackStyle);
stream.WriteSingle(WindSpeed);
stream.WriteByte(NumberOfClouds);
stream.WriteInt8((byte) BossFlags);
stream.WriteInt8((byte)BossFlags2);
stream.WriteSingle(Rain);
stream.WriteBytes(Encoding.UTF8.GetBytes(WorldName)); stream.WriteBytes(Encoding.UTF8.GetBytes(WorldName));
} }
} }

View file

@ -22,8 +22,8 @@ using System.ComponentModel;
using System.IO; using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using Hooks;
using Terraria; using Terraria;
using TerrariaApi.Server;
namespace TShockAPI namespace TShockAPI
{ {
@ -34,6 +34,8 @@ namespace TShockAPI
/// </summary> /// </summary>
public int BytesPerUpdate { get; set; } public int BytesPerUpdate { get; set; }
private readonly TShock plugin;
private PacketBuffer[] buffers = new PacketBuffer[Netplay.serverSock.Length]; private PacketBuffer[] buffers = new PacketBuffer[Netplay.serverSock.Length];
private int[] Bytes = new int[52]; private int[] Bytes = new int[52];
@ -45,8 +47,9 @@ namespace TShockAPI
Command flush; Command flush;
#endif #endif
public PacketBufferer() public PacketBufferer(TShock p)
{ {
plugin = p;
BytesPerUpdate = 0xFFFF; BytesPerUpdate = 0xFFFF;
for (int i = 0; i < buffers.Length; i++) for (int i = 0; i < buffers.Length; i++)
buffers[i] = new PacketBuffer(); buffers[i] = new PacketBuffer();
@ -58,9 +61,9 @@ namespace TShockAPI
Commands.ChatCommands.Add(flush); Commands.ChatCommands.Add(flush);
#endif #endif
NetHooks.SendBytes += ServerHooks_SendBytes; ServerApi.Hooks.NetSendBytes.Register(plugin, ServerHooks_SendBytes);
ServerHooks.SocketReset += ServerHooks_SocketReset; ServerApi.Hooks.ServerSocketReset.Register(plugin, ServerHooks_SocketReset);
GameHooks.PostUpdate += GameHooks_Update; ServerApi.Hooks.GamePostUpdate.Register(plugin, GameHooks_Update);
} }
~PacketBufferer() ~PacketBufferer()
@ -82,9 +85,9 @@ namespace TShockAPI
Commands.ChatCommands.Remove(dump); Commands.ChatCommands.Remove(dump);
Commands.ChatCommands.Remove(flush); Commands.ChatCommands.Remove(flush);
#endif #endif
NetHooks.SendBytes -= ServerHooks_SendBytes; ServerApi.Hooks.NetSendBytes.Deregister(plugin, ServerHooks_SendBytes);
ServerHooks.SocketReset -= ServerHooks_SocketReset; ServerApi.Hooks.ServerSocketReset.Deregister(plugin, ServerHooks_SocketReset);
GameHooks.PostUpdate -= GameHooks_Update; ServerApi.Hooks.GamePostUpdate.Deregister(plugin, GameHooks_Update);
} }
} }
@ -107,7 +110,7 @@ namespace TShockAPI
Compressed = new int[52]; Compressed = new int[52];
} }
private void GameHooks_Update() private void GameHooks_Update(EventArgs args)
{ {
FlushAll(); FlushAll();
} }
@ -148,9 +151,9 @@ namespace TShockAPI
} }
private void ServerHooks_SocketReset(ServerSock socket) private void ServerHooks_SocketReset(SocketResetEventArgs args)
{ {
buffers[socket.whoAmI] = new PacketBuffer(); buffers[args.Socket.whoAmI] = new PacketBuffer();
} }
public bool SendBytes(ServerSock socket, byte[] buffer) public bool SendBytes(ServerSock socket, byte[] buffer)
@ -217,10 +220,10 @@ namespace TShockAPI
return false; return false;
} }
private void ServerHooks_SendBytes(ServerSock socket, byte[] buffer, int offset, int count, HandledEventArgs e) private void ServerHooks_SendBytes(SendBytesEventArgs args)
{ {
e.Handled = true; args.Handled = true;
BufferBytes(socket, buffer, offset, count); BufferBytes(args.Socket, args.Buffer, args.Offset, args.Count);
} }
#if DEBUG_NET #if DEBUG_NET

View file

@ -248,6 +248,9 @@ namespace TShockAPI
[Description("User can modify the world.")] [Description("User can modify the world.")]
public static readonly string canbuild = "tshock.world.modify"; public static readonly string canbuild = "tshock.world.modify";
[Description("User can paint tiles.")]
public static readonly string canpaint = "tshock.world.paint";
// Non-grouped // Non-grouped
[Description("User can kill others.")] [Description("User can kill others.")]
@ -280,6 +283,9 @@ namespace TShockAPI
[Description("User can get the server info.")] [Description("User can get the server info.")]
public static readonly string serverinfo = "tshock.info"; public static readonly string serverinfo = "tshock.info";
[Description("Player recovers health as damage is taken. Can be one shotted.")]
public static readonly string godmode = "tshock.godmode";
/// <summary> /// <summary>
/// Lists all commands associated with a given permission /// Lists all commands associated with a given permission
/// </summary> /// </summary>

View file

@ -1,87 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.IO;
using System.Threading;
using Terraria;
namespace TShockAPI.PluginUpdater
{
class PluginUpdaterThread
{
private TSPlayer invoker;
public PluginUpdaterThread(TSPlayer player)
{
invoker = player;
PluginVersionCheck.PluginUpdate += PluginUpdate;
HandleUpdate();
}
private void HandleUpdate()
{
foreach(PluginContainer cont in ProgramServer.Plugins)
new Thread(PluginVersionCheck.CheckPlugin).Start(cont.Plugin);
}
private int Updates = 0;
private void PluginUpdate(UpdateArgs args)
{
Updates++;
if(args.Success && String.IsNullOrEmpty(args.Error))
{
invoker.SendSuccessMessage(String.Format("{0} was downloaded successfully.", args.Plugin.Name));
}
else if(args.Success)
{
invoker.SendSuccessMessage(String.Format("{0} was skipped. Reason: {1}", args.Plugin.Name, args.Error));
}
else
{
invoker.SendSuccessMessage(String.Format("{0} failed to downloaded. Error: {1}", args.Plugin.Name, args.Error));
}
if(Updates >= Terraria.ProgramServer.Plugins.Count)
{
PluginVersionCheck.PluginUpdate -= PluginUpdate;
invoker.SendSuccessMessage("All plugins have been downloaded. Now copying them to the plugin folder...");
string folder = Path.Combine(TShock.SavePath, "UpdatedPlugins");
string dest = Path.Combine(TShock.SavePath, "..", "ServerPlugins");
foreach (string dir in Directory.GetDirectories(folder, "*", System.IO.SearchOption.AllDirectories))
{
string new_folder = dest + dir.Substring(folder.Length);
if (!Directory.Exists(new_folder))
Directory.CreateDirectory(new_folder);
}
foreach (string file_name in Directory.GetFiles(folder, "*.*", System.IO.SearchOption.AllDirectories))
{
TSPlayer.Server.SendSuccessMessage(String.Format("Copied {0}", file_name));
File.Copy(file_name, dest + file_name.Substring(folder.Length), true);
}
Directory.Delete(folder, true);
invoker.SendSuccessMessage("All plugins have been processed. Restart the server to have access to the new plugins.");
}
}
}
}

View file

@ -1,127 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using JsonLoader;
using Newtonsoft.Json;
namespace TShockAPI.PluginUpdater
{
public class PluginVersionCheck
{
public delegate void PluginUpdateD(UpdateArgs e);
public static event PluginUpdateD PluginUpdate;
public static void OnPluginUpdate(UpdateArgs args)
{
if (PluginUpdate == null)
{
return;
}
PluginUpdate(args);
}
public static void CheckPlugin(object p)
{
TerrariaPlugin plugin = (TerrariaPlugin)p;
UpdateArgs args = new UpdateArgs {Plugin = plugin, Success = true, Error = ""};
List<string> files = new List<string>();
try
{
if (!String.IsNullOrEmpty(plugin.UpdateURL))
{
var request = HttpWebRequest.Create(plugin.UpdateURL);
VersionInfo vi;
request.Timeout = 5000;
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
vi = JsonConvert.DeserializeObject<VersionInfo>(reader.ReadToEnd());
}
}
System.Version v = System.Version.Parse((vi.version.ToString()));
if (!v.Equals(plugin.Version))
{
DownloadPackage pkg;
request = HttpWebRequest.Create(vi.url);
request.Timeout = 5000;
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
pkg = JsonConvert.DeserializeObject<DownloadPackage>(reader.ReadToEnd());
}
}
foreach (PluginFile f in pkg.files)
{
using (WebClient Client = new WebClient())
{
string dir = Path.Combine(TShock.SavePath, "UpdatedPlugins");
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
Client.DownloadFile(f.url,
Path.Combine(dir, f.destination));
files.Add(Path.Combine(dir, f.destination));
}
}
}
else
{
args.Error = "Plugin is up to date.";
}
}
else
{
args.Error = "Plugin has no updater recorded.";
}
}
catch(Exception e)
{
args.Success = false;
args.Error = e.Message;
if(files.Count > 0)
{
foreach(string s in files)
{
File.Delete(s);
}
}
}
OnPluginUpdate(args);
}
}
public class UpdateArgs
{
public TerrariaPlugin Plugin { get; set; }
public bool Success { get; set; }
public string Error { get; set; }
}
}

View file

@ -1,87 +0,0 @@
/*
TShock, a server mod for Terraria
Copyright (C) 2011-2013 Nyx Studios (fka. The TShock Team)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
namespace JsonLoader
{
class VersionInfo
{
public Version version;
public string url;
}
public class Version
{
public int Major;
public int Minor;
public int Build;
public int Revision;
public int MajorRevision;
public int MinorRevision;
public Version()
{
SetVersion(0,0,0,0);
}
public Version(int m)
{
SetVersion(m, 0, 0, 0);
}
public Version(int ma, int mi)
{
SetVersion(ma, mi, 0, 0);
}
public Version(int ma, int mi, int b)
{
SetVersion(ma, mi, b, 0);
}
public Version(int ma, int mi, int b, int r)
{
SetVersion(ma, mi, b, r);
}
private void SetVersion(int ma, int mi, int b, int r)
{
Major = ma;
Minor = mi;
Build = b;
Revision = r;
}
public string ToString()
{
return String.Format("{0}.{1}.{2}.{3}", Major, Minor, Build, Revision);
}
}
class DownloadPackage
{
public List<PluginFile> files;
}
class PluginFile
{
public string url;
public string destination = "";
}
}

View file

@ -307,7 +307,7 @@ namespace TShockAPI
return RestMissingParam("password"); return RestMissingParam("password");
// NOTE: ip can be blank // NOTE: ip can be blank
User user = new User(username, password, group, "", ""); User user = new User(username, password, group, "", "", "");
try try
{ {
TShock.Users.AddUser(user); TShock.Users.AddUser(user);

View file

@ -20,6 +20,7 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Threading; using System.Threading;
using Terraria; using Terraria;
using TerrariaApi.Server;
namespace TShockAPI namespace TShockAPI
{ {
@ -45,7 +46,7 @@ namespace TShockAPI
/// <summary> /// <summary>
/// SaveWorld event handler which notifies users that the server may lag /// SaveWorld event handler which notifies users that the server may lag
/// </summary> /// </summary>
public void OnSaveWorld(bool resettime = false, HandledEventArgs e = null) public void OnSaveWorld(WorldSaveEventArgs args)
{ {
// Protect against internal errors causing save failures // Protect against internal errors causing save failures
// These can be caused by an unexpected error such as a bad or out of date plugin // These can be caused by an unexpected error such as a bad or out of date plugin
@ -120,7 +121,7 @@ namespace TShockAPI
{ {
if (task.direct) if (task.direct)
{ {
OnSaveWorld(); OnSaveWorld(new WorldSaveEventArgs());
WorldGen.realsaveWorld(task.resetTime); WorldGen.realsaveWorld(task.resetTime);
} }
else else

View file

@ -58,15 +58,20 @@ namespace TShockAPI
/// </summary> /// </summary>
public int ProjectileThreshold { get; set; } public int ProjectileThreshold { get; set; }
/// <summary>
/// A timer to keep track of whether or not the player has recently thrown an explosive
// </summary>
public int RecentFuse = 0;
/// <summary> /// <summary>
/// A queue of tiles destroyed by the player for reverting. /// A queue of tiles destroyed by the player for reverting.
/// </summary> /// </summary>
public Dictionary<Vector2, TileData> TilesDestroyed { get; protected set; } public Dictionary<Vector2, Tile> TilesDestroyed { get; protected set; }
/// <summary> /// <summary>
/// A queue of tiles placed by the player for reverting. /// A queue of tiles placed by the player for reverting.
/// </summary> /// </summary>
public Dictionary<Vector2, TileData> TilesCreated { get; protected set; } public Dictionary<Vector2, Tile> TilesCreated { get; protected set; }
public int FirstMaxHP { get; set; } public int FirstMaxHP { get; set; }
@ -390,7 +395,7 @@ namespace TShockAPI
bool flag = false; bool flag = false;
if (RealPlayer) if (RealPlayer)
{ {
for (int i = 0; i < 40; i++) //41 is trash can, 42-45 is coins, 46-49 is ammo for (int i = 0; i < 50; i++) //51 is trash can, 52-55 is coins, 56-59 is ammo
{ {
if (TPlayer.inventory[i] == null || !TPlayer.inventory[i].active || TPlayer.inventory[i].name == "") if (TPlayer.inventory[i] == null || !TPlayer.inventory[i].active || TPlayer.inventory[i].name == "")
{ {
@ -405,8 +410,8 @@ namespace TShockAPI
public TSPlayer(int index) public TSPlayer(int index)
{ {
TilesDestroyed = new Dictionary<Vector2, TileData>(); TilesDestroyed = new Dictionary<Vector2, Tile>();
TilesCreated = new Dictionary<Vector2, TileData>(); TilesCreated = new Dictionary<Vector2, Tile>();
Index = index; Index = index;
Group = Group.DefaultGroup; Group = Group.DefaultGroup;
IceTiles = new List<Point>(); IceTiles = new List<Point>();
@ -415,8 +420,8 @@ namespace TShockAPI
protected TSPlayer(String playerName) protected TSPlayer(String playerName)
{ {
TilesDestroyed = new Dictionary<Vector2, TileData>(); TilesDestroyed = new Dictionary<Vector2, Tile>();
TilesCreated = new Dictionary<Vector2, TileData>(); TilesCreated = new Dictionary<Vector2, Tile>();
Index = -1; Index = -1;
FakePlayer = new Player {name = playerName, whoAmi = -1}; FakePlayer = new Player {name = playerName, whoAmi = -1};
Group = Group.DefaultGroup; Group = Group.DefaultGroup;
@ -457,12 +462,47 @@ namespace TShockAPI
//Sending a fake world id causes the client to not be able to find a stored spawnx/y. //Sending a fake world id causes the client to not be able to find a stored spawnx/y.
//This fixes the bed spawn point bug. With a fake world id it wont be able to find the bed spawn. //This fixes the bed spawn point bug. With a fake world id it wont be able to find the bed spawn.
WorldID = !fakeid ? Main.worldID : -1, WorldID = !fakeid ? Main.worldID : -1,
WorldFlags = (WorldGen.shadowOrbSmashed ? WorldInfoFlag.OrbSmashed : WorldInfoFlag.None) | MoonType = (byte)Main.moonType,
(NPC.downedBoss1 ? WorldInfoFlag.DownedBoss1 : WorldInfoFlag.None) | TreeX0 = Main.treeX[0],
(NPC.downedBoss2 ? WorldInfoFlag.DownedBoss2 : WorldInfoFlag.None) | TreeX1 = Main.treeX[1],
(NPC.downedBoss3 ? WorldInfoFlag.DownedBoss3 : WorldInfoFlag.None) | TreeX2 = Main.treeX[2],
(Main.hardMode ? WorldInfoFlag.HardMode : WorldInfoFlag.None) | TreeStyle0 = (byte)Main.treeStyle[0],
(NPC.downedClown ? WorldInfoFlag.DownedClown : WorldInfoFlag.None), TreeStyle1 = (byte)Main.treeStyle[1],
TreeStyle2 = (byte)Main.treeStyle[2],
TreeStyle3 = (byte)Main.treeStyle[3],
CaveBackX0 = Main.caveBackX[0],
CaveBackX1 = Main.caveBackX[1],
CaveBackX2 = Main.caveBackX[2],
CaveBackStyle0 = (byte)Main.caveBackStyle[0],
CaveBackStyle1 = (byte)Main.caveBackStyle[1],
CaveBackStyle2 = (byte)Main.caveBackStyle[2],
CaveBackStyle3 = (byte)Main.caveBackStyle[3],
SetBG0 = (byte)WorldGen.treeBG,
SetBG1 = (byte)WorldGen.corruptBG,
SetBG2 = (byte)WorldGen.jungleBG,
SetBG3 = (byte)WorldGen.snowBG,
SetBG4 = (byte)WorldGen.hallowBG,
SetBG5 = (byte)WorldGen.crimsonBG,
SetBG6 = (byte)WorldGen.desertBG,
SetBG7 = (byte)WorldGen.oceanBG,
IceBackStyle = (byte)Main.iceBackStyle,
JungleBackStyle = (byte)Main.jungleBackStyle,
HellBackStyle = (byte)Main.hellBackStyle,
WindSpeed = Main.windSpeed,
NumberOfClouds = (byte)Main.numClouds,
BossFlags = (WorldGen.shadowOrbSmashed ? BossFlags.OrbSmashed : BossFlags.None) |
(NPC.downedBoss1 ? BossFlags.DownedBoss1 : BossFlags.None) |
(NPC.downedBoss2 ? BossFlags.DownedBoss2 : BossFlags.None) |
(NPC.downedBoss3 ? BossFlags.DownedBoss3 : BossFlags.None) |
(Main.hardMode ? BossFlags.HardMode : BossFlags.None) |
(NPC.downedClown ? BossFlags.DownedClown : BossFlags.None),
BossFlags2 = (NPC.downedMechBoss1 ? BossFlags2.DownedMechBoss1 : BossFlags2.None) |
(NPC.downedMechBoss2 ? BossFlags2.DownedMechBoss2 : BossFlags2.None) |
(NPC.downedMechBoss3 ? BossFlags2.DownedMechBoss3 : BossFlags2.None) |
(NPC.downedMechBossAny ? BossFlags2.DownedMechBossAny : BossFlags2.None) |
(Main.cloudBGActive == 1f ? BossFlags2.CloudBg : BossFlags2.None) |
(WorldGen.crimson ? BossFlags2.Crimson : BossFlags2.None),
Rain = Main.maxRaining,
WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
}; };
msg.PackFull(ms); msg.PackFull(ms);
@ -470,41 +510,35 @@ namespace TShockAPI
} }
} }
public bool Teleport(int tilex, int tiley) public bool Teleport(float x, float y, byte style = 1)
{ {
InitSpawn = false; if (x > Main.rightWorld - 992)
SendWorldInfo(tilex, tiley, true);
//150 Should avoid all client crash errors
//The error occurs when a tile trys to update which the client hasnt load yet, Clients only update tiles withen 150 blocks
//Try 300 if it does not work (Higher number - Longer load times - Less chance of error)
//Should we properly send sections so that clients don't get tiles twice?
SendTileSquare(tilex, tiley, 150);
/* //We shouldn't need this section anymore -it can prevent otherwise acceptable teleportation under some circumstances.
if (!SendTileSquare(tilex, tiley, 150))
{ {
InitSpawn = true; x = Main.rightWorld - 992;
SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false); }
return false; if (x < 992)
{
x = 992;
}
if (y > Main.bottomWorld - 992)
{
y = Main.bottomWorld - 992;
}
if (y < 992)
{
y = 992;
} }
*/ TPlayer.Teleport(new Vector2(x, y), style);
Spawn(-1, -1); NetMessage.SendData((int)PacketTypes.Teleport, -1, -1, "", 0, TPlayer.whoAmi, x, y, style);
SendWorldInfo(Main.spawnTileX, Main.spawnTileY, false);
TPlayer.position.X = (float)(tilex * 16 + 8 - TPlayer.width /2);
TPlayer.position.Y = (float)(tiley * 16 - TPlayer.height);
//We need to send the tile data again to prevent clients from thinking they *really* destroyed blocks just now.
SendTileSquare(tilex, tiley, 10);
return true; return true;
} }
public void Heal(int damage = 400)
{
NetMessage.SendData((int)PacketTypes.PlayerHealOther, -1, -1, "", this.TPlayer.whoAmi, damage);
}
public void Spawn() public void Spawn()
{ {
Spawn(TPlayer.SpawnX, TPlayer.SpawnY); Spawn(TPlayer.SpawnX, TPlayer.SpawnY);
@ -594,7 +628,7 @@ namespace TShockAPI
public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0) public virtual void GiveItem(int type, string name, int width, int height, int stack, int prefix = 0)
{ {
int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix); int itemid = Item.NewItem((int) X, (int) Y, width, height, type, stack, true, prefix, true);
// This is for special pickaxe/hammers/swords etc // This is for special pickaxe/hammers/swords etc
Main.item[itemid].SetDefaults(name); Main.item[itemid].SetDefaults(name);
@ -604,8 +638,10 @@ namespace TShockAPI
Main.item[itemid].stack = stack; Main.item[itemid].stack = stack;
Main.item[itemid].owner = Index; Main.item[itemid].owner = Index;
Main.item[itemid].prefix = (byte) prefix; Main.item[itemid].prefix = (byte) prefix;
NetMessage.SendData((int) PacketTypes.ItemDrop, -1, -1, "", itemid, 0f, 0f, 0f); Main.item[itemid].noGrabDelay = 1;
NetMessage.SendData((int) PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f); Main.item[itemid].velocity = Main.player[this.Index].velocity;
NetMessage.SendData((int)PacketTypes.ItemDrop, -1, -1, "", itemid, 0f, 0f, 0f);
NetMessage.SendData((int)PacketTypes.ItemOwner, -1, -1, "", itemid, 0f, 0f, 0f);
} }
public virtual void SendInfoMessage(string msg) public virtual void SendInfoMessage(string msg)
@ -877,6 +913,12 @@ namespace TShockAPI
SetTime(false, 0); SetTime(false, 0);
} }
public void SetEclipse(bool Eclipse)
{
Main.eclipse = Eclipse;
SetTime(true, 150);
}
public void SetTime(bool dayTime, double time) public void SetTime(bool dayTime, double time)
{ {
Main.dayTime = dayTime; Main.dayTime = dayTime;
@ -910,12 +952,12 @@ namespace TShockAPI
NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection); NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection);
} }
public void RevertTiles(Dictionary<Vector2, TileData> tiles) public void RevertTiles(Dictionary<Vector2, Tile> tiles)
{ {
// Update Main.Tile first so that when tile sqaure is sent it is correct // Update Main.Tile first so that when tile sqaure is sent it is correct
foreach (KeyValuePair<Vector2, TileData> entry in tiles) foreach (KeyValuePair<Vector2, Tile> entry in tiles)
{ {
Main.tile[(int) entry.Key.X, (int) entry.Key.Y].Data = entry.Value; Main.tile[(int) entry.Key.X, (int) entry.Key.Y] = entry.Value;
} }
// Send all players updated tile sqaures // Send all players updated tile sqaures
foreach (Vector2 coords in tiles.Keys) foreach (Vector2 coords in tiles.Keys)
@ -977,9 +1019,10 @@ namespace TShockAPI
this.maxHealth = player.TPlayer.statLifeMax; this.maxHealth = player.TPlayer.statLifeMax;
Item[] inventory = player.TPlayer.inventory; Item[] inventory = player.TPlayer.inventory;
Item[] armor = player.TPlayer.armor; Item[] armor = player.TPlayer.armor;
Item[] dye = player.TPlayer.dye;
for (int i = 0; i < NetItem.maxNetInventory; i++) for (int i = 0; i < NetItem.maxNetInventory; i++)
{ {
if (i < 49) if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
{ {
if (player.TPlayer.inventory[i] != null) if (player.TPlayer.inventory[i] != null)
{ {
@ -1001,11 +1044,12 @@ namespace TShockAPI
this.inventory[i].prefix = 0; this.inventory[i].prefix = 0;
} }
} }
else else if (i < NetItem.maxNetInventory - NetItem.dyeSlots)
{ {
if (player.TPlayer.armor[i - 48] != null) var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
if (player.TPlayer.armor[index] != null)
{ {
this.inventory[i].netID = armor[i - 48].netID; this.inventory[i].netID = armor[index].netID;
} }
else else
{ {
@ -1014,8 +1058,31 @@ namespace TShockAPI
if (this.inventory[i].netID != 0) if (this.inventory[i].netID != 0)
{ {
this.inventory[i].stack = armor[i - 48].stack; this.inventory[i].stack = armor[index].stack;
this.inventory[i].prefix = armor[i - 48].prefix; this.inventory[i].prefix = armor[index].prefix;
}
else
{
this.inventory[i].stack = 0;
this.inventory[i].prefix = 0;
}
}
else
{
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
if (player.TPlayer.dye[index] != null)
{
this.inventory[i].netID = armor[index].netID;
}
else
{
this.inventory[i].netID = 0;
}
if (this.inventory[i].netID != 0)
{
this.inventory[i].stack = armor[index].stack;
this.inventory[i].prefix = armor[index].prefix;
} }
else else
{ {
@ -1029,7 +1096,9 @@ namespace TShockAPI
public class NetItem public class NetItem
{ {
public static int maxNetInventory = 59; public static readonly int maxNetInventory = 73;
public static readonly int armorSlots = 11;
public static readonly int dyeSlots = 3;
public int netID; public int netID;
public int stack; public int stack;
public int prefix; public int prefix;

View file

@ -27,19 +27,19 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using Hooks;
using MaxMind; using MaxMind;
using Mono.Data.Sqlite; using Mono.Data.Sqlite;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using Newtonsoft.Json; using Newtonsoft.Json;
using Rests; using Rests;
using Terraria; using Terraria;
using TerrariaApi.Server;
using TShockAPI.DB; using TShockAPI.DB;
using TShockAPI.Net; using TShockAPI.Net;
namespace TShockAPI namespace TShockAPI
{ {
[APIVersion(1, 13)] [ApiVersion(1, 14)]
public class TShock : TerrariaPlugin public class TShock : TerrariaPlugin
{ {
public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version; public static readonly Version VersionNum = Assembly.GetExecutingAssembly().GetName().Version;
@ -231,25 +231,25 @@ namespace TShockAPI
Log.ConsoleInfo(string.Format("|> Version {0} ({1}) now running.", Version, VersionCodename)); Log.ConsoleInfo(string.Format("|> Version {0} ({1}) now running.", Version, VersionCodename));
GameHooks.PostInitialize += OnPostInit; ServerApi.Hooks.GamePostInitialize.Register(this, OnPostInit);
GameHooks.Update += OnUpdate; ServerApi.Hooks.GameUpdate.Register(this, OnUpdate);
GameHooks.HardUpdate += OnHardUpdate; ServerApi.Hooks.GameHardmodeTileUpdate.Register(this, OnHardUpdate);
GameHooks.StatueSpawn += OnStatueSpawn; ServerApi.Hooks.GameStatueSpawn.Register(this, OnStatueSpawn);
ServerHooks.Connect += OnConnect; ServerApi.Hooks.ServerConnect.Register(this, OnConnect);
ServerHooks.Join += OnJoin; ServerApi.Hooks.ServerJoin.Register(this, OnJoin);
ServerHooks.Leave += OnLeave; ServerApi.Hooks.ServerLeave.Register(this, OnLeave);
ServerHooks.Chat += OnChat; ServerApi.Hooks.ServerChat.Register(this, OnChat);
ServerHooks.Command += ServerHooks_OnCommand; ServerApi.Hooks.ServerCommand.Register(this, ServerHooks_OnCommand);
NetHooks.GetData += OnGetData; ServerApi.Hooks.NetGetData.Register(this, OnGetData);
NetHooks.SendData += NetHooks_SendData; ServerApi.Hooks.NetSendData.Register(this, NetHooks_SendData);
NetHooks.GreetPlayer += OnGreetPlayer; ServerApi.Hooks.NetGreetPlayer.Register(this, OnGreetPlayer);
NpcHooks.StrikeNpc += NpcHooks_OnStrikeNpc; ServerApi.Hooks.NpcStrike.Register(this, NpcHooks_OnStrikeNpc);
NpcHooks.SetDefaultsInt += OnNpcSetDefaults; ServerApi.Hooks.NpcSetDefaultsInt.Register(this, OnNpcSetDefaults);
ProjectileHooks.SetDefaults += OnProjectileSetDefaults; ServerApi.Hooks.ProjectileSetDefaults.Register(this, OnProjectileSetDefaults);
WorldHooks.StartHardMode += OnStartHardMode; ServerApi.Hooks.WorldStartHardMode.Register(this, OnStartHardMode);
WorldHooks.SaveWorld += SaveManager.Instance.OnSaveWorld; ServerApi.Hooks.WorldSave.Register(this, SaveManager.Instance.OnSaveWorld);
WorldHooks.ChristmasCheck += OnXmasCheck; ServerApi.Hooks.WorldChristmasCheck.Register(this, OnXmasCheck);
NetHooks.NameCollision += NetHooks_NameCollision; ServerApi.Hooks.NetNameCollision.Register(this, NetHooks_NameCollision);
TShockAPI.Hooks.PlayerHooks.PlayerPostLogin += OnPlayerLogin; TShockAPI.Hooks.PlayerHooks.PlayerPostLogin += OnPlayerLogin;
GetDataHandlers.InitGetDataHandler(); GetDataHandlers.InitGetDataHandler();
@ -260,7 +260,7 @@ namespace TShockAPI
RestApi.Start(); RestApi.Start();
if (Config.BufferPackets) if (Config.BufferPackets)
PacketBuffer = new PacketBufferer(); PacketBuffer = new PacketBufferer(this);
Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled")); Log.ConsoleInfo("Backups " + (Backups.Interval > 0 ? "Enabled" : "Disabled"));
@ -306,25 +306,26 @@ namespace TShockAPI
} }
SaveManager.Instance.Dispose(); SaveManager.Instance.Dispose();
GameHooks.PostInitialize -= OnPostInit;
GameHooks.Update -= OnUpdate; ServerApi.Hooks.GamePostInitialize.Deregister(this, OnPostInit);
GameHooks.HardUpdate -= OnHardUpdate; ServerApi.Hooks.GameUpdate.Deregister(this, OnUpdate);
GameHooks.StatueSpawn -= OnStatueSpawn; ServerApi.Hooks.GameHardmodeTileUpdate.Deregister(this, OnHardUpdate);
ServerHooks.Connect -= OnConnect; ServerApi.Hooks.GameStatueSpawn.Deregister(this, OnStatueSpawn);
ServerHooks.Join -= OnJoin; ServerApi.Hooks.ServerConnect.Deregister(this, OnConnect);
ServerHooks.Leave -= OnLeave; ServerApi.Hooks.ServerJoin.Deregister(this, OnJoin);
ServerHooks.Chat -= OnChat; ServerApi.Hooks.ServerLeave.Deregister(this, OnLeave);
ServerHooks.Command -= ServerHooks_OnCommand; ServerApi.Hooks.ServerChat.Deregister(this, OnChat);
NetHooks.GetData -= OnGetData; ServerApi.Hooks.ServerCommand.Deregister(this, ServerHooks_OnCommand);
NetHooks.SendData -= NetHooks_SendData; ServerApi.Hooks.NetGetData.Deregister(this, OnGetData);
NetHooks.GreetPlayer -= OnGreetPlayer; ServerApi.Hooks.NetSendData.Deregister(this, NetHooks_SendData);
NpcHooks.StrikeNpc -= NpcHooks_OnStrikeNpc; ServerApi.Hooks.NetGreetPlayer.Deregister(this, OnGreetPlayer);
NpcHooks.SetDefaultsInt -= OnNpcSetDefaults; ServerApi.Hooks.NpcStrike.Deregister(this, NpcHooks_OnStrikeNpc);
ProjectileHooks.SetDefaults -= OnProjectileSetDefaults; ServerApi.Hooks.NpcSetDefaultsInt.Deregister(this, OnNpcSetDefaults);
WorldHooks.StartHardMode -= OnStartHardMode; ServerApi.Hooks.ProjectileSetDefaults.Deregister(this, OnProjectileSetDefaults);
WorldHooks.SaveWorld -= SaveManager.Instance.OnSaveWorld; ServerApi.Hooks.WorldStartHardMode.Deregister(this, OnStartHardMode);
WorldHooks.ChristmasCheck -= OnXmasCheck; ServerApi.Hooks.WorldSave.Deregister(this, SaveManager.Instance.OnSaveWorld);
NetHooks.NameCollision -= NetHooks_NameCollision; ServerApi.Hooks.WorldChristmasCheck.Deregister(this, OnXmasCheck);
ServerApi.Hooks.NetNameCollision.Deregister(this, NetHooks_NameCollision);
TShockAPI.Hooks.PlayerHooks.PlayerPostLogin -= OnPlayerLogin; TShockAPI.Hooks.PlayerHooks.PlayerPostLogin -= OnPlayerLogin;
if (File.Exists(Path.Combine(SavePath, "tshock.pid"))) if (File.Exists(Path.Combine(SavePath, "tshock.pid")))
@ -362,34 +363,34 @@ namespace TShockAPI
Users.UpdateLogin(u); Users.UpdateLogin(u);
} }
private void NetHooks_NameCollision(int who, string name, HandledEventArgs e) private void NetHooks_NameCollision(NameCollisionEventArgs args)
{ {
string ip = TShock.Utils.GetRealIP(Netplay.serverSock[who].tcpClient.Client.RemoteEndPoint.ToString()); string ip = TShock.Utils.GetRealIP(Netplay.serverSock[args.Who].tcpClient.Client.RemoteEndPoint.ToString());
foreach (TSPlayer ply in TShock.Players) foreach (TSPlayer ply in TShock.Players)
{ {
if (ply == null) if (ply == null)
{ {
continue; continue;
} }
if (ply.Name == name && ply.Index != who) if (ply.Name == args.Name && ply.Index != args.Who)
{ {
if (ply.IP == ip) if (ply.IP == ip)
{ {
if (ply.State < 2) if (ply.State < 2)
{ {
Utils.ForceKick(ply, "Name collision and this client has no world data.", true, false); Utils.ForceKick(ply, "Name collision and this client has no world data.", true, false);
e.Handled = true; args.Handled = true;
return; return;
} }
else else
{ {
e.Handled = false; args.Handled = false;
return; return;
} }
} }
} }
} }
e.Handled = false; args.Handled = false;
return; return;
} }
@ -533,7 +534,7 @@ namespace TShockAPI
public static int AuthToken = -1; public static int AuthToken = -1;
private void OnPostInit() private void OnPostInit(EventArgs args)
{ {
SetConsoleTitle(); SetConsoleTitle();
if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt"))) if (!File.Exists(Path.Combine(SavePath, "auth.lck")) && !File.Exists(Path.Combine(SavePath, "authcode.txt")))
@ -597,7 +598,7 @@ namespace TShockAPI
private DateTime LastCheck = DateTime.UtcNow; private DateTime LastCheck = DateTime.UtcNow;
private DateTime LastSave = DateTime.UtcNow; private DateTime LastSave = DateTime.UtcNow;
private void OnUpdate() private void OnUpdate(EventArgs args)
{ {
UpdateManager.UpdateProcedureCheck(); UpdateManager.UpdateProcedureCheck();
if (Backups.IsBackupTime) if (Backups.IsBackupTime)
@ -638,12 +639,11 @@ namespace TShockAPI
break; break;
} }
} }
int count = 0;
foreach (TSPlayer player in Players) foreach (TSPlayer player in Players)
{ {
if (player != null && player.Active) if (player != null && player.Active)
{ {
count++;
if (player.TilesDestroyed != null) if (player.TilesDestroyed != null)
{ {
if (player.TileKillThreshold >= Config.TileKillThreshold) if (player.TileKillThreshold >= Config.TileKillThreshold)
@ -672,6 +672,10 @@ namespace TShockAPI
{ {
player.TilePlaceThreshold = 0; player.TilePlaceThreshold = 0;
} }
if (player.RecentFuse >0)
player.RecentFuse--;
if (player.TileLiquidThreshold >= Config.TileLiquidThreshold) if (player.TileLiquidThreshold >= Config.TileLiquidThreshold)
{ {
player.Disable("Reached TileLiquid threshold."); player.Disable("Reached TileLiquid threshold.");
@ -737,7 +741,7 @@ namespace TShockAPI
Config.MaxSlots, Netplay.serverListenIP, Netplay.serverPort, Version); Config.MaxSlots, Netplay.serverListenIP, Netplay.serverPort, Version);
} }
private void OnHardUpdate( HardUpdateEventArgs args ) private void OnHardUpdate(HardmodeTileUpdateEventArgs args)
{ {
if (args.Handled) if (args.Handled)
return; return;
@ -767,14 +771,14 @@ namespace TShockAPI
} }
} }
private void OnConnect(int ply, HandledEventArgs handler) private void OnConnect(ConnectEventArgs args)
{ {
var player = new TSPlayer(ply); var player = new TSPlayer(args.Who);
if (Utils.ActivePlayers() + 1 > Config.MaxSlots + Config.ReservedSlots) if (Utils.ActivePlayers() + 1 > Config.MaxSlots + Config.ReservedSlots)
{ {
Utils.ForceKick(player, Config.ServerFullNoReservedReason, true, false); Utils.ForceKick(player, Config.ServerFullNoReservedReason, true, false);
handler.Handled = true; args.Handled = true;
return; return;
} }
@ -790,7 +794,7 @@ namespace TShockAPI
DateTime exp; DateTime exp;
string duration = DateTime.TryParse(ban.Expiration, out exp) ? String.Format("until {0}", exp.ToString("G")) : "forever"; string duration = DateTime.TryParse(ban.Expiration, out exp) ? String.Format("until {0}", exp.ToString("G")) : "forever";
Utils.ForceKick(player, string.Format("You are banned {0}: {1}", duration, ban.Reason), true, false); Utils.ForceKick(player, string.Format("You are banned {0}: {1}", duration, ban.Reason), true, false);
handler.Handled = true; args.Handled = true;
return; return;
} }
} }
@ -798,7 +802,7 @@ namespace TShockAPI
if (!FileTools.OnWhitelist(player.IP)) if (!FileTools.OnWhitelist(player.IP))
{ {
Utils.ForceKick(player, Config.WhitelistKickReason, true, false); Utils.ForceKick(player, Config.WhitelistKickReason, true, false);
handler.Handled = true; args.Handled = true;
return; return;
} }
@ -811,20 +815,20 @@ namespace TShockAPI
if (Config.KickProxyUsers) if (Config.KickProxyUsers)
{ {
Utils.ForceKick(player, "Proxies are not allowed.", true, false); Utils.ForceKick(player, "Proxies are not allowed.", true, false);
handler.Handled = true; args.Handled = true;
return; return;
} }
} }
} }
Players[ply] = player; Players[args.Who] = player;
} }
private void OnJoin(int ply, HandledEventArgs handler) private void OnJoin(JoinEventArgs args)
{ {
var player = Players[ply]; var player = Players[args.Who];
if (player == null) if (player == null)
{ {
handler.Handled = true; args.Handled = true;
return; return;
} }
@ -848,16 +852,16 @@ namespace TShockAPI
DateTime exp; DateTime exp;
string duration = DateTime.TryParse(ban.Expiration, out exp) ? String.Format("until {0}", exp.ToString("G")) : "forever"; string duration = DateTime.TryParse(ban.Expiration, out exp) ? String.Format("until {0}", exp.ToString("G")) : "forever";
Utils.ForceKick(player, string.Format("You are banned {0}: {1}", duration, ban.Reason), true, false); Utils.ForceKick(player, string.Format("You are banned {0}: {1}", duration, ban.Reason), true, false);
handler.Handled = true; args.Handled = true;
} }
} }
} }
private void OnLeave(int ply) private void OnLeave(LeaveEventArgs args)
{ {
var tsplr = Players[ply]; var tsplr = Players[args.Who];
Players[ply] = null; Players[args.Who] = null;
if (tsplr != null && tsplr.ReceivedInfo) if (tsplr != null && tsplr.ReceivedInfo)
{ {
@ -880,15 +884,15 @@ namespace TShockAPI
} }
} }
private void OnChat(messageBuffer msg, int ply, string text, HandledEventArgs e) private void OnChat(ServerChatEventArgs args)
{ {
if (e.Handled) if (args.Handled)
return; return;
var tsplr = Players[msg.whoAmI]; var tsplr = Players[args.Who];
if (tsplr == null) if (tsplr == null)
{ {
e.Handled = true; args.Handled = true;
return; return;
} }
@ -898,11 +902,11 @@ namespace TShockAPI
return; return;
}*/ }*/
if (text.StartsWith("/")) if (args.Text.StartsWith("/"))
{ {
try try
{ {
e.Handled = Commands.HandleCommand(tsplr, text); args.Handled = Commands.HandleCommand(tsplr, args.Text);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -913,18 +917,18 @@ namespace TShockAPI
else if (!tsplr.mute && !TShock.Config.EnableChatAboveHeads) else if (!tsplr.mute && !TShock.Config.EnableChatAboveHeads)
{ {
Utils.Broadcast( Utils.Broadcast(
String.Format(Config.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, text), String.Format(Config.ChatFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, args.Text),
tsplr.Group.R, tsplr.Group.G, tsplr.Group.B); tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
e.Handled = true; args.Handled = true;
} else if (!tsplr.mute && TShock.Config.EnableChatAboveHeads) } else if (!tsplr.mute && TShock.Config.EnableChatAboveHeads)
{ {
Utils.Broadcast(ply, String.Format(Config.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, text), tsplr.Group.R, tsplr.Group.G, tsplr.Group.B); Utils.Broadcast(args.Who, String.Format(Config.ChatAboveHeadsFormat, tsplr.Group.Name, tsplr.Group.Prefix, tsplr.Name, tsplr.Group.Suffix, args.Text), tsplr.Group.R, tsplr.Group.G, tsplr.Group.B);
e.Handled = true; args.Handled = true;
} }
else if (tsplr.mute) else if (tsplr.mute)
{ {
tsplr.SendErrorMessage("You are muted!"); tsplr.SendErrorMessage("You are muted!");
e.Handled = true; args.Handled = true;
} }
} }
@ -933,9 +937,9 @@ namespace TShockAPI
/// </summary> /// </summary>
/// <param name="cmd"></param> /// <param name="cmd"></param>
/// <param name="e"></param> /// <param name="e"></param>
private void ServerHooks_OnCommand(string text, HandledEventArgs e) private void ServerHooks_OnCommand(CommandEventArgs args)
{ {
if (e.Handled) if (args.Handled)
return; return;
// Damn you ThreadStatic and Redigit // Damn you ThreadStatic and Redigit
@ -948,7 +952,7 @@ namespace TShockAPI
WorldGen.genRand = new Random(); WorldGen.genRand = new Random();
} }
if (text.StartsWith("playing") || text.StartsWith("/playing")) if (args.Command.StartsWith("playing") || args.Command.StartsWith("/playing"))
{ {
int count = 0; int count = 0;
foreach (TSPlayer player in Players) foreach (TSPlayer player in Players)
@ -962,20 +966,20 @@ namespace TShockAPI
} }
TSPlayer.Server.SendInfoMessage(string.Format("{0} players connected.", count)); TSPlayer.Server.SendInfoMessage(string.Format("{0} players connected.", count));
} }
else if (text == "autosave") else if (args.Command == "autosave")
{ {
Main.autoSave = Config.AutoSave = !Config.AutoSave; Main.autoSave = Config.AutoSave = !Config.AutoSave;
Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled")); Log.ConsoleInfo("AutoSave " + (Config.AutoSave ? "Enabled" : "Disabled"));
} }
else if (text.StartsWith("/")) else if (args.Command.StartsWith("/"))
{ {
Commands.HandleCommand(TSPlayer.Server, text); Commands.HandleCommand(TSPlayer.Server, args.Command);
} }
else else
{ {
Commands.HandleCommand(TSPlayer.Server, "/" + text); Commands.HandleCommand(TSPlayer.Server, "/" + args.Command);
} }
e.Handled = true; args.Handled = true;
} }
private void OnGetData(GetDataEventArgs e) private void OnGetData(GetDataEventArgs e)
@ -1027,12 +1031,12 @@ namespace TShockAPI
} }
} }
private void OnGreetPlayer(int who, HandledEventArgs e) private void OnGreetPlayer(GreetPlayerEventArgs args)
{ {
var player = Players[who]; var player = Players[args.Who];
if (player == null) if (player == null)
{ {
e.Handled = true; args.Handled = true;
return; return;
} }
player.LoginMS= DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.LoginMS= DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
@ -1072,10 +1076,13 @@ namespace TShockAPI
if (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero){ if (RememberedPos.GetLeavePos(player.Name, player.IP) != Vector2.Zero){
var pos = RememberedPos.GetLeavePos(player.Name, player.IP); var pos = RememberedPos.GetLeavePos(player.Name, player.IP);
player.Teleport((int) pos.X, (int) pos.Y + 3); player.Teleport(pos.X*16, pos.Y*16 + 48);
}} }}
e.Handled = true; Item i = new Item();
i.SetDefaults("Confetti Gun");
player.GiveItem(i.type, i.name, i.width, i.headSlot, 10);
args.Handled = true;
} }
private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e) private void NpcHooks_OnStrikeNpc(NpcStrikeEventArgs e)
@ -1152,7 +1159,7 @@ namespace TShockAPI
private void NetHooks_SendData(SendDataEventArgs e) private void NetHooks_SendData(SendDataEventArgs e)
{ {
if (e.MsgID == PacketTypes.Disconnect) if (e.MsgId == PacketTypes.Disconnect)
{ {
Action<ServerSock, string> senddisconnect = (sock, str) => Action<ServerSock, string> senddisconnect = (sock, str) =>
{ {
@ -1182,7 +1189,7 @@ namespace TShockAPI
} }
e.Handled = true; e.Handled = true;
} }
if (e.MsgID == PacketTypes.WorldInfo) if (e.MsgId == PacketTypes.WorldInfo)
{ {
if (e.remoteClient == -1) return; if (e.remoteClient == -1) return;
var player = Players[e.remoteClient]; var player = Players[e.remoteClient];
@ -1193,25 +1200,61 @@ namespace TShockAPI
{ {
var msg = new WorldInfoMsg var msg = new WorldInfoMsg
{ {
Time = (int)Main.time, Time = (int) Main.time,
DayTime = Main.dayTime, DayTime = Main.dayTime,
MoonPhase = (byte)Main.moonPhase, MoonPhase = (byte) Main.moonPhase,
BloodMoon = Main.bloodMoon, BloodMoon = Main.bloodMoon,
MaxTilesX = Main.maxTilesX, MaxTilesX = Main.maxTilesX,
MaxTilesY = Main.maxTilesY, MaxTilesY = Main.maxTilesY,
SpawnX = Main.spawnTileX, SpawnX = Main.spawnTileX,
SpawnY = Main.spawnTileY, SpawnY = Main.spawnTileY,
WorldSurface = (int)Main.worldSurface, WorldSurface = (int) Main.worldSurface,
RockLayer = (int)Main.rockLayer, RockLayer = (int) Main.rockLayer,
//Sending a fake world id causes the client to not be able to find a stored spawnx/y.
//This fixes the bed spawn point bug. With a fake world id it wont be able to find the bed spawn.
WorldID = Main.worldID, WorldID = Main.worldID,
WorldFlags = MoonType = (byte)Main.moonType,
(WorldGen.shadowOrbSmashed ? WorldInfoFlag.OrbSmashed : WorldInfoFlag.None) | TreeX0 = Main.treeX[0],
(NPC.downedBoss1 ? WorldInfoFlag.DownedBoss1 : WorldInfoFlag.None) | TreeX1 = Main.treeX[1],
(NPC.downedBoss2 ? WorldInfoFlag.DownedBoss2 : WorldInfoFlag.None) | TreeX2 = Main.treeX[2],
(NPC.downedBoss3 ? WorldInfoFlag.DownedBoss3 : WorldInfoFlag.None) | TreeStyle0 = (byte)Main.treeStyle[0],
(Main.hardMode ? WorldInfoFlag.HardMode : WorldInfoFlag.None) | TreeStyle1 = (byte)Main.treeStyle[1],
(NPC.downedClown ? WorldInfoFlag.DownedClown : WorldInfoFlag.None), TreeStyle2 = (byte)Main.treeStyle[2],
WorldName = Config.ServerName TreeStyle3 = (byte)Main.treeStyle[3],
CaveBackX0 = Main.caveBackX[0],
CaveBackX1 = Main.caveBackX[1],
CaveBackX2 = Main.caveBackX[2],
CaveBackStyle0 = (byte)Main.caveBackStyle[0],
CaveBackStyle1 = (byte)Main.caveBackStyle[1],
CaveBackStyle2 = (byte)Main.caveBackStyle[2],
CaveBackStyle3 = (byte)Main.caveBackStyle[3],
SetBG0 = (byte)WorldGen.treeBG,
SetBG1 = (byte)WorldGen.corruptBG,
SetBG2 = (byte)WorldGen.jungleBG,
SetBG3 = (byte)WorldGen.snowBG,
SetBG4 = (byte)WorldGen.hallowBG,
SetBG5 = (byte)WorldGen.crimsonBG,
SetBG6 = (byte)WorldGen.desertBG,
SetBG7 = (byte)WorldGen.oceanBG,
IceBackStyle = (byte)Main.iceBackStyle,
JungleBackStyle = (byte)Main.jungleBackStyle,
HellBackStyle = (byte)Main.hellBackStyle,
WindSpeed = Main.windSpeed,
NumberOfClouds = (byte)Main.numClouds,
BossFlags = (WorldGen.shadowOrbSmashed ? BossFlags.OrbSmashed : BossFlags.None) |
(NPC.downedBoss1 ? BossFlags.DownedBoss1 : BossFlags.None) |
(NPC.downedBoss2 ? BossFlags.DownedBoss2 : BossFlags.None) |
(NPC.downedBoss3 ? BossFlags.DownedBoss3 : BossFlags.None) |
(Main.hardMode ? BossFlags.HardMode : BossFlags.None) |
(NPC.downedClown ? BossFlags.DownedClown : BossFlags.None),
BossFlags2 = (NPC.downedMechBoss1 ? BossFlags2.DownedMechBoss1 : BossFlags2.None) |
(NPC.downedMechBoss2 ? BossFlags2.DownedMechBoss2 : BossFlags2.None) |
(NPC.downedMechBoss3 ? BossFlags2.DownedMechBoss3 : BossFlags2.None) |
(NPC.downedMechBossAny ? BossFlags2.DownedMechBossAny : BossFlags2.None) |
(Main.cloudBGActive == 1f ? BossFlags2.CloudBg : BossFlags2.None) |
(WorldGen.crimson ? BossFlags2.Crimson : BossFlags2.None),
Rain = Main.maxRaining,
WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
}; };
msg.PackFull(ms); msg.PackFull(ms);
player.SendRawData(ms.ToArray()); player.SendRawData(ms.ToArray());
@ -1332,11 +1375,11 @@ namespace TShockAPI
return false; return false;
} }
public static bool CheckTilePermission( TSPlayer player, int tileX, int tileY, byte tileType, byte actionType ) public static bool CheckTilePermission( TSPlayer player, int tileX, int tileY, byte tileType, GetDataHandlers.EditAction actionType )
{ {
if (!player.Group.HasPermission(Permissions.canbuild)) if (!player.Group.HasPermission(Permissions.canbuild))
{ {
if (TShock.Config.AllowIce && actionType != 1) if (TShock.Config.AllowIce && actionType != GetDataHandlers.EditAction.PlaceTile)
{ {
foreach (Point p in player.IceTiles) foreach (Point p in player.IceTiles)
@ -1356,7 +1399,7 @@ namespace TShockAPI
return true; return true;
} }
if (TShock.Config.AllowIce && actionType == 1 && tileType == 127) if (TShock.Config.AllowIce && actionType == GetDataHandlers.EditAction.PlaceTile && tileType == 127)
{ {
player.IceTiles.Add(new Point(tileX, tileY)); player.IceTiles.Add(new Point(tileX, tileY));
return false; return false;
@ -1387,11 +1430,11 @@ namespace TShockAPI
{ {
if (!player.Group.HasPermission(Permissions.editspawn)) if (!player.Group.HasPermission(Permissions.editspawn))
{ {
if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000){ if (((DateTime.Now.Ticks/TimeSpan.TicksPerMillisecond) - player.WPm) > 2000)
{
player.SendMessage("The world is protected from changes.", Color.Red); player.SendMessage("The world is protected from changes.", Color.Red);
player.WPm=DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; player.WPm = DateTime.Now.Ticks/TimeSpan.TicksPerMillisecond;
}
}
return true; return true;
} }
} }
@ -1498,9 +1541,10 @@ namespace TShockAPI
Item[] inventory = player.TPlayer.inventory; Item[] inventory = player.TPlayer.inventory;
Item[] armor = player.TPlayer.armor; Item[] armor = player.TPlayer.armor;
Item[] dye = player.TPlayer.dye;
for (int i = 0; i < NetItem.maxNetInventory; i++) for (int i = 0; i < NetItem.maxNetInventory; i++)
{ {
if (i < 49) if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
{ {
Item item = new Item(); Item item = new Item();
if (inventory[i] != null && inventory[i].netID != 0) if (inventory[i] != null && inventory[i].netID != 0)
@ -1517,15 +1561,16 @@ namespace TShockAPI
} }
} }
} }
else else if(i < (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots)))
{ {
Item item = new Item(); Item item = new Item();
if (armor[i - 48] != null && armor[i - 48].netID != 0) var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
if (armor[index] != null && armor[index].netID != 0)
{ {
item.netDefaults(armor[i - 48].netID); item.netDefaults(armor[index].netID);
item.Prefix(armor[i - 48].prefix); item.Prefix(armor[index].prefix);
item.AffixName(); item.AffixName();
if (armor[i - 48].stack > item.maxStack) if (armor[index].stack > item.maxStack)
{ {
check = true; check = true;
player.SendMessage( player.SendMessage(
@ -1534,6 +1579,24 @@ namespace TShockAPI
} }
} }
} }
else if (i < (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots)))
{
Item item = new Item();
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
if (dye[index] != null && dye[index].netID != 0)
{
item.netDefaults(dye[index].netID);
item.Prefix(dye[index].prefix);
item.AffixName();
if (dye[index].stack > item.maxStack)
{
check = true;
player.SendMessage(
String.Format("Stack cheat detected. Remove dye {0} ({1}) and then rejoin", item.name, dye[index].stack),
Color.Cyan);
}
}
}
} }
return check; return check;
@ -1553,9 +1616,10 @@ namespace TShockAPI
Item[] inventory = player.TPlayer.inventory; Item[] inventory = player.TPlayer.inventory;
Item[] armor = player.TPlayer.armor; Item[] armor = player.TPlayer.armor;
Item[] dye = player.TPlayer.dye;
for (int i = 0; i < NetItem.maxNetInventory; i++) for (int i = 0; i < NetItem.maxNetInventory; i++)
{ {
if (i < 49) if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
{ {
Item item = new Item(); Item item = new Item();
Item serverItem = new Item(); Item serverItem = new Item();
@ -1592,34 +1656,35 @@ namespace TShockAPI
} }
} }
} }
else else if(i < (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots)))
{ {
Item item = new Item(); Item item = new Item();
Item serverItem = new Item(); Item serverItem = new Item();
if (armor[i - 48] != null && armor[i - 48].netID != 0) var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
if (armor[index] != null && armor[index].netID != 0)
{ {
if (playerData.inventory[i].netID != armor[i - 48].netID) if (playerData.inventory[i].netID != armor[index].netID)
{ {
item.netDefaults(armor[i - 48].netID); item.netDefaults(armor[index].netID);
item.Prefix(armor[i - 48].prefix); item.Prefix(armor[index].prefix);
item.AffixName(); item.AffixName();
player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.", player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.",
Color.Cyan); Color.Cyan);
check = false; check = false;
} }
else if (playerData.inventory[i].prefix != armor[i - 48].prefix) else if (playerData.inventory[i].prefix != armor[index].prefix)
{ {
item.netDefaults(armor[i - 48].netID); item.netDefaults(armor[index].netID);
item.Prefix(armor[i - 48].prefix); item.Prefix(armor[index].prefix);
item.AffixName(); item.AffixName();
player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.", player.SendMessage(player.IgnoreActionsForInventory = "Your armor (" + item.name + ") needs to be deleted.",
Color.Cyan); Color.Cyan);
check = false; check = false;
} }
else if (armor[i - 48].stack > playerData.inventory[i].stack) else if (armor[index].stack > playerData.inventory[i].stack)
{ {
item.netDefaults(armor[i - 48].netID); item.netDefaults(armor[index].netID);
item.Prefix(armor[i - 48].prefix); item.Prefix(armor[index].prefix);
item.AffixName(); item.AffixName();
player.SendMessage( player.SendMessage(
player.IgnoreActionsForInventory = player.IgnoreActionsForInventory =
@ -1629,6 +1694,44 @@ namespace TShockAPI
} }
} }
} }
else if(i < (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots)))
{
Item item = new Item();
Item serverItem = new Item();
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
if (dye[index] != null && dye[index].netID != 0)
{
if (playerData.inventory[i].netID != dye[index].netID)
{
item.netDefaults(dye[index].netID);
item.Prefix(dye[index].prefix);
item.AffixName();
player.SendMessage(player.IgnoreActionsForInventory = "Your dye (" + item.name + ") needs to be deleted.",
Color.Cyan);
check = false;
}
else if (playerData.inventory[i].prefix != dye[index].prefix)
{
item.netDefaults(dye[index].netID);
item.Prefix(dye[index].prefix);
item.AffixName();
player.SendMessage(player.IgnoreActionsForInventory = "Your dye (" + item.name + ") needs to be deleted.",
Color.Cyan);
check = false;
}
else if (dye[index].stack > playerData.inventory[i].stack)
{
item.netDefaults(dye[index].netID);
item.Prefix(dye[index].prefix);
item.AffixName();
player.SendMessage(
player.IgnoreActionsForInventory =
"Your dye (" + item.name + ") (" + inventory[i].stack + ") needs to have its stack size decreased to (" +
playerData.inventory[i].stack + ").", Color.Cyan);
check = false;
}
}
}
} }
return check; return check;
@ -1636,20 +1739,7 @@ namespace TShockAPI
public static bool CheckIgnores(TSPlayer player) public static bool CheckIgnores(TSPlayer player)
{ {
bool check = false; return Config.PvPMode == "always" && !player.TPlayer.hostile || player.IgnoreActionsForInventory != "none" || player.IgnoreActionsForCheating != "none" || player.IgnoreActionsForDisabledArmor != "none" || player.IgnoreActionsForClearingTrashCan || !player.IsLoggedIn && Config.RequireLogin;;
if (Config.PvPMode == "always" && !player.TPlayer.hostile)
check = true;
if (player.IgnoreActionsForInventory != "none")
check = true;
if (player.IgnoreActionsForCheating != "none")
check = true;
if (player.IgnoreActionsForDisabledArmor != "none")
check = true;
if (player.IgnoreActionsForClearingTrashCan)
check = true;
if (!player.IsLoggedIn && Config.RequireLogin)
check = true;
return check;
} }
public void OnConfigRead(ConfigFile file) public void OnConfigRead(ConfigFile file)

View file

@ -38,6 +38,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DocumentationFile>bin\Debug\TShockAPI.XML</DocumentationFile> <DocumentationFile>bin\Debug\TShockAPI.XML</DocumentationFile>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
@ -67,7 +68,7 @@
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="TerrariaServer, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="TerrariaServer, Version=1.14.0.0, Culture=neutral, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<ExecutableExtension>.exe</ExecutableExtension> <ExecutableExtension>.exe</ExecutableExtension>
<HintPath>..\TerrariaServerBins\TerrariaServer.exe</HintPath> <HintPath>..\TerrariaServerBins\TerrariaServer.exe</HintPath>
@ -79,9 +80,6 @@
<Compile Include="Hooks\GeneralHooks.cs" /> <Compile Include="Hooks\GeneralHooks.cs" />
<Compile Include="Hooks\PlayerHooks.cs" /> <Compile Include="Hooks\PlayerHooks.cs" />
<Compile Include="PaginationTools.cs" /> <Compile Include="PaginationTools.cs" />
<Compile Include="PluginUpdater\PluginUpdaterThread.cs" />
<Compile Include="PluginUpdater\PluginVersionCheck.cs" />
<Compile Include="PluginUpdater\VersionInfo.cs" />
<Compile Include="Rest\RestPermissions.cs" /> <Compile Include="Rest\RestPermissions.cs" />
<Compile Include="SaveManager.cs" /> <Compile Include="SaveManager.cs" />
<Compile Include="DB\BanManager.cs" /> <Compile Include="DB\BanManager.cs" />

View file

@ -329,7 +329,7 @@ namespace TShockAPI
/// <returns>The state of the tile</returns> /// <returns>The state of the tile</returns>
private bool TileClear(int tileX, int tileY) private bool TileClear(int tileX, int tileY)
{ {
return !Main.tile[tileX, tileY].active; return !Main.tile[tileX, tileY].active();
} }
/// <summary> /// <summary>
@ -371,7 +371,7 @@ namespace TShockAPI
var found = new List<Item>(); var found = new List<Item>();
Item item = new Item(); Item item = new Item();
string nameLower = name.ToLower(); string nameLower = name.ToLower();
for (int i = -24; i < Main.maxItemTypes; i++) for (int i = -48; i < Main.maxItemTypes; i++)
{ {
item.netDefaults(i); item.netDefaults(i);
if (item.name.ToLower() == nameLower) if (item.name.ToLower() == nameLower)