diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..c1f89e94
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "TerrariaServerAPI"]
+ path = TerrariaServerAPI
+ url = https://github.com/Deathmax/TerrariaAPI-Server.git
diff --git a/TShock.sln b/TShock.sln
index da320f87..904e7dcd 100644
--- a/TShock.sln
+++ b/TShock.sln
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\Unit
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TShockRestTestPlugin", "TShockRestTestPlugin\TShockRestTestPlugin.csproj", "{F2FEDAFB-58DE-4611-9168-A86112C346C7}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TerrariaAPI-Server", "TerrariaServerAPI\TerrariaAPI-Server.csproj", "{549A7941-D9C9-4544-BAC8-D9EEEAB4D777}"
+EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = Terraria.vsmdi
@@ -52,6 +54,18 @@ Global
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F2FEDAFB-58DE-4611-9168-A86112C346C7}.Release|x86.ActiveCfg = Release|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|x86.ActiveCfg = Debug|x86
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Debug|x86.Build.0 = Debug|x86
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Any CPU.Build.0 = Release|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|x86.ActiveCfg = Release|x86
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/TShockAPI/ConfigFile.cs b/TShockAPI/ConfigFile.cs
index 6f66607e..f835105d 100755
--- a/TShockAPI/ConfigFile.cs
+++ b/TShockAPI/ConfigFile.cs
@@ -276,6 +276,8 @@ namespace TShockAPI
[Description("Forces your world to be in Halloween mode regardless of the data.")] public bool ForceHalloween = false;
+ [Description("Allows anyone to break grass, pots, etc.")] public bool AllowCutTilesAndBreakables = false;
+
///
/// Reads a configuration file from a given path
///
diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs
index a0159806..2747ee58 100755
--- a/TShockAPI/GetDataHandlers.cs
+++ b/TShockAPI/GetDataHandlers.cs
@@ -716,13 +716,18 @@ namespace TShockAPI
/// Y location of said chest
///
public int Y { get; set; }
+
+ ///
+ /// The player opening the chest
+ ///
+ public TSPlayer Player { get; set; }
}
///
/// ChestOpen - Called when any chest is opened
///
public static HandlerList ChestOpen;
- private static bool OnChestOpen(int x, int y)
+ private static bool OnChestOpen(int x, int y, TSPlayer player)
{
if (ChestOpen == null)
return false;
@@ -731,6 +736,7 @@ namespace TShockAPI
{
X = x,
Y = y,
+ Player = player,
};
ChestOpen.Invoke(null, args);
return args.Handled;
@@ -1608,7 +1614,7 @@ namespace TShockAPI
///
/// Tiles that can be oriented (e.g., beds, chairs, bathtubs, etc).
///
- private static byte[] orientableTiles = new byte[] { 15, 79, 90, 105, 128, 137, 139, 209 };
+ private static byte[] orientableTiles = new byte[] { 15, 79, 90, 105, 128, 137, 139, 207, 209 };
private static bool HandleSendTileSquare(GetDataHandlerArgs args)
{
@@ -1738,7 +1744,14 @@ namespace TShockAPI
KillTileNoItem,
PlaceWire,
KillWire,
- PoundTile
+ PoundTile,
+ PlaceActuator,
+ KillActuator,
+ PlaceWire2,
+ KillWire2,
+ PlaceWire3,
+ KillWire3,
+ SlopeTile
}
public enum EditType
{
@@ -1751,6 +1764,14 @@ namespace TShockAPI
/// Tiles that can be broken without any tools.
///
private static byte[] breakableTiles = new byte[] { 4, 13, 33, 49, 50, 127, 128, 162 };
+ ///
+ /// The maximum place styles for each tile.
+ ///
+ public static Dictionary MaxPlaceStyles = new Dictionary();
+ ///
+ /// These projectiles create tiles on death.
+ ///
+ private static Dictionary projectileCreatesTile = new Dictionary {{42, 53}, {65, 112}, {68, 116}};
private static bool HandleTile(GetDataHandlerArgs args)
{
@@ -1848,6 +1869,7 @@ namespace TShockAPI
}
Item selectedItem = args.Player.SelectedItem;
+ int lastKilledProj = args.Player.LastKilledProjectile;
if (action == EditAction.KillTile && !Main.tileCut[Main.tile[tileX, tileY].type] && !breakableTiles.Contains(Main.tile[tileX, tileY].type))
{
// If the tile is an axe tile and they aren't selecting an axe, they're hacking.
@@ -1878,17 +1900,19 @@ namespace TShockAPI
return true;
}
}
+ else if (action == EditAction.PlaceTile && (projectileCreatesTile.ContainsKey(lastKilledProj) && editData == projectileCreatesTile[lastKilledProj]))
+ {
+ args.Player.LastKilledProjectile = 0;
+ }
else if (action == EditAction.PlaceTile || action == EditAction.PlaceWall)
{
- if (action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle && ((editData == 4 && style > 11) ||
- (editData == 13 && style > 4) || (editData == 15 && style > 23) || (editData == 21 && style > 22) ||
- (editData == 82 && style > 5) || (editData == 91 && style > 108) || (editData == 105 && style > 49) ||
- (editData == 135 && style > 6) || (editData == 139 && style > 27) || (editData == 144 && style > 2) ||
- (editData == 149 && style > 2) || (editData == 137 && style > 4) || (editData == 79 && style > 12)))
+ if (action == EditAction.PlaceTile && TShock.Config.PreventInvalidPlaceStyle &&
+ MaxPlaceStyles.ContainsKey(editData) && style > MaxPlaceStyles[editData])
{
args.Player.SendTileSquare(tileX, tileY, 4);
return true;
}
+
// If they aren't selecting the item which creates the tile or wall, they're hacking.
if ((editData != 127 && editData != 213) && editData != (action == EditAction.PlaceTile ? selectedItem.createTile : selectedItem.createWall))
{
@@ -1922,24 +1946,48 @@ namespace TShockAPI
}
}
}
- else if (action == EditAction.PlaceWire)
+ else if (action == EditAction.PlaceWire || action == EditAction.PlaceWire2 || action == EditAction.PlaceWire3)
{
- // If they aren't selecting the wrench, they're hacking.
- if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 509)
+ // If they aren't selecting a wrench, they're hacking.
+ if (selectedItem.type != 509 && selectedItem.type != 850 && selectedItem.type != 851)
{
args.Player.SendTileSquare(tileX, tileY, 1);
return true;
}
}
- else if (action == EditAction.KillWire)
+ else if (action == EditAction.KillActuator || action == EditAction.KillWire ||
+ action == EditAction.KillWire2 || action == EditAction.KillWire3)
{
// If they aren't selecting the wire cutter, they're hacking.
- if (args.TPlayer.inventory[args.TPlayer.selectedItem].type != 510)
+ if (selectedItem.type != 510)
{
args.Player.SendTileSquare(tileX, tileY, 1);
return true;
}
}
+ else if (action == EditAction.PlaceActuator)
+ {
+ // If they aren't selecting the actuator, they're hacking.
+ if (selectedItem.type != 849)
+ {
+ args.Player.SendTileSquare(tileX, tileY, 1);
+ return true;
+ }
+ }
+ else if (action == EditAction.PoundTile || action == EditAction.SlopeTile)
+ {
+ // If they aren't selecting a hammer, they're hacking.
+ if (selectedItem.hammer == 0)
+ {
+ args.Player.SendTileSquare(tileX, tileY, 1);
+ return true;
+ }
+ }
+
+ if (TShock.Config.AllowCutTilesAndBreakables && (Main.tileCut[Main.tile[tileX, tileY].type] || breakableTiles.Contains(Main.tile[tileX, tileY].type)))
+ {
+ return false;
+ }
if (TShock.CheckIgnores(args.Player))
{
@@ -2490,6 +2538,8 @@ namespace TShockAPI
return true;
}
+ args.Player.LastKilledProjectile = type;
+
return false;
}
@@ -2754,7 +2804,7 @@ namespace TShockAPI
var x = args.Data.ReadInt32();
var y = args.Data.ReadInt32();
- if (OnChestOpen(x, y))
+ if (OnChestOpen(x, y, args.Player))
return true;
if (TShock.CheckIgnores(args.Player))
@@ -2783,6 +2833,12 @@ namespace TShockAPI
args.Player.ActiveChest = id;
+ if (TShock.CheckTilePermission(args.Player, x, y) && TShock.Config.RegionProtectChests)
+ {
+ args.Player.SendData(PacketTypes.ChestOpen, "", -1);
+ return true;
+ }
+
return false;
}
diff --git a/TShockAPI/Properties/AssemblyInfo.cs b/TShockAPI/Properties/AssemblyInfo.cs
index e2731e33..feea2a19 100644
--- a/TShockAPI/Properties/AssemblyInfo.cs
+++ b/TShockAPI/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Runtime.InteropServices;
// Build Number
// MMdd of the build
-[assembly: AssemblyVersion("4.2.0.1019")]
-[assembly: AssemblyFileVersion("4.2.0.1019")]
+[assembly: AssemblyVersion("4.2.1.1110")]
+[assembly: AssemblyFileVersion("4.2.1.1110")]
diff --git a/TShockAPI/StatTracker.cs b/TShockAPI/StatTracker.cs
new file mode 100644
index 00000000..a3381bf7
--- /dev/null
+++ b/TShockAPI/StatTracker.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Net;
+using System.Threading;
+using System.IO;
+using System.Web;
+
+namespace TShockAPI
+{
+ public class StatTracker
+ {
+ private bool failed;
+ private bool initialized;
+ public StatTracker()
+ {
+
+ }
+
+ public void Initialize()
+ {
+ if (!initialized)
+ {
+ initialized = true;
+ ThreadPool.QueueUserWorkItem(SendUpdate);
+ }
+ }
+
+ private HttpWebResponse GetResponseNoException(HttpWebRequest req)
+ {
+ try
+ {
+ return (HttpWebResponse)req.GetResponse();
+ }
+ catch (WebException we)
+ {
+ var resp = we.Response as HttpWebResponse;
+ if (resp == null)
+ throw;
+ return resp;
+ }
+ }
+
+ private void SendUpdate(object info)
+ {
+ Thread.Sleep(1000*60*15);
+ var data = new JsonData
+ {
+ port = Terraria.Netplay.serverPort,
+ currentPlayers = TShock.Utils.ActivePlayers(),
+ maxPlayers = TShock.Config.MaxSlots,
+ systemRam = 0,
+ systemCPUClock = 0,
+ version = TShock.VersionNum.ToString(),
+ terrariaVersion = Terraria.Main.versionNumber2,
+ mono = Terraria.Main.runningMono
+ };
+
+ var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(data);
+ var encoded = HttpUtility.UrlEncode(serialized);
+ var uri = String.Format("http://96.47.231.227:8000?data={0}", encoded);
+ var client = (HttpWebRequest)WebRequest.Create(uri);
+ client.Timeout = 5000;
+ try
+ {
+ using (var resp = GetResponseNoException(client))
+ {
+ if (resp.StatusCode != HttpStatusCode.OK)
+ {
+ throw new IOException("Server did not respond with an OK.");
+ }
+
+ failed = false;
+ }
+ }
+ catch (Exception e)
+ {
+ if (!failed)
+ {
+ Log.ConsoleError("StatTracker Exception: {0}", e);
+ failed = true;
+ }
+ }
+
+ ThreadPool.QueueUserWorkItem(SendUpdate);
+ }
+ }
+
+ public struct JsonData
+ {
+ public int port;
+ public int currentPlayers;
+ public int maxPlayers;
+ public int systemRam;
+ public int systemCPUClock;
+ public string version;
+ public string terrariaVersion;
+ public bool mono;
+ }
+}
diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs
index b45e4c79..4eac6a2d 100755
--- a/TShockAPI/TSPlayer.cs
+++ b/TShockAPI/TSPlayer.cs
@@ -308,6 +308,11 @@ namespace TShockAPI
/// Players controls are inverted if using SSC
///
public bool Confused = false;
+
+ ///
+ /// The last projectile type this player tried to kill.
+ ///
+ public int LastKilledProjectile = 0;
///
/// Whether the player is a real, human, player on the server.
diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs
index 686b4072..105ca044 100755
--- a/TShockAPI/TShock.cs
+++ b/TShockAPI/TShock.cs
@@ -72,6 +72,7 @@ namespace TShockAPI
public static SecureRest RestApi;
public static RestManager RestManager;
public static Utils Utils = Utils.Instance;
+ public static StatTracker StatTracker = new StatTracker();
///
/// Used for implementing REST Tokens prior to the REST system starting up.
///
@@ -611,14 +612,35 @@ namespace TShockAPI
{
AuthToken = 0;
}
-
- Regions.Reload();
+
+ Regions.Reload();
Warps.ReloadWarps();
Lighting.lightMode = 2;
+ ComputeMaxStyles();
FixChestStacks();
+
+ StatTracker.Initialize();
}
+ private void ComputeMaxStyles()
+ {
+ var item = new Item();
+ for (int i = 0; i < Main.maxItemTypes; i++)
+ {
+ item.netDefaults(i);
+ if (item.placeStyle > 0)
+ {
+ if (GetDataHandlers.MaxPlaceStyles.ContainsKey(item.createTile))
+ {
+ if (item.placeStyle > GetDataHandlers.MaxPlaceStyles[item.createTile])
+ GetDataHandlers.MaxPlaceStyles[item.createTile] = item.placeStyle;
+ }
+ else
+ GetDataHandlers.MaxPlaceStyles.Add(item.createTile, item.placeStyle);
+ }
+ }
+ }
private void FixChestStacks()
{
if (Config.IgnoreChestStacksOnLoad)
diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj
index a2a54944..3ebc9d93 100644
--- a/TShockAPI/TShockAPI.csproj
+++ b/TShockAPI/TShockAPI.csproj
@@ -68,11 +68,7 @@
-
- False
- .exe
- ..\TerrariaServerBins\TerrariaServer.exe
-
+
@@ -126,6 +122,7 @@
+
@@ -165,7 +162,12 @@
true
-
+
+
+ {549A7941-D9C9-4544-BAC8-D9EEEAB4D777}
+ TerrariaAPI-Server
+
+
diff --git a/TShockAPI/Utils.cs b/TShockAPI/Utils.cs
index 2e3c51fc..135604f0 100644
--- a/TShockAPI/Utils.cs
+++ b/TShockAPI/Utils.cs
@@ -24,6 +24,7 @@ using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
+using System.Text.RegularExpressions;
using Terraria;
using TShockAPI.DB;
@@ -717,7 +718,7 @@ namespace TShockAPI
///
/// Shows a file to the user.
///
- /// int player
+ /// TSPlayer player
/// string filename reletave to savedir
public void ShowFileToUser(TSPlayer player, string file)
{
@@ -726,31 +727,28 @@ namespace TShockAPI
{
while ((foo = tr.ReadLine()) != null)
{
+ if (string.IsNullOrWhiteSpace(foo))
+ {
+ continue;
+ }
+
foo = foo.Replace("%map%", Main.worldName);
foo = foo.Replace("%players%", GetPlayers());
- //foo = SanitizeString(foo);
- if (foo.Substring(0, 1) == "%" && foo.Substring(12, 1) == "%") //Look for a beginning color code.
+ Regex reg = new Regex("%\\s*(?\\d{1,3})\\s*,\\s*(?\\d{1,3})\\s*,\\s*(?\\d{1,3})\\s*%");
+ var matches = reg.Matches(foo);
+ Color c = Color.White;
+ foreach (Match match in matches)
{
- string possibleColor = foo.Substring(0, 13);
- foo = foo.Remove(0, 13);
- float[] pC = {0, 0, 0};
- possibleColor = possibleColor.Replace("%", "");
- string[] pCc = possibleColor.Split(',');
- if (pCc.Length == 3)
+ byte r, g, b;
+ if (byte.TryParse(match.Groups["r"].Value, out r) &&
+ byte.TryParse(match.Groups["g"].Value, out g) &&
+ byte.TryParse(match.Groups["b"].Value, out b))
{
- try
- {
- player.SendMessage(foo, (byte) Convert.ToInt32(pCc[0]), (byte) Convert.ToInt32(pCc[1]),
- (byte) Convert.ToInt32(pCc[2]));
- continue;
- }
- catch (Exception e)
- {
- Log.Error(e.ToString());
- }
+ c = new Color(r, g, b);
}
+ foo = foo.Remove(match.Index, match.Length);
}
- player.SendMessage(foo);
+ player.SendMessage(foo, c);
}
}
}
diff --git a/TerrariaServerAPI b/TerrariaServerAPI
new file mode 160000
index 00000000..92aeb654
--- /dev/null
+++ b/TerrariaServerAPI
@@ -0,0 +1 @@
+Subproject commit 92aeb65461a164c5a715dd72e8fc7a6e3dfbb24b
diff --git a/TerrariaServerBins/TerrariaServer.exe b/TerrariaServerBins/TerrariaServer.exe
deleted file mode 100644
index f4cb8f2c..00000000
Binary files a/TerrariaServerBins/TerrariaServer.exe and /dev/null differ
diff --git a/create_release.py b/create_release.py
index 81493519..fa2e05e0 100644
--- a/create_release.py
+++ b/create_release.py
@@ -18,7 +18,8 @@ http_bin_name = "HttpServer.dll"
tshock_bin_name = "TShockAPI.dll"
tshock_symbols = "TShockAPI.dll.mdb"
-terraria_bin = os.path.join(cur_wd, "TerrariaServerBins", terraria_bin_name)
+terraria_release_bin = os.path.join(cur_wd, "TerrariaServerAPI", "bin", "Release", terraria_bin_name)
+terraria_debug_bin = os.path.join(cur_wd, "TerrariaServerAPI", "bin", "Debug", terraria_bin_name)
sql_dep = os.path.join(cur_wd, "SqlBins")
http_bin = os.path.join(cur_wd, "HttpBins", http_bin_name)
json_bin = os.path.join(cur_wd, "TShockAPI", json_bin_name)
@@ -38,10 +39,12 @@ def copy_dependencies():
shutil.copy(os.path.join(sql_dep, f), release_dir)
def copy_debug_files():
+ shutil.copy(terraria_debug_bin, release_dir)
shutil.copy(os.path.join(debug_folder, tshock_bin_name), release_dir)
shutil.copy(os.path.join(debug_folder, tshock_symbols), release_dir)
def copy_release_files():
+ shutil.copy(terraria_release_bin, release_dir)
shutil.copy(release_bin, release_dir)
shutil.copy(release_bin, release_dir)
@@ -62,6 +65,7 @@ def package_release():
zip.write(tshock_bin_name, os.path.join("ServerPlugins", tshock_bin_name))
zip.close()
os.remove(tshock_bin_name)
+ os.remove(terraria_bin_name)
os.chdir(cur_wd)
def package_debug():
@@ -72,11 +76,11 @@ def package_debug():
zip.close()
os.remove(tshock_bin_name)
os.remove(tshock_symbols)
+ os.remove(terraria_bin_name)
os.chdir(cur_wd)
def delete_files():
os.chdir(release_dir)
- os.remove(terraria_bin_name)
for f in sql_bins_names:
os.remove(f)
os.remove(sqlite_dep)
@@ -84,23 +88,23 @@ def delete_files():
os.remove(http_bin_name)
os.chdir(cur_wd)
-def update_terraria_exe():
- url = urllib2.urlopen('http://direct.tshock.co:8085/browse/TERRA-TSAPI/latestSuccessful/artifact/JOB1/Server-Bin/TerrariaServer.exe')
- localFile = open('TerrariaServer.exe', 'w')
- localFile.write(url.read())
- localFile.close()
- shutil.copy(terraria_bin_name, terraria_bin)
- os.remove(terraria_bin_name)
+def update_terraria_source():
+ subprocess.check_call('/usr/local/bin/git submodule init')
+ subprocess.check_call('/usr/local/bin/git submodule update')
def build_software():
release_proc = subprocess.Popen(['/usr/local/bin/xbuild', './TShockAPI/TShockAPI.csproj', '/p:Configuration=Release'])
debug_proc = subprocess.Popen(['/usr/local/bin/xbuild', './TShockAPI/TShockAPI.csproj', '/p:Configuration=Debug'])
release_proc.wait()
debug_proc.wait()
-
+ if (release_proc.returncode != 0):
+ raise CalledProcessError(release_proc.returncode)
+ if (debug_proc.returncode != 0):
+ raise CalledProcessError(debug_proc.returncode)
+
if __name__ == '__main__':
create_release_folder()
- update_terraria_exe()
+ update_terraria_source()
copy_dependencies()
build_software()
package_release()