1498 lines
45 KiB
C#
Executable file
1498 lines
45 KiB
C#
Executable file
/*
|
|
TShock, a server mod for Terraria
|
|
Copyright (C) 2011-2015 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.Diagnostics;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using Terraria;
|
|
using TShockAPI.DB;
|
|
using TShockAPI.Net;
|
|
|
|
namespace TShockAPI
|
|
{
|
|
public class TSPlayer
|
|
{
|
|
/// <summary>
|
|
/// This represents the server as a player.
|
|
/// </summary>
|
|
public static readonly TSServerPlayer Server = new TSServerPlayer();
|
|
|
|
/// <summary>
|
|
/// This player represents all the players.
|
|
/// </summary>
|
|
public static readonly TSPlayer All = new TSPlayer("All");
|
|
|
|
/// <summary>
|
|
/// The amount of tiles that the player has killed in the last second.
|
|
/// </summary>
|
|
public int TileKillThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// The amount of tiles the player has placed in the last second.
|
|
/// </summary>
|
|
public int TilePlaceThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// The amount of liquid (in tiles) that the player has placed in the last second.
|
|
/// </summary>
|
|
public int TileLiquidThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// The amount of tiles that the player has painted in the last second.
|
|
/// </summary>
|
|
public int PaintThreshold { get; set; }
|
|
|
|
/// <summary>
|
|
/// The number of projectiles created by the player in the last second.
|
|
/// </summary>
|
|
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>
|
|
/// Whether to ignore packets that are SSC-relevant.
|
|
/// </summary>
|
|
public bool IgnoreSSCPackets { get; set; }
|
|
|
|
/// <summary>
|
|
/// A system to delay Remembered Position Teleports a few seconds
|
|
/// </summary>
|
|
public int RPPending = 0;
|
|
|
|
public int sX = -1;
|
|
public int sY = -1;
|
|
|
|
/// <summary>
|
|
/// A queue of tiles destroyed by the player for reverting.
|
|
/// </summary>
|
|
public Dictionary<Vector2, Tile> TilesDestroyed { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// A queue of tiles placed by the player for reverting.
|
|
/// </summary>
|
|
public Dictionary<Vector2, Tile> TilesCreated { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// The player's group.
|
|
/// </summary>
|
|
public Group Group
|
|
{
|
|
get
|
|
{
|
|
if (tempGroup != null)
|
|
return tempGroup;
|
|
return group;
|
|
}
|
|
set { group = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The player's temporary group. This overrides the user's actual group.
|
|
/// </summary>
|
|
public Group tempGroup = null;
|
|
|
|
private Group group = null;
|
|
|
|
public bool ReceivedInfo { get; set; }
|
|
|
|
/// <summary>
|
|
/// The players index in the player array( Main.players[] ).
|
|
/// </summary>
|
|
public int Index { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// The last time the player changed their team or pvp status.
|
|
/// </summary>
|
|
public DateTime LastPvPTeamChange;
|
|
|
|
/// <summary>
|
|
/// Temp points for use in regions and other plugins.
|
|
/// </summary>
|
|
public Point[] TempPoints = new Point[2];
|
|
|
|
/// <summary>
|
|
/// Whether the player is waiting to place/break a tile to set as a temp point.
|
|
/// </summary>
|
|
public int AwaitingTempPoint { get; set; }
|
|
|
|
/// <summary>
|
|
/// A list of command callbacks indexed by the command they need to do.
|
|
/// </summary>
|
|
public Dictionary<string, Action<object>> AwaitingResponse;
|
|
|
|
public bool AwaitingName { get; set; }
|
|
|
|
public string[] AwaitingNameParameters { get; set; }
|
|
|
|
/// <summary>
|
|
/// The last time a player broke a grief check.
|
|
/// </summary>
|
|
public DateTime LastThreat { get; set; }
|
|
|
|
public bool InitSpawn;
|
|
|
|
/// <summary>
|
|
/// Whether the player should see logs.
|
|
/// </summary>
|
|
public bool DisplayLogs = true;
|
|
|
|
/// <summary>
|
|
/// The last player that the player whispered with (to or from).
|
|
/// </summary>
|
|
public TSPlayer LastWhisper;
|
|
|
|
/// <summary>
|
|
/// The number of unsuccessful login attempts.
|
|
/// </summary>
|
|
public int LoginAttempts { get; set; }
|
|
|
|
public Vector2 TeleportCoords = new Vector2(-1, -1);
|
|
|
|
public Vector2 LastNetPosition = Vector2.Zero;
|
|
|
|
/// <summary>
|
|
/// The player's login name.
|
|
/// </summary>
|
|
public string UserAccountName { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether the player performed a valid login attempt (i.e. entered valid user name and password) but is still blocked
|
|
/// from logging in because of SSI.
|
|
/// </summary>
|
|
public bool LoginFailsBySsi { get; set; }
|
|
|
|
/// <summary>
|
|
/// Whether the player is logged in or not.
|
|
/// </summary>
|
|
public bool IsLoggedIn;
|
|
|
|
/// <summary>
|
|
/// Whether the player has sent their whole inventory to the server while connecting.
|
|
/// </summary>
|
|
public bool HasSentInventory { get; set; }
|
|
|
|
/// <summary>
|
|
/// The player's user id( from the db ).
|
|
/// </summary>
|
|
public int UserID = -1;
|
|
|
|
/// <summary>
|
|
/// Whether the player has been nagged about logging in.
|
|
/// </summary>
|
|
public bool HasBeenNaggedAboutLoggingIn;
|
|
|
|
public bool TPAllow = true;
|
|
|
|
/// <summary>
|
|
/// Whether the player is muted or not.
|
|
/// </summary>
|
|
public bool mute;
|
|
|
|
private Player FakePlayer;
|
|
|
|
public bool RequestedSection;
|
|
|
|
/// <summary>
|
|
/// The player's respawn timer.
|
|
/// </summary>
|
|
public int RespawnTimer;
|
|
|
|
/// <summary>
|
|
/// Whether the player is dead or not.
|
|
/// </summary>
|
|
public bool Dead;
|
|
|
|
public string Country = "??";
|
|
|
|
/// <summary>
|
|
/// The players difficulty( normal[softcore], mediumcore, hardcore ).
|
|
/// </summary>
|
|
public int Difficulty;
|
|
|
|
private string CacheIP;
|
|
|
|
public string IgnoreActionsForInventory = "none";
|
|
|
|
public string IgnoreActionsForCheating = "none";
|
|
|
|
public string IgnoreActionsForDisabledArmor = "none";
|
|
|
|
public bool IgnoreActionsForClearingTrashCan;
|
|
|
|
/// <summary>
|
|
/// The player's server side inventory data.
|
|
/// </summary>
|
|
public PlayerData PlayerData;
|
|
|
|
/// <summary>
|
|
/// Whether the player needs to specify a password upon connection( either server or user account ).
|
|
/// </summary>
|
|
public bool RequiresPassword;
|
|
|
|
public bool SilentKickInProgress;
|
|
|
|
public bool SilentJoinInProgress;
|
|
|
|
/// <summary>
|
|
/// A list of points where ice tiles have been placed.
|
|
/// </summary>
|
|
public List<Point> IceTiles;
|
|
|
|
/// <summary>
|
|
/// Unused, can be removed.
|
|
/// </summary>
|
|
public long RPm = 1;
|
|
|
|
/// <summary>
|
|
/// World protection message cool down.
|
|
/// </summary>
|
|
public long WPm = 1;
|
|
|
|
/// <summary>
|
|
/// Spawn protection message cool down.
|
|
/// </summary>
|
|
public long SPm = 1;
|
|
|
|
/// <summary>
|
|
/// Permission to build message cool down.
|
|
/// </summary>
|
|
public long BPm = 1;
|
|
|
|
/// <summary>
|
|
/// The time in ms when the player has logged in.
|
|
/// </summary>
|
|
public long LoginMS;
|
|
|
|
/// <summary>
|
|
/// Whether the player has been harrassed about logging in due to server side inventory or forced login.
|
|
/// </summary>
|
|
public bool LoginHarassed = false;
|
|
|
|
/// <summary>
|
|
/// Player cant die, unless onehit
|
|
/// </summary>
|
|
public bool GodMode = false;
|
|
|
|
/// <summary>
|
|
/// Players controls are inverted if using SSC
|
|
/// </summary>
|
|
public bool Confused = false;
|
|
|
|
/// <summary>
|
|
/// The last projectile type this player tried to kill.
|
|
/// </summary>
|
|
public int LastKilledProjectile = 0;
|
|
|
|
/// <summary>
|
|
/// Whether the player is a real, human, player on the server.
|
|
/// </summary>
|
|
public bool RealPlayer
|
|
{
|
|
get { return Index >= 0 && Index < Main.maxNetPlayers && Main.player[Index] != null; }
|
|
}
|
|
|
|
public bool ConnectionAlive
|
|
{
|
|
get
|
|
{
|
|
return RealPlayer &&
|
|
(Netplay.serverSock[Index] != null && Netplay.serverSock[Index].active && !Netplay.serverSock[Index].kill);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the player's selected item.
|
|
/// </summary>
|
|
public Item SelectedItem
|
|
{
|
|
get { return TPlayer.inventory[TPlayer.selectedItem]; }
|
|
}
|
|
|
|
public int State
|
|
{
|
|
get { return Netplay.serverSock[Index].state; }
|
|
set { Netplay.serverSock[Index].state = value; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the player's UUID.
|
|
/// </summary>
|
|
public string UUID
|
|
{
|
|
get { return RealPlayer ? Netplay.serverSock[Index].clientUUID : ""; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the player's IP.
|
|
/// </summary>
|
|
public string IP
|
|
{
|
|
get
|
|
{
|
|
if (string.IsNullOrEmpty(CacheIP))
|
|
return
|
|
CacheIP =
|
|
RealPlayer
|
|
? (Netplay.serverSock[Index].tcpClient.Connected
|
|
? TShock.Utils.GetRealIP(Netplay.serverSock[Index].tcpClient.Client.RemoteEndPoint.ToString())
|
|
: "")
|
|
: "";
|
|
else
|
|
return CacheIP;
|
|
}
|
|
}
|
|
|
|
public IEnumerable<Item> Accessories
|
|
{
|
|
get
|
|
{
|
|
for (int i = 3; i < 8; i++)
|
|
yield return TPlayer.armor[i];
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves the player's inventory to SSI
|
|
/// </summary>
|
|
/// <returns>bool - True/false if it saved successfully</returns>
|
|
public bool SaveServerCharacter()
|
|
{
|
|
if (!Main.ServerSideCharacter)
|
|
{
|
|
return false;
|
|
}
|
|
try
|
|
{
|
|
PlayerData.CopyCharacter(this);
|
|
TShock.CharacterDB.InsertPlayerData(this);
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TShock.Log.Error(e.Message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sends the players server side character to client
|
|
/// </summary>
|
|
/// <returns>bool - True/false if it saved successfully</returns>
|
|
public bool SendServerCharacter()
|
|
{
|
|
if (!Main.ServerSideCharacter)
|
|
{
|
|
return false;
|
|
}
|
|
try
|
|
{
|
|
PlayerData.RestoreCharacter(this);
|
|
return true;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TShock.Log.Error(e.Message);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Terraria Player
|
|
/// </summary>
|
|
public Player TPlayer
|
|
{
|
|
get { return FakePlayer ?? Main.player[Index]; }
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return TPlayer.name; }
|
|
}
|
|
|
|
public bool Active
|
|
{
|
|
get { return TPlayer != null && TPlayer.active; }
|
|
}
|
|
|
|
public int Team
|
|
{
|
|
get { return TPlayer.team; }
|
|
}
|
|
|
|
public float X
|
|
{
|
|
get { return RealPlayer ? TPlayer.position.X : Main.spawnTileX*16; }
|
|
}
|
|
|
|
public float Y
|
|
{
|
|
get { return RealPlayer ? TPlayer.position.Y : Main.spawnTileY*16; }
|
|
}
|
|
|
|
public int TileX
|
|
{
|
|
get { return (int) (X/16); }
|
|
}
|
|
|
|
public int TileY
|
|
{
|
|
get { return (int) (Y/16); }
|
|
}
|
|
|
|
public bool TpLock;
|
|
|
|
public bool InventorySlotAvailable
|
|
{
|
|
get
|
|
{
|
|
bool flag = false;
|
|
if (RealPlayer)
|
|
{
|
|
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 == "")
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return flag;
|
|
}
|
|
}
|
|
|
|
public TSPlayer(int index)
|
|
{
|
|
TilesDestroyed = new Dictionary<Vector2, Tile>();
|
|
TilesCreated = new Dictionary<Vector2, Tile>();
|
|
Index = index;
|
|
Group = Group.DefaultGroup;
|
|
IceTiles = new List<Point>();
|
|
AwaitingResponse = new Dictionary<string, Action<object>>();
|
|
}
|
|
|
|
protected TSPlayer(String playerName)
|
|
{
|
|
TilesDestroyed = new Dictionary<Vector2, Tile>();
|
|
TilesCreated = new Dictionary<Vector2, Tile>();
|
|
Index = -1;
|
|
FakePlayer = new Player {name = playerName, whoAmi = -1};
|
|
Group = Group.DefaultGroup;
|
|
AwaitingResponse = new Dictionary<string, Action<object>>();
|
|
}
|
|
|
|
public virtual void Disconnect(string reason)
|
|
{
|
|
SendData(PacketTypes.Disconnect, reason);
|
|
}
|
|
|
|
public virtual void Flush()
|
|
{
|
|
var sock = Netplay.serverSock[Index];
|
|
if (sock == null)
|
|
return;
|
|
|
|
TShock.PacketBuffer.Flush(sock);
|
|
}
|
|
|
|
|
|
public void SendWorldInfo(int tilex, int tiley, bool fakeid)
|
|
{
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
var msg = new WorldInfoMsg
|
|
{
|
|
Time = (int)Main.time,
|
|
DayTime = Main.dayTime,
|
|
MoonPhase = (byte)Main.moonPhase,
|
|
BloodMoon = Main.bloodMoon,
|
|
Eclipse = Main.eclipse,
|
|
MaxTilesX = (short)Main.maxTilesX,
|
|
MaxTilesY = (short)Main.maxTilesY,
|
|
SpawnX = (short)Main.spawnTileX,
|
|
SpawnY = (short)Main.spawnTileY,
|
|
WorldSurface = (short)Main.worldSurface,
|
|
RockLayer = (short)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,
|
|
MoonType = (byte)Main.moonType,
|
|
TreeX0 = Main.treeX[0],
|
|
TreeX1 = Main.treeX[1],
|
|
TreeX2 = Main.treeX[2],
|
|
TreeStyle0 = (byte)Main.treeStyle[0],
|
|
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) |
|
|
(Main.ServerSideCharacter ? BossFlags.ServerSideCharacter : BossFlags.None) |
|
|
(NPC.downedPlantBoss ? BossFlags.DownedPlantBoss : 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) |
|
|
(Main.pumpkinMoon ? BossFlags2.PumpkinMoon : BossFlags2.None) |
|
|
(Main.snowMoon ? BossFlags2.SnowMoon : BossFlags2.None),
|
|
Rain = Main.maxRaining,
|
|
WorldName = TShock.Config.UseServerName ? TShock.Config.ServerName : Main.worldName
|
|
};
|
|
msg.PackFull(ms);
|
|
SendRawData(ms.ToArray());
|
|
}
|
|
}
|
|
|
|
public bool Teleport(float x, float y, byte style = 1)
|
|
{
|
|
if (x > Main.rightWorld - 992)
|
|
{
|
|
x = Main.rightWorld - 992;
|
|
}
|
|
if (x < 992)
|
|
{
|
|
x = 992;
|
|
}
|
|
if (y > Main.bottomWorld - 992)
|
|
{
|
|
y = Main.bottomWorld - 992;
|
|
}
|
|
if (y < 992)
|
|
{
|
|
y = 992;
|
|
}
|
|
|
|
SendTileSquare((int) (x/16), (int) (y/16), 15);
|
|
TPlayer.Teleport(new Vector2(x, y), style);
|
|
NetMessage.SendData((int)PacketTypes.Teleport, -1, -1, "", 0, TPlayer.whoAmi, x, y, style);
|
|
return true;
|
|
}
|
|
|
|
public void Heal(int health = 600)
|
|
{
|
|
NetMessage.SendData((int)PacketTypes.PlayerHealOther, -1, -1, "", this.TPlayer.whoAmi, health);
|
|
}
|
|
|
|
public void Spawn()
|
|
{
|
|
if (this.sX > 0 && this.sY > 0)
|
|
{
|
|
Spawn(this.sX, this.sY);
|
|
}
|
|
else
|
|
{
|
|
Spawn(TPlayer.SpawnX, TPlayer.SpawnY);
|
|
}
|
|
}
|
|
|
|
public void Spawn(int tilex, int tiley)
|
|
{
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
var msg = new SpawnMsg
|
|
{
|
|
PlayerIndex = (byte) Index,
|
|
TileX = (short)tilex,
|
|
TileY = (short)tiley
|
|
};
|
|
msg.PackFull(ms);
|
|
SendRawData(ms.ToArray());
|
|
}
|
|
}
|
|
|
|
public void RemoveProjectile(int index, int owner)
|
|
{
|
|
using (var ms = new MemoryStream())
|
|
{
|
|
var msg = new ProjectileRemoveMsg
|
|
{
|
|
Index = (short) index,
|
|
Owner = (byte) owner
|
|
};
|
|
msg.PackFull(ms);
|
|
SendRawData(ms.ToArray());
|
|
}
|
|
}
|
|
|
|
public virtual bool SendTileSquare(int x, int y, int size = 10)
|
|
{
|
|
try
|
|
{
|
|
int num = (size - 1)/2;
|
|
int m_x = 0;
|
|
int m_y = 0;
|
|
|
|
if (x - num < 0)
|
|
{
|
|
m_x = 0;
|
|
}
|
|
else
|
|
{
|
|
m_x = x - num;
|
|
}
|
|
|
|
if (y - num < 0)
|
|
{
|
|
m_y = 0;
|
|
}
|
|
else
|
|
{
|
|
m_y = y - num;
|
|
}
|
|
|
|
if (m_x + size > Main.maxTilesX)
|
|
{
|
|
m_x = Main.maxTilesX - size;
|
|
}
|
|
|
|
if (m_y + size > Main.maxTilesY)
|
|
{
|
|
m_y = Main.maxTilesY - size;
|
|
}
|
|
|
|
SendData(PacketTypes.TileSendSquare, "", size, m_x, m_y);
|
|
return true;
|
|
}
|
|
catch (IndexOutOfRangeException)
|
|
{
|
|
// This is expected if square exceeds array.
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
TShock.Log.Error(ex.ToString());
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public bool GiveItemCheck(int type, string name, int width, int height, int stack, int prefix = 0)
|
|
{
|
|
if ((TShock.Itembans.ItemIsBanned(name) && TShock.Config.PreventBannedItemSpawn) &&
|
|
(TShock.Itembans.ItemIsBanned(name, this) || !TShock.Config.AllowAllowedGroupsToSpawnBannedItems))
|
|
return false;
|
|
|
|
GiveItem(type,name,width,height,stack,prefix);
|
|
return true;
|
|
}
|
|
|
|
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, true);
|
|
|
|
// This is for special pickaxe/hammers/swords etc
|
|
Main.item[itemid].SetDefaults(name);
|
|
// The set default overrides the wet and stack set by NewItem
|
|
Main.item[itemid].wet = Collision.WetCollision(Main.item[itemid].position, Main.item[itemid].width,
|
|
Main.item[itemid].height);
|
|
Main.item[itemid].stack = stack;
|
|
Main.item[itemid].owner = Index;
|
|
Main.item[itemid].prefix = (byte) prefix;
|
|
Main.item[itemid].noGrabDelay = 1;
|
|
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)
|
|
{
|
|
SendMessage(msg, Color.Yellow);
|
|
}
|
|
|
|
public void SendInfoMessage(string format, params object[] args)
|
|
{
|
|
SendInfoMessage(string.Format(format, args));
|
|
}
|
|
|
|
public virtual void SendSuccessMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.Green);
|
|
}
|
|
|
|
public void SendSuccessMessage(string format, params object[] args)
|
|
{
|
|
SendSuccessMessage(string.Format(format, args));
|
|
}
|
|
|
|
public virtual void SendWarningMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.OrangeRed);
|
|
}
|
|
|
|
public void SendWarningMessage(string format, params object[] args)
|
|
{
|
|
SendWarningMessage(string.Format(format, args));
|
|
}
|
|
|
|
public virtual void SendErrorMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.Red);
|
|
}
|
|
|
|
public void SendErrorMessage(string format, params object[] args)
|
|
{
|
|
SendErrorMessage(string.Format(format, args));
|
|
}
|
|
|
|
public virtual void SendMessage(string msg, Color color)
|
|
{
|
|
SendMessage(msg, color.R, color.G, color.B);
|
|
}
|
|
|
|
public virtual void SendMessage(string msg, byte red, byte green, byte blue)
|
|
{
|
|
SendData(PacketTypes.ChatText, msg, 255, red, green, blue);
|
|
}
|
|
|
|
public virtual void SendMessageFromPlayer(string msg, byte red, byte green, byte blue, int ply)
|
|
{
|
|
SendDataFromPlayer(PacketTypes.ChatText, ply, msg, red, green, blue, 0);
|
|
}
|
|
|
|
public virtual void DamagePlayer(int damage)
|
|
{
|
|
NetMessage.SendData((int) PacketTypes.PlayerDamage, -1, -1, "", Index, ((new Random()).Next(-1, 1)), damage,
|
|
(float) 0);
|
|
}
|
|
|
|
public virtual void SetTeam(int team)
|
|
{
|
|
Main.player[Index].team = team;
|
|
SendData(PacketTypes.PlayerTeam, "", Index);
|
|
}
|
|
|
|
private DateTime LastDisableNotification = DateTime.UtcNow;
|
|
public int ActiveChest = -1;
|
|
public Item ItemInHand = new Item();
|
|
|
|
public virtual void Disable(string reason = "", bool displayConsole = true)
|
|
{
|
|
LastThreat = DateTime.UtcNow;
|
|
SetBuff(33, 330, true); //Weak
|
|
SetBuff(32, 330, true); //Slow
|
|
SetBuff(23, 330, true); //Cursed
|
|
SetBuff(47, 330, true); //Frozen
|
|
|
|
if (ActiveChest != -1)
|
|
{
|
|
SendData(PacketTypes.ChestOpen, "", -1);
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(reason))
|
|
{
|
|
if ((DateTime.UtcNow - LastDisableNotification).TotalMilliseconds > 5000)
|
|
{
|
|
if (displayConsole)
|
|
{
|
|
TShock.Log.ConsoleInfo("Player {0} has been disabled for {1}.", Name, reason);
|
|
}
|
|
else
|
|
{
|
|
TShock.Log.Info("Player {0} has been disabled for {1}.", Name, reason);
|
|
}
|
|
LastDisableNotification = DateTime.UtcNow;
|
|
}
|
|
}
|
|
var trace = new StackTrace();
|
|
StackFrame frame = null;
|
|
frame = trace.GetFrame(1);
|
|
if (frame != null && frame.GetMethod().DeclaringType != null)
|
|
TShock.Log.Debug(frame.GetMethod().DeclaringType.Name + " called Disable().");
|
|
}
|
|
|
|
public virtual void Whoopie(object time)
|
|
{
|
|
var time2 = (int) time;
|
|
var launch = DateTime.UtcNow;
|
|
var startname = Name;
|
|
SendInfoMessage("You are now being annoyed.");
|
|
while ((DateTime.UtcNow - launch).TotalSeconds < time2 && startname == Name)
|
|
{
|
|
SendData(PacketTypes.NpcSpecial, number: Index, number2: 2f);
|
|
Thread.Sleep(50);
|
|
}
|
|
}
|
|
|
|
public virtual void SetBuff(int type, int time = 3600, bool bypass = false)
|
|
{
|
|
if ((DateTime.UtcNow - LastThreat).TotalMilliseconds < 5000 && !bypass)
|
|
return;
|
|
|
|
SendData(PacketTypes.PlayerAddBuff, number: Index, number2: type, number3: time);
|
|
}
|
|
|
|
//Todo: Separate this into a few functions. SendTo, SendToAll, etc
|
|
public virtual void SendData(PacketTypes msgType, string text = "", int number = 0, float number2 = 0f,
|
|
float number3 = 0f, float number4 = 0f, int number5 = 0)
|
|
{
|
|
if (RealPlayer && !ConnectionAlive)
|
|
return;
|
|
|
|
NetMessage.SendData((int) msgType, Index, -1, text, number, number2, number3, number4, number5);
|
|
}
|
|
|
|
public virtual void SendDataFromPlayer(PacketTypes msgType, int ply, string text = "", float number2 = 0f, float number3 = 0f, float number4 = 0f, int number5 = 0)
|
|
{
|
|
if (RealPlayer && !ConnectionAlive)
|
|
return;
|
|
|
|
NetMessage.SendData((int) msgType, Index, -1, text, ply, number2, number3, number4, number5);
|
|
}
|
|
|
|
public virtual void SendRawData(byte[] data)
|
|
{
|
|
if (!RealPlayer || !ConnectionAlive)
|
|
return;
|
|
NetMessage.SendBytes(Netplay.serverSock[Index], data, 0, data.Length, Netplay.serverSock[Index].ServerWriteCallBack, Netplay.serverSock[Index].networkStream);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a command callback to a specified command string.
|
|
/// </summary>
|
|
/// <param name="name">The string representing the command i.e "yes" == /yes</param>
|
|
/// <param name="callback">The method that will be executed on confirmation ie user accepts</param>
|
|
public void AddResponse( string name, Action<object> callback)
|
|
{
|
|
if( AwaitingResponse.ContainsKey(name))
|
|
{
|
|
AwaitingResponse.Remove(name);
|
|
}
|
|
|
|
AwaitingResponse.Add(name, callback);
|
|
}
|
|
}
|
|
|
|
public class TSRestPlayer : TSPlayer
|
|
{
|
|
internal List<string> CommandOutput = new List<string>();
|
|
|
|
public TSRestPlayer(string playerName, Group playerGroup): base(playerName)
|
|
{
|
|
Group = playerGroup;
|
|
AwaitingResponse = new Dictionary<string, Action<object>>();
|
|
}
|
|
|
|
public override void SendMessage(string msg, Color color)
|
|
{
|
|
SendInfoMessage(msg, color.R, color.G, color.B);
|
|
}
|
|
|
|
public override void SendMessage(string msg, byte red, byte green, byte blue)
|
|
{
|
|
this.CommandOutput.Add(msg);
|
|
}
|
|
|
|
public override void SendInfoMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.Yellow);
|
|
}
|
|
|
|
public override void SendSuccessMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.Green);
|
|
}
|
|
|
|
public override void SendWarningMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.OrangeRed);
|
|
}
|
|
|
|
public override void SendErrorMessage(string msg)
|
|
{
|
|
SendMessage(msg, Color.Red);
|
|
}
|
|
|
|
public List<string> GetCommandOutput()
|
|
{
|
|
return this.CommandOutput;
|
|
}
|
|
}
|
|
|
|
public class TSServerPlayer : TSPlayer
|
|
{
|
|
public static string AccountName = "ServerConsole";
|
|
public TSServerPlayer()
|
|
: base("Server")
|
|
{
|
|
Group = new SuperAdminGroup();
|
|
UserAccountName = AccountName;
|
|
}
|
|
|
|
public override void SendErrorMessage(string msg)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Red;
|
|
Console.WriteLine(msg);
|
|
Console.ResetColor();
|
|
}
|
|
|
|
public override void SendInfoMessage(string msg)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Yellow;
|
|
Console.WriteLine(msg);
|
|
Console.ResetColor();
|
|
}
|
|
|
|
public override void SendSuccessMessage(string msg)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.Green;
|
|
Console.WriteLine(msg);
|
|
Console.ResetColor();
|
|
}
|
|
|
|
public override void SendWarningMessage(string msg)
|
|
{
|
|
Console.ForegroundColor = ConsoleColor.DarkRed;
|
|
Console.WriteLine(msg);
|
|
Console.ResetColor();
|
|
}
|
|
|
|
public override void SendMessage(string msg, Color color)
|
|
{
|
|
SendMessage(msg, color.R, color.G, color.B);
|
|
}
|
|
|
|
public override void SendMessage(string msg, byte red, byte green, byte blue)
|
|
{
|
|
Console.WriteLine(msg);
|
|
}
|
|
|
|
public void SetFullMoon()
|
|
{
|
|
Main.dayTime = false;
|
|
Main.moonPhase = 0;
|
|
Main.time = 0.0;
|
|
TSPlayer.All.SendData(PacketTypes.WorldInfo);
|
|
}
|
|
|
|
public void SetBloodMoon(bool bloodMoon)
|
|
{
|
|
if (bloodMoon)
|
|
{
|
|
Main.dayTime = false;
|
|
Main.bloodMoon = true;
|
|
Main.time = 0.0;
|
|
}
|
|
else
|
|
Main.bloodMoon = false;
|
|
TSPlayer.All.SendData(PacketTypes.WorldInfo);
|
|
}
|
|
|
|
public void SetFrostMoon(bool snowMoon)
|
|
{
|
|
if (snowMoon)
|
|
{
|
|
Main.dayTime = false;
|
|
Main.snowMoon = true;
|
|
Main.time = 0.0;
|
|
}
|
|
else
|
|
Main.snowMoon = false;
|
|
TSPlayer.All.SendData(PacketTypes.WorldInfo);
|
|
}
|
|
|
|
public void SetPumpkinMoon(bool pumpkinMoon)
|
|
{
|
|
if (pumpkinMoon)
|
|
{
|
|
Main.dayTime = false;
|
|
Main.pumpkinMoon = true;
|
|
Main.time = 0.0;
|
|
}
|
|
else
|
|
Main.pumpkinMoon = false;
|
|
TSPlayer.All.SendData(PacketTypes.WorldInfo);
|
|
}
|
|
|
|
public void SetEclipse(bool eclipse)
|
|
{
|
|
if (eclipse)
|
|
{
|
|
Main.dayTime = Main.eclipse = true;
|
|
Main.time = 0.0;
|
|
}
|
|
else
|
|
Main.eclipse = false;
|
|
TSPlayer.All.SendData(PacketTypes.WorldInfo);
|
|
}
|
|
|
|
public void SetTime(bool dayTime, double time)
|
|
{
|
|
Main.dayTime = dayTime;
|
|
Main.time = time;
|
|
TSPlayer.All.SendData(PacketTypes.TimeSet, "", 0, 0, Main.sunModY, Main.moonModY);
|
|
}
|
|
|
|
public void SpawnNPC(int type, string name, int amount, int startTileX, int startTileY, int tileXRange = 100,
|
|
int tileYRange = 50)
|
|
{
|
|
for (int i = 0; i < amount; i++)
|
|
{
|
|
int spawnTileX;
|
|
int spawnTileY;
|
|
TShock.Utils.GetRandomClearTileWithInRange(startTileX, startTileY, tileXRange, tileYRange, out spawnTileX,
|
|
out spawnTileY);
|
|
int npcid = NPC.NewNPC(spawnTileX*16, spawnTileY*16, type, 0);
|
|
// This is for special slimes
|
|
Main.npc[npcid].SetDefaults(name);
|
|
}
|
|
}
|
|
|
|
public void StrikeNPC(int npcid, int damage, float knockBack, int hitDirection)
|
|
{
|
|
// Main.rand is thread static.
|
|
if (Main.rand == null)
|
|
Main.rand = new Random();
|
|
|
|
Main.npc[npcid].StrikeNPC(damage, knockBack, hitDirection);
|
|
NetMessage.SendData((int) PacketTypes.NpcStrike, -1, -1, "", npcid, damage, knockBack, hitDirection);
|
|
}
|
|
|
|
public void RevertTiles(Dictionary<Vector2, Tile> tiles)
|
|
{
|
|
// Update Main.Tile first so that when tile sqaure is sent it is correct
|
|
foreach (KeyValuePair<Vector2, Tile> entry in tiles)
|
|
{
|
|
Main.tile[(int) entry.Key.X, (int) entry.Key.Y] = entry.Value;
|
|
}
|
|
// Send all players updated tile sqaures
|
|
foreach (Vector2 coords in tiles.Keys)
|
|
{
|
|
All.SendTileSquare((int) coords.X, (int) coords.Y, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class PlayerData
|
|
{
|
|
public NetItem[] inventory = new NetItem[NetItem.maxNetInventory];
|
|
public int health = TShock.ServerSideCharacterConfig.StartingHealth;
|
|
public int maxHealth = TShock.ServerSideCharacterConfig.StartingHealth;
|
|
public int mana = TShock.ServerSideCharacterConfig.StartingMana;
|
|
public int maxMana = TShock.ServerSideCharacterConfig.StartingMana;
|
|
public bool exists;
|
|
public int spawnX= -1;
|
|
public int spawnY= -1;
|
|
public int? hair;
|
|
public byte hairDye;
|
|
public Color? hairColor;
|
|
public Color? pantsColor;
|
|
public Color? shirtColor;
|
|
public Color? underShirtColor;
|
|
public Color? shoeColor;
|
|
public Color? skinColor;
|
|
public Color? eyeColor;
|
|
public BitsByte? hideVisuals;
|
|
public int questsCompleted;
|
|
|
|
public PlayerData(TSPlayer player)
|
|
{
|
|
for (int i = 0; i < NetItem.maxNetInventory; i++)
|
|
{
|
|
this.inventory[i] = new NetItem();
|
|
}
|
|
this.inventory[0].netID = -15;
|
|
this.inventory[0].stack = 1;
|
|
if (player.TPlayer.inventory[0] != null && player.TPlayer.inventory[0].netID == -15)
|
|
this.inventory[0].prefix = player.TPlayer.inventory[0].prefix;
|
|
this.inventory[1].netID = -13;
|
|
this.inventory[1].stack = 1;
|
|
if (player.TPlayer.inventory[1] != null && player.TPlayer.inventory[1].netID == -13)
|
|
this.inventory[1].prefix = player.TPlayer.inventory[1].prefix;
|
|
this.inventory[2].netID = -16;
|
|
this.inventory[2].stack = 1;
|
|
if (player.TPlayer.inventory[2] != null && player.TPlayer.inventory[2].netID == -16)
|
|
this.inventory[2].prefix = player.TPlayer.inventory[2].prefix;
|
|
|
|
for (int i = 0; i < TShock.ServerSideCharacterConfig.StartingInventory.Count; i++)
|
|
{
|
|
var item = TShock.ServerSideCharacterConfig.StartingInventory[i];
|
|
StoreSlot(i, item.netID, item.prefix, item.stack);
|
|
}
|
|
}
|
|
|
|
public void StoreSlot(int slot, int netID, int prefix, int stack)
|
|
{
|
|
if(slot > (this.inventory.Length - 1)) //if the slot is out of range then dont save
|
|
{
|
|
return;
|
|
}
|
|
|
|
this.inventory[slot].netID = netID;
|
|
if (this.inventory[slot].netID != 0)
|
|
{
|
|
this.inventory[slot].stack = stack;
|
|
this.inventory[slot].prefix = prefix;
|
|
}
|
|
else
|
|
{
|
|
this.inventory[slot].stack = 0;
|
|
this.inventory[slot].prefix = 0;
|
|
}
|
|
}
|
|
|
|
public void CopyCharacter(TSPlayer player)
|
|
{
|
|
this.health = player.TPlayer.statLife > 0 ? player.TPlayer.statLife : 1;
|
|
this.maxHealth = player.TPlayer.statLifeMax;
|
|
this.mana = player.TPlayer.statMana;
|
|
this.maxMana = player.TPlayer.statManaMax;
|
|
if (player.sX > 0 && player.sY > 0)
|
|
{
|
|
this.spawnX = player.sX;
|
|
this.spawnY = player.sY;
|
|
}
|
|
else
|
|
{
|
|
this.spawnX = player.TPlayer.SpawnX;
|
|
this.spawnY = player.TPlayer.SpawnY;
|
|
}
|
|
this.hair = player.TPlayer.hair;
|
|
this.hairDye = player.TPlayer.hairDye;
|
|
this.hairColor = player.TPlayer.hairColor;
|
|
this.pantsColor = player.TPlayer.pantsColor;
|
|
this.shirtColor = player.TPlayer.shirtColor;
|
|
this.underShirtColor = player.TPlayer.underShirtColor;
|
|
this.shoeColor = player.TPlayer.shoeColor;
|
|
this.hideVisuals = player.TPlayer.hideVisual;
|
|
this.skinColor = player.TPlayer.skinColor;
|
|
this.eyeColor = player.TPlayer.eyeColor;
|
|
this.questsCompleted = player.TPlayer.anglerQuestsFinished;
|
|
|
|
Item[] inventory = player.TPlayer.inventory;
|
|
Item[] armor = player.TPlayer.armor;
|
|
Item[] dye = player.TPlayer.dye;
|
|
for (int i = 0; i < NetItem.maxNetInventory; i++)
|
|
{
|
|
if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
|
|
{
|
|
if (player.TPlayer.inventory[i] != null)
|
|
{
|
|
this.inventory[i].netID = inventory[i].netID;
|
|
}
|
|
else
|
|
{
|
|
this.inventory[i].netID = 0;
|
|
}
|
|
|
|
if (this.inventory[i].netID != 0)
|
|
{
|
|
this.inventory[i].stack = inventory[i].stack;
|
|
this.inventory[i].prefix = inventory[i].prefix;
|
|
}
|
|
else
|
|
{
|
|
this.inventory[i].stack = 0;
|
|
this.inventory[i].prefix = 0;
|
|
}
|
|
}
|
|
else if (i < NetItem.maxNetInventory - NetItem.dyeSlots)
|
|
{
|
|
var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
|
|
if (player.TPlayer.armor[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
|
|
{
|
|
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 = dye[index].netID;
|
|
}
|
|
else
|
|
{
|
|
this.inventory[i].netID = 0;
|
|
}
|
|
|
|
if (this.inventory[i].netID != 0)
|
|
{
|
|
this.inventory[i].stack = dye[index].stack;
|
|
this.inventory[i].prefix = dye[index].prefix;
|
|
}
|
|
else
|
|
{
|
|
this.inventory[i].stack = 0;
|
|
this.inventory[i].prefix = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RestoreCharacter(TSPlayer player)
|
|
{
|
|
// Start ignoring SSC-related packets! This is critical so that we don't send or receive dirty data!
|
|
player.IgnoreSSCPackets = true;
|
|
|
|
player.TPlayer.statLife = this.health;
|
|
player.TPlayer.statLifeMax = this.maxHealth;
|
|
player.TPlayer.statMana = this.maxMana;
|
|
player.TPlayer.statManaMax = this.maxMana;
|
|
player.TPlayer.SpawnX = this.spawnX;
|
|
player.TPlayer.SpawnY = this.spawnY;
|
|
player.sX = this.spawnX;
|
|
player.sY = this.spawnY;
|
|
player.TPlayer.hairDye = this.hairDye;
|
|
player.TPlayer.anglerQuestsFinished = this.questsCompleted;
|
|
|
|
if (this.hair != null)
|
|
player.TPlayer.hair = this.hair.Value;
|
|
if (this.hairColor != null)
|
|
player.TPlayer.hairColor = this.hairColor.Value;
|
|
if (this.pantsColor != null)
|
|
player.TPlayer.pantsColor = this.pantsColor.Value;
|
|
if (this.shirtColor != null)
|
|
player.TPlayer.shirtColor = this.shirtColor.Value;
|
|
if (this.underShirtColor != null)
|
|
player.TPlayer.underShirtColor = this.underShirtColor.Value;
|
|
if (this.shoeColor != null)
|
|
player.TPlayer.shoeColor = this.shoeColor.Value;
|
|
if (this.skinColor != null)
|
|
player.TPlayer.skinColor = this.skinColor.Value;
|
|
if (this.eyeColor != null)
|
|
player.TPlayer.eyeColor = this.eyeColor.Value;
|
|
|
|
if (this.hideVisuals != null)
|
|
player.TPlayer.hideVisual = this.hideVisuals.Value;
|
|
else
|
|
player.TPlayer.hideVisual.ClearAll();
|
|
|
|
for (int i = 0; i < NetItem.maxNetInventory; i++)
|
|
{
|
|
if (i < NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots))
|
|
{
|
|
if (this.inventory[i] != null)
|
|
{
|
|
player.TPlayer.inventory[i].netDefaults(this.inventory[i].netID);
|
|
}
|
|
else
|
|
{
|
|
player.TPlayer.inventory[i].netDefaults(0);
|
|
}
|
|
|
|
if (player.TPlayer.inventory[i].netID != 0)
|
|
{
|
|
player.TPlayer.inventory[i].stack = this.inventory[i].stack;
|
|
player.TPlayer.inventory[i].prefix = (byte)this.inventory[i].prefix;
|
|
}
|
|
}
|
|
else if (i < NetItem.maxNetInventory - NetItem.dyeSlots)
|
|
{
|
|
var index = i - (NetItem.maxNetInventory - (NetItem.armorSlots + NetItem.dyeSlots));
|
|
if (this.inventory[i] != null)
|
|
{
|
|
player.TPlayer.armor[index].netDefaults(this.inventory[i].netID);
|
|
}
|
|
else
|
|
{
|
|
player.TPlayer.armor[index].netDefaults(0);
|
|
}
|
|
|
|
if (player.TPlayer.armor[index].netID != 0)
|
|
{
|
|
player.TPlayer.armor[index].stack = this.inventory[i].stack;
|
|
player.TPlayer.armor[index].prefix = (byte)this.inventory[i].prefix;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var index = i - (NetItem.maxNetInventory - NetItem.dyeSlots);
|
|
if (this.inventory[i] != null)
|
|
{
|
|
player.TPlayer.dye[index].netDefaults(this.inventory[i].netID);
|
|
}
|
|
else
|
|
{
|
|
player.TPlayer.dye[index].netDefaults(0);
|
|
}
|
|
|
|
if (player.TPlayer.dye[index].netID != 0)
|
|
{
|
|
player.TPlayer.dye[index].stack = this.inventory[i].stack;
|
|
player.TPlayer.dye[index].prefix = (byte)this.inventory[i].prefix;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int k = 0; k < 59; k++)
|
|
{
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].inventory[k].name, player.Index, (float)k, (float)Main.player[player.Index].inventory[k].prefix, 0f, 0);
|
|
}
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0);
|
|
NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0);
|
|
NetMessage.SendData(4, -1, -1, player.Name, player.Index, 0f, 0f, 0f, 0);
|
|
NetMessage.SendData(42, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
|
|
NetMessage.SendData(16, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
|
|
|
|
for (int k = 0; k < 59; k++)
|
|
{
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].inventory[k].name, player.Index, (float)k, (float)Main.player[player.Index].inventory[k].prefix, 0f, 0);
|
|
}
|
|
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[0].name, player.Index, 59f, (float)Main.player[player.Index].armor[0].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[1].name, player.Index, 60f, (float)Main.player[player.Index].armor[1].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[2].name, player.Index, 61f, (float)Main.player[player.Index].armor[2].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[3].name, player.Index, 62f, (float)Main.player[player.Index].armor[3].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[4].name, player.Index, 63f, (float)Main.player[player.Index].armor[4].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[5].name, player.Index, 64f, (float)Main.player[player.Index].armor[5].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[6].name, player.Index, 65f, (float)Main.player[player.Index].armor[6].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[7].name, player.Index, 66f, (float)Main.player[player.Index].armor[7].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[8].name, player.Index, 67f, (float)Main.player[player.Index].armor[8].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[9].name, player.Index, 68f, (float)Main.player[player.Index].armor[9].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[10].name, player.Index, 69f, (float)Main.player[player.Index].armor[10].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[11].name, player.Index, 70f, (float)Main.player[player.Index].armor[11].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[12].name, player.Index, 71f, (float)Main.player[player.Index].armor[12].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[13].name, player.Index, 72f, (float)Main.player[player.Index].armor[13].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[14].name, player.Index, 73f, (float)Main.player[player.Index].armor[14].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[15].name, player.Index, 74f, (float)Main.player[player.Index].armor[15].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[0].name, player.Index, 75f, (float)Main.player[player.Index].dye[0].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[1].name, player.Index, 76f, (float)Main.player[player.Index].dye[1].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[2].name, player.Index, 77f, (float)Main.player[player.Index].dye[2].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[3].name, player.Index, 78f, (float)Main.player[player.Index].dye[3].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[4].name, player.Index, 79f, (float)Main.player[player.Index].dye[4].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[5].name, player.Index, 80f, (float)Main.player[player.Index].dye[5].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[6].name, player.Index, 81f, (float)Main.player[player.Index].dye[6].prefix, 0f, 0);
|
|
NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[7].name, player.Index, 82f, (float)Main.player[player.Index].dye[7].prefix, 0f, 0);
|
|
NetMessage.SendData(4, player.Index, -1, player.Name, player.Index, 0f, 0f, 0f, 0);
|
|
NetMessage.SendData(42, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
|
|
NetMessage.SendData(16, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
|
|
|
|
for (int k = 0; k < 22; k++)
|
|
{
|
|
player.TPlayer.buffType[k] = 0;
|
|
}
|
|
NetMessage.SendData(50, -1, -1, "", player.Index, 0f, 0f, 0f, 0);
|
|
NetMessage.SendData(50, player.Index, -1, "", player.Index, 0f, 0f, 0f, 0);
|
|
NetMessage.SendData(76, -1, -1, "", player.Index);
|
|
|
|
NetMessage.SendData(39, player.Index, -1, "", 400);
|
|
}
|
|
}
|
|
|
|
public class NetItem
|
|
{
|
|
public static readonly int maxNetInventory = 83;
|
|
public static readonly int armorSlots = 16;
|
|
public static readonly int dyeSlots = 8;
|
|
public int netID;
|
|
public int stack;
|
|
public int prefix;
|
|
|
|
public static string ToString(NetItem[] inventory)
|
|
{
|
|
StringBuilder items = new StringBuilder();
|
|
for (int i = 0; i < maxNetInventory; i++)
|
|
{
|
|
items.Append(inventory[i].netID).Append(",");
|
|
if (inventory[i].netID != 0)
|
|
items.Append(inventory[i].stack).Append(",").Append(inventory[i].prefix).Append("~");
|
|
else
|
|
items.Append("0,0~");
|
|
}
|
|
return items.ToString(0, items.Length - 1);
|
|
}
|
|
|
|
public static NetItem[] Parse(string data)
|
|
{
|
|
NetItem[] inventory = new NetItem[maxNetInventory];
|
|
int i;
|
|
for (i = 0; i < maxNetInventory; i++)
|
|
{
|
|
inventory[i] = new NetItem();
|
|
}
|
|
string[] items = data.Split('~');
|
|
i = 0;
|
|
foreach (string item in items)
|
|
{
|
|
string[] idata = item.Split(',');
|
|
inventory[i].netID = int.Parse(idata[0]);
|
|
inventory[i].stack = int.Parse(idata[1]);
|
|
inventory[i].prefix = int.Parse(idata[2]);
|
|
i++;
|
|
}
|
|
return inventory;
|
|
}
|
|
}
|
|
}
|