Files
Runelite-EssentialsPlus/item-charges.md
T
2026-09-18 17:18:57 +02:00

13 KiB
Raw Blame History

Item charges – Taskbeschreibung

Implementiere einen „Item charges"-Helper in Essentials Plus (com.example.essentialsplus.helpers): Auf dem Icon jedes Items mit bekanntem Charge/Füllstand wird eine Zahl gerendert. Manche Items zeigen mehrere Zahlen (z. B. Toxic Blowpipe: Scales + Darts). Togglebar per Checkbox, anzeige in Inventar, Ausrüstung und (optional) Bank.

Beispiele:

  • Toxic Blowpipe (mit Scales) → scales-Zahl; mit geladenen Darts → zweiter Wert (Darts-Marker, s. Hinweise).
  • Dizan's Quiver → zwei Zahlen: Ammo (CHARGES_DIZANAS_QUIVER_QUANTITY) + Blessing (CHARGES_DIZANAS_QUIVER_BLESSING).
  • Trident/Shadow/Tome/Bowfa etc. → eine Zahl.
  • Lootingsack: Geldwert (Coins) als Zahl auf dem Sack-Icon.
  • Coal Bag: Füllstand via Chat-Tracking + Persistenz (kein Varbit!).

Format: Ganzzahlen / Stack-Format (Geld: QuantityFormatter.quantityToStackSize, z. B. 1.2M). Unbekannter Wert → ?.

Datenquellen & Mechanik

1. CHARGES_*-Varbits (Hauptquelle, charakterweit)

Werte via client.getVarbitValue(id) (net.runelite.api.gameval.VarbitID). Mapping Item-Gruppe → Varbit (verifiziert, Release 1.12.39). Varbit aus der ID-Variante des Items ableiten (s. Quelle 2), nicht aus einem Katalog — zwei identische Waffen haben nur EINEN Varbit-Wert (OSRS-Grenze!).

