Player post-spawn hook and player ghosting controlled by preset (#2734)
* GamePreset: Add a hook to catch all player spawns for modification. Unless someone makes the entire job system unpluggable, this is what you get... * GamePreset: Is now in control of voluntary ghosting * Clean up ghost code to only rely on a player's Mind
This commit is contained in:
@@ -3,7 +3,9 @@ using System.Collections.Generic;
|
|||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Content.Server.Mobs;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -49,6 +51,11 @@ namespace Content.IntegrationTests
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnGhostAttempt(Mind mind, bool canReturnGlobal)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public void MakeObserve(IPlayerSession player)
|
public void MakeObserve(IPlayerSession player)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,71 +27,22 @@ namespace Content.Server.Commands.Observer
|
|||||||
{
|
{
|
||||||
if (player == null)
|
if (player == null)
|
||||||
{
|
{
|
||||||
shell.SendText(player, "Nah");
|
shell?.SendText(player, "You have no session, you can't ghost.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var mind = player.ContentData()?.Mind;
|
var mind = player!.ContentData()?.Mind;
|
||||||
|
|
||||||
if (mind == null)
|
if (mind == null)
|
||||||
{
|
{
|
||||||
shell.SendText(player, "You can't ghost here!");
|
shell?.SendText(player, "You have no Mind, you can't ghost.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerEntity = player.AttachedEntity;
|
if (!IoCManager.Resolve<IGameTicker>().OnGhostAttempt(mind, CanReturn))
|
||||||
|
{
|
||||||
if (playerEntity != null && playerEntity.HasComponent<GhostComponent>())
|
shell?.SendText(player, "You can't ghost right now.");
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mind.VisitingEntity != null)
|
|
||||||
{
|
|
||||||
mind.UnVisit();
|
|
||||||
mind.VisitingEntity.Delete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var position = playerEntity?.Transform.Coordinates ?? IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint();
|
|
||||||
var canReturn = false;
|
|
||||||
|
|
||||||
if (playerEntity != null && CanReturn && playerEntity.TryGetComponent(out IMobStateComponent? mobState))
|
|
||||||
{
|
|
||||||
if (mobState.IsDead())
|
|
||||||
{
|
|
||||||
canReturn = true;
|
|
||||||
}
|
|
||||||
else if (mobState.IsCritical())
|
|
||||||
{
|
|
||||||
canReturn = true;
|
|
||||||
|
|
||||||
if (playerEntity.TryGetComponent(out IDamageableComponent? damageable))
|
|
||||||
{
|
|
||||||
//todo: what if they dont breathe lol
|
|
||||||
damageable.ChangeDamage(DamageType.Asphyxiation, 100, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
canReturn = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
|
||||||
var ghost = entityManager.SpawnEntity("MobObserver", position);
|
|
||||||
ghost.Name = mind.CharacterName;
|
|
||||||
|
|
||||||
var ghostComponent = ghost.GetComponent<GhostComponent>();
|
|
||||||
ghostComponent.CanReturnToBody = canReturn;
|
|
||||||
|
|
||||||
if (playerEntity != null &&
|
|
||||||
playerEntity.TryGetComponent(out ServerOverlayEffectsComponent? overlayComponent))
|
|
||||||
{
|
|
||||||
overlayComponent.RemoveOverlay(SharedOverlayID.CircleMaskOverlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canReturn)
|
|
||||||
mind.Visit(ghost);
|
|
||||||
else
|
|
||||||
mind.TransferTo(ghost);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,21 @@
|
|||||||
|
#nullable enable annotations
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.GameObjects.Components.Mobs;
|
||||||
|
using Content.Server.GameObjects.Components.Observer;
|
||||||
|
using Content.Server.Interfaces.GameTicking;
|
||||||
|
using Content.Server.Players;
|
||||||
|
using Content.Server.Mobs;
|
||||||
|
using Content.Shared.Damage;
|
||||||
|
using Content.Shared.GameObjects.Components.Damage;
|
||||||
|
using Content.Shared.GameObjects.Components.Mobs;
|
||||||
|
using Content.Shared.GameObjects.Components.Mobs.State;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking
|
namespace Content.Server.GameTicking
|
||||||
{
|
{
|
||||||
@@ -18,6 +32,72 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
public virtual void OnGameStarted() { }
|
public virtual void OnGameStarted() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a player is spawned in (this includes, but is not limited to, before Start)
|
||||||
|
/// </summary>
|
||||||
|
public virtual void OnSpawnPlayerCompleted(IPlayerSession session, IEntity mob, bool lateJoin) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when a player attempts to ghost.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool OnGhostAttempt(Mind mind, bool canReturnGlobal)
|
||||||
|
{
|
||||||
|
var playerEntity = mind.OwnedEntity;
|
||||||
|
|
||||||
|
if (playerEntity != null && playerEntity.HasComponent<GhostComponent>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (mind.VisitingEntity != null)
|
||||||
|
{
|
||||||
|
mind.UnVisit();
|
||||||
|
mind.VisitingEntity.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = playerEntity?.Transform.Coordinates ?? IoCManager.Resolve<IGameTicker>().GetObserverSpawnPoint();
|
||||||
|
var canReturn = false;
|
||||||
|
|
||||||
|
if (playerEntity != null && canReturnGlobal && playerEntity.TryGetComponent(out IMobStateComponent? mobState))
|
||||||
|
{
|
||||||
|
if (mobState.IsDead())
|
||||||
|
{
|
||||||
|
canReturn = true;
|
||||||
|
}
|
||||||
|
else if (mobState.IsCritical())
|
||||||
|
{
|
||||||
|
canReturn = true;
|
||||||
|
|
||||||
|
if (playerEntity.TryGetComponent(out IDamageableComponent? damageable))
|
||||||
|
{
|
||||||
|
//todo: what if they dont breathe lol
|
||||||
|
damageable.ChangeDamage(DamageType.Asphyxiation, 100, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
canReturn = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
var ghost = entityManager.SpawnEntity("MobObserver", position);
|
||||||
|
ghost.Name = mind.CharacterName;
|
||||||
|
|
||||||
|
var ghostComponent = ghost.GetComponent<GhostComponent>();
|
||||||
|
ghostComponent.CanReturnToBody = canReturn;
|
||||||
|
|
||||||
|
if (playerEntity != null &&
|
||||||
|
playerEntity.TryGetComponent(out ServerOverlayEffectsComponent? overlayComponent))
|
||||||
|
{
|
||||||
|
overlayComponent.RemoveOverlay(SharedOverlayID.CircleMaskOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canReturn)
|
||||||
|
mind.Visit(ghost);
|
||||||
|
else
|
||||||
|
mind.TransferTo(ghost);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public virtual string GetRoundEndDescription() => "";
|
public virtual string GetRoundEndDescription() => "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ using Robust.Server.Interfaces.Maps;
|
|||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Server.ServerStatus;
|
using Robust.Server.ServerStatus;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Interfaces.Configuration;
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
@@ -440,6 +441,11 @@ namespace Content.Server.GameTicking
|
|||||||
UpdateJobsAvailable();
|
UpdateJobsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnGhostAttempt(Mind mind, bool canReturnGlobal)
|
||||||
|
{
|
||||||
|
return Preset.OnGhostAttempt(mind, canReturnGlobal);
|
||||||
|
}
|
||||||
|
|
||||||
public T AddGameRule<T>() where T : GameRule, new()
|
public T AddGameRule<T>() where T : GameRule, new()
|
||||||
{
|
{
|
||||||
var instance = _dynamicTypeFactory.CreateInstance<T>();
|
var instance = _dynamicTypeFactory.CreateInstance<T>();
|
||||||
@@ -887,6 +893,8 @@ namespace Content.Server.GameTicking
|
|||||||
AddSpawnedPosition(jobId);
|
AddSpawnedPosition(jobId);
|
||||||
EquipIdCard(mob, character.Name, jobPrototype);
|
EquipIdCard(mob, character.Name, jobPrototype);
|
||||||
jobPrototype.Special?.AfterEquip(mob);
|
jobPrototype.Special?.AfterEquip(mob);
|
||||||
|
|
||||||
|
Preset.OnSpawnPlayerCompleted(session, mob, lateJoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EquipIdCard(IEntity mob, string characterName, JobPrototype jobPrototype)
|
private void EquipIdCard(IEntity mob, string characterName, JobPrototype jobPrototype)
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
|
using Content.Server.Mobs;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -42,6 +44,9 @@ namespace Content.Server.Interfaces.GameTicking
|
|||||||
void ToggleReady(IPlayerSession player, bool ready);
|
void ToggleReady(IPlayerSession player, bool ready);
|
||||||
void ToggleDisallowLateJoin(bool disallowLateJoin);
|
void ToggleDisallowLateJoin(bool disallowLateJoin);
|
||||||
|
|
||||||
|
/// <summary>proxy to GamePreset (actual handler)</summary>
|
||||||
|
bool OnGhostAttempt(Mind mind, bool canReturnGlobal);
|
||||||
|
|
||||||
EntityCoordinates GetLateJoinSpawnPoint();
|
EntityCoordinates GetLateJoinSpawnPoint();
|
||||||
EntityCoordinates GetJobSpawnPoint(string jobId);
|
EntityCoordinates GetJobSpawnPoint(string jobId);
|
||||||
EntityCoordinates GetObserverSpawnPoint();
|
EntityCoordinates GetObserverSpawnPoint();
|
||||||
|
|||||||
Reference in New Issue
Block a user