From 492b88ca157e656bfaf1607efc0f0e0b91668568 Mon Sep 17 00:00:00 2001 From: Josh Harris Date: Sun, 9 Jul 2017 00:42:37 +0100 Subject: [PATCH 1/2] Updated to the latest Terraria version --- Multiplicity.Packets/AddNPCBuff.cs | 7 +- Multiplicity.Packets/AddPlayerBuff.cs | 13 +- Multiplicity.Packets/AlterItemDrop.cs | 127 +++++-- Multiplicity.Packets/AnglerQuest.cs | 7 +- Multiplicity.Packets/CatchNPC.cs | 7 +- Multiplicity.Packets/ChatMessagev2.cs | 28 +- Multiplicity.Packets/ChestItem.cs | 10 +- Multiplicity.Packets/ClientUUID.cs | 10 +- .../CompleteAnglerQuestToday.cs | 10 +- .../CompleteConnectionandSpawn.cs | 10 +- Multiplicity.Packets/ConnectRequest.cs | 18 +- Multiplicity.Packets/ContinueConnecting.cs | 8 +- Multiplicity.Packets/ContinueConnecting2.cs | 10 +- Multiplicity.Packets/CreateCombatText.cs | 19 +- .../CreateTemporaryAnimation.cs | 7 +- .../CrystalInvasionSendWaitTime.cs | 26 +- Multiplicity.Packets/CrystalInvasionStart.cs | 12 +- .../CrystalInvasionWipeAll.cs | 11 +- Multiplicity.Packets/Deprecated.cs | 16 +- Multiplicity.Packets/DestroyProjectile.cs | 7 +- Multiplicity.Packets/Disconnect.cs | 27 +- Multiplicity.Packets/DoorToggle.cs | 7 +- .../Extensions/BinaryReader.Extensions.cs | 6 + .../Extensions/BinaryWriter.Extensions.cs | 6 + .../ForceItemIntoNearestChest.cs | 8 +- Multiplicity.Packets/GetChestContents.cs | 7 +- Multiplicity.Packets/GetChestName.cs | 84 +++-- Multiplicity.Packets/GetSection.cs | 7 +- Multiplicity.Packets/GrowFX.cs | 15 +- Multiplicity.Packets/HealEffect.cs | 7 +- Multiplicity.Packets/HealOtherPlayer.cs | 7 +- Multiplicity.Packets/HitSwitch.cs | 7 +- Multiplicity.Packets/KillPortal.cs | 7 +- Multiplicity.Packets/ManaEffect.cs | 7 +- Multiplicity.Packets/MassWireOperation.cs | 10 +- .../MassWireOperationConsume.cs | 7 +- .../MinionAttackTargetUpdate.cs | 18 +- Multiplicity.Packets/Models/NetworkText.cs | 114 ++++++ Multiplicity.Packets/ModifyTile.cs | 39 ++- .../Multiplicity.Packets.csproj | 1 + Multiplicity.Packets/NPCHomeUpdate.cs | 10 +- Multiplicity.Packets/NPCStrike.cs | 10 +- .../NPCTeleportThroughPortal.cs | 10 +- Multiplicity.Packets/NPCUpdate.cs | 141 ++------ Multiplicity.Packets/NebulaLevelUpRequest.cs | 11 +- Multiplicity.Packets/NotifyPlayerNPCKilled.cs | 7 +- Multiplicity.Packets/NotifyPlayerOfEvent.cs | 7 +- .../NumberOfAnglerQuestsCompleted.cs | 10 +- Multiplicity.Packets/PaintTile.cs | 7 +- Multiplicity.Packets/PaintWall.cs | 7 +- Multiplicity.Packets/PlaceChest.cs | 151 ++++---- Multiplicity.Packets/PlaceItemFrame.cs | 7 +- Multiplicity.Packets/PlaceObject.cs | 10 +- Multiplicity.Packets/PlaceTileEntity.cs | 7 +- Multiplicity.Packets/PlayMusicItem.cs | 8 +- Multiplicity.Packets/PlayerActive.cs | 7 +- Multiplicity.Packets/PlayerDodge.cs | 8 +- Multiplicity.Packets/PlayerHP.cs | 7 +- Multiplicity.Packets/PlayerInfo.cs | 12 +- Multiplicity.Packets/PlayerInventorySlot.cs | 10 +- Multiplicity.Packets/PlayerItemAnimation.cs | 10 +- Multiplicity.Packets/PlayerMana.cs | 7 +- Multiplicity.Packets/PlayerNPCTeleport.cs | 7 +- Multiplicity.Packets/PlayerTeam.cs | 8 +- .../PlayerTeleportThroughPortal.cs | 10 +- Multiplicity.Packets/PlayerZone.cs | 26 +- Multiplicity.Packets/PoofofSmoke.cs | 7 +- Multiplicity.Packets/ProjectileUpdate.cs | 327 +++++++----------- Multiplicity.Packets/ReleaseNPC.cs | 24 +- Multiplicity.Packets/RemoveItemOwner.cs | 7 +- .../ReportInvasionProgress.cs | 10 +- Multiplicity.Packets/RequestPassword.cs | 10 +- Multiplicity.Packets/RequestSign.cs | 7 +- Multiplicity.Packets/SectionTileFrame.cs | 7 +- Multiplicity.Packets/SendPassword.cs | 8 +- Multiplicity.Packets/SendSection.cs | 24 +- Multiplicity.Packets/SendTileSquare.cs | 39 ++- Multiplicity.Packets/SetActiveNPC.cs | 7 +- Multiplicity.Packets/SetChestName.cs | 173 ++++----- Multiplicity.Packets/SetLiquid.cs | 7 +- Multiplicity.Packets/SetNPCKillCount.cs | 7 +- Multiplicity.Packets/SetNPCShopItem.cs | 10 +- Multiplicity.Packets/SetPlayerStealth.cs | 8 +- Multiplicity.Packets/SocialHandshake.cs | 10 +- Multiplicity.Packets/SpawnBossInvasion.cs | 7 +- Multiplicity.Packets/SpawnPlayer.cs | 7 +- Multiplicity.Packets/SpecialNPCEffect.cs | 8 +- Multiplicity.Packets/Status.cs | 16 +- Multiplicity.Packets/StrikeNPCwithHeldItem.cs | 7 +- Multiplicity.Packets/SyncEmoteBubble.cs | 76 ++-- Multiplicity.Packets/SyncExtraValue.cs | 7 +- Multiplicity.Packets/SyncPlayerChestIndex.cs | 7 +- Multiplicity.Packets/TeleportationPotion.cs | 10 +- Multiplicity.Packets/Time.cs | 7 +- Multiplicity.Packets/ToggleBirthdayParty.cs | 10 +- Multiplicity.Packets/ToggleGemLock.cs | 7 +- Multiplicity.Packets/TogglePVP.cs | 7 +- Multiplicity.Packets/Unlock.cs | 7 +- Multiplicity.Packets/UpdateGoodEvil.cs | 8 +- Multiplicity.Packets/UpdateItemDrop.cs | 10 +- Multiplicity.Packets/UpdateItemDrop2.cs | 10 +- Multiplicity.Packets/UpdateItemOwner.cs | 7 +- Multiplicity.Packets/UpdateMinionTarget.cs | 8 +- .../UpdateMoonLordCountdown.cs | 7 +- Multiplicity.Packets/UpdateNPCBuff.cs | 43 ++- Multiplicity.Packets/UpdateNPCName.cs | 26 +- Multiplicity.Packets/UpdatePlayer.cs | 197 ++++++----- Multiplicity.Packets/UpdatePlayerBuff.cs | 14 +- Multiplicity.Packets/UpdateShieldStrengths.cs | 10 +- Multiplicity.Packets/UpdateSign.cs | 7 +- Multiplicity.Packets/UpdateTileEntity.cs | 109 ++++-- Multiplicity.Packets/WiredCannonShot.cs | 10 +- Multiplicity.Packets/WorldInfo.cs | 37 +- 113 files changed, 1623 insertions(+), 1024 deletions(-) create mode 100644 Multiplicity.Packets/Models/NetworkText.cs diff --git a/Multiplicity.Packets/AddNPCBuff.cs b/Multiplicity.Packets/AddNPCBuff.cs index 2e975c8..b862016 100644 --- a/Multiplicity.Packets/AddNPCBuff.cs +++ b/Multiplicity.Packets/AddNPCBuff.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(Buff); br.Write(Time); diff --git a/Multiplicity.Packets/AddPlayerBuff.cs b/Multiplicity.Packets/AddPlayerBuff.cs index ba571e4..aa4ca31 100644 --- a/Multiplicity.Packets/AddPlayerBuff.cs +++ b/Multiplicity.Packets/AddPlayerBuff.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -13,7 +14,7 @@ public class AddPlayerBuff : TerrariaPacket public byte Buff { get; set; } - public short Time { get; set; } + public int Time { get; set; } /// /// Initializes a new instance of the class. @@ -33,7 +34,7 @@ public AddPlayerBuff(BinaryReader br) { this.PlayerID = br.ReadByte(); this.Buff = br.ReadByte(); - this.Time = br.ReadInt16(); + this.Time = br.ReadInt32(); } public override string ToString() @@ -45,7 +46,7 @@ public override string ToString() public override short GetLength() { - return (short)(4); + return (short)(6); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Buff); br.Write(Time); diff --git a/Multiplicity.Packets/AlterItemDrop.cs b/Multiplicity.Packets/AlterItemDrop.cs index c34460d..8770d91 100644 --- a/Multiplicity.Packets/AlterItemDrop.cs +++ b/Multiplicity.Packets/AlterItemDrop.cs @@ -7,6 +7,7 @@ // Copyright (c) 2016 Celant using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -54,25 +55,76 @@ public AlterItemDrop(BinaryReader br) { this.ItemIndex = br.ReadInt16(); this.Flags1 = br.ReadByte(); - this.PackedColorValue = br.ReadUInt32(); - this.Damage = br.ReadUInt16(); - this.Knockback = br.ReadSingle(); - this.UseAnimation = br.ReadUInt16(); - this.UseTime = br.ReadUInt16(); - this.Shoot = br.ReadInt16(); - this.ShootSpeed = br.ReadSingle(); - this.Flags2 = br.ReadByte(); - this.Width = br.ReadInt16(); - this.Height = br.ReadInt16(); - this.Scale = br.ReadSingle(); - this.Ammo = br.ReadInt16(); - this.UseAmmo = br.ReadInt16(); - this.NotAmmo = br.ReadBoolean(); + if (this.Flags1.ReadBit(0)) + this.PackedColorValue = br.ReadUInt32(); + if (this.Flags1.ReadBit(1)) + this.Damage = br.ReadUInt16(); + if (this.Flags1.ReadBit(2)) + this.Knockback = br.ReadSingle(); + if (this.Flags1.ReadBit(3)) + this.UseAnimation = br.ReadUInt16(); + if (this.Flags1.ReadBit(4)) + this.UseTime = br.ReadUInt16(); + if (this.Flags1.ReadBit(5)) + this.Shoot = br.ReadInt16(); + if (this.Flags1.ReadBit(6)) + this.ShootSpeed = br.ReadSingle(); + + if (this.Flags1.ReadBit(7)) + { + this.Flags2 = br.ReadByte(); + if (this.Flags1.ReadBit(0)) + this.Width = br.ReadInt16(); + if (this.Flags1.ReadBit(1)) + this.Height = br.ReadInt16(); + if (this.Flags1.ReadBit(2)) + this.Scale = br.ReadSingle(); + if (this.Flags1.ReadBit(3)) + this.Ammo = br.ReadInt16(); + if (this.Flags1.ReadBit(4)) + this.UseAmmo = br.ReadInt16(); + if (this.Flags1.ReadBit(5)) + this.NotAmmo = br.ReadBoolean(); + } } public override short GetLength() { - return 37; + short length = 3; + + if (this.Flags1.ReadBit(0)) + length += 4; + if (this.Flags1.ReadBit(1)) + length += 2; + if (this.Flags1.ReadBit(2)) + length += 4; + if (this.Flags1.ReadBit(3)) + length += 2; + if (this.Flags1.ReadBit(4)) + length += 2; + if (this.Flags1.ReadBit(5)) + length += 2; + if (this.Flags1.ReadBit(6)) + length += 4; + + if (this.Flags1.ReadBit(7)) + { + length += 1; + if (this.Flags1.ReadBit(0)) + length += 2; + if (this.Flags1.ReadBit(1)) + length += 2; + if (this.Flags1.ReadBit(2)) + length += 4; + if (this.Flags1.ReadBit(3)) + length += 2; + if (this.Flags1.ReadBit(4)) + length += 2; + if (this.Flags1.ReadBit(5)) + length += 1; + } + + return length; } public override void ToStream(Stream stream, bool includeHeader = true) @@ -83,20 +135,37 @@ public override void ToStream(Stream stream, bool includeHeader = true) { bw.Write(ItemIndex); bw.Write(Flags1); - bw.Write(PackedColorValue); - bw.Write(Damage); - bw.Write(Knockback); - bw.Write(UseAnimation); - bw.Write(UseTime); - bw.Write(Shoot); - bw.Write(ShootSpeed); - bw.Write(Flags2); - bw.Write(Width); - bw.Write(Height); - bw.Write(Scale); - bw.Write(Ammo); - bw.Write(UseAmmo); - bw.Write(NotAmmo); + if (Flags1.ReadBit(1)) + bw.Write(PackedColorValue); + if (this.Flags1.ReadBit(2)) + bw.Write(Damage); + if (this.Flags1.ReadBit(4)) + bw.Write(Knockback); + if (this.Flags1.ReadBit(8)) + bw.Write(UseAnimation); + if (this.Flags1.ReadBit(16)) + bw.Write(UseTime); + if (this.Flags1.ReadBit(32)) + bw.Write(Shoot); + if (this.Flags1.ReadBit(64)) + bw.Write(ShootSpeed); + + if (this.Flags1.ReadBit(128)) + { + bw.Write(Flags2); + if (this.Flags1.ReadBit(1)) + bw.Write(Width); + if (this.Flags1.ReadBit(1)) + bw.Write(Height); + if (this.Flags1.ReadBit(1)) + bw.Write(Scale); + if (this.Flags1.ReadBit(1)) + bw.Write(Ammo); + if (this.Flags1.ReadBit(1)) + bw.Write(UseAmmo); + if (this.Flags1.ReadBit(1)) + bw.Write(NotAmmo); + } } } diff --git a/Multiplicity.Packets/AnglerQuest.cs b/Multiplicity.Packets/AnglerQuest.cs index 182834a..f9a34a0 100644 --- a/Multiplicity.Packets/AnglerQuest.cs +++ b/Multiplicity.Packets/AnglerQuest.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Quest); br.Write(Completed); } diff --git a/Multiplicity.Packets/CatchNPC.cs b/Multiplicity.Packets/CatchNPC.cs index 98fdb14..339fe28 100644 --- a/Multiplicity.Packets/CatchNPC.cs +++ b/Multiplicity.Packets/CatchNPC.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(Who); } diff --git a/Multiplicity.Packets/ChatMessagev2.cs b/Multiplicity.Packets/ChatMessagev2.cs index e8d280a..7812beb 100644 --- a/Multiplicity.Packets/ChatMessagev2.cs +++ b/Multiplicity.Packets/ChatMessagev2.cs @@ -1,7 +1,8 @@ using System; -using System.Drawing; using System.IO; using Multiplicity.Packets.Extensions; +using System.Drawing; +using Multiplicity.Packets.Models; namespace Multiplicity.Packets { @@ -11,17 +12,15 @@ namespace Multiplicity.Packets public class ChatMessagev2 : TerrariaPacket { - /// - /// Gets or sets the PlayerID - If 255 Then No Name| - /// - public byte PlayerID { get; set; } - /// /// Gets or sets the MessageColor - Client cannot change colors| /// public Color MessageColor { get; set; } - public string Message { get; set; } + /// + /// Gets or sets the Message - |-| + /// + public NetworkText Message { get; set; } public short MessageLength { get; set; } @@ -41,23 +40,21 @@ public ChatMessagev2() public ChatMessagev2(BinaryReader br) : base(br) { - this.PlayerID = br.ReadByte(); this.MessageColor = br.ReadColor(); - this.Message = br.ReadString(); + this.Message = br.ReadNetworkText(); this.MessageLength = br.ReadInt16(); } public override string ToString() { - return - $"[ChatMessagev2: PlayerID = {PlayerID} MessageColor = {MessageColor} Message = {Message} MessageLength = {MessageLength}]"; + return $"[ChatMessagev2: MessageColor = {MessageColor} Message = {Message.Text} MessageLength = {MessageLength}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(7 + Message.Length); + return (short)(5 + Message.GetLength()); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -65,7 +62,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -77,8 +75,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { - br.Write(PlayerID); + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(MessageColor); br.Write(Message); br.Write(MessageLength); diff --git a/Multiplicity.Packets/ChestItem.cs b/Multiplicity.Packets/ChestItem.cs index 851e729..92c3cce 100644 --- a/Multiplicity.Packets/ChestItem.cs +++ b/Multiplicity.Packets/ChestItem.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -44,8 +45,7 @@ public ChestItem(BinaryReader br) public override string ToString() { - return - $"[ChestItem: ChestID = {ChestID} ItemSlot = {ItemSlot} Stack = {Stack} Prefix = {Prefix} ItemNetID = {ItemNetID}]"; + return $"[ChestItem: ChestID = {ChestID} ItemSlot = {ItemSlot} Stack = {Stack} Prefix = {Prefix} ItemNetID = {ItemNetID}]"; } #region implemented abstract members of TerrariaPacket @@ -60,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -72,7 +73,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ChestID); br.Write(ItemSlot); br.Write(Stack); diff --git a/Multiplicity.Packets/ClientUUID.cs b/Multiplicity.Packets/ClientUUID.cs index fdd8af1..5b1366b 100644 --- a/Multiplicity.Packets/ClientUUID.cs +++ b/Multiplicity.Packets/ClientUUID.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -34,7 +36,7 @@ public ClientUUID(BinaryReader br) public override string ToString() { - return $"[ClientUUID: {UUID}]"; + return $"[ClientUUID: UUID = {UUID}]"; } #region implemented abstract members of TerrariaPacket @@ -49,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -61,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(UUID); } } diff --git a/Multiplicity.Packets/CompleteAnglerQuestToday.cs b/Multiplicity.Packets/CompleteAnglerQuestToday.cs index 9efca0c..813e4b9 100644 --- a/Multiplicity.Packets/CompleteAnglerQuestToday.cs +++ b/Multiplicity.Packets/CompleteAnglerQuestToday.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public CompleteAnglerQuestToday(BinaryReader br) public override string ToString() { - return string.Format("[CompleteAnglerQuestToday]"); + return $"[CompleteAnglerQuestToday:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/CompleteConnectionandSpawn.cs b/Multiplicity.Packets/CompleteConnectionandSpawn.cs index ba802c1..e0488db 100644 --- a/Multiplicity.Packets/CompleteConnectionandSpawn.cs +++ b/Multiplicity.Packets/CompleteConnectionandSpawn.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public CompleteConnectionandSpawn(BinaryReader br) public override string ToString() { - return string.Format("[CompleteConnectionandSpawn]"); + return $"[CompleteConnectionandSpawn:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/ConnectRequest.cs b/Multiplicity.Packets/ConnectRequest.cs index 30bd1e8..5e0a914 100644 --- a/Multiplicity.Packets/ConnectRequest.cs +++ b/Multiplicity.Packets/ConnectRequest.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -22,16 +24,6 @@ public ConnectRequest() } - /// - /// Initializes a new instance of the class. - /// - /// The version to be set in the packet - public ConnectRequest(string version) - : base((byte)PacketTypes.ConnectRequest) - { - this.Version = version; - } - /// /// Initializes a new instance of the class. /// @@ -59,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -71,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Version); } } diff --git a/Multiplicity.Packets/ContinueConnecting.cs b/Multiplicity.Packets/ContinueConnecting.cs index 402521f..9525ec3 100644 --- a/Multiplicity.Packets/ContinueConnecting.cs +++ b/Multiplicity.Packets/ContinueConnecting.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -46,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -58,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); } } diff --git a/Multiplicity.Packets/ContinueConnecting2.cs b/Multiplicity.Packets/ContinueConnecting2.cs index a00ff1e..7967a0e 100644 --- a/Multiplicity.Packets/ContinueConnecting2.cs +++ b/Multiplicity.Packets/ContinueConnecting2.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public ContinueConnecting2(BinaryReader br) public override string ToString() { - return string.Format("[ContinueConnecting2]"); + return $"[ContinueConnecting2:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/CreateCombatText.cs b/Multiplicity.Packets/CreateCombatText.cs index 66f9d84..52111d8 100644 --- a/Multiplicity.Packets/CreateCombatText.cs +++ b/Multiplicity.Packets/CreateCombatText.cs @@ -1,6 +1,7 @@ -using System.Drawing; +using System; using System.IO; using Multiplicity.Packets.Extensions; +using System.Drawing; namespace Multiplicity.Packets { @@ -16,7 +17,7 @@ public class CreateCombatText : TerrariaPacket public Color Color { get; set; } - public string Text { get; set; } + public int HealAmount { get; set; } /// /// Initializes a new instance of the class. @@ -37,19 +38,19 @@ public CreateCombatText(BinaryReader br) this.X = br.ReadSingle(); this.Y = br.ReadSingle(); this.Color = br.ReadColor(); - this.Text = br.ReadString(); + this.HealAmount = br.ReadInt32(); } public override string ToString() { - return $"[CreateCombatText: X = {X} Y = {Y} Color = {Color} Text = {Text}]"; + return $"[CreateCombatText: X = {X} Y = {Y} Color = {Color} HealAmount = {HealAmount}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(12 + Text.Length); + return (short)(15); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -57,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -69,11 +71,12 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(Color); - br.Write(Text); + br.Write(HealAmount); } } diff --git a/Multiplicity.Packets/CreateTemporaryAnimation.cs b/Multiplicity.Packets/CreateTemporaryAnimation.cs index b32df27..5c403aa 100644 --- a/Multiplicity.Packets/CreateTemporaryAnimation.cs +++ b/Multiplicity.Packets/CreateTemporaryAnimation.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(AnimationType); br.Write(TileType); br.Write(X); diff --git a/Multiplicity.Packets/CrystalInvasionSendWaitTime.cs b/Multiplicity.Packets/CrystalInvasionSendWaitTime.cs index 92edc03..a0f7ab2 100644 --- a/Multiplicity.Packets/CrystalInvasionSendWaitTime.cs +++ b/Multiplicity.Packets/CrystalInvasionSendWaitTime.cs @@ -1,29 +1,42 @@ -using System.IO; +using System; +using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { /// - /// The CrystalInvasionSendWaitTime (74) packet. + /// The CrystalInvasionSendWaitTime (0x74) packet. /// public class CrystalInvasionSendWaitTime : TerrariaPacket { - public int NextWaveTime { get; set; } + /// + /// Gets or sets the TimeUntilNextWave - 1800 (30s) between waves, 30 (5s) when starting| + /// + public int TimeUntilNextWave { get; set; } + + /// + /// Initializes a new instance of the class. + /// public CrystalInvasionSendWaitTime() : base((byte)PacketTypes.CrystalInvasionSendWaitTime) { } + /// + /// Initializes a new instance of the class. + /// + /// br public CrystalInvasionSendWaitTime(BinaryReader br) : base(br) { - NextWaveTime = br.ReadInt32(); + this.TimeUntilNextWave = br.ReadInt32(); } public override string ToString() { - return $"[CrystalInvasionSendWaitTime: NextWaveTime = {NextWaveTime}]"; + return $"[CrystalInvasionSendWaitTime: TimeUntilNextWave = {TimeUntilNextWave}]"; } #region implemented abstract members of TerrariaPacket @@ -53,10 +66,11 @@ public override void ToStream(Stream stream, bool includeHeader = true) */ using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { - br.Write(NextWaveTime); + br.Write(TimeUntilNextWave); } } #endregion + } } diff --git a/Multiplicity.Packets/CrystalInvasionStart.cs b/Multiplicity.Packets/CrystalInvasionStart.cs index 02a7a7c..7f8acb6 100644 --- a/Multiplicity.Packets/CrystalInvasionStart.cs +++ b/Multiplicity.Packets/CrystalInvasionStart.cs @@ -1,12 +1,15 @@ -using System.IO; +using System; +using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { /// - /// The CrystalInvasionStart (71) packet. + /// The CrystalInvasionStart (0x71) packet. /// public class CrystalInvasionStart : TerrariaPacket { + public short X { get; set; } public short Y { get; set; } @@ -27,8 +30,8 @@ public CrystalInvasionStart() public CrystalInvasionStart(BinaryReader br) : base(br) { - X = br.ReadInt16(); - Y = br.ReadInt16(); + this.X = br.ReadInt16(); + this.Y = br.ReadInt16(); } public override string ToString() @@ -69,5 +72,6 @@ public override void ToStream(Stream stream, bool includeHeader = true) } #endregion + } } diff --git a/Multiplicity.Packets/CrystalInvasionWipeAll.cs b/Multiplicity.Packets/CrystalInvasionWipeAll.cs index c6f14bd..794a51e 100644 --- a/Multiplicity.Packets/CrystalInvasionWipeAll.cs +++ b/Multiplicity.Packets/CrystalInvasionWipeAll.cs @@ -1,12 +1,15 @@ -using System.IO; +using System; +using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { /// - /// The CrystalInvasionWipeAll (72) packet. + /// The CrystalInvasionWipeAll (0x72) packet. /// public class CrystalInvasionWipeAll : TerrariaPacket { + /// /// Initializes a new instance of the class. /// @@ -23,12 +26,11 @@ public CrystalInvasionWipeAll() public CrystalInvasionWipeAll(BinaryReader br) : base(br) { - } public override string ToString() { - return $"[CrystalInvaionWipeAll]"; + return $"[CrystalInvasionWipeAll:]"; } #region implemented abstract members of TerrariaPacket @@ -62,5 +64,6 @@ public override void ToStream(Stream stream, bool includeHeader = true) } #endregion + } } diff --git a/Multiplicity.Packets/Deprecated.cs b/Multiplicity.Packets/Deprecated.cs index a38b4cd..cef9442 100644 --- a/Multiplicity.Packets/Deprecated.cs +++ b/Multiplicity.Packets/Deprecated.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -12,7 +13,7 @@ public class Deprecated : TerrariaPacket /// /// Initializes a new instance of the class. /// - public Deprecated() + public Deprecated() : base((byte)PacketTypes.Deprecated) { @@ -22,15 +23,14 @@ public Deprecated() /// Initializes a new instance of the class. /// /// br - public Deprecated(BinaryReader br) + public Deprecated(BinaryReader br) : base(br) { - } public override string ToString() { - return string.Format("[Deprecated]"); + return $"[Deprecated:]"; } #region implemented abstract members of TerrariaPacket @@ -45,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -57,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/DestroyProjectile.cs b/Multiplicity.Packets/DestroyProjectile.cs index 0dfcb85..9956840 100644 --- a/Multiplicity.Packets/DestroyProjectile.cs +++ b/Multiplicity.Packets/DestroyProjectile.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ProjectileID); br.Write(Owner); } diff --git a/Multiplicity.Packets/Disconnect.cs b/Multiplicity.Packets/Disconnect.cs index 88aeddd..e2e3e1d 100644 --- a/Multiplicity.Packets/Disconnect.cs +++ b/Multiplicity.Packets/Disconnect.cs @@ -1,4 +1,7 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; +using Multiplicity.Packets.Models; namespace Multiplicity.Packets { @@ -8,7 +11,7 @@ namespace Multiplicity.Packets public class Disconnect : TerrariaPacket { - public string Reason { get; set; } + public NetworkText Reason { get; set; } /// /// Initializes a new instance of the class. @@ -19,16 +22,6 @@ public Disconnect() } - /// - /// Initializes a new instance of the class. - /// - /// Reason for disconnecting the client. - public Disconnect(string reason) - : base((byte)PacketTypes.Disconnect) - { - this.Reason = reason; - } - /// /// Initializes a new instance of the class. /// @@ -36,19 +29,19 @@ public Disconnect(string reason) public Disconnect(BinaryReader br) : base(br) { - this.Reason = br.ReadString(); + this.Reason = br.ReadNetworkText(); } public override string ToString() { - return $"[Disconnect: Reason = {Reason}]"; + return $"[Disconnect: Reason = {Reason.Text}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(1 + Reason.Length); + return (short)(0 + Reason.GetLength()); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -56,7 +49,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +62,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Reason); } } diff --git a/Multiplicity.Packets/DoorToggle.cs b/Multiplicity.Packets/DoorToggle.cs index d412043..7f6d66b 100644 --- a/Multiplicity.Packets/DoorToggle.cs +++ b/Multiplicity.Packets/DoorToggle.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -62,7 +63,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -74,7 +76,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Action); br.Write(TileX); br.Write(TileY); diff --git a/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs b/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs index d5afbe4..d690af7 100644 --- a/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs +++ b/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs @@ -1,5 +1,6 @@ using System.Drawing; using System.IO; +using Multiplicity.Packets.Models; namespace Multiplicity.Packets.Extensions { @@ -10,6 +11,11 @@ public static Color ReadColor(this BinaryReader br) byte[] colourPayload = br.ReadBytes(3); return Color.FromArgb(colourPayload[0], colourPayload[1], colourPayload[2]); } + + public static NetworkText ReadNetworkText(this BinaryReader br) + { + return new NetworkText(br); + } } } diff --git a/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs b/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs index abdd819..99f7db2 100644 --- a/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs +++ b/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs @@ -1,4 +1,5 @@ using System.IO; +using Multiplicity.Packets.Models; namespace Multiplicity.Packets.Extensions { @@ -14,6 +15,11 @@ public static void Write(this BinaryWriter bw, System.Drawing.Color color) bw.Write(rgb, 0, 3); } + + public static void Write(this BinaryWriter bw, NetworkText text) + { + text.ToStream(bw); + } } } diff --git a/Multiplicity.Packets/ForceItemIntoNearestChest.cs b/Multiplicity.Packets/ForceItemIntoNearestChest.cs index f639402..06671ae 100644 --- a/Multiplicity.Packets/ForceItemIntoNearestChest.cs +++ b/Multiplicity.Packets/ForceItemIntoNearestChest.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -46,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -58,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(InventorySlot); } } diff --git a/Multiplicity.Packets/GetChestContents.cs b/Multiplicity.Packets/GetChestContents.cs index 904e6ab..17f1b3c 100644 --- a/Multiplicity.Packets/GetChestContents.cs +++ b/Multiplicity.Packets/GetChestContents.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(TileX); br.Write(TileY); } diff --git a/Multiplicity.Packets/GetChestName.cs b/Multiplicity.Packets/GetChestName.cs index b7fc2c9..0cd55d7 100644 --- a/Multiplicity.Packets/GetChestName.cs +++ b/Multiplicity.Packets/GetChestName.cs @@ -1,59 +1,85 @@ -// -// ChestName.cs -// -// Author: -// Luke S -// -// Copyright (c) 2016 Luke S - +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { + /// + /// The GetChestName (0x45) packet. + /// public class GetChestName : TerrariaPacket { + public short ChestID { get; set; } - public short X { get; set; } - public short Y { get; set; } + + public short ChestX { get; set; } + + public short ChestY { get; set; } + public string Name { get; set; } - public GetChestName(short chestID, short x, short y, string name) + /// + /// Initializes a new instance of the class. + /// + public GetChestName() : base((byte)PacketTypes.GetChestName) { - this.ChestID = chestID; - this.X = x; - this.Y = y; - this.Name = name; + } + /// + /// Initializes a new instance of the class. + /// + /// br public GetChestName(BinaryReader br) : base(br) { this.ChestID = br.ReadInt16(); - this.X = br.ReadInt16(); - this.Y = br.ReadInt16(); + this.ChestX = br.ReadInt16(); + this.ChestY = br.ReadInt16(); this.Name = br.ReadString(); } + public override string ToString() + { + return $"[GetChestName: ChestID = {ChestID} ChestX = {ChestX} ChestY = {ChestY} Name = {Name}]"; + } + + #region implemented abstract members of TerrariaPacket + + public override short GetLength() + { + return (short)(7 + Name.Length); + } + public override void ToStream(Stream stream, bool includeHeader = true) { - base.ToStream(stream, includeHeader); + /* + * Length and ID headers get written in the base packet class. + */ + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } - using (BinaryWriter bw = new BinaryWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true)) + /* + * Always make sure to not close the stream when serializing. + * + * It is up to the caller to decide if the underlying stream + * gets closed. If this is a network stream we do not want + * the regressions of unconditionally closing the TCP socket + * once the payload of data has been sent to the client. + */ + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { - bw.Write(this.ChestID); - bw.Write(this.X); - bw.Write(this.Y); - bw.Write(this.Name); + br.Write(ChestID); + br.Write(ChestX); + br.Write(ChestY); + br.Write(Name); } } - public override short GetLength() - { - return (short)(6 + this.Name.Length); - } + #endregion - public override string ToString() => - $"[{nameof(GetChestName)}: ChestID={ChestID},X={X},Y={Y},Name={Name}]"; } } diff --git a/Multiplicity.Packets/GetSection.cs b/Multiplicity.Packets/GetSection.cs index a07db6a..0cff2ce 100644 --- a/Multiplicity.Packets/GetSection.cs +++ b/Multiplicity.Packets/GetSection.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); } diff --git a/Multiplicity.Packets/GrowFX.cs b/Multiplicity.Packets/GrowFX.cs index 553de11..97048eb 100644 --- a/Multiplicity.Packets/GrowFX.cs +++ b/Multiplicity.Packets/GrowFX.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -17,6 +18,8 @@ public class GrowFX : TerrariaPacket public byte Height { get; set; } + public short TreeGore { get; set; } + /// /// Initializes a new instance of the class. /// @@ -37,18 +40,19 @@ public GrowFX(BinaryReader br) this.X = br.ReadInt16(); this.Y = br.ReadInt16(); this.Height = br.ReadByte(); + this.TreeGore = br.ReadInt16(); } public override string ToString() { - return $"[GrowFX: GrowEffect = {GrowEffect} X = {X} Y = {Y} Height = {Height}]"; + return $"[GrowFX: GrowEffect = {GrowEffect} X = {X} Y = {Y} Height = {Height} TreeGore = {TreeGore}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(6); + return (short)(8); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -56,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,11 +73,13 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(GrowEffect); br.Write(X); br.Write(Y); br.Write(Height); + br.Write(TreeGore); } } diff --git a/Multiplicity.Packets/HealEffect.cs b/Multiplicity.Packets/HealEffect.cs index 19f0d09..d03d40f 100644 --- a/Multiplicity.Packets/HealEffect.cs +++ b/Multiplicity.Packets/HealEffect.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(HealAmount); } diff --git a/Multiplicity.Packets/HealOtherPlayer.cs b/Multiplicity.Packets/HealOtherPlayer.cs index 5390e57..0a5205e 100644 --- a/Multiplicity.Packets/HealOtherPlayer.cs +++ b/Multiplicity.Packets/HealOtherPlayer.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(HealAmount); } diff --git a/Multiplicity.Packets/HitSwitch.cs b/Multiplicity.Packets/HitSwitch.cs index 9384bc5..cb5bed7 100644 --- a/Multiplicity.Packets/HitSwitch.cs +++ b/Multiplicity.Packets/HitSwitch.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); } diff --git a/Multiplicity.Packets/KillPortal.cs b/Multiplicity.Packets/KillPortal.cs index 40cea31..070839f 100644 --- a/Multiplicity.Packets/KillPortal.cs +++ b/Multiplicity.Packets/KillPortal.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -59,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ProjectileIndex); } } diff --git a/Multiplicity.Packets/ManaEffect.cs b/Multiplicity.Packets/ManaEffect.cs index ecc5dff..9cda453 100644 --- a/Multiplicity.Packets/ManaEffect.cs +++ b/Multiplicity.Packets/ManaEffect.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(ManaAmount); } diff --git a/Multiplicity.Packets/MassWireOperation.cs b/Multiplicity.Packets/MassWireOperation.cs index 89c9441..3b41cb9 100644 --- a/Multiplicity.Packets/MassWireOperation.cs +++ b/Multiplicity.Packets/MassWireOperation.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,8 +48,7 @@ public MassWireOperation(BinaryReader br) public override string ToString() { - return - $"[MassWireOperation: StartX = {StartX} StartY = {StartY} EndX = {EndX} EndY = {EndY} ToolMode = {ToolMode}]"; + return $"[MassWireOperation: StartX = {StartX} StartY = {StartY} EndX = {EndX} EndY = {EndY} ToolMode = {ToolMode}]"; } #region implemented abstract members of TerrariaPacket @@ -63,7 +63,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -75,7 +76,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(StartX); br.Write(StartY); br.Write(EndX); diff --git a/Multiplicity.Packets/MassWireOperationConsume.cs b/Multiplicity.Packets/MassWireOperationConsume.cs index cea9834..88ec5c6 100644 --- a/Multiplicity.Packets/MassWireOperationConsume.cs +++ b/Multiplicity.Packets/MassWireOperationConsume.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ItemType); br.Write(Quantity); br.Write(PlayerID); diff --git a/Multiplicity.Packets/MinionAttackTargetUpdate.cs b/Multiplicity.Packets/MinionAttackTargetUpdate.cs index a6afdbe..0a709fb 100644 --- a/Multiplicity.Packets/MinionAttackTargetUpdate.cs +++ b/Multiplicity.Packets/MinionAttackTargetUpdate.cs @@ -1,13 +1,16 @@ -using System.IO; +using System; +using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { /// - /// The MinionAttackTargetUpdate (73) packet. + /// The MinionAttackTargetUpdate (0x73) packet. /// public class MinionAttackTargetUpdate : TerrariaPacket { - public byte PlayerId { get; set; } + + public byte PlayerID { get; set; } public short MinionAttackTarget { get; set; } @@ -27,13 +30,13 @@ public MinionAttackTargetUpdate() public MinionAttackTargetUpdate(BinaryReader br) : base(br) { - PlayerId = br.ReadByte(); - MinionAttackTarget = br.ReadInt16(); + this.PlayerID = br.ReadByte(); + this.MinionAttackTarget = br.ReadInt16(); } public override string ToString() { - return $"[MinionAttackTargetUpdate: PlayerId = {PlayerId} MinionAttackTarget = {MinionAttackTarget}]"; + return $"[MinionAttackTargetUpdate: PlayerID = {PlayerID} MinionAttackTarget = {MinionAttackTarget}]"; } #region implemented abstract members of TerrariaPacket @@ -63,11 +66,12 @@ public override void ToStream(Stream stream, bool includeHeader = true) */ using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { - br.Write(PlayerId); + br.Write(PlayerID); br.Write(MinionAttackTarget); } } #endregion + } } diff --git a/Multiplicity.Packets/Models/NetworkText.cs b/Multiplicity.Packets/Models/NetworkText.cs new file mode 100644 index 0000000..bf86784 --- /dev/null +++ b/Multiplicity.Packets/Models/NetworkText.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Multiplicity.Packets.Extensions; + +namespace Multiplicity.Packets.Models +{ + /// + /// Represents an translatable string of text + /// + public class NetworkText + { + public enum Mode : byte + { + Literal = 0, + Formattable, + LocalizationKey, + } + + /// + /// Mode of the text + /// + public byte TextMode { get; set; } + + /// + /// The text itself + /// + public string Text { get; set; } + + /// + /// The length of the SubstitutionList + /// + public byte SubstitutionListLength { get; set; } + + /// + /// A list of substitutions to make + /// + public NetworkText[] SubstitutionList { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public NetworkText() + { + + } + + /// + /// Reads from the given reader and initializes a new instance of the class. + /// + /// Reader to initialize instance from. + public NetworkText(BinaryReader br) + { + this.TextMode = br.ReadByte(); + this.Text = br.ReadString(); + if (this.TextMode != (byte) Mode.Literal) + { + this.SubstitutionListLength = br.ReadByte(); + this.SubstitutionList = new NetworkText[(int)SubstitutionListLength]; + + for (int i = 0; i < this.SubstitutionListLength; i++) + { + this.SubstitutionList[i] = br.ReadNetworkText(); + } + } + } + + /// + /// Writes this instance to the given BinaryWriter. + /// + /// BinaryWriter to write contents to. + public void ToStream(BinaryWriter bw) + { + bw.Write(TextMode); + bw.Write(Text); + if (this.TextMode != (byte) Mode.Literal) + { + bw.Write(SubstitutionList.Length); + + for (int i = 0; i < this.SubstitutionListLength; i++) + { + bw.Write(this.SubstitutionList[i]); + } + } + } + + /// + /// Gets the length of the NetworkText object in bytes. + /// + /// The length in bytes. + public short GetLength() + { + short length = 1; + + // Length of the text in bytes (Terraria only supports extended ASCII) + // Add 1 to accomodate for the string length byte + length += (short)(1 + (short)this.Text.Length); + + if (this.TextMode != (byte) Mode.Literal) + { + length += 1; + for (int i = 0; i < this.SubstitutionListLength; i++) + { + length += this.SubstitutionList[i].GetLength(); + } + } + + return length; + } + } +} diff --git a/Multiplicity.Packets/ModifyTile.cs b/Multiplicity.Packets/ModifyTile.cs index 90a2078..d3cbdc8 100644 --- a/Multiplicity.Packets/ModifyTile.cs +++ b/Multiplicity.Packets/ModifyTile.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -10,9 +11,7 @@ public class ModifyTile : TerrariaPacket { /// - /// Gets or sets the Action - 0 = Kill Tile, 1 = Place Tile, 2 = Kill Wall, 3 = Place Wall, 4 = Kill Tile No Item, 5 = Place Wire - /// 6 = Kill Wire, 7 = Pound Tile, 8 = Place Actuator, 9 = Kill Actuator, 10 = Place Wire2, 11 = Kill Wire2, 12 = Place Wire3, 13 = Kill Wire3 - /// 14 = Slope Tile, 15 = Frame Track, 16 = Place Wire4, 17 = Kill Wire4, 18 = Poke Logic Gate, 19 = Actuate + /// Gets or sets the Action - Values: 0 = KillTile, 1 = PlaceTile, 2 = KillWall, 3 = PlaceWall, 4 = KillTileNoItem, 5 = PlaceWire, 6 = KillWire, 7 = PoundTile, 8 = PlaceActuator, 9 = KillActuator, 10 = PlaceWire2, 11 = KillWire2, 12 = PlaceWire3, 13 = KillWire3, 14 = SlopeTile, 15 = FrameTrack, 16 = PlaceWire4, 17 = KillWire4, 18 = PokeLogicGate, 19 = Actuate| /// public byte Action { get; set; } @@ -20,15 +19,21 @@ public class ModifyTile : TerrariaPacket public short TileY { get; set; } - public short EditData { get; set; } + /// + /// Gets or sets the Var1 - KillTile (Fail: Bool), PlaceTile (Type: Byte), KillWall (Fail: Bool), PlaceWall (Type: Byte), KillTileNoItem (Fail: Bool), SlopeTile (Slope: Byte)| + /// + public short Var1 { get; set; } - public byte Style { get; set; } + /// + /// Gets or sets the Var2 - Var2: PlaceTile (Style: Byte)| + /// + public byte Var2 { get; set; } /// /// Initializes a new instance of the class. /// - public ModifyTile() - : base((byte)PacketTypes.ModifyTile) + public ModifyTile() + : base((byte)PacketTypes.ModifyTile) { } @@ -37,19 +42,19 @@ public ModifyTile() /// Initializes a new instance of the class. /// /// br - public ModifyTile(BinaryReader br) + public ModifyTile(BinaryReader br) : base(br) { this.Action = br.ReadByte(); this.TileX = br.ReadInt16(); this.TileY = br.ReadInt16(); - this.EditData = br.ReadInt16(); - this.Style = br.ReadByte(); + this.Var1 = br.ReadInt16(); + this.Var2 = br.ReadByte(); } public override string ToString() { - return $"[ModifyTile: Action = {Action} TileX = {TileX} TileY = {TileY} EditData = {EditData} Style = {Style}]"; + return $"[ModifyTile: Action = {Action} TileX = {TileX} TileY = {TileY} Var1 = {Var1} Var2 = {Var2}]"; } #region implemented abstract members of TerrariaPacket @@ -64,7 +69,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -76,12 +82,13 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Action); br.Write(TileX); br.Write(TileY); - br.Write(EditData); - br.Write(Style); + br.Write(Var1); + br.Write(Var2); } } diff --git a/Multiplicity.Packets/Multiplicity.Packets.csproj b/Multiplicity.Packets/Multiplicity.Packets.csproj index 1fd5ae0..6e7f723 100644 --- a/Multiplicity.Packets/Multiplicity.Packets.csproj +++ b/Multiplicity.Packets/Multiplicity.Packets.csproj @@ -172,6 +172,7 @@ + \ No newline at end of file diff --git a/Multiplicity.Packets/NPCHomeUpdate.cs b/Multiplicity.Packets/NPCHomeUpdate.cs index 5aab499..9148078 100644 --- a/Multiplicity.Packets/NPCHomeUpdate.cs +++ b/Multiplicity.Packets/NPCHomeUpdate.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -41,8 +42,7 @@ public NPCHomeUpdate(BinaryReader br) public override string ToString() { - return - $"[NPCHomeUpdate: NPCID = {NPCID} HomeTileX = {HomeTileX} HomeTileY = {HomeTileY} Homeless = {Homeless}]"; + return $"[NPCHomeUpdate: NPCID = {NPCID} HomeTileX = {HomeTileX} HomeTileY = {HomeTileY} Homeless = {Homeless}]"; } #region implemented abstract members of TerrariaPacket @@ -57,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -69,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(HomeTileX); br.Write(HomeTileY); diff --git a/Multiplicity.Packets/NPCStrike.cs b/Multiplicity.Packets/NPCStrike.cs index 9548a86..a78a72e 100644 --- a/Multiplicity.Packets/NPCStrike.cs +++ b/Multiplicity.Packets/NPCStrike.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -44,8 +45,7 @@ public NPCStrike(BinaryReader br) public override string ToString() { - return - $"[NPCStrike: NPCID = {NPCID} Damage = {Damage} Knockback = {Knockback} Direction = {Direction} Crit = {Crit}]"; + return $"[NPCStrike: NPCID = {NPCID} Damage = {Damage} Knockback = {Knockback} Direction = {Direction} Crit = {Crit}]"; } #region implemented abstract members of TerrariaPacket @@ -60,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -72,7 +73,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(Damage); br.Write(Knockback); diff --git a/Multiplicity.Packets/NPCTeleportThroughPortal.cs b/Multiplicity.Packets/NPCTeleportThroughPortal.cs index 543a49e..a1d88c1 100644 --- a/Multiplicity.Packets/NPCTeleportThroughPortal.cs +++ b/Multiplicity.Packets/NPCTeleportThroughPortal.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,8 +48,7 @@ public NPCTeleportThroughPortal(BinaryReader br) public override string ToString() { - return - $"[NPCTeleportThroughPortal: NPCID = {NPCID} PortalColorIndex = {PortalColorIndex} NewPositionX = {NewPositionX} NewPositionY = {NewPositionY} VelocityX = {VelocityX} VelocityY = {VelocityY}]"; + return $"[NPCTeleportThroughPortal: NPCID = {NPCID} PortalColorIndex = {PortalColorIndex} NewPositionX = {NewPositionX} NewPositionY = {NewPositionY} VelocityX = {VelocityX} VelocityY = {VelocityY}]"; } #region implemented abstract members of TerrariaPacket @@ -63,7 +63,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -75,7 +76,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(PortalColorIndex); br.Write(NewPositionX); diff --git a/Multiplicity.Packets/NPCUpdate.cs b/Multiplicity.Packets/NPCUpdate.cs index 0bd10a7..fdc92ca 100644 --- a/Multiplicity.Packets/NPCUpdate.cs +++ b/Multiplicity.Packets/NPCUpdate.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -19,9 +20,6 @@ public enum NPCUpdateFlags : byte public class NPCUpdate : TerrariaPacket { - protected short _npcLifeBytes = 1; - protected bool _releaseOwner = false; - public short NPCID { get; protected set; } public float PositionX { get; set; } @@ -32,23 +30,16 @@ public class NPCUpdate : TerrariaPacket public float VelocityY { get; set; } - public byte Target { get; set; } - - public NPCUpdateFlags Flags { get; set; } - - public int? Life { get; set; } + public ushort Target { get; set; } - public float[] AI { get; set; } + public byte Flags { get; set; } - public short NPCNetID { get; set; } - - public byte ReleaseOwner { get; set; } + public byte[] Remainder { get; set; } public NPCUpdate() : base((byte)PacketTypes.NPCUpdate) { this.NPCID = NPCID; - this.AI = new float[4]; } public NPCUpdate(BinaryReader br) @@ -59,90 +50,36 @@ public NPCUpdate(BinaryReader br) this.PositionY = br.ReadSingle(); this.VelocityX = br.ReadSingle(); this.VelocityY = br.ReadSingle(); - this.Target = br.ReadByte(); - this.Flags = (NPCUpdateFlags)br.ReadByte(); - - this.AI = new float[4]; - - for (int i = 0; i < 4; i++) - { - float ai = 0; - - if (((byte)Flags & (1 << (i + 2))) != 0) - { - ai = br.ReadSingle(); - } - - AI[i] = ai; - } - - this.NPCNetID = br.ReadInt16(); + this.Target = br.ReadUInt16(); + this.Flags = br.ReadByte(); - if ((Flags & NPCUpdateFlags.FullLife) == NPCUpdateFlags.None) - { - /* - * This is a fucking filthy hack, have to take stream length - * as a way to work out how much packet buffer we have left - * because the Terraria process has a runtime dictionary of NPC - * life bytes which tells the packet processor how many bytes of - * the NPC life there is in the packet. - * - * We don't have access to this information short of blurting - * up our on dictionary of NPC life bytes in which I would rather - * kill myself than do. - */ - long bufferLeft = br.BaseStream.Length - br.BaseStream.Position; - - if (bufferLeft >= 4) - { - this.Life = (int)br.ReadInt32(); - _npcLifeBytes = 4; - } - else if (bufferLeft >= 2) - { - this.Life = (int)br.ReadInt16(); - _npcLifeBytes = 2; - } - else - { - this.Life = (int)br.ReadSByte(); - _npcLifeBytes = 1; - } - } + /* + * This is a fucking filthy hack, have to take stream length + * as a way to work out how much packet buffer we have left + * because the Terraria process has a runtime dictionary of NPC + * life bytes which tells the packet processor how many bytes of + * the NPC life there is in the packet. + * + * We don't have access to this information short of blurting + * up our on dictionary of NPC life bytes in which I would rather + * kill myself than do. + */ if (br.BaseStream.Length - br.BaseStream.Position > 0) { - _releaseOwner = true; - this.ReleaseOwner = br.ReadByte(); + this.Remainder = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)); } } public override short GetLength() { - short fixedLen = 22; + short fixedLen = 21; /* * Dynamic packet sizes fucking suck balls */ - for (int i = 0; i < 4; i++) - { - if (((byte)Flags & (1 << (i + 2))) != 0) - { - fixedLen += 4; - } - } - - - if ((Flags & NPCUpdateFlags.FullLife) == NPCUpdateFlags.None) - { - fixedLen += _npcLifeBytes; - } - - if (_releaseOwner) - { - fixedLen += 1; - } + fixedLen += (short)Remainder.Length; return fixedLen; } @@ -159,45 +96,15 @@ public override void ToStream(Stream stream, bool includeHeader = true) bw.Write(this.VelocityX); bw.Write(this.VelocityY); bw.Write(this.Target); - bw.Write((byte)this.Flags); - - for (int i = 0; i < 4; i++) - { - if (((byte)Flags & (1 << (i + 2))) != 0) - { - bw.Write(AI[i]); - } - } - - bw.Write(NPCNetID); - - if ((Flags & NPCUpdateFlags.FullLife) == NPCUpdateFlags.None) - { - switch (_npcLifeBytes) - { - case 4: - bw.Write(Life.Value); - break; - case 2: - bw.Write((short)Life.Value); - break; - case 1: - bw.Write((sbyte)Life.Value); - break; - } - } - - if (_releaseOwner) - { - bw.Write(ReleaseOwner); - } + bw.Write(this.Flags); + bw.Write(Remainder); } } public override string ToString() { - return string.Format("[NPCUpdate: NPCID={0}, PositionX={1}, PositionY={2}, VelocityX={3}, VelocityY={4}, Target={5}, Flags={6}, Life={7}, AI={8}, NPCNetID={9}, ReleaseOwner={10}]", - NPCID, PositionX, PositionY, VelocityX, VelocityY, Target, Flags, Life, AI, NPCNetID, ReleaseOwner); + return string.Format("[NPCUpdate: NPCID={0}, PositionX={1}, PositionY={2}, VelocityX={3}, VelocityY={4}, Target={5}, Flags={6}]", + NPCID, PositionX, PositionY, VelocityX, VelocityY, Target, Flags); } } } diff --git a/Multiplicity.Packets/NebulaLevelUpRequest.cs b/Multiplicity.Packets/NebulaLevelUpRequest.cs index f27807a..5efa1fa 100644 --- a/Multiplicity.Packets/NebulaLevelUpRequest.cs +++ b/Multiplicity.Packets/NebulaLevelUpRequest.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -46,8 +48,7 @@ public NebulaLevelUpRequest(BinaryReader br) public override string ToString() { - return - $"[NebulaLevelUpRequest: PlayerID = {PlayerID} LevelUpType = {LevelUpType} OriginX = {OriginX} OriginY = {OriginY}]"; + return $"[NebulaLevelUpRequest: PlayerID = {PlayerID} LevelUpType = {LevelUpType} OriginX = {OriginX} OriginY = {OriginY}]"; } #region implemented abstract members of TerrariaPacket @@ -62,7 +63,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -74,7 +76,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(LevelUpType); br.Write(OriginX); diff --git a/Multiplicity.Packets/NotifyPlayerNPCKilled.cs b/Multiplicity.Packets/NotifyPlayerNPCKilled.cs index 50de270..eb1ac60 100644 --- a/Multiplicity.Packets/NotifyPlayerNPCKilled.cs +++ b/Multiplicity.Packets/NotifyPlayerNPCKilled.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -59,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); } } diff --git a/Multiplicity.Packets/NotifyPlayerOfEvent.cs b/Multiplicity.Packets/NotifyPlayerOfEvent.cs index fc734a2..72c9d10 100644 --- a/Multiplicity.Packets/NotifyPlayerOfEvent.cs +++ b/Multiplicity.Packets/NotifyPlayerOfEvent.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -59,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(EventID); } } diff --git a/Multiplicity.Packets/NumberOfAnglerQuestsCompleted.cs b/Multiplicity.Packets/NumberOfAnglerQuestsCompleted.cs index fa88642..c182846 100644 --- a/Multiplicity.Packets/NumberOfAnglerQuestsCompleted.cs +++ b/Multiplicity.Packets/NumberOfAnglerQuestsCompleted.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -35,8 +36,7 @@ public NumberOfAnglerQuestsCompleted(BinaryReader br) public override string ToString() { - return - $"[NumberOfAnglerQuestsCompleted: PlayerID = {PlayerID} AnglerQuestsCompleted = {AnglerQuestsCompleted}]"; + return $"[NumberOfAnglerQuestsCompleted: PlayerID = {PlayerID} AnglerQuestsCompleted = {AnglerQuestsCompleted}]"; } #region implemented abstract members of TerrariaPacket @@ -51,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -63,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(AnglerQuestsCompleted); } diff --git a/Multiplicity.Packets/PaintTile.cs b/Multiplicity.Packets/PaintTile.cs index fa7d7b6..354646b 100644 --- a/Multiplicity.Packets/PaintTile.cs +++ b/Multiplicity.Packets/PaintTile.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(Color); diff --git a/Multiplicity.Packets/PaintWall.cs b/Multiplicity.Packets/PaintWall.cs index 103b50b..d82b9ce 100644 --- a/Multiplicity.Packets/PaintWall.cs +++ b/Multiplicity.Packets/PaintWall.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(Color); diff --git a/Multiplicity.Packets/PlaceChest.cs b/Multiplicity.Packets/PlaceChest.cs index c28d1de..02b9f22 100644 --- a/Multiplicity.Packets/PlaceChest.cs +++ b/Multiplicity.Packets/PlaceChest.cs @@ -1,62 +1,80 @@ -using System.IO; +using System; +using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { - /// - /// The PlaceChest (34) packet. - /// - public class PlaceChest : TerrariaPacket - { - public byte Action { get; set; } - public short X { get; set; } - public short Y { get; set; } - public short Style { get; set; } - public short ChestID { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public PlaceChest() : base((byte)PacketTypes.PlaceChest) { } - - /// - /// Initializes a new instance of the class. - /// - /// br - public PlaceChest(BinaryReader br) - : base(br) - { - Action = br.ReadByte(); - X = br.ReadInt16(); - Y = br.ReadInt16(); - Style = br.ReadInt16(); - - //ID = br.ReadInt16(); - ChestID = 0; //TODO: Client detection? This is particular field is server->client only - } - - public override string ToString() - { - return $"[{nameof(PlaceChest)}: Action={Action},X={X},Y={Y},Style={Style}]"; - } - - #region implemented abstract members of TerrariaPacket - - public override short GetLength() - { - return (short)(7); - } - - public override void ToStream(Stream stream, bool includeHeader = true) - { - /* + /// + /// The PlaceChest (0x22) packet. + /// + public class PlaceChest : TerrariaPacket + { + + /// + /// Gets or sets the ChestID - BitFlags:0 = Place Chest, 1 = Kill Chest, 2 = Place Dresser, 3 = Kill Dresser. 4 = Place Containers2, 5 = Kill Containers2| + /// + public byte ChestID { get; set; } + + public short TileX { get; set; } + + public short TileY { get; set; } + + /// + /// Gets or sets the Style - FrameX(Chest type)| + /// + public short Style { get; set; } + + /// + /// Gets or sets the ChestIDtodestroy - ID if client is receiving packet, else 0| + /// + public short ChestIDtodestroy { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public PlaceChest() + : base((byte)PacketTypes.PlaceChest) + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// br + public PlaceChest(BinaryReader br) + : base(br) + { + this.ChestID = br.ReadByte(); + this.TileX = br.ReadInt16(); + this.TileY = br.ReadInt16(); + this.Style = br.ReadInt16(); + this.ChestIDtodestroy = br.ReadInt16(); + } + + public override string ToString() + { + return $"[PlaceChest: ChestID = {ChestID} TileX = {TileX} TileY = {TileY} Style = {Style} ChestIDtodestroy = {ChestIDtodestroy}]"; + } + + #region implemented abstract members of TerrariaPacket + + public override short GetLength() + { + return (short)(9); + } + + public override void ToStream(Stream stream, bool includeHeader = true) + { + /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) - { - base.ToStream(stream, includeHeader); - } + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } - /* + /* * Always make sure to not close the stream when serializing. * * It is up to the caller to decide if the underlying stream @@ -64,16 +82,17 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter writer = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) - { - writer.Write(Action); - writer.Write(X); - writer.Write(Y); - writer.Write(Style); - writer.Write(ChestID); - } - } - - #endregion - } -} \ No newline at end of file + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(ChestID); + br.Write(TileX); + br.Write(TileY); + br.Write(Style); + br.Write(ChestIDtodestroy); + } + } + + #endregion + + } +} diff --git a/Multiplicity.Packets/PlaceItemFrame.cs b/Multiplicity.Packets/PlaceItemFrame.cs index 6eb35b6..7b1e3ca 100644 --- a/Multiplicity.Packets/PlaceItemFrame.cs +++ b/Multiplicity.Packets/PlaceItemFrame.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -59,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -71,7 +73,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(ItemId); diff --git a/Multiplicity.Packets/PlaceObject.cs b/Multiplicity.Packets/PlaceObject.cs index 29c6369..b0fdd4e 100644 --- a/Multiplicity.Packets/PlaceObject.cs +++ b/Multiplicity.Packets/PlaceObject.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,8 +51,7 @@ public PlaceObject(BinaryReader br) public override string ToString() { - return - $"[PlaceObject: X = {X} Y = {Y} Type = {Type} Style = {Style} Alternate = {Alternate} Random = {Random} Direction = {Direction}]"; + return $"[PlaceObject: X = {X} Y = {Y} Type = {Type} Style = {Style} Alternate = {Alternate} Random = {Random} Direction = {Direction}]"; } #region implemented abstract members of TerrariaPacket @@ -66,7 +66,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -78,7 +79,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(Type); diff --git a/Multiplicity.Packets/PlaceTileEntity.cs b/Multiplicity.Packets/PlaceTileEntity.cs index 263ad14..3b70dec 100644 --- a/Multiplicity.Packets/PlaceTileEntity.cs +++ b/Multiplicity.Packets/PlaceTileEntity.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(Type); diff --git a/Multiplicity.Packets/PlayMusicItem.cs b/Multiplicity.Packets/PlayMusicItem.cs index daa4a3e..5f8a49b 100644 --- a/Multiplicity.Packets/PlayMusicItem.cs +++ b/Multiplicity.Packets/PlayMusicItem.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -49,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -61,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Note); } diff --git a/Multiplicity.Packets/PlayerActive.cs b/Multiplicity.Packets/PlayerActive.cs index 01ce93e..5a25333 100644 --- a/Multiplicity.Packets/PlayerActive.cs +++ b/Multiplicity.Packets/PlayerActive.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Active); } diff --git a/Multiplicity.Packets/PlayerDodge.cs b/Multiplicity.Packets/PlayerDodge.cs index 10f4154..d798662 100644 --- a/Multiplicity.Packets/PlayerDodge.cs +++ b/Multiplicity.Packets/PlayerDodge.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -52,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -64,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Flag); } diff --git a/Multiplicity.Packets/PlayerHP.cs b/Multiplicity.Packets/PlayerHP.cs index b36694e..f008e80 100644 --- a/Multiplicity.Packets/PlayerHP.cs +++ b/Multiplicity.Packets/PlayerHP.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(HP); br.Write(MaxHP); diff --git a/Multiplicity.Packets/PlayerInfo.cs b/Multiplicity.Packets/PlayerInfo.cs index 33f076c..d1e7195 100644 --- a/Multiplicity.Packets/PlayerInfo.cs +++ b/Multiplicity.Packets/PlayerInfo.cs @@ -1,6 +1,7 @@ -using System.Drawing; +using System; using System.IO; using Multiplicity.Packets.Extensions; +using System.Drawing; namespace Multiplicity.Packets { @@ -81,8 +82,7 @@ public PlayerInfo(BinaryReader br) public override string ToString() { - return - $"[PlayerInfo: PlayerID = {PlayerID} SkinVarient = {SkinVarient} Hair = {Hair} Name = {Name} HairDye = {HairDye} HideVisuals = {HideVisuals} HideVisuals2 = {HideVisuals2} HideMisc = {HideMisc} HairColor = {HairColor} SkinColor = {SkinColor} EyeColor = {EyeColor} ShirtColor = {ShirtColor} UnderShirtColor = {UnderShirtColor} PantsColor = {PantsColor} ShoeColor = {ShoeColor} Difficulty = {Difficulty}]"; + return $"[PlayerInfo: PlayerID = {PlayerID} SkinVarient = {SkinVarient} Hair = {Hair} Name = {Name} HairDye = {HairDye} HideVisuals = {HideVisuals} HideVisuals2 = {HideVisuals2} HideMisc = {HideMisc} HairColor = {HairColor} SkinColor = {SkinColor} EyeColor = {EyeColor} ShirtColor = {ShirtColor} UnderShirtColor = {UnderShirtColor} PantsColor = {PantsColor} ShoeColor = {ShoeColor} Difficulty = {Difficulty}]"; } #region implemented abstract members of TerrariaPacket @@ -97,7 +97,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -109,7 +110,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(SkinVarient); br.Write(Hair); diff --git a/Multiplicity.Packets/PlayerInventorySlot.cs b/Multiplicity.Packets/PlayerInventorySlot.cs index 5aa3b8f..d23b018 100644 --- a/Multiplicity.Packets/PlayerInventorySlot.cs +++ b/Multiplicity.Packets/PlayerInventorySlot.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,8 +48,7 @@ public PlayerInventorySlot(BinaryReader br) public override string ToString() { - return - $"[PlayerInventorySlot: PlayerID = {PlayerID} SlotID = {SlotID} Stack = {Stack} Prefix = {Prefix} ItemNetID = {ItemNetID}]"; + return $"[PlayerInventorySlot: PlayerID = {PlayerID} SlotID = {SlotID} Stack = {Stack} Prefix = {Prefix} ItemNetID = {ItemNetID}]"; } #region implemented abstract members of TerrariaPacket @@ -63,7 +63,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -75,7 +76,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(SlotID); br.Write(Stack); diff --git a/Multiplicity.Packets/PlayerItemAnimation.cs b/Multiplicity.Packets/PlayerItemAnimation.cs index 50215e1..4f9b06d 100644 --- a/Multiplicity.Packets/PlayerItemAnimation.cs +++ b/Multiplicity.Packets/PlayerItemAnimation.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -38,8 +39,7 @@ public PlayerItemAnimation(BinaryReader br) public override string ToString() { - return - $"[PlayerItemAnimation: PlayerID = {PlayerID} ItemRotation = {ItemRotation} ItemAnimation = {ItemAnimation}]"; + return $"[PlayerItemAnimation: PlayerID = {PlayerID} ItemRotation = {ItemRotation} ItemAnimation = {ItemAnimation}]"; } #region implemented abstract members of TerrariaPacket @@ -54,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -66,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(ItemRotation); br.Write(ItemAnimation); diff --git a/Multiplicity.Packets/PlayerMana.cs b/Multiplicity.Packets/PlayerMana.cs index 2b74058..51fced3 100644 --- a/Multiplicity.Packets/PlayerMana.cs +++ b/Multiplicity.Packets/PlayerMana.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Mana); br.Write(MaxMana); diff --git a/Multiplicity.Packets/PlayerNPCTeleport.cs b/Multiplicity.Packets/PlayerNPCTeleport.cs index 817c6c2..545df8e 100644 --- a/Multiplicity.Packets/PlayerNPCTeleport.cs +++ b/Multiplicity.Packets/PlayerNPCTeleport.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -59,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -71,7 +73,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Flags); br.Write(TargetID); br.Write(X); diff --git a/Multiplicity.Packets/PlayerTeam.cs b/Multiplicity.Packets/PlayerTeam.cs index 8cda465..21f1cb5 100644 --- a/Multiplicity.Packets/PlayerTeam.cs +++ b/Multiplicity.Packets/PlayerTeam.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -49,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -61,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Team); } diff --git a/Multiplicity.Packets/PlayerTeleportThroughPortal.cs b/Multiplicity.Packets/PlayerTeleportThroughPortal.cs index f3b2183..7e3a809 100644 --- a/Multiplicity.Packets/PlayerTeleportThroughPortal.cs +++ b/Multiplicity.Packets/PlayerTeleportThroughPortal.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,8 +48,7 @@ public PlayerTeleportThroughPortal(BinaryReader br) public override string ToString() { - return - $"[PlayerTeleportThroughPortal: PlayerID = {PlayerID} PortalColorIndex = {PortalColorIndex} NewPositionX = {NewPositionX} NewPositionY = {NewPositionY} VelocityX = {VelocityX} VelocityY = {VelocityY}]"; + return $"[PlayerTeleportThroughPortal: PlayerID = {PlayerID} PortalColorIndex = {PortalColorIndex} NewPositionX = {NewPositionX} NewPositionY = {NewPositionY} VelocityX = {VelocityX} VelocityY = {VelocityY}]"; } #region implemented abstract members of TerrariaPacket @@ -63,7 +63,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -75,7 +76,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(PortalColorIndex); br.Write(NewPositionX); diff --git a/Multiplicity.Packets/PlayerZone.cs b/Multiplicity.Packets/PlayerZone.cs index 768f9d4..a143e64 100644 --- a/Multiplicity.Packets/PlayerZone.cs +++ b/Multiplicity.Packets/PlayerZone.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -20,6 +22,16 @@ public class PlayerZone : TerrariaPacket /// public byte Zone2 { get; set; } + /// + /// Gets or sets the Zone3 - 1 = Overworld, 2 = Dirt Layer, 4 = Rock Layer, 8 = Underworld, 16 = Beach, 32 = Rain, 64 = Sandstorm| + /// + public byte Zone3 { get; set; } + + /// + /// Gets or sets the Zone4 - 1 = Old One's Army| + /// + public byte Zone4 { get; set; } + /// /// Initializes a new instance of the class. /// @@ -39,18 +51,20 @@ public PlayerZone(BinaryReader br) this.PlayerID = br.ReadByte(); this.Zone1 = br.ReadByte(); this.Zone2 = br.ReadByte(); + this.Zone3 = br.ReadByte(); + this.Zone4 = br.ReadByte(); } public override string ToString() { - return $"[PlayerZone: PlayerID = {PlayerID} Zone1 = {Zone1} Zone2 = {Zone2}]"; + return $"[PlayerZone: PlayerID = {PlayerID} Zone1 = {Zone1} Zone2 = {Zone2} Zone3 = {Zone3} Zone4 = {Zone4}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(3); + return (short)(5); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -58,7 +72,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -70,10 +85,13 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Zone1); br.Write(Zone2); + br.Write(Zone3); + br.Write(Zone4); } } diff --git a/Multiplicity.Packets/PoofofSmoke.cs b/Multiplicity.Packets/PoofofSmoke.cs index 888f5ba..187d18e 100644 --- a/Multiplicity.Packets/PoofofSmoke.cs +++ b/Multiplicity.Packets/PoofofSmoke.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PackedVector); } } diff --git a/Multiplicity.Packets/ProjectileUpdate.cs b/Multiplicity.Packets/ProjectileUpdate.cs index 7ba832a..3834eab 100644 --- a/Multiplicity.Packets/ProjectileUpdate.cs +++ b/Multiplicity.Packets/ProjectileUpdate.cs @@ -1,175 +1,114 @@ -using System.IO; +using System; +using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { - /// - /// The ProjectileUpdate (27) packet. - /// - public class ProjectileUpdate : TerrariaPacket - { - //Always sent - public short ProjectileID { get; set; } - public float PositionX { get; set; } - public float PositionY { get; set; } - public float VelocityX { get; set; } - public float VelocityY { get; set; } - public float KnockBack { get; set; } - public short Damage { get; set; } - public byte Owner { get; set; } - public short Type { get; set; } - public AIFlags Flags { get; set; } - - //Sent conditionally - public float[] AI { get; set; } - public short UUID { get; set; } - - public const int MaxAI = 2; - - public bool HasAI0 - { - get - { - return (this.Flags & AIFlags.AI0) != 0; - } - set - { - if (value) - { - this.Flags |= AIFlags.AI0; - } - else - { - this.Flags &= ~AIFlags.AI0; - } - } - } - - public bool HasAI1 - { - get - { - return (this.Flags & AIFlags.AI1) != 0; - } - set - { - if (value) - { - this.Flags |= AIFlags.AI1; - } - else - { - this.Flags &= ~AIFlags.AI1; - } - } - } - - public bool HasUUID - { - get - { - return (this.Flags & AIFlags.HasUUID) != 0; - } - set - { - if (value) - { - this.Flags |= AIFlags.HasUUID; - } - else - { - this.Flags &= ~AIFlags.HasUUID; - } - } - } - - [System.Flags] - public enum AIFlags : byte - { - AI0 = 1, - AI1 = 2, - HasUUID = 4 - } - - /// - /// Initializes a new instance of the class. - /// - public ProjectileUpdate() - : base((byte)PacketTypes.ProjectileUpdate) - { - - } - - /// - /// Initializes a new instance of the class. - /// - /// br - public ProjectileUpdate(BinaryReader br) - : base(br) - { - this.ProjectileID = br.ReadInt16(); - this.PositionX = br.ReadSingle(); - this.PositionY = br.ReadSingle(); - this.VelocityX = br.ReadSingle(); - this.VelocityY = br.ReadSingle(); - this.KnockBack = br.ReadSingle(); - this.Damage = br.ReadInt16(); - this.Owner = br.ReadByte(); - this.Type = br.ReadInt16(); - this.Flags = (AIFlags)br.ReadByte(); - - this.AI = new float[MaxAI]; - for (var i = 0; i < MaxAI; i++) - { - if (((byte)this.Flags & (1 << i)) != 0) - { - this.AI[i] = br.ReadSingle(); - } - else - { - this.AI[i] = 0f; - } - } - - if (HasUUID) - { - this.UUID = br.ReadInt16(); - } - } - - public override string ToString() - { - return $"[{nameof(ProjectileUpdate)}: ProjectileID={ProjectileID},PositionX={PositionX}," + - $"PositionY={PositionY},VelocityX={VelocityX},VelocityY={VelocityY},KnockBack={KnockBack}," + - $"Damage={Damage},Owner={Owner},Type={Type},Flags={Flags},UUID={UUID}]"; - } - - #region implemented abstract members of TerrariaPacket - - public override short GetLength() - { - short length = 28; - - if (HasAI0) - length += 4; - if (HasAI1) - length += 4; - if (HasUUID) - length += 2; - - return length; - } - - public override void ToStream(Stream stream, bool includeHeader = true) - { - /* + /// + /// The ProjectileUpdate (0x1B) packet. + /// + public class ProjectileUpdate : TerrariaPacket + { + + public short ProjectileID { get; set; } + + public float PositionX { get; set; } + + public float PositionY { get; set; } + + public float VelocityX { get; set; } + + public float VelocityY { get; set; } + + public float KnockBack { get; set; } + + public short Damage { get; set; } + + /// + /// Gets or sets the Owner - Player ID| + /// + public byte Owner { get; set; } + + public short Type { get; set; } + + /// + /// Gets or sets the AIFlags - BitFlags: 0 = AI[0] is Present, 1 = AI[1] is Present, 2 = Needs UUID| + /// + public byte AIFlags { get; set; } + + /// + /// Gets or sets the AI0 - Requires the AI0 flag to be set in order to be sent down the wire| + /// + public float AI0 { get; set; } + + /// + /// Gets or sets the AI1 - Requires the AI1 flag to be set in order to be sent down the wire| + /// + public float AI1 { get; set; } + + /// + /// Gets or sets the ProjUUID - Requires the Needs UUID flag to be set in order to be sent down the wire| + /// + public short ProjUUID { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public ProjectileUpdate() + : base((byte)PacketTypes.ProjectileUpdate) + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// br + public ProjectileUpdate(BinaryReader br) + : base(br) + { + this.ProjectileID = br.ReadInt16(); + this.PositionX = br.ReadSingle(); + this.PositionY = br.ReadSingle(); + this.VelocityX = br.ReadSingle(); + this.VelocityY = br.ReadSingle(); + this.KnockBack = br.ReadSingle(); + this.Damage = br.ReadInt16(); + this.Owner = br.ReadByte(); + this.Type = br.ReadInt16(); + this.AIFlags = br.ReadByte(); + + if (this.AIFlags.ReadBit(0)) + this.AI0 = br.ReadSingle(); + if (this.AIFlags.ReadBit(1)) + this.AI1 = br.ReadSingle(); + if (this.AIFlags.ReadBit(2)) + this.ProjUUID = br.ReadInt16(); + } + + public override string ToString() + { + return $"[ProjectileUpdate: ProjectileID = {ProjectileID} PositionX = {PositionX} PositionY = {PositionY} VelocityX = {VelocityX} VelocityY = {VelocityY} KnockBack = {KnockBack} Damage = {Damage} Owner = {Owner} Type = {Type} AIFlags = {AIFlags} AI0 = {AI0} AI1 = {AI1} ProjUUID = {ProjUUID}]"; + } + + #region implemented abstract members of TerrariaPacket + + public override short GetLength() + { + return (short)(38); + } + + public override void ToStream(Stream stream, bool includeHeader = true) + { + /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) - { - base.ToStream(stream, includeHeader); - } + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } - /* + /* * Always make sure to not close the stream when serializing. * * It is up to the caller to decide if the underlying stream @@ -177,34 +116,28 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter writer = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) - { - writer.Write(ProjectileID); - writer.Write(PositionX); - writer.Write(PositionY); - writer.Write(VelocityX); - writer.Write(VelocityY); - writer.Write(KnockBack); - writer.Write(Damage); - writer.Write(Owner); - writer.Write(Type); - writer.Write((byte)Flags); - - for (var i = 0; i < MaxAI; i++) - { - if (((byte)this.Flags & (1 << i)) != 0) - { - writer.Write(this.AI[i]); - } - } - - if (HasUUID) - { - writer.Write(this.UUID); - } - } - } - - #endregion - } -} \ No newline at end of file + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(ProjectileID); + br.Write(PositionX); + br.Write(PositionY); + br.Write(VelocityX); + br.Write(VelocityY); + br.Write(KnockBack); + br.Write(Damage); + br.Write(Owner); + br.Write(Type); + br.Write(AIFlags); + if (this.AIFlags.ReadBit(0)) + br.Write(AI0); + if (this.AIFlags.ReadBit(1)) + br.Write(AI1); + if (this.AIFlags.ReadBit(2)) + br.Write(ProjUUID); + } + } + + #endregion + + } +} diff --git a/Multiplicity.Packets/ReleaseNPC.cs b/Multiplicity.Packets/ReleaseNPC.cs index a697cb1..62ad2a2 100644 --- a/Multiplicity.Packets/ReleaseNPC.cs +++ b/Multiplicity.Packets/ReleaseNPC.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -13,14 +14,17 @@ public class ReleaseNPC : TerrariaPacket public int Y { get; set; } - public short Type { get; set; } + public short NPCType { get; set; } + /// + /// Gets or sets the Style - Sent to NPC AI[2]| + /// public byte Style { get; set; } /// /// Initializes a new instance of the class. /// - public ReleaseNPC() + public ReleaseNPC() : base((byte)PacketTypes.ReleaseNPC) { @@ -30,18 +34,18 @@ public ReleaseNPC() /// Initializes a new instance of the class. /// /// br - public ReleaseNPC(BinaryReader br) + public ReleaseNPC(BinaryReader br) : base(br) { this.X = br.ReadInt32(); this.Y = br.ReadInt32(); - this.Type = br.ReadInt16(); + this.NPCType = br.ReadInt16(); this.Style = br.ReadByte(); } public override string ToString() { - return $"[ReleaseNPC: X = {X} Y = {Y} Type = {Type} Style = {Style}]"; + return $"[ReleaseNPC: X = {X} Y = {Y} NPCType = {NPCType} Style = {Style}]"; } #region implemented abstract members of TerrariaPacket @@ -56,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,10 +73,11 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); - br.Write(Type); + br.Write(NPCType); br.Write(Style); } } diff --git a/Multiplicity.Packets/RemoveItemOwner.cs b/Multiplicity.Packets/RemoveItemOwner.cs index dc92804..3b4d783 100644 --- a/Multiplicity.Packets/RemoveItemOwner.cs +++ b/Multiplicity.Packets/RemoveItemOwner.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -59,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ItemIndex); } } diff --git a/Multiplicity.Packets/ReportInvasionProgress.cs b/Multiplicity.Packets/ReportInvasionProgress.cs index 6e8d0c3..4254702 100644 --- a/Multiplicity.Packets/ReportInvasionProgress.cs +++ b/Multiplicity.Packets/ReportInvasionProgress.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -41,8 +42,7 @@ public ReportInvasionProgress(BinaryReader br) public override string ToString() { - return - $"[ReportInvasionProgress: Progress = {Progress} MaxProgress = {MaxProgress} Icon = {Icon} Wave = {Wave}]"; + return $"[ReportInvasionProgress: Progress = {Progress} MaxProgress = {MaxProgress} Icon = {Icon} Wave = {Wave}]"; } #region implemented abstract members of TerrariaPacket @@ -57,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -69,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Progress); br.Write(MaxProgress); br.Write(Icon); diff --git a/Multiplicity.Packets/RequestPassword.cs b/Multiplicity.Packets/RequestPassword.cs index 1b45fbe..67a9f32 100644 --- a/Multiplicity.Packets/RequestPassword.cs +++ b/Multiplicity.Packets/RequestPassword.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public RequestPassword(BinaryReader br) public override string ToString() { - return string.Format("[RequestPassword]"); + return $"[RequestPassword:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/RequestSign.cs b/Multiplicity.Packets/RequestSign.cs index 5e8761f..b9a5b24 100644 --- a/Multiplicity.Packets/RequestSign.cs +++ b/Multiplicity.Packets/RequestSign.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); } diff --git a/Multiplicity.Packets/SectionTileFrame.cs b/Multiplicity.Packets/SectionTileFrame.cs index 78fa1f2..0942e2f 100644 --- a/Multiplicity.Packets/SectionTileFrame.cs +++ b/Multiplicity.Packets/SectionTileFrame.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(StartX); br.Write(StartY); br.Write(EndX); diff --git a/Multiplicity.Packets/SendPassword.cs b/Multiplicity.Packets/SendPassword.cs index 2b02a76..608314e 100644 --- a/Multiplicity.Packets/SendPassword.cs +++ b/Multiplicity.Packets/SendPassword.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -46,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -58,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Password); } } diff --git a/Multiplicity.Packets/SendSection.cs b/Multiplicity.Packets/SendSection.cs index 1ebfa7c..004331e 100644 --- a/Multiplicity.Packets/SendSection.cs +++ b/Multiplicity.Packets/SendSection.cs @@ -9,16 +9,6 @@ namespace Multiplicity.Packets public class SendSection : TerrariaPacket { - public bool Compressed { get; set; } - - public int XStart { get; set; } - - public int YStart { get; set; } - - public short Width { get; set; } - - public short Height { get; set; } - public byte[] TilePayload { get; set; } /// @@ -68,10 +58,7 @@ public SendSection(BinaryReader br) } */ - this.XStart = br.ReadInt32(); - this.YStart = br.ReadInt32(); - this.Width = br.ReadInt16(); - this.Height = br.ReadInt16(); + // I hate myself for this, but there's no easy way to check if compressed and read the packet this.TilePayload = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)); } @@ -79,14 +66,14 @@ public SendSection(BinaryReader br) public override string ToString() { return - $"[SendSection Compressed: {Compressed}, X: {XStart}, Y: {YStart}, Width: {Width}, Height: {Height} TileData: {TilePayload.Length/1024:0.###} kB]"; + $"[SendSection Compressed: TileData: {TilePayload.Length/1024:0.###} kB]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short) (13 + TilePayload.Length); + return (short) (TilePayload.Length); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -108,11 +95,6 @@ public override void ToStream(Stream stream, bool includeHeader = true) */ using (BinaryWriter bw = new BinaryWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true)) { - bw.Write(Compressed); - bw.Write(XStart); - bw.Write(YStart); - bw.Write(Width); - bw.Write(Height); bw.Write(TilePayload); } } diff --git a/Multiplicity.Packets/SendTileSquare.cs b/Multiplicity.Packets/SendTileSquare.cs index c791ff7..6658fe3 100644 --- a/Multiplicity.Packets/SendTileSquare.cs +++ b/Multiplicity.Packets/SendTileSquare.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -9,12 +10,21 @@ namespace Multiplicity.Packets public class SendTileSquare : TerrariaPacket { + public ushort PlayerID { get; set; } + + /// + /// Gets or sets the TileChangeType - Only if != 0| + /// + public byte TileChangeType { get; set; } + public short Size { get; set; } public short TileX { get; set; } public short TileY { get; set; } + public byte[] TilePayload { get; set; } + /// /// Initializes a new instance of the class. /// @@ -31,21 +41,31 @@ public SendTileSquare() public SendTileSquare(BinaryReader br) : base(br) { + this.PlayerID = br.ReadUInt16(); + + int num24 = 32768; + int num25 = (uint)(this.PlayerID & num24) > 0U ? 1 : 0; + + if (num25 != 0) + this.TileChangeType = br.ReadByte(); + this.Size = br.ReadInt16(); this.TileX = br.ReadInt16(); this.TileY = br.ReadInt16(); + + this.TilePayload = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)); } public override string ToString() { - return $"[SendTileSquare: Size = {Size} TileX = {TileX} TileY = {TileY}]"; + return $"[SendTileSquare: PlayerID = {PlayerID} TileChangeType = {TileChangeType} Size = {Size} TileX = {TileX} TileY = {TileY} TileData: {TilePayload.Length / 1024:0.###} kB]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(6); + return (short)(9 + TilePayload.Length); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -53,7 +73,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,10 +86,20 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(PlayerID); + + int num24 = 32768; + int num25 = (uint)(this.PlayerID & num24) > 0U ? 1 : 0; + + if (num25 != 0) + br.Write(TileChangeType); + br.Write(Size); br.Write(TileX); br.Write(TileY); + br.Write(TilePayload); } } diff --git a/Multiplicity.Packets/SetActiveNPC.cs b/Multiplicity.Packets/SetActiveNPC.cs index fb6fcc8..3d0da60 100644 --- a/Multiplicity.Packets/SetActiveNPC.cs +++ b/Multiplicity.Packets/SetActiveNPC.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(NpcTalkTarget); } diff --git a/Multiplicity.Packets/SetChestName.cs b/Multiplicity.Packets/SetChestName.cs index a42c0b0..387f1e2 100644 --- a/Multiplicity.Packets/SetChestName.cs +++ b/Multiplicity.Packets/SetChestName.cs @@ -1,74 +1,86 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { - /// - /// The SetChestName (33) packet. - /// - public class SetChestName : TerrariaPacket - { - public short ChestID { get; set; } - public short X { get; set; } - public short Y { get; set; } - public byte NameLength { get; set; } - public string Name { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public SetChestName() : base((byte)PacketTypes.SetChestName) { } - - /// - /// Initializes a new instance of the class. - /// - /// br - public SetChestName(BinaryReader br) - : base(br) - { - ChestID = br.ReadInt16(); - - X = br.ReadInt16(); - Y = br.ReadInt16(); - NameLength = br.ReadByte(); - Name = String.Empty; - - if (NameLength != 0) - { - if (NameLength <= 20) - Name = br.ReadString(); - else if (NameLength != 255) - NameLength = 0; - } - } - - public override string ToString() - { - return $"[{nameof(SetChestName)}: ChestID={ChestID},X={X},Y={Y},TextLength={NameLength},Text={Name}]"; - } - - #region implemented abstract members of TerrariaPacket - - public override short GetLength() - { - const short Length = 7; - if (Name == null) - return Length; - - return (short)(Length + Name.Length); - } - - public override void ToStream(Stream stream, bool includeHeader = true) - { - /* + /// + /// The SetChestName (0x21) packet. + /// + public class SetChestName : TerrariaPacket + { + + public short ChestID { get; set; } + + public short ChestX { get; set; } + + public short ChestY { get; set; } + + public byte NameLength { get; set; } + + /// + /// Gets or sets the ChestName - Only if length > 0 && <= 20| + /// + public string ChestName { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public SetChestName() + : base((byte)PacketTypes.SetChestName) + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// br + public SetChestName(BinaryReader br) + : base(br) + { + this.ChestID = br.ReadInt16(); + this.ChestX = br.ReadInt16(); + this.ChestY = br.ReadInt16(); + this.NameLength = br.ReadByte(); + this.ChestName = String.Empty; + + if (this.NameLength != 0) + { + if (this.NameLength <= 20) + this.ChestName = br.ReadString(); + else if (this.NameLength != 255) + this.NameLength = 0; + } + } + + public override string ToString() + { + return $"[SetChestName: ChestID = {ChestID} ChestX = {ChestX} ChestY = {ChestY} NameLength = {NameLength} ChestName = {ChestName}]"; + } + + #region implemented abstract members of TerrariaPacket + + public override short GetLength() + { + const short Length = 7; + if (ChestName == null) + return Length; + + return (short)(Length + ChestName.Length + 1); + } + + public override void ToStream(Stream stream, bool includeHeader = true) + { + /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) - { - base.ToStream(stream, includeHeader); - } + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } - /* + /* * Always make sure to not close the stream when serializing. * * It is up to the caller to decide if the underlying stream @@ -76,19 +88,20 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter writer = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) - { - writer.Write(ChestID); - writer.Write(X); - writer.Write(Y); - if (Name != null) - { - writer.Write(NameLength); - writer.Write(Name); - } - } - } - - #endregion - } -} \ No newline at end of file + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(ChestID); + br.Write(ChestX); + br.Write(ChestY); + if (ChestName != null) + { + br.Write(NameLength); + br.Write(ChestName); + } + } + } + + #endregion + + } +} diff --git a/Multiplicity.Packets/SetLiquid.cs b/Multiplicity.Packets/SetLiquid.cs index 9a6b37b..708c285 100644 --- a/Multiplicity.Packets/SetLiquid.cs +++ b/Multiplicity.Packets/SetLiquid.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(Liquid); diff --git a/Multiplicity.Packets/SetNPCKillCount.cs b/Multiplicity.Packets/SetNPCKillCount.cs index e6b9cc1..d8f91c0 100644 --- a/Multiplicity.Packets/SetNPCKillCount.cs +++ b/Multiplicity.Packets/SetNPCKillCount.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCType); br.Write(KillCount); } diff --git a/Multiplicity.Packets/SetNPCShopItem.cs b/Multiplicity.Packets/SetNPCShopItem.cs index b5fe31a..57eb1bf 100644 --- a/Multiplicity.Packets/SetNPCShopItem.cs +++ b/Multiplicity.Packets/SetNPCShopItem.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,8 +51,7 @@ public SetNPCShopItem(BinaryReader br) public override string ToString() { - return - $"[SetNPCShopItem: Slot = {Slot} ItemType = {ItemType} Stack = {Stack} Prefix = {Prefix} Value = {Value} Flags = {Flags}]"; + return $"[SetNPCShopItem: Slot = {Slot} ItemType = {ItemType} Stack = {Stack} Prefix = {Prefix} Value = {Value} Flags = {Flags}]"; } #region implemented abstract members of TerrariaPacket @@ -66,7 +66,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -78,7 +79,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Slot); br.Write(ItemType); br.Write(Stack); diff --git a/Multiplicity.Packets/SetPlayerStealth.cs b/Multiplicity.Packets/SetPlayerStealth.cs index 3842265..a159250 100644 --- a/Multiplicity.Packets/SetPlayerStealth.cs +++ b/Multiplicity.Packets/SetPlayerStealth.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -49,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -61,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Player); br.Write(Stealth); } diff --git a/Multiplicity.Packets/SocialHandshake.cs b/Multiplicity.Packets/SocialHandshake.cs index 55e2a62..e073053 100644 --- a/Multiplicity.Packets/SocialHandshake.cs +++ b/Multiplicity.Packets/SocialHandshake.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public SocialHandshake(BinaryReader br) public override string ToString() { - return string.Format("[SocialHandshake]"); + return $"[SocialHandshake:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/SpawnBossInvasion.cs b/Multiplicity.Packets/SpawnBossInvasion.cs index bfcf0e1..fb108e3 100644 --- a/Multiplicity.Packets/SpawnBossInvasion.cs +++ b/Multiplicity.Packets/SpawnBossInvasion.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Type); } diff --git a/Multiplicity.Packets/SpawnPlayer.cs b/Multiplicity.Packets/SpawnPlayer.cs index ca87211..953c0e4 100644 --- a/Multiplicity.Packets/SpawnPlayer.cs +++ b/Multiplicity.Packets/SpawnPlayer.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(SpawnX); br.Write(SpawnY); diff --git a/Multiplicity.Packets/SpecialNPCEffect.cs b/Multiplicity.Packets/SpecialNPCEffect.cs index 6794052..4ee8249 100644 --- a/Multiplicity.Packets/SpecialNPCEffect.cs +++ b/Multiplicity.Packets/SpecialNPCEffect.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -52,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -64,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(Type); } diff --git a/Multiplicity.Packets/Status.cs b/Multiplicity.Packets/Status.cs index bff8220..f02a73f 100644 --- a/Multiplicity.Packets/Status.cs +++ b/Multiplicity.Packets/Status.cs @@ -1,5 +1,7 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; +using Multiplicity.Packets.Models; namespace Multiplicity.Packets { @@ -14,7 +16,7 @@ public class Status : TerrariaPacket /// public int StatusMax { get; set; } - public string StatusText { get; set; } + public NetworkText StatusText { get; set; } /// /// Initializes a new instance of the class. @@ -33,19 +35,19 @@ public Status(BinaryReader br) : base(br) { this.StatusMax = br.ReadInt32(); - this.StatusText = br.ReadString(); + this.StatusText = br.ReadNetworkText(); } public override string ToString() { - return $"[Status: StatusMax = {StatusMax} StatusText = {StatusText}]"; + return $"[Status: StatusMax = {StatusMax} StatusText = {StatusText.Text}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(5 + StatusText.Length); + return (short)(4 + StatusText.GetLength()); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -53,7 +55,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +68,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(StatusMax); br.Write(StatusText); } diff --git a/Multiplicity.Packets/StrikeNPCwithHeldItem.cs b/Multiplicity.Packets/StrikeNPCwithHeldItem.cs index ffd0c9c..32ebd86 100644 --- a/Multiplicity.Packets/StrikeNPCwithHeldItem.cs +++ b/Multiplicity.Packets/StrikeNPCwithHeldItem.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(PlayerID); } diff --git a/Multiplicity.Packets/SyncEmoteBubble.cs b/Multiplicity.Packets/SyncEmoteBubble.cs index 4442738..2e4b4cc 100644 --- a/Multiplicity.Packets/SyncEmoteBubble.cs +++ b/Multiplicity.Packets/SyncEmoteBubble.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -13,21 +14,30 @@ public class SyncEmoteBubble : TerrariaPacket public byte AnchorType { get; set; } + /// + /// Gets or sets the MetaData - Only if AnchorType != 255| + /// public ushort MetaData { get; set; } - public byte LifeTime { get; set; } - - public byte Emote { get; set; } + /// + /// Gets or sets the Lifetime - Only if AnchorType != 255| + /// + public byte Lifetime { get; set; } /// - /// Only sent if Emote is less than 0 + /// Gets or sets the Emote - Only if AnchorType != 255| /// - public short MetaData2 { get; set; } + public byte Emote { get; set; } + + /// + /// Gets or sets the EmoteMetaData - Only sent if AnchorType != 255 and Emote < 0| + /// + public short EmoteMetaData { get; set; } /// /// Initializes a new instance of the class. /// - public SyncEmoteBubble() + public SyncEmoteBubble() : base((byte)PacketTypes.SyncEmoteBubble) { @@ -36,28 +46,41 @@ public SyncEmoteBubble() /// /// Initializes a new instance of the class. /// - /// - public SyncEmoteBubble(BinaryReader br) + /// br + public SyncEmoteBubble(BinaryReader br) : base(br) { - this.EmoteID = br.ReadInt32(); - this.AnchorType = br.ReadByte(); - this.MetaData = br.ReadUInt16(); - this.LifeTime = br.ReadByte(); - this.Emote = br.ReadByte(); - this.MetaData2 = br.ReadInt16(); + this.EmoteID = br.ReadInt32(); + this.AnchorType = br.ReadByte(); + if (this.AnchorType != 255) + { + this.MetaData = br.ReadUInt16(); + this.Lifetime = br.ReadByte(); + this.Emote = br.ReadByte(); + if (this.Emote < 0) + this.EmoteMetaData = br.ReadInt16(); + } + } public override string ToString() { - return $"[SyncEmoteBubble: EmoteID = {EmoteID} AnchorType = {AnchorType} MetaData = {MetaData} LifeTime = {LifeTime} Emote = {Emote} MetaData2 = {MetaData2}]"; + return $"[SyncEmoteBubble: EmoteID = {EmoteID} AnchorType = {AnchorType} MetaData = {MetaData} Lifetime = {Lifetime} Emote = {Emote} EmoteMetaData = {EmoteMetaData}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(11); + short length = 5; + + if (this.AnchorType != 255) + { + length += 4; + if (this.Emote < 0) + length += 2; + } + return length; } public override void ToStream(Stream stream, bool includeHeader = true) @@ -65,7 +88,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -77,18 +101,22 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(EmoteID); br.Write(AnchorType); - br.Write(MetaData); - br.Write(LifeTime); - br.Write(Emote); - br.Write(MetaData2); + if (this.AnchorType != 255) + { + br.Write(MetaData); + br.Write(Lifetime); + br.Write(Emote); + if (this.Emote < 0) + br.Write(EmoteMetaData); + } } } #endregion - } } diff --git a/Multiplicity.Packets/SyncExtraValue.cs b/Multiplicity.Packets/SyncExtraValue.cs index 7731b6e..cba8ee3 100644 --- a/Multiplicity.Packets/SyncExtraValue.cs +++ b/Multiplicity.Packets/SyncExtraValue.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCIndex); br.Write(ExtraValue); br.Write(X); diff --git a/Multiplicity.Packets/SyncPlayerChestIndex.cs b/Multiplicity.Packets/SyncPlayerChestIndex.cs index ce5d1a8..e6ffca6 100644 --- a/Multiplicity.Packets/SyncPlayerChestIndex.cs +++ b/Multiplicity.Packets/SyncPlayerChestIndex.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Player); br.Write(Chest); } diff --git a/Multiplicity.Packets/TeleportationPotion.cs b/Multiplicity.Packets/TeleportationPotion.cs index 4527509..bfa3e50 100644 --- a/Multiplicity.Packets/TeleportationPotion.cs +++ b/Multiplicity.Packets/TeleportationPotion.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public TeleportationPotion(BinaryReader br) public override string ToString() { - return string.Format("[TeleportationPotion]"); + return $"[TeleportationPotion:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/Time.cs b/Multiplicity.Packets/Time.cs index 1870a51..ba41fa7 100644 --- a/Multiplicity.Packets/Time.cs +++ b/Multiplicity.Packets/Time.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(DayTime); br.Write(TimeValue); br.Write(SunModY); diff --git a/Multiplicity.Packets/ToggleBirthdayParty.cs b/Multiplicity.Packets/ToggleBirthdayParty.cs index 27c5452..f2159fa 100644 --- a/Multiplicity.Packets/ToggleBirthdayParty.cs +++ b/Multiplicity.Packets/ToggleBirthdayParty.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -28,7 +30,7 @@ public ToggleBirthdayParty(BinaryReader br) public override string ToString() { - return string.Format("[ToggleBirthdayParty]"); + return $"[ToggleBirthdayParty:]"; } #region implemented abstract members of TerrariaPacket @@ -43,7 +45,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -55,7 +58,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { } } diff --git a/Multiplicity.Packets/ToggleGemLock.cs b/Multiplicity.Packets/ToggleGemLock.cs index e517af3..33d6ded 100644 --- a/Multiplicity.Packets/ToggleGemLock.cs +++ b/Multiplicity.Packets/ToggleGemLock.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(X); br.Write(Y); br.Write(On); diff --git a/Multiplicity.Packets/TogglePVP.cs b/Multiplicity.Packets/TogglePVP.cs index d3d1b77..b1d036f 100644 --- a/Multiplicity.Packets/TogglePVP.cs +++ b/Multiplicity.Packets/TogglePVP.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(PVPEnabled); } diff --git a/Multiplicity.Packets/Unlock.cs b/Multiplicity.Packets/Unlock.cs index d911637..3ad7a26 100644 --- a/Multiplicity.Packets/Unlock.cs +++ b/Multiplicity.Packets/Unlock.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -56,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -68,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Type); br.Write(X); br.Write(Y); diff --git a/Multiplicity.Packets/UpdateGoodEvil.cs b/Multiplicity.Packets/UpdateGoodEvil.cs index 8186870..5fd9f8b 100644 --- a/Multiplicity.Packets/UpdateGoodEvil.cs +++ b/Multiplicity.Packets/UpdateGoodEvil.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -52,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -64,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Good); br.Write(Evil); br.Write(Crimson); diff --git a/Multiplicity.Packets/UpdateItemDrop.cs b/Multiplicity.Packets/UpdateItemDrop.cs index fd50dee..2f4ea8a 100644 --- a/Multiplicity.Packets/UpdateItemDrop.cs +++ b/Multiplicity.Packets/UpdateItemDrop.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -62,8 +63,7 @@ public UpdateItemDrop(BinaryReader br) public override string ToString() { - return - $"[UpdateItemDrop: ItemID = {ItemID} PositionX = {PositionX} PositionY = {PositionY} VelocityX = {VelocityX} VelocityY = {VelocityY} StackSize = {StackSize} Prefix = {Prefix} NoDelay = {NoDelay} ItemNetID = {ItemNetID}]"; + return $"[UpdateItemDrop: ItemID = {ItemID} PositionX = {PositionX} PositionY = {PositionY} VelocityX = {VelocityX} VelocityY = {VelocityY} StackSize = {StackSize} Prefix = {Prefix} NoDelay = {NoDelay} ItemNetID = {ItemNetID}]"; } #region implemented abstract members of TerrariaPacket @@ -78,7 +78,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -90,7 +91,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ItemID); br.Write(PositionX); br.Write(PositionY); diff --git a/Multiplicity.Packets/UpdateItemDrop2.cs b/Multiplicity.Packets/UpdateItemDrop2.cs index 0b400d1..66a524e 100644 --- a/Multiplicity.Packets/UpdateItemDrop2.cs +++ b/Multiplicity.Packets/UpdateItemDrop2.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -62,8 +63,7 @@ public UpdateItemDrop2(BinaryReader br) public override string ToString() { - return - $"[UpdateItemDrop2: ItemID = {ItemID} PositionX = {PositionX} PositionY = {PositionY} VelocityX = {VelocityX} VelocityY = {VelocityY} StackSize = {StackSize} Prefix = {Prefix} NoDelay = {NoDelay} ItemNetID = {ItemNetID}]"; + return $"[UpdateItemDrop2: ItemID = {ItemID} PositionX = {PositionX} PositionY = {PositionY} VelocityX = {VelocityX} VelocityY = {VelocityY} StackSize = {StackSize} Prefix = {Prefix} NoDelay = {NoDelay} ItemNetID = {ItemNetID}]"; } #region implemented abstract members of TerrariaPacket @@ -78,7 +78,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -90,7 +91,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ItemID); br.Write(PositionX); br.Write(PositionY); diff --git a/Multiplicity.Packets/UpdateItemOwner.cs b/Multiplicity.Packets/UpdateItemOwner.cs index d27d1bb..dcfa6f5 100644 --- a/Multiplicity.Packets/UpdateItemOwner.cs +++ b/Multiplicity.Packets/UpdateItemOwner.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -50,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -62,7 +64,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(ItemID); br.Write(PlayerID); } diff --git a/Multiplicity.Packets/UpdateMinionTarget.cs b/Multiplicity.Packets/UpdateMinionTarget.cs index 6a939d9..5a07c46 100644 --- a/Multiplicity.Packets/UpdateMinionTarget.cs +++ b/Multiplicity.Packets/UpdateMinionTarget.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -52,7 +54,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -64,7 +67,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); br.Write(TargetX); br.Write(TargetY); diff --git a/Multiplicity.Packets/UpdateMoonLordCountdown.cs b/Multiplicity.Packets/UpdateMoonLordCountdown.cs index 9c08789..69b6195 100644 --- a/Multiplicity.Packets/UpdateMoonLordCountdown.cs +++ b/Multiplicity.Packets/UpdateMoonLordCountdown.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -47,7 +48,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -59,7 +61,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(MoonLordCountdown); } } diff --git a/Multiplicity.Packets/UpdateNPCBuff.cs b/Multiplicity.Packets/UpdateNPCBuff.cs index 10791fc..10c7f31 100644 --- a/Multiplicity.Packets/UpdateNPCBuff.cs +++ b/Multiplicity.Packets/UpdateNPCBuff.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -15,6 +16,22 @@ public class UpdateNPCBuff : TerrariaPacket public short Time { get; set; } + public byte BuffID2 { get; set; } + + public short Time2 { get; set; } + + public byte BuffID3 { get; set; } + + public short Time3 { get; set; } + + public byte BuffID4 { get; set; } + + public short Time4 { get; set; } + + public byte BuffID5 { get; set; } + + public short Time5 { get; set; } + /// /// Initializes a new instance of the class. /// @@ -34,18 +51,26 @@ public UpdateNPCBuff(BinaryReader br) this.NPCID = br.ReadInt16(); this.BuffID = br.ReadByte(); this.Time = br.ReadInt16(); + this.BuffID2 = br.ReadByte(); + this.Time2 = br.ReadInt16(); + this.BuffID3 = br.ReadByte(); + this.Time3 = br.ReadInt16(); + this.BuffID4 = br.ReadByte(); + this.Time4 = br.ReadInt16(); + this.BuffID5 = br.ReadByte(); + this.Time5 = br.ReadInt16(); } public override string ToString() { - return $"[UpdateNPCBuff: NPCID = {NPCID} BuffID = {BuffID} Time = {Time}]"; + return $"[UpdateNPCBuff: NPCID = {NPCID} BuffID = {BuffID} Time = {Time} BuffID2 = {BuffID2} Time2 = {Time2} BuffID3 = {BuffID3} Time3 = {Time3} BuffID4 = {BuffID4} Time4 = {Time4} BuffID5 = {BuffID5} Time5 = {Time5}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(5); + return (short)(17); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -53,7 +78,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,10 +91,19 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); br.Write(BuffID); br.Write(Time); + br.Write(BuffID2); + br.Write(Time2); + br.Write(BuffID3); + br.Write(Time3); + br.Write(BuffID4); + br.Write(Time4); + br.Write(BuffID5); + br.Write(Time5); } } diff --git a/Multiplicity.Packets/UpdateNPCName.cs b/Multiplicity.Packets/UpdateNPCName.cs index ca4c7bd..deb3f98 100644 --- a/Multiplicity.Packets/UpdateNPCName.cs +++ b/Multiplicity.Packets/UpdateNPCName.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -12,7 +13,7 @@ public class UpdateNPCName : TerrariaPacket public short NPCID { get; set; } /// - /// Gets or sets the Name - Read-only from the client| + /// Gets or sets the Name - Only if client is receiving packet| /// public string Name { get; set; } @@ -33,7 +34,10 @@ public UpdateNPCName(BinaryReader br) : base(br) { this.NPCID = br.ReadInt16(); - this.Name = br.ReadString(); + + if (br.BaseStream.Length > br.BaseStream.Position) { + this.Name = br.ReadString(); + } } public override string ToString() @@ -45,7 +49,12 @@ public override string ToString() public override short GetLength() { - return (short)(3 + Name.Length); + int length = 2; + + if (!string.IsNullOrEmpty(Name)) { + length += 1 + Name.Length; + } + return (short)length; } public override void ToStream(Stream stream, bool includeHeader = true) @@ -53,7 +62,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -65,9 +75,13 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(NPCID); - br.Write(Name); + if (!string.IsNullOrEmpty(Name)) + { + br.Write(Name); + } } } diff --git a/Multiplicity.Packets/UpdatePlayer.cs b/Multiplicity.Packets/UpdatePlayer.cs index 17bf1d7..4589cd6 100644 --- a/Multiplicity.Packets/UpdatePlayer.cs +++ b/Multiplicity.Packets/UpdatePlayer.cs @@ -1,86 +1,121 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { - [Flags] - public enum PlayerControlFlags : byte - { - None = 0, - Up = 1, - Down = 1 << 1, - Left = 1 << 2, - Right = 1 << 3, - Jump = 1 << 4, - UseItem = 1 << 5, - Direction = 1 << 6 - } - - [Flags] - public enum PulleyDirectionFlags : byte - { - None = 0, - Direction1 = 1, - Direction2 = 1 << 1 - } - - public class UpdatePlayer : TerrariaPacket - { - public byte PlayerID { get; protected set; } - public PlayerControlFlags Control { get; set; } - public byte SelectedItem { get; set; } - public float PositionX { get; set; } - public float PositionY { get; set; } - public float VelocityX { get; set; } - public float VelocityY { get; set; } - public PulleyDirectionFlags Pulley { get; set; } - - public UpdatePlayer() - : base((byte)PacketTypes.UpdatePlayer) - { - - } - - public UpdatePlayer(BinaryReader br) - : base(br) - { - PlayerID = br.ReadByte(); - Control = (PlayerControlFlags)br.ReadByte(); - SelectedItem = br.ReadByte(); - PositionX = br.ReadSingle(); - PositionY = br.ReadSingle(); - VelocityX = br.ReadSingle(); - VelocityY = br.ReadSingle(); - Pulley = (PulleyDirectionFlags)br.ReadByte(); - } - - public override short GetLength() - { - return 20; - } - - public override void ToStream(Stream stream, bool includeHeader = true) - { - base.ToStream(stream, includeHeader); - - using (BinaryWriter bw = new BinaryWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true)) - { - bw.Write(PlayerID); - bw.Write((byte)Control); - bw.Write(SelectedItem); - bw.Write(PositionX); - bw.Write(PositionY); - bw.Write(VelocityX); - bw.Write(VelocityY); - bw.Write((byte)Pulley); - } - } - - public override string ToString() - { - return - $"[UpdatePlayer: PlayerID={PlayerID}, Control={Control}, SelectedItem={SelectedItem}, PositionX={PositionX}, PositionY={PositionY}, VelocityX={VelocityX}, VelocityY={VelocityY}, Pulley={Pulley}]"; - } - } -} + /// + /// The UpdatePlayer (0xD) packet. + /// + public class UpdatePlayer : TerrariaPacket + { + + public byte PlayerID { get; set; } + + /// + /// Gets or sets the Control - BitFlags: ControlUp = 1, ControlDown = 2, ControlLeft = 4, ControlRight = 8, ControlJump = 16, ControlUseItem = 32, Direction = 64| + /// + public byte Control { get; set; } + + /// + /// Gets or sets the Pulley - BitFlags: 0 = None, 1 = Direction, 2 = Direction, 4 = Update Velocity, 8 = Vortex Stealth Active, 16 = Gravity Direction, 32 = Shield Raised| + /// + public byte Pulley { get; set; } + + public byte SelectedItem { get; set; } + + public float PositionX { get; set; } + + public float PositionY { get; set; } + + /// + /// Gets or sets the VelocityX - Not sent if Update Velocity is not set| + /// + public float VelocityX { get; set; } + + /// + /// Gets or sets the VelocityY - Not sent if Update Velocity is not set| + /// + public float VelocityY { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public UpdatePlayer() + : base((byte)PacketTypes.UpdatePlayer) + { + + } + /// + /// Initializes a new instance of the class. + /// + /// br + public UpdatePlayer(BinaryReader br) + : base(br) + { + this.PlayerID = br.ReadByte(); + this.Control = br.ReadByte(); + this.Pulley = br.ReadByte(); + this.SelectedItem = br.ReadByte(); + this.PositionX = br.ReadSingle(); + this.PositionY = br.ReadSingle(); + + if (this.Pulley.ReadBit(2)) + { + this.VelocityX = br.ReadSingle(); + this.VelocityY = br.ReadSingle(); + } + } + + public override string ToString() + { + return $"[UpdatePlayer: PlayerID = {PlayerID} Control = {Control} Pulley = {Pulley} SelectedItem = {SelectedItem} PositionX = {PositionX} PositionY = {PositionY} VelocityX = {VelocityX} VelocityY = {VelocityY}]"; + } + + #region implemented abstract members of TerrariaPacket + + public override short GetLength() + { + return (short)(20); + } + + public override void ToStream(Stream stream, bool includeHeader = true) + { + /* + * Length and ID headers get written in the base packet class. + */ + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } + + /* + * Always make sure to not close the stream when serializing. + * + * It is up to the caller to decide if the underlying stream + * gets closed. If this is a network stream we do not want + * the regressions of unconditionally closing the TCP socket + * once the payload of data has been sent to the client. + */ + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(PlayerID); + br.Write(Control); + br.Write(Pulley); + br.Write(SelectedItem); + br.Write(PositionX); + br.Write(PositionY); + + if (this.Pulley.ReadBit(2)) + { + br.Write(VelocityX); + br.Write(VelocityY); + } + } + } + + #endregion + + } +} diff --git a/Multiplicity.Packets/UpdatePlayerBuff.cs b/Multiplicity.Packets/UpdatePlayerBuff.cs index 57f8956..2e93b23 100644 --- a/Multiplicity.Packets/UpdatePlayerBuff.cs +++ b/Multiplicity.Packets/UpdatePlayerBuff.cs @@ -1,4 +1,6 @@ +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -10,6 +12,8 @@ public class UpdatePlayerBuff : TerrariaPacket public byte PlayerID { get; set; } + public byte[] BuffType { get; set; } + /// /// Initializes a new instance of the class. /// @@ -27,6 +31,7 @@ public UpdatePlayerBuff(BinaryReader br) : base(br) { this.PlayerID = br.ReadByte(); + this.BuffType = br.ReadBytes(22); } public override string ToString() @@ -38,7 +43,7 @@ public override string ToString() public override short GetLength() { - return (short)(1); + return (short)(23); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -46,7 +51,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -58,8 +64,10 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(PlayerID); + br.Write(BuffType); } } diff --git a/Multiplicity.Packets/UpdateShieldStrengths.cs b/Multiplicity.Packets/UpdateShieldStrengths.cs index 3981fe2..b860e6f 100644 --- a/Multiplicity.Packets/UpdateShieldStrengths.cs +++ b/Multiplicity.Packets/UpdateShieldStrengths.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -41,8 +42,7 @@ public UpdateShieldStrengths(BinaryReader br) public override string ToString() { - return - $"[UpdateShieldStrengths: SolarTowerShield = {SolarTowerShield} VortexTowerShield = {VortexTowerShield} NebulaTowerShield = {NebulaTowerShield} StardustTowerShield = {StardustTowerShield}]"; + return $"[UpdateShieldStrengths: SolarTowerShield = {SolarTowerShield} VortexTowerShield = {VortexTowerShield} NebulaTowerShield = {NebulaTowerShield} StardustTowerShield = {StardustTowerShield}]"; } #region implemented abstract members of TerrariaPacket @@ -57,7 +57,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -69,7 +70,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(SolarTowerShield); br.Write(VortexTowerShield); br.Write(NebulaTowerShield); diff --git a/Multiplicity.Packets/UpdateSign.cs b/Multiplicity.Packets/UpdateSign.cs index c4fde7c..b6a11a7 100644 --- a/Multiplicity.Packets/UpdateSign.cs +++ b/Multiplicity.Packets/UpdateSign.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -59,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -71,7 +73,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(SignID); br.Write(X); br.Write(Y); diff --git a/Multiplicity.Packets/UpdateTileEntity.cs b/Multiplicity.Packets/UpdateTileEntity.cs index a17c98c..b798f9d 100644 --- a/Multiplicity.Packets/UpdateTileEntity.cs +++ b/Multiplicity.Packets/UpdateTileEntity.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -9,30 +10,54 @@ namespace Multiplicity.Packets public class UpdateTileEntity : TerrariaPacket { - public int EntityID { get; set; } + public int Key { get; set; } - public bool Remove { get; set; } + public byte IsRemove { get; set; } - public byte EntityType { get; set; } + /// + /// Gets or sets the TileEntityType - If Remove? == false| + /// + public byte TileEntityType { get; set; } - public int Id { get; set; } + /// + /// Gets or sets the ID - If Remove? == false| + /// + public int TileID { get; set; } + /// + /// Gets or sets the X - If Remove? == false| + /// public short X { get; set; } + /// + /// Gets or sets the Y - If Remove? == false| + /// public short Y { get; set; } - public short Npc { get; set; } + /// + /// Gets or sets the NPC - If Remove? == false && Type = 0| + /// + public short NPC { get; set; } + /// + /// Gets or sets the ItemType - If Remove? == false| + /// public short ItemType { get; set; } + /// + /// Gets or sets the Prefix - If Remove? == false| + /// public byte Prefix { get; set; } + /// + /// Gets or sets the Stack - If Remove? == false| + /// public short Stack { get; set; } /// /// Initializes a new instance of the class. /// - public UpdateTileEntity() + public UpdateTileEntity() : base((byte)PacketTypes.UpdateTileEntity) { @@ -41,31 +66,45 @@ public UpdateTileEntity() /// /// Initializes a new instance of the class. /// - /// - public UpdateTileEntity(BinaryReader br) : base(br) + /// br + public UpdateTileEntity(BinaryReader br) + : base(br) { - this.EntityID = br.ReadInt32(); - this.Remove = br.ReadBoolean(); - this.EntityType = br.ReadByte(); - this.Id = br.ReadInt32(); - this.X = br.ReadInt16(); - this.Y = br.ReadInt16(); - this.Npc = br.ReadInt16(); - this.ItemType = br.ReadInt16(); - this.Prefix = br.ReadByte(); - this.Stack = br.ReadInt16(); + this.Key = br.ReadInt32(); + this.IsRemove = br.ReadByte(); + + if (this.IsRemove == 0) + { + this.TileEntityType = br.ReadByte(); + this.TileID = br.ReadInt32(); + this.X = br.ReadInt16(); + this.Y = br.ReadInt16(); + if (this.TileEntityType == 0) + this.NPC = br.ReadInt16(); + this.ItemType = br.ReadInt16(); + this.Prefix = br.ReadByte(); + this.Stack = br.ReadInt16(); + } } public override string ToString() { - return $"[UpdateTileEntity: EntityID = {EntityID} Remove = {Remove} EntityType = {EntityType} Id = {Id} X = {X} Y = {Y} NPC = {Npc} ItemType = {ItemType} Prefix = {Prefix} Stack = {Stack}]"; + return $"[UpdateTileEntity: Key = {Key} IsRemove = {IsRemove} TileEntityType = {TileEntityType} TileID = {TileID} X = {X} Y = {Y} NPC = {NPC} ItemType = {ItemType} Prefix = {Prefix} Stack = {Stack}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(21); + if (IsRemove == 0) + { + if (TileEntityType == 0) + { + return (short)21; + } + return (short)19; + } + return (short)(5); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -86,17 +125,23 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { - br.Write(EntityID); - br.Write(Remove); - br.Write(EntityType); - br.Write(Id); - br.Write(X); - br.Write(Y); - br.Write(Npc); - br.Write(ItemType); - br.Write(Prefix); - br.Write(Stack); + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(Key); + br.Write(IsRemove); + + if (this.IsRemove == 0) + { + br.Write(TileEntityType); + br.Write(TileID); + br.Write(X); + br.Write(Y); + if (this.TileEntityType == 0) + br.Write(NPC); + br.Write(ItemType); + br.Write(Prefix); + br.Write(Stack); + } } } diff --git a/Multiplicity.Packets/WiredCannonShot.cs b/Multiplicity.Packets/WiredCannonShot.cs index 4acb6ba..3bb2381 100644 --- a/Multiplicity.Packets/WiredCannonShot.cs +++ b/Multiplicity.Packets/WiredCannonShot.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -53,8 +54,7 @@ public WiredCannonShot(BinaryReader br) public override string ToString() { - return - $"[WiredCannonShot: Damage = {Damage} Knockback = {Knockback} X = {X} Y = {Y} Angle = {Angle} Ammo = {Ammo} PlayerID = {PlayerID}]"; + return $"[WiredCannonShot: Damage = {Damage} Knockback = {Knockback} X = {X} Y = {Y} Angle = {Angle} Ammo = {Ammo} PlayerID = {PlayerID}]"; } #region implemented abstract members of TerrariaPacket @@ -69,7 +69,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -81,7 +82,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Damage); br.Write(Knockback); br.Write(X); diff --git a/Multiplicity.Packets/WorldInfo.cs b/Multiplicity.Packets/WorldInfo.cs index 071b3b1..ae75281 100644 --- a/Multiplicity.Packets/WorldInfo.cs +++ b/Multiplicity.Packets/WorldInfo.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using Multiplicity.Packets.Extensions; namespace Multiplicity.Packets { @@ -34,6 +35,10 @@ public class WorldInfo : TerrariaPacket public string WorldName { get; set; } + public byte[] WorldUniqueID { get; set; } + + public ulong WorldGeneratorVersion { get; set; } + public byte MoonType { get; set; } public byte TreeBackground { get; set; } @@ -102,14 +107,27 @@ public class WorldInfo : TerrariaPacket /// public byte EventInfo2 { get; set; } + /// + /// Gets or sets the EventInfo3 - BitFlags: 1 = Expert Mode, 2 = FastForwardTime, 3 = Slime Rain, 4 = Downed Slime King, 5 = Downed Queen Bee, 6 = Downed Fishron, 7 = Downed Martians, 8 = Downed Ancient Cultist| + /// public byte EventInfo3 { get; set; } + /// + /// Gets or sets the EventInfo4 - BitFlags: 1 = Downed Moon Lord, 2 = Downed Pumking, 3 = Downed Mourning Wood, 4 = Downed Ice Queen, 5 = Downed Santank, 6 = Downed Everscream, 7 = Downed Golem, 8 = Birthday Party| + /// public byte EventInfo4 { get; set; } + /// + /// Gets or sets the EventInfo5 - BitFlags: 1 = Downed Pirates, 2 = Downed Frost Legion, 3 = Downed Goblins, 4 = Sandstorm, 5 = DD2 Event, 6 = Downed DD2 Tier 1, 7 = Downed DD2 Tier 2, 8 = Downed DD2 Tier 3| + /// + public byte EventInfo5 { get; set; } + public sbyte InvasionType { get; set; } public ulong LobbyID { get; set; } + public float SandstormSeverity { get; set; } + /// /// Initializes a new instance of the class. /// @@ -137,6 +155,8 @@ public WorldInfo(BinaryReader br) this.RockLayer = br.ReadInt16(); this.WorldID = br.ReadInt32(); this.WorldName = br.ReadString(); + this.WorldUniqueID = br.ReadBytes(16); + this.WorldGeneratorVersion = br.ReadUInt64(); this.MoonType = br.ReadByte(); this.TreeBackground = br.ReadByte(); this.CorruptionBackground = br.ReadByte(); @@ -170,21 +190,22 @@ public WorldInfo(BinaryReader br) this.EventInfo2 = br.ReadByte(); this.EventInfo3 = br.ReadByte(); this.EventInfo4 = br.ReadByte(); + this.EventInfo5 = br.ReadByte(); this.InvasionType = br.ReadSByte(); this.LobbyID = br.ReadUInt64(); + this.SandstormSeverity = br.ReadSingle(); } public override string ToString() { - return - $"[WorldInfo: Time = {Time} DayandMoonInfo = {DayandMoonInfo} MoonPhase = {MoonPhase} MaxTilesX = {MaxTilesX} MaxTilesY = {MaxTilesY} SpawnX = {SpawnX} SpawnY = {SpawnY} WorldSurface = {WorldSurface} RockLayer = {RockLayer} WorldID = {WorldID} WorldName = {WorldName} MoonType = {MoonType} TreeBackground = {TreeBackground} CorruptionBackground = {CorruptionBackground} JungleBackground = {JungleBackground} SnowBackground = {SnowBackground} HallowBackground = {HallowBackground} CrimsonBackground = {CrimsonBackground} DesertBackground = {DesertBackground} OceanBackground = {OceanBackground} IceBackStyle = {IceBackStyle} JungleBackStyle = {JungleBackStyle} HellBackStyle = {HellBackStyle} WindSpeedSet = {WindSpeedSet} CloudNumber = {CloudNumber} Tree1 = {Tree1} Tree2 = {Tree2} Tree3 = {Tree3} TreeStyle1 = {TreeStyle1} TreeStyle2 = {TreeStyle2} TreeStyle3 = {TreeStyle3} TreeStyle4 = {TreeStyle4} CaveBack1 = {CaveBack1} CaveBack2 = {CaveBack2} CaveBack3 = {CaveBack3} CaveBackStyle1 = {CaveBackStyle1} CaveBackStyle2 = {CaveBackStyle2} CaveBackStyle3 = {CaveBackStyle3} CaveBackStyle4 = {CaveBackStyle4} Rain = {Rain} EventInfo = {EventInfo} EventInfo2 = {EventInfo2} EventInfo3 = {EventInfo3} EventInfo4 = {EventInfo4} InvasionType = {InvasionType} LobbyID = {LobbyID}]"; + return $"[WorldInfo: Time = {Time} DayandMoonInfo = {DayandMoonInfo} MoonPhase = {MoonPhase} MaxTilesX = {MaxTilesX} MaxTilesY = {MaxTilesY} SpawnX = {SpawnX} SpawnY = {SpawnY} WorldSurface = {WorldSurface} RockLayer = {RockLayer} WorldID = {WorldID} WorldName = {WorldName} WorldUniqueID = {WorldUniqueID} WorldGeneratorVersion = {WorldGeneratorVersion} MoonType = {MoonType} TreeBackground = {TreeBackground} CorruptionBackground = {CorruptionBackground} JungleBackground = {JungleBackground} SnowBackground = {SnowBackground} HallowBackground = {HallowBackground} CrimsonBackground = {CrimsonBackground} DesertBackground = {DesertBackground} OceanBackground = {OceanBackground} IceBackStyle = {IceBackStyle} JungleBackStyle = {JungleBackStyle} HellBackStyle = {HellBackStyle} WindSpeedSet = {WindSpeedSet} CloudNumber = {CloudNumber} Tree1 = {Tree1} Tree2 = {Tree2} Tree3 = {Tree3} TreeStyle1 = {TreeStyle1} TreeStyle2 = {TreeStyle2} TreeStyle3 = {TreeStyle3} TreeStyle4 = {TreeStyle4} CaveBack1 = {CaveBack1} CaveBack2 = {CaveBack2} CaveBack3 = {CaveBack3} CaveBackStyle1 = {CaveBackStyle1} CaveBackStyle2 = {CaveBackStyle2} CaveBackStyle3 = {CaveBackStyle3} CaveBackStyle4 = {CaveBackStyle4} Rain = {Rain} EventInfo = {EventInfo} EventInfo2 = {EventInfo2} EventInfo3 = {EventInfo3} EventInfo4 = {EventInfo4} EventInfo5 = {EventInfo5} InvasionType = {InvasionType} LobbyID = {LobbyID}]"; } #region implemented abstract members of TerrariaPacket public override short GetLength() { - return (short)(89 + WorldName.Length); + return (short)(118 + WorldName.Length); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -192,7 +213,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } @@ -204,7 +226,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { br.Write(Time); br.Write(DayandMoonInfo); br.Write(MoonPhase); @@ -216,6 +239,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) br.Write(RockLayer); br.Write(WorldID); br.Write(WorldName); + br.Write(WorldUniqueID); + br.Write(WorldGeneratorVersion); br.Write(MoonType); br.Write(TreeBackground); br.Write(CorruptionBackground); @@ -249,8 +274,10 @@ public override void ToStream(Stream stream, bool includeHeader = true) br.Write(EventInfo2); br.Write(EventInfo3); br.Write(EventInfo4); + br.Write(EventInfo5); br.Write(InvasionType); br.Write(LobbyID); + br.Write(SandstormSeverity); } } From e194f56ab8e3e94a28676661faec440984f14cc4 Mon Sep 17 00:00:00 2001 From: ASgoPew <35419712+ASgoPew@users.noreply.github.com> Date: Fri, 21 Jun 2019 15:01:17 +0300 Subject: [PATCH 2/2] Updated to the latest Terraria version 2 --- Multiplicity.Packets/AlterItemDrop.cs | 44 ++++--- Multiplicity.Packets/ChatMessage.cs | 5 +- Multiplicity.Packets/ChatMessagev2.cs | 2 +- Multiplicity.Packets/ColorStruct.cs | 15 +++ Multiplicity.Packets/CombatTextString.cs | 86 +++++++++++++ Multiplicity.Packets/CreateCombatText.cs | 2 +- .../Extensions/BinaryReader.Extensions.cs | 7 +- .../Extensions/BinaryWriter.Extensions.cs | 10 +- .../Multiplicity.Packets.csproj | 7 +- Multiplicity.Packets/NPCUpdate.cs | 121 ++++++++++++++---- Multiplicity.Packets/PacketTypes.cs | 3 +- Multiplicity.Packets/PlayerDeathV2.cs | 52 +++----- Multiplicity.Packets/PlayerHurtV2.cs | 55 +++----- Multiplicity.Packets/PlayerInfo.cs | 14 +- Multiplicity.Packets/ProjectileUpdate.cs | 9 +- Multiplicity.Packets/SetChestName.cs | 22 +--- Multiplicity.Packets/TerrariaPacket.cs | 3 +- .../TravellingMerchantInventory.cs | 12 +- Multiplicity.Packets/UpdatePlayer.cs | 5 +- Multiplicity.Packets/UpdateTileEntity.cs | 19 ++- .../_BuildResult/Multiplicity.Packets.dll | Bin 0 -> 162304 bytes 21 files changed, 324 insertions(+), 169 deletions(-) create mode 100644 Multiplicity.Packets/ColorStruct.cs create mode 100644 Multiplicity.Packets/CombatTextString.cs create mode 100644 Multiplicity.Packets/_BuildResult/Multiplicity.Packets.dll diff --git a/Multiplicity.Packets/AlterItemDrop.cs b/Multiplicity.Packets/AlterItemDrop.cs index 8770d91..f510848 100644 --- a/Multiplicity.Packets/AlterItemDrop.cs +++ b/Multiplicity.Packets/AlterItemDrop.cs @@ -73,17 +73,17 @@ public AlterItemDrop(BinaryReader br) if (this.Flags1.ReadBit(7)) { this.Flags2 = br.ReadByte(); - if (this.Flags1.ReadBit(0)) + if (this.Flags2.ReadBit(0)) this.Width = br.ReadInt16(); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) this.Height = br.ReadInt16(); - if (this.Flags1.ReadBit(2)) + if (this.Flags2.ReadBit(2)) this.Scale = br.ReadSingle(); - if (this.Flags1.ReadBit(3)) + if (this.Flags2.ReadBit(3)) this.Ammo = br.ReadInt16(); - if (this.Flags1.ReadBit(4)) + if (this.Flags2.ReadBit(4)) this.UseAmmo = br.ReadInt16(); - if (this.Flags1.ReadBit(5)) + if (this.Flags2.ReadBit(5)) this.NotAmmo = br.ReadBoolean(); } } @@ -110,17 +110,17 @@ public override short GetLength() if (this.Flags1.ReadBit(7)) { length += 1; - if (this.Flags1.ReadBit(0)) + if (this.Flags2.ReadBit(0)) length += 2; - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) length += 2; - if (this.Flags1.ReadBit(2)) + if (this.Flags2.ReadBit(2)) length += 4; - if (this.Flags1.ReadBit(3)) + if (this.Flags2.ReadBit(3)) length += 2; - if (this.Flags1.ReadBit(4)) + if (this.Flags2.ReadBit(4)) length += 2; - if (this.Flags1.ReadBit(5)) + if (this.Flags2.ReadBit(5)) length += 1; } @@ -129,7 +129,13 @@ public override short GetLength() public override void ToStream(Stream stream, bool includeHeader = true) { - base.ToStream(stream, includeHeader); + /* + * Length and ID headers get written in the base packet class. + */ + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } using (BinaryWriter bw = new BinaryWriter(stream, System.Text.Encoding.UTF8, leaveOpen: true)) { @@ -153,17 +159,17 @@ public override void ToStream(Stream stream, bool includeHeader = true) if (this.Flags1.ReadBit(128)) { bw.Write(Flags2); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) bw.Write(Width); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) bw.Write(Height); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) bw.Write(Scale); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) bw.Write(Ammo); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) bw.Write(UseAmmo); - if (this.Flags1.ReadBit(1)) + if (this.Flags2.ReadBit(1)) bw.Write(NotAmmo); } } diff --git a/Multiplicity.Packets/ChatMessage.cs b/Multiplicity.Packets/ChatMessage.cs index 18cc971..c88f59f 100644 --- a/Multiplicity.Packets/ChatMessage.cs +++ b/Multiplicity.Packets/ChatMessage.cs @@ -18,7 +18,7 @@ public class ChatMessage : TerrariaPacket /// /// Gets or sets the MessageColor - Client cannot change colors| /// - public Color MessageColor { get; set; } + public ColorStruct MessageColor { get; set; } public string Message { get; set; } @@ -60,7 +60,8 @@ public override void ToStream(Stream stream, bool includeHeader = true) /* * Length and ID headers get written in the base packet class. */ - if (includeHeader) { + if (includeHeader) + { base.ToStream(stream, includeHeader); } diff --git a/Multiplicity.Packets/ChatMessagev2.cs b/Multiplicity.Packets/ChatMessagev2.cs index 7812beb..5f59d71 100644 --- a/Multiplicity.Packets/ChatMessagev2.cs +++ b/Multiplicity.Packets/ChatMessagev2.cs @@ -15,7 +15,7 @@ public class ChatMessagev2 : TerrariaPacket /// /// Gets or sets the MessageColor - Client cannot change colors| /// - public Color MessageColor { get; set; } + public ColorStruct MessageColor { get; set; } /// /// Gets or sets the Message - |-| diff --git a/Multiplicity.Packets/ColorStruct.cs b/Multiplicity.Packets/ColorStruct.cs new file mode 100644 index 0000000..e671aab --- /dev/null +++ b/Multiplicity.Packets/ColorStruct.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Multiplicity.Packets +{ + public struct ColorStruct + { + public byte R { get; set; } + public byte G { get; set; } + public byte B { get; set; } + } +} diff --git a/Multiplicity.Packets/CombatTextString.cs b/Multiplicity.Packets/CombatTextString.cs new file mode 100644 index 0000000..933a3e9 --- /dev/null +++ b/Multiplicity.Packets/CombatTextString.cs @@ -0,0 +1,86 @@ +using System; +using System.IO; +using Multiplicity.Packets.Extensions; +using Multiplicity.Packets.Models; + +namespace Multiplicity.Packets +{ + /// + /// The CombatTextString (0x77) packet. + /// + public class CombatTextString : TerrariaPacket + { + + public float X { get; set; } + + public float Y { get; set; } + + public ColorStruct Color { get; set; } + + public NetworkText CombatText { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public CombatTextString() + : base((byte)PacketTypes.CombatTextString) + { + + } + + /// + /// Initializes a new instance of the class. + /// + /// br + public CombatTextString(BinaryReader br) + : base(br) + { + this.X = br.ReadSingle(); + this.Y = br.ReadSingle(); + this.Color = br.ReadColor(); + this.CombatText = br.ReadNetworkText(); + } + + public override string ToString() + { + return $"[CombatTextString: X = {X}, Y = {Y}, Color = {Color}, CombatText = {CombatText}]"; + } + + #region implemented abstract members of TerrariaPacket + + public override short GetLength() + { + return (short)(11 + CombatText.GetLength()); + } + + public override void ToStream(Stream stream, bool includeHeader = true) + { + /* + * Length and ID headers get written in the base packet class. + */ + if (includeHeader) + { + base.ToStream(stream, includeHeader); + } + + /* + * Always make sure to not close the stream when serializing. + * + * It is up to the caller to decide if the underlying stream + * gets closed. If this is a network stream we do not want + * the regressions of unconditionally closing the TCP socket + * once the payload of data has been sent to the client. + */ + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + br.Write(X); + br.Write(Y); + br.Write(Color); + br.Write(CombatText); + } + } + + #endregion + + } +} diff --git a/Multiplicity.Packets/CreateCombatText.cs b/Multiplicity.Packets/CreateCombatText.cs index 52111d8..63c7c70 100644 --- a/Multiplicity.Packets/CreateCombatText.cs +++ b/Multiplicity.Packets/CreateCombatText.cs @@ -15,7 +15,7 @@ public class CreateCombatText : TerrariaPacket public float Y { get; set; } - public Color Color { get; set; } + public ColorStruct Color { get; set; } public int HealAmount { get; set; } diff --git a/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs b/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs index d690af7..5211d19 100644 --- a/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs +++ b/Multiplicity.Packets/Extensions/BinaryReader.Extensions.cs @@ -1,4 +1,5 @@ -using System.Drawing; +using System; +using System.Drawing; using System.IO; using Multiplicity.Packets.Models; @@ -6,10 +7,10 @@ namespace Multiplicity.Packets.Extensions { public static class BinaryReaderExtensions { - public static Color ReadColor(this BinaryReader br) + public static ColorStruct ReadColor(this BinaryReader br) { byte[] colourPayload = br.ReadBytes(3); - return Color.FromArgb(colourPayload[0], colourPayload[1], colourPayload[2]); + return new ColorStruct() { R = colourPayload[0], G = colourPayload[1], B = colourPayload[2] }; } public static NetworkText ReadNetworkText(this BinaryReader br) diff --git a/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs b/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs index 99f7db2..efb743e 100644 --- a/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs +++ b/Multiplicity.Packets/Extensions/BinaryWriter.Extensions.cs @@ -5,15 +5,9 @@ namespace Multiplicity.Packets.Extensions { public static class BinaryWriterExtensions { - public static void Write(this BinaryWriter bw, System.Drawing.Color color) + public static void Write(this BinaryWriter bw, ColorStruct color) { - byte[] rgb = new byte[3]; - - rgb[0] = (byte)color.R; - rgb[1] = (byte)color.G; - rgb[2] = (byte)color.B; - - bw.Write(rgb, 0, 3); + bw.Write(new byte[3] { color.R, color.G, color.B }, 0, 3); } public static void Write(this BinaryWriter bw, NetworkText text) diff --git a/Multiplicity.Packets/Multiplicity.Packets.csproj b/Multiplicity.Packets/Multiplicity.Packets.csproj index 6e7f723..680d015 100644 --- a/Multiplicity.Packets/Multiplicity.Packets.csproj +++ b/Multiplicity.Packets/Multiplicity.Packets.csproj @@ -34,9 +34,10 @@ - + + @@ -175,4 +176,8 @@ + + if not exist "$(ProjectDir)_BuildResult" mkdir "$(ProjectDir)_BuildResult" +copy /Y "$(TargetDir)$(TargetName).dll" "$(ProjectDir)_BuildResult\$(TargetName).dll + \ No newline at end of file diff --git a/Multiplicity.Packets/NPCUpdate.cs b/Multiplicity.Packets/NPCUpdate.cs index fdc92ca..47a7062 100644 --- a/Multiplicity.Packets/NPCUpdate.cs +++ b/Multiplicity.Packets/NPCUpdate.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using Multiplicity.Packets.Extensions; @@ -20,7 +21,19 @@ public enum NPCUpdateFlags : byte public class NPCUpdate : TerrariaPacket { - public short NPCID { get; protected set; } + public static readonly int[] NetIDMap = new int[] + { + 81,81,1,1,1,1,1,1,1,1,6,6,31,31,77,42,42,176,176,176,176,173,173,183,183,3, + 3,132,132,186,186,187,187,188,188,189,189,190,191,192,193,194,2,200,200,21, + 21,201,201,202,202,203,203,223,223,231,231,232,232,233,233,234,234,235,235 + }; + public static readonly HashSet npcCatchable = new HashSet() + { + 46,55,74,148,149,297,298,299,300,355,356,357,358,359,360,361,362,363,364, + 365,366,367,374,377,539,538,484,485,486,487,442,443,444,445,446,447,448 + }; + + public short NPCID { get; set; } public float PositionX { get; set; } @@ -34,12 +47,22 @@ public class NPCUpdate : TerrariaPacket public byte Flags { get; set; } - public byte[] Remainder { get; set; } + public float[] AI { get; set; } + + public short NPCNetID { get; set; } + + public byte LifeBytes { get; set; } + + public int Life { get; set; } + + public byte ReleaseOwner { get; set; } + + public int NPCType { get; set; } public NPCUpdate() : base((byte)PacketTypes.NPCUpdate) { - this.NPCID = NPCID; + } public NPCUpdate(BinaryReader br) @@ -52,36 +75,59 @@ public NPCUpdate(BinaryReader br) this.VelocityY = br.ReadSingle(); this.Target = br.ReadUInt16(); this.Flags = br.ReadByte(); + this.AI = new float[4]; + if (this.Flags.ReadBit(2)) + this.AI[0] = br.ReadSingle(); + if (this.Flags.ReadBit(3)) + this.AI[1] = br.ReadSingle(); + if (this.Flags.ReadBit(4)) + this.AI[2] = br.ReadSingle(); + if (this.Flags.ReadBit(5)) + this.AI[3] = br.ReadSingle(); + this.NPCNetID = br.ReadInt16(); + if (!this.Flags.ReadBit(7)) + { + this.LifeBytes = br.ReadByte(); + if (this.LifeBytes == 1) + this.Life = br.ReadByte(); + else if (this.LifeBytes == 2) + this.Life = br.ReadInt16(); + else + this.Life = br.ReadInt32(); + } + this.NPCType = NPCTypeFromNetID(this.NPCNetID); + if (this.NPCType >= 0 && this.NPCType < 580 && npcCatchable.Contains((short)this.NPCType)) + this.ReleaseOwner = br.ReadByte(); + } - /* - * This is a fucking filthy hack, have to take stream length - * as a way to work out how much packet buffer we have left - * because the Terraria process has a runtime dictionary of NPC - * life bytes which tells the packet processor how many bytes of - * the NPC life there is in the packet. - * - * We don't have access to this information short of blurting - * up our on dictionary of NPC life bytes in which I would rather - * kill myself than do. - */ - - if (br.BaseStream.Length - br.BaseStream.Position > 0) + public static int NPCTypeFromNetID(int id) + { + if (id < 0) { - this.Remainder = br.ReadBytes((int)(br.BaseStream.Length - br.BaseStream.Position)); + return NetIDMap[-id - 1]; } + return id; } public override short GetLength() { - short fixedLen = 21; - - /* - * Dynamic packet sizes fucking suck balls - */ - - fixedLen += (short)Remainder.Length; - - return fixedLen; + short length = 23; + + if (this.Flags.ReadBit(2)) + length++; + if (this.Flags.ReadBit(3)) + length++; + if (this.Flags.ReadBit(4)) + length++; + if (this.Flags.ReadBit(5)) + length++; + if (!this.Flags.ReadBit(7)) + length += (short)(1 + this.LifeBytes); + this.NPCType = NPCTypeFromNetID(this.NPCNetID); + if (this.NPCType >= 0 && this.NPCType < 580 && npcCatchable.Contains((short)this.NPCType)) + length++; + + return length; } public override void ToStream(Stream stream, bool includeHeader = true) @@ -97,7 +143,28 @@ public override void ToStream(Stream stream, bool includeHeader = true) bw.Write(this.VelocityY); bw.Write(this.Target); bw.Write(this.Flags); - bw.Write(Remainder); + if (this.Flags.ReadBit(2)) + bw.Write(this.AI[0]); + if (this.Flags.ReadBit(3)) + bw.Write(this.AI[1]); + if (this.Flags.ReadBit(4)) + bw.Write(this.AI[2]); + if (this.Flags.ReadBit(5)) + bw.Write(this.AI[3]); + bw.Write(this.NPCNetID); + if (!this.Flags.ReadBit(7)) + { + bw.Write(this.LifeBytes); + if (this.LifeBytes == 1) + bw.Write((byte)this.Life); + else if (this.LifeBytes == 2) + bw.Write((short)this.Life); + else + bw.Write((int)this.Life); + } + this.NPCType = NPCTypeFromNetID(this.NPCNetID); + if (this.NPCType >= 0 && this.NPCType < 580 && npcCatchable.Contains((short)this.NPCType)) + bw.Write(this.ReleaseOwner); } } diff --git a/Multiplicity.Packets/PacketTypes.cs b/Multiplicity.Packets/PacketTypes.cs index 21b868e..2e681b2 100644 --- a/Multiplicity.Packets/PacketTypes.cs +++ b/Multiplicity.Packets/PacketTypes.cs @@ -119,7 +119,8 @@ public enum PacketTypes : byte /*115*/ MinionAttackTargetUpdate, /*116*/ CrystalInvasionSendWaitTime, /*117*/ PlayerHurtV2, - /*118*/ PlayerDeathV2 + /*118*/ PlayerDeathV2, + /*119*/ CombatTextString } } diff --git a/Multiplicity.Packets/PlayerDeathV2.cs b/Multiplicity.Packets/PlayerDeathV2.cs index a190646..ba3716e 100644 --- a/Multiplicity.Packets/PlayerDeathV2.cs +++ b/Multiplicity.Packets/PlayerDeathV2.cs @@ -8,8 +8,6 @@ namespace Multiplicity.Packets /// public class PlayerDeathV2 : TerrariaPacket { - private int _packetLength; - public byte PlayerId { get; set; } /// @@ -87,52 +85,21 @@ public PlayerDeathV2(BinaryReader br) PlayerDeathReason = br.ReadByte(); if (PlayerDeathReason.ReadBit(0)) - { FromPlayerIndex = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(1)) - { FromNpcIndex = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(2)) - { FromProjectileIndex = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(3)) - { FromOther = br.ReadByte(); - _packetLength += 1; - } - if (PlayerDeathReason.ReadBit(4)) - { FromProjectileType = br.ReadInt16(); - _length += 2; - } - if (PlayerDeathReason.ReadBit(5)) - { FromItemType = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(6)) - { FromItemPrefix = br.ReadByte(); - _packetLength += 1; - } - if (PlayerDeathReason.ReadBit(7)) - { FromCustomReason = br.ReadString(); - _packetLength += FromCustomReason.Length; - } Damage = br.ReadInt16(); HitDirection = br.ReadByte(); @@ -149,7 +116,24 @@ public override string ToString() public override short GetLength() { - return (short)(6 + _length); + int _packetLength = 0; + if (PlayerDeathReason.ReadBit(0)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(1)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(2)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(3)) + _packetLength += 1; + if (PlayerDeathReason.ReadBit(4)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(5)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(6)) + _packetLength += 1; + if (PlayerDeathReason.ReadBit(7)) + _packetLength += 1 + FromCustomReason.Length; + return (short)(6 + _packetLength); } public override void ToStream(Stream stream, bool includeHeader = true) diff --git a/Multiplicity.Packets/PlayerHurtV2.cs b/Multiplicity.Packets/PlayerHurtV2.cs index 6465327..3d79c7e 100644 --- a/Multiplicity.Packets/PlayerHurtV2.cs +++ b/Multiplicity.Packets/PlayerHurtV2.cs @@ -8,8 +8,6 @@ namespace Multiplicity.Packets /// public class PlayerHurtV2 : TerrariaPacket { - private int _packetLength; - public byte PlayerId { get; set; } /// @@ -68,7 +66,7 @@ public class PlayerHurtV2 : TerrariaPacket /// public byte Flags { get; set; } - public byte CooldownCounter { get; set; } + public sbyte CooldownCounter { get; set; } /// /// Initializes a new instance of the class. @@ -90,56 +88,26 @@ public PlayerHurtV2(BinaryReader br) PlayerDeathReason = br.ReadByte(); if (PlayerDeathReason.ReadBit(0)) - { FromPlayerIndex = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(1)) - { FromNpcIndex = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(2)) - { FromProjectileIndex = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(3)) - { FromOther = br.ReadByte(); - _packetLength += 1; - } - if (PlayerDeathReason.ReadBit(4)) - { FromProjectileType = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(5)) - { FromItemType = br.ReadInt16(); - _packetLength += 2; - } - if (PlayerDeathReason.ReadBit(6)) - { FromItemPrefix = br.ReadByte(); - _packetLength += 1; - } - if (PlayerDeathReason.ReadBit(7)) - { FromCustomReason = br.ReadString(); - _packetLength += FromCustomReason.Length; - } Damage = br.ReadInt16(); HitDirection = br.ReadByte(); Flags = br.ReadByte(); + CooldownCounter = br.ReadSByte(); } public override string ToString() @@ -152,7 +120,24 @@ public override string ToString() public override short GetLength() { - return (short)(6 + _length); + int _packetLength = 0; + if (PlayerDeathReason.ReadBit(0)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(1)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(2)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(3)) + _packetLength += 1; + if (PlayerDeathReason.ReadBit(4)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(5)) + _packetLength += 2; + if (PlayerDeathReason.ReadBit(6)) + _packetLength += 1; + if (PlayerDeathReason.ReadBit(7)) + _packetLength += 1 + FromCustomReason.Length; + return (short)(7 + _packetLength); } public override void ToStream(Stream stream, bool includeHeader = true) diff --git a/Multiplicity.Packets/PlayerInfo.cs b/Multiplicity.Packets/PlayerInfo.cs index d1e7195..a88917f 100644 --- a/Multiplicity.Packets/PlayerInfo.cs +++ b/Multiplicity.Packets/PlayerInfo.cs @@ -30,19 +30,19 @@ public class PlayerInfo : TerrariaPacket public byte HideMisc { get; set; } - public Color HairColor { get; set; } + public ColorStruct HairColor { get; set; } - public Color SkinColor { get; set; } + public ColorStruct SkinColor { get; set; } - public Color EyeColor { get; set; } + public ColorStruct EyeColor { get; set; } - public Color ShirtColor { get; set; } + public ColorStruct ShirtColor { get; set; } - public Color UnderShirtColor { get; set; } + public ColorStruct UnderShirtColor { get; set; } - public Color PantsColor { get; set; } + public ColorStruct PantsColor { get; set; } - public Color ShoeColor { get; set; } + public ColorStruct ShoeColor { get; set; } public byte Difficulty { get; set; } diff --git a/Multiplicity.Packets/ProjectileUpdate.cs b/Multiplicity.Packets/ProjectileUpdate.cs index 3834eab..9fd5779 100644 --- a/Multiplicity.Packets/ProjectileUpdate.cs +++ b/Multiplicity.Packets/ProjectileUpdate.cs @@ -95,7 +95,14 @@ public override string ToString() public override short GetLength() { - return (short)(38); + byte length = 28; + if (this.AIFlags.ReadBit(0)) + length += 4; + if (this.AIFlags.ReadBit(1)) + length += 4; + if (this.AIFlags.ReadBit(2)) + length += 2; + return (short)(length); } public override void ToStream(Stream stream, bool includeHeader = true) diff --git a/Multiplicity.Packets/SetChestName.cs b/Multiplicity.Packets/SetChestName.cs index 387f1e2..3afb15f 100644 --- a/Multiplicity.Packets/SetChestName.cs +++ b/Multiplicity.Packets/SetChestName.cs @@ -45,13 +45,10 @@ public SetChestName(BinaryReader br) this.NameLength = br.ReadByte(); this.ChestName = String.Empty; - if (this.NameLength != 0) - { - if (this.NameLength <= 20) - this.ChestName = br.ReadString(); - else if (this.NameLength != 255) - this.NameLength = 0; - } + if (this.NameLength >= 0 && this.NameLength <= 20) + this.ChestName = br.ReadString(); + else + this.NameLength = 0; } public override string ToString() @@ -63,11 +60,7 @@ public override string ToString() public override short GetLength() { - const short Length = 7; - if (ChestName == null) - return Length; - - return (short)(Length + ChestName.Length + 1); + return (short)(8 + ChestName?.Length); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -93,11 +86,10 @@ public override void ToStream(Stream stream, bool includeHeader = true) br.Write(ChestID); br.Write(ChestX); br.Write(ChestY); + NameLength = (byte)ChestName?.Length; + br.Write(NameLength); if (ChestName != null) - { - br.Write(NameLength); br.Write(ChestName); - } } } diff --git a/Multiplicity.Packets/TerrariaPacket.cs b/Multiplicity.Packets/TerrariaPacket.cs index e2b7ed6..1087ed6 100644 --- a/Multiplicity.Packets/TerrariaPacket.cs +++ b/Multiplicity.Packets/TerrariaPacket.cs @@ -140,7 +140,8 @@ public abstract class TerrariaPacket : TerrariaNetworkObject /*115*/ { PacketTypes.MinionAttackTargetUpdate, (br) => new MinionAttackTargetUpdate(br) }, /*116*/ { PacketTypes.CrystalInvasionSendWaitTime, (br) => new CrystalInvasionSendWaitTime(br) }, /*117*/ { PacketTypes.PlayerHurtV2, (br) => new PlayerHurtV2(br) }, - /*118*/ { PacketTypes.PlayerDeathV2, (br) => new PlayerDeathV2(br) } + /*118*/ { PacketTypes.PlayerDeathV2, (br) => new PlayerDeathV2(br) }, + /*119*/ { PacketTypes.CombatTextString, (br) => new CombatTextString(br) } }; /// diff --git a/Multiplicity.Packets/TravellingMerchantInventory.cs b/Multiplicity.Packets/TravellingMerchantInventory.cs index 604b16a..e9cafcd 100644 --- a/Multiplicity.Packets/TravellingMerchantInventory.cs +++ b/Multiplicity.Packets/TravellingMerchantInventory.cs @@ -8,6 +8,8 @@ namespace Multiplicity.Packets public class TravellingMerchantInventory : TerrariaPacket { + public short[] Items { get; set; } + /// /// Initializes a new instance of the class. /// @@ -24,6 +26,9 @@ public TravellingMerchantInventory() public TravellingMerchantInventory(BinaryReader br) : base(br) { + Items = new short[40]; + for (int i = 0; i < 40; i++) + Items[i] = br.ReadInt16(); } public override string ToString() @@ -35,7 +40,7 @@ public override string ToString() public override short GetLength() { - return (short)(0); + return (short)(80); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -55,7 +60,10 @@ public override void ToStream(Stream stream, bool includeHeader = true) * the regressions of unconditionally closing the TCP socket * once the payload of data has been sent to the client. */ - using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) { + using (BinaryWriter br = new BinaryWriter(stream, new System.Text.UTF8Encoding(), leaveOpen: true)) + { + for (int i = 0; i < 40; i++) + br.Write(Items[i]); } } diff --git a/Multiplicity.Packets/UpdatePlayer.cs b/Multiplicity.Packets/UpdatePlayer.cs index 4589cd6..9622da7 100644 --- a/Multiplicity.Packets/UpdatePlayer.cs +++ b/Multiplicity.Packets/UpdatePlayer.cs @@ -77,7 +77,10 @@ public override string ToString() public override short GetLength() { - return (short)(20); + byte length = 12; + if (Pulley.ReadBit(2)) + length += 8; + return (short)(length); } public override void ToStream(Stream stream, bool includeHeader = true) diff --git a/Multiplicity.Packets/UpdateTileEntity.cs b/Multiplicity.Packets/UpdateTileEntity.cs index b798f9d..0e80952 100644 --- a/Multiplicity.Packets/UpdateTileEntity.cs +++ b/Multiplicity.Packets/UpdateTileEntity.cs @@ -12,7 +12,7 @@ public class UpdateTileEntity : TerrariaPacket public int Key { get; set; } - public byte IsRemove { get; set; } + public bool IsRemove { get; set; } /// /// Gets or sets the TileEntityType - If Remove? == false| @@ -71,9 +71,9 @@ public UpdateTileEntity(BinaryReader br) : base(br) { this.Key = br.ReadInt32(); - this.IsRemove = br.ReadByte(); + this.IsRemove = br.ReadBoolean(); - if (this.IsRemove == 0) + if (!this.IsRemove) { this.TileEntityType = br.ReadByte(); this.TileID = br.ReadInt32(); @@ -96,15 +96,14 @@ public override string ToString() public override short GetLength() { - if (IsRemove == 0) + short length = 5; + if (!IsRemove) { + length += 14; if (TileEntityType == 0) - { - return (short)21; - } - return (short)19; + length += 2; } - return (short)(5); + return (short)(length); } public override void ToStream(Stream stream, bool includeHeader = true) @@ -130,7 +129,7 @@ public override void ToStream(Stream stream, bool includeHeader = true) br.Write(Key); br.Write(IsRemove); - if (this.IsRemove == 0) + if (!this.IsRemove) { br.Write(TileEntityType); br.Write(TileID); diff --git a/Multiplicity.Packets/_BuildResult/Multiplicity.Packets.dll b/Multiplicity.Packets/_BuildResult/Multiplicity.Packets.dll new file mode 100644 index 0000000000000000000000000000000000000000..7c5675bfc5ecb3397a9757864dd95bb3ccdb3be5 GIT binary patch literal 162304 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φa{KN!7OT|k~ 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

E?Jl&YWn^FelkF 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%0DY$!|x1Ua&!Lm|5qY4+?;NLfO1*|S57z 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