forked from DeltaV-Station/Delta-v
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Load/SpawnCharacter back (DeltaV-Station#198)
* Add Load/SpawnCharacter back Funny admin QoL * Rider automatic code cleanup * Update Admin.yml * Implement intention actions Thanks Rider :clueless:
- Loading branch information
Showing
4 changed files
with
310 additions
and
0 deletions.
There are no files selected for viewing
169 changes: 169 additions & 0 deletions
169
Content.Server/DeltaV/Administration/Commands/LoadCharacter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
using System.Linq; | ||
using Content.Server.Administration; | ||
using Content.Server.GameTicking; | ||
using Content.Server.Players; | ||
using Content.Server.Preferences.Managers; | ||
using Content.Server.Station.Systems; | ||
using Content.Shared.Administration; | ||
using Content.Shared.Humanoid; | ||
using Content.Shared.Humanoid.Prototypes; | ||
using Content.Shared.Preferences; | ||
using Robust.Server.Player; | ||
using Robust.Shared.Console; | ||
using Robust.Shared.Network; | ||
using Robust.Shared.Prototypes; | ||
|
||
// This literally only exists because haha felinid oni | ||
namespace Content.Server.DeltaV.Administration.Commands; | ||
|
||
[AdminCommand(AdminFlags.Admin)] | ||
public sealed class LoadCharacter : IConsoleCommand | ||
{ | ||
[Dependency] private readonly IEntitySystemManager _entitySys = default!; | ||
[Dependency] private readonly IEntityManager _entityManager = default!; | ||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; | ||
[Dependency] private readonly IServerPreferencesManager _prefs = default!; | ||
|
||
public string Command => "loadcharacter"; | ||
public string Description => Loc.GetString("loadcharacter-command-description"); | ||
public string Help => Loc.GetString("loadcharacter-command-help"); | ||
|
||
public void Execute(IConsoleShell shell, string argStr, string[] args) | ||
{ | ||
if (shell.Player is not IPlayerSession player) | ||
{ | ||
shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command")); | ||
return; | ||
} | ||
|
||
var data = player.ContentData(); | ||
|
||
if (data == null) | ||
{ | ||
shell.WriteError(Loc.GetString("shell-entity-is-not-mob")); // No mind specific errors? :( | ||
return; | ||
} | ||
|
||
EntityUid target; | ||
|
||
if (args.Length >= 1) | ||
{ | ||
if (!EntityUid.TryParse(args.First(), out var uid)) | ||
{ | ||
shell.WriteLine(Loc.GetString("shell-entity-uid-must-be-number")); | ||
return; | ||
} | ||
|
||
target = uid; | ||
} | ||
else | ||
{ | ||
if (player.AttachedEntity == null || | ||
!_entityManager.HasComponent<HumanoidAppearanceComponent>(player.AttachedEntity.Value)) | ||
{ | ||
shell.WriteError(Loc.GetString("shell-must-be-attached-to-entity")); | ||
return; | ||
} | ||
|
||
target = player.AttachedEntity.Value; | ||
} | ||
|
||
if (!target.IsValid() || !_entityManager.EntityExists(target)) | ||
{ | ||
shell.WriteLine(Loc.GetString("shell-invalid-entity-id")); | ||
return; | ||
} | ||
|
||
if (!_entityManager.TryGetComponent<HumanoidAppearanceComponent>(target, out var humanoidAppearance)) | ||
{ | ||
shell.WriteError(Loc.GetString("shell-entity-with-uid-lacks-component", ("uid", target.ToString()), | ||
("componentName", nameof(HumanoidAppearanceComponent)))); | ||
return; | ||
} | ||
|
||
HumanoidCharacterProfile character; | ||
|
||
if (args.Length >= 2) | ||
{ | ||
// This seems like a bad way to go about it, but it works so eh? | ||
var name = string.Join(" ", args.Skip(1).ToArray()); | ||
shell.WriteLine(Loc.GetString("loadcharacter-command-fetching", ("name", name))); | ||
|
||
if (!FetchCharacters(data.UserId, out var characters)) | ||
{ | ||
shell.WriteError(Loc.GetString("loadcharacter-command-failed-fetching")); | ||
return; | ||
} | ||
|
||
var selectedCharacter = characters.FirstOrDefault(c => c.Name == name); | ||
|
||
if (selectedCharacter == null) | ||
{ | ||
shell.WriteError(Loc.GetString("loadcharacter-command-failed-fetching")); | ||
return; | ||
} | ||
|
||
character = selectedCharacter; | ||
} | ||
else | ||
character = (HumanoidCharacterProfile) _prefs.GetPreferences(data.UserId).SelectedCharacter; | ||
|
||
// This shouldn't ever fail considering the previous checks | ||
if (!_prototypeManager.TryIndex(humanoidAppearance.Species, out var speciesPrototype) || | ||
!_prototypeManager.TryIndex<SpeciesPrototype>(character.Species, out var entPrototype)) | ||
return; | ||
|
||
if (speciesPrototype != entPrototype) | ||
shell.WriteLine(Loc.GetString("loadcharacter-command-mismatch")); | ||
|
||
var coordinates = player.AttachedEntity != null | ||
? _entityManager.GetComponent<TransformComponent>(player.AttachedEntity.Value).Coordinates | ||
: _entitySys.GetEntitySystem<GameTicker>().GetObserverSpawnPoint(); | ||
|
||
_entityManager.System<StationSpawningSystem>() | ||
.SpawnPlayerMob(coordinates, profile: character, entity: target, job: null, station: null); | ||
|
||
shell.WriteLine(Loc.GetString("loadcharacter-command-complete")); | ||
} | ||
|
||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args) | ||
{ | ||
switch (args.Length) | ||
{ | ||
case 1: | ||
return CompletionResult.FromHint(Loc.GetString("shell-argument-uid")); | ||
case 2: | ||
{ | ||
var player = shell.Player as IPlayerSession; | ||
if (player == null) | ||
return CompletionResult.Empty; | ||
|
||
var data = player.ContentData(); | ||
var mind = data?.Mind; | ||
|
||
if (mind == null || data == null) | ||
return CompletionResult.Empty; | ||
|
||
return FetchCharacters(data.UserId, out var characters) | ||
? CompletionResult.FromOptions(characters.Select(c => c.Name)) | ||
: CompletionResult.Empty; | ||
} | ||
default: | ||
return CompletionResult.Empty; | ||
} | ||
} | ||
|
||
private bool FetchCharacters(NetUserId player, out HumanoidCharacterProfile[] characters) | ||
{ | ||
characters = null!; | ||
if (!_prefs.TryGetCachedPreferences(player, out var prefs)) | ||
return false; | ||
|
||
characters = prefs.Characters | ||
.Where(kv => kv.Value is HumanoidCharacterProfile) | ||
.Select(kv => (HumanoidCharacterProfile) kv.Value) | ||
.ToArray(); | ||
|
||
return true; | ||
} | ||
} |
124 changes: 124 additions & 0 deletions
124
Content.Server/DeltaV/Administration/Commands/SpawnCharacter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
using System.Linq; | ||
using Content.Server.Administration; | ||
using Content.Server.GameTicking; | ||
using Content.Server.Players; | ||
using Content.Server.Preferences.Managers; | ||
using Content.Server.Station.Systems; | ||
using Content.Shared.Administration; | ||
using Content.Shared.Mind; | ||
using Content.Shared.Preferences; | ||
using Robust.Server.Player; | ||
using Robust.Shared.Console; | ||
using Robust.Shared.Network; | ||
|
||
namespace Content.Server.DeltaV.Administration.Commands; | ||
|
||
[AdminCommand(AdminFlags.Admin)] | ||
public sealed class SpawnCharacter : IConsoleCommand | ||
{ | ||
[Dependency] private readonly IEntitySystemManager _entitySys = default!; | ||
[Dependency] private readonly IEntityManager _entityManager = default!; | ||
[Dependency] private readonly IServerPreferencesManager _prefs = default!; | ||
|
||
public string Command => "spawncharacter"; | ||
public string Description => Loc.GetString("spawncharacter-command-description"); | ||
public string Help => Loc.GetString("spawncharacter-command-help"); | ||
|
||
public void Execute(IConsoleShell shell, string argStr, string[] args) | ||
{ | ||
if (shell.Player is not IPlayerSession player) | ||
{ | ||
shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command")); | ||
return; | ||
} | ||
|
||
var mindSystem = _entitySys.GetEntitySystem<SharedMindSystem>(); | ||
|
||
var data = player.ContentData(); | ||
|
||
if (data?.UserId == null) | ||
{ | ||
shell.WriteError(Loc.GetString("shell-entity-is-not-mob")); | ||
return; | ||
} | ||
|
||
|
||
HumanoidCharacterProfile character; | ||
|
||
if (args.Length >= 1) | ||
{ | ||
// This seems like a bad way to go about it, but it works so eh? | ||
var name = string.Join(" ", args.ToArray()); | ||
shell.WriteLine(Loc.GetString("loadcharacter-command-fetching", ("name", name))); | ||
|
||
if (!FetchCharacters(data.UserId, out var characters)) | ||
{ | ||
shell.WriteError(Loc.GetString("loadcharacter-command-failed-fetching")); | ||
return; | ||
} | ||
|
||
var selectedCharacter = characters.FirstOrDefault(c => c.Name == name); | ||
|
||
if (selectedCharacter == null) | ||
{ | ||
shell.WriteError(Loc.GetString("loadcharacter-command-failed-fetching")); | ||
return; | ||
} | ||
|
||
character = selectedCharacter; | ||
} | ||
else | ||
character = (HumanoidCharacterProfile) _prefs.GetPreferences(data.UserId).SelectedCharacter; | ||
|
||
|
||
var coordinates = player.AttachedEntity != null | ||
? _entityManager.GetComponent<TransformComponent>(player.AttachedEntity.Value).Coordinates | ||
: _entitySys.GetEntitySystem<GameTicker>().GetObserverSpawnPoint(); | ||
|
||
if (player.AttachedEntity == null || | ||
!mindSystem.TryGetMind(player.AttachedEntity.Value, out var mindId, out var mind)) | ||
return; | ||
|
||
|
||
mindSystem.TransferTo(mindId, _entityManager.System<StationSpawningSystem>() | ||
.SpawnPlayerMob(coordinates, profile: character, entity: null, job: null, station: null)); | ||
|
||
shell.WriteLine(Loc.GetString("spawncharacter-command-complete")); | ||
} | ||
|
||
public CompletionResult GetCompletion(IConsoleShell shell, string[] args) | ||
{ | ||
if (args.Length == 1) | ||
{ | ||
var player = shell.Player as IPlayerSession; | ||
if (player == null) | ||
return CompletionResult.Empty; | ||
|
||
var data = player.ContentData(); | ||
var mind = data?.Mind; | ||
|
||
if (mind == null || data == null) | ||
return CompletionResult.Empty; | ||
|
||
return FetchCharacters(data.UserId, out var characters) | ||
? CompletionResult.FromOptions(characters.Select(c => c.Name)) | ||
: CompletionResult.Empty; | ||
} | ||
|
||
return CompletionResult.Empty; | ||
} | ||
|
||
private bool FetchCharacters(NetUserId player, out HumanoidCharacterProfile[] characters) | ||
{ | ||
characters = null!; | ||
if (!_prefs.TryGetCachedPreferences(player, out var prefs)) | ||
return false; | ||
|
||
characters = prefs.Characters | ||
.Where(kv => kv.Value is HumanoidCharacterProfile) | ||
.Select(kv => (HumanoidCharacterProfile) kv.Value) | ||
.ToArray(); | ||
|
||
return true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
Resources/Locale/en-US/administration/commands/load-character.ftl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
loadcharacter-command-description = Applies your currently selected character to an entity | ||
loadcharacter-command-help = Usage: loadcharacter | loadcharacter <entityUid> | loadcharacter <entityUid> <characterName> | ||
loadcharacter-command-mismatch = Species mismatch detected between character and selected entity, this may have unexpected results. | ||
loadcharacter-command-complete = Character loaded. | ||
loadcharacter-command-fetching = Fetching character data for {$name}... | ||
loadcharacter-command-fetching-failed = Failed to fetch character data! | ||
loadcharacter-command-failed-fetching = Profile fetching failed??? | ||
loadcharacter-command-hint-select = Select character | ||
spawncharacter-command-description = Spawns your currently selected/specified character | ||
spawncharacter-command-help = Usage: spawncharacter | spawncharacter <characterName> | ||
spawncharacter-command-complete = Character spawned. |