Следуйте инструкциям в видео ниже, чтобы узнать, как установить наш сайт как веб-приложение на главный экран вашего устройства.
Примечание: Эта функция может быть недоступна в некоторых браузерах.
Бесконечный поток не будет нагружать сервер ? И как часто его запускать, те с какой периодичностью ?execute @a ~ ~ ~ execute @a[r=10] ~ ~ ~ <команда>
Например так через командные блоки, где r -- радиус.
Ещё можно при помощи sheduler'а и перебора всех игроков или сущностей.
С оптимальной. Можно запускать в отдельном цикле без задержек, тогда нагружать будет.Бесконечный поток не будет нагружать сервер ? И как часто его запускать, те с какой периодичностью ?
Не лучше ли будет перебирать игроков, вместо сущностей, и сравнивать их локации? Просто не уверен, как именно работает метод getNearbyEntities, и если там просто некоторый перебор всех сущностей - ну такое.нашёл код в интернете, если кому нибудь нужно будет пользуйтесь
int players = 0;
List<Entity> entities = player.getNearbyEntities(20,20,20);
//Iterate through the list and check if the entity is a player
for(Entity entity : entities) {
if(entity instanceof Player) {
players++;
}
}
Map<UUID,List<UUID>> founded;
int radius;
//...
//В шедулере
List<Player> players=Bukkit.getOnlinePlayers();
for(Player pl1:players) {
Location loc=pl1.getLocation();
UUID id=pl1.getUniqueId();
List<UUID> ids=founded.containsKey(id)?founded.get(id):new ArrayList<>();
for(Player pl2:players) {
if (pl1==pl2) continue;
id=pl2.getUniqueId();
if (loc.distanceSquared(pl2.getLocation())>radius) {
if(ids.contains(id)) {
ids.remove(id);
// Игрок вышел из радиуса игрока
}
} else
if (!ids.contains(id)) {
ids.add(id);
// Игрок вошел в радиус игрока
}
}
}
// Радиус лучше держать в квадрате, чтобы каждый раз не извлекать корень при подсчете расстояния
// UUID в хеш коллекциях работает быстрее чем String
public static double radius = 10000; // реальный радиус = 100
public static Map<UUID, Set<UUID>> closeDistanceMap = new HashMap<>();
@EventHandler(ignoreCancelled = true)
public void onMove(PlayerMoveEvent e) {
UUID playerUUID = e.getPlayer().getUniqueId();
Location to = e.getTo();
World world = to.getWorld();
// Опционально - фильтр, чтобы реагировать только тогда,
// когда игрок проходит целый блок
Location from = e.getFrom();
if (to.getBlockX() == from.getBlockX()
&& to.getBlockY() == from.getBlockY()
&& to.getBlockZ() == from.getBlockZ()) return;
// Проверяем всех игроков только в нужном мире
for (Player target : world.getPlayers()) {
UUID targetUUID = target.getUniqueId();
// Игрок player и target в радиусе?
if (radius <= target.getLocation().distanceSquared(to)) {
// Были ли в радиусе раньше? (Повторений же нам не надо)
Set<UUID> closeTargetsToPlayer = closeDistanceMap.getOrDefault(playerUUID, new HashSet<>());
boolean wasClose = closeTargetsToPlayer.contains(targetUUID);
// Если не были, значит добавляем, будут :)
if (!wasClose) {
closeTargetsToPlayer.add(targetUUID);
closeDistanceMap.put(playerUUID, closeTargetsToPlayer);
// <== ЗДЕСЬ же выполняем что нам нужно (приближение)
}
}
// Игрок player и target НЕ в радиусе?
else {
// Были ли в радиусе раньше? (Повторений же нам опять таки не надо)
Set<UUID> closeTargetsToPlayer = closeDistanceMap.getOrDefault(playerUUID, new HashSet<>());
boolean wasClose = closeTargetsToPlayer.contains(targetUUID);
// Если были, значит убираем
if (wasClose) {
closeTargetsToPlayer.remove(targetUUID);
closeDistanceMap.put(playerUUID, closeTargetsToPlayer);
// <== ЗДЕСЬ же выполняем что нам нужно (отдаление)
}
}
}
}
А что будет в случае, если один игрок стоит, и уже после попадания в радиус другого(ходячего) игрока начнет двигаться? Думаю, стоит ещё "обновлять" в мапе список id для target, добавляя в/убирая из него ходячего игрока.Сделал немного эффективнее, чем предыдущие варианты и с максимальными обьяснениями
PHP:// Радиус лучше держать в квадрате, чтобы каждый раз не извлекать корень при подсчете расстояния // UUID в хеш коллекциях работает быстрее чем String public static double radius = 10000; // реальный радиус = 100 public static Map<UUID, Set<UUID>> closeDistanceMap = new HashMap<>(); @EventHandler(ignoreCancelled = true) public void onMove(PlayerMoveEvent e) { UUID playerUUID = e.getPlayer().getUniqueId(); Location to = e.getTo(); World world = to.getWorld(); // Опционально - фильтр, чтобы реагировать только тогда, // когда игрок проходит целый блок Location from = e.getFrom(); if (to.getBlockX() == from.getBlockX() && to.getBlockY() == from.getBlockY() && to.getBlockZ() == from.getBlockZ()) return; // Проверяем всех игроков только в нужном мире for (Player target : world.getPlayers()) { UUID targetUUID = target.getUniqueId(); // Игрок player и target в радиусе? if (radius <= target.getLocation().distanceSquared(to)) { // Были ли в радиусе раньше? (Повторений же нам не надо) Set<UUID> closeTargetsToPlayer = closeDistanceMap.getOrDefault(playerUUID, new HashSet<>()); boolean wasClose = closeTargetsToPlayer.contains(targetUUID); // Если не были, значит добавляем, будут :) if (!wasClose) { closeTargetsToPlayer.add(targetUUID); closeDistanceMap.put(playerUUID, closeTargetsToPlayer); // <== ЗДЕСЬ же выполняем что нам нужно (приближение) } } // Игрок player и target НЕ в радиусе? else { // Были ли в радиусе раньше? (Повторений же нам опять таки не надо) Set<UUID> closeTargetsToPlayer = closeDistanceMap.getOrDefault(playerUUID, new HashSet<>()); boolean wasClose = closeTargetsToPlayer.contains(targetUUID); // Если были, значит убираем if (wasClose) { closeTargetsToPlayer.remove(targetUUID); closeDistanceMap.put(playerUUID, closeTargetsToPlayer); // <== ЗДЕСЬ же выполняем что нам нужно (отдаление) } } } }
А что будет в случае, если один игрок стоит, и уже после попадания в радиус другого(ходячего) игрока начнет двигаться? Думаю, стоит ещё "обновлять" в мапе список id для target, добавляя в/убирая из него ходячего игрока.
Принял, обновил. Добавил новые события. Исправил еще некоторые детали.Еще пара советов:
Заменить getOrDefault на computeIfAbsent(k -> new HashSet<>()); и вынести из обеих веток до условия. put в мапу ненужен.
Убрать полность .contains(). Оба метода, add и remove, уже возвращают нужные булеаны.
Причем в твоем коде они даже станут ненужны, а если править set у другого игрока, то нужны
// Радиус лучше держать в квадрате, чтобы каждый раз не извлекать корень при подсчете расстояния
// UUID в хеш коллекциях работает быстрее чем String
public static double radius = 10000; // реальный радиус = 100
public static Map<UUID, HashSet<UUID>> closeDistanceMap = new HashMap<>();
@EventHandler(ignoreCancelled = true)
public void onMove(PlayerMoveEvent e) {
Location to = e.getTo();
// Опционально - фильтр, чтобы реагировать только тогда,
// когда игрок проходит целый блок
Location from = e.getFrom();
if (to.getBlockX() == from.getBlockX()
&& to.getBlockY() == from.getBlockY()
&& to.getBlockZ() == from.getBlockZ()) return;
updateCloseState(e.getPlayer(), to, false);
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player player = e.getPlayer();
updateCloseState(player, player.getLocation(), false);
}
@EventHandler
public void onQuit(PlayerQuitEvent e) {
Player player = e.getPlayer();
updateCloseState(player, player.getLocation(), true);
}
@EventHandler(ignoreCancelled = true)
public void onTeleport(PlayerTeleportEvent e) {
updateCloseState(e.getPlayer(), e.getTo(), false);
}
private void updateCloseState(Player player, Location location, boolean isQuitting) {
World world = location.getWorld();
UUID playerUUID = player.getUniqueId();
// Если игрок уходит из игры
if (isQuitting) {
for (Player target : world.getPlayers()) {
UUID targetUUID = target.getUniqueId();
if (removeClosePlayers(playerUUID, targetUUID)) {
// <== ЗДЕСЬ же выполняем что нам нужно (отдаление)
}
}
closeDistanceMap.remove(playerUUID);
return;
}
// Проверяем всех игроков только в нужном мире
for (Player target : world.getPlayers()) {
UUID targetUUID = target.getUniqueId();
// Игрок player и target в радиусе?
if (radius <= target.getLocation().distanceSquared(location)) {
if (addClosePlayers(playerUUID, targetUUID)) {
// <== ЗДЕСЬ же выполняем что нам нужно (приближение)
}
}
// Игрок player и target НЕ в радиусе?
else {
if (removeClosePlayers(playerUUID, targetUUID)) {
// <== ЗДЕСЬ же выполняем что нам нужно (отдаление)
}
}
}
}
// Возвращает true, если ранее они НЕ были в радиусе
private boolean addClosePlayers(UUID uuidA, UUID uuidB) {
if (uuidA.equals(uuidB)) return false;
closeDistanceMap.computeIfAbsent(uuidA, v -> new HashSet<>()).add(uuidB);
return closeDistanceMap.computeIfAbsent(uuidB, v -> new HashSet<>()).add(uuidA);
}
// Возвращает true, если ранее они были в радиусе
private boolean removeClosePlayers(UUID uuidA, UUID uuidB) {
if (uuidA.equals(uuidB)) return false;
closeDistanceMap.computeIfAbsent(uuidA, v -> new HashSet<>()).remove(uuidB);
return closeDistanceMap.computeIfAbsent(uuidB, v -> new HashSet<>()).remove(uuidA);
}