|
8 | 8 | using Content.Server.Station.Components; |
9 | 9 | using Content.Shared.Database; |
10 | 10 | using Content.Shared.GameTicking; |
| 11 | +using Content.Shared.CCVar; |
| 12 | +using Content.Shared.Chat; |
| 13 | +using Content.Shared.Database; |
11 | 14 | using Content.Shared.Mind; |
12 | 15 | using Content.Shared.Players; |
13 | 16 | using Content.Shared.Preferences; |
@@ -174,6 +177,20 @@ private void SpawnPlayer(ICommonSession player, |
174 | 177 | return; |
175 | 178 | } |
176 | 179 |
|
| 180 | + //Ghost system return to round, check for whether the character isn't the same. |
| 181 | + if (!_cfg.GetCVar(CCVars.GhostAllowSameCharacter) && lateJoin && !_adminManager.IsAdmin(player) && !CheckGhostReturnToRound(player, character, out var checkAvoid)) |
| 182 | + { |
| 183 | + var message = checkAvoid |
| 184 | + ? Loc.GetString("ghost-respawn-same-character-slightly-changed-name") |
| 185 | + : Loc.GetString("ghost-respawn-same-character"); |
| 186 | + var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message)); |
| 187 | + |
| 188 | + _chatManager.ChatMessageToOne(ChatChannel.Server, message, wrappedMessage, |
| 189 | + default, false, player.Channel, Color.Red); |
| 190 | + |
| 191 | + return; |
| 192 | + } |
| 193 | + |
177 | 194 | // We raise this event to allow other systems to handle spawning this player themselves. (e.g. late-join wizard, etc) |
178 | 195 | var bev = new PlayerBeforeSpawnEvent(player, character, jobId, lateJoin, station); |
179 | 196 | RaiseLocalEvent(bev); |
@@ -371,6 +388,68 @@ public void SpawnObserver(ICommonSession player) |
371 | 388 | $"{player.Name} late joined the round as an Observer with {ToPrettyString(ghost):entity}."); |
372 | 389 | } |
373 | 390 |
|
| 391 | + private bool CheckGhostReturnToRound(ICommonSession player, HumanoidCharacterProfile character, out bool checkAvoid) |
| 392 | + { |
| 393 | + checkAvoid = false; |
| 394 | + |
| 395 | + var allPlayerMinds = EntityQuery<MindComponent>() |
| 396 | + .Where(mind => mind.OriginalOwnerUserId == player.UserId); |
| 397 | + |
| 398 | + foreach (var mind in allPlayerMinds) |
| 399 | + { |
| 400 | + if (mind.CharacterName == character.Name) |
| 401 | + return false; |
| 402 | + |
| 403 | + if (mind.CharacterName == null) |
| 404 | + continue; |
| 405 | + |
| 406 | + var similarity = CalculateStringSimilarity(mind.CharacterName, character.Name); |
| 407 | + switch (similarity) |
| 408 | + { |
| 409 | + case >= 85f: |
| 410 | + _chatManager.SendAdminAlert(Loc.GetString("ghost-respawn-log-character-almost-same", |
| 411 | + ("player", player.Name), ("try", false), ("oldName", mind.CharacterName), |
| 412 | + ("newName", character.Name))); |
| 413 | + checkAvoid = true; |
| 414 | + |
| 415 | + return false; |
| 416 | + case >= 50f: |
| 417 | + _chatManager.SendAdminAlert(Loc.GetString("ghost-respawn-log-character-almost-same", |
| 418 | + ("player", player.Name), ("try", true), ("oldName", mind.CharacterName), |
| 419 | + ("newName", character.Name))); |
| 420 | + |
| 421 | + break; |
| 422 | + } |
| 423 | + } |
| 424 | + |
| 425 | + return true; |
| 426 | + } |
| 427 | + |
| 428 | + private float CalculateStringSimilarity(string str1, string str2) |
| 429 | + { |
| 430 | + var minLength = Math.Min(str1.Length, str2.Length); |
| 431 | + var matchingCharacters = 0; |
| 432 | + |
| 433 | + for (var i = 0; i < minLength; i++) |
| 434 | + { |
| 435 | + if (str1[i] == str2[i]) |
| 436 | + matchingCharacters++; |
| 437 | + } |
| 438 | + |
| 439 | + float maxLength = Math.Max(str1.Length, str2.Length); |
| 440 | + var similarityPercentage = (matchingCharacters / maxLength) * 100; |
| 441 | + |
| 442 | + return similarityPercentage; |
| 443 | + } |
| 444 | + |
| 445 | + #region Mob Spawning Helpers |
| 446 | + private EntityUid SpawnObserverMob() |
| 447 | + { |
| 448 | + var coordinates = GetObserverSpawnPoint(); |
| 449 | + return EntityManager.SpawnEntity(ObserverPrototypeName, coordinates); |
| 450 | + } |
| 451 | + #endregion |
| 452 | + |
374 | 453 | #region Spawn Points |
375 | 454 |
|
376 | 455 | public EntityCoordinates GetObserverSpawnPoint() |
|
0 commit comments