Configuration Résolu (Go direct à la page 4)Java : Check si un joueur est dans une zone

Alex Fatta

Commandant de la Flotte et de la Horde
13 Août 2014
1 391
1
191
187
Bonsoir !

Ah oui effectivement ! Il y a beaucoup de choses à améliorer xD @DiscowZombie je croyais pourtant avoir utilisé les UUID ^^ J'ai du en zapper quelque part. Concernant les éléments que vous venez de citer tous les deux, je n'en connaissais pas l'existence (je suis pas dev de base ^^). Mais c'est toujours pratique d'apprendre de nouvelles choses et surtout, même pour un usage privé, d'avoir un programme optimisé. Je me renseignerai sur tout cela très prochainement ! (Là les études prennent pas mal de place).

Je ferais les modifs dans le code aussi, puis je reviendrai vers vous dans les prochains jours.

Merci encore à vous ! ;)

Bonne soirée,

AlexFatta
 

ShE3py

Enbogueuse
Support
26 Septembre 2015
4 129
162
461
247
21
Mìlhüsa
Bonsoir,

Ce n'est pas que je critique votre code ou quoi que ce soit, mais bon mes yeux souffrent devant tant de complexité inutile ^c^
Java:
// Trouver le nom de la base depuis le nom du joueur
final Optional<String> baseName = BasesManager.getPlayerPerBase().entrySet().stream()
        .filter(e -> e.getKey().equals(player.getUniqueId()))
        .map(Map.Entry::getValue)
        .findFirst();

if (baseName.isPresent()) {
    final Optional<Base> base = BasesManager.getBases().stream()
            .filter(b -> b.getName().equalsIgnoreCase(baseName.get()))
            .findFirst();

    // Cette condition devrait toujours être vrai sauf si tes deux structure de données sont desync
    if (base.isPresent()) {
        final Location l1 = base.get().getLimits().get(0);
        final Location l2 = base.get().getLimits().get(1);

        if (!new CuboidManager(l1, l2).isInCube(l)) {
            player.sendMessage(ChatColor.RED + "Erreur : tu ne peux pas poser ce block : type=" + e.getBlock().getType());
            e.setCancelled(true);
        }
    }
}

Là t'es quand même en train de récupérer le nom de l'éventuelle base du joueur, puis à partir du nom tu récupères la base (pas moyen de faire ça en une itération ?), ensuite tu récupères deux emplacements avec des nombres magiques (il s'passe quoi si y'a plus de deux limites ou s'il n'y en a aucune ?) pour finalement construire un objet qui ne servira que pour une méthode. Humm...

Bref j'ai réécrit les classes à ma façon, je n'ai pas testé mais je pense que cette structure est un peu meilleure.
Java:
package fr.she3y.foo;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Entity;

import fr.she3y.util.Objects;

public class Region {
    public final World world;
    
    public final int minX;
    public final int minY;
    public final int minZ;
    
    public final int maxX;
    public final int maxY;
    public final int maxZ;
    
    public Region(World world, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
        Objects.requireNonNull("world", world);
        Objects.require(minX <= maxX, "minX must be less than maxX");
        Objects.require(minY <= maxY, "minY must be less than maxY");
        Objects.require(minZ <= maxZ, "minZ must be less than maxZ");
        
        this.world = world;
        this.minX = minX;
        this.minY = minY;
        this.minZ = minZ;
        this.maxX = maxX;
        this.maxY = maxY;
        this.maxZ = maxZ;
    }
    
    public Region(Location min, Location max) {
        this(min.getWorld(), min.getBlockX(), min.getBlockY(), min.getBlockZ(), max.getBlockX(), max.getBlockY(), max.getBlockZ());
        
        Objects.require(min.getWorld() == max.getWorld(), "the locations must be of the same world");
    }
    
    public boolean isInside(World world, double x, double y, double z) {
        return this.world == world && x >= minX && y >= minY && z >= minZ && x <= maxX && y <= maxY && z <= maxZ;
    }
    
    public boolean isInside(double x, double y, double z) {
        return isInside(this.world, x, y, z);
    }
    
