Merge branch 'general-devel' into handlegolfpacket
This commit is contained in:
commit
f7a8695c8f
17 changed files with 532 additions and 177 deletions
|
|
@ -3,6 +3,8 @@
|
|||
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
|
||||
* New permission `tshock.tp.pylon` to enable teleporting via Teleportation Pylons (@QuiCM)
|
||||
* New permission `tshock.journey.research` to enable sharing research via item sacrifice (@QuiCM)
|
||||
* Added LandGolfBallInCup event which is accessible for developers to work with, as well as LandGolfBallInCup handler to handle exploits where players could send direct packets to trigger and imitate golf ball cup landing anywhere in the game world. Added two public lists in Handlers.LandGolfBallInCupHandler: GolfBallProjectileIDs and GolfClubItemIDs. (@Patrikkk)
|
||||
|
||||
## TShock 4.4.0 (Pre-release 10)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ namespace TShockAPI
|
|||
internal sealed class Bouncer
|
||||
{
|
||||
internal Handlers.SendTileSquareHandler STSHandler { get; set; }
|
||||
internal Handlers.NetModules.NetModulePacketHandler NetModuleHandler { get; set; }
|
||||
internal Handlers.LandGolfBallInCupHandler LandGolfBallInCupHandler { get; set; }
|
||||
|
||||
/// <summary>Constructor call initializes Bouncer and related functionality.</summary>
|
||||
|
|
@ -44,7 +45,10 @@ namespace TShockAPI
|
|||
internal Bouncer()
|
||||
{
|
||||
STSHandler = new Handlers.SendTileSquareHandler();
|
||||
GetDataHandlers.SendTileSquare += STSHandler.OnReceiveSendTileSquare;
|
||||
GetDataHandlers.SendTileSquare += STSHandler.OnReceive;
|
||||
|
||||
NetModuleHandler = new Handlers.NetModules.NetModulePacketHandler();
|
||||
GetDataHandlers.ReadNetModule += NetModuleHandler.OnReceive;
|
||||
|
||||
LandGolfBallInCupHandler = new Handlers.LandGolfBallInCupHandler();
|
||||
GetDataHandlers.LandGolfBallInCup += LandGolfBallInCupHandler.OnLandGolfBallInCup;
|
||||
|
|
|
|||
|
|
@ -1987,7 +1987,7 @@ namespace TShockAPI
|
|||
|
||||
void FailedPermissionCheck()
|
||||
{
|
||||
args.Player.SendErrorMessage("You do not have sufficient permissions to start the {0} event.", eventType);
|
||||
args.Player.SendErrorMessage("You do not have permission to start the {0} event.", eventType);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4873,7 +4873,7 @@ namespace TShockAPI
|
|||
{
|
||||
if (!args.Player.HasPermission(Permissions.tp))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have the necessary permission to do that.");
|
||||
args.Player.SendErrorMessage("You do not have permission to teleport.");
|
||||
break;
|
||||
}
|
||||
if (args.Parameters.Count <= 1)
|
||||
|
|
@ -5051,7 +5051,7 @@ namespace TShockAPI
|
|||
}
|
||||
if (displayIdsRequested && !args.Player.HasPermission(Permissions.seeids))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have the required permission to list player ids.");
|
||||
args.Player.SendErrorMessage("You do not have permission to list player ids.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -6025,7 +6025,7 @@ namespace TShockAPI
|
|||
{
|
||||
if (!args.Player.HasPermission(Permissions.godmodeother))
|
||||
{
|
||||
args.Player.SendErrorMessage("You do not have permission to god mode another player!");
|
||||
args.Player.SendErrorMessage("You do not have permission to god mode another player.");
|
||||
return;
|
||||
}
|
||||
string plStr = String.Join(" ", args.Parameters);
|
||||
|
|
|
|||
|
|
@ -2002,6 +2002,40 @@ namespace TShockAPI
|
|||
return args.Handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used when a net module is loaded
|
||||
/// </summary>
|
||||
public class ReadNetModuleEventArgs : GetDataHandledEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of net module being loaded
|
||||
/// </summary>
|
||||
public NetModuleType ModuleType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a net module is received
|
||||
/// </summary>
|
||||
public static HandlerList<ReadNetModuleEventArgs> ReadNetModule = new HandlerList<ReadNetModuleEventArgs>();
|
||||
|
||||
private static bool OnReadNetModule(TSPlayer player, MemoryStream data, NetModuleType moduleType)
|
||||
{
|
||||
if (ReadNetModule == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var args = new ReadNetModuleEventArgs
|
||||
{
|
||||
Player = player,
|
||||
Data = data,
|
||||
ModuleType = moduleType
|
||||
};
|
||||
|
||||
ReadNetModule.Invoke(null, args);
|
||||
return args.Handled;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static bool HandlePlayerInfo(GetDataHandlerArgs args)
|
||||
|
|
@ -2259,11 +2293,10 @@ namespace TShockAPI
|
|||
|
||||
else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0) && (args.TPlayer.SpawnX > 0) && ((args.TPlayer.SpawnX != args.Player.sX) && (args.TPlayer.SpawnY != args.Player.sY)))
|
||||
{
|
||||
|
||||
args.Player.sX = args.TPlayer.SpawnX;
|
||||
args.Player.sY = args.TPlayer.SpawnY;
|
||||
|
||||
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY - 1)))
|
||||
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == TileID.Beds)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY - 1)))
|
||||
{
|
||||
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) - 48);
|
||||
TShock.Log.ConsoleDebug("GetDataHandlers / HandleSpawn force teleport phase 1 {0}", args.Player.Name);
|
||||
|
|
@ -2272,7 +2305,7 @@ namespace TShockAPI
|
|||
|
||||
else if ((Main.ServerSideCharacter) && (args.Player.sX > 0) && (args.Player.sY > 0))
|
||||
{
|
||||
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == 79)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY - 1)))
|
||||
if (((Main.tile[args.Player.sX, args.Player.sY - 1].active() && Main.tile[args.Player.sX, args.Player.sY - 1].type == TileID.Beds)) && (WorldGen.StartRoomCheck(args.Player.sX, args.Player.sY - 1)))
|
||||
{
|
||||
args.Player.Teleport(args.Player.sX * 16, (args.Player.sY * 16) - 48);
|
||||
TShock.Log.ConsoleDebug("GetDataHandlers / HandleSpawn force teleport phase 2 {0}", args.Player.Name);
|
||||
|
|
@ -2979,21 +3012,21 @@ namespace TShockAPI
|
|||
if (bosses.Contains(thingType) && !args.Player.HasPermission(Permissions.summonboss))
|
||||
{
|
||||
TShock.Log.ConsoleDebug("GetDataHandlers / HandleSpawnBoss rejected boss {0} {1}", args.Player.Name, thingType);
|
||||
args.Player.SendErrorMessage("You don't have permission to summon a boss.");
|
||||
args.Player.SendErrorMessage("You do not have permission to summon a boss.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (invasions.Contains(thingType) && !args.Player.HasPermission(Permissions.startinvasion))
|
||||
{
|
||||
TShock.Log.ConsoleDebug("GetDataHandlers / HandleSpawnBoss rejected invasion {0} {1}", args.Player.Name, thingType);
|
||||
args.Player.SendErrorMessage("You don't have permission to start an invasion.");
|
||||
args.Player.SendErrorMessage("You do not have permission to start an invasion.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pets.Contains(thingType) && !args.Player.HasPermission(Permissions.spawnpets))
|
||||
{
|
||||
TShock.Log.ConsoleDebug("GetDataHandlers / HandleSpawnBoss rejected pet {0} {1}", args.Player.Name, thingType);
|
||||
args.Player.SendErrorMessage("You don't have permission to spawn pets.");
|
||||
args.Player.SendErrorMessage("You do not have permission to spawn pets.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3276,160 +3309,12 @@ namespace TShockAPI
|
|||
private static bool HandleLoadNetModule(GetDataHandlerArgs args)
|
||||
{
|
||||
short moduleId = args.Data.ReadInt16();
|
||||
if (moduleId == (int)NetModulesTypes.CreativePowers)
|
||||
{
|
||||
CreativePowerTypes powerId = (CreativePowerTypes)args.Data.ReadInt16();
|
||||
switch (powerId)
|
||||
{
|
||||
case CreativePowerTypes.FreezeTime:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_timefreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the time of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.SetDawn:
|
||||
case CreativePowerTypes.SetNoon:
|
||||
case CreativePowerTypes.SetDusk:
|
||||
case CreativePowerTypes.SetMidnight:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_timeset))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the time of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.Godmode:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_godmode))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to toggle godmode!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.WindStrength:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_windstrength))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the wind strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.RainStrength:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_rainstrength))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the rain strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.TimeSpeed:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_timespeed))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the time speed of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.RainFreeze:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_rainfreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the rain strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.WindFreeze:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_windfreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the wind strength of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.IncreasePlacementRange:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_placementrange))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the tile placement range of your character!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.WorldDifficulty:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_setdifficulty))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the world difficulty of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.BiomeSpreadFreeze:
|
||||
{
|
||||
if (!args.Player.HasPermission(Permissions.journey_biomespreadfreeze))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to freeze the biome spread of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CreativePowerTypes.SetSpawnRate:
|
||||
{
|
||||
// This is a monkeypatch because the 1.4.0.4 seemingly at random sends NPC spawn rate changes even outside of journey mode
|
||||
// (with SSC on) -- particles, May 25, 2 Reiwa
|
||||
if (!Main.GameModeInfo.IsJourneyMode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!args.Player.HasPermission(Permissions.journey_setspawnrate))
|
||||
{
|
||||
args.Player.SendErrorMessage("You don't have permission to modify the NPC spawn rate of the server!");
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (moduleId == (int)NetModulesTypes.CreativeUnlocksPlayerReport && Main.GameModeInfo.IsJourneyMode)
|
||||
{
|
||||
var unknownField = args.Data.ReadByte();
|
||||
|
||||
if (unknownField == 0) //this is required or something???
|
||||
if (OnReadNetModule(args.Player, args.Data, (NetModuleType)moduleId))
|
||||
{
|
||||
var itemId = args.Data.ReadUInt16();
|
||||
var amount = args.Data.ReadUInt16();
|
||||
|
||||
var totalSacrificed = TShock.ResearchDatastore.SacrificeItem(itemId, amount, args.Player);
|
||||
|
||||
var response = NetCreativeUnlocksModule.SerializeItemSacrifice(itemId, totalSacrificed);
|
||||
NetManager.Instance.Broadcast(response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// As of 1.4.x.x, this is now used for more things:
|
||||
// NetCreativePowersModule
|
||||
// NetCreativePowerPermissionsModule
|
||||
// NetLiquidModule
|
||||
// NetParticlesModule
|
||||
// NetPingModule
|
||||
// NetTeleportPylonModule
|
||||
// NetTextModule
|
||||
// I (particles) have disabled the original return here, which means that we need to
|
||||
// handle this more. In the interm, this unbreaks parts of vanilla. Originally
|
||||
// we just blocked this because it was a liquid exploit.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3627,7 +3512,7 @@ namespace TShockAPI
|
|||
if (!args.Player.HasPermission(Permissions.startdd2))
|
||||
{
|
||||
TShock.Log.ConsoleDebug("GetDataHandlers / HandleOldOnesArmy rejected permissions {0}", args.Player.Name);
|
||||
args.Player.SendErrorMessage("You don't have permission to start the Old One's Army event.");
|
||||
args.Player.SendErrorMessage("You do not have permission to start the Old One's Army event.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3958,7 +3843,7 @@ namespace TShockAPI
|
|||
public bool Killed { get; internal set; }
|
||||
}
|
||||
|
||||
public enum NetModulesTypes
|
||||
public enum NetModuleType
|
||||
{
|
||||
Liquid,
|
||||
Text,
|
||||
|
|
|
|||
16
TShockAPI/Handlers/IPacketHandler.cs
Normal file
16
TShockAPI/Handlers/IPacketHandler.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
namespace TShockAPI.Handlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a packet handler that receives a packet from a GetDataHandler
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventArgs"></typeparam>
|
||||
public interface IPacketHandler<TEventArgs> where TEventArgs : GetDataHandledEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Invoked when the packet is received
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
void OnReceive(object sender, TEventArgs args);
|
||||
}
|
||||
}
|
||||
28
TShockAPI/Handlers/NetModules/AmbienceHandler.cs
Normal file
28
TShockAPI/Handlers/NetModules/AmbienceHandler.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.IO;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Rejects ambience new modules from clients
|
||||
/// </summary>
|
||||
public class AmbienceHandler : INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// No deserialization needed. This should never be received by the server
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Deserialize(MemoryStream data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This should never be received by the server
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
public void HandlePacket(TSPlayer player, out bool rejectPacket)
|
||||
{
|
||||
rejectPacket = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
TShockAPI/Handlers/NetModules/BestiaryHandler.cs
Normal file
28
TShockAPI/Handlers/NetModules/BestiaryHandler.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System.IO;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Rejects client->server bestiary net modules as the client should never send this to the server
|
||||
/// </summary>
|
||||
public class BestiaryHandler : INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// No deserialization needed. This should never be received by the server
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Deserialize(MemoryStream data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This should never be received by the server
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
public void HandlePacket(TSPlayer player, out bool rejectPacket)
|
||||
{
|
||||
rejectPacket = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
113
TShockAPI/Handlers/NetModules/CreativePowerHandler.cs
Normal file
113
TShockAPI/Handlers/NetModules/CreativePowerHandler.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Streams;
|
||||
using static TShockAPI.GetDataHandlers;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides handling for the Creative Power net module. Checks permissions on all creative powers
|
||||
/// </summary>
|
||||
public class CreativePowerHandler : INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// The power type being activated
|
||||
/// </summary>
|
||||
public CreativePowerTypes PowerType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads the power type from the stream
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Deserialize(MemoryStream data)
|
||||
{
|
||||
PowerType = (CreativePowerTypes)data.ReadInt16();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the player has permission to use the power type
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
public void HandlePacket(TSPlayer player, out bool rejectPacket)
|
||||
{
|
||||
if (!HasPermission(PowerType, player))
|
||||
{
|
||||
rejectPacket = true;
|
||||
return;
|
||||
}
|
||||
|
||||
rejectPacket = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a player has permission to use a specific creative power
|
||||
/// </summary>
|
||||
/// <param name="powerType"></param>
|
||||
/// <param name="player"></param>
|
||||
/// <returns></returns>
|
||||
public static bool HasPermission(CreativePowerTypes powerType, TSPlayer player)
|
||||
{
|
||||
if (!PowerToPermissionMap.ContainsKey(powerType))
|
||||
{
|
||||
TShock.Log.ConsoleDebug("CreativePowerHandler received permission check request for unknown creative power");
|
||||
return false;
|
||||
}
|
||||
|
||||
string permission = PowerToPermissionMap[powerType];
|
||||
|
||||
if (!player.HasPermission(permission))
|
||||
{
|
||||
player.SendErrorMessage("You do not have permission to {0}.", PermissionToDescriptionMap[permission]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Maps creative powers to permission nodes
|
||||
/// </summary>
|
||||
public static Dictionary<CreativePowerTypes, string> PowerToPermissionMap = new Dictionary<CreativePowerTypes, string>
|
||||
{
|
||||
{ CreativePowerTypes.FreezeTime, Permissions.journey_timefreeze },
|
||||
{ CreativePowerTypes.SetDawn, Permissions.journey_timeset },
|
||||
{ CreativePowerTypes.SetNoon, Permissions.journey_timeset },
|
||||
{ CreativePowerTypes.SetDusk, Permissions.journey_timeset },
|
||||
{ CreativePowerTypes.SetMidnight, Permissions.journey_timeset },
|
||||
{ CreativePowerTypes.Godmode, Permissions.journey_godmode },
|
||||
{ CreativePowerTypes.WindStrength, Permissions.journey_windstrength },
|
||||
{ CreativePowerTypes.RainStrength, Permissions.journey_rainstrength },
|
||||
{ CreativePowerTypes.TimeSpeed, Permissions.journey_timespeed },
|
||||
{ CreativePowerTypes.RainFreeze, Permissions.journey_rainfreeze },
|
||||
{ CreativePowerTypes.WindFreeze, Permissions.journey_windfreeze },
|
||||
{ CreativePowerTypes.IncreasePlacementRange, Permissions.journey_placementrange },
|
||||
{ CreativePowerTypes.WorldDifficulty, Permissions.journey_setdifficulty },
|
||||
{ CreativePowerTypes.BiomeSpreadFreeze, Permissions.journey_biomespreadfreeze },
|
||||
{ CreativePowerTypes.SetSpawnRate, Permissions.journey_setspawnrate },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Maps journey mode permission nodes to descriptions of what the permission allows
|
||||
/// </summary>
|
||||
public static Dictionary<string, string> PermissionToDescriptionMap = new Dictionary<string, string>
|
||||
{
|
||||
{ Permissions.journey_timefreeze, "freeze the time of the server" },
|
||||
{ Permissions.journey_timeset, "modify the time of the server" },
|
||||
{ Permissions.journey_timeset, "modify the time of the server" },
|
||||
{ Permissions.journey_timeset, "modify the time of the server" },
|
||||
{ Permissions.journey_timeset, "modify the time of the server" },
|
||||
{ Permissions.journey_godmode, "toggle godmode" },
|
||||
{ Permissions.journey_windstrength, "modify the wind strength of the server" },
|
||||
{ Permissions.journey_rainstrength, "modify the rain strength of the server" },
|
||||
{ Permissions.journey_timespeed, "modify the time speed of the server" },
|
||||
{ Permissions.journey_rainfreeze, "freeze the rain strength of the server" },
|
||||
{ Permissions.journey_windfreeze, "freeze the wind strength of the server" },
|
||||
{ Permissions.journey_placementrange, "modify the tile placement range of your character" },
|
||||
{ Permissions.journey_setdifficulty, "modify the world difficulty of the server" },
|
||||
{ Permissions.journey_biomespreadfreeze, "freeze the biome spread of the server" },
|
||||
{ Permissions.journey_setspawnrate, "modify the NPC spawn rate of the server" },
|
||||
};
|
||||
}
|
||||
}
|
||||
90
TShockAPI/Handlers/NetModules/CreativeUnlocksHandler.cs
Normal file
90
TShockAPI/Handlers/NetModules/CreativeUnlocksHandler.cs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
using System.IO;
|
||||
using System.IO.Streams;
|
||||
using Terraria;
|
||||
using Terraria.GameContent.NetModules;
|
||||
using Terraria.Net;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles creative unlock requests
|
||||
/// </summary>
|
||||
public class CreativeUnlocksHandler : INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// An unknown field. If this does not have a value of '0' the packet should be rejected.
|
||||
/// </summary>
|
||||
public byte UnknownField { get; set; }
|
||||
/// <summary>
|
||||
/// ID of the item being sacrificed
|
||||
/// </summary>
|
||||
public ushort ItemId { get; set; }
|
||||
/// <summary>
|
||||
/// Stack size of the item being sacrificed
|
||||
/// </summary>
|
||||
public ushort Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads the unlock data from the stream
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Deserialize(MemoryStream data)
|
||||
{
|
||||
// For whatever reason Terraria writes '0' to the stream at the beginning of this packet.
|
||||
// If this value is not 0 then its been crafted by a non-vanilla client.
|
||||
// We don't actually know why the 0 is written, so we're just going to call this UnknownField for now
|
||||
UnknownField = data.ReadInt8();
|
||||
if (UnknownField == 0)
|
||||
{
|
||||
ItemId = data.ReadUInt16();
|
||||
Amount = data.ReadUInt16();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the unlock is valid and the player has permission to perform the unlock.
|
||||
/// Syncs unlock status if the packet is accepted
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
public void HandlePacket(TSPlayer player, out bool rejectPacket)
|
||||
{
|
||||
if (!Main.GameModeInfo.IsJourneyMode)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(
|
||||
"NetModuleHandler received attempt to unlock sacrifice while not in journey mode from",
|
||||
player.Name
|
||||
);
|
||||
|
||||
rejectPacket = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (UnknownField != 0)
|
||||
{
|
||||
TShock.Log.ConsoleDebug(
|
||||
"CreativeUnlocksHandler received non-vanilla unlock request. Random field value: {0} but should be 0 from {1}",
|
||||
UnknownField,
|
||||
player.Name
|
||||
);
|
||||
|
||||
rejectPacket = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.HasPermission(Permissions.journey_contributeresearch))
|
||||
{
|
||||
player.SendErrorMessage("You do not have permission to contribute research.");
|
||||
rejectPacket = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var totalSacrificed = TShock.ResearchDatastore.SacrificeItem(ItemId, Amount, player);
|
||||
|
||||
var response = NetCreativeUnlocksModule.SerializeItemSacrifice(ItemId, totalSacrificed);
|
||||
NetManager.Instance.Broadcast(response);
|
||||
|
||||
rejectPacket = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
TShockAPI/Handlers/NetModules/INetModuleHandler.cs
Normal file
23
TShockAPI/Handlers/NetModules/INetModuleHandler.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System.IO;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Describes a handler for a net module
|
||||
/// </summary>
|
||||
public interface INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads the net module's data from the given stream
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
void Deserialize(MemoryStream data);
|
||||
|
||||
/// <summary>
|
||||
/// Provides handling for the packet and determines if it should be accepted or rejected
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
void HandlePacket(TSPlayer player, out bool rejectPacket);
|
||||
}
|
||||
}
|
||||
29
TShockAPI/Handlers/NetModules/LiquidHandler.cs
Normal file
29
TShockAPI/Handlers/NetModules/LiquidHandler.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System.IO;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles the NetLiquidModule. Rejects all incoming net liquid requests, as clients should never send them
|
||||
/// </summary>
|
||||
public class LiquidHandler : INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Does nothing. We should not deserialize this data
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Deserialize(MemoryStream data)
|
||||
{
|
||||
// No need to deserialize
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rejects the packet. Clients should not send this to us
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
public void HandlePacket(TSPlayer player, out bool rejectPacket)
|
||||
{
|
||||
rejectPacket = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
54
TShockAPI/Handlers/NetModules/NetModulePacketHandler.cs
Normal file
54
TShockAPI/Handlers/NetModules/NetModulePacketHandler.cs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Terraria;
|
||||
using static TShockAPI.GetDataHandlers;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles packet 82 - Load Net Module packets
|
||||
/// </summary>
|
||||
public class NetModulePacketHandler : IPacketHandler<ReadNetModuleEventArgs>
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps net module types to handlers for the net module type. Add to or edit this dictionary to customise handling
|
||||
/// </summary>
|
||||
public static Dictionary<NetModuleType, Type> NetModulesToHandlersMap = new Dictionary<NetModuleType, Type>
|
||||
{
|
||||
{ NetModuleType.CreativePowers, typeof(CreativePowerHandler) },
|
||||
{ NetModuleType.CreativeUnlocksPlayerReport, typeof(CreativeUnlocksHandler) },
|
||||
{ NetModuleType.TeleportPylon, typeof(PylonHandler) },
|
||||
{ NetModuleType.Liquid, typeof(LiquidHandler) },
|
||||
{ NetModuleType.Bestiary, typeof(BestiaryHandler) },
|
||||
{ NetModuleType.Ambience, typeof(AmbienceHandler) }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when a load net module packet is received. This method picks a <see cref="INetModuleHandler"/> based on the
|
||||
/// net module type being loaded, then forwards the data to the chosen handler to process
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
public void OnReceive(object sender, ReadNetModuleEventArgs args)
|
||||
{
|
||||
INetModuleHandler handler;
|
||||
|
||||
if (NetModulesToHandlersMap.ContainsKey(args.ModuleType))
|
||||
{
|
||||
handler = (INetModuleHandler)Activator.CreateInstance(NetModulesToHandlersMap[args.ModuleType]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't have handlers for NetModuleType.Ping and NetModuleType.Particles.
|
||||
// These net modules are fairly innocuous and can be processed normally by the game
|
||||
args.Handled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
handler.Deserialize(args.Data);
|
||||
handler.HandlePacket(args.Player, out bool rejectPacket);
|
||||
|
||||
args.Handled = rejectPacket;
|
||||
}
|
||||
}
|
||||
}
|
||||
62
TShockAPI/Handlers/NetModules/PylonHandler.cs
Normal file
62
TShockAPI/Handlers/NetModules/PylonHandler.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
using System.IO;
|
||||
using System.IO.Streams;
|
||||
using Terraria.GameContent;
|
||||
using static Terraria.GameContent.NetModules.NetTeleportPylonModule;
|
||||
|
||||
namespace TShockAPI.Handlers.NetModules
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles a pylon net module
|
||||
/// </summary>
|
||||
public class PylonHandler : INetModuleHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Event occuring
|
||||
/// </summary>
|
||||
public SubPacketType PylonEventType { get; set; }
|
||||
/// <summary>
|
||||
/// Tile X coordinate of the pylon
|
||||
/// </summary>
|
||||
public short TileX { get; set; }
|
||||
/// <summary>
|
||||
/// Tile Y coordinate of the pylon
|
||||
/// </summary>
|
||||
public short TileY { get; set; }
|
||||
/// <summary>
|
||||
/// Type of Pylon
|
||||
/// </summary>
|
||||
public TeleportPylonType PylonType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reads the pylon data from the net module
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
public void Deserialize(MemoryStream data)
|
||||
{
|
||||
PylonEventType = (SubPacketType)data.ReadInt8();
|
||||
TileX = data.ReadInt16();
|
||||
TileY = data.ReadInt16();
|
||||
PylonType = (TeleportPylonType)data.ReadInt8();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rejects a pylon teleport request if the player does not have permission
|
||||
/// </summary>
|
||||
/// <param name="player"></param>
|
||||
/// <param name="rejectPacket"></param>
|
||||
public void HandlePacket(TSPlayer player, out bool rejectPacket)
|
||||
{
|
||||
if (PylonEventType == SubPacketType.PlayerRequestsTeleport)
|
||||
{
|
||||
if (!player.HasPermission(Permissions.pylon))
|
||||
{
|
||||
rejectPacket = true;
|
||||
player.SendErrorMessage("You do not have permission to teleport with pylons.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rejectPacket = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,12 +14,12 @@ namespace TShockAPI.Handlers
|
|||
/// <summary>
|
||||
/// Provides processors for handling Tile Square packets
|
||||
/// </summary>
|
||||
public class SendTileSquareHandler
|
||||
public class SendTileSquareHandler : IPacketHandler<GetDataHandlers.SendTileSquareEventArgs>
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps grass-type blocks to flowers that can be grown on them with flower boots
|
||||
/// </summary>
|
||||
Dictionary<ushort, List<ushort>> _grassToPlantMap = new Dictionary<ushort, List<ushort>>
|
||||
public static Dictionary<ushort, List<ushort>> GrassToPlantMap = new Dictionary<ushort, List<ushort>>
|
||||
{
|
||||
{ TileID.Grass, new List<ushort> { TileID.Plants, TileID.Plants2 } },
|
||||
{ TileID.HallowedGrass, new List<ushort> { TileID.HallowedPlants, TileID.HallowedPlants2 } },
|
||||
|
|
@ -29,7 +29,7 @@ namespace TShockAPI.Handlers
|
|||
/// <summary>
|
||||
/// Item IDs that can spawn flowers while you walk
|
||||
/// </summary>
|
||||
List<int> _flowerBootItems = new List<int>
|
||||
public static List<int> FlowerBootItems = new List<int>
|
||||
{
|
||||
ItemID.FlowerBoots,
|
||||
ItemID.FairyBoots
|
||||
|
|
@ -40,7 +40,7 @@ namespace TShockAPI.Handlers
|
|||
/// Note: <see cref="Terraria.ID.TileEntityID"/> is empty at the time of writing, but entities are dynamically assigned their ID at initialize time
|
||||
/// which is why we can use the _myEntityId field on each entity type
|
||||
/// </summary>
|
||||
Dictionary<int, int> _tileEntityIdToTileIdMap = new Dictionary<int, int>
|
||||
public static Dictionary<int, int> TileEntityIdToTileIdMap = new Dictionary<int, int>
|
||||
{
|
||||
{ TileID.TargetDummy, TETrainingDummy._myEntityID },
|
||||
{ TileID.ItemFrame, TEItemFrame._myEntityID },
|
||||
|
|
@ -57,7 +57,7 @@ namespace TShockAPI.Handlers
|
|||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
public void OnReceiveSendTileSquare(object sender, GetDataHandlers.SendTileSquareEventArgs args)
|
||||
public void OnReceive(object sender, GetDataHandlers.SendTileSquareEventArgs args)
|
||||
{
|
||||
// By default, we'll handle everything
|
||||
args.Handled = true;
|
||||
|
|
@ -192,13 +192,19 @@ namespace TShockAPI.Handlers
|
|||
return;
|
||||
}
|
||||
|
||||
if (TShock.TileBans.TileIsBanned((short)tileType))
|
||||
{
|
||||
TShock.Log.ConsoleDebug("Bouncer / SendTileSquare rejected for banned tile");
|
||||
return;
|
||||
}
|
||||
|
||||
// Update all tiles in the tile object. These will be sent back to the player later
|
||||
UpdateMultipleServerTileStates(realX, realY, width, height, newTiles);
|
||||
|
||||
// Tile entities have special placements that we should let the game deal with
|
||||
if (_tileEntityIdToTileIdMap.ContainsKey(tileType))
|
||||
if (TileEntityIdToTileIdMap.ContainsKey(tileType))
|
||||
{
|
||||
TileEntity.PlaceEntityNet(realX, realY, _tileEntityIdToTileIdMap[tileType]);
|
||||
TileEntity.PlaceEntityNet(realX, realY, TileEntityIdToTileIdMap[tileType]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -214,7 +220,7 @@ namespace TShockAPI.Handlers
|
|||
{
|
||||
// Some boots allow growing flowers on grass. This process sends a 1x1 tile square to grow the flowers
|
||||
// The square size must be 1 and the player must have an accessory that allows growing flowers in order for this square to be valid
|
||||
if (squareSize == 1 && args.Player.Accessories.Any(a => a != null && _flowerBootItems.Contains(a.type)))
|
||||
if (squareSize == 1 && args.Player.Accessories.Any(a => a != null && FlowerBootItems.Contains(a.type)))
|
||||
{
|
||||
ProcessFlowerBoots(realX, realY, newTile, args);
|
||||
return;
|
||||
|
|
@ -254,7 +260,7 @@ namespace TShockAPI.Handlers
|
|||
}
|
||||
|
||||
ITile tile = Main.tile[realX, realY + 1];
|
||||
if (!_grassToPlantMap.TryGetValue(tile.type, out List<ushort> plantTiles) && !plantTiles.Contains(newTile.Type))
|
||||
if (!GrassToPlantMap.TryGetValue(tile.type, out List<ushort> plantTiles) && !plantTiles.Contains(newTile.Type))
|
||||
{
|
||||
// If the tile below the tile square isn't a valid plant tile (eg grass) then we don't update the server tile state
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -267,6 +267,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("User can use wormhole potions.")]
|
||||
public static readonly string wormhole = "tshock.tp.wormhole";
|
||||
|
||||
[Description("User can use pylons to teleport")]
|
||||
public static readonly string pylon = "tshock.tp.pylon";
|
||||
#endregion
|
||||
|
||||
#region tshock.world nodes
|
||||
|
|
@ -409,6 +412,9 @@ namespace TShockAPI
|
|||
|
||||
[Description("User can use Creative UI to set the NPC spawn rate of the world.")]
|
||||
public static readonly string journey_setspawnrate = "tshock.journey.setspawnrate";
|
||||
|
||||
[Description("User can contribute research by sacrificing items")]
|
||||
public static readonly string journey_contributeresearch = "tshock.journey.research";
|
||||
#endregion
|
||||
|
||||
#region Non-grouped
|
||||
|
|
|
|||
|
|
@ -664,13 +664,13 @@ namespace TShockAPI
|
|||
switch (failure)
|
||||
{
|
||||
case BuildPermissionFailPoint.GeneralBuild:
|
||||
SendErrorMessage("You lack permission to build on this server.");
|
||||
SendErrorMessage("You do not have permission to build on this server.");
|
||||
break;
|
||||
case BuildPermissionFailPoint.SpawnProtect:
|
||||
SendErrorMessage("You lack permission to build in the spawn point.");
|
||||
SendErrorMessage("You do not have permission to build in the spawn point.");
|
||||
break;
|
||||
case BuildPermissionFailPoint.Regions:
|
||||
SendErrorMessage("You lack permission to build in this region.");
|
||||
SendErrorMessage("You do not have permission to build in this region.");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,15 @@
|
|||
<Compile Include="DB\ResearchDatastore.cs" />
|
||||
<Compile Include="DB\TileManager.cs" />
|
||||
<Compile Include="Extensions\ExceptionExt.cs" />
|
||||
<Compile Include="Handlers\IPacketHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\AmbienceHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\BestiaryHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\CreativePowerHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\CreativeUnlocksHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\INetModuleHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\LiquidHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\NetModulePacketHandler.cs" />
|
||||
<Compile Include="Handlers\NetModules\PylonHandler.cs" />
|
||||
<Compile Include="Handlers\LandGolfBallInCupHandler.cs" />
|
||||
<Compile Include="Handlers\SendTileSquareHandler.cs" />
|
||||
<Compile Include="Hooks\AccountHooks.cs" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue