Basis for the job system (#434)

* Add basic yaml Jobs file

* Add Job Prototype

* Rename Jobs to Job

* Remove BaseJob

* Add the Job class child of Role

* Add code for spawning as an assistant. Not actually working, the job prototype can't be found.

* Fix role instead of job left in yaml

* Add starting gear support for job and the starting gear for assistant as an exemple

* Link job with starting gear in yaml

* Better naming and some error handling

* Tweak error handling
This commit is contained in:
ZelteHonor
2019-11-17 11:18:39 -05:00
committed by Pieter-Jan Briers
parent 480d3b26c4
commit 447db2e458
8 changed files with 376 additions and 74 deletions

View File

@@ -7,9 +7,11 @@ using Content.Server.GameTicking.GamePresets;
using Content.Server.Interfaces.Chat;
using Content.Server.Interfaces.GameTicking;
using Content.Server.Mobs;
using Content.Server.Mobs.Roles;
using Content.Server.Players;
using Content.Shared;
using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.Jobs;
using Robust.Server.Interfaces.Maps;
using Robust.Server.Interfaces.Player;
using Robust.Server.Player;
@@ -27,6 +29,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timers;
using Robust.Shared.Timing;
@@ -91,6 +94,7 @@ namespace Content.Server.GameTicking
[Dependency] private IChatManager _chatManager;
[Dependency] private IServerNetManager _netManager;
[Dependency] private IDynamicTypeFactory _dynamicTypeFactory;
[Dependency] private IPrototypeManager _prototypeManager;
[Dependency] private readonly ILocalizationManager _localization;
[Dependency] private readonly IRobustRandom _robustRandom;
#pragma warning restore 649
@@ -260,16 +264,23 @@ namespace Content.Server.GameTicking
UpdateInfoText();
}
private IEntity _spawnPlayerMob()
private IEntity _spawnPlayerMob(Job job)
{
var entity = _entityManager.SpawnEntityAt(PlayerPrototypeName, _getLateJoinSpawnPoint());
if (entity.TryGetComponent(out InventoryComponent inventory))
{
var uniform = _entityManager.SpawnEntity("UniformAssistant");
inventory.Equip(EquipmentSlotDefines.Slots.INNERCLOTHING, uniform.GetComponent<ClothingComponent>());
var gear = _prototypeManager.Index<StartingGearPrototype>(job.StartingGear).Equipment;
var shoes = _entityManager.SpawnEntity("ShoesBlack");
inventory.Equip(EquipmentSlotDefines.Slots.SHOES, shoes.GetComponent<ClothingComponent>());
foreach (var (slotStr, equipmentStr) in gear)
{
if (!Enum.TryParse(slotStr.ToUpper(), out EquipmentSlotDefines.Slots slot))
{
Logger.Error("{0} is an invalid equipment slot.", slotStr);
continue;
}
var equipmentEntity = _entityManager.SpawnEntity(equipmentStr);
inventory.Equip(slot, equipmentEntity.GetComponent<ClothingComponent>());
}
}
return entity;
@@ -441,8 +452,11 @@ namespace Content.Server.GameTicking
var data = session.ContentData();
data.WipeMind();
data.Mind = new Mind(session.SessionId);
//TODO Replace "Assistant" with the job when char preference are done
var job = new Job(data.Mind, _prototypeManager.Index<JobPrototype>("Assistant"));
data.Mind.AddRole(job);
var mob = _spawnPlayerMob();
var mob = _spawnPlayerMob(job);
data.Mind.TransferTo(mob);
}

View File

