Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Traits V2 #1182

Merged
merged 22 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Content.Server/Jobs/AddComponentSpecial.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ namespace Content.Server.Jobs
[UsedImplicitly]
public sealed partial class AddComponentSpecial : JobSpecial
{
[DataField("components")]
[AlwaysPushInheritance]
[DataField, AlwaysPushInheritance]
public ComponentRegistry Components { get; private set; } = new();

public override void AfterEquip(EntityUid mob)
Expand Down
265 changes: 265 additions & 0 deletions Content.Server/Traits/TraitSystem.Functions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
using Content.Shared.Traits;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Content.Shared.Implants;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
using Content.Shared.Actions;
using Content.Server.Abilities.Psionics;
using Content.Shared.Psionics;
using Content.Server.Language;
using Content.Shared.Mood;
using Content.Server.NPC.Systems;

namespace Content.Server.Traits;

/// Used for traits that add a Component upon spawning in, overwriting the pre-existing component if it already exists.
[UsedImplicitly]
public sealed partial class TraitReplaceComponent : TraitFunction
{
[DataField, AlwaysPushInheritance]
public ComponentRegistry Components { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
foreach (var (name, data) in Components)
{
var component = (Component) factory.GetComponent(name);

var temp = (object) component;
serializationManager.CopyTo(data.Component, ref temp);
entityManager.RemoveComponent(uid, temp!.GetType());
entityManager.AddComponent(uid, (Component) temp, true);
}
}
}

/// <summary>
/// Used for traits that add a Component upon spawning in.
/// This will do nothing if the Component already exists.
/// </summary>
[UsedImplicitly]
public sealed partial class TraitAddComponent : TraitFunction
{
[DataField, AlwaysPushInheritance]
public ComponentRegistry Components { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
foreach (var (name, _) in Components)
{
var component = (Component) factory.GetComponent(name);

entityManager.AddComponent(uid, component, true);
}
}
}

/// Used for traits that remove a component upon a player spawning in.
[UsedImplicitly]
public sealed partial class TraitRemoveComponent : TraitFunction
{
[DataField, AlwaysPushInheritance]
public ComponentRegistry Components { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
foreach (var (name, _) in Components)
entityManager.RemoveComponent(uid, (Component) factory.GetComponent(name));
}
}

/// Used for traits that add an action upon a player spawning in.
[UsedImplicitly]
public sealed partial class TraitAddActions : TraitFunction
{
[DataField, AlwaysPushInheritance]
public List<EntProtoId> Actions { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var actionSystem = entityManager.System<SharedActionsSystem>();

foreach (var id in Actions)
{
EntityUid? actionId = null;
if (actionSystem.AddAction(uid, ref actionId, id))
actionSystem.StartUseDelay(actionId);
}
}
}

/// Used for traits that add an Implant upon spawning in.
[UsedImplicitly]
public sealed partial class TraitAddImplant : TraitFunction
{
[DataField(customTypeSerializer: typeof(PrototypeIdHashSetSerializer<EntityPrototype>))]
[AlwaysPushInheritance]
public HashSet<string> Implants { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var implantSystem = entityManager.System<SharedSubdermalImplantSystem>();
implantSystem.AddImplants(uid, Implants);
}
}

/// <summary>
/// If a trait includes any Psionic Powers, this enters the powers into PsionicSystem to be initialized.
/// If the lack of logic here seems startling, it's okay. All of the logic necessary for adding Psionics is handled by InitializePsionicPower.
/// </summary>
[UsedImplicitly]
public sealed partial class TraitAddPsionics : TraitFunction
{
[DataField, AlwaysPushInheritance]
public List<ProtoId<PsionicPowerPrototype>> PsionicPowers { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var prototype = IoCManager.Resolve<IPrototypeManager>();
var psionic = entityManager.System<PsionicAbilitiesSystem>();

foreach (var powerProto in PsionicPowers)
if (prototype.TryIndex(powerProto, out var psionicPower))
psionic.InitializePsionicPower(uid, psionicPower, false);
}
}

/// Handles all modification of Known Languages. Removes languages before adding them.
[UsedImplicitly]
public sealed partial class TraitModifyLanguages : TraitFunction
{
/// The list of all Spoken Languages that this trait adds.
[DataField, AlwaysPushInheritance]
public List<string>? LanguagesSpoken { get; private set; } = default!;

/// The list of all Understood Languages that this trait adds.
[DataField, AlwaysPushInheritance]
public List<string>? LanguagesUnderstood { get; private set; } = default!;

/// The list of all Spoken Languages that this trait removes.
[DataField, AlwaysPushInheritance]
public List<string>? RemoveLanguagesSpoken { get; private set; } = default!;

/// The list of all Understood Languages that this trait removes.
[DataField, AlwaysPushInheritance]
public List<string>? RemoveLanguagesUnderstood { get; private set; } = default!;

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var language = entityManager.System<LanguageSystem>();

if (RemoveLanguagesSpoken is not null)
foreach (var lang in RemoveLanguagesSpoken)
language.RemoveLanguage(uid, lang, true, false);

if (RemoveLanguagesUnderstood is not null)
foreach (var lang in RemoveLanguagesUnderstood)
language.RemoveLanguage(uid, lang, false, true);

if (LanguagesSpoken is not null)
foreach (var lang in LanguagesSpoken)
language.AddLanguage(uid, lang, true, false);

if (LanguagesUnderstood is not null)
foreach (var lang in LanguagesUnderstood)
language.AddLanguage(uid, lang, false, true);
Comment on lines +173 to +187
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simply want nullable lists gone here. Make them empty lists instead.
Or AT LEAST add some brackets

if (list is not null)
{
   foreach (var lang in list)
       doSomething()
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very keen on flexing my "Line Count To Bracket Ratio" against Wizden, so if I can get away with no brackets, I will lmao.

}
}

/// Handles adding Moodlets to a player character upon spawning in. Typically used for permanent moodlets or drug addictions.
[UsedImplicitly]
public sealed partial class TraitAddMoodlets : TraitFunction
{
/// The list of all Moodlets that this trait adds.
[DataField, AlwaysPushInheritance]
public List<ProtoId<MoodEffectPrototype>> MoodEffects { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var prototype = IoCManager.Resolve<IPrototypeManager>();

foreach (var moodProto in MoodEffects)
if (prototype.TryIndex(moodProto, out var moodlet))
entityManager.EventBus.RaiseLocalEvent(uid, new MoodEffectEvent(moodlet.ID));
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// Add or remove Factions from a player upon spawning in.
[UsedImplicitly]
public sealed partial class TraitModifyFactions : TraitFunction
{
/// <summary>
/// The list of all Factions that this trait removes.
/// </summary>
/// <remarks>
/// I can't actually Validate these because the proto lives in Shared.
/// </remarks>
[DataField, AlwaysPushInheritance]
public List<string> RemoveFactions { get; private set; } = new();

/// <summary>
/// The list of all Factions that this trait adds.
/// </summary>
/// <remarks>
/// I can't actually Validate these because the proto lives in Shared.
/// </remarks>
[DataField, AlwaysPushInheritance]
public List<string> AddFactions { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var factionSystem = entityManager.System<NpcFactionSystem>();

foreach (var faction in RemoveFactions)
factionSystem.RemoveFaction(uid, faction);

foreach (var faction in AddFactions)
factionSystem.AddFaction(uid, faction);
}
}

/// Only use this if you know what you're doing. This function directly writes to any arbitrary component.
[UsedImplicitly]
public sealed partial class TraitVVEdit : TraitFunction
{
[DataField, AlwaysPushInheritance]
public Dictionary<string, string> VVEdit { get; private set; } = new();

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var vvm = IoCManager.Resolve<IViewVariablesManager>();
foreach (var (path, value) in VVEdit)
vvm.WritePath(path, value);
}
}
Loading
Loading