Skip to content

Commit

Permalink
[Port] Respawn Button / Кнопка Респавна (#56)
Browse files Browse the repository at this point in the history
* add: respawn button

* fix: Loc

* fix

* fix

* fix

* fix

* Update CVars.cs
  • Loading branch information
Spatison authored Sep 21, 2024
1 parent 6fb8e63 commit 4e0cb0b
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 15 deletions.
6 changes: 6 additions & 0 deletions Content.Client/Ghost/GhostSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,5 +181,11 @@ public void ToggleGhostVisibility()
{
GhostVisibility = !GhostVisibility;
}

public void ReturnToRound() // WD EDIT
{
var msg = new GhostReturnToRoundRequest();
RaiseNetworkEvent(msg);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public void LoadGui()
Gui.ReturnToBodyPressed += ReturnToBody;
Gui.GhostRolesPressed += GhostRolesPressed;
Gui.TargetWindow.WarpClicked += OnWarpClicked;
Gui.ReturnToRoundPressed += ReturnToRound; // WD EDIT

UpdateGui();
}
Expand All @@ -133,6 +134,7 @@ public void UnloadGui()
Gui.ReturnToBodyPressed -= ReturnToBody;
Gui.GhostRolesPressed -= GhostRolesPressed;
Gui.TargetWindow.WarpClicked -= OnWarpClicked;
Gui.ReturnToRoundPressed -= ReturnToRound; // WD EDIT

Gui.Hide();
}
Expand All @@ -142,6 +144,11 @@ private void ReturnToBody()
_system?.ReturnToBody();
}

private void ReturnToRound() // WD EDIT
{
_system?.ReturnToRound();
}

private void RequestWarps()
{
_system?.RequestWarps();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
<Button Name="ReturnToBodyButton" Text="{Loc ghost-gui-return-to-body-button}" />
<Button Name="GhostWarpButton" Text="{Loc ghost-gui-ghost-warp-button}" />
<Button Name="GhostRolesButton" />
<Button Name="ReturnToRound" Text="{Loc ghost-gui-return-to-round-button}" /> <!-- WD EDIT -->
</BoxContainer>
</widgets:GhostGui>
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public sealed partial class GhostGui : UIWidget
public event Action? RequestWarpsPressed;
public event Action? ReturnToBodyPressed;
public event Action? GhostRolesPressed;
public event Action? ReturnToRoundPressed; // WD EDIT

public GhostGui()
{
Expand All @@ -26,6 +27,7 @@ public GhostGui()
GhostWarpButton.OnPressed += _ => RequestWarpsPressed?.Invoke();
ReturnToBodyButton.OnPressed += _ => ReturnToBodyPressed?.Invoke();
GhostRolesButton.OnPressed += _ => GhostRolesPressed?.Invoke();
ReturnToRound.OnPressed += _ => ReturnToRoundPressed?.Invoke(); // WD EDIT
}

public void Hide()
Expand Down
3 changes: 3 additions & 0 deletions Content.Server/GameTicking/GameTicker.GamePreset.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;
using Content.Server._White.Ghost;
using Content.Server.GameTicking.Presets;
using Content.Server.Maps;
using Content.Shared.CCVar;
Expand All @@ -21,6 +22,7 @@ namespace Content.Server.GameTicking
public sealed partial class GameTicker
{
[Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
[Dependency] private readonly GhostReturnToRoundSystem _ghostReturnToRound = default!; // WD EDIT

public const float PresetFailedCooldownIncrease = 30f;

Expand Down Expand Up @@ -303,6 +305,7 @@ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaComma
_mind.Visit(mindId, ghost, mind);
else
_mind.TransferTo(mindId, ghost, mind: mind);

return true;
}

Expand Down
78 changes: 78 additions & 0 deletions Content.Server/GameTicking/GameTicker.Spawning.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
using Content.Server.Speech.Components;
using Content.Server.Station.Components;
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Database;
using Content.Shared.Mind;
using Content.Shared.Players;
using Content.Shared.Preferences;
using Content.Shared.Roles;
Expand Down Expand Up @@ -154,6 +156,22 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact
return;
}

//WD EDIT START
//Ghost system return to round, check for whether the character isn't the same.
if (lateJoin && !_adminManager.IsAdmin(player) && !CheckGhostReturnToRound(player, character, out var checkAvoid))
{
var message = checkAvoid
? Loc.GetString("ghost-respawn-same-character-slightly-changed-name")
: Loc.GetString("ghost-respawn-same-character");
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));

_chatManager.ChatMessageToOne(ChatChannel.Server, message, wrappedMessage,
default, false, player.Channel, Color.Red);

return;
}
//WD EDIT END

// We raise this event to allow other systems to handle spawning this player themselves. (e.g. late-join wizard, etc)
var bev = new PlayerBeforeSpawnEvent(player, character, jobId, lateJoin, station);
RaiseLocalEvent(bev);
Expand Down Expand Up @@ -346,6 +364,66 @@ public void SpawnObserver(ICommonSession player)
_adminLogger.Add(LogType.LateJoin, LogImpact.Low, $"{player.Name} late joined the round as an Observer with {ToPrettyString(ghost):entity}.");
}

