7.4 KiB
7.4 KiB
Skill "Reset Hourly" – Taskbeschreibung
Implementiere ein Rechtsklick-Feature „Reset Hourly" in Essentials Plus. Es erscheint an zwei Stellen:
- In-Game-XP-HUD (
skills/SkillsHudOverlay.java): Rechtsklick auf das Overlay zeigt den Menüeintrag „Reset Hourly". - Skills-Karte im Seitenpanel: auf der Overview-Karte als Eintrag im bestehenden Karten-Rechtsklick-Menü und im Skills-Tab als eigenes Rechtsklick-Popup auf der Karte.
Klick setzt die aktuell angezeigte XP-Zählung zurück. Es wirkt nur, wenn der global aktive Zeitraum Session oder Now ist. Alle anderen Zeiträume (1H, 1D, 2W, 3M, All) bleiben unberührt – insbesondere bleibt der Gesamt-XP-Wert (All) erhalten, weil er aus der ersten Sample-Spur abgeleitet wird.
Display-Sprache: Deutsch (Menütext trotzdem exakt Reset Hourly).
Hintergrund / Datenmodell
skills/SkillHistory.javaspeichert absolute XP-Samples pro Skill mit Zeitstempel (XpSample,List<XpSample> samples), ein File pro Charakter (JSON inessentials-plus/skills).ui/TimeFilter.java+ui/TimeRange.javaliefern den global geteilten Zeitraum:CURRENT("Now"),SESSION("Sess"),HOUR("1H"),DAY,TWO_WEEKS,QUARTER,ALL.- Gewinne werden als
latest - at(start)berechnet; der Start kommt ausSkillHistory.start(filter),starts(filter)undgained(filter). - Es gibt noch kein Reset-/Baseline-Feld. Der Reset wird als Zeitmarker umgesetzt, nicht durch Löschen von Samples.
Neue Dateien
skills/SkillHistory.java (erweitern, keine neue Datei)
- Zwei persistente Marker ergänzen (0 = nie zurückgesetzt):
public long resetSessionAt;public long resetNowAt;
public synchronized void reset(TimeRange range):SESSION→resetSessionAt = System.currentTimeMillis()CURRENT→resetNowAt = System.currentTimeMillis()- sonst → no-op
dirty = true(Persistenz-Flag, existiert bereits)
- Startlogik nur für die betroffenen Ranges clampen:
starts(TimeFilter): beiSESSIONfür jeden SkillMath.max(filter.start(), resetSessionAt); beiCURRENTpro SkillMath.max(currentStart(i, now), resetNowAt), idle (Long.MAX_VALUE) bleibt idle.start(TimeFilter): beiSESSIONMath.max(filter.start(), resetSessionAt); beiCURRENTnachcurrentStart(-1, now)clampen (Fallbacknowwenn idle).gained(TimeFilter): Nicht-Current-Zweig vongained(filter.start())aufgained(start(filter))umstellen, damit der Session-Clamp greift. Current-Zweig nutzt bereitsstarts(filter).
- Da
range(long),levelUps(long)undactiveMillis(long, int)ihren Start ausstart(filter)bekommen, ziehen Charts, Stats/„XP per hour" und Level-Ups automatisch mit. normalize()prüft nurskills/samples; die neuen Felder brauchen keine Migration (fehlend = 0 = nie zurückgesetzt).
skills/SkillStore.java (erweitern)
public void resetHourly(String key, TimeRange range): History perhistories.get(key)holen; wenn vorhandenh.reset(range)undsave(h)aufrufen.- Wird vom Plugin auf dem Executor aufgerufen (File-I/O), nicht auf dem Swing-/Client-Thread.
Zu ändernde Dateien
skills/SkillsHudOverlay.java
- Im Konstruktor:
addMenuEntry(net.runelite.api.MenuAction.RUNELITE_OVERLAY, "Reset Hourly", "Skills"). - Die Render-Logik nutzt bereits
history.starts(filter)/gained(filter)→ greift den Reset automatisch, kein Render-Umbau nötig. - Verifikation der API (RuneLite 1.12.39):
Overlay.addMenuEntry(MenuAction, option, target)und die 4-arg-Variante mitConsumer<MenuEntry>existieren;OverlayRendererinjiziert den Callback inMenuEntry.onClick(...)und feuertOverlayMenuClicked.
EssentialsPlusPlugin.java
- Import
net.runelite.client.events.OverlayMenuClicked(+net.runelite.client.ui.overlay.Overlayfalls nötig). public void resetSkillsHourly(String key):if (key == null) return;executor.execute(() -> skillStore.resetHourly(key, timeFilter.getRange()));- danach Panel-Refresh:
EssentialsPlusPanel p = panel; if (p != null) p.refreshSkillsLater();
@Subscribe public void onOverlayMenuClicked(OverlayMenuClicked event):- wenn
event.getOverlay() == skillsHudOverlayund"Reset Hourly".equals(event.getEntry().getOption())→resetSkillsHourly(skillKey).
- wenn
getSkillStore(),getSkillKey(),getTimeFilter()sind vorhandene Lombok-Getter;skillsHudOverlayist injiziert (EssentialsPlusPlugin.java:232).- Alternativ den
Consumer<MenuEntry>der 4-arg-addMenuEntrynutzen; dann ist keinOverlayMenuClicked-Subscriber nötig (beides funktioniert). Empfehlung: Subscriber, damit die Aktion im Plugin kapselt bleibt.
ui/EssentialsPlusPanel.java (Overview-Karte)
- In
menu(String id)imcase SKILLS(ca. Zeile 560) einen Eintrag ergänzen:JMenuItem reset = new JMenuItem("Reset Hourly");- Action: Character über
SkillsPanel.resolve(plugin.getSkillStore(), null, plugin.getSkillKey())auflösen; wenn nicht null →plugin.resetSkillsHourly(h.key);und danachrefreshSkills();.
- Kein zweites Popup auf der Overview-Karte installieren:
CardDrag(ui/CardDrag.java) konsumiert dort bereits Rechtsklick und öffnetmenu(id)– sonst gäbe es zwei Menüs.
ui/SkillsPanel.java (Skills-Tab)
- Nach
private final SkillsCard card = new SkillsCard(null);(Zeile 61) im Konstruktor einenMouseAdapteraufcardinstallieren:- bei
SwingUtilities.isRightMouseButton(e)(odere.isPopupTrigger()) einJPopupMenumitJMenuItem "Reset Hourly"bauen undmenu.show(card, e.getX(), e.getY())zeigen. - Action:
plugin.resetSkillsHourly(shownKey);danachrefresh();(bzw.refreshLater()).
- bei
- Im Skills-Tab ist keine
CardDraginstalliert, daher kollidiert das Popup nicht.
Verifikation
./gradlew test(bestehende Tests + neuer Test unten) und./gradlew build.- Neuer Test in
src/test/java/com/example/essentialsplus/SkillHistoryTest.java(Muster:recordper Reflection, package-private):- Samples über ca. eine Stunde anlegen, dann
h.reset(TimeRange.CURRENT)bzw.h.reset(TimeRange.SESSION). - Erwartung:
gained(filter)für den betroffenen Range startet neu (Baseline = Sample beiresetAt);gained(TimeRange.ALL)bleibt unverändert;1H/1Dbleiben unverändert.
- Samples über ca. eine Stunde anlegen, dann
- Manuell:
- Filter auf Sess oder Now stellen → Rechtsklick aufs XP-HUD → „Reset Hourly" →
XP gainedzählt ab 0 neu; Gesamt-XP (All) unverändert. - Filter auf
1H/1D/Allstellen → „Reset Hourly" ändert die Anzeige nicht. - Overview-Skills-Karte rechtsklicken → „Reset Hourly"; Skills-Tab-Karte rechtsklicken → „Reset Hourly".
- Nach Reset Datei
essentials-plus/skills/<key>.jsonprüfen (resetSessionAt/resetNowAtgesetzt); Relog → Session wird ohnehin vom neuen Login übersteuert,Now-Marker bleibt gespeichert.
- Filter auf Sess oder Now stellen → Rechtsklick aufs XP-HUD → „Reset Hourly" →
Hinweise / Einschränkungen
- „Reset Hourly" wirkt bewusst nur auf
SessionundNow; bei1H/1D/2W/3M/Allpassiert nichts (TimeRange-Vergleich imreset(...)). - Der Gesamtwert (
All) bleibt in jedem Fall erhalten, da er aus der ersten Sample-Spur (samples.get(0)) berechnet wird und der Reset nur einen Start-Clamp setzt. - Marker sind pro Charakter im
SkillHistory-JSON persistiert; ein fehlendes Feld nach älterem Stand bedeutet 0 (nie zurückgesetzt) und ist damit abwärtskompatibel. record(...)bleibt unverändert: Es fügt weiterhin Samples hinzu; der Reset löscht keine Historie.