Skip to content

Commit fd59d56

Browse files
Search for Bluemap markers (#44)
Closes #44.
1 parent 1a66fff commit fd59d56

File tree

8 files changed

+162
-63
lines changed

8 files changed

+162
-63
lines changed

MCMaps/Legacy/Views/Sidebar/CartographyMapSidebar.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ struct CartographyMapSidebar: View {
113113
PinnedLibrarySection(pins: results.pins, viewModel: $viewModel, file: $file)
114114
}
115115

116+
if !results.integratedData.isEmpty {
117+
GroupedPinsSection(
118+
name: "From Integrations",
119+
pins: results.integratedData,
120+
viewModel: $viewModel,
121+
file: $file
122+
)
123+
}
124+
116125
GroupedPinsSection(
117126
pins: results.structures,
118127
viewModel: $viewModel,

MCMaps/Red Window/Routing/RedWindowRoute.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ extension RedWindowRoute {
6262
case .allPins: "All Pins"
6363
case .allPinsCompact: "Library"
6464
case .search: "Search"
65-
case let .pin(pin): "Pin"
65+
case .pin: "Pin"
6666
}
6767
}
6868

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,15 @@ struct RedWindowSearchLandmarkResultCell: View {
2525
/// The landmark represents a player-created pin.
2626
case pin
2727

28+
/// The landmark represents a pin pulled from integrations.
29+
case integratedPin
30+
2831
/// A symbol representation for the landmark.
2932
var symbol: String {
3033
switch self {
3134
case .biome: "mountain.2"
3235
case .structure: "building.2.crop.circle"
33-
case .pin: "mappin"
36+
case .pin, .integratedPin: "mappin"
3437
}
3538
}
3639
}

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

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ struct RedWindowSearchView: View {
9393
}
9494

9595
private func resultList(for result: CartographySearchService.SearchResult) -> some View {
96-
let currentLoc = redWindowEnvironment.mapCenterCoordinate
9796
return List {
9897
Section {
9998
ForEach(result.pins) { pin in
@@ -105,31 +104,57 @@ struct RedWindowSearchView: View {
105104
} header: {
106105
Text("Your Pinned Places")
107106
}
108-
Section {
109-
ForEach(result.biomes) { biome in
110-
RedWindowSearchLandmarkResultCell(
111-
request: $pinCreationRequest,
112-
landmark: biome,
113-
landmarkType: .biome
114-
)
115-
}
116-
ForEach(result.structures) { structure in
117-
RedWindowSearchLandmarkResultCell(
118-
request: $pinCreationRequest,
119-
landmark: structure,
120-
landmarkType: .structure
121-
)
122-
}
123-
if result.structures.isEmpty, result.biomes.isEmpty {
124-
ContentUnavailableView.search(text: query)
125-
}
126-
} header: {
127-
Text("Biomes and Structures")
128-
} footer: {
129-
Text(
130-
"Relative where you are on the map (\(currentLoc.accessibilityReadout))."
107+
if file.integrations.enabled {
108+
integratedSection(data: result.integratedData)
109+
}
110+
biomesAndStructures(result: result)
111+
}
112+
}
113+
114+
private func integratedSection(data: [CartographyMapPin]) -> some View {
115+
Section {
116+
ForEach(data) { pin in
117+
RedWindowSearchLandmarkResultCell(
118+
request: $pinCreationRequest,
119+
landmark: pin,
120+
landmarkType: .integratedPin
131121
)
132122
}
123+
if data.isEmpty {
124+
ContentUnavailableView.search(text: query)
125+
}
126+
} header: {
127+
Text("From Integrations")
128+
}
129+
}
130+
131+
private func biomesAndStructures(result: CartographySearchService.SearchResult) -> some View {
132+
let currentLoc = redWindowEnvironment.mapCenterCoordinate
133+
134+
return Section {
135+
ForEach(result.biomes) { biome in
136+
RedWindowSearchLandmarkResultCell(
137+
request: $pinCreationRequest,
138+
landmark: biome,
139+
landmarkType: .biome
140+
)
141+
}
142+
ForEach(result.structures) { structure in
143+
RedWindowSearchLandmarkResultCell(
144+
request: $pinCreationRequest,
145+
landmark: structure,
146+
landmarkType: .structure
147+
)
148+
}
149+
if result.structures.isEmpty, result.biomes.isEmpty {
150+
ContentUnavailableView.search(text: query)
151+
}
152+
} header: {
153+
Text("Biomes and Structures")
154+
} footer: {
155+
Text(
156+
"Relative where you are on the map (\(currentLoc.accessibilityReadout))."
157+
)
133158
}
134159
}
135160
}

MCMaps/Resources/Alidade.docc/Changelogs/Changelog-Unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ time as new versions and features are added.
2525
- Players can now enable Realtime Sync for Bluemap to get realtime updates
2626
for player locations. Server and death markers sync independently of
2727
players.
28+
- Players can now search for markers from Bluemap in the search views.
2829

2930
### Map
3031

MCMaps/Resources/AppIcon-RedWindow.icon/icon.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
"color-space-for-untagged-svg-colors" : "display-p3",
33
"fill" : {
44
"linear-gradient" : [
5-
"srgb:0.41233,0.61333,0.72654,1.00000",
6-
"srgb:0.16708,0.40676,0.52647,1.00000"
5+
"srgb:0.24121,0.62164,0.72654,1.00000",
6+
"srgb:0.10620,0.36519,0.52647,1.00000"
77
]
88
},
99
"groups" : [
1010
{
1111
"layers" : [
1212
{
13+
"glass" : true,
1314
"image-name" : "Icon-2.png",
1415
"name" : "Icon-2",
1516
"position" : {
@@ -21,10 +22,13 @@
2122
}
2223
},
2324
{
25+
"blend-mode" : "normal",
26+
"fill" : "none",
2427
"glass" : true,
2528
"hidden" : false,
2629
"image-name" : "Icon.png",
2730
"name" : "Icon",
31+
"opacity" : 0.8,
2832
"position-specializations" : [
2933
{
3034
"value" : {

MCMaps/Resources/Localizable.xcstrings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@
218218
},
219219
"From Finder" : {
220220

221+
},
222+
"From Integrations" : {
223+
221224
},
222225
"From Photos" : {
223226

MCMaps/Shared/Services/CartographySearchService.swift

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
//
77

88
import CubiomesKit
9-
import MCMap
109
import Foundation
10+
import MCMap
1111

1212
/// A service that searches and filters content in Minecraft worlds and `.mcmap` files.
1313
class CartographySearchService {
@@ -34,6 +34,9 @@ class CartographySearchService {
3434
/// The pins that matched a given query.
3535
var pins: [CartographyMapPin]
3636

37+
/// The integration data that matched a given query.
38+
var integratedData: [CartographyMapPin]
39+
3740
/// The coordinates that matched a given query.
3841
///
3942
/// This is typically populated when the query represents a coordinate that can be quickly jumped to, such as
@@ -48,14 +51,15 @@ class CartographySearchService {
4851

4952
/// Whether the search results are completely empty.
5053
var isEmpty: Bool {
51-
pins.isEmpty && coordinates.isEmpty && structures.isEmpty && biomes.isEmpty
54+
pins.isEmpty && coordinates.isEmpty && structures.isEmpty && biomes.isEmpty && integratedData.isEmpty
5255
}
5356

5457
init() {
5558
self.pins = []
5659
self.coordinates = []
5760
self.structures = []
5861
self.biomes = []
62+
self.integratedData = []
5963
}
6064
}
6165

@@ -80,48 +84,25 @@ class CartographySearchService {
8084
/// - Parameter filters: The filters to apply in this search.
8185
func search(for query: Query, in context: SearchContext, filters: SearchFilterGroup? = nil) async -> SearchResult {
8286
var results = SearchResult()
87+
var integratedMarkers = [CartographyMapPin]()
88+
89+
if context.file.supportedFeatures.contains(.integrations), context.file.integrations.bluemap.enabled {
90+
integratedMarkers.append(contentsOf: await getBluemapMarkers(in: context))
91+
}
8392

8493
if let matches = query.matches(of: Constants.coordinateRegex).first?.output {
8594
if let x = Double(matches.1), let y = Double(matches.2) {
8695
results.coordinates.append(CGPoint(x: x, y: y))
8796
}
8897
}
8998

90-
for pin in context.file.pins {
91-
let nameMatches = pin.name.lowercased().contains(query.lowercased())
92-
if let filters = filters, !filters.isEmpty {
93-
if filters.matchTags(for: pin).isEmpty { continue }
94-
if !nameMatches, !query.isEmpty { continue }
95-
results.pins.append(pin)
96-
continue
97-
}
98-
99-
if !nameMatches { continue }
100-
results.pins.append(pin)
101-
}
99+
let playerPins = filterPins(context.file.pins, by: query, filters: filters)
100+
let filteredMarkers = filterPins(integratedMarkers, by: query, filters: filters)
101+
results.pins = playerPins
102+
results.integratedData = filteredMarkers
102103

103104
if let structure = MinecraftStructure(string: query) {
104-
let foundStructures = context.world.findStructures(
105-
ofType: structure,
106-
at: context.position,
107-
inRadius: searchRadius,
108-
dimension: context.dimension
109-
)
110-
for foundStruct in foundStructures {
111-
results.structures
112-
.append(
113-
CartographyMapPin(
114-
named: structure.name,
115-
at: CGPoint(x: Double(foundStruct.x), y: Double(foundStruct.z)),
116-
color: structure.pinColor)
117-
)
118-
}
119-
120-
let cgPointOrigin = CGPoint(minecraftPoint: context.position)
121-
results.structures.sort { first, second in
122-
first.position
123-
.manhattanDistance(to: cgPointOrigin) < second.position.manhattanDistance(to: cgPointOrigin)
124-
}
105+
searchStructures(context, structure, &results)
125106
}
126107

127108
results.biomes = searchBiomes(
@@ -135,6 +116,51 @@ class CartographySearchService {
135116
return results
136117
}
137118

119+
private func getBluemapMarkers(in context: SearchContext) async -> [CartographyMapPin] {
120+
let service = CartographyIntegrationService(
121+
serviceType: .bluemap,
122+
integrationSettings: context.file.integrations)
123+
do {
124+
let results: BluemapResults? = try await service.sync(dimension: context.dimension)
125+
guard let markers = results?.markers else {
126+
return []
127+
}
128+
let allMarkers = markers.map(\.value)
129+
return allMarkers.flatMap { group in
130+
group.markers.map { (_, marker) in
131+
CartographyMapPin(
132+
named: marker.label,
133+
at: CGPoint(x: marker.position.x, y: marker.position.z),
134+
color: .gray
135+
)
136+
}
137+
}
138+
} catch {
139+
return []
140+
}
141+
}
142+
143+
private func filterPins(
144+
_ pins: [CartographyMapPin],
145+
by query: Query,
146+
filters: SearchFilterGroup? = nil
147+
) -> [CartographyMapPin] {
148+
var newPins = [CartographyMapPin]()
149+
for pin in pins {
150+
let nameMatches = pin.name.lowercased().contains(query.lowercased())
151+
if let filters = filters, !filters.isEmpty {
152+
if filters.matchTags(for: pin).isEmpty { continue }
153+
if !nameMatches, !query.isEmpty { continue }
154+
newPins.append(pin)
155+
continue
156+
}
157+
158+
if !nameMatches { continue }
159+
newPins.append(pin)
160+
}
161+
return newPins
162+
}
163+
138164
private func searchBiomes(
139165
query: String, mcVersion: String, world: MinecraftWorld, pos: Point3D<Int32>,
140166
dimension: MinecraftWorld.Dimension
@@ -162,4 +188,32 @@ class CartographySearchService {
162188
}
163189
return biomes
164190
}
191+
192+
private func searchStructures(
193+
_ context: SearchContext,
194+
_ structure: MinecraftStructure,
195+
_ results: inout SearchResult
196+
) {
197+
let foundStructures = context.world.findStructures(
198+
ofType: structure,
199+
at: context.position,
200+
inRadius: searchRadius,
201+
dimension: context.dimension
202+
)
203+
for foundStruct in foundStructures {
204+
results.structures
205+
.append(
206+
CartographyMapPin(
207+
named: structure.name,
208+
at: CGPoint(x: Double(foundStruct.x), y: Double(foundStruct.z)),
209+
color: structure.pinColor)
210+
)
211+
}
212+
213+
let cgPointOrigin = CGPoint(minecraftPoint: context.position)
214+
results.structures.sort { first, second in
215+
first.position
216+
.manhattanDistance(to: cgPointOrigin) < second.position.manhattanDistance(to: cgPointOrigin)
217+
}
218+
}
165219
}

0 commit comments

Comments
 (0)