Skip to content

Commit f08edb0

Browse files
committed
🐝🐝🐝
Signed-off-by: Jannik Hollenbach <jannik.hollenbach@owasp.org>
1 parent 95bfb07 commit f08edb0

File tree

9 files changed

+43
-47
lines changed

9 files changed

+43
-47
lines changed
3.59 KB
Loading

balancer/ui/src/components/ctf/Globe.tsx

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ export interface GlobeHandle {
2828
/** Transition a country from solid fill to pattern fill */
2929
transitionCountryToSolved(
3030
countryName: string,
31-
patternIndex: number
31+
patternPath: string
3232
): Promise<void>;
3333
/** Rotate camera to the country, transition material, and pulse a highlight glow */
34-
focusAndHighlightCountry(countryName: string, patternIndex: number): void;
34+
focusAndHighlightCountry(countryName: string, patternPath: string): void;
3535
/**
3636
* Enqueue multiple solve animations, sorted by geographic proximity
3737
* (greedy nearest-neighbor from the current camera position) so the camera
3838
* traces a short path instead of jumping randomly around the globe.
3939
*/
4040
focusAndHighlightCountries(
41-
solves: Array<{ countryName: string; patternIndex: number }>
41+
solves: Array<{ countryName: string; patternPath: string }>
4242
): void;
4343
}
4444

