diff --git a/src/GameCult.Networking/CultNetDatabase.cs b/src/GameCult.Networking/CultNetDatabase.cs index 0c4351a3..4db79307 100644 --- a/src/GameCult.Networking/CultNetDatabase.cs +++ b/src/GameCult.Networking/CultNetDatabase.cs @@ -1509,15 +1509,12 @@ namespace GameCult.Networking "not_primary"); } - private static bool MatchesCatalogFilter( + private bool MatchesCatalogFilter( CultNetShardDescriptor shard, IReadOnlyList? schemaIds, IReadOnlyList? recordKeys) { - var schemaMatches = schemaIds == null || - schemaIds.Count == 0 || - shard.SchemaIds.Count == 0 || - schemaIds.Any(schemaId => shard.SchemaIds.Contains(schemaId, StringComparer.Ordinal)); + var schemaMatches = SchemaMatchesCatalogFilter(shard, schemaIds); var keyMatches = recordKeys == null || recordKeys.Count == 0 || recordKeys.Any(key => string.IsNullOrEmpty(shard.KeyPrefix) || @@ -1525,6 +1522,33 @@ namespace GameCult.Networking return schemaMatches && keyMatches; } + private bool SchemaMatchesCatalogFilter( + CultNetShardDescriptor shard, + IReadOnlyList? schemaIds) + { + if (schemaIds == null || schemaIds.Count == 0 || shard.SchemaIds.Count == 0) + return true; + + var requestedSchemaIds = schemaIds.ToHashSet(StringComparer.Ordinal); + if (shard.SchemaIds.Any(requestedSchemaIds.Contains)) + return true; + + foreach (var shardSchemaId in shard.SchemaIds) + { + try + { + if (MatchesRequestedSchema(_cache.Registry.GetRequiredBySchemaId(shardSchemaId), requestedSchemaIds)) + return true; + } + catch (InvalidOperationException) + { + // Shards can advertise schemas that are not loaded in this process. + } + } + + return false; + } + private static bool MatchesRequestedSchema( CultDocumentDescriptor descriptor, ISet requestedSchemaIds) diff --git a/tests/GameCult.Networking.Tests/NetworkingTests.cs b/tests/GameCult.Networking.Tests/NetworkingTests.cs index 1edab188..f8b3463a 100644 --- a/tests/GameCult.Networking.Tests/NetworkingTests.cs +++ b/tests/GameCult.Networking.Tests/NetworkingTests.cs @@ -1955,6 +1955,16 @@ namespace GameCult.Networking.Tests Assert.That(response.Shards[0].Epoch, Is.EqualTo(3)); Assert.That(response.Shards[0].PrimaryEndpoints, Is.EqualTo(["cultnet://runtime-a:3075"])); Assert.That(response.Shards[0].ReadReplicaEndpoints, Is.EqualTo(["cultnet://edge-a:3075"])); + + var aliasResponse = databaseServer.CreateShardCatalogResponse(new CultNetShardCatalogRequestMessage + { + MessageId = "catalog-players-alias", + SchemaIds = ["gamecult.player_data.v2"], + RecordKeys = ["player:one"] + }); + + Assert.That(aliasResponse.Shards, Has.Length.EqualTo(1)); + Assert.That(aliasResponse.Shards[0].ShardId, Is.EqualTo("players")); } [Test]