Skip to content

Commit

Permalink
Add a way to make it abundantly clear when the client and server are …
Browse files Browse the repository at this point in the history
…on different versions.
  • Loading branch information
airbreather committed Dec 18, 2024
1 parent 4b34bef commit f8e9f2b
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/Autopelago/GameDefinitions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ private GameDefinitions()
{
}

public required string VersionStamp { get; init; }

// EVERYTHING must be derived from these first few collections. this is important to minimize
// how much work #52 will be!
public required ImmutableArray<ItemDefinitionModel> AllItems { get; init; }
Expand Down Expand Up @@ -95,6 +97,7 @@ private static GameDefinitions LoadFromEmbeddedResource()
using StreamReader yamlReader = new(yamlStream, Encoding.UTF8);
YamlMappingNode map = new DeserializerBuilder().Build().Deserialize<YamlMappingNode>(yamlReader);

string versionStamp = map["version_stamp"].To<string>();
YamlMappingNode itemsMap = (YamlMappingNode)map["items"];
YamlMappingNode regionsMap = (YamlMappingNode)map["regions"];

Expand All @@ -103,6 +106,8 @@ private static GameDefinitions LoadFromEmbeddedResource()
ItemKey goalItem = items.AllItems.First(i => i.Name == "Victory").Key;
return new()
{
VersionStamp = versionStamp,

AllItems = items.AllItems,
AllLocations = regions.AllLocations,
AllRegions = regions.AllRegions,
Expand Down
21 changes: 21 additions & 0 deletions src/Autopelago/GameInitializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public sealed class GameAndContext
public required MultiworldInfo Context { get; init; }
}

public sealed record AutopelagoWorldMetadata
{
public required string VersionStamp { get; init; }
}

public sealed record MultiworldInfo
{
public required FrozenDictionary<string, FrozenDictionary<long, string>> GeneralItemNameMapping { get; init; }
Expand All @@ -42,6 +47,10 @@ public sealed record MultiworldInfo
[JsonSerializable(typeof(JsonElement))]
public sealed partial class AuraDataSerializationContext : JsonSerializerContext;

[JsonSerializable(typeof(AutopelagoWorldMetadata))]
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower)]
public sealed partial class AutopelagoWorldMetadataSerializationContext : JsonSerializerContext;

public sealed class GameInitializer : ArchipelagoPacketHandler
{
private readonly AsyncSubject<GameAndContext> _initializedGame = new();
Expand Down Expand Up @@ -167,6 +176,18 @@ private async ValueTask HandleAsync(ConnectResponsePacketModel connectResponse,
}

ConnectedPacketModel connected = (ConnectedPacketModel)connectResponse;

if (connected.SlotData.Deserialize(AutopelagoWorldMetadataSerializationContext.Default.AutopelagoWorldMetadata) is not { } autopelagoWorldMetadata ||
autopelagoWorldMetadata.VersionStamp != GameDefinitions.Instance.VersionStamp)
{
throw new InvalidOperationException($"""
Client and .apworld are from different versions! This client wants to see '{GameDefinitions.Instance.VersionStamp}'.
To check this yourself, open the .apworld file in 7-zip or something like that, look near the top of
its 'AutopelagoDefinitions.yml' file for a "version_stamp". If it's not there, or if its value isn't
the one we were looking for (again, '{GameDefinitions.Instance.VersionStamp}'), then that's why this happened.
""");
}

_slotInfo = connected.SlotInfo.ToFrozenDictionary();
_slotByPlayerAlias = connected.Players.ToFrozenDictionary(p => p.Alias, p => p.Slot);
LocationScoutsPacketModel locationScouts = new()
Expand Down
10 changes: 9 additions & 1 deletion src/Autopelago/PacketModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ private protected ConnectResponsePacketModel() { }

public sealed record ConnectedPacketModel : ConnectResponsePacketModel
{
private static readonly JsonElement s_emptyObject = CreateJsonElementForEmptyObject();

public required int Team { get; init; }

public required int Slot { get; init; }
Expand All @@ -195,11 +197,17 @@ public sealed record ConnectedPacketModel : ConnectResponsePacketModel

public required ImmutableArray<long> CheckedLocations { get; init; }

public Dictionary<string, JsonElement> SlotData { get; init; } = [];
public JsonElement SlotData { get; init; } = s_emptyObject;

public Dictionary<int, SlotModel> SlotInfo { get; init; } = [];

public required int HintPoints { get; init; }

private static JsonElement CreateJsonElementForEmptyObject()
{
using JsonDocument document = JsonDocument.Parse("{}");
return document.RootElement.Clone();
}
}

public sealed record ConnectionRefusedPacketModel : ConnectResponsePacketModel
Expand Down
2 changes: 2 additions & 0 deletions src/AutopelagoDefinitions.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# This file exists in both the client and the server projects.
# Please make sure that it matches in both places.

version_stamp: '20241218'

items:
blackbird: 'Lockheed SR-71 Blackbird'
mongoose_in_a_combat_spacecraft:
Expand Down

0 comments on commit f8e9f2b

Please sign in to comment.