fix: Fixes PlayerConstructed stacking/BODs (#2579)

### Summary

* Removes player constructed as a requirement for BODs.
* When two items stack and they don't match player constructed flags, the resulting stack loses the flag.
This commit is contained in:
Kamron Batman 2026-08-14 17:14:38 -07:00 committed by GitHub
parent 2dbaa87377
commit be3a08513f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 7 additions and 48 deletions

View file

@ -24,26 +24,6 @@ public class PlayerConstructedStackingTests
private static StackableItem MakeStack(Serial serial, int amount, bool playerConstructed) => private static StackableItem MakeStack(Serial serial, int amount, bool playerConstructed) =>
new(serial) { Amount = amount, PlayerConstructed = playerConstructed }; new(serial) { Amount = amount, PlayerConstructed = playerConstructed };
[Fact]
public void CanStackWith_IsFalseWhenProvenanceDiffers()
{
var bought = MakeStack((Serial)0x1, 5, false);
var crafted = MakeStack((Serial)0x2, 5, true);
try
{
// Both orders must fail. Whichever is the receiver decides the merged pile's flag,
// so allowing either one means the result is decided by drag direction.
Assert.False(bought.CanStackWith(crafted));
Assert.False(crafted.CanStackWith(bought));
}
finally
{
bought.Delete();
crafted.Delete();
}
}
[Theory] [Theory]
[InlineData(false)] [InlineData(false)]
[InlineData(true)] [InlineData(true)]
@ -63,27 +43,6 @@ public class PlayerConstructedStackingTests
} }
} }
[Fact]
public void StackWith_RefusesToMergeAcrossProvenance()
{
var bought = MakeStack((Serial)0x1, 5, false);
var crafted = MakeStack((Serial)0x2, 5, true);
try
{
Assert.False(bought.StackWith(null, crafted, false));
Assert.Equal(5, bought.Amount);
Assert.Equal(5, crafted.Amount);
Assert.False(bought.PlayerConstructed);
Assert.False(crafted.Deleted);
}
finally
{
bought.Delete();
crafted.Delete();
}
}
[Theory] [Theory]
[InlineData(false)] [InlineData(false)]
[InlineData(true)] [InlineData(true)]

View file

@ -2350,7 +2350,6 @@ public partial class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropert
dropped.ItemID == ItemID && dropped.ItemID == ItemID &&
dropped.Hue == Hue && dropped.Hue == Hue &&
dropped.Name == Name && dropped.Name == Name &&
dropped.PlayerConstructed == PlayerConstructed &&
dropped.Amount + Amount <= 60000 && dropped.Amount + Amount <= 60000 &&
dropped != this; dropped != this;
@ -2369,6 +2368,11 @@ public partial class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropert
} }
Amount += dropped.Amount; Amount += dropped.Amount;
if (PlayerConstructed != dropped.PlayerConstructed)
{
PlayerConstructed = false;
}
dropped.Delete(); dropped.Delete();
if (playSound && from != null) if (playSound && from != null)
@ -3451,7 +3455,7 @@ public partial class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropert
for (var i = 0; i < props.Length; i++) for (var i = 0; i < props.Length; i++)
{ {
var p = props[i]; var p = props[i];
if (p.GetCustomAttribute(typeof(IgnoreDupeAttribute), true) != null || !p.CanRead || !p.CanWrite) if (p.GetCustomAttribute<IgnoreDupeAttribute>(true) != null || !p.CanRead || !p.CanWrite)
{ {
continue; continue;
} }

View file

@ -137,11 +137,7 @@ public abstract partial class SmallBOD : BaseBOD
{ {
var material = GetMaterial(armor?.Resource ?? clothing?.Resource ?? CraftResource.None); var material = GetMaterial(armor?.Resource ?? clothing?.Resource ?? CraftResource.None);
if (!item.PlayerConstructed) if (Material >= BulkMaterialType.DullCopper && Material <= BulkMaterialType.Valorite && material != Material)
{
from.SendLocalizedMessage(1045169); // The item is not in the request.
}
else if (Material >= BulkMaterialType.DullCopper && Material <= BulkMaterialType.Valorite && material != Material)
{ {
from.SendLocalizedMessage(1045168); // The item is not made from the requested ore. from.SendLocalizedMessage(1045168); // The item is not made from the requested ore.
} }