Item-Gruppe (ItemID-Konstanten) VarbitID-Konstante
TOXIC_BLOWPIPE, TOXIC_BLOWPIPE_LOADED, TOXIC_BLOWPIPE_ORNAMENT, TOXIC_BLOWPIPE_LOADED_ORNAMENT CHARGES_TOXIC_BLOWPIPE_QUANTITY
SERPENTINE_HELM, SERPENTINE_HELM_CHARGED, _CYAN, _CYAN_CHARGED, _RED, _RED_CHARGED CHARGES_SERPENTINE_HELM_QUANTITY
WARPED_SCEPTRE, WARPED_SCEPTRE_UNCHARGED CHARGES_WARPED_SCEPTRE_QUANTITY
TUMEKENS_SHADOW, TUMEKENS_SHADOW_UNCHARGED, TUMEKENS_HEKA, TUMEKENS_HEKA_UNCHARGED CHARGES_TUMEKENS_SHADOW_QUANTITY
SANGUINESTI_STAFF, SANGUINESTI_STAFF_UNCHARGED, _OR, _UNCHARGED_OR CHARGES_SANGUINESTI_STAFF_QUANTITY
TRIDENT_OF_THE_SEAS (+ _E), jew. gecharge/un-gecharge-Varianten CHARGES_TRIDENT_OF_THE_SEAS_QUANTITY bzw. ..._E_QUANTITY
TOXIC_STAFF_OF_THE_DEAD (+ _UNCHARGED, _OR-Varianten) CHARGES_TOXIC_STAFF_OF_THE_DEAD_QUANTITY
BOW_OF_FAERDHINEN, BOW_OF_FAERDHINEN_INACTIVE, _INFINITE* CHARGES_BOW_OF_FAERDHINEN_QUANTITY (+ CHARGES_BOW_OF_FAERDHINEN_CORRUPTION für korrupte Variante)
BLADE_OF_SAELDOR, BLADE_OF_SAELDOR_INACTIVE, _INFINITE CHARGES_BLADE_OF_SAELDOR_QUANTITY (+ _CORRUPTION)
VENATOR_BOW, VENATOR_BOW_UNCHARGED, VENATOR_BOW_ORNAMENT(_UNCHARGED) CHARGES_VENATOR_BOW_QUANTITY
TONALZTICS_OF_RALOS_CHARGED, _UNCHARGED CHARGES_TONALZTICS_OF_RALOS_QUANTITY
ARCLIGHT CHARGES_ARCLIGHT_QUANTITY
DIZANAS_QUIVER_CHARGED, _UNCHARGED, _INFINITE, _BROKEN, Trouver-Varianten CHARGES_DIZANAS_QUIVER_QUANTITY (Ammo) + CHARGES_DIZANAS_QUIVER_BLESSING (Blessing) — zwei Zahlen
TOME_OF_FIRE, TOME_OF_FIRE_UNCHARGED CHARGES_TOME_OF_FIRE_QUANTITY
TOME_OF_WATER, TOME_OF_WATER_UNCHARGED CHARGES_TOME_OF_WATER_QUANTITY
TOME_OF_EARTH, TOME_OF_EARTH_UNCHARGED CHARGES_TOME_OF_EARTH_QUANTITY
ASH_SANCTIFIER CHARGES_ASH_SANCTIFIER_QUANTITY
BONECRUSHER CHARGES_BONECRUSHER_QUANTITY
BRYOPHYTAS_STAFF CHARGES_BRYOPHYTAS_STAFF_QUANTITY
CIRCLET_OF_WATER CHARGES_CIRCLET_OF_WATER_QUANTITY
SOUL_BEARER CHARGES_SOUL_BEARER_QUANTITY
CELESTIAL_RING, CELESTIAL_RING_CHARGED CHARGES_CELESTIAL_RING_QUANTITY
WILD_CAVE_SCEPTRE_CHARGED, WILD_CAVE_SCEPTRE_UNCHARGED CHARGES_WILDERNESS_WEAPON_QUANTITY
BRACELET_OF_ETHEREUM CHARGES_BRACELET_OF_ETHEREUM_QUANTITY
RING_OF_SUFFERING CHARGES_RING_OF_SUFFERING_QUANTITY
XERIC_TALISMAN, XERIC_TALISMAN_EMPTY CHARGES_XERICS_TALISMAN_QUANTITY
RING_OF_SHADOWS, RING_OF_SHADOWS_UNCHARGED CHARGES_RING_OF_SHADOWS_QUANTITY
ECHO_BOOTS CHARGES_ECHO_BOOTS_QUANTITY
AMULET_OF_BLOOD_FURY CHARGES_AMULET_OF_BLOOD_FURY_QUANTITY
GIANTSOUL_AMULET_CHARGED, _UNCHARGED CHARGES_GIANTSOUL_AMULET_QUANTITY
EYE_OF_AYAK, EYE_OF_AYAK_UNCHARGED CHARGES_EYE_OF_AYAK_QUANTITY
HORN_OF_PLENTY, _UNCHARGED, SAILORS_AMULET, _EMPTY, COWBELL_AMULET, _EMPTY, PENDANT_OF_ATES, _EMPTY jew. CHARGES_*_QUANTITY-Varbit
Crystal Armour/Tools (Crystal, CRYSTAL_* piece IDs) CHARGES_CRYSTAL_ARMOUR_QUANTITY, CHARGES_CRYSTAL_TOOLS_QUANTITY, CHARGES_CRYSTAL_WEAK_QUANTITY
ALCHEMIST_RING CHARGES_ALCHEMIST_AMULET_QUANTITY

Vollständige Liste ergänzen per javap -constants net.runelite.api.gameval.VarbitID | grep 'CHARGES_.*_QUANTITY' gegen das runelite-api-Jar (release 1.12.39; Pfad s. Referenzen). Das sind ~55 Konstanten; es kommen auch Solo-/Sailing-Charges vor (CHARGES_PLANK_SACK*, CHARGES_BOWSTRING_SPOOL*), nur relevante übernehmen. Stichproben-Hinweis: DBTableID$Charges$Row (in runelite-api net.runelite.api.gameval.DBTableID) listet dieselben Charge-Typen als DB-Rows (Referenz/Querschnitt, nicht zwingend zur Laufzeit nötig).

Varianten-Ableitung für die Tabelle: Einträge in net.runelite.api.gameval.ItemID mit typischen Suffixen (_CHARGED, _UNCHARGED, _INACTIVE, _EMPTY, _LOADED, _OR, _CYAN/_RED, _TROUVER, _INFINITE, _BROKEN) — per javap -constants ... ItemID | grep verifizieren.

2. Item-ID-Statusvarianten (Ladungs-Status)

