package de.luca.lager; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Rechnet aus, wie schnell etwas reinkommt. * * Drei Quellen: * - Geld aus dem Scoreboard, das steht ja laufend da. * - Was du einsammelst: die Mod schaut deinem Rucksack zu und zaehlt, * was dazukommt. Gibt dir die Schaufel neunfach Sand, zaehlt sie neun — * es geht um das, was du wirklich bekommst, nicht um den Klick. * - Was in den Truhen liegt. Das weiss dein Spiel erst, wenn du sie * aufmachst, darum wird der Wert dort erst ab der zweiten Sichtung was. */ public class Farm { /** So weit schaue ich zurueck, aelteres wirft die Rechnung durcheinander. */ private static final long FENSTER = 6 * 3600000L; /** Unter dieser Spanne ist ein Wert je Stunde reine Fantasie. */ private static final long MINDEST_SPANNE = 60000L; /** Hoechstens so oft einen Messpunkt setzen. */ private static final long PUNKT_ABSTAND = 30000L; private static final int MAX_PUNKTE = 120; private static final int MAX_SACHEN = 60; public static class Punkt { public final long zeit; public final long menge; public Punkt(long zeit, long menge) { this.zeit = zeit; this.menge = menge; } } /** Verlauf je Gegenstand: wie viel insgesamt in den Truhen lag. */ public final Map> truhen = new LinkedHashMap>(); /** Verlauf je Gegenstand: wie viel du insgesamt eingesammelt hast. */ public final Map> gefarmt = new LinkedHashMap>(); /** Der laufende Zaehler dazu — der steht immer auf dem neuesten Stand. */ public final Map gesamt = new LinkedHashMap(); /** Verlauf des Vermoegens (Bargeld und Bank zusammen). */ public final List geld = new ArrayList(); /** Wann die Mod angefangen hat mitzuzaehlen. */ public long start = System.currentTimeMillis(); // ================================================================= // Mitschreiben // ================================================================= /** Was gerade eingesammelt wurde, oben draufzaehlen. */ public void einsammeln(String name, long dazu, long jetzt) { if (dazu <= 0) { return; } Long bisher = gesamt.get(name); long neu = (bisher == null ? 0 : bisher) + dazu; gesamt.put(name, neu); punktSetzen(gefarmt, name, neu, jetzt); aufraeumen(gefarmt); } /** Was in den Truhen liegt. Wird weniger, faengt die Zaehlung neu an. */ public void ausTruhe(String name, long menge, long jetzt) { List l = truhen.get(name); if (l != null && !l.isEmpty() && menge < l.get(l.size() - 1).menge) { // Rausgenommen oder verkauft — sonst kaeme ein Minus heraus. l.clear(); } punktSetzen(truhen, name, menge, jetzt); aufraeumen(truhen); } public void merkenGeld(long betrag, long jetzt) { if (!geld.isEmpty()) { Punkt letzter = geld.get(geld.size() - 1); if (letzter.menge == betrag && jetzt - letzter.zeit < PUNKT_ABSTAND) { return; } } geld.add(new Punkt(jetzt, betrag)); stutzen(geld); } private static void punktSetzen(Map> wo, String name, long menge, long jetzt) { List l = wo.get(name); if (l == null) { l = new ArrayList(); wo.put(name, l); } if (!l.isEmpty()) { Punkt letzter = l.get(l.size() - 1); if (jetzt - letzter.zeit < PUNKT_ABSTAND) { // Noch zu frisch: den letzten Punkt nur hochsetzen. l.set(l.size() - 1, new Punkt(letzter.zeit, menge)); return; } } l.add(new Punkt(jetzt, menge)); stutzen(l); } private static void stutzen(List l) { while (l.size() > MAX_PUNKTE) { l.remove(0); } } /** Nur die zuletzt gesehenen Sachen behalten, sonst waechst die Datei ewig. */ private static void aufraeumen(Map> wo) { while (wo.size() > MAX_SACHEN) { String aeltester = null; long zeit = Long.MAX_VALUE; for (Map.Entry> e : wo.entrySet()) { List l = e.getValue(); long z = l.isEmpty() ? 0 : l.get(l.size() - 1).zeit; if (z < zeit) { zeit = z; aeltester = e.getKey(); } } if (aeltester == null) { return; } wo.remove(aeltester); } } // ================================================================= // Auswerten // ================================================================= public Double gefarmtProStunde(String name, long jetzt) { return proStunde(gefarmt.get(name), jetzt); } public Double truheProStunde(String name, long jetzt) { return proStunde(truhen.get(name), jetzt); } public Double geldProStunde(long jetzt) { return proStunde(geld, jetzt); } public long geldSpanneMinuten(long jetzt) { return spanne(geld, jetzt); } public long gefarmtSpanneMinuten(String name, long jetzt) { return spanne(gefarmt.get(name), jetzt); } private static Double proStunde(List l, long jetzt) { if (l == null || l.size() < 2) { return null; } Punkt letzter = l.get(l.size() - 1); Punkt erster = null; for (Punkt p : l) { if (jetzt - p.zeit <= FENSTER) { erster = p; break; } } if (erster == null || erster == letzter) { return null; } long dauer = letzter.zeit - erster.zeit; if (dauer < MINDEST_SPANNE) { return null; } return (letzter.menge - erster.menge) * 3600000.0 / dauer; } private static long spanne(List l, long jetzt) { if (l == null || l.size() < 2) { return 0; } Punkt letzter = l.get(l.size() - 1); for (Punkt p : l) { if (jetzt - p.zeit <= FENSTER) { return Math.max((letzter.zeit - p.zeit) / 60000, 0); } } return 0; } /** * Wie lange es bei dem Tempo noch dauert, in Stunden. * Null heisst: so nicht auszurechnen. */ public static Double stundenBis(long fehlt, Double proStunde) { if (fehlt <= 0 || proStunde == null || proStunde <= 0) { return null; } return fehlt / proStunde; } /** Aus Stunden etwas machen, das man lesen kann. */ public static String dauer(Double stunden) { if (stunden == null) { return "—"; } long minuten = Math.round(stunden * 60); if (minuten < 60) { return minuten + " min"; } long tage = minuten / (60 * 24); if (tage > 0) { return tage + " Tage " + ((minuten % (60 * 24)) / 60) + " h"; } return (minuten / 60) + " h " + (minuten % 60) + " min"; } }