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 19 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
306 changes: 306 additions & 0 deletions Content.Server/Traits/TraitSystem.Functions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
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;
using Robust.Shared.Serialization;

namespace Content.Server.Traits;

/// <summary>
/// Used for traits that add a Component upon spawning in, overwriting the pre-existing component if it already exists.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[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);
component.Owner = uid;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

var temp = (object) component;
serializationManager.CopyTo(data.Component, ref temp);
entityManager.RemoveComponent(uid, temp!.GetType());
entityManager.AddComponent(uid, (Component) temp);
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

/// <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);
component.Owner = uid;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

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

/// <summary>
/// Used for traits that remove a component upon a player spawning in.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[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));
}
}

/// <summary>
/// Used for traits that add an action upon a player spawning in.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[UsedImplicitly]
public sealed partial class TraitAddActions : TraitFunction
{
[DataField, AlwaysPushInheritance]
public List<EntProtoId>? Actions { get; private set; } = default!;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
if (Actions is null)
return;

VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
var actionSystem = entityManager.System<SharedActionsSystem>();

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

/// <summary>
/// Used for traits that add an Implant upon spawning in.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[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<string>? PsionicPowers { get; private set; } = default!;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var prototype = IoCManager.Resolve<IPrototypeManager>();
var psionic = entityManager.System<PsionicAbilitiesSystem>();
if (PsionicPowers is null)
return;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

foreach (var powerProto in PsionicPowers)
if (prototype.TryIndex<PsionicPowerPrototype>(powerProto, out var psionicPower))
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
psionic.InitializePsionicPower(uid, psionicPower, false);
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
}
}

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

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

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

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

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.

}
}

/// <summary>
/// Handles adding Moodlets to a player character upon spawning in. Typically used for permanent moodlets or drug addictions.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[UsedImplicitly]
public sealed partial class TraitAddMoodlets : TraitFunction
{
/// <summary>
/// The list of all Moodlets that this trait adds.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[DataField, AlwaysPushInheritance]
public List<ProtoId<MoodEffectPrototype>>? MoodEffects { get; private set; } = default!;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
var prototype = IoCManager.Resolve<IPrototypeManager>();
if (MoodEffects is null)
return;
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

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
}
}

/// <summary>
/// Add or remove Factions from a player upon spawning in.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[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; } = default!;

/// <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; } = default!;

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

if (RemoveFactions is not null)
foreach (var faction in RemoveFactions)
factionSystem.RemoveFaction(uid, faction);

if (AddFactions is not null)
foreach (var faction in AddFactions)
factionSystem.AddFaction(uid, faction);
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// <summary>
/// Only use this if you know what you're doing. This function directly writes to arbitrarily any component.
/// </summary>
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
[UsedImplicitly]
public sealed partial class TraitVVEdit : TraitFunction
{
[DataField, AlwaysPushInheritance]
public Dictionary<string, string>? VVEdit { get; private set; }
VMSolidus marked this conversation as resolved.
Show resolved Hide resolved

public override void OnPlayerSpawn(EntityUid uid,
IComponentFactory factory,
IEntityManager entityManager,
ISerializationManager serializationManager)
{
if (VVEdit is null)
return;

VMSolidus marked this conversation as resolved.
Show resolved Hide resolved
var vvm = IoCManager.Resolve<IViewVariablesManager>();
foreach (var (path, value) in VVEdit)
vvm.WritePath(path, value);
}
}
Loading
Loading