180 lines
8 KiB
C#
180 lines
8 KiB
C#
using System.Linq;
|
|
using System.Reflection;
|
|
using Content.Server.Body.Systems;
|
|
using Content.Server.Hands.Systems;
|
|
using Content.Server.Humanoid;
|
|
using Content.Shared._Starlight.Medical.Body;
|
|
using Content.Shared._Starlight.Medical.Limbs;
|
|
using Content.Shared.Body.Components;
|
|
using Content.Shared.Body.Part;
|
|
using Content.Shared.Hands.Components;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Humanoid.Prototypes;
|
|
using Content.Shared.Interaction.Components;
|
|
using Content.Shared.Starlight;
|
|
using Content.Shared.Starlight.Medical.Surgery;
|
|
using Robust.Server.Containers;
|
|
using Robust.Shared.Prototypes;
|
|
using Robust.Shared.Reflection;
|
|
|
|
namespace Content.Server._Starlight.Medical.Limbs;
|
|
public sealed partial class LimbSystem : SharedLimbSystem
|
|
{
|
|
private static MethodInfo? s_raiseLocalEventRefMethod;
|
|
static LimbSystem()
|
|
=> s_raiseLocalEventRefMethod = typeof(LimbSystem)
|
|
.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
|
|
.Where(m => m.Name == nameof(RaiseLocalEvent)
|
|
&& m.IsGenericMethodDefinition)
|
|
.FirstOrDefault(m =>
|
|
{
|
|
var pars = m.GetParameters();
|
|
if (pars.Length != 3)
|
|
return false;
|
|
|
|
if (pars[0].ParameterType != typeof(EntityUid))
|
|
return false;
|
|
|
|
if (!pars[1].ParameterType.IsByRef)
|
|
return false;
|
|
|
|
if (pars[2].ParameterType != typeof(bool))
|
|
return false;
|
|
|
|
return true;
|
|
});
|
|
private void AddLimb(Entity<HumanoidAppearanceComponent> body, string slot, Entity<BodyPartComponent> limb)
|
|
{
|
|
var hands = EnsureComp<HandsComponent>(body.Owner);
|
|
switch (limb.Comp.PartType)
|
|
{
|
|
case BodyPartType.Arm:
|
|
if (limb.Comp.Children.Keys.Count == 0)
|
|
_body.TryCreatePartSlot(limb, limb.Comp.Symmetry == BodyPartSymmetry.Left ? "left hand" : "right hand", BodyPartType.Hand, out _);
|
|
|
|
foreach (var slotId in limb.Comp.Children.Keys)
|
|
{
|
|
if (slotId is null) continue;
|
|
var slotFullId = BodySystem.GetPartSlotContainerId(slotId);
|
|
var child = _containers.GetContainer(limb, slotFullId);
|
|
|
|
foreach (var containedEnt in child.ContainedEntities)
|
|
{
|
|
if (TryComp(containedEnt, out BodyPartComponent? innerPart)
|
|
&& innerPart.PartType == BodyPartType.Hand)
|
|
{
|
|
_hands.AddHand((body, hands), slotFullId, limb.Comp.Symmetry == BodyPartSymmetry.Left ? HandLocation.Left : HandLocation.Right);
|
|
AddLimbVisual(body, (containedEnt, innerPart));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case BodyPartType.Hand:
|
|
_hands.AddHand((body, hands), BodySystem.GetPartSlotContainerId(slot), limb.Comp.Symmetry == BodyPartSymmetry.Left ? HandLocation.Left : HandLocation.Right);
|
|
break;
|
|
case BodyPartType.Leg:
|
|
if (limb.Comp.Children.Keys.Count == 0)
|
|
_body.TryCreatePartSlot(limb, limb.Comp.Symmetry == BodyPartSymmetry.Left ? "left foot" : "right foot", BodyPartType.Foot, out var slotId);
|
|
|
|
foreach (var slotId in limb.Comp.Children.Keys)
|
|
{
|
|
if (slotId is null) continue;
|
|
var slotFullId = BodySystem.GetPartSlotContainerId(slotId);
|
|
var child = _containers.GetContainer(limb, slotFullId);
|
|
|
|
foreach (var containedEnt in child.ContainedEntities)
|
|
{
|
|
if (TryComp(containedEnt, out BodyPartComponent? innerPart)
|
|
&& innerPart.PartType == BodyPartType.Foot)
|
|
AddLimbVisual(body, (containedEnt, innerPart));
|
|
}
|
|
}
|
|
break;
|
|
case BodyPartType.Foot:
|
|
break;
|
|
}
|
|
foreach (var comp in EntityManager.GetComponents(limb))
|
|
{
|
|
if (comp is IImplantable)
|
|
{
|
|
{
|
|
var eventType = typeof(LimbAttachedEvent<>).MakeGenericType(comp.GetType());
|
|
var limbAttachedEvent = Activator.CreateInstance(eventType, [limb.Owner, comp]);
|
|
|
|
if (limbAttachedEvent != null)
|
|
{
|
|
var closedMethod = s_raiseLocalEventRefMethod!.MakeGenericMethod(eventType);
|
|
closedMethod.Invoke(this, [body.Owner, limbAttachedEvent, false]);
|
|
}
|
|
}
|
|
|
|
foreach (var face in comp.GetType().GetInterfaces().Where(x => x.IsAssignableTo(typeof(IImplantable))))
|
|
{
|
|
var eventType = typeof(LimbAttachedEvent<>).MakeGenericType(face);
|
|
var limbAttachedEvent = Activator.CreateInstance(eventType, [limb.Owner, comp]);
|
|
|
|
if (limbAttachedEvent != null)
|
|
{
|
|
var closedMethod = s_raiseLocalEventRefMethod!.MakeGenericMethod(eventType);
|
|
closedMethod.Invoke(this, [ body.Owner, limbAttachedEvent, false ]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RemoveLimb(Entity<TransformComponent, HumanoidAppearanceComponent, BodyComponent> body, Entity<TransformComponent, MetaDataComponent, BodyPartComponent> limb)
|
|
{
|
|
var hands = EnsureComp<HandsComponent>(body.Owner);
|
|
switch (limb.Comp3.PartType)
|
|
{
|
|
case BodyPartType.Arm:
|
|
foreach (var limbSlotId in limb.Comp3.Children.Keys)
|
|
{
|
|
if (limbSlotId is null) continue;
|
|
var child = _containers.GetContainer(limb, BodySystem.GetPartSlotContainerId(limbSlotId));
|
|
|
|
foreach (var containedEnt in child.ContainedEntities)
|
|
{
|
|
if (TryComp(containedEnt, out BodyPartComponent? innerPart)
|
|
&& innerPart.PartType == BodyPartType.Hand)
|
|
_hands.RemoveHand((body, hands), BodySystem.GetPartSlotContainerId(limbSlotId));
|
|
}
|
|
}
|
|
break;
|
|
case BodyPartType.Hand:
|
|
var parentSlot = _body.GetParentPartAndSlotOrNull(limb);
|
|
if (parentSlot is not null)
|
|
_hands.RemoveHand((body, hands), BodySystem.GetPartSlotContainerId(parentSlot.Value.Slot));
|
|
break;
|
|
case BodyPartType.Leg:
|
|
case BodyPartType.Foot:
|
|
break;
|
|
}
|
|
foreach (var comp in EntityManager.GetComponents(limb))
|
|
{
|
|
if (comp is IImplantable)
|
|
{
|
|
{
|
|
var eventType = typeof(LimbRemovedEvent<>).MakeGenericType(comp.GetType());
|
|
var limbAttachedEvent = Activator.CreateInstance(eventType, limb.Owner, comp);
|
|
if (limbAttachedEvent != null)
|
|
{
|
|
var closedMethod = s_raiseLocalEventRefMethod!.MakeGenericMethod(eventType);
|
|
closedMethod.Invoke(this, [body.Owner, limbAttachedEvent, false]);
|
|
}
|
|
}
|
|
foreach (var face in comp.GetType().GetInterfaces().Where(x => x.IsAssignableTo(typeof(IImplantable))))
|
|
{
|
|
var eventType = typeof(LimbRemovedEvent<>).MakeGenericType(face);
|
|
var limbAttachedEvent = Activator.CreateInstance(eventType, limb.Owner, comp);
|
|
if (limbAttachedEvent != null)
|
|
{
|
|
var closedMethod = s_raiseLocalEventRefMethod!.MakeGenericMethod(eventType);
|
|
closedMethod.Invoke(this, [body.Owner, limbAttachedEvent, false]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|