@@ -201,12 +201,12 @@ function GlobeInternal({
201201
const handle: GlobeHandle = {
202202
transitionCountryToSolved: async (
203203
countryName: string,
204-
patternIndex: number
204+
patternPath: string
205205
) => {
206206
const colors = themeColorsRef.current;
207207
await globeRenderer.transitionCountryToSolved(
208208
countryName,
209-
patternIndex,
209+
patternPath,
210210
{
211211
primary: colors.primary,
212212
glowIntensity: colors.glowIntensity,
@@ -215,14 +215,14 @@ function GlobeInternal({
215215
},
216216
focusAndHighlightCountry: (
217217
countryName: string,
218-
patternIndex: number
218+
patternPath: string
219219
) => {
220220
const center = globeRenderer.getCountryCenter(countryName);
221221
if (!center) {
222222
// Fallback: just do the material transition without animation
223223
const colors = themeColorsRef.current;
224224
globeRenderer
225-
.transitionCountryToSolved(countryName, patternIndex, {
225+
.transitionCountryToSolved(countryName, patternPath, {
226226
primary: colors.primary,
227227
glowIntensity: colors.glowIntensity,
228228
})
@@ -242,7 +242,7 @@ function GlobeInternal({
242242
animator.enqueue(
243243
new SolveSequenceAnimation({
244244
countryName,
245-
patternIndex,
245+
patternPath,
246246
targetPosition: capitalWorld,
247247
capitalWorldPos: capitalWorld,
248248
camera,
@@ -256,14 +256,14 @@ function GlobeInternal({
256256
);
257257
},
258258
focusAndHighlightCountries: (
259-
solves: Array<{ countryName: string; patternIndex: number }>
259+
solves: Array<{ countryName: string; patternPath: string }>
260260
) => {
261261
if (solves.length === 0) return;
262262

263263
// Resolve centers for all solves, separate those without geo data
264264
type SolveWithCenter = {
265265
countryName: string;
266-
patternIndex: number;
266+
patternPath: string;
267267
lat: number;
268268
lon: number;
269269
};
@@ -276,7 +276,7 @@ function GlobeInternal({
276276
// No geo data — transition immediately without animation
277277
const colors = themeColorsRef.current;
278278
globeRenderer
279-
.transitionCountryToSolved(s.countryName, s.patternIndex, {
279+
.transitionCountryToSolved(s.countryName, s.patternPath, {
280280
primary: colors.primary,
281281
glowIntensity: colors.glowIntensity,
282282
})
@@ -329,7 +329,7 @@ function GlobeInternal({
329329
animator.enqueue(
330330
new SolveSequenceAnimation({
331331
countryName: s.countryName,
332-
patternIndex: s.patternIndex,
332+
patternPath: s.patternPath,
333333
targetPosition: capitalWorld,
334334
capitalWorldPos: capitalWorld,
335335
camera,

balancer/ui/src/lib/challenges/challenge-diff.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { Challenge } from "@/hooks/useChallenges";
22

3-
import { getPatternIndexForTeam } from "../patterns/pattern-selector";
3+
import { getPatternPathForTeam } from "../patterns/pattern-selector";
44

55
export interface NewlySolvedChallenge {
66
countryName: string;
7-
patternIndex: number;
7+
patternPath: string;
88
challengeKey: string;
99
firstSolver: string;
1010
}
@@ -48,10 +48,10 @@ export function findNewlySolvedChallenges(
4848
const isNowSolved = challenge.solveCount > 0;
4949

5050
if (wasUnsolved && isNowSolved && challenge.firstSolver) {
51-
const patternIndex = getPatternIndexForTeam(challenge.firstSolver);
51+
const patternPath = getPatternPathForTeam(challenge.firstSolver);
5252
newlySolved.push({
5353
countryName,
54-
patternIndex,
54+
patternPath,
5555
challengeKey: challenge.key,
5656
firstSolver: challenge.firstSolver,
5757
});

balancer/ui/src/lib/challenges/challenge-mapper.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { CountryData } from "../globe/data/geojson-loader";
2-
import { getPatternIndexForTeam } from "../patterns/pattern-selector";
2+
import { getPatternPathForTeam } from "../patterns/pattern-selector";
33

44
// Re-export Challenge from the hook
55
export type { Challenge } from "../../hooks/useChallenges";
@@ -13,7 +13,7 @@ export interface ChallengeCountryMapping {
1313
challenge: Challenge;
1414
countryName: string | null;
1515
firstSolver?: string | null;
16-
patternIndex?: number;
16+
patternPath?: string;
1717
}
1818

1919
/**
@@ -77,15 +77,15 @@ export function mapChallengesToCountries(
7777
(challenge, index) => {
7878
const country = sortedCountries[index];
7979
const firstSolver = challenge.firstSolver || null;
80-
const patternIndex = firstSolver
81-
? getPatternIndexForTeam(firstSolver)
80+
const patternPath = firstSolver
81+
? getPatternPathForTeam(firstSolver)
8282
: undefined;
8383

8484
return {
8585
challenge,
8686
countryName: country ? country.name : null,
8787
firstSolver,
88-
patternIndex,
88+
patternPath,
8989
};
9090
}
9191
);
@@ -103,18 +103,18 @@ export function getCountriesByChallengeStatus(
103103
): {
104104
solved: Set<string>;
105105
unsolved: Set<string>;
106-
solvedWithPatterns: Map<string, number>;
106+
solvedWithPatterns: Map<string, string>;
107107
} {
108108
const solved = new Set<string>();
109109
const unsolved = new Set<string>();
110-
const solvedWithPatterns = new Map<string, number>();
110+
const solvedWithPatterns = new Map<string, string>();
111111

112112
for (const mapping of mappings) {
113113
if (mapping.countryName) {
114114
if (mapping.challenge.solveCount > 0) {
115115
solved.add(mapping.countryName);
116-
if (mapping.patternIndex !== undefined) {
117-
solvedWithPatterns.set(mapping.countryName, mapping.patternIndex);
116+
if (mapping.patternPath !== undefined) {
117+
solvedWithPatterns.set(mapping.countryName, mapping.patternPath);
118118
}
119119
} else {
120120
unsolved.add(mapping.countryName);

balancer/ui/src/lib/globe/animations/solve-sequence.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const HIGHLIGHT_START = 1500;
2525

2626
interface SolveSequenceParams {
2727
countryName: string;
28-
patternIndex: number;
28+
patternPath: string;
2929
targetPosition: Vector3;
3030
capitalWorldPos: Vector3;
3131
camera: PerspectiveCamera;
@@ -77,7 +77,7 @@ export class SolveSequenceAnimation implements Animation {
7777
this.params.globeRenderer
7878
.transitionCountryToSolved(
7979
this.params.countryName,
80-
this.params.patternIndex,
80+
this.params.patternPath,
8181
this.params.themeColors,
8282
true // animated reveal — starts with u_revealRadius = 0
8383
)

balancer/ui/src/lib/globe/country-geometry.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ export class CountryGeometryManager {
1919
totalVertexCount: number = 0;
2020
countriesWithChallenges: Set<string>;
2121
solvedCountries: Set<string>;
22-
countryPatternMap: Map<string, number>;
22+
countryPatternMap: Map<string, string>;
2323

2424
constructor(
2525
countries: CountryData[],
2626
solvedCountries: Set<string>,
2727
countriesWithChallenges: Set<string>,
28-
solvedWithPatterns: Map<string, number>
28+
solvedWithPatterns: Map<string, string>
2929
) {
3030
this.countriesWithChallenges = countriesWithChallenges;
3131
this.solvedCountries = solvedCountries;
@@ -106,7 +106,7 @@ export class CountryGeometryManager {
106106
/**
107107
* Get the pattern index for a country
108108
*/
109-
getPatternIndex(countryName: string): number | undefined {
109+
getPatternPath(countryName: string): string | undefined {
110110
return this.countryPatternMap.get(countryName);
111111
}
112112
}

balancer/ui/src/lib/globe/globe-renderer.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
ShaderMaterial,
99
} from "three";
1010

11-
import { getPatternPathByIndex } from "../patterns/pattern-selector";
1211
import { TextureCache } from "../patterns/texture-cache";
1312

1413
import { createCapitalMarkers } from "./capital-markers";
@@ -78,16 +77,13 @@ export class GlobeRenderer {
7877

7978
// Create pattern meshes for solved challenges
8079
for (const { geometry, name } of geometryManager.patternGeometries) {
81-
const patternIndex = geometryManager.getPatternIndex(name);
80+
const patternPath = geometryManager.getPatternPath(name);
8281

83-
if (patternIndex === undefined) {
84-
console.warn(`No pattern index for country: ${name}`);
82+
if (patternPath === undefined) {
83+
console.warn(`No pattern path for country: ${name}`);
8584
continue;
8685
}
8786

88-
// Load texture
89-
const patternPath = getPatternPathByIndex(patternIndex);
90-
9187
try {
9288
const texture = await this.textureCache.loadTexture(patternPath);
9389

@@ -206,7 +202,7 @@ export class GlobeRenderer {
206202
*/
207203
async transitionCountryToSolved(
208204
countryName: string,
209-
patternIndex: number,
205+
patternPath: string,
210206
themeColors: { primary: number[]; glowIntensity: number },
211207
animated = false
212208
): Promise<void> {
@@ -222,9 +218,6 @@ export class GlobeRenderer {
222218
return;
223219
}
224220

225-
// Load the pattern texture once
226-
const patternPath = getPatternPathByIndex(patternIndex);
227-
228221
try {
229222
const texture = await this.textureCache.loadTexture(patternPath);
230223

balancer/ui/src/lib/patterns/pattern-selector.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export function getPatternPathByIndex(index: number): string {
3434
* Get pattern file path for a team name
3535
*/
3636
export function getPatternPathForTeam(teamName: string): string {
37+
if (teamName === "owasp") {
38+
return "/balancer/patterns/special_owasp.png";
39+
}
3740
const index = getPatternIndexForTeam(teamName);
3841
return getPatternPathByIndex(index);
3942
}

balancer/ui/src/pages/CtfPage.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
} from "@/lib/challenges/challenge-mapper";
1818
import { CountryGeometryManager } from "@/lib/globe/country-geometry";
1919
import { loadGeoJSON, type CountryData } from "@/lib/globe/data/geojson-loader";
20-
import { getPatternIndexForTeam } from "@/lib/patterns/pattern-selector";
20+
import { getPatternPathForTeam } from "@/lib/patterns/pattern-selector";
2121

2222
// CSS Color Utilities
2323
function getCSSVariable(name: string): string {
@@ -165,15 +165,15 @@ export default function CtfPage() {
165165
const countryName =
166166
preparedData.challengeToCountryMap.get(challenge.key) ?? null;
167167
const firstSolver = challenge.firstSolver || null;
168-
const patternIndex = firstSolver
169-
? getPatternIndexForTeam(firstSolver)
168+
const patternPath = firstSolver
169+
? getPatternPathForTeam(firstSolver)
170170
: undefined;
171171

172172
return {
173173
challenge,
174174
countryName,
175175
firstSolver,
176-
patternIndex,
176+
patternPath,
177177
};
178178
});
179179

@@ -207,7 +207,7 @@ export default function CtfPage() {
207207
globeHandleRef.current.focusAndHighlightCountries(
208208
newlySolved.map((s) => ({
209209
countryName: s.countryName,
210-
patternIndex: s.patternIndex,
210+
patternPath: s.patternPath,
211211
}))
212212
);
213213

@@ -256,7 +256,7 @@ export default function CtfPage() {
256256
setLoadingProgress(60);
257257
let solved = new Set<string>();
258258
let countriesWithChallenges = new Set<string>();
259-
let solvedWithPatterns = new Map<string, number>();
259+
let solvedWithPatterns = new Map<string, string>();
260260
const challengeToCountryMap = new Map<string, string>();
261261

262262
if (challenges.length > 0) {

0 commit comments

Comments
 (0)