Skip to content

Commit

Permalink
Save round information into replay_final.yml (space-wizards#23013)
Browse files Browse the repository at this point in the history
* Save round information into the replay

* Add round end text too

* This is way better

* Get actual job

* oop

* OK THERE

* Fake line endings to make life easier

* I was told this yaml is legal

* I just realised this will make my life easier

* REVIEWS BABY IM A PROGRAMMER MOMMY

* Live pjb reaction

* Live pjb reaction 2

* Reviews 2

* Dont need this

* Please no more have mercy on my soul

* Oh frick
  • Loading branch information
VasilisThePikachu authored and joshepvodka committed Feb 18, 2024
1 parent 5e06b76 commit d5ed348
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 7 deletions.
21 changes: 21 additions & 0 deletions Content.Server/GameTicking/GameTicker.Replays.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
using Robust.Shared;
using Robust.Shared.ContentPack;
using Robust.Shared.Replays;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.Markdown;
using Robust.Shared.Serialization.Markdown.Mapping;
using Robust.Shared.Serialization.Markdown.Value;
using Robust.Shared.Utility;

namespace Content.Server.GameTicking;
Expand All @@ -10,12 +14,15 @@ public sealed partial class GameTicker
{
[Dependency] private readonly IReplayRecordingManager _replays = default!;
[Dependency] private readonly IResourceManager _resourceManager = default!;
[Dependency] private readonly ISerializationManager _serialman = default!;


private ISawmill _sawmillReplays = default!;

private void InitializeReplays()
{
_replays.RecordingFinished += ReplaysOnRecordingFinished;
_replays.RecordingStopped += ReplaysOnRecordingStopped;
}

/// <summary>
Expand Down Expand Up @@ -108,6 +115,20 @@ private void ReplaysOnRecordingFinished(ReplayRecordingFinished data)
data.Directory.Rename(data.Path, state.MoveToPath.Value);
}

private void ReplaysOnRecordingStopped(MappingDataNode metadata)
{
// Write round info like map and round end summery into the replay_final.yml file. Useful for external parsers.

metadata["map"] = new ValueDataNode(_gameMapManager.GetSelectedMap()?.MapName);
metadata["gamemode"] = new ValueDataNode(CurrentPreset != null ? Loc.GetString(CurrentPreset.ModeTitle) : string.Empty);
metadata["roundEndPlayers"] = _serialman.WriteValue(_replayRoundPlayerInfo);
metadata["roundEndText"] = new ValueDataNode(_replayRoundText);
metadata["server_id"] = new ValueDataNode(_configurationManager.GetCVar(CCVars.ServerId));
// These should be set to null to prepare them for the next round.
_replayRoundPlayerInfo = null;
_replayRoundText = null;
}

private ResPath GetAutoReplayPath()
{
var cfgValue = _cfg.GetCVar(CCVars.ReplayAutoRecordName);
Expand Down
10 changes: 10 additions & 0 deletions Content.Server/GameTicking/GameTicker.RoundFlow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public sealed partial class GameTicker
[ViewVariables]
private GameRunLevel _runLevel;

private RoundEndMessageEvent.RoundEndPlayerInfo[]? _replayRoundPlayerInfo;

private string? _replayRoundText;

[ViewVariables]
public GameRunLevel RunLevel
{
Expand Down Expand Up @@ -372,11 +376,14 @@ public void ShowRoundEndScoreboard(string text = "")
PlayerOOCName = contentPlayerData?.Name ?? "(IMPOSSIBLE: REGISTERED MIND WITH NO OWNER)",
// Character name takes precedence over current entity name
PlayerICName = playerIcName,
PlayerGuid = userId,
PlayerNetEntity = GetNetEntity(entity),
Role = antag
? roles.First(role => role.Antagonist).Name
: roles.FirstOrDefault().Name ?? Loc.GetString("game-ticker-unknown-role"),
Antag = antag,
JobPrototypes = roles.Where(role => !role.Antagonist).Select(role => role.Prototype).ToArray(),
AntagPrototypes = roles.Where(role => role.Antagonist).Select(role => role.Prototype).ToArray(),
Observer = observer,
Connected = connected
};
Expand All @@ -389,6 +396,9 @@ public void ShowRoundEndScoreboard(string text = "")

RaiseNetworkEvent(new RoundEndMessageEvent(gamemodeTitle, roundEndText, roundDuration, RoundId,
listOfPlayerInfoFinal.Length, listOfPlayerInfoFinal, LobbySong, sound));

_replayRoundPlayerInfo = listOfPlayerInfoFinal;
_replayRoundText = roundEndText;
}

private async void SendRoundEndDiscordMessage()
Expand Down
28 changes: 24 additions & 4 deletions Content.Shared/GameTicking/SharedGameTicker.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Content.Shared.Roles;
using Robust.Shared.Network;
using Robust.Shared.Replays;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Markdown.Mapping;
Expand Down Expand Up @@ -144,18 +145,37 @@ public TickerJobsAvailableEvent(Dictionary<NetEntity, string> stationNames, Dict
}
}

