feat(objects): ExtractCtors — constructible ctor arguments

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kamron Batman 2026-07-19 10:49:48 -07:00
parent d02cb56871
commit 95d57afdec
No known key found for this signature in database
GPG key ID: 7D81DF26D9A5D94A
2 changed files with 57 additions and 0 deletions

View file

@ -0,0 +1,24 @@
using System.Linq;
using Server.Commands;
using Server.Items;
using Xunit;
namespace UOContent.Tests.Commands.Objects;
[Collection("Sequential UOContent Tests")]
public class ObjectIntrospectionCtorsTests
{
[Fact]
public void ExtractCtors_lists_both_constructible_runebook_overloads()
{
// Runebook has [Constructible] Runebook() and [Constructible] Runebook(int maxCharges).
var ctors = ObjectIntrospection.ExtractCtors(typeof(Runebook));
Assert.Equal(2, ctors.Count);
Assert.Contains(ctors, c => c.Parameters.Count == 0);
var parameterized = Assert.Single(ctors, c => c.Parameters.Count == 1);
Assert.Equal("maxCharges", parameterized.Parameters[0].Name);
Assert.Equal("int", parameterized.Parameters[0].Type);
}
}

View file

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using Server.Items;
namespace Server.Commands;
@ -57,4 +59,35 @@ public static class ObjectIntrospection
throw new ArgumentException($"{type} is neither Item nor Mobile.", nameof(type));
}
public static List<CtorDoc> ExtractCtors(Type type)
{
var docs = new List<CtorDoc>();
foreach (var ctor in type.GetConstructors())
{
if (!Attributes.IsConstructible(ctor, AccessLevel.Developer))
{
continue;
}
var doc = new CtorDoc();
foreach (var p in ctor.GetParameters())
{
doc.Parameters.Add(
new ParamDoc
{
Name = p.Name,
Type = ObjectNaming.FriendlyTypeName(p.ParameterType),
Default = p.HasDefaultValue ? p.DefaultValue?.ToString() ?? "null" : null,
IsParams = p.IsDefined(typeof(ParamArrayAttribute), false)
}
);
}
docs.Add(doc);
}
return docs;
}
}