Cherrypicks 3 (#382)

* Mobs burn to ashes on excessive heat damage (#26971)

* mobs burn to ashes on excessive heat damage

* remove comment, remove random lines I didn't mean to add

* combine code into behavior

* clean unused

* fix namespace

* drop next to

* fix spawn entities behavior spawning entities outside container

* fix burning to ash not working on all mobs (#27158)

* add ghostnado button to warp menu (#27556)

* add ghostnado button to warp menu

* translator ops

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>

* Make arguments and parameters wrap to one variable per line (#27766)

* Fix ghosts getting spawned in nullspace (#27617)

* Add tests for ghost spawn position

* Make ghosts spawn immediately

* Format mind system

* Move ghost spawning to GhostSystem

* Spawn ghost on grid or map

This fixes the ghosts being attached the parent entity instead of the grid.

* Move logging out of the ghost system

* Make round start observer spawn using GhostSystem

* Move GameTicker ghost spawning to GhostSystem

Moved the more robust character name selection code over.
Moved the TimeOfDeath code over.
Added canReturn logic.

* Add overrides and default for ghost spawn coordinates

* Add warning log to ghost spawn fail

* Clean up test

* Dont spawn ghost on map delete

* Minor changes to the role test

* Fix role test failing to spawn ghost

It was failing the map check due to using Nullspace

* Fix ghost tests when running in parallel

Not sure what happened, but it seems to be because they were running simultaneously and overwriting values.

* Clean up ghost tests

* Test that map deletion does not spawn ghosts

* Spawn ghost on the next available map

* Disallow spawning on deleted maps

* Fix map deletion ghost test

* Cleanup

---------

Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: ShadowCommander <shadowjjt@gmail.com>
This commit is contained in:
Aviu00
2024-06-25 21:39:44 +00:00
committed by GitHub
parent b6201631ae
commit 2fefca5f70
18 changed files with 460 additions and 131 deletions

View File

@@ -283,40 +283,18 @@ namespace Content.Server.GameTicking
}
}
var xformQuery = GetEntityQuery<TransformComponent>();
var coords = _transform.GetMoverCoordinates(position, xformQuery);
var ghost = Spawn(ObserverPrototypeName, coords);
// Try setting the ghost entity name to either the character name or the player name.
// If all else fails, it'll default to the default entity prototype name, "observer".
// However, that should rarely happen.
if (!string.IsNullOrWhiteSpace(mind.CharacterName))
_metaData.SetEntityName(ghost, mind.CharacterName);
else if (!string.IsNullOrWhiteSpace(mind.Session?.Name))
_metaData.SetEntityName(ghost, mind.Session.Name);
var ghostComponent = Comp<GhostComponent>(ghost);
if (mind.TimeOfDeath.HasValue)
{
_ghost.SetTimeOfDeath(ghost, mind.TimeOfDeath!.Value, ghostComponent);
}
var ghost = _ghost.SpawnGhost((mindId, mind), position, canReturn);
if (ghost == null)
return false;
if (playerEntity != null)
_adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}");
_ghost.SetCanReturnToBody(ghostComponent, canReturn);
if (canReturn)
_mind.Visit(mindId, ghost, mind);
else
_mind.TransferTo(mindId, ghost, mind: mind);
var player = mind.Session;
var userId = player?.UserId;
if (userId.HasValue && !_ghostSystem._deathTime.TryGetValue(userId.Value, out _))
_ghostSystem._deathTime[userId.Value] = _gameTiming.CurTime;
return true;
}

View File

@@ -9,6 +9,7 @@ using Content.Server.Speech.Components;
using Content.Server.Station.Components;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Mind;
using Content.Shared.Players;
using Content.Shared.Mind;
using Content.Shared.Preferences;
@@ -59,7 +60,9 @@ namespace Content.Server.GameTicking
return spawnableStations;
}
private void SpawnPlayers(List<ICommonSession> readyPlayers, Dictionary<NetUserId, HumanoidCharacterProfile> profiles, bool force)
private void SpawnPlayers(List<ICommonSession> readyPlayers,
Dictionary<NetUserId, HumanoidCharacterProfile> profiles,
bool force)
{
// Allow game rules to spawn players by themselves if needed. (For example, nuke ops or wizard)
RaiseLocalEvent(new RulePlayerSpawningEvent(readyPlayers, profiles, force));
@@ -120,10 +123,17 @@ namespace Content.Server.GameTicking
RefreshLateJoinAllowed();
// Allow rules to add roles to players who have been spawned in. (For example, on-station traitors)
RaiseLocalEvent(new RulePlayerJobsAssignedEvent(assignedJobs.Keys.Select(x => _playerManager.GetSessionById(x)).ToArray(), profiles, force));
RaiseLocalEvent(new RulePlayerJobsAssignedEvent(
assignedJobs.Keys.Select(x => _playerManager.GetSessionById(x)).ToArray(),
profiles,
force));
}
private void SpawnPlayer(ICommonSession player, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false)
private void SpawnPlayer(ICommonSession player,
EntityUid station,
string? jobId = null,
bool lateJoin = true,
bool silent = false)
{
var character = GetPlayerProfile(player);
@@ -136,7 +146,12 @@ namespace Content.Server.GameTicking
SpawnPlayer(player, character, station, jobId, lateJoin, silent);
}
private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile character, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false)
private void SpawnPlayer(ICommonSession player,
HumanoidCharacterProfile character,
EntityUid station,
string? jobId = null,
bool lateJoin = true,
bool silent = false)
{
// Can't spawn players with a dummy ticker!
if (DummyTicker)
@@ -244,7 +259,9 @@ namespace Content.Server.GameTicking
restrictedRoles.UnionWith(jobBans);
// Pick best job best on prefs.
jobId ??= _stationJobs.PickBestAvailableJobWithPriority(station, character.JobPriorities, true,
jobId ??= _stationJobs.PickBestAvailableJobWithPriority(station,
character.JobPriorities,
true,
restrictedRoles);
// If no job available, stay in lobby, or if no lobby spawn as observer
if (jobId is null)
@@ -253,7 +270,9 @@ namespace Content.Server.GameTicking
{
JoinAsObserver(player);
}
_chatManager.DispatchServerMessage(player, Loc.GetString("game-ticker-player-no-jobs-available-when-joining"));
_chatManager.DispatchServerMessage(player,
Loc.GetString("game-ticker-player-no-jobs-available-when-joining"));
return;
}
@@ -267,7 +286,7 @@ namespace Content.Server.GameTicking
_mind.SetUserId(newMind, data.UserId);
var jobPrototype = _prototypeManager.Index<JobPrototype>(jobId);
var job = new JobComponent { Prototype = jobId };
var job = new JobComponent {Prototype = jobId};
_roles.MindAddRole(newMind, job, silent: silent);
var jobName = _jobs.MindTryGetJobName(newMind);
@@ -311,12 +330,11 @@ namespace Content.Server.GameTicking
if (lateJoin && !silent)
{
_chatSystem.DispatchStationAnnouncement(station,
Loc.GetString(
"latejoin-arrival-announcement",
("character", MetaData(mob).EntityName),
Loc.GetString("latejoin-arrival-announcement",
("character", MetaData(mob).EntityName),
("gender", character.Gender), // WD-EDIT
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))
), Loc.GetString("latejoin-arrival-sender"),
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))),
Loc.GetString("latejoin-arrival-sender"),
playDefaultSound: false);
}
@@ -328,14 +346,17 @@ namespace Content.Server.GameTicking
_stationJobs.TryAssignJob(station, jobPrototype, player.UserId);
if (lateJoin)
_adminLogger.Add(LogType.LateJoin, LogImpact.Medium, $"Player {player.Name} late joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}.");
_adminLogger.Add(LogType.LateJoin,
LogImpact.Medium,
$"Player {player.Name} late joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}.");
else
_adminLogger.Add(LogType.RoundStartJoin, LogImpact.Medium, $"Player {player.Name} joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}.");
_adminLogger.Add(LogType.RoundStartJoin,
LogImpact.Medium,
$"Player {player.Name} joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}.");
// Make sure they're aware of extended access.
if (Comp<StationJobsComponent>(station).ExtendedAccess
&& (jobPrototype.ExtendedAccess.Count > 0
|| jobPrototype.ExtendedAccessGroups.Count > 0))
&& (jobPrototype.ExtendedAccess.Count > 0 || jobPrototype.ExtendedAccessGroups.Count > 0))
{
_chatManager.DispatchServerMessage(player, Loc.GetString("job-greet-crew-shortages"));
}
@@ -357,14 +378,20 @@ namespace Content.Server.GameTicking
}
else
{
_chatManager.DispatchServerMessage(player, Loc.GetString("latejoin-arrivals-direction-time",
("time", $"{arrival:mm\\:ss}")));
_chatManager.DispatchServerMessage(player,
Loc.GetString("latejoin-arrivals-direction-time", ("time", $"{arrival:mm\\:ss}")));
}
}
// We raise this event directed to the mob, but also broadcast it so game rules can do something now.
PlayersJoinedRoundNormally++;
var aev = new PlayerSpawnCompleteEvent(mob, player, jobId, lateJoin, PlayersJoinedRoundNormally, station, character);
var aev = new PlayerSpawnCompleteEvent(mob,
player,
jobId,
lateJoin,
PlayersJoinedRoundNormally,
station,
character);
RaiseLocalEvent(mob, aev, true);
}
@@ -485,32 +512,24 @@ namespace Content.Server.GameTicking
if (DummyTicker)
return;
var mind = player.GetMind();
Entity<MindComponent?>? mind = player.GetMind();
if (mind == null)
{
mind = _mind.CreateMind(player.UserId);
var name = GetPlayerProfile(player).Name;
var (mindId, mindComp) = _mind.CreateMind(player.UserId, name);
mind = (mindId, mindComp);
_mind.SetUserId(mind.Value, player.UserId);
_roles.MindAddRole(mind.Value, new ObserverRoleComponent());
}
var name = GetPlayerProfile(player).Name;
var ghost = SpawnObserverMob();
_metaData.SetEntityName(ghost, name);
_ghost.SetCanReturnToBody(ghost, false);
_mind.TransferTo(mind.Value, ghost);
_adminLogger.Add(LogType.LateJoin, LogImpact.Low, $"{player.Name} late joined the round as an Observer with {ToPrettyString(ghost):entity}.");
var ghost = _ghost.SpawnGhost(mind.Value);
_adminLogger.Add(LogType.LateJoin,
LogImpact.Low,
$"{player.Name} late joined the round as an Observer with {ToPrettyString(ghost):entity}.");
}
#region Mob Spawning Helpers
private EntityUid SpawnObserverMob()
{
var coordinates = GetObserverSpawnPoint();
return EntityManager.SpawnEntity(ObserverPrototypeName, coordinates);
}
#endregion
#region Spawn Points
public EntityCoordinates GetObserverSpawnPoint()
{
_possiblePositions.Clear();
@@ -531,8 +550,7 @@ namespace Content.Server.GameTicking
var query = AllEntityQuery<MapGridComponent>();
while (query.MoveNext(out var uid, out var grid))
{
if (!metaQuery.TryGetComponent(uid, out var meta) ||
meta.EntityPaused)
if (!metaQuery.TryGetComponent(uid, out var meta) || meta.EntityPaused || TerminatingOrDeleted(uid))
{
continue;
}
@@ -553,8 +571,7 @@ namespace Content.Server.GameTicking
{
var gridXform = Transform(gridUid);
return new EntityCoordinates(gridUid,
gridXform.InvWorldMatrix.Transform(toMap.Position));
return new EntityCoordinates(gridUid, gridXform.InvWorldMatrix.Transform(toMap.Position));
}
return spawn;
@@ -570,8 +587,9 @@ namespace Content.Server.GameTicking
{
var mapUid = _mapManager.GetMapEntityId(map);
if (!metaQuery.TryGetComponent(mapUid, out var meta) ||
meta.EntityPaused)
if (!metaQuery.TryGetComponent(mapUid, out var meta)
|| meta.EntityPaused
|| TerminatingOrDeleted(mapUid))
{
continue;
}
@@ -584,6 +602,7 @@ namespace Content.Server.GameTicking
_sawmill.Warning("Found no observer spawn points!");
return EntityCoordinates.Invalid;
}
#endregion
}
@@ -601,7 +620,11 @@ namespace Content.Server.GameTicking
public bool LateJoin { get; }
public EntityUid Station { get; }
public PlayerBeforeSpawnEvent(ICommonSession player, HumanoidCharacterProfile profile, string? jobId, bool lateJoin, EntityUid station)
public PlayerBeforeSpawnEvent(ICommonSession player,
HumanoidCharacterProfile profile,
string? jobId,
bool lateJoin,
EntityUid station)
{
Player = player;
Profile = profile;
@@ -629,7 +652,13 @@ namespace Content.Server.GameTicking
// Ex. If this is the 27th person to join, this will be 27.
public int JoinOrder { get; }
public PlayerSpawnCompleteEvent(EntityUid mob, ICommonSession player, string? jobId, bool lateJoin, int joinOrder, EntityUid station, HumanoidCharacterProfile profile)
public PlayerSpawnCompleteEvent(EntityUid mob,
ICommonSession player,
string? jobId,
bool lateJoin,
int joinOrder,
EntityUid station,
HumanoidCharacterProfile profile)
{
Mob = mob;
Player = player;