• 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!

Items Spawnen!

LukyLazzer

Minecrafter
Registriert
22 Oktober 2017
Beiträge
18
Alter
26
Diamanten
300
Hey ich bin dabei zu lernen wie man Minecraft Plugins programmiert. wie man in dem Code Ausschnitt sieht will ich alle paar sekunden über einem gesetzten Kohle erz block gold spawnen. Wie ich es gemacht ist es nur ein bisschen suboptimal, da der server abstürzt wenn ich einen block setze weil er diese while schleife 100000 mal pro sekunde durchgeht^^ Weiß jemand wie ich das besser mache? Wo wir schonmal dabei sind: was gibt es für Alternativen zu .getTypeId() scheint ja nicht ganz richtig zu sein das zu verwenden.^^

Code:
    @SuppressWarnings("deprecation")
    @EventHandler(priority = EventPriority.HIGH)
    public void onSetBlock(BlockPlaceEvent placeEvent) {
        if (placeEvent.getBlock().getTypeId() == 16) {
            Location loc = placeEvent.getBlock().getLocation();
            loc.setY(loc.getY()+1);
            ItemStack i = new ItemStack(266, 1);
            while (placeEvent.getBlock().getLocation().getBlock().getTypeId() == 16) {
                placeEvent.getBlock().getWorld().dropItemNaturally(loc, i);
            }
        }
    }
 
Zuletzt bearbeitet:

Subjektiv

Kuhfänger
Registriert
8 Juli 2017
Beiträge
54
Diamanten
300
Minecraft
Subjektiv
Ja... der Server crasht vermutlich weil du in der while-Schleife abfragst ob der Block die TypeId 16 hat, was er dann eben immer hat und das dann permanent das Item spawnt.. das solltest du eher mit einem Scheduler machen. Ja, dafür gibt es eine andere Methode, du kannst auch einfach nach dem Material also .getType() gucken, wenn es das ist was du meinst.
 

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Verwende einfach getType(), das liefert ein Material zurück, das evtl. auch noch mit 1.13 funktioniert. Ich halte es für einigermaßen wahrscheinlich, dass getTypeId() mit 1.13 nicht mehr funktionieren könnte. Genauso könntest du Material bei ItemStack verwenden.

Beim restlichen Code wird nicht so ganz klar, warum du diese while-Schleife machst. Du holst dir dort den Block aus dem Event, davon die Location, dann wieder den Block und fragst dann wieder den Typ ab. Das könnte man auch auch als "while (true)" schreiben, was völlig sinnlos ist, da diese Schleife nie auf natürliche Weise beendet werden kann.

Du solltest dir die Koordinaten der gesetzten Kohleblöcke z.B. in einem Set merken und dann wie vom Vorposter geschrieben einen Task regelmäßig starten.
 

Subjektiv

Kuhfänger
Registriert
8 Juli 2017
Beiträge
54
Diamanten
300
Minecraft
Subjektiv
@Subjektiv dann werde ich mich mal über den Scheduler informieren.
@BlackHole Ich nehme ja den vom Block die Location und davon wieder den Block. wenn der block abgebaut wird müsste die while schleife doch aufhören oder? und was ist ein "set"?

Klar würde sie aufhören, es wird jedoch niemals dazu kommen da der Server ja crasht wenn die while-Schleife in einer extremen Geschwindigkeit diese ganzen Items spawnt, deshalb lieber Tasks benutzen, statt Schleifen, bei sowas..

Das ist ein Set
 

LukyLazzer

Minecrafter
Registriert
22 Oktober 2017
Beiträge
18
Alter
26
Diamanten
300
ich habs jetzt fast geschafft aber irgendwas stimmt noch nicht:
Code:
@EventHandler(priority = EventPriority.HIGH)
    public void onSetBlock(BlockPlaceEvent placeEvent) {
        if (placeEvent.getBlock().getType() == Material.COAL_ORE) {
            ItemStack i = new ItemStack(Material.GOLD_INGOT, 1);
            Location locBlock = placeEvent.getBlock().getLocation();
            Location loc = locBlock;
            loc.setY(loc.getY()+1);
            Bukkit.getScheduler().scheduleSyncRepeatingTask(this.plugin, new Runnable() {

                @Override
                public void run() {
                    placeEvent.getPlayer().sendMessage("Debug");
                    if (locBlock.getBlock().getType() == Material.COAL_ORE) {
                        placeEvent.getPlayer().sendMessage("Hallo!");
                        loc.getWorld().dropItemNaturally(loc, i);
                    } else {
                    
                    }
                }
            
            }, 20L, 20L);
        
        }
    }
Mir wird im 1 sekunden Takt Debug geschrieben aber es werden keine Items gespawnt
Edit: wenn ich die "sendMessage" zeile in die if bedingung schreibe, wird es nicht angezeigt.
die bedingung müsste doch richtig sein. meine vermutung ist, dass etwas mit den "variablen" nicht stimmt (aber ich hab keine Ahnung xD)
 
Zuletzt bearbeitet:

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
In Zeile 7 veränderst du die Y-Koordinate des Location-Objekts. Du könntest Location.clone() verwenden, um eine Kopie zu erhalten.

