• Es freut uns dass du in unser Minecraft Forum gefunden hast. Hier kannst du mit über 130.000 Minecraft Fans über Minecraft diskutieren, Fragen stellen und anderen helfen. In diesem Minecraft Forum kannst du auch nach Teammitgliedern, Administratoren, Moderatoren , Supporter oder Sponsoren suchen. Gerne kannst du im Offtopic Bereich unseres Minecraft Forums auch über nicht Minecraft spezifische Themen reden. Wir hoffen dir gefällt es in unserem Minecraft Forum!

Spigot Code dynamisch verzögern

BloodEko

Schafhirte
Showcase Teilnehmer
Registriert
9 September 2012
Beiträge
144
Diamanten
36
Hey!
Vielleicht gehe ich zuerst kurz auf meinen existierenden Code ein, und dann auf das Ziel.
Code:
    public void start() {
        for (int i = 0; i < cmds.size(); i++) {
            cmds.get(index).execute(this);
            if (isEnding) break;
            index++;
        }
        index = 0;
    }
Code:
    public void execute(CommandQueue queue) {
        // ...
    }
(cmds, isEnding, index) sind Klassenvariablen. Die queue führt bei start() beliebige Command-Objekte einfach aus, indem sie die die .execute() Methode aufruft. Das läuft synchron im Main-Thread und funktioniert soweit auch ohne Probleme.

Nun zur Herausforderung. Ich möchte einen Delay Command machen, durch den X Sekunden gewartet wird, bis der nächste Command ausgeführt wird. In execute() könnte man dann einfach eine flag auf die queue setzen, allerdings habe ich bisher noch keine Idee, wie man die eigentliche Verzögerung in der CommandQueue implementieren könnte.

Die Standart ScheduleRepeatingTask... Methoden von Spigot nehmen ja keinen dynamischen, sondern nur einen konstanten Delay, was mir nicht weiterhilft. Und wenn ich es in einen anderen Thread packe läuft execute() nicht mehr synchron, was es soll.

Jemand eine Idee?
 

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
Wenn ich das richtig verstehe hast du eine Queue mit Aufgaben, die du gerne schnellstmöglichst, aber unter Beibehaltung eines zeitlichen Mindestabstands ausführen möchtest. Das ganze ist recht einfach umzusetzen, aber es gibt einen Punkt an dem man etwas optimieren kann. Daher nur die einfache Variante ausführlich:

Zuerst erstellst du deine Worker Queue ganz normal mit der Datenstruktur deiner Wahl. Gleichzeitig fügst du einen normalen Bukkittask in den Bukkitscheduler ein, der in jedem Tick prüft, ob die Worker Queue einen Task enthält und ob seit der Ausführung des letzten Tasks die gewünschte Wartezeit vergangen ist. Wenn beides der Fall ist, dann führst du den Task aus und speicherst dir den aktuellen Zeitpunkt um den nächstmöglichen Ausführungszeitpunkt zu bestimmen.

Die Optimierung besteht nun darin, dass du den Task aus dem Bukkit Scheduler entfernst oder einfügst, je nach dem, ob deine Queue überhaupt Tasks enthält, bzw. so einreihst, dass er nur genau in dem Tick ausgeführt wird, in dem er ohnehin fällig wird, da musst du aber auch aufpassen, dass kein neuerer Task kommt, der ggf. früher ausgeführt werden muss. Das ganze ist ein klassischer Scheduler Algorithmus. Falls du auch aus anderen Threads arbeitest, musst du aber aufpassen, dass die Worker Queue und auch das dynamische deaktivieren des (Bukkit)Tasks Threadsafe sind.

Es kann allerdings auch sein, dass du anstelle eines Repeating Tasks ganz einfach in jeder Ausführung des Tasks den Task neu registrieren willst, je nach dem ob ich dein Problem richtig verstanden hab oder nicht.
 

BloodEko

Schafhirte
Showcase Teilnehmer
Registriert
9 September 2012
Beiträge
144
Diamanten
36
@❤️可愛い❤️
Wenn ich deinen Post richtig verstanden habe, würde ich sagen fast.
Schnellstmöglich ist richtig, "Beibehaltung eines zeitlichen Mindesabstandes" allerdings nicht.
Nehmen wir mal eine Beispielqueue mit 7 Einträgen Ausgabe Ausgabe Ausgabe -> delay 3s -> Ausgabe -> delay 2s -> Ausgabe
Die ersten 3 Ausgaben würden instant(also ohne Wartezeit zwischen den Einträgen) ausgegeben, dann 3 Sekunden warten, Ausgabe, 2 Sekunden warten, Ausgabe.

Die Commands wären z.b. so implementiert, die Implementierung des Delay selbst in der queue fehlt aber.
Code:
    public void execute(CommandQueue queue) {
        System.out.println("random text");
    }
Code:
    public void execute(CommandQueue queue) {
        queue.setDelay(3);
    }

Derzeit ist es sozusagen einfach nur ein Loop welcher durch die Liste iteriert und die Commands anstößt. Es kann mehrere queues geben, welche da synchron und noch ohne delay hintereinander statt nebeneinander laufen, das würde sich ändern und muss bedacht werden.
 

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
Ja in dem Fall musst du einfach nur am Ende deines Tasks den selben Task wieder in den Bukkitscheduler werfen. Erstell dir ne Klasse, die das Taskinterface des Bukkit Schedulers implementiert und am Ende der run Methode registriert sich der Task selbst wieder neu.
 

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Der Bukkit-Scheduler arbeitet mit Ticks. Wenn der Server mit weniger als 20 TPS läuft, ist diese Zeitmessung also nicht genau.
Du kannst also durchaus einen anderen Thread verwenden und die Methoden des Schedulers nutzen, um Bukkit-Methoden synchron beim nächsten Tick auszuführen.
 

BloodEko

Schafhirte
Showcase Teilnehmer
Registriert
9 September 2012
Beiträge
144
Diamanten
36
So in etwa habe ich es jetzt. Die queue Runnable implementieren lassen und start() zu run() umbenennen, dann sind diese Zeilen Gold wert und können einfach in den loop gepackt werden:
Code:
            // in loop
            if (waitTicks > 0) {
                Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, this, waitTicks);
                waitTicks = 0;
                break;
            }
Dankeschön an euch, und auch an baba. :)
 
Oben