    public boolean isInside(Location location) {
        if(location == null)
            return false;
        
        return isInside(location.getWorld(), location.getX(), location.getY(), location.getZ());
    }
    
    public boolean isInside(Entity entity) {
        if(entity == null)
            return false;
        
        return isInside(entity.getLocation());
    }
    
    public int width() {
        return maxX - minX;
    }
    
    public int height() {
        return maxY - minY;
    }
    
    public int depth() {
        return maxZ - minZ;
    }
}
Java:
package fr.she3y.foo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;

import fr.she3y.util.Objects;

public class Guild {
    private String name;
    private final List<UUID> players;
    private final List<Region> regions;
    
    public Guild(String name, List<UUID> players, List<Region> regions) {
        Objects.requireNonEmpty("name", name);
        Objects.requireNonNull("players", players);
        Objects.requireNonNull("regions", regions);
        
        this.name = name;
        this.players = players;
        this.regions = regions;
    }
    
    public Guild(String name) {
        this(name, new ArrayList<>(), new ArrayList<>());
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        Objects.requireNonEmpty("name", name);
        
        this.name = name;
    }
    
    public List<UUID> getPlayerUUIDs() {
        return Collections.unmodifiableList(players);
    }
    
    public List<OfflinePlayer> getPlayers() {
        return players.stream().map(Bukkit::getOfflinePlayer).collect(Collectors.toList());
    }
    
    public List<Player> getOnlinePlayers() {
        return getPlayers().stream().filter(OfflinePlayer::isOnline).map(OfflinePlayer::getPlayer).collect(Collectors.toList());
    }
    
    public boolean addPlayer(UUID player) {
        return players.add(player);
    }
    
    public boolean addPlayer(OfflinePlayer player) {
        return addPlayer(player.getUniqueId());
    }
    
    public boolean hasPlayer(UUID player) {
        return players.contains(player);
    }
    
    public boolean hasPlayer(OfflinePlayer player) {
        return hasPlayer(player.getUniqueId());
    }
    
    public List<Region> getRegions() {
        return regions;
    }
}
Java:
package fr.she3y.foo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import org.bukkit.OfflinePlayer;

public class GuildManager {
    private static final List<Guild> GUILDS = new ArrayList<>();
    
    public static List<Guild> getGuilds() {
        return Collections.unmodifiableList(GUILDS);
    }
    
    public static Optional<Guild> getGuild(UUID player) {
        for(Guild guild : GUILDS)
            if(guild.hasPlayer(player))
                return Optional.of(guild);
        
        return Optional.empty();
    }
    
    public static Optional<Guild> getGuild(OfflinePlayer player) {
        return getGuild(player.getUniqueId());
    }
}
Java:
package fr.she3y.foo;

import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;

public class EventManager implements Listener {
    @EventHandler(priority = EventPriority.LOWEST)
    public void onBlockPlace(BlockPlaceEvent e) {
        Player player = e.getPlayer();
        Location location = e.getBlockPlaced().getLocation();
        World world = location.getWorld();
        
        for(Guild guild : GuildManager.getGuilds()) {
            if(guild.hasPlayer(player)) continue;
            
            if(guild.getRegions().stream().filter(region -> region.world == world).anyMatch(region -> region.isInside(location))) {
                player.sendMessage("§cVous ne pouvez pas construire ici.");
                e.setCancelled(true);
            }
        }
    }
}
Java:
package fr.she3y.util;

import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

public class Objects {
    @Contract(value = "false, _, _ -> fail", pure = true)
    public static <E extends RuntimeException, T> void require(boolean op, Function<T, E> exception, T description) throws E {
        if(!op) throw exception.apply(description);
    }