[Serializable, NetSerializable]
public sealed class RoundEndMessageEvent : EntityEventArgs
[Serializable, NetSerializable, DataDefinition]
public sealed partial class RoundEndMessageEvent : EntityEventArgs
{
[Serializable, NetSerializable]
public struct RoundEndPlayerInfo
[Serializable, NetSerializable, DataDefinition]
public partial struct RoundEndPlayerInfo
{
[DataField]
public string PlayerOOCName;

[DataField]
public string? PlayerICName;

[DataField, NonSerialized]
public NetUserId? PlayerGuid;

public string Role;

[DataField, NonSerialized]
public string[] JobPrototypes;

[DataField, NonSerialized]
public string[] AntagPrototypes;

public NetEntity? PlayerNetEntity;

[DataField]
public bool Antag;

[DataField]
public bool Observer;

public bool Connected;
}

Expand Down
3 changes: 2 additions & 1 deletion Content.Shared/Roles/MindGetAllRolesEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ namespace Content.Shared.Roles;
/// <param name="Name">Name of the role.</param>
/// <param name="Antagonist">Whether or not this role makes this player an antagonist.</param>
/// <param name="PlayTimeTrackerId">The <see cref="PlayTimeTrackerPrototype"/> id associated with the role.</param>
public readonly record struct RoleInfo(Component Component, string Name, bool Antagonist, string? PlayTimeTrackerId);
/// <param name="Prototype">The prototype ID of the role</param>
public readonly record struct RoleInfo(Component Component, string Name, bool Antagonist, string? PlayTimeTrackerId, string Prototype);
8 changes: 6 additions & 2 deletions Content.Shared/Roles/SharedRoleSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,30 +27,34 @@ public override void Initialize()
private void OnJobGetAllRoles(EntityUid uid, JobComponent component, ref MindGetAllRolesEvent args)
{
var name = "game-ticker-unknown-role";
var prototype = "";
string? playTimeTracker = null;
if (component.Prototype != null && _prototypes.TryIndex(component.Prototype, out JobPrototype? job))
{
name = job.Name;
prototype = job.ID;
playTimeTracker = job.PlayTimeTracker;
}

name = Loc.GetString(name);

args.Roles.Add(new RoleInfo(component, name, false, playTimeTracker));
args.Roles.Add(new RoleInfo(component, name, false, playTimeTracker, prototype));
}

protected void SubscribeAntagEvents<T>() where T : AntagonistRoleComponent
{
SubscribeLocalEvent((EntityUid _, T component, ref MindGetAllRolesEvent args) =>
{
var name = "game-ticker-unknown-role";
var prototype = "";
if (component.PrototypeId != null && _prototypes.TryIndex(component.PrototypeId, out AntagPrototype? antag))
{
name = antag.Name;
prototype = antag.ID;
}
name = Loc.GetString(name);
args.Roles.Add(new RoleInfo(component, name, true, null));
args.Roles.Add(new RoleInfo(component, name, true, null, prototype));
});

SubscribeLocalEvent((EntityUid _, T _, ref MindIsAntagonistEvent args) => args.IsAntagonist = true);
Expand Down

0 comments on commit d5ed348

Please sign in to comment.