Skip to content

Commit 46b3836

Browse files
Allow specifying coords in search
1 parent b039bfb commit 46b3836

File tree

7 files changed

+110
-18
lines changed

7 files changed

+110
-18
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// RedWindowSearchTips.swift
3+
// MCMaps
4+
//
5+
// Created by Marquis Kurt on 10-08-2025.
6+
//
7+
8+
import SwiftUI
9+
10+
struct RedWindowSearchTips: View {
11+
private let tips: [LocalizedStringKey] = [
12+
"Use the `@{0,0} syntax to filter search results near a specific coordinate.",
13+
"Type the name of a tag to filter search results by that tag."
14+
]
15+
16+
@State private var randomIndex: [LocalizedStringKey].Index = 0
17+
18+
var body: some View {
19+
Label {
20+
Text(tips[randomIndex])
21+
} icon: {
22+
Image(systemName: "lightbulb")
23+
.symbolRenderingMode(.hierarchical)
24+
.foregroundStyle(.teal)
25+
}
26+
.task {
27+
randomIndex = tips.indices.randomElement() ?? 0
28+
}
29+
}
30+
}

MCMaps/Red Window/Views/Search/RedWindowSearchView.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,16 @@ struct RedWindowSearchView: View {
9797
}
9898
} else {
9999
// swiftlint:disable line_length
100-
ContentUnavailableView(
101-
"Search Everything",
102-
image: "map.badge.magnifyingglass",
103-
description: Text(
100+
ContentUnavailableView {
101+
Label("Search Everything", image: "map.badge.magnifyingglass")
102+
} description: {
103+
Text(
104104
"Search for nearby biomes and structures, pinned places, and any marked locations from integrations like Bluemap."
105105
)
106-
)
106+
} actions: {
107+
RedWindowSearchTips()
108+
}
109+
107110
// swiftlint:enable line_length
108111
}
109112
}
@@ -168,10 +171,6 @@ struct RedWindowSearchView: View {
168171
}
169172
} header: {
170173
Text("Biomes and Structures")
171-
} footer: {
172-
Text(
173-
"Relative where you are on the map (\(currentLoc.accessibilityReadout))."
174-
)
175174
}
176175
}
177176
}

