diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bacd3bd..cd777369 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ This is the rolling changelog for TShock for Terraria. Use past tense when adding new entries; sign your name off when you add or change something. This should primarily be things like user changes, not necessarily codebase changes unless it's really relevant or large. +## Upcoming Changes + +* Fixed character styles/gender not being saved properly on first login while SSC is on (@WhiteXZ) +* Added a PlayerPermission hook fired whenever a permission check involving said player occurs (when the new TSPlayer.HasPermission method is called) (@Enerdy) + ## TShock 4.3.12 * Fixed issues with TSPlayer.SetTeam not working (@WhiteXZ) @@ -16,7 +21,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin ## TShock 4.3.11 -* This release is actuall 4.3.10, but was ticked extra due to a version issue on gen-dev prior to master push. +* This release is actually 4.3.10, but was ticked extra due to a version issue on gen-dev prior to master push. ## TShock 4.3.10 diff --git a/TShockAPI/Commands.cs b/TShockAPI/Commands.cs index 4ab71eb0..5934dd16 100755 --- a/TShockAPI/Commands.cs +++ b/TShockAPI/Commands.cs @@ -175,7 +175,7 @@ namespace TShockAPI return true; foreach (var Permission in Permissions) { - if (ply.Group.HasPermission(Permission)) + if (ply.HasPermission(Permission)) return true; } return false; @@ -795,7 +795,7 @@ namespace TShockAPI if (Main.ServerSideCharacter) { - if (group.HasPermission(Permissions.bypassssc)) + if (args.Player.HasPermission(Permissions.bypassssc)) { args.Player.IgnoreActionsForClearingTrashCan = false; } @@ -803,10 +803,10 @@ namespace TShockAPI } args.Player.LoginFailsBySsi = false; - if (group.HasPermission(Permissions.ignorestackhackdetection)) + if (args.Player.HasPermission(Permissions.ignorestackhackdetection)) args.Player.IgnoreActionsForCheating = "none"; - if (group.HasPermission(Permissions.usebanneditem)) + if (args.Player.HasPermission(Permissions.usebanneditem)) args.Player.IgnoreActionsForDisabledArmor = "none"; args.Player.Group = group; @@ -1381,7 +1381,7 @@ namespace TShockAPI TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); else { - if (args.Player.RealPlayer && players[0].Group.HasPermission(Permissions.immunetoban)) + if (args.Player.RealPlayer && players[0].HasPermission(Permissions.immunetoban)) { args.Player.SendErrorMessage("You can't ban {0}!", players[0].Name); return; @@ -2237,7 +2237,7 @@ namespace TShockAPI { if (args.Parameters.Count != 1 && args.Parameters.Count != 2) { - if (args.Player.Group.HasPermission(Permissions.tpothers)) + if (args.Player.HasPermission(Permissions.tpothers)) args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}tp [player 2]", Specifier); else args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}tp ", Specifier); @@ -2254,7 +2254,7 @@ namespace TShockAPI else { var target = players[0]; - if (!target.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride)) + if (!target.TPAllow && !args.Player.HasPermission(Permissions.tpoverride)) { args.Player.SendErrorMessage("{0} has disabled players from teleporting.", target.Name); return; @@ -2262,14 +2262,14 @@ namespace TShockAPI if (args.Player.Teleport(target.TPlayer.position.X, target.TPlayer.position.Y)) { args.Player.SendSuccessMessage("Teleported to {0}.", target.Name); - if (!args.Player.Group.HasPermission(Permissions.tpsilent)) + if (!args.Player.HasPermission(Permissions.tpsilent)) target.SendInfoMessage("{0} teleported to you.", args.Player.Name); } } } else { - if (!args.Player.Group.HasPermission(Permissions.tpothers)) + if (!args.Player.HasPermission(Permissions.tpothers)) { args.Player.SendErrorMessage("You do not have access to this command."); return; @@ -2286,7 +2286,7 @@ namespace TShockAPI { if (args.Parameters[0] == "*") { - if (!args.Player.Group.HasPermission(Permissions.tpallothers)) + if (!args.Player.HasPermission(Permissions.tpallothers)) { args.Player.SendErrorMessage("You do not have access to this command."); return; @@ -2295,22 +2295,22 @@ namespace TShockAPI var target = players2[0]; foreach (var source in TShock.Players.Where(p => p != null && p != args.Player)) { - if (!target.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride)) + if (!target.TPAllow && !args.Player.HasPermission(Permissions.tpoverride)) continue; if (source.Teleport(target.TPlayer.position.X, target.TPlayer.position.Y)) { if (args.Player != source) { - if (args.Player.Group.HasPermission(Permissions.tpsilent)) + if (args.Player.HasPermission(Permissions.tpsilent)) source.SendSuccessMessage("You were teleported to {0}.", target.Name); else source.SendSuccessMessage("{0} teleported you to {1}.", args.Player.Name, target.Name); } if (args.Player != target) { - if (args.Player.Group.HasPermission(Permissions.tpsilent)) + if (args.Player.HasPermission(Permissions.tpsilent)) target.SendInfoMessage("{0} was teleported to you.", source.Name); - if (!args.Player.Group.HasPermission(Permissions.tpsilent)) + if (!args.Player.HasPermission(Permissions.tpsilent)) target.SendInfoMessage("{0} teleported {1} to you.", args.Player.Name, source.Name); } } @@ -2325,13 +2325,13 @@ namespace TShockAPI else { var source = players1[0]; - if (!source.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride)) + if (!source.TPAllow && !args.Player.HasPermission(Permissions.tpoverride)) { args.Player.SendErrorMessage("{0} has disabled players from teleporting.", source.Name); return; } var target = players2[0]; - if (!target.TPAllow && !args.Player.Group.HasPermission(Permissions.tpoverride)) + if (!target.TPAllow && !args.Player.HasPermission(Permissions.tpoverride)) { args.Player.SendErrorMessage("{0} has disabled players from teleporting.", target.Name); return; @@ -2341,16 +2341,16 @@ namespace TShockAPI { if (args.Player != source) { - if (args.Player.Group.HasPermission(Permissions.tpsilent)) + if (args.Player.HasPermission(Permissions.tpsilent)) source.SendSuccessMessage("You were teleported to {0}.", target.Name); else source.SendSuccessMessage("{0} teleported you to {1}.", args.Player.Name, target.Name); } if (args.Player != target) { - if (args.Player.Group.HasPermission(Permissions.tpsilent)) + if (args.Player.HasPermission(Permissions.tpsilent)) target.SendInfoMessage("{0} was teleported to you.", source.Name); - if (!args.Player.Group.HasPermission(Permissions.tpsilent)) + if (!args.Player.HasPermission(Permissions.tpsilent)) target.SendInfoMessage("{0} teleported {1} to you.", args.Player.Name, source.Name); } } @@ -2362,7 +2362,7 @@ namespace TShockAPI { if (args.Parameters.Count < 1) { - if (args.Player.Group.HasPermission(Permissions.tpallothers)) + if (args.Player.HasPermission(Permissions.tpallothers)) args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}tphere ", Specifier); else args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}tphere ", Specifier); @@ -2375,7 +2375,7 @@ namespace TShockAPI { if (playerName == "*") { - if (!args.Player.Group.HasPermission(Permissions.tpallothers)) + if (!args.Player.HasPermission(Permissions.tpallothers)) { args.Player.SendErrorMessage("You do not have permission to use this command."); return; @@ -2500,7 +2500,7 @@ namespace TShockAPI private static void Warp(CommandArgs args) { - bool hasManageWarpPermission = args.Player.Group.HasPermission(Permissions.managewarp); + bool hasManageWarpPermission = args.Player.HasPermission(Permissions.managewarp); if (args.Parameters.Count < 1) { if (hasManageWarpPermission) @@ -2603,7 +2603,7 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid syntax! Proper syntax: {0}warp hide [name] ", Specifier); #endregion } - else if (args.Parameters[0].ToLower() == "send" && args.Player.Group.HasPermission(Permissions.tpothers)) + else if (args.Parameters[0].ToLower() == "send" && args.Player.HasPermission(Permissions.tpothers)) { #region Warp send if (args.Parameters.Count < 3) @@ -3852,7 +3852,7 @@ namespace TShockAPI { int.TryParse(args.Parameters[1], out damage); } - if (!args.Player.Group.HasPermission(Permissions.kill)) + if (!args.Player.HasPermission(Permissions.kill)) { damage = TShock.Utils.Clamp(damage, 15, 0); } @@ -4349,7 +4349,7 @@ namespace TShockAPI } case "tp": { - if (!args.Player.Group.HasPermission(Permissions.tp)) + if (!args.Player.HasPermission(Permissions.tp)) { args.Player.SendErrorMessage("You don't have the necessary permission to do that."); break; @@ -4397,7 +4397,7 @@ namespace TShockAPI "protect - Sets whether the tiles inside the region are protected or not.", "z <#> - Sets the z-order of the region.", }; - if (args.Player.Group.HasPermission(Permissions.tp)) + if (args.Player.HasPermission(Permissions.tp)) lines.Add("tp - Teleports you to the given region's center."); PaginationTools.SendPage( @@ -4526,7 +4526,7 @@ namespace TShockAPI args.Player.SendErrorMessage("Invalid usage, proper usage: {0}who [-i] [pagenumber]", Specifier); return; } - if (displayIdsRequested && !args.Player.Group.HasPermission(Permissions.seeids)) + if (displayIdsRequested && !args.Player.HasPermission(Permissions.seeids)) { args.Player.SendErrorMessage("You don't have the required permission to list player ids."); return; @@ -4658,7 +4658,7 @@ namespace TShockAPI { TShock.Utils.SendMultipleMatchError(args.Player, players.Select(p => p.Name)); } - else if (players[0].Group.HasPermission(Permissions.mute)) + else if (players[0].HasPermission(Permissions.mute)) { args.Player.SendErrorMessage("You cannot mute this player."); } @@ -5497,7 +5497,7 @@ namespace TShockAPI TSPlayer playerToGod; if (args.Parameters.Count > 0) { - if (!args.Player.Group.HasPermission(Permissions.godmodeother)) + if (!args.Player.HasPermission(Permissions.godmodeother)) { args.Player.SendErrorMessage("You do not have permission to god mode another player!"); return; diff --git a/TShockAPI/DB/CharacterManager.cs b/TShockAPI/DB/CharacterManager.cs index eb7deebc..f1e5a5fc 100755 --- a/TShockAPI/DB/CharacterManager.cs +++ b/TShockAPI/DB/CharacterManager.cs @@ -96,7 +96,7 @@ namespace TShockAPI.DB playerData.extraSlot = reader.Get("extraSlot"); playerData.spawnX = reader.Get("spawnX"); playerData.spawnY = reader.Get("spawnY"); - playerData.skinVariant = reader.Get("skinVariant"); + playerData.skinVariant = reader.Get("skinVariant"); playerData.hair = reader.Get("hair"); playerData.hairDye = (byte)reader.Get("hairDye"); playerData.hairColor = TShock.Utils.DecodeColor(reader.Get("hairColor")); @@ -162,13 +162,13 @@ namespace TShockAPI.DB if (!player.IsLoggedIn) return false; - - if ((player.tempGroup != null && player.tempGroup.HasPermission(Permissions.bypassssc)) || player.Group.HasPermission(Permissions.bypassssc)) - { - TShock.Log.ConsoleInfo("Skipping SSC Backup for " + player.User.Name); // Debug code - return true; - } - + + if (player.HasPermission(Permissions.bypassssc)) + { + TShock.Log.ConsoleInfo("Skipping SSC Backup for " + player.User.Name); // Debug code + return true; + } + if (!GetPlayerData(player, player.User.ID).exists) { try diff --git a/TShockAPI/DB/ItemManager.cs b/TShockAPI/DB/ItemManager.cs index 99ff89e3..ebff94bc 100755 --- a/TShockAPI/DB/ItemManager.cs +++ b/TShockAPI/DB/ItemManager.cs @@ -192,32 +192,32 @@ namespace TShockAPI.DB return Name == other.Name; } - public bool HasPermissionToUseItem(TSPlayer ply) - { - if (ply == null) - return false; + public bool HasPermissionToUseItem(TSPlayer ply) + { + if (ply == null) + return false; - if (ply.Group.HasPermission(Permissions.usebanneditem)) - return true; + if (ply.HasPermission(Permissions.usebanneditem)) + return true; - var cur = ply.Group; - var traversed = new List(); - while (cur != null) - { - if (AllowedGroups.Contains(cur.Name)) - { - return true; - } - if (traversed.Contains(cur)) - { - throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name)); - } - traversed.Add(cur); - cur = cur.Parent; - } - return false; - // could add in the other permissions in this class instead of a giant if switch. - } + var cur = ply.Group; + var traversed = new List(); + while (cur != null) + { + if (AllowedGroups.Contains(cur.Name)) + { + return true; + } + if (traversed.Contains(cur)) + { + throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name)); + } + traversed.Add(cur); + cur = cur.Parent; + } + return false; + // could add in the other permissions in this class instead of a giant if switch. + } public void SetAllowedGroups(String groups) { diff --git a/TShockAPI/DB/ProjectileManager.cs b/TShockAPI/DB/ProjectileManager.cs index ee955a2f..c52baf3b 100755 --- a/TShockAPI/DB/ProjectileManager.cs +++ b/TShockAPI/DB/ProjectileManager.cs @@ -202,7 +202,7 @@ namespace TShockAPI.DB if (ply == null) return false; - if (ply.Group.HasPermission(Permissions.canusebannedprojectiles)) + if (ply.HasPermission(Permissions.canusebannedprojectiles)) return true; var cur = ply.Group; diff --git a/TShockAPI/DB/RegionManager.cs b/TShockAPI/DB/RegionManager.cs index 5bd58d5f..622b94e2 100755 --- a/TShockAPI/DB/RegionManager.cs +++ b/TShockAPI/DB/RegionManager.cs @@ -210,7 +210,7 @@ namespace TShockAPI.DB public bool CanBuild(int x, int y, TSPlayer ply) { - if (!ply.Group.HasPermission(Permissions.canbuild)) + if (!ply.HasPermission(Permissions.canbuild)) { return false; } diff --git a/TShockAPI/DB/TileManager.cs b/TShockAPI/DB/TileManager.cs index bf7f28dc..a16f30fb 100755 --- a/TShockAPI/DB/TileManager.cs +++ b/TShockAPI/DB/TileManager.cs @@ -202,7 +202,7 @@ namespace TShockAPI.DB if (ply == null) return false; - if (ply.Group.HasPermission(Permissions.canusebannedtiles)) + if (ply.HasPermission(Permissions.canusebannedtiles)) return true; var cur = ply.Group; diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index ef67b844..4b8e3b83 100755 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -1305,7 +1305,7 @@ namespace TShockAPI args.Player.PlayerData.StoreSlot(slot, type, prefix, stack); } else if (Main.ServerSideCharacter && TShock.Config.DisableLoginBeforeJoin && !bypassTrashCanCheck && - args.Player.HasSentInventory && !args.Player.Group.HasPermission(Permissions.bypassssc)) + args.Player.HasSentInventory && !args.Player.HasPermission(Permissions.bypassssc)) { // The player might have moved an item to their trash can before they performed a single login attempt yet. args.Player.IgnoreActionsForClearingTrashCan = true; @@ -1329,7 +1329,7 @@ namespace TShockAPI if (OnPlayerHP(plr, cur, max) || cur <= 0 || max <= 0 || args.Player.IgnoreSSCPackets) return true; - if (max > TShock.Config.MaxHP && !args.Player.Group.HasPermission(Permissions.ignorehp)) + if (max > TShock.Config.MaxHP && !args.Player.HasPermission(Permissions.ignorehp)) { args.Player.Disable("Maximum HP beyond limit", DisableFlags.WriteToLogAndConsole); return true; @@ -1358,7 +1358,7 @@ namespace TShockAPI if (OnPlayerMana(plr, cur, max) || cur < 0 || max < 0 || args.Player.IgnoreSSCPackets) return true; - if (max > TShock.Config.MaxMP && !args.Player.Group.HasPermission(Permissions.ignoremp)) + if (max > TShock.Config.MaxMP && !args.Player.HasPermission(Permissions.ignoremp)) { args.Player.Disable("Maximum MP beyond limit", DisableFlags.WriteToLogAndConsole); return true; @@ -1476,17 +1476,17 @@ namespace TShockAPI if (Main.ServerSideCharacter) { - if (!group.HasPermission(Permissions.bypassssc)) + if (!args.Player.HasPermission(Permissions.bypassssc)) { args.Player.PlayerData.RestoreCharacter(args.Player); } } args.Player.LoginFailsBySsi = false; - if (group.HasPermission(Permissions.ignorestackhackdetection)) + if (args.Player.HasPermission(Permissions.ignorestackhackdetection)) args.Player.IgnoreActionsForCheating = "none"; - if (group.HasPermission(Permissions.usebanneditem)) + if (args.Player.HasPermission(Permissions.usebanneditem)) args.Player.IgnoreActionsForDisabledArmor = "none"; args.Player.Group = group; @@ -1551,7 +1551,7 @@ namespace TShockAPI if (Main.ServerSideCharacter) { - if (group.HasPermission(Permissions.bypassssc)) + if (args.Player.HasPermission(Permissions.bypassssc)) { args.Player.IgnoreActionsForClearingTrashCan = false; } @@ -1559,10 +1559,10 @@ namespace TShockAPI } args.Player.LoginFailsBySsi = false; - if (group.HasPermission(Permissions.ignorestackhackdetection)) + if (args.Player.HasPermission(Permissions.ignorestackhackdetection)) args.Player.IgnoreActionsForCheating = "none"; - if (group.HasPermission(Permissions.usebanneditem)) + if (args.Player.HasPermission(Permissions.usebanneditem)) args.Player.IgnoreActionsForDisabledArmor = "none"; args.Player.Group = group; @@ -1614,13 +1614,13 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignorestackhackdetection)) + if (!args.Player.HasPermission(Permissions.ignorestackhackdetection)) { TShock.HackedInventory(args.Player); } if (TShock.Utils.ActivePlayers() + 1 > TShock.Config.MaxSlots && - !args.Player.Group.HasPermission(Permissions.reservedslot)) + !args.Player.HasPermission(Permissions.reservedslot)) { TShock.Utils.ForceKick(args.Player, TShock.Config.ServerFullReason, true); return true; @@ -1681,7 +1681,7 @@ namespace TShockAPI isTrapdoor = true; } - if (args.Player.Group.HasPermission(Permissions.allowclientsideworldedit) && !isTrapdoor) + if (args.Player.HasPermission(Permissions.allowclientsideworldedit) && !isTrapdoor) return false; if (OnSendTileSquare(size, tileX, tileY)) @@ -2133,7 +2133,7 @@ namespace TShockAPI return true; } - if ((action == EditAction.PlaceTile || action == EditAction.PlaceWall) && !args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection)) + if ((action == EditAction.PlaceTile || action == EditAction.PlaceWall) && !args.Player.HasPermission(Permissions.ignoreplacetiledetection)) { args.Player.TilePlaceThreshold++; var coords = new Vector2(tileX, tileY); @@ -2142,7 +2142,7 @@ namespace TShockAPI } if ((action == EditAction.KillTile || action == EditAction.KillTileNoItem || action == EditAction.KillWall) && Main.tileSolid[Main.tile[tileX, tileY].type] && - !args.Player.Group.HasPermission(Permissions.ignorekilltiledetection)) + !args.Player.HasPermission(Permissions.ignorekilltiledetection)) { args.Player.TileKillThreshold++; var coords = new Vector2(tileX, tileY); @@ -2235,7 +2235,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignoreplacetiledetection)) + if (!args.Player.HasPermission(Permissions.ignoreplacetiledetection)) { args.Player.TilePlaceThreshold++; var coords = new Vector2(x, y); @@ -2437,7 +2437,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignorenoclipdetection) && + if (!args.Player.HasPermission(Permissions.ignorenoclipdetection) && TSCheckNoclip(pos, args.TPlayer.width, args.TPlayer.height) && !TShock.Config.IgnoreNoClip && !args.TPlayer.tongued) { @@ -2617,7 +2617,7 @@ namespace TShockAPI return true; } - if (dmg > TShock.Config.MaxProjDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) + if (dmg > TShock.Config.MaxProjDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) { args.Player.Disable(String.Format("Projectile damage is higher than {0}.", TShock.Config.MaxProjDamage), DisableFlags.WriteToLogAndConsole); args.Player.RemoveProjectile(ident, owner); @@ -2631,7 +2631,7 @@ namespace TShockAPI } bool hasPermission = !TShock.CheckProjectilePermission(args.Player, index, type); - if (!TShock.Config.IgnoreProjUpdate && !hasPermission && !args.Player.Group.HasPermission(Permissions.ignoreprojectiledetection)) + if (!TShock.Config.IgnoreProjUpdate && !hasPermission && !args.Player.HasPermission(Permissions.ignoreprojectiledetection)) { if (type == ProjectileID.BlowupSmokeMoonlord || type == ProjectileID.PhantasmalEye @@ -2668,7 +2668,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignoreprojectiledetection)) + if (!args.Player.HasPermission(Permissions.ignoreprojectiledetection)) { if (type == ProjectileID.CrystalShard && TShock.Config.ProjIgnoreShrapnel) // Ignore crystal shards { @@ -2831,7 +2831,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignoreliquidsetdetection)) + if (!args.Player.HasPermission(Permissions.ignoreliquidsetdetection)) { args.Player.TileLiquidThreshold++; } @@ -3149,7 +3149,7 @@ namespace TShockAPI if (OnUpdateNPCHome(id, x, y, homeless)) return true; - if (!args.Player.Group.HasPermission(Permissions.movenpc)) + if (!args.Player.HasPermission(Permissions.movenpc)) { args.Player.SendErrorMessage("You do not have permission to relocate NPCs."); args.Player.SendData(PacketTypes.UpdateNPCHome, "", id, Main.npc[id].homeTileX, Main.npc[id].homeTileY, @@ -3281,7 +3281,7 @@ namespace TShockAPI Item item = new Item(); item.netDefaults(type); - if ((stacks > item.maxStack || stacks <= 0) || (TShock.Itembans.ItemIsBanned(item.name, args.Player) && !args.Player.Group.HasPermission(Permissions.allowdroppingbanneditems))) + if ((stacks > item.maxStack || stacks <= 0) || (TShock.Itembans.ItemIsBanned(item.name, args.Player) && !args.Player.HasPermission(Permissions.allowdroppingbanneditems))) { args.Player.SendData(PacketTypes.ItemDrop, "", id); return true; @@ -3338,7 +3338,7 @@ namespace TShockAPI return true; } - if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) + if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap) && id != args.Player.Index) { if (TShock.Config.KickOnDamageThresholdBroken) { @@ -3404,7 +3404,7 @@ namespace TShockAPI if (Main.npc[id] == null) return true; - if (dmg > TShock.Config.MaxDamage && !args.Player.Group.HasPermission(Permissions.ignoredamagecap)) + if (dmg > TShock.Config.MaxDamage && !args.Player.HasPermission(Permissions.ignoredamagecap)) { if (TShock.Config.KickOnDamageThresholdBroken) { @@ -3425,7 +3425,7 @@ namespace TShockAPI return true; } - if (Main.npc[id].townNPC && !args.Player.Group.HasPermission(Permissions.hurttownnpc)) + if (Main.npc[id].townNPC && !args.Player.HasPermission(Permissions.hurttownnpc)) { args.Player.SendErrorMessage("You do not have permission to hurt this NPC."); args.Player.SendData(PacketTypes.NpcUpdate, "", id); @@ -3588,12 +3588,12 @@ namespace TShockAPI break; } } - if (spawnboss && !args.Player.Group.HasPermission(Permissions.summonboss)) + if (spawnboss && !args.Player.HasPermission(Permissions.summonboss)) { args.Player.SendErrorMessage("You don't have permission to summon a boss."); return true; } - if (invasion && !args.Player.Group.HasPermission(Permissions.startinvasion)) + if (invasion && !args.Player.HasPermission(Permissions.startinvasion)) { args.Player.SendErrorMessage("You don't have permission to start an invasion."); return true; @@ -3670,7 +3670,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignorepaintdetection)) + if (!args.Player.HasPermission(Permissions.ignorepaintdetection)) { args.Player.PaintThreshold++; } @@ -3714,7 +3714,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.ignorepaintdetection)) + if (!args.Player.HasPermission(Permissions.ignorepaintdetection)) { args.Player.PaintThreshold++; } @@ -3753,7 +3753,7 @@ namespace TShockAPI } //Rod of Discord teleport (usually (may be used by modded clients to teleport)) - if (type == 0 && !args.Player.Group.HasPermission(Permissions.rod)) + if (type == 0 && !args.Player.HasPermission(Permissions.rod)) { args.Player.SendErrorMessage("You do not have permission to teleport."); args.Player.Teleport(args.TPlayer.position.X, args.TPlayer.position.Y); @@ -3774,7 +3774,7 @@ namespace TShockAPI return true; } - if (!args.Player.Group.HasPermission(Permissions.wormhole)) + if (!args.Player.HasPermission(Permissions.wormhole)) { args.Player.SendErrorMessage("You do not have permission to teleport."); args.Player.Teleport(args.TPlayer.position.X, args.TPlayer.position.Y); diff --git a/TShockAPI/Group.cs b/TShockAPI/Group.cs index 1f953dff..8c05d64c 100644 --- a/TShockAPI/Group.cs +++ b/TShockAPI/Group.cs @@ -22,56 +22,59 @@ using System.Collections.Generic; namespace TShockAPI { + /// + /// A class used to group multiple users' permissions and settings. + /// public class Group { // NOTE: Using a const still suffers from needing to recompile to change the default // ideally we would use a static but this means it can't be used for the default parameter :( - /// - /// Default chat color. - /// + /// + /// Default chat color. + /// public const string defaultChatColor = "255,255,255"; - /// - /// List of permissions available to the group. - /// + /// + /// List of permissions available to the group. + /// public readonly List permissions = new List(); - /// - /// List of permissions that the group is explicitly barred from. - /// + /// + /// List of permissions that the group is explicitly barred from. + /// public readonly List negatedpermissions = new List(); - /// - /// The group's name. - /// + /// + /// The group's name. + /// public string Name { get; set; } - /// - /// The group that this group inherits permissions from. - /// + /// + /// The group that this group inherits permissions from. + /// public Group Parent { get; set; } - /// - /// The chat prefix for this group. - /// + /// + /// The chat prefix for this group. + /// public string Prefix { get; set; } - /// - /// The chat suffix for this group. - /// + /// + /// The chat suffix for this group. + /// public string Suffix { get; set; } - /// - /// The name of the parent, not particularly sure why this is here. - /// We can use group.Parent.Name and not have this second reference. - /// This was added for rest, so a discussion with Shank is necessary. - /// + /// + /// The name of the parent, not particularly sure why this is here. + /// We can use group.Parent.Name and not have this second reference. + /// This was added for rest, so a discussion with Shank is necessary. + /// public string ParentName { get { return (null == Parent) ? "" : Parent.Name; } } - /// - /// The chat color of the group. - /// Returns "255,255,255", sets "255,255,255" - /// + /// + /// The chat color of the group. + /// Returns "255,255,255", sets "255,255,255" + /// public string ChatColor { get { return string.Format("{0},{1},{2}", R.ToString("D3"), G.ToString("D3"), B.ToString("D3")); } @@ -95,9 +98,9 @@ namespace TShockAPI } } - /// - /// The permissions of the user in string form. - /// + /// + /// The permissions of the user in string form. + /// public string Permissions { get @@ -115,9 +118,9 @@ namespace TShockAPI } } - /// - /// The permissions of this group and all that it inherits from. - /// + /// + /// The permissions of this group and all that it inherits from. + /// public virtual List TotalPermissions { get @@ -148,12 +151,31 @@ namespace TShockAPI } } + /// + /// The group's chat color red byte. + /// public byte R = 255; + /// + /// The group's chat color green byte. + /// public byte G = 255; + /// + /// The group's chat color blue byte. + /// public byte B = 255; - public static Group DefaultGroup = null; + /// + /// The default group attributed to unregistered users. + /// + public static Group DefaultGroup = null; + /// + /// Initializes a new instance of the group class. + /// + /// The name of the group. + /// The parent group, if any. + /// The chat color, in "RRR,GGG,BBB" format. + /// The list of permissions associated with this group, separated by commas. public Group(string groupname, Group parentgroup = null, string chatcolor = "255,255,255", string permissions = null) { Name = groupname; @@ -162,21 +184,21 @@ namespace TShockAPI Permissions = permissions; } - /// - /// Checks to see if a group has a specified permission. - /// - /// The permission to check. - /// Returns true if the user has that permission. + /// + /// Checks to see if a group has a specified permission. + /// + /// The permission to check. + /// True if the group has that permission. public virtual bool HasPermission(string permission) - { - bool negated = false; + { + bool negated = false; if (String.IsNullOrEmpty(permission) || (RealHasPermission(permission, ref negated) && !negated)) { return true; } - if (negated) - return false; + if (negated) + return false; string[] nodes = permission.Split('.'); for (int i = nodes.Length - 1; i >= 0; i--) @@ -189,37 +211,37 @@ namespace TShockAPI } return false; } - private bool RealHasPermission(string permission, ref bool negated) - { - negated = false; - if (string.IsNullOrEmpty(permission)) - return true; + private bool RealHasPermission(string permission, ref bool negated) + { + negated = false; + if (string.IsNullOrEmpty(permission)) + return true; - var cur = this; - var traversed = new List(); - while (cur != null) - { - if (cur.negatedpermissions.Contains(permission)) - { - negated = true; - return false; - } - if (cur.permissions.Contains(permission)) - return true; - if (traversed.Contains(cur)) - { - throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name)); - } - traversed.Add(cur); - cur = cur.Parent; - } - return false; - } + var cur = this; + var traversed = new List(); + while (cur != null) + { + if (cur.negatedpermissions.Contains(permission)) + { + negated = true; + return false; + } + if (cur.permissions.Contains(permission)) + return true; + if (traversed.Contains(cur)) + { + throw new InvalidOperationException("Infinite group parenting ({0})".SFormat(cur.Name)); + } + traversed.Add(cur); + cur = cur.Parent; + } + return false; + } - /// - /// Adds a permission to the list of negated permissions. - /// - /// The permission to negate. + /// + /// Adds a permission to the list of negated permissions. + /// + /// The permission to negate. public void NegatePermission(string permission) { // Avoid duplicates @@ -230,10 +252,10 @@ namespace TShockAPI } } - /// - /// Adds a permission to the list of permissions. - /// - /// The permission to add. + /// + /// Adds a permission to the list of permissions. + /// + /// The permission to add. public void AddPermission(string permission) { if (permission.StartsWith("!")) @@ -249,11 +271,11 @@ namespace TShockAPI } } - /// - /// Clears the permission list and sets it to the list provided, - /// will parse "!permssion" and add it to the negated permissions. - /// - /// + /// + /// Clears the permission list and sets it to the list provided, + /// will parse "!permssion" and add it to the negated permissions. + /// + /// The new list of permissions to associate with the group. public void SetPermission(List permission) { permissions.Clear(); @@ -261,11 +283,11 @@ namespace TShockAPI permission.ForEach(p => AddPermission(p)); } - /// - /// Will remove a permission from the respective list, - /// where "!permission" will remove a negated permission. - /// - /// + /// + /// Will remove a permission from the respective list, + /// where "!permission" will remove a negated permission. + /// + /// public void RemovePermission(string permission) { if (permission.StartsWith("!")) @@ -277,9 +299,9 @@ namespace TShockAPI } /// - /// Assigns all fields of this instance to another. - /// - /// The other instance. + /// Assigns all fields of this instance to another. + /// + /// The other instance. public void AssignTo(Group otherGroup) { otherGroup.Name = Name; @@ -292,35 +314,44 @@ namespace TShockAPI otherGroup.Permissions = Permissions; } - public override string ToString() { + public override string ToString() + { return this.Name; } } - /// - /// This class is the SuperAdminGroup, which has access to everything. - /// + /// + /// This class is the SuperAdminGroup, which has access to everything. + /// public class SuperAdminGroup : Group { + /// + /// The superadmin class has every permission, represented by '*'. + /// public override List TotalPermissions { get { return new List { "*" }; } } + + /// + /// Initializes a new instance of the SuperAdminGroup class with the configured parameters. + /// Those can be changed in the config file. + /// public SuperAdminGroup() : base("superadmin") { - R = (byte) TShock.Config.SuperAdminChatRGB[0]; - G = (byte) TShock.Config.SuperAdminChatRGB[1]; - B = (byte) TShock.Config.SuperAdminChatRGB[2]; + R = (byte)TShock.Config.SuperAdminChatRGB[0]; + G = (byte)TShock.Config.SuperAdminChatRGB[1]; + B = (byte)TShock.Config.SuperAdminChatRGB[2]; Prefix = TShock.Config.SuperAdminChatPrefix; Suffix = TShock.Config.SuperAdminChatSuffix; } - /// - /// Override to allow access to everything. - /// - /// The permission - /// True + /// + /// Override to allow access to everything. + /// + /// The permission + /// True public override bool HasPermission(string permission) { return true; diff --git a/TShockAPI/Hooks/PlayerHooks.cs b/TShockAPI/Hooks/PlayerHooks.cs index d8801399..b3e6b585 100644 --- a/TShockAPI/Hooks/PlayerHooks.cs +++ b/TShockAPI/Hooks/PlayerHooks.cs @@ -21,66 +21,221 @@ using System.ComponentModel; namespace TShockAPI.Hooks { + /// + /// EventArgs used for the event. + /// public class PlayerPostLoginEventArgs { + /// + /// The player who fired the event. + /// public TSPlayer Player { get; set; } + + /// + /// Initializes a new instance of the PlayerPostLoginEventArgs class. + /// + /// The player who fired the event. public PlayerPostLoginEventArgs(TSPlayer ply) { Player = ply; } } + /// + /// EventArgs used for the event. + /// public class PlayerPreLoginEventArgs : HandledEventArgs { + /// + /// The player who fired the event. + /// public TSPlayer Player { get; set; } + + /// + /// The player's login name. + /// public string LoginName { get; set; } + + /// + /// The player's raw password. + /// public string Password { get; set; } } + /// + /// EventArgs used for the event. + /// public class PlayerLogoutEventArgs { + /// + /// The player who fired the event. + /// public TSPlayer Player { get; set; } + /// + /// Initializes a new instance of the PlayerLogoutEventArgs class. + /// + /// The player who fired the event. public PlayerLogoutEventArgs(TSPlayer player) { Player = player; } } + /// + /// EventArgs used for the event. + /// public class PlayerCommandEventArgs : HandledEventArgs { + /// + /// The player who fired the event. + /// public TSPlayer Player { get; set; } + + /// + /// The command's name that follows the . + /// public string CommandName { get; set; } + + /// + /// The command's full text. + /// public string CommandText { get; set; } + + /// + /// The command's parameters extracted from . + /// public List Parameters { get; set; } + + /// + /// The full list of server commands. + /// public IEnumerable CommandList { get; set; } + + /// + /// The prefix used to send the command (either or ). + /// public string CommandPrefix { get; set; } } + /// + /// EventArgs used for the event. + /// public class PlayerChatEventArgs : HandledEventArgs { + /// + /// The player who fired the event. + /// public TSPlayer Player { get; set; } + + /// + /// The raw chat text as received by the server. + /// public string RawText { get; set; } + + /// + /// The string after being formatted by TShock as specified in the config file. + /// public string TShockFormattedText { get; set; } } + /// + /// EventArgs used for the event. + /// + public class PlayerPermissionEventArgs : HandledEventArgs + { + /// + /// The player who fired the event. + /// + public TSPlayer Player { get; set; } + + /// + /// The permission being checked. + /// + public string Permission { get; set; } + + /// + /// Initializes a new instance of the PlayerPermissionEventArgs class. + /// + /// The player who fired the event. + /// The permission being checked. + public PlayerPermissionEventArgs(TSPlayer player, string permission) + { + Player = player; + Permission = permission; + } + } + + /// + /// A collection of events fired by players that can be hooked to. + /// public static class PlayerHooks { + /// + /// The delegate of the event. + /// + /// The EventArgs for this event. public delegate void PlayerPostLoginD(PlayerPostLoginEventArgs e); + /// + /// Fired by players after they've successfully logged in to a user account. + /// public static event PlayerPostLoginD PlayerPostLogin; + /// + /// The delegate of the event. + /// + /// The EventArgs for this event. public delegate void PlayerPreLoginD(PlayerPreLoginEventArgs e); + /// + /// Fired by players when sending login credentials to the server. + /// public static event PlayerPreLoginD PlayerPreLogin; + /// + /// The delegate of the event. + /// + /// The EventArgs for this event. public delegate void PlayerLogoutD(PlayerLogoutEventArgs e); + /// + /// Fired by players upon logging out from a user account. + /// public static event PlayerLogoutD PlayerLogout; + /// + /// The delegate of the event. + /// + /// The EventArgs for this event. public delegate void PlayerCommandD(PlayerCommandEventArgs e); + /// + /// Fired by players when using a command. + /// public static event PlayerCommandD PlayerCommand; + /// + /// The delegate of the event. + /// + /// The EventArgs for this event. public delegate void PlayerChatD(PlayerChatEventArgs e); + /// + /// Fired by players when they send a chat message packet to the server + /// and before it is transmitted to the rest of the players. + /// public static event PlayerChatD PlayerChat; + /// + /// The delegate of the event. + /// + /// The EventArgs for this event. + public delegate void PlayerPermissionD(PlayerPermissionEventArgs e); + /// + /// Fired by players every time a permission check involving them occurs. + /// + public static event PlayerPermissionD PlayerPermission; + + /// + /// Fires the event. + /// + /// The player firing the event. public static void OnPlayerPostLogin(TSPlayer ply) { if (PlayerPostLogin == null) @@ -92,6 +247,16 @@ namespace TShockAPI.Hooks PlayerPostLogin(args); } + /// + /// Fires the event. + /// + /// The player firing the event. + /// The command name. + /// The raw command text. + /// The command args extracted from the command text. + /// The list of commands. + /// The command specifier used. + /// True if the event has been handled. public static bool OnPlayerCommand(TSPlayer player, string cmdName, string cmdText, List args, ref IEnumerable commands, string cmdPrefix) { if (PlayerCommand == null) @@ -111,6 +276,13 @@ namespace TShockAPI.Hooks return playerCommandEventArgs.Handled; } + /// + /// Fires the event. + /// + /// The player firing the event. + /// The user name. + /// The password. + /// True if the event has been handled. public static bool OnPlayerPreLogin(TSPlayer ply, string name, string pass) { if (PlayerPreLogin == null) @@ -121,6 +293,10 @@ namespace TShockAPI.Hooks return args.Handled; } + /// + /// Fires the event. + /// + /// The player firing the event. public static void OnPlayerLogout(TSPlayer ply) { if (PlayerLogout == null) @@ -130,6 +306,12 @@ namespace TShockAPI.Hooks PlayerLogout(args); } + /// + /// Fires the event. + /// + /// The player firing the event. + /// The raw chat text sent by the player. + /// The chat text after being formatted. public static void OnPlayerChat(TSPlayer ply, string rawtext, ref string tshockText) { if (PlayerChat == null) @@ -139,5 +321,20 @@ namespace TShockAPI.Hooks PlayerChat(args); tshockText = args.TShockFormattedText; } + + /// + /// Fires the event. + /// + /// The player firing the event. + /// True if the event has been handled. + public static bool OnPlayerPermission(TSPlayer player, string permission) + { + if (PlayerPermission == null) + return false; + + var args = new PlayerPermissionEventArgs(player, permission); + PlayerPermission(args); + return args.Handled; + } } } diff --git a/TShockAPI/PlayerData.cs b/TShockAPI/PlayerData.cs new file mode 100644 index 00000000..497dab72 --- /dev/null +++ b/TShockAPI/PlayerData.cs @@ -0,0 +1,411 @@ +using Terraria; +using TShockAPI; + +public class PlayerData +{ + public NetItem[] inventory = new NetItem[NetItem.MaxInventory]; + 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? extraSlot; + public int? skinVariant; + 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 bool[] hideVisuals; + public int questsCompleted; + + public PlayerData(TSPlayer player) + { + for (int i = 0; i < NetItem.MaxInventory; i++) + { + this.inventory[i] = new NetItem(); + } + + for (int i = 0; i < TShock.ServerSideCharacterConfig.StartingInventory.Count; i++) + { + var item = TShock.ServerSideCharacterConfig.StartingInventory[i]; + StoreSlot(i, item.NetId, item.PrefixId, item.Stack); + } + } + + /// + /// Stores an item at the specific storage slot + /// + /// + /// + /// + /// + public void StoreSlot(int slot, int netID, byte prefix, int stack) + { + if (slot > (this.inventory.Length - 1)) //if the slot is out of range then dont save + { + return; + } + + this.inventory[slot] = new NetItem(netID, stack, prefix); + } + + /// + /// Copies a characters data to this object + /// + /// + 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; + } + extraSlot = player.TPlayer.extraAccessory ? 1 : 0; + this.skinVariant = player.TPlayer.skinVariant; + 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; + Item[] miscEqups = player.TPlayer.miscEquips; + Item[] miscDyes = player.TPlayer.miscDyes; + Item[] piggy = player.TPlayer.bank.item; + Item[] safe = player.TPlayer.bank2.item; + Item trash = player.TPlayer.trashItem; + + for (int i = 0; i < NetItem.MaxInventory; i++) + { + if (i < NetItem.InventorySlots) + { + //0-58 + this.inventory[i] = (NetItem)inventory[i]; + } + else if (i < NetItem.InventorySlots + NetItem.ArmorSlots) + { + //59-78 + var index = i - NetItem.InventorySlots; + this.inventory[i] = (NetItem)armor[index]; + } + else if (i < NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots) + { + //79-88 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots); + this.inventory[i] = (NetItem)dye[index]; + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots) + { + //89-93 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots); + this.inventory[i] = (NetItem)miscEqups[index]; + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + + NetItem.MiscDyeSlots) + { + //93-98 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + + NetItem.MiscEquipSlots); + this.inventory[i] = (NetItem)miscDyes[index]; + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + + NetItem.MiscDyeSlots + NetItem.PiggySlots) + { + //98-138 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots); + this.inventory[i] = (NetItem)piggy[index]; + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + + NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots) + { + //138-178 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots); + this.inventory[i] = (NetItem)safe[index]; + } + else + { + //179 + this.inventory[i] = (NetItem)trash; + } + } + } + + /// + /// Restores a player's character to the state stored in the database + /// + /// + 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 (extraSlot != null) + player.TPlayer.extraAccessory = extraSlot.Value == 1 ? true : false; + if (this.skinVariant != null) + player.TPlayer.skinVariant = this.skinVariant.Value; + 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; + else + player.TPlayer.hideVisual = new bool[player.TPlayer.hideVisual.Length]; + + for (int i = 0; i < NetItem.MaxInventory; i++) + { + if (i < NetItem.InventorySlots) + { + //0-58 + player.TPlayer.inventory[i].netDefaults(this.inventory[i].NetId); + + if (player.TPlayer.inventory[i].netID != 0) + { + player.TPlayer.inventory[i].stack = this.inventory[i].Stack; + player.TPlayer.inventory[i].prefix = this.inventory[i].PrefixId; + } + } + else if (i < NetItem.InventorySlots + NetItem.ArmorSlots) + { + //59-78 + var index = i - NetItem.InventorySlots; + player.TPlayer.armor[index].netDefaults(this.inventory[i].NetId); + + 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].PrefixId; + } + } + else if (i < NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots) + { + //79-88 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots); + player.TPlayer.dye[index].netDefaults(this.inventory[i].NetId); + + 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].PrefixId; + } + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots) + { + //89-93 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots); + player.TPlayer.miscEquips[index].netDefaults(this.inventory[i].NetId); + + if (player.TPlayer.miscEquips[index].netID != 0) + { + player.TPlayer.miscEquips[index].stack = this.inventory[i].Stack; + player.TPlayer.miscEquips[index].prefix = (byte)this.inventory[i].PrefixId; + } + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + + NetItem.MiscDyeSlots) + { + //93-98 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + + NetItem.MiscEquipSlots); + player.TPlayer.miscDyes[index].netDefaults(this.inventory[i].NetId); + + if (player.TPlayer.miscDyes[index].netID != 0) + { + player.TPlayer.miscDyes[index].stack = this.inventory[i].Stack; + player.TPlayer.miscDyes[index].prefix = (byte)this.inventory[i].PrefixId; + } + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + + NetItem.MiscDyeSlots + NetItem.PiggySlots) + { + //98-138 + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots); + player.TPlayer.bank.item[index].netDefaults(this.inventory[i].NetId); + + if (player.TPlayer.bank.item[index].netID != 0) + { + player.TPlayer.bank.item[index].stack = this.inventory[i].Stack; + player.TPlayer.bank.item[index].prefix = (byte)this.inventory[i].PrefixId; + } + } + else if (i < + NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + + NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots) + { + var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots); + player.TPlayer.bank2.item[index].netDefaults(this.inventory[i].NetId); + + if (player.TPlayer.bank2.item[index].netID != 0) + { + player.TPlayer.bank2.item[index].stack = this.inventory[i].Stack; + player.TPlayer.bank2.item[index].prefix = (byte)this.inventory[i].PrefixId; + } + } + else + { + player.TPlayer.trashItem.netDefaults(this.inventory[i].NetId); + + if (player.TPlayer.trashItem.netID != 0) + { + player.TPlayer.trashItem.stack = this.inventory[i].Stack; + player.TPlayer.trashItem.prefix = (byte)this.inventory[i].PrefixId; + } + } + } + + float slot = 0f; + for (int k = 0; k < NetItem.InventorySlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].inventory[k].name, player.Index, slot, (float)Main.player[player.Index].inventory[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.ArmorSlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[k].name, player.Index, slot, (float)Main.player[player.Index].armor[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.DyeSlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[k].name, player.Index, slot, (float)Main.player[player.Index].dye[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.MiscEquipSlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].miscEquips[k].name, player.Index, slot, (float)Main.player[player.Index].miscEquips[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.MiscDyeSlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].miscDyes[k].name, player.Index, slot, (float)Main.player[player.Index].miscDyes[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.PiggySlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].bank.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank.item[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.SafeSlots; k++) + { + NetMessage.SendData(5, -1, -1, Main.player[player.Index].bank2.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank2.item[k].prefix); + slot++; + } + + NetMessage.SendData(5, -1, -1, Main.player[player.Index].trashItem.name, player.Index, slot, (float)Main.player[player.Index].trashItem.prefix); + + 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); + + slot = 0f; + for (int k = 0; k < NetItem.InventorySlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].inventory[k].name, player.Index, slot, (float)Main.player[player.Index].inventory[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.ArmorSlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[k].name, player.Index, slot, (float)Main.player[player.Index].armor[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.DyeSlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[k].name, player.Index, slot, (float)Main.player[player.Index].dye[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.MiscEquipSlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].miscEquips[k].name, player.Index, slot, (float)Main.player[player.Index].miscEquips[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.MiscDyeSlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].miscDyes[k].name, player.Index, slot, (float)Main.player[player.Index].miscDyes[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.PiggySlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].bank.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank.item[k].prefix); + slot++; + } + for (int k = 0; k < NetItem.SafeSlots; k++) + { + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].bank2.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank2.item[k].prefix); + slot++; + } + + NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].trashItem.name, player.Index, slot, (float)Main.player[player.Index].trashItem.prefix); + + 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); + } +} diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index c5ed9371..ce4d3e10 100755 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -26,6 +26,7 @@ using System.Timers; using Terraria; using Terraria.ID; using TShockAPI.DB; +using TShockAPI.Hooks; using TShockAPI.Net; using Timer = System.Timers.Timer; @@ -430,11 +431,11 @@ namespace TShockAPI } try { - if ((tempGroup != null && tempGroup.HasPermission(Permissions.bypassssc)) || Group.HasPermission(Permissions.bypassssc)) - { - TShock.Log.ConsoleInfo("Skipping SSC Backup for " + User.Name); // Debug Code - return true; - } + if (HasPermission(Permissions.bypassssc)) + { + TShock.Log.ConsoleInfo("Skipping SSC Backup for " + User.Name); // Debug Code + return true; + } PlayerData.CopyCharacter(this); TShock.CharacterDB.InsertPlayerData(this); return true; @@ -875,22 +876,22 @@ namespace TShockAPI } } - /* - * Calling new StackTrace() is incredibly expensive, and must be disabled - * in release builds. Use a conditional call instead. - */ - LogStackFrame(); + /* + * Calling new StackTrace() is incredibly expensive, and must be disabled + * in release builds. Use a conditional call instead. + */ + LogStackFrame(); } - [Conditional("DEBUG")] - private void LogStackFrame() - { - 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()."); - } + [Conditional("DEBUG")] + private void LogStackFrame() + { + 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) { @@ -954,6 +955,22 @@ namespace TShockAPI AwaitingResponse.Add(name, callback); } + + /// + /// Checks to see if a player or its associated group/temporary group has a specified permission. + /// + /// The permission to check. + /// True if the player has that permission. + public bool HasPermission(string permission) + { + if (PlayerHooks.OnPlayerPermission(this, permission)) + return true; + + if (tempGroup != null) + return tempGroup.HasPermission(permission); + else + return Group.HasPermission(permission); + } } public class TSRestPlayer : TSPlayer @@ -1001,568 +1018,4 @@ namespace TShockAPI return this.CommandOutput; } } - - public class TSServerPlayer : TSPlayer - { - public static string AccountName = "ServerConsole"; - - public TSServerPlayer() - : base("Server") - { - Group = new SuperAdminGroup(); - User = new User{Name = 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, "", dayTime ? 1 : 0, (int)time, 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 tiles) - { - // Update Main.Tile first so that when tile sqaure is sent it is correct - foreach (KeyValuePair 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.MaxInventory]; - 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? extraSlot; - public int? skinVariant; - 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 bool[] hideVisuals; - public int questsCompleted; - - public PlayerData(TSPlayer player) - { - for (int i = 0; i < NetItem.MaxInventory; i++) - { - this.inventory[i] = new NetItem(); - } - - for (int i = 0; i < TShock.ServerSideCharacterConfig.StartingInventory.Count; i++) - { - var item = TShock.ServerSideCharacterConfig.StartingInventory[i]; - StoreSlot(i, item.NetId, item.PrefixId, item.Stack); - } - } - - /// - /// Stores an item at the specific storage slot - /// - /// - /// - /// - /// - public void StoreSlot(int slot, int netID, byte prefix, int stack) - { - if (slot > (this.inventory.Length - 1)) //if the slot is out of range then dont save - { - return; - } - - this.inventory[slot] = new NetItem(netID, stack, prefix); - } - - /// - /// Copies a characters data to this object - /// - /// - 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; - } - extraSlot = player.TPlayer.extraAccessory ? 1 : 0; - this.skinVariant = player.TPlayer.skinVariant; - 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; - Item[] miscEqups = player.TPlayer.miscEquips; - Item[] miscDyes = player.TPlayer.miscDyes; - Item[] piggy = player.TPlayer.bank.item; - Item[] safe = player.TPlayer.bank2.item; - Item trash = player.TPlayer.trashItem; - - for (int i = 0; i < NetItem.MaxInventory; i++) - { - if (i < NetItem.InventorySlots) - { - //0-58 - this.inventory[i] = (NetItem)inventory[i]; - } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots) - { - //59-78 - var index = i - NetItem.InventorySlots; - this.inventory[i] = (NetItem)armor[index]; - } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots) - { - //79-88 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots); - this.inventory[i] = (NetItem)dye[index]; - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots) - { - //89-93 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots); - this.inventory[i] = (NetItem)miscEqups[index]; - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots - + NetItem.MiscDyeSlots) - { - //93-98 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots); - this.inventory[i] = (NetItem)miscDyes[index]; - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots) - { - //98-138 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots); - this.inventory[i] = (NetItem)piggy[index]; - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots) - { - //138-178 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots); - this.inventory[i] = (NetItem)safe[index]; - } - else - { - //179 - this.inventory[i] = (NetItem)trash; - } - } - } - - /// - /// Restores a player's character to the state stored in the database - /// - /// - 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 (extraSlot != null) - player.TPlayer.extraAccessory = extraSlot.Value == 1 ? true : false; - if (this.skinVariant != null) - player.TPlayer.skinVariant = this.skinVariant.Value; - 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; - else - player.TPlayer.hideVisual = new bool[player.TPlayer.hideVisual.Length]; - - for (int i = 0; i < NetItem.MaxInventory; i++) - { - if (i < NetItem.InventorySlots) - { - //0-58 - player.TPlayer.inventory[i].netDefaults(this.inventory[i].NetId); - - if (player.TPlayer.inventory[i].netID != 0) - { - player.TPlayer.inventory[i].stack = this.inventory[i].Stack; - player.TPlayer.inventory[i].prefix = this.inventory[i].PrefixId; - } - } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots) - { - //59-78 - var index = i - NetItem.InventorySlots; - player.TPlayer.armor[index].netDefaults(this.inventory[i].NetId); - - 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].PrefixId; - } - } - else if (i < NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots) - { - //79-88 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots); - player.TPlayer.dye[index].netDefaults(this.inventory[i].NetId); - - 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].PrefixId; - } - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots) - { - //89-93 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots); - player.TPlayer.miscEquips[index].netDefaults(this.inventory[i].NetId); - - if (player.TPlayer.miscEquips[index].netID != 0) - { - player.TPlayer.miscEquips[index].stack = this.inventory[i].Stack; - player.TPlayer.miscEquips[index].prefix = (byte)this.inventory[i].PrefixId; - } - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots - + NetItem.MiscDyeSlots) - { - //93-98 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots); - player.TPlayer.miscDyes[index].netDefaults(this.inventory[i].NetId); - - if (player.TPlayer.miscDyes[index].netID != 0) - { - player.TPlayer.miscDyes[index].stack = this.inventory[i].Stack; - player.TPlayer.miscDyes[index].prefix = (byte)this.inventory[i].PrefixId; - } - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots) - { - //98-138 - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots); - player.TPlayer.bank.item[index].netDefaults(this.inventory[i].NetId); - - if (player.TPlayer.bank.item[index].netID != 0) - { - player.TPlayer.bank.item[index].stack = this.inventory[i].Stack; - player.TPlayer.bank.item[index].prefix = (byte)this.inventory[i].PrefixId; - } - } - else if (i < - NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots + NetItem.MiscEquipSlots + - NetItem.MiscDyeSlots + NetItem.PiggySlots + NetItem.SafeSlots) - { - var index = i - (NetItem.InventorySlots + NetItem.ArmorSlots + NetItem.DyeSlots - + NetItem.MiscEquipSlots + NetItem.MiscDyeSlots + NetItem.PiggySlots); - player.TPlayer.bank2.item[index].netDefaults(this.inventory[i].NetId); - - if (player.TPlayer.bank2.item[index].netID != 0) - { - player.TPlayer.bank2.item[index].stack = this.inventory[i].Stack; - player.TPlayer.bank2.item[index].prefix = (byte)this.inventory[i].PrefixId; - } - } - else - { - player.TPlayer.trashItem.netDefaults(this.inventory[i].NetId); - - if (player.TPlayer.trashItem.netID != 0) - { - player.TPlayer.trashItem.stack = this.inventory[i].Stack; - player.TPlayer.trashItem.prefix = (byte)this.inventory[i].PrefixId; - } - } - } - - float slot = 0f; - for (int k = 0; k < NetItem.InventorySlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].inventory[k].name, player.Index, slot, (float)Main.player[player.Index].inventory[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.ArmorSlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].armor[k].name, player.Index, slot, (float)Main.player[player.Index].armor[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.DyeSlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].dye[k].name, player.Index, slot, (float)Main.player[player.Index].dye[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.MiscEquipSlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].miscEquips[k].name, player.Index, slot, (float)Main.player[player.Index].miscEquips[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.MiscDyeSlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].miscDyes[k].name, player.Index, slot, (float)Main.player[player.Index].miscDyes[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.PiggySlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].bank.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank.item[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.SafeSlots; k++) - { - NetMessage.SendData(5, -1, -1, Main.player[player.Index].bank2.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank2.item[k].prefix); - slot++; - } - - NetMessage.SendData(5, -1, -1, Main.player[player.Index].trashItem.name, player.Index, slot, (float)Main.player[player.Index].trashItem.prefix); - - 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); - - slot = 0f; - for (int k = 0; k < NetItem.InventorySlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].inventory[k].name, player.Index, slot, (float)Main.player[player.Index].inventory[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.ArmorSlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].armor[k].name, player.Index, slot, (float)Main.player[player.Index].armor[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.DyeSlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].dye[k].name, player.Index, slot, (float)Main.player[player.Index].dye[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.MiscEquipSlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].miscEquips[k].name, player.Index, slot, (float)Main.player[player.Index].miscEquips[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.MiscDyeSlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].miscDyes[k].name, player.Index, slot, (float)Main.player[player.Index].miscDyes[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.PiggySlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].bank.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank.item[k].prefix); - slot++; - } - for (int k = 0; k < NetItem.SafeSlots; k++) - { - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].bank2.item[k].name, player.Index, slot, (float)Main.player[player.Index].bank2.item[k].prefix); - slot++; - } - - NetMessage.SendData(5, player.Index, -1, Main.player[player.Index].trashItem.name, player.Index, slot, (float)Main.player[player.Index].trashItem.prefix); - - 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); - } - } } diff --git a/TShockAPI/TSServerPlayer.cs b/TShockAPI/TSServerPlayer.cs new file mode 100644 index 00000000..f36c3621 --- /dev/null +++ b/TShockAPI/TSServerPlayer.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using Terraria; +using TShockAPI; +using TShockAPI.DB; + +public class TSServerPlayer : TSPlayer +{ + public static string AccountName = "ServerConsole"; + + public TSServerPlayer() + : base("Server") + { + Group = new SuperAdminGroup(); + User = new User { Name = 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, "", dayTime ? 1 : 0, (int)time, 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 tiles) + { + // Update Main.Tile first so that when tile sqaure is sent it is correct + foreach (KeyValuePair 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); + } + } +} diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index c8a3ed11..977554f9 100755 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -989,7 +989,7 @@ namespace TShockAPI string check = "none"; foreach (Item item in player.TPlayer.inventory) { - if (!player.Group.HasPermission(Permissions.ignorestackhackdetection) && (item.stack > item.maxStack || item.stack < 0) && + if (!player.HasPermission(Permissions.ignorestackhackdetection) && (item.stack > item.maxStack || item.stack < 0) && item.type != 0) { check = "Remove item " + item.name + " (" + item.stack + ") exceeds max stack of " + item.maxStack; @@ -1334,7 +1334,7 @@ namespace TShockAPI } else { - if (!tsplr.Group.HasPermission(Permissions.canchat)) + if (!tsplr.HasPermission(Permissions.canchat)) { args.Handled = true; } @@ -1652,7 +1652,7 @@ namespace TShockAPI /// bool - True if the player should not be able to modify a tile. public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY, short tileType, GetDataHandlers.EditAction actionType) { - if (!player.Group.HasPermission(Permissions.canbuild)) + if (!player.HasPermission(Permissions.canbuild)) { if (TShock.Config.AllowIce && actionType != GetDataHandlers.EditAction.PlaceTile) { @@ -1687,7 +1687,7 @@ namespace TShockAPI return true; } - if (!player.Group.HasPermission(Permissions.editregion) && !Regions.CanBuild(tileX, tileY, player) && + if (!player.HasPermission(Permissions.editregion) && !Regions.CanBuild(tileX, tileY, player) && Regions.InArea(tileX, tileY)) { if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000) @@ -1700,7 +1700,7 @@ namespace TShockAPI if (Config.DisableBuild) { - if (!player.Group.HasPermission(Permissions.antibuild)) + if (!player.HasPermission(Permissions.antibuild)) { if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000) { @@ -1713,7 +1713,7 @@ namespace TShockAPI if (Config.SpawnProtection) { - if (!player.Group.HasPermission(Permissions.editspawn)) + if (!player.HasPermission(Permissions.editspawn)) { if (CheckSpawn(tileX, tileY)) { @@ -1737,8 +1737,8 @@ namespace TShockAPI /// bool - True if the player should not be able to modify the tile. public static bool CheckTilePermission(TSPlayer player, int tileX, int tileY, bool paint = false) { - if ((!paint && !player.Group.HasPermission(Permissions.canbuild)) || - (paint && !player.Group.HasPermission(Permissions.canpaint))) + if ((!paint && !player.HasPermission(Permissions.canbuild)) || + (paint && !player.HasPermission(Permissions.canpaint))) { if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.BPm) > 2000) { @@ -1755,7 +1755,7 @@ namespace TShockAPI return true; } - if (!player.Group.HasPermission(Permissions.editregion) && !Regions.CanBuild(tileX, tileY, player) && + if (!player.HasPermission(Permissions.editregion) && !Regions.CanBuild(tileX, tileY, player) && Regions.InArea(tileX, tileY)) { if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.RPm) > 2000) @@ -1768,7 +1768,7 @@ namespace TShockAPI if (Config.DisableBuild) { - if (!player.Group.HasPermission(Permissions.antibuild)) + if (!player.HasPermission(Permissions.antibuild)) { if (((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) - player.WPm) > 2000) { @@ -1781,7 +1781,7 @@ namespace TShockAPI if (Config.SpawnProtection) { - if (!player.Group.HasPermission(Permissions.editspawn)) + if (!player.HasPermission(Permissions.editspawn)) { if (CheckSpawn(tileX, tileY)) { diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index ec9b6549..21ce6172 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -89,6 +89,7 @@ + @@ -137,6 +138,7 @@ + @@ -193,7 +195,7 @@ - +