Skip to content

Commit

Permalink
fix: Fixes spawner timer deserialization, decimal deserialization, an…
Browse files Browse the repository at this point in the history
…d adds potion keg reverse lookup (#1711)

### Summary
* Fixes spawner timer deserialization
* Adds a check for a null timer and allows the timer to get recreated
* Adds PotionKeg reverse lookup
* Heavily optimizes decimal serialize/deserialize
  • Loading branch information
kamronbatman committed Mar 28, 2024
1 parent 70575e1 commit 1a7e7c7
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Buffers.Binary;
using System.Runtime.InteropServices;
using Xunit;

namespace Server.Tests;

public class DecimalSerializationTests
{
private static void Write(byte[] buffer, decimal value)
{
Span<int> bytes = stackalloc int[sizeof(decimal) / 4];
decimal.GetBits(value, bytes);

MemoryMarshal.Cast<int, byte>(bytes).CopyTo(buffer.AsSpan());
}

private static int ReadInt(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadInt32LittleEndian(buffer);

private static decimal ReadDecimal(ReadOnlySpan<byte> buffer) => new(stackalloc int[4] { ReadInt(buffer), ReadInt(buffer[4..]), ReadInt(buffer[8..]), ReadInt(buffer[12..]) });

public static TheoryData<decimal> Data =>
new()
{
123.46m,
0.0256m,
10000m,
2m,
0.0001m,
0.0000000000000000000000000001m
};

[Theory]
[MemberData(nameof(Data))]
public void TestSerializeDecimal(decimal value)
{
// Arrange
byte[] buffer = new byte[sizeof(decimal)];

// Act
Write(buffer, value);

// Assert
Assert.Equal(value, ReadDecimal(buffer));
}
}
25 changes: 12 additions & 13 deletions Projects/Server.Tests/Tests/Serialization/EnumConversionTests.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using System;
using Xunit;

namespace Server.Tests
namespace Server.Tests;

public class EnumConversionTests
{
public class EnumConversionTests
[Fact]
public void TestToEnum()
{
[Fact]
public void TestToEnum()
{
var e = ReadEnum<TileFlag>();
var e = ReadEnum<TileFlag>();

Assert.Equal(TileFlag.Container, e);
}
Assert.Equal(TileFlag.Container, e);
}

private unsafe T ReadEnum<T>() where T : unmanaged, Enum
{
var num = (long)TileFlag.Container;
return *(T*)&num;
}
private static unsafe T ReadEnum<T>() where T : unmanaged, Enum
{
var num = (long)TileFlag.Container;
return *(T*)&num;
}
}
1 change: 0 additions & 1 deletion Projects/Server/AssemblyHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;
using Server.Logging;

namespace Server;

Expand Down
10 changes: 10 additions & 0 deletions Projects/Server/Serialization/BufferWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using Server.Text;

Expand Down Expand Up @@ -290,6 +291,15 @@ public void Write(Type type)
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Write(decimal value)
{
Span<int> buffer = stackalloc int[sizeof(decimal) / 4];
decimal.GetBits(value, buffer);

Write(MemoryMarshal.Cast<int, byte>(buffer));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void InternalWriteString(string value)
{
Expand Down
11 changes: 2 additions & 9 deletions Projects/Server/Serialization/IGenericWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public interface IGenericWriter
void Write(bool value);
void Write(Serial serial);
void Write(Type type);
void Write(decimal value);

void Write(DateTime value)
{
Expand Down Expand Up @@ -79,20 +80,12 @@ void Write(IPAddress value)
Write((byte)bytesWritten);
Write(stack[..bytesWritten]);
}

void Write(TimeSpan value)
{
Write(value.Ticks);
}

public void Write(decimal value)
{
var bits = decimal.GetBits(value);

for (var i = 0; i < 4; ++i)
{
Write(bits[i]);
}
}
void WriteEncodedInt(int value)
{
var v = (uint)value;
Expand Down
36 changes: 20 additions & 16 deletions Projects/UOContent/Engines/Spawners/BaseSpawner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,11 @@ public TimeSpan NextSpawn
get => _running && _timer?.Running == true ? End - Core.Now : TimeSpan.Zero;
set
{
Start();
DoTimer(value);
if (!_running && Entries.Count > 0)
{
_running = true;
DoTimer(value);
}
}
}

Expand All @@ -219,7 +222,7 @@ public void Remove(ISpawnable spawn)
entry?.RemoveFromSpawned(spawn);
}

if (_running && !IsFull && _timer?.Running == false)
if (_running && !IsFull && _timer?.Running != true)
{
DoTimer();
}
Expand Down Expand Up @@ -377,13 +380,10 @@ public override void OnSingleClick(Mobile from)

public void Start()
{
if (!_running)
if (!_running && Entries.Count > 0)
{
if (Entries.Count > 0)
{
_running = true;
DoTimer();
}
_running = true;
DoTimer();
}
}

Expand Down Expand Up @@ -757,7 +757,14 @@ public virtual void DoTimer(TimeSpan delay)
return;
}

End = Core.Now + delay;
if (delay <= TimeSpan.Zero)
{
End = Core.Now;
}
else
{
End = Core.Now + delay;
}

if (_timer == null)
{
Expand Down Expand Up @@ -795,7 +802,7 @@ public void RemoveEntry(SpawnerEntry entry)

Entries.Remove(entry);

if (_running && !IsFull && _timer?.Running == false)
if (_running && !IsFull && _timer?.Running != true)
{
DoTimer();
}
Expand Down Expand Up @@ -847,7 +854,7 @@ public void RemoveSpawns()
}
}

if (_running && !IsFull && _timer?.Running == false)
if (_running && !IsFull && _timer?.Running != true)
{
DoTimer();
}
Expand Down Expand Up @@ -912,10 +919,7 @@ private void AfterDeserialization()
}
}