Besser wäre es, wenn du die Koordinaten in einem Set speicherst und auch das BlockBreakEvent behandelst, um dort bei abgebauten Kohleerzen die Koordinaten wieder aus dem Set zu entfernen.
 

LukyLazzer

Minecrafter
Registriert
22 Oktober 2017
Beiträge
18
Alter
26
Diamanten
300
Habe es jetzt dank dem .clone() geschafft den code zum Funktionieren zu bringen

Code:
int s;
@EventHandler(priority = EventPriority.HIGH)
    public void onSetBlock(BlockPlaceEvent placeEvent) {
        if (placeEvent.getBlock().getType() == Material.COAL_ORE) {
            ItemStack i = new ItemStack(Material.GOLD_INGOT, 1);
            Location locBlock = placeEvent.getBlock().getLocation();
            Location loc = locBlock.clone();
            loc.setY(locBlock.getY()+1);
            loc.setX(locBlock.getX()+0.5);
            loc.setZ(locBlock.getZ()+0.5);
           
            int s = Bukkit.getScheduler().scheduleSyncRepeatingTask(this.plugin, new Runnable() {
               
                @Override
                public void run() {
                    placeEvent.getPlayer().sendMessage("Debug");
                    if (locBlock.getBlock().getType() == Material.COAL_ORE) {
                        loc.getWorld().dropItemNaturally(loc, i);
                    } else {
                        Bukkit.getScheduler().cancelTask(s);
                    }
                }
            }, 20L, 20L);
        }
    }

Ich verstehe leider noch nicht weshalb ich deiner Meinung nach ein Set brauche :/.
Ich bräuchte denke ich eine Art Tabelle mit der ich über die Koordinaten an die TaskID des Schedulers komme, da ja die variable S bei setzen eines weiteren kohleblocks überschrieben wird und wenn ich die variable s in der onSetBlock Methode initialisiere erkennt er das im Scheduler nicht als initialisierung an. :/
 

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
Ich versteh gar nicht wie dieser Thread so eskalieren konnte. Dein Code aus der ersten Zeile war (sofern ich dein Anliegen richtig erahne) fast korrekt. Du brauchst weder einen Task noch muss du irgendwas mit dem Scheduler machen. Die Hinweise diese Konstrukte zu benutzen sind einfach falsch. Wenn ich später mehr Zeit habe schau ich mir das nochmal konkret an. Bis dahin wär es nett, wenn du erklären würde, was du genau vor hast. (In Worten, ohne Code). So dass jemand der absolut keine Ahnung davon hat danach in der Lage wäre diese Funktion selbst zu programmieren.

Übrigens wieder so ein typisches Beispiel warum es wichtig ist, dass man auch immer erklärt was man vor hat und nicht nur Code hinschmiert und frägt warum es nicht funktioniert.
 

LukyLazzer

Minecrafter
Registriert
22 Oktober 2017
Beiträge
18
Alter
26
Diamanten
300
Ich bin dabei Programmieren zu lernen und möchte mich an mein erstes Projekt machen.
Ich möchte einen Spielmodus aus dem Spiel Garrys Mod nachprogrammieren, der Spielmodus heißt DarkRP.
In diesem Spielmodus kann man in verschiedene Rollen schlüpfen. Als Zivilist kann man Gelddrucker aufstellen und somit Geld generieren. Das Kohle-Erz soll einen Gelddrucker darstellen (es soll später dann auch verschiedenere bessere gelddrucker geben) auf diesem Gelddrucker soll Geld also GoldIngots spawnen, das man dann später in einem Admin shop in richtiges Geld eintauschen kann.
So ist es hoffentlich verständlich erklärt.
 

Chrisliebär❤️

nur echt mit ❤️
Moderator
Registriert
19 Mai 2014
Beiträge
1.675
Diamanten
830
Als Zivilist kann man Gelddrucker aufstellen und somit Geld generieren. Das Kohle-Erz soll einen Gelddrucker darstellen (es soll später dann auch verschiedenere bessere gelddrucker geben) auf diesem Gelddrucker soll Geld also GoldIngots spawnen
Okay, dann habe ich das falsch verstanden. Ich ging aufgrund des ersten Posts davon aus, dass du beim Platzieren einmalig Items spawnen willst. In diesem Fall ist natürlich das was in diesem Thread gesagt wurde korrekt.

Um deine Frage zum Set zu beantworten. Dein aktueller Ansatz (und das liegt vermutlich daran, weil du noch nicht so viel Erfahrung hast) ist eine eher lokale Sichtweise. Du guckst dir an wann der Block plaziert wird und dann möchtest du für diesen Block Items spanwen. Das bedeutet aber auch, dass jeder einzelne deiner Block einen Task im Scheduler besitzt. Grundsätzlich sollte man nicht unnötig Tasks in den Scheduler werfen, wenn das nicht nötig ist (aber bitte nicht mit Gewalt darauf verzichten).

