/*
TShock, a server mod for Terraria
Copyright (C) 2011-2019 Pryaxis & TShock Contributors
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 .
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using Terraria;
using Terraria.ID;
using Terraria.Utilities;
using Microsoft.Xna.Framework;
using Terraria.Localization;
using TShockAPI.Localization;
namespace TShockAPI
{
///
/// Utilities and other TShock core calls that don't fit anywhere else
///
public class Utils
{
///
/// Hex code for a blue pastel color
///
public const string BoldHighlight = "AAAAFF";
///
/// Hex code for a red pastel color
///
public const string RedHighlight = "FFAAAA";
///
/// Hex code for a green pastel color
///
public const string GreenHighlight = "AAFFAA";
///
/// Hex code for a pink pastel color
///
public const string PinkHighlight = "FFAAFF";
///
/// Hex code for a yellow pastel color
///
public const string YellowHighlight = "FFFAAA";
///
/// Hex code for a white highlight
///
public const string WhiteHighlight = "FFFFFF";
///
/// Hex code for a cyan pastel color
///
public const string CyanHighlight = "AAFFFF";
///
/// The lowest id for a prefix.
///
private const int FirstItemPrefix = 1;
///
/// The highest id for a prefix.
///
private const int LastItemPrefix = 83;
/// instance - an instance of the utils class
private static readonly Utils instance = new Utils();
/// Utils - Creates a utilities object.
private Utils() { }
/// Instance - An instance of the utils class.
/// value - the Utils instance
public static Utils Instance { get { return instance; } }
///
/// Provides the real IP address from a RemoteEndPoint string that contains a port and an IP
///
/// A string IPv4 address in IP:PORT form.
/// A string IPv4 address.
public string GetRealIP(string mess)
{
return mess.Split(':')[0];
}
///
/// It's a clamp function
///
///
/// Value to clamp
/// Maximum bounds of the clamp
/// Minimum bounds of the clamp
///
public T Clamp(T value, T max, T min)
where T : IComparable
{
T result = value;
if (value.CompareTo(max) > 0)
result = max;
if (value.CompareTo(min) < 0)
result = min;
return result;
}
///
/// Saves the map data by calling the SaveManager and instructing it to save the world.
///
public void SaveWorld()
{
SaveManager.Instance.SaveWorld();
}
/// Broadcast - Broadcasts a message to all players on the server, as well as the server console, and the logs.
/// msg - The message to send
/// red - The amount of red (0-255) in the color for supported destinations.
/// green - The amount of green (0-255) in the color for supported destinations.
/// blue - The amount of blue (0-255) in the color for the supported destinations.
public void Broadcast(string msg, byte red, byte green, byte blue)
{
TSPlayer.All.SendMessage(msg, red, green, blue);
TSPlayer.Server.SendMessage(msg, red, green, blue);
TShock.Log.Info(GetString("Broadcast: {0}", msg));
}
/// >Broadcast - Broadcasts a message to all players on the server, as well as the server console, and the logs.
/// msg - The message to send
/// color - The color object for supported destinations.
public void Broadcast(string msg, Color color)
{
Broadcast(msg, color.R, color.G, color.B);
}
///
/// Broadcasts a message from a Terraria player, not TShock
///
/// ply - the Terraria player index that will send the packet
/// msg - The message to send
/// red - The amount of red (0-255) in the color for supported destinations.
/// green - The amount of green (0-255) in the color for supported destinations.
/// blue - The amount of blue (0-255) in the color for the supported destinations.
public void Broadcast(int ply, string msg, byte red, byte green, byte blue)
{
TSPlayer.All.SendMessageFromPlayer(msg, red, green, blue, ply);
TSPlayer.Server.SendMessage(Main.player[ply].name + ": " + msg, red, green, blue);
TShock.Log.Info(GetString("Broadcast: {0}: {1}", Main.player[ply].name, msg));
}
///
/// Sends message to all players with 'logs' permission.
///
/// Message to send
/// Color of the message
/// The player to not send the message to.
public void SendLogs(string log, Color color, TSPlayer excludedPlayer = null)
{
TShock.Log.Info(log);
TSPlayer.Server.SendMessage(log, color);
foreach (TSPlayer player in TShock.Players)
{
if (player != null && player != excludedPlayer && player.Active && player.HasPermission(Permissions.logs) &&
player.DisplayLogs && TShock.Config.Settings.DisableSpewLogs == false)
player.SendMessage(log, color);
}
}
///
/// Gets the number of active players on the server.
///
/// The number of active players on the server.
public int GetActivePlayerCount()
{
return Main.player.Where(p => null != p && p.active).Count();
}
//Random should not be generated in a method
Random r = new Random();
///
/// Gets a random clear tile in range
///
/// Bound X
/// Bound Y
/// Range on the X axis
/// Range on the Y axis
/// X location
/// Y location
public void GetRandomClearTileWithInRange(int startTileX, int startTileY, int tileXRange, int tileYRange,
out int tileX, out int tileY)
{
int j = 0;
do
{
if (j == 100)
{
tileX = startTileX;
tileY = startTileY;
break;
}
tileX = startTileX + r.Next(tileXRange * -1, tileXRange);
tileY = startTileY + r.Next(tileYRange * -1, tileYRange);
j++;
} while (TilePlacementValid(tileX, tileY) && TileSolid(tileX, tileY));
}
///
/// Determines if a tile is valid.
///
/// Location X
/// Location Y
/// If the tile is valid
public bool TilePlacementValid(int tileX, int tileY)
{
return tileX >= 0 && tileX < Main.maxTilesX && tileY >= 0 && tileY < Main.maxTilesY;
}
///
/// Checks if the tile is solid.
///
/// Location X
/// Location Y
/// The tile's solidity.
public bool TileSolid(int tileX, int tileY)
{
return TilePlacementValid(tileX, tileY) && Main.tile[tileX, tileY] != null &&
Main.tile[tileX, tileY].active() && Main.tileSolid[Main.tile[tileX, tileY].type] &&
!Main.tile[tileX, tileY].inActive() && !Main.tile[tileX, tileY].halfBrick() &&
Main.tile[tileX, tileY].slope() == 0 && Main.tile[tileX, tileY].type != TileID.Bubble;
}
///
/// Gets a list of items by ID, Name or Tag.
///
/// Item ID, Name or Tag.
/// A list of matching items.
public List- GetItemByIdOrName(string text)
{
int type = -1;
if (Int32.TryParse(text, out type))
{
if (type >= Terraria.ID.ItemID.Count)
return new List
- ();
return new List
- { GetItemById(type) };
}
Item item = GetItemFromTag(text);
if (item != null)
return new List
- () { item };
return GetItemByName(text);
}
///
/// Gets an item by ID
///
/// ID
/// Item
public Item GetItemById(int id)
{
Item item = new Item();
item.netDefaults(id);
return item;
}
///
/// Gets items by name
///
/// name
/// List of Items
public List
- GetItemByName(string name)
{
var startswith = new List();
var contains = new List();
for (int i = 1; i < ItemID.Count; i++)
{
var currentName = Lang.GetItemNameValue(i);
if (!string.IsNullOrEmpty(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List
- { GetItemById(i) };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
currentName = EnglishLanguage.GetItemNameById(i);
if (!string.IsNullOrEmpty(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List
- { GetItemById(i) };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
}
if (startswith.Count != 1)
startswith.AddRange(contains);
return startswith.Select(GetItemById).ToList();
}
///
/// Gets an item based on a chat item tag.
///
/// A tag in the [i/s#/p#:netid] format.
/// The item represented by the tag.
public Item GetItemFromTag(string tag)
{
Regex regex = new Regex(@"\[i(tem)?(?:\/s(?\d{1,4}))?(?:\/p(?\d{1,3}))?:(?-?\d{1,4})\]");
Match match = regex.Match(tag);
if (!match.Success)
return null;
Item item = new Item();
item.netDefaults(Int32.Parse(match.Groups["NetID"].Value));
if (!String.IsNullOrWhiteSpace(match.Groups["Stack"].Value))
item.stack = Int32.Parse(match.Groups["Stack"].Value);
if (!String.IsNullOrWhiteSpace(match.Groups["Prefix"].Value))
item.prefix = Byte.Parse(match.Groups["Prefix"].Value);
return item;
}
///
/// Gets an NPC by ID or Name
///
///
/// List of NPCs
public List GetNPCByIdOrName(string idOrName)
{
int type = -1;
if (int.TryParse(idOrName, out type))
{
if (type >= Terraria.ID.NPCID.Count)
return new List();
return new List { GetNPCById(type) };
}
return GetNPCByName(idOrName);
}
///
/// Gets an NPC by ID
///
/// ID
/// NPC
public NPC GetNPCById(int id)
{
NPC npc = new NPC();
npc.SetDefaults(id);
return npc;
}
///
/// Gets a NPC by name
///
/// Name
/// List of matching NPCs
public List GetNPCByName(string name)
{
var startswith = new List();
var contains = new List();
for (int i = -17; i < NPCID.Count; i++)
{
var currentName = Lang.GetNPCNameValue(i);
if (!string.IsNullOrEmpty(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List { GetNPCById(i) };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
currentName = EnglishLanguage.GetNpcNameById(i);
if (!string.IsNullOrEmpty(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List { GetNPCById(i) };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
}
if (startswith.Count != 1)
startswith.AddRange(contains);
return startswith.Select(GetNPCById).ToList();
}
///
/// Gets a buff name by id
///
/// ID
/// name
public string GetBuffName(int id)
{
return (id > 0 && id < Terraria.ID.BuffID.Count) ? Lang.GetBuffName(id) : null;
}
///
/// Gets the description of a buff
///
/// ID
/// description
public string GetBuffDescription(int id)
{
return (id > 0 && id < Terraria.ID.BuffID.Count) ? Lang.GetBuffDescription(id) : null;
}
///
/// Gets a list of buffs by name
///
/// name
/// Matching list of buff ids
public List GetBuffByName(string name)
{
var startswith = new List();
var contains = new List();
for (int i = 1; i < BuffID.Count; i++)
{
var currentName = Lang.GetBuffName(i);
if (!string.IsNullOrWhiteSpace(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List { i };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
currentName = EnglishLanguage.GetBuffNameById(i);
if (!string.IsNullOrWhiteSpace(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List { i };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
}
if (startswith.Count != 1)
startswith.AddRange(contains);
return startswith;
}
///
/// Gets a prefix based on its id
///
/// ID
/// Prefix name
public string GetPrefixById(int id)
{
return id < FirstItemPrefix || id > LastItemPrefix ? "" : Lang.prefix[id].ToString() ?? "";
}
///
/// Gets a list of prefixes by name
///
/// Name
/// List of prefix IDs
public List GetPrefixByName(string name)
{
var startswith = new List();
var contains = new List();
for (int i = FirstItemPrefix; i <= LastItemPrefix; i++)
{
var currentName = Lang.prefix[i].ToString();
if (!string.IsNullOrWhiteSpace(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List { i };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
currentName = EnglishLanguage.GetPrefixById(i);
if (!string.IsNullOrWhiteSpace(currentName))
{
if (currentName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return new List { i };
if (currentName.StartsWith(name, StringComparison.InvariantCultureIgnoreCase))
{
startswith.Add(i);
continue;
}
if (currentName.Contains(name, StringComparison.InvariantCultureIgnoreCase))
{
contains.Add(i);
continue;
}
}
}
if (startswith.Count != 1)
startswith.AddRange(contains);
return startswith;
}
///
/// Gets a prefix by ID or name
///
/// ID or name
/// List of prefix IDs
public List GetPrefixByIdOrName(string idOrName)
{
int type = -1;
if (int.TryParse(idOrName, out type) && type >= FirstItemPrefix && type <= LastItemPrefix)
{
return new List { type };
}
return GetPrefixByName(idOrName);
}
///
/// Stops the server after kicking all players with a reason message, and optionally saving the world
///
/// bool perform a world save before stop (default: true)
/// string reason (default: "Server shutting down!")
public void StopServer(bool save = true, string reason = "Server shutting down!")
{
TShock.ShuttingDown = true;
if (save)
SaveManager.Instance.SaveWorld();
foreach (var player in TShock.Players.Where(p => p != null))
{
if (player.IsLoggedIn)
{
player.SaveServerCharacter();
}
player.Disconnect(reason);
}
// Broadcast so console can see we are shutting down as well
TShock.Utils.Broadcast(reason, Color.Red);
// Disconnect after kick as that signifies server is exiting and could cause a race
Netplay.Disconnect = true;
}
///
/// Reloads all configuration settings, groups, regions and raises the reload event.
///
public void Reload()
{
FileTools.SetupConfig();
TShock.HandleCommandLinePostConfigLoad(Environment.GetCommandLineArgs());
TShock.Groups.LoadPermisions();
TShock.Regions.Reload();
TShock.ItemBans.DataModel.UpdateItemBans();
TShock.ProjectileBans.UpdateBans();
TShock.TileBans.UpdateBans();
}
///
/// Returns an IPv4 address from a DNS query
///
/// string ip
public string GetIPv4AddressFromHostname(string hostname)
{
try
{
//Get the ipv4 address from GetHostAddresses, if an ip is passed it will return that ip
var ip = Dns.GetHostAddresses(hostname).FirstOrDefault(i => i.AddressFamily == AddressFamily.InterNetwork);
//if the dns query was successful then return it, otherwise return an empty string
return ip != null ? ip.ToString() : "";
}
catch (SocketException)
{
}
return "";
}
///
/// Checks if world has hit the max number of chests
///
/// True if the entire chest array is used
public bool HasWorldReachedMaxChests()
{
for (int i = 0; i < Main.chest.Length; i++)
{
if (Main.chest[i] == null)
return false;
}
return true;
}
///
/// Attempts to parse a string as a timespan (_d_m_h_s).
///
/// The time string.
/// The seconds.
/// Whether the string was parsed successfully.
public bool TryParseTime(string str, out int seconds)
{
seconds = 0;
if (string.IsNullOrWhiteSpace(str))
{
return false;
}
var sb = new StringBuilder(3);
for (int i = 0; i < str.Length; i++)
{
if (char.IsDigit(str[i]) || str[i] == '-' || str[i] == '+' || str[i] == ' ')
sb.Append(str[i]);
else
{
int num;
if (!int.TryParse(sb.ToString(), out num))
return false;
sb.Clear();
switch (str[i])
{
case 's':
seconds += num;
break;
case 'm':
seconds += num * 60;
break;
case 'h':
seconds += num * 60 * 60;
break;
case 'd':
seconds += num * 60 * 60 * 24;
break;
default:
return false;
}
}
}
if (sb.Length != 0)
return false;
return true;
}
///
/// Attempts to parse a string as a positive timespan (_d_m_h_s).
///
/// The time string.
/// The seconds.
/// Whether the string was parsed successfully.
public bool TryParseTime(string str, out ulong seconds)
{
seconds = 0;
if (string.IsNullOrWhiteSpace(str))
{
return false;
}
var sb = new StringBuilder(3);
for (int i = 0; i < str.Length; i++)
{
if (char.IsDigit(str[i]) || str[i] == '-' || str[i] == '+' || str[i] == ' ')
sb.Append(str[i]);
else
{
int num;
if (!int.TryParse(sb.ToString().Trim(' '), out num))
return false;
sb.Clear();
if (num == 0)
{
continue;
}
int numSeconds;
switch (str[i])
{
case 's':
numSeconds = num;
break;
case 'm':
numSeconds = num * 60;
break;
case 'h':
numSeconds = num * 60 * 60;
break;
case 'd':
numSeconds = num * 60 * 60 * 24;
break;
default:
return false;
}
if (numSeconds > 0)
{
if (ulong.MaxValue - seconds < (uint)numSeconds)
{
return false;
}
seconds += (uint)numSeconds;
}
else if (seconds >= (uint)Math.Abs(numSeconds))
{
seconds -= (uint)Math.Abs(numSeconds);
}
else
{
return false;
}
}
}
if (sb.Length != 0)
return false;
return true;
}
///
/// Searches for a projectile by identity and owner
///
/// identity
/// owner
/// projectile ID
public int SearchProjectile(short identity, int owner)
{
for (int i = 0; i < Main.maxProjectiles; i++)
{
if (Main.projectile[i].identity == identity && Main.projectile[i].owner == owner)
return i;
}
return 1000;
}
///
/// Enumerates boundary points of the given region's rectangle.
///
/// The region's area to enumerate through.
/// The enumerated boundary points.
public IEnumerable EnumerateRegionBoundaries(Rectangle regionArea)
{
for (int x = 0; x < regionArea.Width + 1; x++)
{
yield return new Point(regionArea.Left + x, regionArea.Top);
yield return new Point(regionArea.Left + x, regionArea.Bottom);
}
for (int y = 1; y < regionArea.Height; y++)
{
yield return new Point(regionArea.Left, regionArea.Top + y);
yield return new Point(regionArea.Right, regionArea.Top + y);
}
}
/// EncodeColor - Encodes a color as an int.
/// color - The color to encode
/// int? - The encoded color
public int? EncodeColor(Color? color)
{
if (color == null)
return null;
return BitConverter.ToInt32(new[] { color.Value.R, color.Value.G, color.Value.B, color.Value.A }, 0);
}
/// DecodeColor - Decodes a color encoded by the EncodeColor function.
/// encodedColor - The encoded color
/// Color? - The decoded color
public Color? DecodeColor(int? encodedColor)
{
if (encodedColor == null)
return null;
byte[] data = BitConverter.GetBytes(encodedColor.Value);
return new Color(data[0], data[1], data[2], data[3]);
}
///
/// Encodes a Boolean Array as an int.
///
/// The boolean array to encode.
/// The encoded int.
public int? EncodeBoolArray(bool[] bools)
{
if (bools == null)
return null;
int result = 0;
for (int i = 0; i < bools.Length; i++)
if (bools[i])
result |= (1 << i);
return result;
}
///
/// Decodes a Boolean Array from an int.
///
/// The encoded Boolean Array.
/// The resulting Boolean Array.
public bool[] DecodeBoolArray(int? encodedbools)
{
if (encodedbools == null)
return null;
bool[] result = new bool[10];
for (int i = 0; i < result.Length; i++)
result[i] = (encodedbools & 1 << i) != 0;
return result;
}
/// EncodeBitsByte - Encodes a BitsByte as a byte.
/// bitsByte - The BitsByte object
/// byte? - The converted byte
public byte? EncodeBitsByte(BitsByte? bitsByte)
{
if (bitsByte == null)
return null;
byte result = 0;
for (int i = 0; i < 8; i++)
if (bitsByte.Value[i])
result |= (byte)(1 << i);
return result;
}
/// DecodeBitsByte - Decodes a bitsbyte from an int.
/// encodedBitsByte - The encoded bitsbyte object.
/// BitsByte? - The decoded bitsbyte object
public BitsByte? DecodeBitsByte(int? encodedBitsByte)
{
if (encodedBitsByte == null)
return null;
BitsByte result = new BitsByte();
for (int i = 0; i < 8; i++)
result[i] = (encodedBitsByte & 1 << i) != 0;
return result;
}
/// GetResponseNoException - Gets a web response without generating an exception.
/// req - The request to send.
/// HttpWebResponse - The response object.
public HttpWebResponse GetResponseNoException(HttpWebRequest req)
{
try
{
return (HttpWebResponse)req.GetResponse();
}
catch (WebException we)
{
var resp = we.Response as HttpWebResponse;
if (resp == null)
throw;
return resp;
}
}
///
/// Colors the given text by correctly applying the color chat tag.
///
/// The text to color.
/// The color to apply.
/// The , surrounded by the color tag with the appropriated hex code.
public string ColorTag(string text, Color color)
{
return String.Format("[c/{0}:{1}]", color.Hex3(), text);
}
///
/// Converts an item into its text representation using the item chat tag.
///
/// The item to convert.
/// The NetID surrounded by the item tag with proper stack/prefix data.
public string ItemTag(Item item)
{
int netID = item.netID;
int stack = item.stack;
int prefix = item.prefix;
string options = stack > 1 ? "/s" + stack : prefix != 0 ? "/p" + prefix : "";
return String.Format("[i{0}:{1}]", options, netID);
}
///
/// Gets a list of points selected by a mass-wiring tool.
///
/// The starting point for the selection.
/// The ending point for the selection.
/// False if facing left, True if facing right.
///
/// A list of coordinates containing the and
/// points and a list of points between them, forming an L shape based on .
///
public List GetMassWireOperationRange(Point start, Point end, bool direction = false)
{
List points = new List();
#region Tile Selection Logic stolen from Wiring.cs
// Slightly modified version of Wiring.MassWireOperationInner, ignores a player's wire count
int num = Math.Sign(end.X - start.X);
int num2 = Math.Sign(end.Y - start.Y);
Point pt = new Point();
int num3;
int num4;
int num5;
if (direction)
{
pt.X = start.X;
num3 = start.Y;
num4 = end.Y;
num5 = num2;
}
else
{
pt.Y = start.Y;
num3 = start.X;
num4 = end.X;
num5 = num;
}
int num6 = num3;
while (num6 != num4)
{
if (direction)
{
pt.Y = num6;
}
else
{
pt.X = num6;
}
points.Add(pt);
num6 += num5;
}
if (direction)
{
pt.Y = end.Y;
num3 = start.X;
num4 = end.X;
num5 = num;
}
else
{
pt.X = end.X;
num3 = start.Y;
num4 = end.Y;
num5 = num2;
}
int num7 = num3;
while (num7 != num4)
{
if (!direction)
{
pt.Y = num7;
}
else
{
pt.X = num7;
}
points.Add(pt);
num7 += num5;
}
points.Add(end);
#endregion
return points;
}
///
/// Dumps information and optionally exits afterwards
///
///
public void Dump(bool exit = true)
{
PrepareLangForDump();
// Lang.setLang(true);
Directory.CreateDirectory("docs");
Configuration.TShockConfig.DumpDescriptions();
Permissions.DumpDescriptions();
Configuration.ServerSideConfig.DumpDescriptions();
RestManager.DumpDescriptions();
if (exit)
{
Environment.Exit(1);
}
}
internal void PrepareLangForDump()
{
for (int i = 0; i < Main.recipe.Length; i++)
Main.recipe[i] = new Recipe();
}
/// Dumps a matrix of all permissions & all groups in Markdown table format.
/// The save destination.
internal void DumpPermissionMatrix(string path)
{
StringBuilder output = new StringBuilder();
output.Append("|Permission|");
// Traverse to build group name list
foreach (Group g in TShock.Groups.groups)
{
output.Append("[[");
output.Append(g.Name);
output.Append("]]");
output.Append("|");
}
output.AppendLine();
output.Append("|-------|");
foreach (Group g in TShock.Groups.groups)
{
output.Append("-------|");
}
output.AppendLine();
foreach (var field in typeof(Permissions).GetFields().OrderBy(f => f.Name))
{
output.Append("|[[");
output.Append((string)field.GetValue(null));
output.Append("]]|");
foreach (Group g in TShock.Groups.groups)
{
if (g.HasPermission((string)field.GetValue(null)))
{
output.Append("✔|");
}
else
{
output.Append("|");
}
}
output.AppendLine();
}
File.WriteAllText(path, output.ToString());
}
/// Starts an invasion on the server.
/// The invasion type id.
internal void StartInvasion(int type)
{
int invasionSize = 0;
if (TShock.Config.Settings.InfiniteInvasion)
{
// Not really an infinite size
invasionSize = 20000000;
}
else
{
invasionSize = 100 + (TShock.Config.Settings.InvasionMultiplier * GetActivePlayerCount());
}
// Order matters
// StartInvasion will reset the invasion size
Main.StartInvasion(type);
// Note: This is a workaround to previously providing the size as a parameter in StartInvasion
// Have to set start size to report progress correctly
Main.invasionSizeStart = invasionSize;
Main.invasionSize = invasionSize;
}
/// Verifies that each stack in each chest is valid and not over the max stack count.
internal void FixChestStacks()
{
if (TShock.Config.Settings.IgnoreChestStacksOnLoad)
return;
foreach (Chest chest in Main.chest)
{
if (chest != null)
{
foreach (Item item in chest.item)
{
if (item != null && item.stack > item.maxStack)
item.stack = item.maxStack;
}
}
}
}
/// Updates the console title with some pertinent information.
/// If the server is empty; determines if we should use Utils.GetActivePlayerCount() for player count or 0.
internal void SetConsoleTitle(bool empty)
{
Console.Title = GetString("{0}{1}/{2} on {3} @ {4}:{5} (TShock for Terraria v{6})",
!string.IsNullOrWhiteSpace(TShock.Config.Settings.ServerName) ? TShock.Config.Settings.ServerName + " - " : "",
empty ? 0 : GetActivePlayerCount(),
TShock.Config.Settings.MaxSlots, Main.worldName, Netplay.ServerIP.ToString(), Netplay.ListenPort, TShock.VersionNum);
}
/// Determines the distance between two vectors.
/// The first vector location.
/// The second vector location.
/// The distance between the two vectors.
public static float Distance(Vector2 value1, Vector2 value2)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
float num3 = (num2 * num2) + (num * num);
return (float)Math.Sqrt(num3);
}
/// Checks to see if a location is in the spawn protection area.
/// The x coordinate to check.
/// The y coordinate to check.
/// If the given x,y location is in the spawn area.
public static bool IsInSpawn(int x, int y)
{
Vector2 tile = new Vector2(x, y);
Vector2 spawn = new Vector2(Main.spawnTileX, Main.spawnTileY);
return Distance(spawn, tile) <= TShock.Config.Settings.SpawnProtectionRadius;
}
/// Computes the max styles...
internal void ComputeMaxStyles()
{
var item = new Item();
for (int i = 0; i < Terraria.ID.ItemID.Count; 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);
}
}
}
}
}