MCMaps/Resources/Localizable.xcstrings

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@
113113
},
114114
"Are you sure you want to remove %lld pins?" : {
115115

116+
},
117+
"At: (%@)" : {
118+
116119
},
117120
"Bastion" : {
118121

@@ -437,9 +440,6 @@
437440
},
438441
"Refresh every: ^[%lld second](inflect: true)" : {
439442

440-
},
441-
"Relative where you are on the map (%@)." : {
442-
443443
},
444444
"Remove" : {
445445

@@ -560,12 +560,18 @@
560560
},
561561
"Type a tag above to create it." : {
562562

563+
},
564+
"Type the name of a tag to filter search results by that tag." : {
565+
563566
},
564567
"Update player locations more frequently with Realtime Sync. [Learn more…](https://example.com)" : {
565568

566569
},
567570
"Update World" : {
568571

572+
},
573+
"Use the `@{0,0} syntax to filter search results near a specific coordinate." : {
574+
569575
},
570576
"Use the search bar to look through your pins, or to locate nearby structures and biomes." : {
571577

MCMaps/Shared/Services/CartographySearchService+SearchFilterGroup.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Created by Marquis Kurt on 01-06-2025.
66
//
77

8+
import Foundation
89
import MCMap
910

1011
extension CartographySearchService {
@@ -14,6 +15,9 @@ extension CartographySearchService {
1415

1516
/// Filter by a specific tag.
1617
case tag(String)
18+
19+
/// Filter results relative to a specific origin.
20+
case origin(CGPoint)
1721
}
1822

1923
/// A collection of search filters.
@@ -44,6 +48,19 @@ extension CartographySearchService.SearchFilterGroup {
4448

4549
return matches
4650
}
51+
52+
func getFilteredOrigin() -> CGPoint? {
53+
var point: CGPoint?
54+
for filter in filters {
55+
switch filter {
56+
case .tag:
57+
continue
58+
case let .origin(position):
59+
point = position
60+
}
61+
}
62+
return point
63+
}
4764
}
4865

4966
extension CartographySearchService.SearchFilterGroup: Collection {

MCMaps/Shared/Services/CartographySearchService.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ class CartographySearchService {
8585
func search(for query: Query, in context: SearchContext, filters: SearchFilterGroup? = nil) async -> SearchResult {
8686
var results = SearchResult()
8787
var integratedMarkers = [CartographyMapPin]()
88+
var position = context.position
89+
90+
if let point = filters?.getFilteredOrigin() {
91+
position = MinecraftPoint(cgPoint: point)
92+
}
8893

8994
if context.file.supportedFeatures.contains(.integrations), context.file.integrations.bluemap.enabled {
9095
integratedMarkers.append(contentsOf: await getBluemapMarkers(in: context))
@@ -102,14 +107,14 @@ class CartographySearchService {
102107
results.integratedData = filteredMarkers
103108

104109
if let structure = MinecraftStructure(string: query) {
105-
searchStructures(context, structure, &results)
110+
searchStructures(at: position, context, structure, &results)
106111
}
107112

108113
results.biomes = searchBiomes(
109114
query: query,
110115
mcVersion: context.file.manifest.worldSettings.version,
111116
world: context.world,
112-
pos: context.position,
117+
pos: position,
113118
dimension: context.dimension
114119
)
115120

@@ -191,13 +196,14 @@ class CartographySearchService {
191196
}
192197

193198
private func searchStructures(
199+
at position: MinecraftPoint,
194200
_ context: SearchContext,
195201
_ structure: MinecraftStructure,
196202
_ results: inout SearchResult
197203
) {
198204
let foundStructures = context.world.findStructures(
199205
ofType: structure,
200-
at: context.position,
206+
at: position,
201207
inRadius: searchRadius,
202208
dimension: context.dimension
203209
)

MCMaps/Shared/Views/Search/CartographySearchView.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,22 @@ struct CartographySearchView<InitialView: View, ResultsView: View>: View {
141141
prompt: useRedWindowDesign ? "Search" : "Go To..."
142142
) { token in
143143
switch token {
144-
case let .tag(tagName):
144+
case .tag(let tagName):
145145
Text(tagName)
146+
case .origin(let point):
147+
Text("At: (\(point.accessibilityReadout))")
146148
}
147149
}
148150
.searchFocused($searchFocused)
149151
.searchSuggestions {
150152
ForEach(getSuggestions()) { searchToken in
151153
switch searchToken {
152-
case let .tag(tagName):
154+
case .tag(let tagName):
153155
Label(tagName, systemImage: "tag")
154156
.searchCompletion(searchToken)
157+
case .origin(let pos):
158+
Label(pos.accessibilityReadout, systemImage: "location")
159+
.searchCompletion(searchToken)
155160
}
156161
}
157162
}
@@ -193,9 +198,19 @@ struct CartographySearchView<InitialView: View, ResultsView: View>: View {
193198
}
194199

195200
private func getSuggestions() -> [SearchToken] {
201+
var searchTokens = [SearchToken]()
202+
203+
let positionSyntax = /\@\{(-?\d+),\s*(-?\d+)\}/
204+
if let match = rawQuery.wholeMatch(of: positionSyntax) {
205+
let (_, xCoord, zCoord) = match.output
206+
let coordinate = CGPoint(x: Int(xCoord) ?? 0, y: Int(zCoord) ?? 0)
207+
searchTokens.append(.origin(coordinate))
208+
}
209+
196210
let fileTags = file.tags
197211
let matchingTags = fileTags.filter { tag in rawQuery.lowercased().contains(tag.lowercased()) }
198-
return matchingTags.map { SearchToken.tag($0) }
212+
searchTokens.append(contentsOf: matchingTags.map { SearchToken.tag($0) })
213+
return searchTokens
199214
}
200215
}
201216

MCMapsTests/Services/CartographySearchServiceTests.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,23 @@ struct CartographySearchServiceTests {
9999
in: SearchContext(world: world, file: file, position: .zero))
100100
#expect(!results.biomes.isEmpty)
101101
}
102+
103+
@Test func searchReturnsNearbyBiomesRelativeToFilteredOrigin() async throws {
104+
let world = try MinecraftWorld(version: "1.21.3", seed: 123)
105+
let file = CartographyMapFile(withManifest: .sampleFile)
106+
let service = CartographySearchService()
107+
let context = SearchContext(world: world, file: file, position: .zero)
108+
109+
let originResults = await service.search(for: "Frozen River", in: context)
110+
111+
let results = await service.search(
112+
for: "Frozen River",
113+
in: context,
114+
filters: SearchFilterGroup(
115+
filters: [.origin(CGPoint(x: 1000, y: 1000))]
116+
)
117+
)
118+
119+
#expect(originResults.biomes.map(\.position) != results.biomes.map(\.position))
120+
}
102121
}

0 commit comments

Comments
 (0)