Was @BlackHole dir vorgeschlagen hat ist ein anderer Ansatz. Anstelle jeden Block einzeln zu betrachten, wäre es besser wenn du alle Blöcke betrachtest, die Gelddrucker sind. Das heißt du spawnst einfach für jeden Gelddrucker auf der Map das Geld. Dafür verwendest du nur noch einen Task, welchen du zu Beginn des Spiels registrierst. Dieser Task wird alle x Sekunden/Ticks ausgeführt und lässt alle bekannten Gelddrucker das Geld droppen. Der Trick besteht jetzt darin, dass du beim Platzieren eines Gelddruckers diesen in ein Set aufnimmst und diesen bei seiner Zerstörung wieder aus diesem Set entfernst. Beachte: ohne dabei einen weiteren Task zu erzeugen, du machst einfach set.add(event.getBlock()). In deinem Task musst du nun nur noch über alle Blöcke, die aktuell im Set sind iterieren und für diese das Geld droppen. Der Vorteil ist ein deutlich übersichtlicherer Code und deutlich weniger Tasks. Außerdem hast du nur noch eine zentrale Instanz, welche das Geld dropt und musst bei Änderungen (z.B. mehr Drops wenn das Spiel weiter fortgeschritten ist oder ähnliches) nicht irgendwie deine ganzen Tasks wieder einfangen.
 

LukyLazzer

Minecrafter
Registriert
22 Oktober 2017
Beiträge
18
Alter
26
Diamanten
300
Vielen dank an alle, hier ist der Code den ich dank eurer Tipps schreiben konnte :)
Code:
    Set<Location> CoalOreSet = new HashSet<Location>();
    @EventHandler(priority = EventPriority.HIGH)
    public void onSetBlock(BlockPlaceEvent placeEvent) {
        if (placeEvent.getBlock().getType() == Material.COAL_ORE) {
            ItemStack i = new ItemStack(Material.GOLD_INGOT, 1);
            Location locBlock = placeEvent.getBlock().getLocation();
            if (CoalOreSet.isEmpty()) {
                CoalOreSet.add(locBlock);
                Bukkit.getScheduler().scheduleSyncRepeatingTask(this.plugin, new Runnable() {
                   
                    @Override
                    public void run() {
                        for (Location l : CoalOreSet) {
                            Location lclone = l.clone();
                            lclone.setX(lclone.getX()+0.5);
                            lclone.setY(lclone.getY()+1);
                            lclone.setZ(lclone.getZ()+0.5);
                            lclone.getWorld().dropItemNaturally(lclone, i);
                        }
                    }
                   
                }, 60*20L, 60*20L);
            } else {
                CoalOreSet.add(locBlock);
            }
        }
    }
    @EventHandler(priority = EventPriority.HIGH)
    public void onBreakBlock(BlockBreakEvent breakEvent) {
        if (breakEvent.getBlock().getType() == Material.COAL_ORE) {
            if (CoalOreSet.contains(breakEvent.getBlock().getLocation())) {
                CoalOreSet.remove(breakEvent.getBlock().getLocation());
            }
        }
    }
Funktioniert einwandfrei.
 

LukyLazzer

Minecrafter
Registriert
22 Oktober 2017
Beiträge
18
Alter
26
Diamanten
300
Funktioniert doch nicht einwandfrei. Wenn ich alle Blöcke abbaue und dann wieder einen platziere startet sich ein weiterer Scheduler. Wie starte ich den Task am Anfang des Spiels? Schreibe ich das in meine main.class in die onEnable Funktion?

Dafür verwendest du nur noch einen Task, welchen du zu Beginn des Spiels registrierst.
 

petomka

Redstoneengineer
Registriert
8 Oktober 2012
Beiträge
41
Alter
26
Diamanten
322
Naja, irgendwas muss dein Spiel ja starten, entweder ein Methodenaufruf oder eine Instanzierung deiner Klasse. Somit kannst du den Task entweder im Konstruktor oder in entwaigen Methodenaufruf registrieren.
Das Registrieren eines Tasks gibt gleichzeitig die ID zurück, mit welcher dieser registriert wurde. Speicherst du diese also zwischen, kannst du kontrollieren, ob bereits ein solcher Task läuft und ihn beim Beenden des Spiels vom Scheduler entfernen.
 
Zuletzt bearbeitet:

BlackHole

Workaholic
Registriert
1 Juli 2012
Beiträge
752
Diamanten
0
Minecraft
BlackHole
Die Annotation von BlockPlaceEvent und BlockBreakEvent könntest du noch so ändern:
Code:
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)

Damit arbeitet dein Plugin besser mit anderen Plugins zusammen, die das Platzieren oder Abbauen von Blöcken in bestimmten Gebieten möglicherweise abbrechen.

Wie schon von @LukyLazzer geschrieben ist es wichtig, den Task auch wieder abzubrechen, wenn das letzte Kohleerz abgebaut wurde.
Außerdem solltest du den ItemStack entweder einmalig außerhalb der Eventbehandlung erzeugen (und dann bei Droppen dort ebenfalls .clone() verwenden) oder direkt beim Droppen immer einen neuen ItemStack erzeugen.
 
Oben