Spieler detecten wenn er über ein bestimmten Block läuft java?

3 Antworten

Von Experte Brockdish bestätigt

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:

Bild zum Beitrag

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:

Bild zum Beitrag

Woher ich das weiß:eigene Erfahrung
 - (Computer, Spiele und Gaming, Minecraft)  - (Computer, Spiele und Gaming, Minecraft)
JanMarcel01  05.08.2021, 10:21

Ich würde auf keinen Fall das PlayerMoveEvent nutzen, das wird einfach bereits an ein paar Spielern viel zu oft getriggered

0
JanMarcel01  05.08.2021, 16:18
@DerEnzon

Wie in meiner Antwort geschrieben würde ich einen Scheduler nutzen, welcher jeden bzw. jeden 2. Tick ausgeführt wird

1
DerEnzon  05.08.2021, 16:28
@JanMarcel01

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.

0
JanMarcel01  05.08.2021, 16:30
@DerEnzon

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

0
DerEnzon  05.08.2021, 16:32
@JanMarcel01

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

0
DerEnzon  05.08.2021, 16:34
@DerEnzon

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.

0

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)

Woher ich das weiß:eigene Erfahrung