    @Contract(value = "false, _ -> fail", pure = true)
    public static void require(boolean op, String message) {
        require(op, IllegalArgumentException::new, message);
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static void requireEmpty(String name, @Nullable Collection<?> obj) {
        requireNonNull(name, obj);
        require(obj.isEmpty(), name + " must be empty");
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static void requireEmpty(String name, @Nullable Map<?, ?> obj) {
        requireNonNull(name, obj);
        require(obj.isEmpty(), name + " must be empty");
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static void requireEmpty(String name, @Nullable String obj) {
        requireNonNull(name, obj);
        require(obj.isEmpty(), name + " must be empty");
    }
    
    public static <T, S extends T> void requireEqual(String name, @Nullable S a, T b) {
        //noinspection EqualsReplaceableByObjectsCall
        require((a == b) || (a != null && a.equals(b)), name + " must be equal to " + b + ", got " + a);
    }

    @Contract(value = "_, true -> fail", pure = true)
    public static void requireFalse(String name, boolean op) {
        require(!op, name + " must be false");
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static void requireNonEmpty(String name, @Nullable Collection<?> obj) {
        requireNonNull(name, obj);
        require(!obj.isEmpty(), name + " must not be empty");
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static void requireNonEmpty(String name, @Nullable Map<?, ?> obj) {
        requireNonNull(name, obj);
        require(!obj.isEmpty(), name + " must not be empty");
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static void requireNonEmpty(String name, @Nullable String obj) {
        requireNonNull(name, obj);
        require(!obj.isEmpty(), name + " must not be empty");
    }
    
    public static <T, S extends T> void requireNonEqual(String name, @Nullable S a, T b) {
        require(a == null || !a.equals(b), name + " must not be equal to " + b);
    }

    @Contract(value = "_, null -> fail", pure = true)
    public static <T> void requireNonNull(String name, @Nullable T obj) {
        require(obj != null, NullPointerException::new, name + " must not be null");
    }

    @Contract(value = "_, !null -> fail", pure = true)
    public static <T> void requireNull(String name, @Nullable T obj) {
        require(obj == null, name + " must be null");
    }

    @Contract(value = "_, false -> fail", pure = true)
    public static void requireTrue(String name, boolean op) {
        require(op, name + " must be true");
    }
}

Je pense que ça correspond à ce que tu veux faire, si jamais tu ne comprends pas les lignes avec les lambdas je peux te les réécrire sans. La dernière classe est une classe utilitaire pour faire les assertions, utilise ce que tu veux si tu as une autre librairie.
Je te laisse le soin d'écrire les fonctions pour sauvegarder/charger les configurations, ainsi que pour créer les guildes.

Sinon pour répondre à @Detobel36, s'il l'on type les conteneurs avec l'interface c'est car dans l'exemple d'une List, ça ne change rien dans le code qu'elle soit une ArrayList ou une LinkedList, on y accède de la même manière. On s'en tape mais complètement si la liste est stockée en un ou plusieurs blocs dans la mémoire, ça ne change quelque chose qu'à l'exécution alors l'on ne va pas se trimbaler avec un LinkedHashMap<UUID, LinkedHashSet<Foo>> à rallonge pendant tout le code. Puis si tu changes le type tu vas devoir regarder partout où tu utilises l'accesseur/le getter.
Par contre il faut vraiment avoir un problème pour stocker une variable sous une Collection, car tu n'utilises pas une Stack comme tu utilises une Queue, là ça change quelque chose.

Et puis ça évite les trucs ahurissants.
Java:
new ArrayList<>(Arrays.asList(location1, location2))

Cordialement,
ShE3py.
 

Alex Fatta

Commandant de la Flotte et de la Horde
13 Août 2014
1 391
1
191
187
Bonjour à tous !

Bon je suis allé me renseigner sur les filter et j'ai appris vraiment pas mal de choses, voilà qui raccourcira le code pour l'analyse des Collections.

Concernant le code, j'ai gardé beaucoup des classes de @ShE3py mais pas toutes. Notamment la classe Region avec laquelle j'ai pas mal galéré à incorporer dans le code. Je n'ai pas non plus utilisé la classe Objects avec laquelle j'ai pas réussi à importer les dépendances de JetBrain (oui oui je suis sous IntelliJ). J'ai utilisé toutes les autres classes et tout fonctionne parfaitement !

Merci à tous pour votre aide en tout cas ! Bonne soirée,

Alexfatta