//WD EDIT START
private bool CheckGhostReturnToRound(ICommonSession player, HumanoidCharacterProfile character, out bool checkAvoid)
{
checkAvoid = false;

var allPlayerMinds = EntityQuery<MindComponent>()
.Where(mind => mind.OriginalOwnerUserId == player.UserId);

foreach (var mind in allPlayerMinds)
{
if (mind.CharacterName == character.Name)
return false;

if (mind.CharacterName == null)
continue;

var similarity = CalculateStringSimilarity(mind.CharacterName, character.Name);
switch (similarity)
{
case >= 85f:
{
_chatManager.SendAdminAlert(Loc.GetString("ghost-respawn-log-character-almost-same",
("player", player.Name), ("try", false), ("oldName", mind.CharacterName),
("newName", character.Name)));
checkAvoid = true;

return false;
}
case >= 50f:
{
_chatManager.SendAdminAlert(Loc.GetString("ghost-respawn-log-character-almost-same",
("player", player.Name), ("try", true), ("oldName", mind.CharacterName),
("newName", character.Name)));

break;
}
}
}

return true;
}

private float CalculateStringSimilarity(string str1, string str2)
{
var minLength = Math.Min(str1.Length, str2.Length);
var matchingCharacters = 0;

for (var i = 0; i < minLength; i++)
{
if (str1[i] == str2[i])
matchingCharacters++;
}

float maxLength = Math.Max(str1.Length, str2.Length);
var similarityPercentage = (matchingCharacters / maxLength) * 100;

return similarityPercentage;
}
//WD EDIT END

#region Mob Spawning Helpers
private EntityUid SpawnObserverMob()
{
Expand Down
81 changes: 81 additions & 0 deletions Content.Server/_White/Ghost/GhostReturnToRoundSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using Content.Server.Administration.Logs;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Shared._White;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Ghost;
using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Timing;

namespace Content.Server._White.Ghost;

public sealed class GhostReturnToRoundSystem : EntitySystem
{
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;

public override void Initialize()
{
SubscribeNetworkEvent<GhostReturnToRoundRequest>(OnGhostReturnToRoundRequest);
}

private void OnGhostReturnToRoundRequest(GhostReturnToRoundRequest msg, EntitySessionEventArgs args)
{
var uid = args.SenderSession.AttachedEntity;

if (uid == null)
return;

var connectedClient = args.SenderSession.ConnectedClient;
var userId = args.SenderSession.UserId;

TryGhostReturnToRound(uid.Value, connectedClient, userId, out var message, out var wrappedMessage);

_chatManager.ChatMessageToOne(Shared.Chat.ChatChannel.Server,
message,
wrappedMessage,
default,
false,
connectedClient,
Color.Red);
}

private void TryGhostReturnToRound(EntityUid uid, INetChannel connectedClient, NetUserId userId, out string message, out string wrappedMessage)
{
var maxPlayers = _cfg.GetCVar(WhiteCVars.GhostRespawnMaxPlayers);
if (_playerManager.PlayerCount >= maxPlayers)
{
message = Loc.GetString("ghost-respawn-max-players", ("players", maxPlayers));
wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
return;
}

var deathTime = EnsureComp<GhostComponent>(uid).TimeOfDeath;
var timeUntilRespawn = _cfg.GetCVar(WhiteCVars.GhostRespawnTime);
var timePast = (_gameTiming.CurTime - deathTime).TotalMinutes;
if (timePast >= timeUntilRespawn)
{
var ticker = Get<GameTicker>();
_playerManager.TryGetSessionById(userId, out var targetPlayer);

if (targetPlayer != null)
ticker.Respawn(targetPlayer);

_adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{Loc.GetString("ghost-respawn-log-return-to-lobby", ("userName", connectedClient.UserName))}");

message = Loc.GetString("ghost-respawn-window-rules-footer");
wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));

return;
}

message = Loc.GetString("ghost-respawn-time-left", ("time", (int) (timeUntilRespawn - timePast)));
wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
}
}
5 changes: 5 additions & 0 deletions Content.Shared/Ghost/SharedGhostSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,9 @@ public GhostUpdateGhostRoleCountEvent(int availableGhostRoleCount)
AvailableGhostRoles = availableGhostRoleCount;
}
}

// WD EDIT START
[Serializable, NetSerializable]
public sealed class GhostReturnToRoundRequest : EntityEventArgs;
// WD EDIT END
}
9 changes: 9 additions & 0 deletions Content.Shared/_White/CVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ public static readonly CVarDef<string>

#endregion

#region GhostRespawn
public static readonly CVarDef<double> GhostRespawnTime =
CVarDef.Create("ghost.respawn_time", 15d, CVar.SERVERONLY);

public static readonly CVarDef<int> GhostRespawnMaxPlayers =
CVarDef.Create("ghost.respawn_max_players", 40, CVar.SERVERONLY);

