Skip to content

Commit

Permalink
fix: only parse time & seeking from TagPackets for Hide&Seek or Sardines
Browse files Browse the repository at this point in the history
Freeze-Tag uses the same `UpdateType` flags for some of its `TagPacket`s as H&S and Sardines do.
But Freeze-Tag has another packet data structure that isn't matching IsIt, Seconds and Minutes.
Therefore the server wrongly interprets Freeze-Tag packets and updates its "seeking" and "time" metadata wrongly.
(These metadata fields are used to resend the `TagPacket` to later joining clients.)

This commit does the following changes:
- add: game mode detection in the first 4 bit of the `TagPacket.UpdateType`
- change: parse the `TagPacket` for the metadata iff it is clearly for H&S or Sardines
- change: only resend `TagPacket` to new clients for H&S or Sardines
  • Loading branch information
Istador committed Oct 13, 2024
1 parent 189ac2d commit 765af57
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 12 deletions.
10 changes: 10 additions & 0 deletions Server/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public async Task Send(Memory<byte> data, Client? sender) {

public void CleanMetadataOnNewConnection() {
object? tmp;
Metadata.TryRemove("gameMode", out tmp);
Metadata.TryRemove("time", out tmp);
Metadata.TryRemove("seeking", out tmp);
Metadata.TryRemove("lastCostumePacket", out tmp);
Expand All @@ -101,10 +102,19 @@ public void CleanMetadataOnNewConnection() {
}

public TagPacket? GetTagPacket() {
var gmode = (GameMode?) (this.Metadata.ContainsKey("gameMode") ? this.Metadata["gameMode"] : null);
if (gmode == null) { return null; }
if ( gmode != GameMode.Legacy
&& gmode != GameMode.HideAndSeek
&& gmode != GameMode.Sardines
) { return null; }

var time = (Time?) (this.Metadata.ContainsKey("time") ? this.Metadata["time"] : null);
var seek = (bool?) (this.Metadata.ContainsKey("seeking") ? this.Metadata["seeking"] : null);
if (time == null && seek == null) { return null; }

return new TagPacket {
GameMode = (GameMode) gmode,
UpdateType = (seek != null ? TagPacket.TagUpdate.State : 0) | (time != null ? TagPacket.TagUpdate.Time: 0),
IsIt = seek ?? false,
Seconds = (byte) (time?.Seconds ?? 0),
Expand Down
25 changes: 21 additions & 4 deletions Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,23 @@ void logError(Task x) {
}

case TagPacket tagPacket: {
// c.Logger.Info($"Got tag packet: {tagPacket.IsIt}");
if ((tagPacket.UpdateType & TagPacket.TagUpdate.State) != 0) c.Metadata["seeking"] = tagPacket.IsIt;
if ((tagPacket.UpdateType & TagPacket.TagUpdate.Time) != 0)
c.Metadata["time"] = new Time(tagPacket.Minutes, tagPacket.Seconds, DateTime.Now);
if ( (tagPacket.GameMode == GameMode.Legacy && tagPacket.UpdateType == TagPacket.TagUpdate.Both)
|| tagPacket.GameMode == GameMode.HideAndSeek
|| tagPacket.GameMode == GameMode.Sardines
) {
// c.Logger.Info($"Got tag packet: {tagPacket.GameMode} {tagPacket.UpdateType} {tagPacket.IsIt} {tagPacket.Minutes}:{tagPacket.Seconds}");
if ((tagPacket.UpdateType & TagPacket.TagUpdate.State) != 0) {
c.Metadata["seeking"] = tagPacket.IsIt;
}
if ((tagPacket.UpdateType & TagPacket.TagUpdate.Time) != 0) {
c.Metadata["time"] = new Time(tagPacket.Minutes, tagPacket.Seconds, DateTime.Now);
}
} else {
// c.Logger.Info($"Got tag packet: {tagPacket.GameMode} {(byte) tagPacket.UpdateType}");
c.Metadata["seeking"] = null;
c.Metadata["time"] = null;
}
c.Metadata["gameMode"] = tagPacket.GameMode;
break;
}

Expand Down Expand Up @@ -462,6 +475,7 @@ await c.Send(new ChangeStagePacket {
if (!byte.TryParse(args[3], out byte seconds) || seconds >= 60)
return $"Invalid time for seconds {args[3]} (range: 0-59)";
TagPacket tagPacket = new TagPacket {
GameMode = GameMode.Legacy,
UpdateType = TagPacket.TagUpdate.Time,
Minutes = minutes,
Seconds = seconds,
Expand All @@ -482,6 +496,7 @@ await c.Send(new ChangeStagePacket {
Client? client = server.Clients.FirstOrDefault(x => x.Name == args[1]);
if (!bool.TryParse(args[2], out bool seeking)) return $"Usage: tag seeking {args[1]} <true/false>";
TagPacket tagPacket = new TagPacket {
GameMode = GameMode.Legacy,
UpdateType = TagPacket.TagUpdate.State,
IsIt = seeking,
};
Expand Down Expand Up @@ -509,6 +524,7 @@ await c.Send(new ChangeStagePacket {
await Task.WhenAll(
Parallel.ForEachAsync(seekers, async (seeker, _) => {
TagPacket packet = new TagPacket {
GameMode = GameMode.Legacy,
UpdateType = TagPacket.TagUpdate.State,
IsIt = true,
};
Expand All @@ -517,6 +533,7 @@ await Task.WhenAll(
}),
Parallel.ForEachAsync(server.Clients.Except(seekers), async (hider, _) => {
TagPacket packet = new TagPacket {
GameMode = GameMode.Legacy,
UpdateType = TagPacket.TagUpdate.State,
IsIt = false,
};
Expand Down
3 changes: 2 additions & 1 deletion Server/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,8 @@ await Parallel.ForEachAsync(this.ClientsConnected, async (other, _) => {

private async Task SendEmptyPackets(Client client, Client other) {
await other.Send(new TagPacket {
UpdateType = TagPacket.TagUpdate.State | TagPacket.TagUpdate.Time,
GameMode = GameMode.Legacy,
UpdateType = TagPacket.TagUpdate.Both,
IsIt = false,
Seconds = 0,
Minutes = 0,
Expand Down
51 changes: 44 additions & 7 deletions Shared/Packet/Packets/TagPacket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Shared.Packet.Packets;

[Packet(PacketType.Tag)]
public struct TagPacket : IPacket {
public GameMode GameMode;
public TagUpdate UpdateType;
public bool IsIt;
public byte Seconds;
Expand All @@ -12,22 +13,58 @@ public struct TagPacket : IPacket {
public short Size => 5;

public void Serialize(Span<byte> data) {
MemoryMarshal.Write(data, ref UpdateType);
byte both = (byte)((byte) UpdateType | ((byte) GameMode << 4));
MemoryMarshal.Write(data, ref both);
MemoryMarshal.Write(data[1..], ref IsIt);
MemoryMarshal.Write(data[2..], ref Seconds);
MemoryMarshal.Write(data[3..], ref Minutes);
}

public void Deserialize(ReadOnlySpan<byte> data) {
UpdateType = MemoryMarshal.Read<TagUpdate>(data);
IsIt = MemoryMarshal.Read<bool>(data[1..]);
Seconds = MemoryMarshal.Read<byte>(data[2..]);
Minutes = MemoryMarshal.Read<ushort>(data[3..]);
byte both = MemoryMarshal.Read<byte>(data);
GameMode = (GameMode) (sbyte) (((((both & (byte) 0xf0) >> 4) + 1) % 16) - 1);
UpdateType = (TagUpdate) (byte) (both & (byte) 0x0f);
IsIt = MemoryMarshal.Read<bool>(data[1..]);
Seconds = MemoryMarshal.Read<byte>(data[2..]);
Minutes = MemoryMarshal.Read<ushort>(data[3..]);
}

[Flags]
public enum TagUpdate : byte {
Time = 1,
State = 2
None = 0,
Time = 1,
State = 2,
Both = 3,
Unknown04 = 4,
Unknown05 = 5,
Unknown06 = 6,
Unknown07 = 7,
Unknown08 = 8,
Unknown09 = 9,
Unknown10 = 10,
Unknown11 = 11,
Unknown12 = 12,
Unknown13 = 13,
Unknown14 = 14,
All = 15,
}
}

public enum GameMode : sbyte {
None = -1,
Legacy = 0,
HideAndSeek = 1,
Sardines = 2,
FreezeTag = 3,
Unknown04 = 4,
Unknown05 = 5,
Unknown06 = 6,
Unknown07 = 7,
Unknown08 = 8,
Unknown09 = 9,
Unknown10 = 10,
Unknown11 = 11,
Unknown12 = 12,
Unknown13 = 13,
Reserved = 14, // extension possibility for more future game modes with an extra added byte
}

0 comments on commit 765af57

Please sign in to comment.