Viele Items wechseln die Item-ID bei leer/laden — mehrere exakte IDs auf dieselbe Charge abbilden bzw. „0"-Semantik:

  • TOXIC_BLOWPIPE (12924) vs TOXIC_BLOWPIPE_LOADED (12926): Darts geladen: ja/nein (zweiter Wert, Marker; die exakte Dart-Anzahl ist NICHT in der API — kein Varbit/Container). DRYGORE_BLOWPIPE vs DRYGORE_BLOWPIPE_LOADED analog.
  • BOW_OF_FAERDHINEN_INACTIVE → 0; BLADE_OF_SAELDOR_INACTIVE → 0; *_INFINITE → „∞".
  • Alle *_UNCHARGED/*_EMPTY → 0 bzw. kein Varbit abfragen.

3. Container (Echtzeit; per GameTick gelesen)

  • Lootingsack: client.getItemContainer(InventoryID.LOOTING_BAG) (auch LOOTING_BAG_OPEN). Geldwert = Σ qty von ItemID.COINS im Container. (Plugin hat bereits readContainer()/WealthStore für Loot — hier eigenes Lesen im Overlay-Tick, da das Overlay nicht an den Container-Event gebunden ist.)
  • Dizan's Quiver Ammo: InventoryID.DIZANAS_QUIVER_AMMO als Crosscheck/Geld-Anzeige zum Varbit-Wert möglich.
  • Coal/Gem/Herb sack: kein Container, kein Varbit (verifiziert) → Quelle 4.

4. Coal Bag — Chat-Tracking + Persistenz

  • Kein Varbit/Container in VarbitID/InventoryID (verifiziert; nur ItemID.COAL_BAG/COAL_BAG_OPEN).
  • Füllstand (max 27) ableiten aus Chat-Nachrichten + letzten bekannten Wert pro Account in configManager persistieren (key coalBag.<accountKey>, Wert int 0–27; accountKey-Konvention wie bestehende Persistenz im Plugin).
  • Zu verarbeitende Muster (ChatMessage-Filter Game): Check-/Fill-Feedback „[…]X coal in your coal bag]" o. Ä. exakt in-game verifizieren (2024 wurde Feedback von Popups auf Chat umgestellt); zusätzlich Empty → 0; bei unbekannter Nachricht/Login ohne Check → ? anzeigen statt falscher Zahl.
  • ChatMessage-Events: Fehler-tolerant parsen (Regex), bei Update sofort speichern. Beim LOGOUT aktuellen Wert speichern. Optional Rechtsklick „Coal bag vergessen" → Wert nicht aus Chat-Nachrichten ableiten.

Neue Dateien

helpers/ItemCharges.java (@Singleton, Logik)

  • Datenmodell: ChargeValue { String text; Color color; } (+ optional 2. Wert). Lookup-API List<ChargeValue> chargesFor(int itemId):
    1. exakte itemId in Tabelle (Load/Empty/Inactive-Varianten); dann
    2. itemManager.canonicalize(itemId) (Noten/Placeholder) erneut prüfen.
  • CHARGE_MAP: Map<Integer itemId, ChargeSource> statisch aufgebaut aus den ItemID-Konstanten (Quelle 1+2); ChargeSource = Varbit-Konstante bzw. COAL_BAG-Typ bzw. LOOTING_BAG-Container-Typ.
  • State: Coal-Bag-Count pro Account + Map<Integer, ...>-Cache nur so weit nötig (Varbit-Lesen ist billig; kein harter Cache zwingend).
  • Events (im Plugin registriert, Muster TreeCooldowns):
    • GameTick → die zwei Bag-Varbits/Container aktualisieren.
    • VarbitChanged → relevante Varbit-Id → Value merken.
    • ChatMessage → Coal-Bag-Messages parsen (s. o.), speichern.
    • GameStateChanged → != LOGGED_IN → reset(), Coal-Bag-Count aus configManager laden bzw. auf „?" zurücksetzen.
  • Reset: Coal-Bag-Cache auf ? beim Logout (Persistenz bleibt).

helpers/ItemChargesOverlay.java (WidgetItemOverlay)

  • showOnInventory(); showOnEquipment(); showOnBank(); — Bank über Config-Sub-Key steuerbar (s. unten).
  • renderItemOverlay(g, itemId, WidgetItem):
    • if (!config.itemCharges()) return;
    • List<ChargeValue> aus chargesFor(itemId); leer → nichts rendern.
    • Zahl unten-links am Icon (offizielles RuneLite-Muster): bounds.x - 1, bounds.y + 15, mit Schatten (Fonts.RUNESCAPE_SMALL bzw. TimerTextSize), Farbe aus itemChargesColor; 2. Wert (Blowpipe-Darts, Quiver-Blessing) darüber (bounds.y - 3) in itemChargesSecondaryColor.
    • Geld (Lootingsack): Stack-Size-Format; Low-Charge-Färbung ab itemChargesLowAt → itemChargesLowColor.
  • Coins/Loot-Bag-Wert: aus chargesFor(LOOTING_BAG_OPEN/LOOTING_BAG)-Container-Lesung im Overlay-Tick (Falls Container null → kein Wert).

Zu ändernde Dateien

  • EssentialsPlusConfig.java: @ConfigItem itemCharges (bool, default false, position ~37). Optionen als configManager-Keys via setHelperOption (Muster wie treeCooldowns):
    • itemChargesWeapons (bool, true) — Varbit-Charges an/aus
    • itemChargesBags (bool, true) — Loot-Bag-Geld + Coal-Bag-Füllstand an/aus
    • itemChargesBank (bool, false) — Overlay auch in Bank (Achtung Hinweise!)
    • itemChargesSize (TimerTextSize, SMALL), itemChargesColor (Color, weiß), itemChargesSecondaryColor (Color, hellgrau 0xC0C0C0), itemChargesLowColor (Color, rot 0xFF3333), itemChargesLowAt (int, 0 = aus)
  • EssentialsPlusPlugin.java: @Inject ItemCharges + ItemChargesOverlay; startUp(): eventBus.register(itemCharges), overlayManager.add(itemChargesOverlay); shutDown(): spiegeln + itemCharges.reset(). isHelperOption(): case "itemCharges" → config.itemCharges(). setHelperOption/onConfigChanged: Bestände für itemcharges*-Keys refresh (Muster solcher Bestands-Abschnitte).
  • HelpersCard.java: neues JCheckBox "Item charges" (Tooltip: „Charge-Zahl auf Item-Icons (Blowpipe, Trident, Tome, …) + Loot-Bag-Geld & Coal-Bag-Füllstand. Rechtsklick für Optionen"). Rechtsklick-Menü analog styleMenu/treeMenu: Toggles itemChargesWeapons/itemChargesBags/itemChargesBank, Größe, Farben, Schwellenwert, Reset. refresh() erweitern.

Verifikation

  • ./gradlew compileJava (bzw. ./gradlew deploy für Bolt).
  • Manuell: Blowpipe mit Scales (nur Scales-Zahl) → mit Darts laden (2. Zahl erscheint); Trident/Shadow/Sang/Tome (Zahl); Lootingsack mit Coins betreten (Geld auf Sack-Icon); Coal Bag füllen → Zahl steigt, Empty → 0, Relog → Wert bleibt; Bank öffnen mit itemChargesBank → Zahlen auch dort; beide Blowpipes (leer + geladen) im Inventar → korrekte per-ID-Darstellung.

Hinweise / Einschränkungen

  • CHARGES_*-Varbits sind charakterweit, nicht pro Item-Exemplar: zwei unterschiedlich geladene Tridents zeigen denselben Wert (OSRS-Systemgrenze, deckungsgleich mit dem In-Game-Charge-Overlay).
  • Bank-Anzeige dementsprechend unzuverlässig für „unbenutzte" Kopien; default daher itemChargesBank = false.
  • Coal Bag: nur Heuristik (Chat + Persistenz), kein API-Wert; nach Login unbekannt → ?.
  • Blowpipe: Dart-Anzahl nicht in der API → 2. Wert ist Darts-geladen-Marker, keine Zahl.
  • Keine Chat-Popup-abhängigkeit (Popup = ist abgeschaltet hat), ausschließlich ChatMessage-Events verwenden.

Referenzen

  • tree-cooldown.md (gleiche Struktur), reflect.txt/Cachierte Jars für Konstanten:
    • runelite-api: /home/hikyu/.gradle/caches/modules-2/files-2.1/net.runelite/runelite-api/1.12.39/<hash>/runelite-api-1.12.39.jar → net/runelite/api/gameval/{VarbitID,ItemID,InventoryID,DBTableID$Charges$Row}
    • client: /home/hikyu/.gradle/caches/modules-2/files-2.1/net.runelite/client/1.12.39/<hash>/client-1.12.39.jar → net.runelite.client.ui.overlay.WidgetItemOverlay, components.TextComponent, ui.FontManager
  • Konventionen: helpers/TreeCooldowns.java (Logik+Events), helpers/TreeCooldownOverlay.java/ItemPriceOverlay.java (Overlay-Zeichnung), HelpersCard.java (Checkbox+Menü), EssentialsPlusPlugin.isHelperOption/setHelperOption/onConfigChanged.