@@ -1,13 +1,17 @@
using System.Text;
using Content.Server.Mobs.Roles;
using Content.Server.Players;
using Content.Shared.Jobs;
using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
namespace Content.Server.Mobs
{
public class MindInfoCommand : IClientCommand
{
public string Command => "mindinfo";
@@ -47,6 +51,10 @@ namespace Content.Server.Mobs
public class AddRoleCommand : IClientCommand
{
#pragma warning disable 649
[Dependency] private IPrototypeManager _prototypeManager;
#pragma warning restore 649
public string Command => "addrole";
public string Description => "Adds a role to a player's mind.";
@@ -65,9 +73,8 @@ namespace Content.Server.Mobs
if (mgr.TryGetPlayerData(new NetSessionId(args[0]), out var data))
{
var mind = data.ContentData().Mind;
var refl = IoCManager.Resolve<IReflectionManager>();
var type = refl.LooseGetType(args[1]);
mind.AddRole(type);
var role = new Job(mind, _prototypeManager.Index<JobPrototype>(args[1]));
mind.AddRole(role);
}
else
{
@@ -78,6 +85,11 @@ namespace Content.Server.Mobs
public class RemoveRoleCommand : IClientCommand
{
#pragma warning disable 649
[Dependency] private IPrototypeManager _prototypeManager;
#pragma warning restore 649
public string Command => "rmrole";
public string Description => "Removes a role from a player's mind.";
@@ -96,9 +108,8 @@ namespace Content.Server.Mobs
if (mgr.TryGetPlayerData(new NetSessionId(args[0]), out var data))
{
var mind = data.ContentData().Mind;
var refl = IoCManager.Resolve<IReflectionManager>();
var type = refl.LooseGetType(args[1]);
mind.RemoveRole(type);
var role = new Job(mind, _prototypeManager.Index<JobPrototype>(args[1]));
mind.RemoveRole(role);
}
else
{

View File

@@ -22,7 +22,7 @@ namespace Content.Server.Mobs
/// </remarks>
public sealed class Mind
{
private readonly Dictionary<Type, Role> _roles = new Dictionary<Type, Role>();
private readonly ISet<Role> _roles = new HashSet<Role>();
/// <summary>
/// Creates the new mind attached to a specific player session.
@@ -66,7 +66,7 @@ namespace Content.Server.Mobs
/// An enumerable over all the roles this mind has.
/// </summary>
[ViewVariables]
public IEnumerable<Role> AllRoles => _roles.Values;
public IEnumerable<Role> AllRoles => _roles;
/// <summary>
/// The session of the player owning this mind.
@@ -87,19 +87,6 @@ namespace Content.Server.Mobs
}
}
/// <summary>
/// Gives this mind a new role.
/// </summary>
/// <typeparam name="T">The type of the role to give.</typeparam>
/// <returns>The instance of the role.</returns>
/// <exception cref="ArgumentException">
/// Thrown if we already have a role with this type.
/// </exception>
public T AddRole<T>() where T : Role
{
return (T)AddRole(typeof(T));
}
/// <summary>
/// Gives this mind a new role.
/// </summary>
@@ -108,31 +95,18 @@ namespace Content.Server.Mobs
/// <exception cref="ArgumentException">
/// Thrown if we already have a role with this type.
/// </exception>
public Role AddRole(Type t)
public Role AddRole(Role role)
{
if (_roles.ContainsKey(t))
if (_roles.Contains(role))
{
throw new ArgumentException($"We already have this role: {t}");
throw new ArgumentException($"We already have this role: {role}");
}
var role = (Role)Activator.CreateInstance(t, this);
_roles[t] = role;
_roles.Add(role);
role.Greet();
return role;
}
/// <summary>
/// Removes a role from this mind.
/// </summary>
/// <typeparam name="T">The type of the role to remove.</typeparam>
/// <exception cref="ArgumentException">
/// Thrown if we do not have this role.
/// </exception>
public void RemoveRole<T>() where T : Role
{
RemoveRole(typeof(T));
}
/// <summary>
/// Removes a role from this mind.
/// </summary>
@@ -140,42 +114,16 @@ namespace Content.Server.Mobs
/// <exception cref="ArgumentException">
/// Thrown if we do not have this role.
/// </exception>
public void RemoveRole(Type t)
public void RemoveRole(Role role)
{
if (!_roles.ContainsKey(t))
if (!_roles.Contains(role))
{
throw new ArgumentException($"We do not have this role: {t}");
throw new ArgumentException($"We do not have this role: {role}");
}
// This can definitely get more complex removal hooks later,
// when we need it.
_roles.Remove(t);
}
/// <summary>
/// Gets a role of a certain type.
/// </summary>
/// <typeparam name="T">The type of the role to get.</typeparam>
/// <returns>The role's instance.</returns>
/// <exception cref="KeyNotFoundException">
/// Thrown if we do not have a role of this type.
/// </exception>
public T GetRole<T>() where T : Role
{
return (T)_roles[typeof(T)];
}
/// <summary>
/// Gets a role of a certain type.
/// </summary>
/// <param name="t">The type of the role to get.</param>
/// <returns>The role's instance.</returns>
/// <exception cref="KeyNotFoundException">
/// Thrown if we do not have a role of this type.
/// </exception>
public Role GetRole(Type t)
{
return _roles[t];
_roles.Remove(role);
}
/// <summary>

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using Content.Server.Interfaces.Chat;
using Content.Shared.Jobs;
using Robust.Shared.IoC;
namespace Content.Server.Mobs.Roles
{
public class Job : Role
{
private readonly JobPrototype _jobPrototype;
public override string Name { get; }
public String StartingGear => _jobPrototype.StartingGear;
public Job(Mind mind, JobPrototype jobPrototype) : base(mind)
{
_jobPrototype = jobPrototype;
Name = jobPrototype.Name;
}
public override void Greet()
{
base.Greet();
var chat = IoCManager.Resolve<IChatManager>();
chat.DispatchServerMessage(
Mind.Session,
String.Format("You're a new {0}. Do your best!", Name));
}
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.Jobs
{
[Prototype("job")]
public class JobPrototype : IPrototype, IIndexedPrototype
{
public string ID { get; private set; }
public string Name { get; private set; }
public string StartingGear { get; private set; }
public IEnumerable<string> Department { get; private set; }
public void LoadFrom(YamlMappingNode mapping)
{
ID = mapping.GetNode("id").AsString();
Name = mapping.GetNode("name").ToString();
StartingGear = mapping.GetNode("startingGear").ToString();
Department = mapping.GetNode("department").AllNodes.Select(i => i.ToString());
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Shared.Jobs
{
[Prototype("startingGear")]
public class StartingGearPrototype : IPrototype, IIndexedPrototype
{
private string _id;
private Dictionary<string, string> _equipment;
[ViewVariables]
public string ID => _id;
[ViewVariables]
public Dictionary<string, string> Equipment => _equipment;
public void LoadFrom(YamlMappingNode mapping)
{
var serializer = YamlObjectSerializer.NewReader(mapping);
serializer.DataField(ref _id, "id", string.Empty);
serializer.DataField(ref _equipment, "equipment", new Dictionary<string, string>());
}
}
}

View File

@@ -0,0 +1,6 @@
- type: startingGear
id: AssistantGear
equipment:
innerclothing: UniformAssistant
backpack: BackpackClothing
shoes: ShoesBlack

View File

@@ -0,0 +1,231 @@
- type: job
id: Captain
name: "Captain"
startingGear: CaptainGear
department:
- Command
- type: job
id: HeadOfPersonnel
name: "Head Of Personnel"
startingGear: HeadOfPersonnelGear
department:
- Command
- Civilian
- Cargo
- type: job
id: HeadOfSecurity
name: "Head Of Security"
startingGear: HeadOfSecurityGear
department:
- Command
- Security
- type: job
id: ChiefEngineer
name: "Chief Engineer"
startingGear: ChiefEngineerGear
department:
- Command
- Engineering
- type: job
id: ResearchDirector
name: "Research Director"
startingGear: ResearchDirectorGear
department:
- Command
- Science
- type: job
id: ChiefMedicalOfficer
name: "Chief Medical Officer"
startingGear: ChiefMedicalOfficerGear
department:
- Command
- Medical
- type: job
id: StationEngineer
name: "Station Engineer"
startingGear: StationEngineerGear
department:
- Engineering
- type: job
id: AtmosphericTechnician
name: "Atmospheric Technician"
startingGear: AtmosphericTechnicianGear
department:
- Engineering
- type: job
id: Mechanic
name: "Mechanic"
startingGear: MechanicGear
department:
- Engineering
- Science
- type: job
id: MedicalDoctor
name: "Medical Doctor"
startingGear: MedicalDoctorGear
department:
- Medical
- type: job
id: Geneticist
name: "Geneticist"
startingGear: GeneticistGear
department:
- Science
- Medical
- type: job
id: Virologist
name: "Virologist"
startingGear: VirologistGear
department:
- Medical
- type: job
id: Paramedic
name: "Paramedic"
startingGear: ParamedicGear
department:
- Medical
- type: job
id: Chemist
name: "Chemist"
startingGear: ChemistGear
department:
- Medical
- type: job
id: Scientist
name: "Scientist"
startingGear: ScientistGear
department:
- Science
- type: job
id: Roboticist
name: "Roboticist"
startingGear: RoboticistGear
department:
- Science
- type: job
id: Bartender
name: "Bartender"
startingGear: BartenderGear
department:
- Civilian
- type: job
id: Botanist
name: "Botanist"
startingGear: BotanistGear
department:
- Civilian
- type: job
id: Chef
name: "Chef"
startingGear: ChefGear
department:
- Civilian
- type: job
id: Janitor
name: "Janitor"
startingGear: JanitorGear
department:
- Civilian
- type: job
id: Librarian
name: "Librarian"
startingGear: LibrarianGear
department:
- Civilian
- type: job
id: InternalAffairsAgent
name: "Internal Affairs Agent"
startingGear: InternalAffairsAgentGear
department:
- Civilian
- type: job
id: Chaplain
name: "Chaplain"
startingGear: ChaplainGear
department:
- Civilian
- type: job
id: Clown
name: "Clown"
startingGear: ClownGear
department:
- Civilian
- type: job
id: Mime
name: "Mime"
startingGear: MimeGear
department:
- Civilian
- type: job
id: Assistant
name: "Assistant"
startingGear: AssistantGear
department:
- Civilian
- type: job
id: Quartermaster
name: "Quartermaster"
startingGear: QuartermasterGear
department:
- Cargo
- type: job
id: CargoTechnician
name: "Cargo Technician"
startingGear: CargoTechnicianGear
department:
- Cargo
- type: job
id: ShaftMiner
name: "Shaft Miner"
startingGear: ShaftMinerGear
department:
- Cargo
- type: job
id: Warden
name: "Warden"
startingGear: WardenGear
department:
- Security
- type: job
id: Detective
name: "Detective"
startingGear: DetectiveGear
department:
- Security
- type: job
id: SecurityOfficer
name: "Security Officer"
startingGear: SecurityOfficerGear
department:
- Security