Skip to content

Commit 95c6f7c

Browse files
Add advancement progress tracker (#4568)
* Fix fetching advancements with invalid parents * Add progress tracker to advancements * Use Java language key for progress counter
1 parent 5019b5a commit 95c6f7c

File tree

2 files changed

+50
-18
lines changed

2 files changed

+50
-18
lines changed

core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,15 @@ public String getDisplayColor() {
8282
this.rootId = this.advancement.getId();
8383
} else {
8484
// Go through our cache, and descend until we find the root ID
85-
GeyserAdvancement advancement = advancementsCache.getStoredAdvancements().get(this.advancement.getParentId());
86-
if (advancement.getParentId() == null) {
87-
this.rootId = advancement.getId();
85+
GeyserAdvancement parent = advancementsCache.getStoredAdvancements().get(this.advancement.getParentId());
86+
if (parent == null) {
87+
// Parent doesn't exist, is invalid, or couldn't be found for another reason
88+
// So assuming there is no parent and this is the root
89+
this.rootId = this.advancement.getId();
90+
} else if (parent.getParentId() == null) {
91+
this.rootId = parent.getId();
8892
} else {
89-
this.rootId = advancement.getRootId(advancementsCache);
93+
this.rootId = parent.getRootId(advancementsCache);
9094
}
9195
}
9296
}

core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,15 @@ public void buildAndShowInfoForm(GeyserAdvancement advancement) {
158158
// Cache language for easier access
159159
String language = session.locale();
160160

161-
String earned = isEarned(advancement) ? "yes" : "no";
161+
boolean advancementHasProgress = advancement.getRequirements().size() > 1;
162+
163+
int advancementProgress = getProgress(advancement);
164+
int advancementRequirements = advancement.getRequirements().size();
165+
166+
boolean advancementEarned = advancementRequirements > 0
167+
&& advancementProgress >= advancementRequirements;
168+
169+
String earned = advancementEarned ? "yes" : "no";
162170

163171
String description = getColorFromAdvancementFrameType(advancement) + MessageTranslator.convertMessage(advancement.getDisplayData().getDescription(), language);
164172
String earnedString = GeyserLocale.getPlayerLocaleString("geyser.advancements.earned", language, MinecraftLocale.getLocaleString("gui." + earned, language));
@@ -171,10 +179,20 @@ public void buildAndShowInfoForm(GeyserAdvancement advancement) {
171179
(Description) Mine stone with your new pickaxe
172180
173181
Earned: Yes
182+
Progress: 1/4 // When advancement has multiple requirements
174183
Parent Advancement: Minecraft // If relevant
175184
*/
176185

177186
String content = description + "\n\n§f" + earnedString + "\n";
187+
188+
if (advancementHasProgress) {
189+
// Only display progress with multiple requirements
190+
String progress = MinecraftLocale.getLocaleString("advancements.progress", language)
191+
.replaceFirst("%s", String.valueOf(advancementProgress))
192+
.replaceFirst("%s", String.valueOf(advancementRequirements));
193+
content += GeyserLocale.getPlayerLocaleString("geyser.advancements.progress", language, progress) + "\n";
194+
}
195+
178196
if (!currentAdvancementCategoryId.equals(advancement.getParentId())) {
179197
// Only display the parent if it is not the category
180198
content += GeyserLocale.getPlayerLocaleString("geyser.advancements.parentid", language, MessageTranslator.convertMessage(storedAdvancements.get(advancement.getParentId()).getDisplayData().getTitle(), language));
@@ -200,34 +218,44 @@ public void buildAndShowInfoForm(GeyserAdvancement advancement) {
200218
* @return true if the advancement has been earned.
201219
*/
202220
public boolean isEarned(GeyserAdvancement advancement) {
203-
boolean earned = false;
204-
if (advancement.getRequirements().size() == 0) {
221+
if (advancement.getRequirements().isEmpty()) {
205222
// Minecraft handles this case, so we better as well
206223
return false;
207224
}
208-
Map<String, Long> progress = storedAdvancementProgress.get(advancement.getId());
209-
if (progress != null) {
225+
// Progress should never be above requirements count, but you never know
226+
return getProgress(advancement) >= advancement.getRequirements().size();
227+
}
228+
229+
/**
230+
* Determine the progress on an advancement.
231+
*
232+
* @param advancement the advancement to determine
233+
* @return the progress on the advancement.
234+
*/
235+
public int getProgress(GeyserAdvancement advancement) {
236+
if (advancement.getRequirements().isEmpty()) {
237+
// Minecraft handles this case
238+
return 0;
239+
}
240+
int progress = 0;
241+
Map<String, Long> progressMap = storedAdvancementProgress.get(advancement.getId());
242+
if (progressMap != null) {
210243
// Each advancement's requirement must be fulfilled
211244
// For example, [[zombie, blaze, skeleton]] means that one of those three categories must be achieved
212245
// But [[zombie], [blaze], [skeleton]] means that all three requirements must be completed
213246
for (List<String> requirements : advancement.getRequirements()) {
214-
boolean requirementsDone = false;
215247
for (String requirement : requirements) {
216-
Long obtained = progress.get(requirement);
248+
Long obtained = progressMap.get(requirement);
217249
// -1 means that this particular component required for completing the advancement
218250
// has yet to be fulfilled
219251
if (obtained != null && !obtained.equals(-1L)) {
220-
requirementsDone = true;
221-
break;
252+
progress++;
222253
}
223254
}
224-
if (!requirementsDone) {
225-
return false;
226-
}
227255
}
228-
earned = true;
229256
}
230-
return earned;
257+
258+
return progress;
231259
}
232260

233261
public String getColorFromAdvancementFrameType(GeyserAdvancement advancement) {

0 commit comments

Comments
 (0)