if (_running && _end > Core.Now)
{
DoTimer(_end - Core.Now);
}
DoTimer(_end - Core.Now);
}

private class InternalTimer : Timer
Expand Down
46 changes: 36 additions & 10 deletions Projects/UOContent/Items/Skill Items/Magical/Misc/PotionKeg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ public static void Initialize()
TileData.ItemTable[0x1940].Height = 4;
}

[InvalidateProperties]
[SerializableField(0)]
[SerializedCommandProperty(AccessLevel.GameMaster)]
[InvalidateProperties] [SerializableField(0)] [SerializedCommandProperty(AccessLevel.GameMaster)]
private PotionEffect _type;

[Constructible]
Expand Down Expand Up @@ -115,7 +113,7 @@ public override void OnDoubleClick(Mobile from)
{
from.SendLocalizedMessage(502242); // You pour some of the keg's contents into an empty bottle...

var pot = FillBottle();
var pot = FillBottle(_type);

if (pack.TryDropItem(from, pot, false))
{
Expand Down Expand Up @@ -184,9 +182,8 @@ public override bool OnDragDrop(Mobile from, Item item)

if (pot.PotionEffect != _type)
{
from.SendLocalizedMessage(
502236
); // You decide that it would be a bad idea to mix different types of potions.
// You decide that it would be a bad idea to mix different types of potions.
from.SendLocalizedMessage(502236);
return false;
}

Expand Down Expand Up @@ -227,10 +224,9 @@ public static bool GiveBottle(Mobile m, int amount)
return true;
}

public BasePotion FillBottle() =>
_type switch
public static BasePotion FillBottle(PotionEffect effect) =>
effect switch
{
PotionEffect.Nightsight => new NightSightPotion(),
PotionEffect.CureLesser => new LesserCurePotion(),
PotionEffect.Cure => new CurePotion(),
PotionEffect.CureGreater => new GreaterCurePotion(),
Expand All @@ -256,4 +252,34 @@ _type switch
PotionEffect.ConfusionBlastGreater => new GreaterConfusionBlastPotion(),
_ => new NightSightPotion()
};

// Function to convert potion type to potion effect enum
public static PotionEffect GetPotionEffect(Type type) =>
type switch
{
_ when type == typeof(LesserCurePotion) => PotionEffect.CureLesser,
_ when type == typeof(CurePotion) => PotionEffect.Cure,
_ when type == typeof(GreaterCurePotion) => PotionEffect.CureGreater,
_ when type == typeof(AgilityPotion) => PotionEffect.Agility,
_ when type == typeof(GreaterAgilityPotion) => PotionEffect.AgilityGreater,
_ when type == typeof(StrengthPotion) => PotionEffect.Strength,
_ when type == typeof(GreaterStrengthPotion) => PotionEffect.StrengthGreater,
_ when type == typeof(LesserPoisonPotion) => PotionEffect.PoisonLesser,
_ when type == typeof(PoisonPotion) => PotionEffect.Poison,
_ when type == typeof(GreaterPoisonPotion) => PotionEffect.PoisonGreater,
_ when type == typeof(DeadlyPoisonPotion) => PotionEffect.PoisonDeadly,
_ when type == typeof(RefreshPotion) => PotionEffect.Refresh,
_ when type == typeof(TotalRefreshPotion) => PotionEffect.RefreshTotal,
_ when type == typeof(LesserHealPotion) => PotionEffect.HealLesser,
_ when type == typeof(HealPotion) => PotionEffect.Heal,
_ when type == typeof(GreaterHealPotion) => PotionEffect.HealGreater,
_ when type == typeof(LesserExplosionPotion) => PotionEffect.ExplosionLesser,
_ when type == typeof(ExplosionPotion) => PotionEffect.Explosion,
_ when type == typeof(GreaterExplosionPotion) => PotionEffect.ExplosionGreater,
_ when type == typeof(ConflagrationPotion) => PotionEffect.Conflagration,
_ when type == typeof(GreaterConflagrationPotion) => PotionEffect.ConflagrationGreater,
_ when type == typeof(ConfusionBlastPotion) => PotionEffect.ConfusionBlast,
_ when type == typeof(GreaterConfusionBlastPotion) => PotionEffect.ConfusionBlastGreater,
_ /* when type == typeof(NightSightPotion) */ => PotionEffect.Nightsight
};
}

0 comments on commit 1a7e7c7

Please sign in to comment.