fix: Fixes duping containers and removes copying private setter properties (#1816)

### Summary
- Removes copying private setters
- Fixes duping containers
- Adds public `Dupe.DoDupe` functions for external scripts to hook into the existing logic.
This commit is contained in:
Kamron Batman 2024-06-03 15:44:56 -07:00 committed by GitHub
parent c69d16a90e
commit 0b802dbe1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 116 additions and 65 deletions

View file

@ -3381,9 +3381,15 @@ public class Item : IHued, IComparable<Item>, ISpawnable, IObjectPropertyListEnt
continue;
}
var setMethod = p.GetSetMethod(false);
try
{
p.SetValue(dest, p.GetValue(src, null), null);
// Do not copy private properties
if (setMethod != null)
{
p.SetValue(dest, p.GetValue(src, null), null);
}
}
catch
{

View file

@ -865,10 +865,12 @@ public partial class Mobile : IHued, IComparable<Mobile>, ISpawnable, IObjectPro
}
}
[IgnoreDupe]
public bool Pushing { get; set; }
public virtual bool IsDeadBondedPet => false;
[IgnoreDupe]
public ISpell Spell
{
get => m_Spell;

View file

@ -123,7 +123,7 @@ public static class ActivatorExtensions
{
var argLength = args?.Length ?? 0;
var types = argLength > 0 ? new Type[argLength] : Array.Empty<Type>();
var types = argLength > 0 ? new Type[argLength] : [];
for (int i = 0; i < types.Length; i++)
{
types[i] = args![i]?.GetType();
@ -139,7 +139,7 @@ public static class ActivatorExtensions
object[] paramArgs;
if (paramCount == 0)
{
paramArgs = Array.Empty<object>();
paramArgs = [];
}
else if (argLength == paramCount)
{

View file

@ -1,4 +1,5 @@
using System;
using System.Reflection;
using Server.Items;
using Server.Targeting;
@ -40,21 +41,110 @@ public static class Dupe
e.Mobile.SendMessage("What do you wish to dupe?");
}
public static bool DoDupe(Item src, int amount, Mobile from = null, Container pack = null)
{
from?.SendMessage($"Duping {amount}...");
var c = src.GetType().GetConstructor(out var paramCount);
if (c == null)
{
from?.SendMessage("Unable to dupe. Item must have a constructor with zero required parameters.");
return false;
}
var args = paramCount == 0 ? null : new object[paramCount];
if (args != null)
{
Array.Fill(args, Type.Missing);
}
try
{
for (var i = 0; i < amount; i++)
{
var newItem = DoDupe(src, c, args, from);
if (newItem != null)
{
if (pack != null)
{
pack.DropItem(newItem);
}
else if (from != null)
{
newItem.MoveToWorld(from.Location, from.Map);
}
}
}
return true;
}
catch
{
return false;
}
}
public static Item DoDupe(Item src, ConstructorInfo c, object[] args, Mobile from = null)
{
try
{
if (c.Invoke(args) is not Item newItem)
{
return null;
}
src.Dupe(newItem);
newItem.UpdateTotals();
newItem.InvalidateProperties();
newItem.Delta(ItemDelta.Update);
if (from != null)
{
CommandLogging.WriteLine(
from,
$"{from.AccessLevel} {CommandLogging.Format(from)} duped {CommandLogging.Format(src)} creating {CommandLogging.Format(newItem)}"
);
}
// Recurse for items that have items
if (newItem.Items.Count > 0)
{
for (var j = newItem.Items.Count - 1; j >= 0; j--)
{
var itemToDelete = newItem.Items[j];
newItem.RemoveItem(itemToDelete);
itemToDelete.Delete();
}
}
for (var j = 0; j < src.Items.Count; j++)
{
var subItem = DoDupe(src.Items[j], c, args, from);
newItem.AddItem(subItem);
}
return newItem;
}
catch
{
return null;
}
}
private class DupeTarget : Target
{
private readonly int m_Amount;
private readonly bool m_InBag;
private readonly int _amount;
private readonly bool _inBag;
public DupeTarget(bool inbag, int amount)
: base(15, false, TargetFlags.None)
public DupeTarget(bool inbag, int amount) : base(15, false, TargetFlags.None)
{
m_InBag = inbag;
m_Amount = amount;
_inBag = inbag;
_amount = amount;
}
protected override void OnTarget(Mobile from, object targ)
{
var done = false;
if (targ is not Item copy)
{
from.SendMessage("You can only dupe items.");
@ -63,12 +153,12 @@ public static class Dupe
CommandLogging.WriteLine(
from,
$"{from.AccessLevel} {CommandLogging.Format(from)} duping {CommandLogging.Format(copy)} (inBag={m_InBag}; amount={m_Amount})"
$"{from.AccessLevel} {CommandLogging.Format(from)} duping {CommandLogging.Format(copy)} (inBag={_inBag}; amount={_amount})"
);
Container pack = null;
Container pack;
if (m_InBag)
if (_inBag)
{
pack = copy.Parent switch
{
@ -82,57 +172,13 @@ public static class Dupe
pack = from.Backpack;
}
var c = copy.GetType().GetConstructor(out var paramCount);
if (c != null)
if (DoDupe(copy, _amount, from, pack))
{
var args = paramCount == 0 ? null : new object[paramCount];
if (args != null)
{
Array.Fill(args, Type.Missing);
}
try
{
from.SendMessage($"Duping {m_Amount}...");
for (var i = 0; i < m_Amount; i++)
{
if (c.Invoke(args) is Item newItem)
{
copy.Dupe(newItem);
if (pack != null)
{
pack.DropItem(newItem);
}
else
{
newItem.MoveToWorld(from.Location, from.Map);
}
newItem.UpdateTotals();
newItem.InvalidateProperties();
newItem.Delta(ItemDelta.Update);
CommandLogging.WriteLine(
from,
$"{from.AccessLevel} {CommandLogging.Format(from)} duped {CommandLogging.Format(copy)} creating {CommandLogging.Format(newItem)}"
);
}
}
from.SendMessage("Done");
done = true;
}
catch
{
from.SendMessage("Error!");
return;
}
from.SendMessage("Duping done.");
}
if (!done)
else
{
from.SendMessage("Unable to dupe. Item must have a constructor with zero required parameters.");
from.SendMessage("Duping Error!");
}
}
}

View file

@ -492,10 +492,7 @@ namespace Server.Items
aquarium.Water.Maintain = Water.Maintain;
aquarium.Water.State = Water.State;
for (var i = 0; i < _events.Count; i++)
{
aquarium.AddToEvents(_events[i]);
}
aquarium.Events = [..Events];
}
private void Deserialize(IGenericReader reader, int version)