#endregion

#region OptionsMisc

public static readonly CVarDef<bool> LogInChat =
Expand Down
1 change: 1 addition & 0 deletions Resources/Locale/en-US/_white/ghost/ghost-gui.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ghost-gui-return-to-round-button = Return to round
15 changes: 15 additions & 0 deletions Resources/Locale/en-US/_white/ghost/ghost-respawn.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ghost-respawn-time-left = Before the opportunity to return to the round { $time }
{ $time ->
[one] minute
*[other] minutes
}
ghost-respawn-max-players = The function is not available, there should be fewer players on the server { $players }.
ghost-respawn-window-title = Rules for returning to the round
ghost-respawn-window-rules-footer = By using this feature, you [color=#ff7700]agree[/color] [color=#ff0000]not to transfer[/color] the knowledge of your past character to a new one. For violation of the clause specified here, [color=#ff0000]a ban in the amount of 3 days or more follows[/color].
ghost-respawn-same-character = You cannot enter the round for the same character. Change it in the character settings.
ghost-respawn-log-character-almost-same = Player { $player } { $try ->
[true] join
*[false] tried to join
} in the round after the respawn with a similar name. Past name: { $oldName }, current: { $newName }.
ghost-respawn-log-return-to-lobby = { $userName } returned to the lobby.
1 change: 1 addition & 0 deletions Resources/Locale/ru-RU/_white/ghost/ghost-gui.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ghost-gui-return-to-round-button = Вернуться в раунд
16 changes: 16 additions & 0 deletions Resources/Locale/ru-RU/_white/ghost/ghost-respawn.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
ghost-respawn-time-left = До возможности вернуться в раунд { $time }
{ $time ->
[one] минута
[few] минуты
*[other] минут
}
ghost-respawn-max-players = Функция недоступна, игроков на сервере должно быть меньше { $players }.
ghost-respawn-window-title = Правила возвращения в раунд
ghost-respawn-window-rules-footer = Пользуясь это функцией, вы [color=#ff7700]обязуетесь[/color] [color=#ff0000]не переносить[/color] знания своего прошлого персонажа в нового. За нарушение пункта, указанного здесь, следует [color=#ff0000]бан в размере от 3-ех дней[/color].
ghost-respawn-same-character = Нельзя заходить в раунд за того же персонажа. Поменяйте его в настройках персонажей.
ghost-respawn-log-character-almost-same = Игрок { $player } { $try ->
[true] зашёл
*[false] попытался зайти
} в раунд после возвращения в лобби с похожим именем. Прошлое имя: { $oldName }, текущее: { $newName }.
ghost-respawn-log-return-to-lobby = { $userName } вернулся в лобби.
16 changes: 1 addition & 15 deletions Resources/Locale/ru-RU/ghost/ghost-gui.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,4 @@ ghost-roles-window-no-roles-available-label = В настоящее время
ghost-return-to-body-title = Вернуться в тело
ghost-return-to-body-text = Вы возрождаетесь! Вернуться в свое тело?
ghost-roles-window-rules-footer = Кнопка станет доступна через { $time } секунд (эта задержка нужна, чтобы убедиться, что вы прочитали правила).
ghost-respawn-time-left = Минут осталось до возможности вернуться в раунд - { $time }.
ghost-respawn-max-players = Функция недоступна, игроков на сервере должно быть меньше { $players }.
ghost-respawn-window-title = Правила возвращения в раунд
ghost-respawn-window-request-button-timer = Принять ({ $time }сек.)
ghost-respawn-window-request-button = Принять
ghost-respawn-window-rules-footer = Пользуясь это функцией, вы [color=#ff7700]обязуетесь[/color] [color=#ff0000]не переносить[/color] знания своего прошлого персонажа в нового, [color=#ff0000]не метамстить[/color]. Каждый новый персонаж - [color=#ff7700]чистый уникальный лист[/color], который никак не связан с предыдущим. Поэтому не забудьте [color=#ff7700]поменять персонажа[/color] перед заходом, а также помните, что за нарушение пункта, указанного здесь, следует [color=#ff0000]бан в размере от 3ех дней[/color].
ghost-respawn-bug = Нет времени смерти. Установлено стандартное значение.
ghost-respawn-same-character = Нельзя заходить в раунд за того же персонажа. Поменяйте его в настройках персонажей.
ghost-respawn-character-almost-same = Игрок { $player } { $try ->
[true] зашёл
*[false] попытался зайти
} в раунд после респауна с похожим именем. Прошлое имя: { $oldName }, текущее: { $newName }.
ghost-respawn-same-character-slightly-changed-name = Попытка обойти запрет входа в раунд тем же персонажем. Ваши действия будут переданы администрации!
ghost-roles-window-rules-footer = Кнопка станет доступна через { $time } секунд (эта задержка нужна, чтобы убедиться, что вы прочитали правила).

0 comments on commit 4e0cb0b

Please sign in to comment.