using System.IO; using System.IO.Streams; using Terraria; using Terraria.GameContent.NetModules; using Terraria.Net; namespace TShockAPI.Handlers.NetModules { /// /// Handles creative unlock requests /// public class CreativeUnlocksHandler : INetModuleHandler { /// /// An unknown field. If this does not have a value of '0' the packet should be rejected. /// public byte UnknownField { get; set; } /// /// ID of the item being sacrificed /// public ushort ItemId { get; set; } /// /// Stack size of the item being sacrificed /// public ushort Amount { get; set; } /// /// Reads the unlock data from the stream /// /// 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(); } } /// /// Determines if the unlock is valid and the player has permission to perform the unlock. /// Syncs unlock status if the packet is accepted /// /// /// public void HandlePacket(TSPlayer player, out bool rejectPacket) { if (!Main.IsJourneyMode) { TShock.Log.ConsoleDebug( GetString( $"NetModuleHandler received attempt to unlock sacrifice while not in journey mode from {player.Name}") ); rejectPacket = true; return; } if (UnknownField != 0) { TShock.Log.ConsoleDebug( GetString( $"CreativeUnlocksHandler received non-vanilla unlock request. Random field value: {UnknownField} but should be 0 from {player.Name}") ); rejectPacket = true; return; } if (!player.HasPermission(Permissions.journey_contributeresearch)) { player.SendErrorMessage(GetString("You do not have permission to contribute research.")); rejectPacket = true; return; } var totalSacrificed = TShock.ResearchDatastore.SacrificeItem(ItemId, Amount, player); var response = NetCreativeUnlocksPlayerReportModule.SerializeSacrificeRequest(player.Index, ItemId, totalSacrificed); NetManager.Instance.Broadcast(response); rejectPacket = false; } } }