From 361ec4dba450aa3bdc2ed542eefa08eb91d9743b Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Thu, 12 Nov 2020 00:52:38 -0800 Subject: [PATCH] Effects packets (#308) - [X] Changes effect packets - [X] Updates playing sounds - [X] Updates Effects class to have more options so there are less direct calls to building the packets - [X] Changes bonding status packet --- .../Packets/Outgoing/EffectPacketTests.cs | 183 ++---- .../Packets/Outgoing}/EffectPackets.cs | 131 +---- .../Packets/Outgoing/MobilePackets.cs} | 19 +- .../Packets/Outgoing/PlayerPacketTests.cs | 29 - Projects/Server/Effects.cs | 548 +++++++++--------- Projects/Server/Mobiles/Mobile.cs | 60 +- Projects/Server/Network/NetState/NetState.cs | 29 +- .../Server/Network/Packets/MobilePackets.cs | 13 - .../Network/Packets/OutgoingCombatPackets.cs | 6 +- .../Network/Packets/OutgoingEffectPackets.cs | 331 +++++++++++ .../Network/Packets/OutgoingMobilePackets.cs | 54 ++ .../Server/Network/Packets/PlayerPackets.cs | 24 +- .../Commands/Generic/Commands/Commands.cs | 2 +- Projects/UOContent/Commands/Handlers.cs | 10 +- .../Context Menus/AddToSpellbookEntry.cs | 3 +- .../Doom/LeverPuzzle/LeverPuzzleController.cs | 6 +- .../Engines/Ethics/Evil/Powers/Blight.cs | 2 +- .../Engines/Ethics/Hero/Powers/Bless.cs | 2 +- .../UOContent/Engines/Khaldun/PuzzleChest.cs | 4 +- .../Quests/Dark Tides/Items/KronusScroll.cs | 19 +- .../Quests/Uzeraan Turmoil/Items/Cannon.cs | 4 +- .../Items/Construction/Doors/BaseDoor.cs | 2 +- Projects/UOContent/Items/Games/BaseBoard.cs | 13 +- Projects/UOContent/Items/Maps/TreasureMap.cs | 2 +- .../Skill Items/Magical/Misc/Moongate.cs | 2 +- .../Items/Skill Items/Magical/Runebook.cs | 4 +- .../Items/Skill Items/Magical/Spellbook.cs | 2 +- .../Items/Skill Items/Misc/FireHorn.cs | 29 +- .../Items/Special/Veteran Rewards/Cannon.cs | 12 +- .../UOContent/Items/Talismans/BaseTalisman.cs | 2 +- .../Items/Talismans/TalismanSummons.cs | 15 +- .../UOContent/Items/Weapons/BaseWeapon.cs | 2 +- Projects/UOContent/Mobiles/BaseCreature.cs | 13 +- .../Humanoid/Melee/KhaldunSummoner.cs | 4 +- .../Monsters/Humanoid/Melee/KhaldunZealot.cs | 2 +- .../Mobiles/Monsters/SE/FanDancer.cs | 87 +-- .../UOContent/Mobiles/Special/BaseChampion.cs | 4 +- .../UOContent/Mobiles/Special/Harrower.cs | 4 +- .../UOContent/Spells/Chivalry/DispelEvil.cs | 2 +- .../UOContent/Spells/Fifth/PoisonField.cs | 2 +- Projects/UOContent/Spells/Fourth/ArchCure.cs | 5 +- .../UOContent/Spells/Fourth/ArchProtection.cs | 6 +- Projects/UOContent/Spells/Fourth/FireField.cs | 2 +- .../Spells/Mysticism/HailStormSpell.cs | 37 +- .../Spells/Mysticism/NetherCycloneSpell.cs | 37 +- .../UOContent/Spells/Seventh/EnergyField.cs | 2 +- .../UOContent/Spells/Seventh/MassDispel.cs | 2 +- .../UOContent/Spells/Seventh/MeteorSwarm.cs | 5 +- Projects/UOContent/Spells/Sixth/Dispel.cs | 2 +- Projects/UOContent/Spells/Sixth/Mark.cs | 2 +- .../UOContent/Spells/Sixth/ParalyzeField.cs | 2 +- Projects/UOContent/Spells/Third/Unlock.cs | 5 +- .../UOContent/Spells/Third/WallOfStone.cs | 2 +- 53 files changed, 958 insertions(+), 833 deletions(-) rename Projects/{Server/Network/Packets => Server.Tests/Tests/Network/Packets/Outgoing}/EffectPackets.cs (68%) rename Projects/{Server/Network/Packets/DisplayHuePicker.cs => Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs} (70%) create mode 100644 Projects/Server/Network/Packets/OutgoingEffectPackets.cs create mode 100644 Projects/Server/Network/Packets/OutgoingMobilePackets.cs diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPacketTests.cs index 8be854bb0..f536adb69 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPacketTests.cs @@ -1,5 +1,4 @@ using System; -using System.Buffers; using Server.Network; using Xunit; @@ -7,6 +6,21 @@ namespace Server.Tests.Network { public class EffectPackets { + [Theory] + [InlineData(10, 1000, 10, 5)] + public void TestSoundEffect(ushort soundID, int x, int y, int z) + { + var p = new Point3D(x, y, z); + + var expected = new PlaySound(soundID, p).Compile(); + + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendSoundEffect(soundID, p); + + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); + } + [Fact] public void TestParticleEffect() { @@ -29,56 +43,21 @@ namespace Server.Tests.Network byte layer = 9; ushort unknown = 0; - var data = new ParticleEffect( - effectType, - from, - to, - itemId, - fromPoint, - toPoint, - speed, - duration, - direction, - explode, - hue, - renderMode, - effect, - explodeEffect, - explodeSound, - serial, - layer, + var expected = new ParticleEffect( + effectType, from, to, itemId, fromPoint, toPoint, speed, duration, direction, + explode, hue, renderMode, effect, explodeEffect, explodeSound, serial, layer, unknown ).Compile(); - Span expectedData = stackalloc byte[49]; + Span actual = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength]; + OutgoingEffectPackets.CreateParticleEffect( + ref actual, + effectType, from, to, itemId, fromPoint, toPoint, speed, duration, direction, + explode, hue, renderMode, effect, explodeEffect, explodeSound, serial, layer, + unknown + ); - var pos = 0; - expectedData.Write(ref pos, (byte)0xC7); // Packet ID - expectedData.Write(ref pos, (byte)effectType); - expectedData.Write(ref pos, from); - expectedData.Write(ref pos, to); - expectedData.Write(ref pos, (ushort)itemId); - expectedData.Write(ref pos, fromPoint); - expectedData.Write(ref pos, toPoint); - expectedData.Write(ref pos, speed); - expectedData.Write(ref pos, duration); -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (ushort)0); -#else - pos += 2; -#endif - expectedData.Write(ref pos, direction); - expectedData.Write(ref pos, explode); - expectedData.Write(ref pos, hue); - expectedData.Write(ref pos, renderMode); - expectedData.Write(ref pos, effect); - expectedData.Write(ref pos, explodeEffect); - expectedData.Write(ref pos, explodeSound); - expectedData.Write(ref pos, serial); - expectedData.Write(ref pos, layer); - expectedData.Write(ref pos, unknown); - - AssertThat.Equal(data, expectedData); + AssertThat.Equal(actual, expected); } [Fact] @@ -97,74 +76,33 @@ namespace Server.Tests.Network var hue = 0x1024; var renderMode = 1; - var data = new HuedEffect( - effectType, - from, - to, - itemId, - fromPoint, - toPoint, - speed, - duration, - direction, - explode, - hue, - renderMode + var expected = new HuedEffect( + effectType, from, to, itemId, fromPoint, toPoint, speed, + duration, direction, explode, hue, renderMode ).Compile(); - Span expectedData = stackalloc byte[36]; + Span actual = stackalloc byte[OutgoingEffectPackets.HuedEffectLength]; + OutgoingEffectPackets.CreateHuedEffect( + ref actual, + effectType, from, to, itemId, fromPoint, toPoint, speed, + duration, direction, explode, hue, renderMode + ); - var pos = 0; - expectedData.Write(ref pos, (byte)0xC0); // Packet ID - expectedData.Write(ref pos, (byte)effectType); - expectedData.Write(ref pos, from); - expectedData.Write(ref pos, to); - expectedData.Write(ref pos, (ushort)itemId); - expectedData.Write(ref pos, fromPoint); - expectedData.Write(ref pos, toPoint); - expectedData.Write(ref pos, speed); - expectedData.Write(ref pos, duration); -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (ushort)0); -#else - pos += 2; -#endif - expectedData.Write(ref pos, direction); - expectedData.Write(ref pos, explode); - expectedData.Write(ref pos, hue); - expectedData.Write(ref pos, renderMode); - - AssertThat.Equal(data, expectedData); + AssertThat.Equal(actual, expected); } - [Fact] - public void TestScreenEffect() + [Theory] + [InlineData(ScreenEffectType.DarkFlash)] + [InlineData(ScreenEffectType.FadeInOut)] + public void TestScreenEffect(ScreenEffectType screenType) { - var type = ScreenEffectType.FadeOut; - var data = new ScreenEffect(type).Compile(); + var expected = new ScreenEffect(screenType).Compile(); - Span expectedData = stackalloc byte[28]; - var pos = 0; + using var ns = PacketTestUtilities.CreateTestNetState(); + ns.SendScreenEffect(screenType); - expectedData.Write(ref pos, (byte)0x70); // Packet ID - expectedData.Write(ref pos, (byte)0x04); // Effect -#if NO_LOCAL_INIT - expectedData.Write(ref pos, 0); - expectedData.Write(ref pos, 0); -#else - pos += 8; -#endif - - expectedData.Write(ref pos, (ushort)type); // Screen Effect Type - -#if NO_LOCAL_INIT - expectedData.Write(ref pos, 0); - expectedData.Write(ref pos, 0); - expectedData.Write(ref pos, 0); - expectedData.Write(ref pos, 0); -#endif - - AssertThat.Equal(data, expectedData); + var result = ns.SendPipe.Reader.TryRead(); + AssertThat.Equal(result.Buffer[0].AsSpan(0), expected); } [Fact] @@ -172,32 +110,15 @@ namespace Server.Tests.Network { IEntity entity = new Entity(0x1000, new Point3D(1000, 100, -10), Map.Felucca); var hue = 0x1024; - var data = new BoltEffect(entity, hue).Compile(); + var expected = new BoltEffect(entity, hue).Compile(); - Span expectedData = stackalloc byte[36]; - var pos = 0; - expectedData.Write(ref pos, (byte)0xC0); // Packet ID - expectedData.Write(ref pos, (byte)0x01); // Effect + Span actual = stackalloc byte[OutgoingEffectPackets.BoltEffectLength]; + OutgoingEffectPackets.CreateBoltEffect( + ref actual, + entity, hue + ); - - expectedData.Write(ref pos, entity.Serial); -#if NO_LOCAL_INIT - expectedData.Write(ref pos, 0); - expectedData.Write(ref pos, (ushort)0); -#else - pos += 6; -#endif - expectedData.Write(ref pos, entity.Location); - expectedData.Write(ref pos, entity.Location); -#if NO_LOCAL_INIT - expectedData.Write(ref pos, 0); - expectedData.Write(ref pos, (ushort)0); -#else - pos += 6; -#endif - expectedData.Write(ref pos, hue); - - AssertThat.Equal(data, expectedData); + AssertThat.Equal(actual, expected); } } } diff --git a/Projects/Server/Network/Packets/EffectPackets.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPackets.cs similarity index 68% rename from Projects/Server/Network/Packets/EffectPackets.cs rename to Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPackets.cs index faad7c948..efc18d915 100644 --- a/Projects/Server/Network/Packets/EffectPackets.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/EffectPackets.cs @@ -15,48 +15,21 @@ namespace Server.Network { - public enum EffectType + public sealed class PlaySound : Packet { - Moving, - Lightning, - FixedXYZ, - FixedFrom + public PlaySound(int soundID, IPoint3D target) : base(0x54, 12) + { + Stream.Write((byte)1); // flags + Stream.Write((short)soundID); + Stream.Write((short)0); // volume + Stream.Write((short)target.X); + Stream.Write((short)target.Y); + Stream.Write((short)target.Z); + } } public class ParticleEffect : Packet { - public ParticleEffect( - EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, - int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, - int explodeEffect, int explodeSound, Serial serial, int layer, int unknown - ) : base(0xC7, 49) - { - Stream.Write((byte)type); - Stream.Write(from); - Stream.Write(to); - Stream.Write((short)itemID); - Stream.Write((short)fromPoint.m_X); - Stream.Write((short)fromPoint.m_Y); - Stream.Write((sbyte)fromPoint.m_Z); - Stream.Write((short)toPoint.m_X); - Stream.Write((short)toPoint.m_Y); - Stream.Write((sbyte)toPoint.m_Z); - Stream.Write((byte)speed); - Stream.Write((byte)duration); - Stream.Write((byte)0); - Stream.Write((byte)0); - Stream.Write(fixedDirection); - Stream.Write(explode); - Stream.Write(hue); - Stream.Write(renderMode); - Stream.Write((short)effect); - Stream.Write((short)explodeEffect); - Stream.Write((short)explodeSound); - Stream.Write(serial); - Stream.Write((byte)layer); - Stream.Write((short)unknown); - } - public ParticleEffect( EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, @@ -92,31 +65,6 @@ namespace Server.Network public class HuedEffect : Packet { - public HuedEffect( - EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, int speed, - int duration, bool fixedDirection, bool explode, int hue, int renderMode - ) : base(0xC0, 36) - { - Stream.Write((byte)type); - Stream.Write(from); - Stream.Write(to); - Stream.Write((short)itemID); - Stream.Write((short)fromPoint.m_X); - Stream.Write((short)fromPoint.m_Y); - Stream.Write((sbyte)fromPoint.m_Z); - Stream.Write((short)toPoint.m_X); - Stream.Write((short)toPoint.m_Y); - Stream.Write((sbyte)toPoint.m_Z); - Stream.Write((byte)speed); - Stream.Write((byte)duration); - Stream.Write((byte)0); - Stream.Write((byte)0); - Stream.Write(fixedDirection); - Stream.Write(explode); - Stream.Write(hue); - Stream.Write(renderMode); - } - public HuedEffect( EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode @@ -294,15 +242,6 @@ namespace Server.Network } } - public enum ScreenEffectType - { - FadeOut = 0x00, - FadeIn = 0x01, - LightFlash = 0x02, - FadeInOut = 0x03, - DarkFlash = 0x04 - } - public class ScreenEffect : Packet { public ScreenEffect(ScreenEffectType type) @@ -315,56 +254,6 @@ namespace Server.Network } } - public sealed class ScreenFadeOut : ScreenEffect - { - public static readonly Packet Instance = SetStatic(new ScreenFadeOut()); - - public ScreenFadeOut() - : base(ScreenEffectType.FadeOut) - { - } - } - - public sealed class ScreenFadeIn : ScreenEffect - { - public static readonly Packet Instance = SetStatic(new ScreenFadeIn()); - - public ScreenFadeIn() - : base(ScreenEffectType.FadeIn) - { - } - } - - public sealed class ScreenFadeInOut : ScreenEffect - { - public static readonly Packet Instance = SetStatic(new ScreenFadeInOut()); - - public ScreenFadeInOut() - : base(ScreenEffectType.FadeInOut) - { - } - } - - public sealed class ScreenLightFlash : ScreenEffect - { - public static readonly Packet Instance = SetStatic(new ScreenLightFlash()); - - public ScreenLightFlash() - : base(ScreenEffectType.LightFlash) - { - } - } - - public sealed class ScreenDarkFlash : ScreenEffect - { - public static readonly Packet Instance = SetStatic(new ScreenDarkFlash()); - - public ScreenDarkFlash() - : base(ScreenEffectType.DarkFlash) - { - } - } - public sealed class BoltEffect : Packet { public BoltEffect(IEntity target, int hue) : base(0xC0, 36) diff --git a/Projects/Server/Network/Packets/DisplayHuePicker.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs similarity index 70% rename from Projects/Server/Network/Packets/DisplayHuePicker.cs rename to Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs index bc829d2de..3e5a432a9 100644 --- a/Projects/Server/Network/Packets/DisplayHuePicker.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/MobilePackets.cs @@ -2,7 +2,7 @@ * ModernUO * * Copyright 2019-2020 - ModernUO Development Team * * Email: hi@modernuo.com * - * File: DisplayHuePicker.cs * + * File: MobilePackets.cs * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -13,17 +13,20 @@ * along with this program. If not, see . * *************************************************************************/ -using Server.HuePickers; +using Server.Network; -namespace Server.Network +namespace Server.Tests.Network { - public sealed class DisplayHuePicker : Packet + public sealed class BondedStatus : Packet { - public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9) + public BondedStatus(Serial serial, bool bonded) : base(0xBF) { - Stream.Write(huePicker.Serial); - Stream.Write((short)0); - Stream.Write((short)huePicker.ItemID); + EnsureCapacity(11); + + Stream.Write((short)0x19); + Stream.Write((byte)0); + Stream.Write(serial); + Stream.Write((byte)(bonded ? 1 : 0)); } } } diff --git a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs index 3d91ef35f..59b23470a 100644 --- a/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs +++ b/Projects/Server.Tests/Tests/Network/Packets/Outgoing/PlayerPacketTests.cs @@ -388,35 +388,6 @@ namespace Server.Tests.Network AssertThat.Equal(data, expectedData); } - [Theory] - [InlineData(10, 1000, 10, 5)] - public void TestPlaySound(ushort soundID, int x, int y, int z) - { - var p = new Point3D(x, y, z); - - var data = new PlaySound(soundID, p).Compile(); - - Span expectedData = stackalloc byte[12]; - var pos = 0; - - expectedData.Write(ref pos, (byte)0x54); // Packet ID - expectedData.Write(ref pos, (byte)1); // Flags - expectedData.Write(ref pos, soundID); - -#if NO_LOCAL_INIT - expectedData.Write(ref pos, (ushort)0); // Volume -#else - pos += 2; -#endif - - expectedData.Write(ref pos, (ushort)p.X); - expectedData.Write(ref pos, (ushort)p.Y); - expectedData.Write(ref pos, (short)p.Z); - - - AssertThat.Equal(data, expectedData); - } - [Theory] [InlineData(MusicName.Approach)] [InlineData(MusicName.Combat1)] diff --git a/Projects/Server/Effects.cs b/Projects/Server/Effects.cs index 871b36712..a86a9aaa7 100644 --- a/Projects/Server/Effects.cs +++ b/Projects/Server/Effects.cs @@ -1,7 +1,40 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: Effects.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; using Server.Network; namespace Server { + public enum EffectType + { + Moving, + Lightning, + FixedXYZ, + FixedFrom + } + + public enum ScreenEffectType + { + FadeOut = 0x00, + FadeIn = 0x01, + LightFlash = 0x02, + FadeInOut = 0x03, + DarkFlash = 0x04 + } + public enum EffectLayer { Head = 0, @@ -28,7 +61,9 @@ namespace Server ParticleSupportType == ParticleSupportType.Full || ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient; - public static void PlaySound(IPoint3D p, Map map, int soundID) + public static void PlaySound(IEntity e, int soundID) => PlaySound(e.Location, e.Map, soundID); + + public static void PlaySound(Point3D p, Map map, int soundID) { if (soundID <= -1) { @@ -37,36 +72,22 @@ namespace Server if (map != null) { - Packet playSound = null; + Span buffer = stackalloc byte[OutgoingEffectPackets.SoundPacketLength]; + OutgoingEffectPackets.CreateSoundEffect(ref buffer, soundID, p); var eable = map.GetClientsInRange(new Point3D(p)); foreach (var state in eable) { state.Mobile.ProcessDelta(); - - playSound ??= Packet.Acquire(new PlaySound(soundID, p)); - - state.Send(playSound); + state.Send(buffer); } - Packet.Release(playSound); - eable.Free(); } } - public static void SendBoltEffect(IEntity e) - { - SendBoltEffect(e, true, 0); - } - - public static void SendBoltEffect(IEntity e, bool sound) - { - SendBoltEffect(e, sound, 0); - } - - public static void SendBoltEffect(IEntity e, bool sound, int hue) + public static void SendBoltEffect(IEntity e, bool sound = true, int hue = 0) { var map = e.Map; @@ -77,7 +98,20 @@ namespace Server e.ProcessDelta(); - Packet preEffect = null, boltEffect = null, playSound = null; + Span preEffect = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength]; + OutgoingEffectPackets.CreateTargetParticleEffect( + ref preEffect, + e, 0, 10, 5, 0, 0, 5031, 3, 0 + ); + + Span boltEffect = stackalloc byte[OutgoingEffectPackets.BoltEffectLength]; + OutgoingEffectPackets.CreateBoltEffect(ref boltEffect, e, hue); + + Span soundEffect = sound ? stackalloc byte[OutgoingEffectPackets.SoundPacketLength] : null; + if (sound) + { + OutgoingEffectPackets.CreateSoundEffect(ref soundEffect, 0x29, e); + } var eable = map.GetClientsInRange(e.Location); @@ -87,52 +121,36 @@ namespace Server { if (SendParticlesTo(state)) { - preEffect ??= Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0)); - state.Send(preEffect); } - boltEffect ??= Packet.Acquire(new BoltEffect(e, hue)); - state.Send(boltEffect); if (sound) { - playSound ??= Packet.Acquire(new PlaySound(0x29, e)); - - state.Send(playSound); + state.Send(soundEffect); } } } - Packet.Release(preEffect); - Packet.Release(boltEffect); - Packet.Release(playSound); - eable.Free(); } - public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration) - { - SendLocationEffect(p, map, itemID, duration, 10, 0, 0); - } - - public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed) - { - SendLocationEffect(p, map, itemID, duration, speed, 0, 0); - } - - public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int hue, int renderMode) - { - SendLocationEffect(p, map, itemID, duration, 10, hue, renderMode); - } + public static void SendLocationEffect( + IEntity e, int itemID, int duration, int speed = 10, int hue = 0, int renderMode = 0 + ) => SendLocationEffect(e.Location, e.Map, itemID, duration, speed, hue, renderMode); public static void SendLocationEffect( - IPoint3D p, Map map, int itemID, int duration, int speed, int hue, - int renderMode + Point3D p, Map map, int itemID, int duration, int speed = 10, int hue = 0, int renderMode = 0 ) { - SendPacket(p, map, new LocationEffect(p, itemID, speed, duration, hue, renderMode)); + Span effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength]; + OutgoingEffectPackets.CreateLocationHuedEffect( + ref effect, + p, itemID, speed, duration, hue, renderMode + ); + + SendPacket(p, map, ref effect); } public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect) @@ -146,71 +164,61 @@ namespace Server } public static void SendLocationParticles( - IEntity e, int itemID, int speed, int duration, int hue, int renderMode, - int effect, int unknown + IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown ) { var map = e.Map; - if (map != null) + if (map == null) { - Packet particles = null, regular = null; + return; + } - var eable = map.GetClientsInRange(e.Location); + Span particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength]; + OutgoingEffectPackets.CreateLocationParticleEffect( + ref particles, + e, itemID, speed, duration, hue, renderMode, effect, unknown + ); - foreach (var state in eable) + Span regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength] : null; + if (itemID != 0) + { + OutgoingEffectPackets.CreateLocationHuedEffect( + ref regular, + e.Location, itemID, speed, duration, hue, renderMode + ); + } + + var eable = map.GetClientsInRange(e.Location); + + foreach (var state in eable) + { + state.Mobile.ProcessDelta(); + + if (SendParticlesTo(state)) { - state.Mobile.ProcessDelta(); - - if (SendParticlesTo(state)) - { - particles ??= - Packet.Acquire( - new LocationParticleEffect(e, itemID, speed, duration, hue, renderMode, effect, unknown) - ); - - state.Send(particles); - } - else if (itemID != 0) - { - regular ??= Packet.Acquire(new LocationEffect(e, itemID, speed, duration, hue, renderMode)); - - state.Send(regular); - } + state.Send(particles); + } + else if (itemID != 0) + { + state.Send(regular); } - - Packet.Release(particles); - Packet.Release(regular); - - eable.Free(); } - // SendPacket( e.Location, e.Map, new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) ); + eable.Free(); } - public static void SendTargetEffect(IEntity target, int itemID, int duration) + public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue = 0, int renderMode = 0) { - SendTargetEffect(target, itemID, duration, 0, 0); - } + (target as Mobile)?.ProcessDelta(); - public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration) - { - SendTargetEffect(target, itemID, speed, duration, 0, 0); - } + Span effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength]; + OutgoingEffectPackets.CreateTargetHuedEffect( + ref effect, + target, itemID, speed, duration, hue, renderMode + ); - public static void SendTargetEffect(IEntity target, int itemID, int duration, int hue, int renderMode) - { - SendTargetEffect(target, itemID, 10, duration, hue, renderMode); - } - - public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue, int renderMode) - { - if (target is Mobile mobile) - { - mobile.ProcessDelta(); - } - - SendPacket(target.Location, target.Map, new TargetEffect(target, itemID, speed, duration, hue, renderMode)); + SendPacket(target.Location, target.Map, ref effect); } public static void SendTargetParticles( @@ -218,121 +226,184 @@ namespace Server EffectLayer layer ) { - SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer, 0); - } - - public static void SendTargetParticles( - IEntity target, int itemID, int speed, int duration, int effect, - EffectLayer layer, int unknown - ) - { - SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer, unknown); + SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer); } public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int hue, int renderMode, - int effect, EffectLayer layer, int unknown + int effect, EffectLayer layer, int unknown = 0 ) { - if (target is Mobile mobile) - { - mobile.ProcessDelta(); - } + (target as Mobile)?.ProcessDelta(); var map = target.Map; - if (map != null) + if (map == null) { - Packet particles = null, regular = null; - - var eable = map.GetClientsInRange(target.Location); - - foreach (var state in eable) - { - state.Mobile.ProcessDelta(); - - if (SendParticlesTo(state)) - { - particles ??= Packet.Acquire( - new TargetParticleEffect( - target, - itemID, - speed, - duration, - hue, - renderMode, - effect, - (int)layer, - unknown - ) - ); - - state.Send(particles); - } - else if (itemID != 0) - { - regular ??= Packet.Acquire(new TargetEffect(target, itemID, speed, duration, hue, renderMode)); - - state.Send(regular); - } - } - - Packet.Release(particles); - Packet.Release(regular); - - eable.Free(); + return; } - // SendPacket( target.Location, target.Map, new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) ); + Span particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength]; + OutgoingEffectPackets.CreateTargetParticleEffect( + ref particles, + target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown + ); + + Span regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength] : null; + if (itemID != 0) + { + OutgoingEffectPackets.CreateTargetHuedEffect(ref regular, target, itemID, speed, duration, hue, renderMode); + } + + var eable = map.GetClientsInRange(target.Location); + + foreach (var state in eable) + { + state.Mobile.ProcessDelta(); + + if (SendParticlesTo(state)) + { + state.Send(particles); + } + else if (itemID != 0) + { + state.Send(regular); + } + } + + eable.Free(); } public static void SendMovingEffect( - IEntity from, IEntity to, int itemID, int speed, int duration, - bool fixedDirection, bool explodes, int hue = 0, int renderMode = 0 + Map map, int itemID, Point3D from, Point3D to, int speed, int duration, + bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0 + ) => SendMovingEffect( + Serial.Zero, + Serial.Zero, + from, + map, + itemID, + from, + to, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + + public static void SendMovingEffect( + Point3D origin, Map map, int itemID, Point3D from, Point3D to, int speed, int duration, + bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0 + ) => SendMovingEffect( + Serial.Zero, + Serial.Zero, + origin, + map, + itemID, + from, + to, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + + public static void SendMovingEffect( + IEntity from, Point3D to, int itemID, + int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0 ) { - if (from is Mobile mobile) - { - mobile.ProcessDelta(); - } + (from as Mobile)?.ProcessDelta(); - if (to is Mobile mobile1) - { - mobile1.ProcessDelta(); - } - - SendPacket( + SendMovingEffect( + from.Serial, + Serial.Zero, from.Location, from.Map, - new MovingEffect(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode) - ); - } - - public static void SendMovingParticles( - IEntity from, IEntity to, int itemID, int speed, int duration, - bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound - ) - { - SendMovingParticles( - from, - to, itemID, + from.Location, + to, speed, duration, fixedDirection, explodes, - 0, - 0, - effect, - explodeEffect, - explodeSound, - 0 + hue, + renderMode ); } + public static void SendMovingEffect( + IEntity from, IEntity to, int itemID, + int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0 + ) + { + (from as Mobile)?.ProcessDelta(); + (to as Mobile)?.ProcessDelta(); + + SendMovingEffect( + from, + to, + from.Location, + from.Map, + itemID, + from.Location, + to.Location, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + } + + public static void SendMovingEffect( + IEntity from, IEntity to, Point3D origin, Map map, int itemID, Point3D fromLocation, Point3D toLocation, + int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0 + ) + { + (from as Mobile)?.ProcessDelta(); + (to as Mobile)?.ProcessDelta(); + + SendMovingEffect( + from.Serial, + to.Serial, + origin, + map, + itemID, + fromLocation, + toLocation, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + } + + public static void SendMovingEffect( + Serial from, Serial to, Point3D origin, Map map, int itemID, Point3D fromLocation, Point3D toLocation, + int speed, int duration, bool fixedDirection = false, bool explodes = false, int hue = 0, int renderMode = 0 + ) + { + Span effect = stackalloc byte[OutgoingEffectPackets.HuedEffectLength]; + OutgoingEffectPackets.CreateMovingHuedEffect( + ref effect, + from, to, itemID, fromLocation, toLocation, speed, duration, fixedDirection, + explodes, hue, renderMode + ); + + SendPacket(origin, map, ref effect); + } + public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, - bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown + bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown = 0 ) { SendMovingParticles( @@ -382,103 +453,52 @@ namespace Server EffectLayer layer, int unknown ) { - if (from is Mobile fromMob) - { - fromMob.ProcessDelta(); - } - - if (to is Mobile toMob) - { - toMob.ProcessDelta(); - } + (from as Mobile)?.ProcessDelta(); + (to as Mobile)?.ProcessDelta(); var map = from.Map; - if (map != null) - { - Packet particles = null, regular = null; - - var eable = map.GetClientsInRange(from.Location); - - foreach (var state in eable) - { - state.Mobile.ProcessDelta(); - - if (SendParticlesTo(state)) - { - particles ??= Packet.Acquire( - new MovingParticleEffect( - from, - to, - itemID, - speed, - duration, - fixedDirection, - explodes, - hue, - renderMode, - effect, - explodeEffect, - explodeSound, - layer, - unknown - ) - ); - - state.Send(particles); - } - else if (itemID > 1) - { - regular ??= Packet.Acquire( - new MovingEffect( - from, - to, - itemID, - speed, - duration, - fixedDirection, - explodes, - hue, - renderMode - ) - ); - - state.Send(regular); - } - } - - Packet.Release(particles); - Packet.Release(regular); - - eable.Free(); - } - - // SendPacket( from.Location, from.Map, new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, unknown ) ); - } - - public static void SendPacket(Point3D origin, Map map, Packet p) - { if (map == null) { return; } - var eable = map.GetClientsInRange(origin); + Span particles = stackalloc byte[OutgoingEffectPackets.ParticleEffectLength]; + OutgoingEffectPackets.CreateMovingParticleEffect( + ref particles, + from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, + explodeEffect, explodeSound, layer, unknown + ); - p.Acquire(); + Span regular = itemID != 0 ? stackalloc byte[OutgoingEffectPackets.HuedEffectLength] : null; + if (itemID != 0) + { + OutgoingEffectPackets.CreateMovingHuedEffect( + ref regular, + from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode + ); + } + + var eable = map.GetClientsInRange(from.Location); foreach (var state in eable) { state.Mobile.ProcessDelta(); - state.Send(p); - } - p.Release(); + if (SendParticlesTo(state)) + { + state.Send(particles); + } + else if (itemID > 1) + { + state.Send(regular); + } + } eable.Free(); } - public static void SendPacket(IPoint3D origin, Map map, Packet p) + public static void SendPacket(Point3D origin, Map map, ref Span effectBuffer) { if (map == null) { @@ -487,16 +507,12 @@ namespace Server var eable = map.GetClientsInRange(new Point3D(origin)); - p.Acquire(); - foreach (var state in eable) { state.Mobile.ProcessDelta(); - state.Send(p); + state.Send(effectBuffer); } - p.Release(); - eable.Free(); } } diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index 552b189fb..e47f875d7 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using Server.Accounting; @@ -3374,12 +3375,14 @@ namespace Server Packet hitsPacket = null; Packet statPacketTrue = null; Packet statPacketFalse = null; - Packet deadPacket = null; Packet hairPacket = null; Packet facialhairPacket = null; Packet hbpPacket = null; Packet hbyPacket = null; + Span deadBuffer = stackalloc byte[OutgoingMobilePackets.BondedStatusPacketLength]; + OutgoingMobilePackets.CreateBondedStatus(ref deadBuffer, m.Serial, true); + var eable = m.Map.GetClientsInRange(m.m_Location); foreach (var state in eable) @@ -3399,9 +3402,7 @@ namespace Server if (m.IsDeadBondedPet) { - deadPacket ??= Packet.Acquire(new BondedStatus(m.Serial, true)); - - state.Send(deadPacket); + state.Send(deadBuffer); } } @@ -3502,7 +3503,6 @@ namespace Server Packet.Release(hitsPacket); Packet.Release(statPacketTrue); Packet.Release(statPacketFalse); - Packet.Release(deadPacket); Packet.Release(hairPacket); Packet.Release(facialhairPacket); Packet.Release(hbpPacket); @@ -5383,7 +5383,7 @@ namespace Server if (sound >= 0) { - Effects.PlaySound(this, Map, sound); + Effects.PlaySound(this, sound); } if (!m_Player) @@ -5660,12 +5660,7 @@ namespace Server from.Holding = item; - var liftSound = item.GetLiftSound(from); - - if (liftSound != -1) - { - from.Send(new PlaySound(liftSound, from)); - } + from.SendSound(item.GetLiftSound(from)); from.NextActionTime = Core.TickCount + ActionDelay; @@ -7319,22 +7314,21 @@ namespace Server eable.Free(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SendSound(int soundID) { - if (soundID != -1 && m_NetState != null) - { - Send(new PlaySound(soundID, this)); - } + m_NetState?.SendSoundEffect(soundID, this); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void SendSound(int soundID, IPoint3D p) { - if (soundID != -1 && m_NetState != null) - { - Send(new PlaySound(soundID, p)); - } + m_NetState?.SendSoundEffect(soundID, p); } + /** + * Plays a sound to netstates that can see this mobile + */ public void PlaySound(int soundID) { if (soundID == -1 || m_Map == null) @@ -7342,7 +7336,8 @@ namespace Server return; } - var p = Packet.Acquire(new PlaySound(soundID, this)); + Span buffer = stackalloc byte[OutgoingEffectPackets.SoundPacketLength]; + OutgoingEffectPackets.CreateSoundEffect(ref buffer, soundID, this); var eable = m_Map.GetClientsInRange(m_Location); @@ -7350,12 +7345,10 @@ namespace Server { if (state.Mobile.CanSee(this)) { - state.Send(p); + state.Send(buffer); } } - Packet.Release(p); - eable.Free(); } @@ -7382,12 +7375,7 @@ namespace Server DisruptiveAction(); // Anything that unhides you will also distrupt meditation } - public void SendRemovePacket() - { - SendRemovePacket(true); - } - - public void SendRemovePacket(bool everyone) + public void SendRemovePacket(bool everyone = true) { if (m_Map == null) { @@ -7530,7 +7518,7 @@ namespace Server if (m.IsDeadBondedPet) { - ns.Send(new BondedStatus(m.Serial, true)); + ns.SendBondedStatus(m.Serial, true); } if (ObjectPropertyList.Enabled) @@ -7690,7 +7678,7 @@ namespace Server if (IsDeadBondedPet) { - state.Send(new BondedStatus(Serial, true)); + state.SendBondedStatus(Serial, true); } if (ObjectPropertyList.Enabled) @@ -7976,7 +7964,7 @@ namespace Server if (IsDeadBondedPet) { - m.m_NetState.Send(new BondedStatus(Serial, true)); + m.m_NetState.SendBondedStatus(Serial, true); } if (ObjectPropertyList.Enabled) @@ -8003,7 +7991,7 @@ namespace Server if (m.IsDeadBondedPet) { - ourState.Send(new BondedStatus(m.Serial, true)); + ourState.SendBondedStatus(m.Serial, true); } if (ObjectPropertyList.Enabled) @@ -8038,7 +8026,7 @@ namespace Server if (IsDeadBondedPet) { - ns.Send(new BondedStatus(Serial, true)); + ns.SendBondedStatus(Serial, true); } if (ObjectPropertyList.Enabled) @@ -8126,7 +8114,7 @@ namespace Server if (IsDeadBondedPet) { - state.Send(new BondedStatus(Serial, true)); + state.SendBondedStatus(Serial, true); } if (ObjectPropertyList.Enabled) diff --git a/Projects/Server/Network/NetState/NetState.cs b/Projects/Server/Network/NetState/NetState.cs index a19835ca3..47de6870e 100644 --- a/Projects/Server/Network/NetState/NetState.cs +++ b/Projects/Server/Network/NetState/NetState.cs @@ -377,7 +377,34 @@ namespace Server.Network return !(result.IsClosed || result.Length <= 0); } - public virtual void Send(ref CircularBuffer buffer, int length) + public void Send(ReadOnlySpan span) + { + var length = span.Length; + if (Connection == null || BlockAllPackets || length <= 0 || !GetSendBuffer(out var buffer)) + { + return; + } + + try + { + buffer.CopyFrom(span); + _packetEncoder?.Invoke(ref buffer, ref length); + SendPipe.Writer.Advance((uint)length); + } + catch (Exception ex) + { +#if DEBUG + Console.WriteLine(ex); + TraceException(ex); +#endif + Dispose(); + } + } + + /** + * Send data using a circular buffer from SendPipe + */ + public void Send(ref CircularBuffer buffer, int length) { if (Connection == null || BlockAllPackets || length <= 0) { diff --git a/Projects/Server/Network/Packets/MobilePackets.cs b/Projects/Server/Network/Packets/MobilePackets.cs index 51beb7da8..0798da260 100644 --- a/Projects/Server/Network/Packets/MobilePackets.cs +++ b/Projects/Server/Network/Packets/MobilePackets.cs @@ -27,19 +27,6 @@ namespace Server.Network } } - public sealed class BondedStatus : Packet - { - public BondedStatus(Serial serial, bool bonded) : base(0xBF) - { - EnsureCapacity(11); - - Stream.Write((short)0x19); - Stream.Write((byte)0); - Stream.Write(serial); - Stream.Write((byte)(bonded ? 1 : 0)); - } - } - public sealed class MobileMoving : Packet { public MobileMoving(Mobile m, int noto) : base(0x77, 17) diff --git a/Projects/Server/Network/Packets/OutgoingCombatPackets.cs b/Projects/Server/Network/Packets/OutgoingCombatPackets.cs index 1e9578c8e..153034621 100644 --- a/Projects/Server/Network/Packets/OutgoingCombatPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingCombatPackets.cs @@ -32,7 +32,7 @@ namespace Server.Network writer.Write(attacker); writer.Write(defender); - ns.Send(ref buffer, 10); + ns.Send(ref buffer, writer.Position); } public static void SendSetWarMode(this NetState ns, bool warmode) @@ -47,7 +47,7 @@ namespace Server.Network // Warmode, 0x00, 0x32, 0x00 writer.Write(warmode ? 0x01003200 : 0x00003200); - ns.Send(ref buffer, 5); + ns.Send(ref buffer, writer.Position); } public static void SendChangeCombatant(this NetState ns, Serial combatant) @@ -61,7 +61,7 @@ namespace Server.Network writer.Write((byte)0xAA); // Packet ID writer.Write(combatant); - ns.Send(ref buffer, 5); + ns.Send(ref buffer, writer.Position); } } } diff --git a/Projects/Server/Network/Packets/OutgoingEffectPackets.cs b/Projects/Server/Network/Packets/OutgoingEffectPackets.cs new file mode 100644 index 000000000..e54554b78 --- /dev/null +++ b/Projects/Server/Network/Packets/OutgoingEffectPackets.cs @@ -0,0 +1,331 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: OutgoingEffectPackets.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Buffers; + +namespace Server.Network +{ + public static class OutgoingEffectPackets + { + public const int SoundPacketLength = 12; + public const int ParticleEffectLength = 49; + public const int HuedEffectLength = 36; + public const int BoltEffectLength = 36; + + public static void CreateSoundEffect(ref Span buffer, int soundID, IPoint3D target) + { + var writer = new SpanWriter(buffer); + writer.Write((byte)0x54); // Packet ID + writer.Write((byte)1); // flags + writer.Write((short)soundID); + writer.Write((short)0); // volume + writer.Write((short)target.X); + writer.Write((short)target.Y); + writer.Write((short)target.Z); + } + + public static void SendSoundEffect(this NetState ns, int soundID, IPoint3D target) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0x54); // Packet ID + writer.Write((byte)1); // flags + writer.Write((short)soundID); + writer.Write((short)0); // volume + writer.Write((short)target.X); + writer.Write((short)target.Y); + writer.Write((short)target.Z); + + ns.Send(ref buffer, writer.Position); + } + + public static void CreateParticleEffect( + ref Span buffer, + EffectType type, Serial from, Serial to, int itemID, IPoint3D fromPoint, IPoint3D toPoint, + int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode, int effect, + int explodeEffect, int explodeSound, Serial serial, int layer, int unknown + ) + { + var writer = new SpanWriter(buffer); + writer.Write((byte)0xC7); // Packet ID + writer.Write((byte)type); + writer.Write(from); + writer.Write(to); + writer.Write((short)itemID); + writer.Write((short)fromPoint.X); + writer.Write((short)fromPoint.Y); + writer.Write((sbyte)fromPoint.Z); + writer.Write((short)toPoint.X); + writer.Write((short)toPoint.Y); + writer.Write((sbyte)toPoint.Z); + writer.Write((byte)speed); + writer.Write((byte)duration); + writer.Write((byte)0); + writer.Write((byte)0); + writer.Write(fixedDirection); + writer.Write(explode); + writer.Write(hue); + writer.Write(renderMode); + writer.Write((short)effect); + writer.Write((short)explodeEffect); + writer.Write((short)explodeSound); + writer.Write(serial); + writer.Write((byte)layer); + writer.Write((short)unknown); + } + + public static void CreateTargetParticleEffect( + ref Span buffer, + IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int layer, int unknown + ) => CreateParticleEffect( + ref buffer, + EffectType.FixedFrom, + e.Serial, + Serial.Zero, + itemID, + e.Location, + e.Location, + speed, + duration, + true, + false, + hue, + renderMode, + effect, + 1, + 0, + e.Serial, + layer, + unknown + ); + + public static void CreateLocationParticleEffect( + ref Span buffer, + IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown + ) => CreateParticleEffect( + ref buffer, + EffectType.FixedXYZ, + e.Serial, + Serial.Zero, + itemID, + e.Location, + e.Location, + speed, + duration, + true, + false, + hue, + renderMode, + effect, + 1, + 0, + e.Serial, + 255, + unknown + ); + + public static void CreateMovingParticleEffect( + ref Span buffer, + IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, + bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, + int unknown + ) => CreateParticleEffect( + ref buffer, + EffectType.Moving, + from.Serial, + to.Serial, + itemID, + from.Location, + to.Location, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode, + effect, + explodeEffect, + explodeSound, + Serial.Zero, + (int)layer, + unknown + ); + + public static void CreateHuedEffect( + ref Span buffer, + EffectType type, Serial from, Serial to, int itemID, Point3D fromPoint, Point3D toPoint, + int speed, int duration, bool fixedDirection, bool explode, int hue, int renderMode + ) + { + var writer = new SpanWriter(buffer); + writer.Write((byte)0xC0); // Packet ID + writer.Write((byte)type); + writer.Write(from); + writer.Write(to); + writer.Write((short)itemID); + writer.Write((short)fromPoint.X); + writer.Write((short)fromPoint.Y); + writer.Write((sbyte)fromPoint.Z); + writer.Write((short)toPoint.X); + writer.Write((short)toPoint.Y); + writer.Write((sbyte)toPoint.Z); + writer.Write((byte)speed); + writer.Write((byte)duration); + writer.Write((byte)0); + writer.Write((byte)0); + writer.Write(fixedDirection); + writer.Write(explode); + writer.Write(hue); + writer.Write(renderMode); + } + + public static void CreateTargetHuedEffect( + ref Span buffer, + IEntity e, int itemID, int speed, int duration, int hue, int renderMode + ) => CreateHuedEffect( + ref buffer, + EffectType.FixedFrom, + e.Serial, + Serial.Zero, + itemID, + e.Location, + e.Location, + speed, + duration, + true, + false, + hue, + renderMode + ); + + public static void CreateLocationHuedEffect( + ref Span buffer, + Point3D p, int itemID, int speed, int duration, int hue, int renderMode + ) => CreateHuedEffect( + ref buffer, + EffectType.FixedXYZ, + Serial.Zero, + Serial.Zero, + itemID, + p, + p, + speed, + duration, + true, + false, + hue, + renderMode + ); + + public static void CreateMovingHuedEffect( + ref Span buffer, + IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, + bool explodes, int hue, int renderMode + ) => CreateHuedEffect( + ref buffer, + EffectType.Moving, + from.Serial, + to.Serial, + itemID, + from.Location, + to.Location, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + + public static void CreateMovingHuedEffect( + ref Span buffer, + int itemID, Point3D fromLocation, Point3D toLocation, int speed, int duration, + bool fixedDirection, bool explodes, int hue, int renderMode + ) => CreateHuedEffect( + ref buffer, + EffectType.Moving, + Serial.Zero, + Serial.Zero, + itemID, + fromLocation, + toLocation, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + + public static void CreateMovingHuedEffect( + ref Span buffer, + Serial from, Serial to, int itemID, Point3D fromLocation, Point3D toLocation, int speed, int duration, + bool fixedDirection, bool explodes, int hue, int renderMode + ) => CreateHuedEffect( + ref buffer, + EffectType.Moving, + from, + to, + itemID, + fromLocation, + toLocation, + speed, + duration, + fixedDirection, + explodes, + hue, + renderMode + ); + + public static void CreateBoltEffect(ref Span buffer, IEntity target, int hue) => CreateHuedEffect( + ref buffer, + EffectType.Lightning, + target.Serial, + Serial.Zero, + 0, + target.Location, + target.Location, + 0, + 0, + false, + false, + hue, + 0 + ); + + public static void SendScreenEffect(this NetState ns, ScreenEffectType type) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + + writer.Write((byte)0x70); // Packet ID + writer.Write((byte)0x4); + writer.Clear(8); + writer.Write((ushort)type); + writer.Clear(16); + + ns.Send(ref buffer, writer.Position); + } + } +} diff --git a/Projects/Server/Network/Packets/OutgoingMobilePackets.cs b/Projects/Server/Network/Packets/OutgoingMobilePackets.cs new file mode 100644 index 000000000..9056710a3 --- /dev/null +++ b/Projects/Server/Network/Packets/OutgoingMobilePackets.cs @@ -0,0 +1,54 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: OutgoingMobilePackets.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Buffers; + +namespace Server.Network +{ + public static class OutgoingMobilePackets + { + public const int BondedStatusPacketLength = 11; + + public static void CreateBondedStatus(ref Span buffer, Serial serial, bool bonded) + { + var writer = new SpanWriter(buffer); + writer.Write((byte)0xBF); // Packet ID + writer.Write((ushort)11); // Length + writer.Write((ushort)0x19); // Subpacket ID + writer.Write((byte)0); // Command + writer.Write(serial); + writer.Write(bonded); + } + + public static void SendBondedStatus(this NetState ns, Serial serial, bool bonded) + { + if (ns == null || !ns.GetSendBuffer(out var buffer)) + { + return; + } + + var writer = new CircularBufferWriter(buffer); + writer.Write((byte)0xBF); // Packet ID + writer.Write((ushort)11); // Length + writer.Write((ushort)0x19); // Subpacket ID + writer.Write((byte)0); // Command + writer.Write(serial); + writer.Write(bonded); + + ns.Send(ref buffer, writer.Position); + } + } +} diff --git a/Projects/Server/Network/Packets/PlayerPackets.cs b/Projects/Server/Network/Packets/PlayerPackets.cs index e81a95b47..8511ff5ef 100644 --- a/Projects/Server/Network/Packets/PlayerPackets.cs +++ b/Projects/Server/Network/Packets/PlayerPackets.cs @@ -14,6 +14,7 @@ *************************************************************************/ using System; +using Server.HuePickers; namespace Server.Network { @@ -305,19 +306,6 @@ namespace Server.Network } } - public sealed class PlaySound : Packet - { - public PlaySound(int soundID, IPoint3D target) : base(0x54, 12) - { - Stream.Write((byte)1); // flags - Stream.Write((short)soundID); - Stream.Write((short)0); // volume - Stream.Write((short)target.X); - Stream.Write((short)target.Y); - Stream.Write((short)target.Z); - } - } - public sealed class PlayMusic : Packet { public static readonly Packet InvalidInstance = SetStatic(new PlayMusic(MusicName.Invalid)); @@ -430,4 +418,14 @@ namespace Server.Network Stream.Write((short)0x21); } } + + public sealed class DisplayHuePicker : Packet + { + public DisplayHuePicker(HuePicker huePicker) : base(0x95, 9) + { + Stream.Write(huePicker.Serial); + Stream.Write((short)0); + Stream.Write((short)huePicker.ItemID); + } + } } diff --git a/Projects/UOContent/Commands/Generic/Commands/Commands.cs b/Projects/UOContent/Commands/Generic/Commands/Commands.cs index c8d3f6e3b..c03abb594 100644 --- a/Projects/UOContent/Commands/Generic/Commands/Commands.cs +++ b/Projects/UOContent/Commands/Generic/Commands/Commands.cs @@ -394,7 +394,7 @@ namespace Server.Commands.Generic index, CommandLogging.Format(mob) ); - mob.Send(new PlaySound(index, mob.Location)); + mob.SendSound(index); } else { diff --git a/Projects/UOContent/Commands/Handlers.cs b/Projects/UOContent/Commands/Handlers.cs index 085df0691..09b082ecf 100644 --- a/Projects/UOContent/Commands/Handlers.cs +++ b/Projects/UOContent/Commands/Handlers.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Text; using Server.Commands.Generic; @@ -420,19 +421,16 @@ namespace Server.Commands toAll ); - Packet p = new PlaySound(index, m.Location); - - p.Acquire(); + Span buffer = stackalloc byte[OutgoingEffectPackets.SoundPacketLength]; + OutgoingEffectPackets.CreateSoundEffect(ref buffer, index, m); foreach (var state in m.GetClientsInRange(12)) { if (toAll || state.Mobile.CanSee(m)) { - state.Send(p); + state.Send(buffer); } } - - p.Release(); } [Usage("Echo ")] diff --git a/Projects/UOContent/Context Menus/AddToSpellbookEntry.cs b/Projects/UOContent/Context Menus/AddToSpellbookEntry.cs index cb6622137..e6ce893cd 100644 --- a/Projects/UOContent/Context Menus/AddToSpellbookEntry.cs +++ b/Projects/UOContent/Context Menus/AddToSpellbookEntry.cs @@ -49,8 +49,7 @@ namespace Server.ContextMenus book.Content |= (ulong)1 << val; m_Scroll.Consume(); - - from.Send(new PlaySound(0x249, book.GetWorldLocation())); + from.SendSound(0x249, book.GetWorldLocation()); } } } diff --git a/Projects/UOContent/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs b/Projects/UOContent/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs index 72ef3e4b0..4dfc6edd2 100644 --- a/Projects/UOContent/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs +++ b/Projects/UOContent/Engines/Doom/LeverPuzzle/LeverPuzzleController.cs @@ -476,14 +476,14 @@ namespace Server.Engines.Doom } } - public static void PlayEffect(IEntity from, IEntity to, int itemid, int speed, bool explodes) + private static void PlayEffect(IEntity from, IEntity to, int itemid, int speed, bool explodes) { Effects.SendMovingParticles(from, to, itemid, speed, 0, true, explodes, 2, 0, 0); } - public static void SendLocationEffect(IPoint3D p, int itemID, int speed, int duration, int hue) + private static void SendLocationEffect(Point3D p, int itemID, int speed, int duration, int hue) { - Effects.SendPacket(p, Map.Malas, new LocationEffect(p, itemID, speed, duration, hue, 0)); + Effects.SendLocationEffect(p, Map.Malas, itemID, speed, duration, hue); } public static void PlayerSendASCII(Mobile player, int index) diff --git a/Projects/UOContent/Engines/Ethics/Evil/Powers/Blight.cs b/Projects/UOContent/Engines/Ethics/Evil/Powers/Blight.cs index 1050e74f3..0d3cfc296 100644 --- a/Projects/UOContent/Engines/Ethics/Evil/Powers/Blight.cs +++ b/Projects/UOContent/Engines/Ethics/Evil/Powers/Blight.cs @@ -68,7 +68,7 @@ namespace Server.Ethics.Evil { SpellHelper.Turn(from.Mobile, p); - Effects.PlaySound(p, from.Mobile.Map, 0x1FB); + Effects.PlaySound(new Point3D(p), from.Mobile.Map, 0x1FB); from.Mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You curse the area."); diff --git a/Projects/UOContent/Engines/Ethics/Hero/Powers/Bless.cs b/Projects/UOContent/Engines/Ethics/Hero/Powers/Bless.cs index 2ba2f04e7..2c341a2da 100644 --- a/Projects/UOContent/Engines/Ethics/Hero/Powers/Bless.cs +++ b/Projects/UOContent/Engines/Ethics/Hero/Powers/Bless.cs @@ -68,7 +68,7 @@ namespace Server.Ethics.Hero { SpellHelper.Turn(from.Mobile, p); - Effects.PlaySound(p, from.Mobile.Map, 0x299); + Effects.PlaySound(new Point3D(p), from.Mobile.Map, 0x299); from.Mobile.LocalOverheadMessage(MessageType.Regular, 0x3B2, false, "You consecrate the area."); diff --git a/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs b/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs index 00ca80e69..cf1828691 100644 --- a/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs +++ b/Projects/UOContent/Engines/Khaldun/PuzzleChest.cs @@ -330,7 +330,7 @@ namespace Server.Items { case 0: { - Effects.SendLocationEffect(to, to.Map, 0x113A, 20, 10); + Effects.SendLocationEffect(to, 0x113A, 20); to.PlaySound(0x231); to.LocalOverheadMessage(MessageType.Regular, 0x44, 1010523); // A toxic vapor envelops thee. @@ -340,7 +340,7 @@ namespace Server.Items } case 1: { - Effects.SendLocationEffect(to, to.Map, 0x3709, 30); + Effects.SendLocationEffect(to, 0x3709, 30); to.PlaySound(0x54); to.LocalOverheadMessage(MessageType.Regular, 0xEE, 1010524); // Searing heat scorches thy skin. diff --git a/Projects/UOContent/Engines/Quests/Dark Tides/Items/KronusScroll.cs b/Projects/UOContent/Engines/Quests/Dark Tides/Items/KronusScroll.cs index d4e347168..2b1f48727 100644 --- a/Projects/UOContent/Engines/Quests/Dark Tides/Items/KronusScroll.cs +++ b/Projects/UOContent/Engines/Quests/Dark Tides/Items/KronusScroll.cs @@ -157,24 +157,7 @@ namespace Server.Engines.Quests.Necro var hue = Utility.RandomList(0x481, 0x482, 0x489, 0x497, 0x66D); - Effects.SendPacket( - from, - map, - new HuedEffect( - EffectType.Moving, - Serial.Zero, - Serial.Zero, - 0x36D4, - from, - to, - 0, - 0, - false, - true, - hue, - 0 - ) - ); + Effects.SendMovingEffect(map, 0x36D4, from, to,0, 0, false, true, hue); } } diff --git a/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs b/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs index cd2798209..1efe69742 100644 --- a/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs +++ b/Projects/UOContent/Engines/Quests/Uzeraan Turmoil/Items/Cannon.cs @@ -66,7 +66,7 @@ namespace Server.Engines.Quests.Haven public override bool HandlesOnMovement => Canoneer?.Deleted == false && Canoneer.Active; - public void DoFireEffect(IPoint3D target) + public void DoFireEffect(Point3D target) { var from = CannonDirection switch { @@ -85,7 +85,7 @@ namespace Server.Engines.Quests.Haven public void Fire(Mobile from, Mobile target) { - DoFireEffect(target); + DoFireEffect(target.Location); target.Damage(9999, from); } diff --git a/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs b/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs index 2b0692c1b..36774a493 100644 --- a/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs +++ b/Projects/UOContent/Items/Construction/Doors/BaseDoor.cs @@ -67,7 +67,7 @@ namespace Server.Items Location = new Point3D(X - Offset.X, Y - Offset.Y, Z - Offset.Z); } - Effects.PlaySound(this, Map, m_Open ? OpenedSound : ClosedSound); + Effects.PlaySound(this, m_Open ? OpenedSound : ClosedSound); if (m_Open) { diff --git a/Projects/UOContent/Items/Games/BaseBoard.cs b/Projects/UOContent/Items/Games/BaseBoard.cs index 8f2df16be..384eccffb 100644 --- a/Projects/UOContent/Items/Games/BaseBoard.cs +++ b/Projects/UOContent/Items/Games/BaseBoard.cs @@ -81,24 +81,21 @@ namespace Server.Items { if (dropped is BasePiece piece && piece.Board == this && base.OnDragDropInto(from, dropped, point)) { - Packet p = new PlaySound(0x127, GetWorldLocation()); - - p.Acquire(); - if (RootParent == from) { - from.Send(p); + from.SendSound(0x127, GetWorldLocation()); } else { + Span buffer = stackalloc byte[OutgoingEffectPackets.SoundPacketLength]; + OutgoingEffectPackets.CreateSoundEffect(ref buffer, 0x127, GetWorldLocation()); + foreach (var state in GetClientsInRange(2)) { - state.Send(p); + state.Send(buffer); } } - p.Release(); - return true; } diff --git a/Projects/UOContent/Items/Maps/TreasureMap.cs b/Projects/UOContent/Items/Maps/TreasureMap.cs index 10ec0ed30..dd7170e4e 100644 --- a/Projects/UOContent/Items/Maps/TreasureMap.cs +++ b/Projects/UOContent/Items/Maps/TreasureMap.cs @@ -886,7 +886,7 @@ namespace Server.Items m_Chest.Z++; } - Effects.PlaySound(m_Chest, m_Map, 0x33B); + Effects.PlaySound(m_Chest.Location, m_Map, 0x33B); } if (m_Chest?.Location.Z >= m_Location.Z) diff --git a/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs b/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs index 7f46db2aa..b083d3940 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Misc/Moongate.cs @@ -180,7 +180,7 @@ namespace Server.Items { if (from.AccessLevel == AccessLevel.Player || !from.Hidden) { - from.Send(new PlaySound(0x20E, from.Location)); + from.SendSound(0x20E, from); } from.CloseGump(); diff --git a/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs b/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs index 1d518b42a..249e815e1 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Runebook.cs @@ -414,7 +414,7 @@ namespace Server.Items rune.Delete(); - from.Send(new PlaySound(0x42, GetWorldLocation())); + from.SendSound(0x42, GetWorldLocation()); from.SendMessage((rune.Description?.Trim()).DefaultIfNullOrEmpty("(indescript)")); @@ -432,7 +432,7 @@ namespace Server.Items { if (CurCharges < MaxCharges) { - from.Send(new PlaySound(0x249, GetWorldLocation())); + from.SendSound(0x249, GetWorldLocation()); var amount = dropped.Amount; diff --git a/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs b/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs index 2fb4e1233..e88f4f7fb 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Spellbook.cs @@ -591,7 +591,7 @@ namespace Server.Items scroll.Delete(); - from.Send(new PlaySound(0x249, GetWorldLocation())); + from.SendSound(0x249, GetWorldLocation()); return true; } } diff --git a/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs b/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs index cf438082f..38692b80a 100644 --- a/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs +++ b/Projects/UOContent/Items/Skill Items/Misc/FireHorn.cs @@ -58,7 +58,7 @@ namespace Server.Items } } - public void Use(Mobile from, IPoint3D loc) + public void Use(Mobile from, Point3D loc) { if (!CheckUse(from)) { @@ -84,23 +84,14 @@ namespace Server.Items from.Backpack.ConsumeUpTo(typeof(SulfurousAsh), sulfAsh); from.PlaySound(0x15F); - Effects.SendPacket( + Effects.SendMovingEffect( from, - from.Map, - new HuedEffect( - EffectType.Moving, - from.Serial, - Serial.Zero, - 0x36D4, - from.Location, - loc, - 5, - 0, - false, - true, - 0, - 0 - ) + loc, + 0x36D4, + 5, + 0, + false, + true ); var eable = from.Map.GetMobilesInRange(new Point3D(loc), 2); @@ -241,14 +232,14 @@ namespace Server.Items return; } - IPoint3D loc; + Point3D loc; if (targeted is Item item) { loc = item.GetWorldLocation(); } else { - loc = targeted as IPoint3D; + loc = new Point3D(targeted as IPoint3D); } m_Horn.Use(from, loc); diff --git a/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs b/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs index a2d0becdf..d89063b0a 100644 --- a/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs +++ b/Projects/UOContent/Items/Special/Veteran Rewards/Cannon.cs @@ -214,11 +214,11 @@ namespace Server.Items } } - public void DoFireEffect(IPoint3D target) + public void DoFireEffect(Point3D target) { var map = Map; - if (target == null || map == null) + if (map == null) { return; } @@ -228,7 +228,7 @@ namespace Server.Items for (var count = Utility.Random(3); count > 0; count--) { - IPoint3D location = new Point3D( + Point3D location = new Point3D( target.X + Utility.RandomMinMax(-1, 1), target.Y + Utility.RandomMinMax(-1, 1), target.Z @@ -320,9 +320,11 @@ namespace Server.Items break; } - if (allow && Utility.InRange(new Point3D(p), m_Cannon.Location, 14)) + var loc = new Point3D(p); + + if (allow && Utility.InRange(loc, m_Cannon.Location, 14)) { - m_Cannon.DoFireEffect(p); + m_Cannon.DoFireEffect(loc); } else { diff --git a/Projects/UOContent/Items/Talismans/BaseTalisman.cs b/Projects/UOContent/Items/Talismans/BaseTalisman.cs index 74aeef2ac..ef6c3508c 100644 --- a/Projects/UOContent/Items/Talismans/BaseTalisman.cs +++ b/Projects/UOContent/Items/Talismans/BaseTalisman.cs @@ -408,7 +408,7 @@ namespace Server.Items 20, 5042 ); - Effects.PlaySound(m_Creature, m_Creature.Map, 0x201); + Effects.PlaySound(m_Creature, 0x201); m_Creature.Delete(); } diff --git a/Projects/UOContent/Items/Talismans/TalismanSummons.cs b/Projects/UOContent/Items/Talismans/TalismanSummons.cs index 7a73e5421..8c79873f1 100644 --- a/Projects/UOContent/Items/Talismans/TalismanSummons.cs +++ b/Projects/UOContent/Items/Talismans/TalismanSummons.cs @@ -58,7 +58,8 @@ namespace Server.Mobiles 20, 5042 ); - Effects.PlaySound(m_Mobile, m_Mobile.Map, 0x201); + + Effects.PlaySound(m_Mobile,0x201); m_Mobile.Delete(); } @@ -405,13 +406,13 @@ namespace Server.Mobiles /* // An area attack that only damages staff, wtf? - + private DateTime m_NextWave; - + public void AreaHeatDamage() { Mobile mob = ControlMaster; - + if (mob != null) { if (mob.InRange( Location, 2 )) @@ -422,9 +423,9 @@ namespace Server.Mobiles mob.SendLocalizedMessage( 1008112 ); // The intense heat is damaging you! } } - + GuardedRegion r = Region as GuardedRegion; - + if (r != null && mob.Alive) { foreach ( Mobile m in GetMobilesInRange( 2 ) ) @@ -434,7 +435,7 @@ namespace Server.Mobiles } } } - + m_NextWave = DateTime.UtcNow + TimeSpan.FromSeconds( 3 ); } */ diff --git a/Projects/UOContent/Items/Weapons/BaseWeapon.cs b/Projects/UOContent/Items/Weapons/BaseWeapon.cs index 3143d988e..e78b812cd 100644 --- a/Projects/UOContent/Items/Weapons/BaseWeapon.cs +++ b/Projects/UOContent/Items/Weapons/BaseWeapon.cs @@ -3550,7 +3550,7 @@ namespace Server.Items 20, 5042 ); - Effects.PlaySound(defender, defender.Map, 0x201); + Effects.PlaySound(defender, 0x201); defender.Delete(); } diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index 1e8a9e2a4..65ac2f7da 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -2278,7 +2278,7 @@ namespace Server.Mobiles 20, 5042 ); - Effects.PlaySound(m, m.Map, 0x201); + Effects.PlaySound(m, 0x201); m.Delete(); } @@ -3216,12 +3216,7 @@ namespace Server.Mobiles if (IsBonded) { - var sound = GetDeathSound(); - - if (sound >= 0) - { - Effects.PlaySound(this, Map, sound); - } + Effects.PlaySound(this, GetDeathSound()); Warmode = false; @@ -3845,7 +3840,9 @@ namespace Server.Mobiles IsDeadPet = false; - Effects.SendPacket(Location, Map, new BondedStatus(Serial, false)); + Span buffer = stackalloc byte[OutgoingMobilePackets.BondedStatusPacketLength]; + OutgoingMobilePackets.CreateBondedStatus(ref buffer, Serial, false); + Effects.SendPacket(Location, Map, ref buffer); SendIncomingPacket(); SendIncomingPacket(); diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs index a2fb42e8d..1b35f0f50 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunSummoner.cs @@ -103,8 +103,8 @@ namespace Server.Mobiles LootPack.FilthyRich.Generate(this, rm.Backpack, false, LootPack.GetLuckChanceForKiller(this)); } - Effects.PlaySound(this, Map, GetDeathSound()); - Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); + Effects.PlaySound(this, GetDeathSound()); + Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835); rm.MoveToWorld(Location, Map); Delete(); diff --git a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs index ebbc1456e..1828bd9aa 100644 --- a/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs +++ b/Projects/UOContent/Mobiles/Monsters/Humanoid/Melee/KhaldunZealot.cs @@ -112,7 +112,7 @@ namespace Server.Mobiles LootPack.FilthyRich.Generate(this, rm.Backpack, false, LootPack.GetLuckChanceForKiller(this)); } - Effects.PlaySound(this, Map, GetDeathSound()); + Effects.PlaySound(this, GetDeathSound()); Effects.SendLocationEffect(Location, Map, 0x3709, 30, 10, 0x835, 0); rm.MoveToWorld(Location, Map); diff --git a/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs b/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs index bb59e2a2a..52c74d09d 100644 --- a/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs +++ b/Projects/UOContent/Mobiles/Monsters/SE/FanDancer.cs @@ -78,68 +78,42 @@ namespace Server.Mobiles * Effect: damage is dealt to the attacker, no damage is taken by the fan dancer */ + private void ThrowFan(Mobile to) + { + if (!(Utility.RandomDouble() < 0.8) || to.InRange(this, 1)) + { + return; + } + + /* Fan Throw + * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" + * Damage: 50-65 + */ + Effects.SendMovingEffect( + to.Location, + to.Map, + 0x27A3, + Location, + to.Location, + 10, + 0, + false, + false + ); + + AOS.Damage(to, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); + } + public override void OnDamagedBySpell(Mobile attacker) { base.OnDamagedBySpell(attacker); - - if (Utility.RandomDouble() < 0.8 && !attacker.InRange(this, 1)) - { - /* Fan Throw - * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" - * Damage: 50-65 - */ - Effects.SendPacket( - attacker, - attacker.Map, - new HuedEffect( - EffectType.Moving, - Serial.Zero, - Serial.Zero, - 0x27A3, - Location, - attacker.Location, - 10, - 0, - false, - false, - 0, - 0 - ) - ); - AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); - } + ThrowFan(attacker); } public override void OnGotMeleeAttack(Mobile attacker) { base.OnGotMeleeAttack(attacker); - - if (Utility.RandomDouble() < 0.8 && !attacker.InRange(this, 1)) - { - /* Fan Throw - * Effect: - To: "0x57D4F5B" - ItemId: "0x27A3" - ItemIdName: "Tessen" - FromLocation: "(992 299, 24)" - ToLocation: "(992 308, 22)" - Speed: "10" - Duration: "0" - FixedDirection: "False" - Explode: "False" - Hue: "0x0" - Render: "0x0" - * Damage: 50-65 - */ - Effects.SendPacket( - attacker, - attacker.Map, - new HuedEffect( - EffectType.Moving, - Serial.Zero, - Serial.Zero, - 0x27A3, - Location, - attacker.Location, - 10, - 0, - false, - false, - 0, - 0 - ) - ); - AOS.Damage(attacker, this, Utility.RandomMinMax(50, 65), 100, 0, 0, 0, 0); - } + ThrowFan(attacker); } public override void OnGaveMeleeAttack(Mobile defender) @@ -158,9 +132,8 @@ namespace Server.Mobiles * Effect does not stack */ - defender.SendLocalizedMessage( - 1070833 - ); // The creature fans you with fire, reducing your resistance to fire attacks. + // The creature fans you with fire, reducing your resistance to fire attacks. + defender.SendLocalizedMessage(1070833); var effect = -(defender.FireResistance / 10); diff --git a/Projects/UOContent/Mobiles/Special/BaseChampion.cs b/Projects/UOContent/Mobiles/Special/BaseChampion.cs index 995ecb053..b387c7eff 100644 --- a/Projects/UOContent/Mobiles/Special/BaseChampion.cs +++ b/Projects/UOContent/Mobiles/Special/BaseChampion.cs @@ -355,7 +355,7 @@ namespace Server.Mobiles 30, 5052 ); - Effects.PlaySound(g, g.Map, 0x208); + Effects.PlaySound(g, 0x208); break; } @@ -368,7 +368,7 @@ namespace Server.Mobiles 10, 5044 ); - Effects.PlaySound(g, g.Map, 0x307); + Effects.PlaySound(g, 0x307); break; } diff --git a/Projects/UOContent/Mobiles/Special/Harrower.cs b/Projects/UOContent/Mobiles/Special/Harrower.cs index c1fef026e..b4611eeef 100644 --- a/Projects/UOContent/Mobiles/Special/Harrower.cs +++ b/Projects/UOContent/Mobiles/Special/Harrower.cs @@ -687,7 +687,7 @@ namespace Server.Mobiles 30, 5052 ); - Effects.PlaySound(g, g.Map, 0x208); + Effects.PlaySound(g, 0x208); break; } @@ -700,7 +700,7 @@ namespace Server.Mobiles 10, 5044 ); - Effects.PlaySound(g, g.Map, 0x307); + Effects.PlaySound(g, 0x307); break; } diff --git a/Projects/UOContent/Spells/Chivalry/DispelEvil.cs b/Projects/UOContent/Spells/Chivalry/DispelEvil.cs index 0f3d8f1a4..556e668d2 100644 --- a/Projects/UOContent/Spells/Chivalry/DispelEvil.cs +++ b/Projects/UOContent/Spells/Chivalry/DispelEvil.cs @@ -67,7 +67,7 @@ namespace Server.Spells.Chivalry 20, 5042 ); - Effects.PlaySound(m, m.Map, 0x201); + Effects.PlaySound(m, 0x201); m.Delete(); continue; diff --git a/Projects/UOContent/Spells/Fifth/PoisonField.cs b/Projects/UOContent/Spells/Fifth/PoisonField.cs index 0abbd4c55..3cbd6c577 100644 --- a/Projects/UOContent/Spells/Fifth/PoisonField.cs +++ b/Projects/UOContent/Spells/Fifth/PoisonField.cs @@ -62,7 +62,7 @@ namespace Server.Spells.Fifth eastToWest = false; } - Effects.PlaySound(p, Caster.Map, 0x20B); + Effects.PlaySound(new Point3D(p), Caster.Map, 0x20B); var itemID = eastToWest ? 0x3915 : 0x3922; diff --git a/Projects/UOContent/Spells/Fourth/ArchCure.cs b/Projects/UOContent/Spells/Fourth/ArchCure.cs index 98d7b5e07..135c55904 100644 --- a/Projects/UOContent/Spells/Fourth/ArchCure.cs +++ b/Projects/UOContent/Spells/Fourth/ArchCure.cs @@ -43,6 +43,7 @@ namespace Server.Spells.Fourth var map = Caster.Map; var directTarget = p as Mobile; + var loc = new Point3D(p); if (map != null) { @@ -54,13 +55,13 @@ namespace Server.Spells.Fourth targets.Add(directTarget); } - var eable = map.GetMobilesInRange(new Point3D(p), 2); + var eable = map.GetMobilesInRange(loc, 2); targets.AddRange(eable.Where(m => m != directTarget).Where(m => AreaCanTarget(m, feluccaRules))); eable.Free(); } - Effects.PlaySound(p, Caster.Map, 0x299); + Effects.PlaySound(loc, Caster.Map, 0x299); if (targets.Count > 0) { diff --git a/Projects/UOContent/Spells/Fourth/ArchProtection.cs b/Projects/UOContent/Spells/Fourth/ArchProtection.cs index 9040cc025..3f313d93d 100644 --- a/Projects/UOContent/Spells/Fourth/ArchProtection.cs +++ b/Projects/UOContent/Spells/Fourth/ArchProtection.cs @@ -40,9 +40,11 @@ namespace Server.Spells.Fourth SpellHelper.GetSurfaceTop(ref p); + var loc = new Point3D(p); + if (!Core.AOS) { - Effects.PlaySound(p, Caster.Map, 0x299); + Effects.PlaySound(loc, Caster.Map, 0x299); } if (Caster.Map == null) @@ -51,7 +53,7 @@ namespace Server.Spells.Fourth return; } - var targets = Caster.Map.GetMobilesInRange(new Point3D(p), Core.AOS ? 2 : 3) + var targets = Caster.Map.GetMobilesInRange(loc, Core.AOS ? 2 : 3) .Where(m => Caster.CanBeBeneficial(m, false)); if (Core.AOS) diff --git a/Projects/UOContent/Spells/Fourth/FireField.cs b/Projects/UOContent/Spells/Fourth/FireField.cs index 3959e2f24..c4eaf37c4 100644 --- a/Projects/UOContent/Spells/Fourth/FireField.cs +++ b/Projects/UOContent/Spells/Fourth/FireField.cs @@ -62,7 +62,7 @@ namespace Server.Spells.Fourth eastToWest = false; } - Effects.PlaySound(p, Caster.Map, 0x20C); + Effects.PlaySound(new Point3D(p), Caster.Map, 0x20C); var itemID = eastToWest ? 0x398C : 0x3996; diff --git a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs index b0689c689..333421217 100644 --- a/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/HailStormSpell.cs @@ -51,9 +51,11 @@ namespace Server.Spells.Mysticism if (map != null) { - PlayEffect(p, Caster.Map); + var loc = new Point3D(p); - foreach (var m in map.GetMobilesInRange(new Point3D(p), 2)) + PlayEffect(loc, Caster.Map); + + foreach (var m in map.GetMobilesInRange(loc, 2)) { if (m == Caster) { @@ -94,7 +96,7 @@ namespace Server.Spells.Mysticism Caster.Target = new SpellTargetPoint3D(this); } - private static void PlayEffect(IPoint3D p, Map map) + private static void PlayEffect(Point3D p, Map map) { Effects.PlaySound(p, map, 0x64F); @@ -105,7 +107,7 @@ namespace Server.Spells.Mysticism PlaySingleEffect(p, map, -1, 1, 1, 3); } - private static void PlaySingleEffect(IPoint3D p, Map map, int a, int b, int c, int d) + private static void PlaySingleEffect(Point3D p, Map map, int a, int b, int c, int d) { int x = p.X, y = p.Y, z = p.Z + 18; @@ -120,25 +122,20 @@ namespace Server.Spells.Mysticism SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + d, z)); } - private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) + private static void SendEffectPacket(Point3D p, Map map, Point3D orig, Point3D dest) { - Effects.SendPacket( + Effects.SendMovingEffect( p, map, - new HuedEffect( - EffectType.Moving, - Serial.Zero, - Serial.Zero, - 0x36D4, - orig, - dest, - 0, - 0, - false, - false, - 0x63, - 0x4 - ) + 0x36D4, + orig, + dest, + 0, + 0, + false, + false, + 0x63, + 0x4 ); } } diff --git a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs index fc7197e06..a73d6d39e 100644 --- a/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/NetherCycloneSpell.cs @@ -54,9 +54,11 @@ namespace Server.Spells.Mysticism if (map != null) { - PlayEffect(p, Caster.Map); + var loc = new Point3D(p); - foreach (var m in map.GetMobilesInRange(new Point3D(p), 2)) + PlayEffect(loc, Caster.Map); + + foreach (var m in map.GetMobilesInRange(loc, 2)) { if (m == Caster) { @@ -103,7 +105,7 @@ namespace Server.Spells.Mysticism Caster.Target = new SpellTargetPoint3D(this); } - private static void PlayEffect(IPoint3D p, Map map) + private static void PlayEffect(Point3D p, Map map) { Effects.PlaySound(p, map, 0x64F); @@ -114,7 +116,7 @@ namespace Server.Spells.Mysticism PlaySingleEffect(p, map, -1, 1, 1, 3); } - private static void PlaySingleEffect(IPoint3D p, Map map, int a, int b, int c, int d) + private static void PlaySingleEffect(Point3D p, Map map, int a, int b, int c, int d) { int x = p.X, y = p.Y, z = p.Z + 18; @@ -129,25 +131,20 @@ namespace Server.Spells.Mysticism SendEffectPacket(p, map, new Point3D(x + a, y + c, z), new Point3D(x + a, y + d, z)); } - private static void SendEffectPacket(IPoint3D p, Map map, Point3D orig, Point3D dest) + private static void SendEffectPacket(Point3D p, Map map, Point3D orig, Point3D dest) { - Effects.SendPacket( + Effects.SendMovingEffect( p, map, - new HuedEffect( - EffectType.Moving, - Serial.Zero, - Serial.Zero, - 0x375A, - orig, - dest, - 0, - 0, - false, - false, - 0x49A, - 0x4 - ) + 0x375A, + orig, + dest, + 0, + 0, + false, + false, + 0x49A, + 0x4 ); } } diff --git a/Projects/UOContent/Spells/Seventh/EnergyField.cs b/Projects/UOContent/Spells/Seventh/EnergyField.cs index 0ac5220a2..c81f0643f 100644 --- a/Projects/UOContent/Spells/Seventh/EnergyField.cs +++ b/Projects/UOContent/Spells/Seventh/EnergyField.cs @@ -62,7 +62,7 @@ namespace Server.Spells.Seventh eastToWest = false; } - Effects.PlaySound(p, Caster.Map, 0x20B); + Effects.PlaySound(new Point3D(p), Caster.Map, 0x20B); TimeSpan duration; diff --git a/Projects/UOContent/Spells/Seventh/MassDispel.cs b/Projects/UOContent/Spells/Seventh/MassDispel.cs index 532d4d656..0702fce41 100644 --- a/Projects/UOContent/Spells/Seventh/MassDispel.cs +++ b/Projects/UOContent/Spells/Seventh/MassDispel.cs @@ -60,7 +60,7 @@ namespace Server.Spells.Seventh 20, 5042 ); - Effects.PlaySound(bc, bc.Map, 0x201); + Effects.PlaySound(bc, 0x201); bc.Delete(); } diff --git a/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs b/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs index 81e9831ad..b1a492d01 100644 --- a/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs +++ b/Projects/UOContent/Spells/Seventh/MeteorSwarm.cs @@ -46,10 +46,11 @@ namespace Server.Spells.Seventh var map = Caster.Map; var playerVsPlayer = false; + var loc = new Point3D(p); if (map != null) { - var eable = map.GetMobilesInRange(new Point3D(p), 2); + var eable = map.GetMobilesInRange(loc, 2); targets = eable.Where( m => @@ -86,7 +87,7 @@ namespace Server.Spells.Seventh if (targets.Count > 0) { - Effects.PlaySound(p, Caster.Map, 0x160); + Effects.PlaySound(loc, Caster.Map, 0x160); if (Core.AOS && targets.Count > 2) { diff --git a/Projects/UOContent/Spells/Sixth/Dispel.cs b/Projects/UOContent/Spells/Sixth/Dispel.cs index 1cc8e12e7..89386d1d4 100644 --- a/Projects/UOContent/Spells/Sixth/Dispel.cs +++ b/Projects/UOContent/Spells/Sixth/Dispel.cs @@ -53,7 +53,7 @@ namespace Server.Spells.Sixth 20, 5042 ); - Effects.PlaySound(m, m.Map, 0x201); + Effects.PlaySound(m, 0x201); m.Delete(); } diff --git a/Projects/UOContent/Spells/Sixth/Mark.cs b/Projects/UOContent/Spells/Sixth/Mark.cs index a0f8ad40c..c36a205f2 100644 --- a/Projects/UOContent/Spells/Sixth/Mark.cs +++ b/Projects/UOContent/Spells/Sixth/Mark.cs @@ -63,7 +63,7 @@ namespace Server.Spells.Sixth rune.Mark(Caster); Caster.PlaySound(0x1FA); - Effects.SendLocationEffect(Caster, Caster.Map, 14201, 16); + Effects.SendLocationEffect(Caster, 14201, 16); } FinishSequence(); diff --git a/Projects/UOContent/Spells/Sixth/ParalyzeField.cs b/Projects/UOContent/Spells/Sixth/ParalyzeField.cs index 20de8418d..21d259b07 100644 --- a/Projects/UOContent/Spells/Sixth/ParalyzeField.cs +++ b/Projects/UOContent/Spells/Sixth/ParalyzeField.cs @@ -61,7 +61,7 @@ namespace Server.Spells.Sixth eastToWest = false; } - Effects.PlaySound(p, Caster.Map, 0x20B); + Effects.PlaySound(new Point3D(p), Caster.Map, 0x20B); var itemID = eastToWest ? 0x3967 : 0x3979; diff --git a/Projects/UOContent/Spells/Third/Unlock.cs b/Projects/UOContent/Spells/Third/Unlock.cs index 91e4a27a6..8f3e94b25 100644 --- a/Projects/UOContent/Spells/Third/Unlock.cs +++ b/Projects/UOContent/Spells/Third/Unlock.cs @@ -27,16 +27,17 @@ namespace Server.Spells.Third if (CheckSequence()) { SpellHelper.Turn(Caster, p); + var loc = new Point3D(p); Effects.SendLocationParticles( - EffectItem.Create(new Point3D(p), Caster.Map, EffectItem.DefaultDuration), + EffectItem.Create(loc, Caster.Map, EffectItem.DefaultDuration), 0x376A, 9, 32, 5024 ); - Effects.PlaySound(p, Caster.Map, 0x1FF); + Effects.PlaySound(loc, Caster.Map, 0x1FF); if (p is Mobile) { diff --git a/Projects/UOContent/Spells/Third/WallOfStone.cs b/Projects/UOContent/Spells/Third/WallOfStone.cs index ecbe773c1..fc64f78dd 100644 --- a/Projects/UOContent/Spells/Third/WallOfStone.cs +++ b/Projects/UOContent/Spells/Third/WallOfStone.cs @@ -59,7 +59,7 @@ namespace Server.Spells.Third eastToWest = false; } - Effects.PlaySound(p, Caster.Map, 0x1F6); + Effects.PlaySound(new Point3D(p), Caster.Map, 0x1F6); for (var i = -1; i <= 1; ++i) {