Spieler detecten wenn er über ein bestimmten Block läuft java?
Hallo, wie kann man irgendwelche Sachen ausführen lassen wenn man über ein bestimmten Block läuft?
Also zum Beispiel wenn ein Spieler über Bedrock oder so läuft soll eine Nachricht gesendet werden oder sowas.
Wie geht sowas?
Danke im Vorraus!
3 Antworten
Dazu müsstest du das PlayerMoveEvent verwenden und abfragen, ob der Spieler sich über einem Bedrock-Block befindet.
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
public class BlockWalkListener implements Listener {
@EventHandler
public void onWalkAcrossBlock(PlayerMoveEvent event) {
Player player = event.getPlayer();
Location toLocation = event.getTo();
if (getMaterialUnderneath(toLocation) == Material.BEDROCK) {
player.sendMessage("Du läufst auf Bedrock");
}
}
private Material getMaterialUnderneath(Location location) {
return location.clone().subtract(0, 1, 0).getBlock().getType();
}
}
Ich habe erst eine Methode geschrieben, mit der man das Material des Blocks unter einer angegebenen Location bekommt.
Dadrüber habe ich einen Eventhandler angelegt, der eben jedes Mal wenn das PlayerMoveEvent ausgelöst wird mit der Methode überprüft, ob die Location, wohin sich der Spieler bewegt hat, über einem Bedrock-Block befindet. Wenn ja, wird die Nachricht ausgegeben.
Jetzt funktioniert es erstmal. Aber: Das PlayerMoveEvent wird jeden Minecraft-Tick, also jede Zwanzigstel-Sekunde ausgelöst, wenn sich der Spieler bewegt. Also wird man ziemlich mit Nachrichten zugespammt:
Ich nehme aber an, dass du nur eine Nachricht gesendet bekommen willst, wenn du das erste Mal auf Bedrock läufst. Und erst wieder erneut eine Nachricht bekommen willst, wenn du in der Zwischenzeit auf einem anderen Block warst. Um das zu erreichen müssen wir den letzten Block auf dem der Player stand in einer Map speichern und bei jedem MoveEvent abfragen, ob der gespeicherte Block vorher nicht Bedrock war:
public class BlockWalkListener implements Listener {
private final HashMap<Player, Material> playerLastBlockSteppedOnHashMap = new HashMap<>();
@EventHandler
public void onWalkAcrossBlock(PlayerMoveEvent event) {
Player player = event.getPlayer();
Location toLocation = event.getTo();
Material materialUnderneath = getMaterialUnderneath(toLocation);
if (materialUnderneath == Material.BEDROCK && playerLastBlockSteppedOnHashMap.get(player) != Material.BEDROCK) {
player.sendMessage("Du läufst auf Bedrock");
}
playerLastBlockSteppedOnHashMap.put(player, materialUnderneath);
}
private Material getMaterialUnderneath(Location location) {
return location.clone().subtract(0, 1, 0).getBlock().getType();
}
}
Jetzt kommen die Nachrichten nur noch einzeln, auch wenn man sich auf dem Block herumbewegt:
Wie in meiner Antwort geschrieben würde ich einen Scheduler nutzen, welcher jeden bzw. jeden 2. Tick ausgeführt wird
Okay, das geht natürlich auch. Aber so krass zieht meine Methode auch die Performance nicht. Computer sind schnell heutzutage. Und n paar HashMap-Operationen sind nicht besonders anspruchsvoll.
Aber das Event wird bereits bei 20 Spielern 400 mal pro Sekunde getriggered und das auch, wenn sie bspw. nur ihren Kopf bewegen ohne ihre Position zu verändern.
Bei noch mehr Spielern steigt das natürlich exponentiell
Da hast du recht, aber es steigt nicht exponentiell. Aber generell hast du Recht. Ich werd gleich noch ne Lösung mit Scheduler posten. Moment :D
Ach ja und man muss natürlich auch bedenken, dass bei deiner Lösung auch gecheckt wird, ob ein Spieler aufm Block steht, wenn die Spieler sich nicht bewegen. Eine Sache die mir noch einfallen würde ist, dass man mit modulo einfach macht, dass das MoveEvent nur jedes 4te mal oder getriggert wird. Also if(i % 4 == 0) {steht auf block?} Und dann halt das i immer einen hochzählen.
https://youtu.be/3Y5oJ1u0IwI dieses Video sollte das für dich erklären
Hey,
anders als DerEnzon würde ich absolut vom PlayerMoveEvent abraten, da dieses bereits bei wenigen Spielern einfach viel zu oft gerriggered wird und somit einfach unendlich viel Leistung ziehen wird.
Es ist definitiv sinnvoller einen Scheduler zu nutzen, welcher alle 2 Ticks bei jedem Spieler überprüft, auf welchem Block dieser steht.
Mfg Jannick (L1nd)
Ich würde auf keinen Fall das PlayerMoveEvent nutzen, das wird einfach bereits an ein paar Spielern viel zu oft getriggered