MENU

通过反射 + 注解注册 MythicMobs 目标选择器

October 27, 2022 • Read: 275 • Bukkit,Minecraft,后端

这不是教程文章,只是一篇代码样例文章

一、项目结构

com.blank038.mythicmobstargeterextends
├── targeters
│   ├── annotations
│   │   └── TargeterDepend(Annotation)
│   └── impl
│      └── AyPartyPlayerInRadiusTargeterImpl(Class)
└── MythicMobsTargeterExtends(Class)

二、代码样例

com.blank038.mythicmobstargeterextends.MythicMobsTargeterExtends

package com.blank038.mythicmobstargeterextends;

import com.aystudio.core.bukkit.plugin.AyPlugin;
import com.blank038.mythicmobstargeterextends.targeters.annotations.TargeterDepend;
import io.lumine.xikage.mythicmobs.skills.SkillManager;
import io.lumine.xikage.mythicmobs.skills.SkillTargeter;
import io.lumine.xikage.mythicmobs.util.annotations.MythicTargeter;
import org.bukkit.Bukkit;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;

/**
 * @author Blank038
 */
public class MythicMobsTargeterExtends extends AyPlugin {

    @Override
    public void onLoad() {
        this.findClassesForPackage(this.getFile(), "com.blank038.mythicmobstargeterextends.targeters.impl").forEach((aClass) -> {
            try {
                if (!aClass.isAnnotationPresent(TargeterDepend.class)) {
                    return;
                }
                String[] dependPlugins = aClass.getAnnotation(TargeterDepend.class).plugin();
                if (dependPlugins.length > 0 && Arrays.stream(dependPlugins).anyMatch((plugin) -> Bukkit.getPluginManager().getPlugin(plugin) == null)) {
                    this.getLogger().log(Level.WARNING, "Failed to load targeter {0} (lack of dependencies)", aClass.getCanonicalName());
                    return;
                }
                if (!SkillTargeter.class.isAssignableFrom(aClass)) {
                    return;
                }
                MythicTargeter mythicTargeter = aClass.getAnnotation(MythicTargeter.class);
                this.registerTargeter(mythicTargeter.name().toUpperCase(), aClass);
                Arrays.stream(mythicTargeter.aliases()).forEach((alias) -> this.registerTargeter(alias.toUpperCase(), aClass));
                this.getLogger().log(Level.INFO, "Loaded targeter {0}", mythicTargeter.name());
            } catch (Exception e) {
                this.getLogger().log(Level.WARNING, "Failed to load targeter {0}", aClass.getCanonicalName());
            }
        });
    }

    private void registerTargeter(String name, Class<?> clazz) {
        try {
            Field field = SkillManager.class.getDeclaredField("TARGETERS");
            field.setAccessible(true);
            ((Map<String, Class<? extends SkillTargeter>>) field.get(null)).put(name, (Class<? extends SkillTargeter>) clazz);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            this.getLogger().info(e.toString());
        }
    }

    public Set<Class<?>> findClassesForPackage(File file, String packageName) {
        Set<Class<?>> classes = new HashSet<>();
        JarFile jarFile = null;
        try {
            jarFile = new JarFile(file);
            Enumeration<JarEntry> entry = jarFile.entries();
            while (entry.hasMoreElements()) {
                JarEntry jarEntry = entry.nextElement();
                String name = jarEntry.getName().replace("/", ".");
                if (name.startsWith(packageName) && name.endsWith(".class")) {
                    try {
                        classes.add(Class.forName(name.substring(0, name.length() - 6)));
                    } catch (ClassNotFoundException ignored) {
                    }
                }
            }
        } catch (Exception e) {
            this.getLogger().info(e.toString());
        } finally {
            if (jarFile != null) {
                try {
                    jarFile.close();
                } catch (IOException e) {
                    this.getLogger().info(e.toString());
                }
            }
        }
        return classes;
    }
}

com.blank038.mythicmobstargeterextends.targeters.annotations.TargeterDepend

package com.blank038.mythicmobstargeterextends.targeters.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface TargeterDepend {
    String[] plugin() default {};
}

com.blank038.mythicmobstargeterextends.targeters.impl.AyPartyPlayerInRadiusTargeterImpl

package com.blank038.mythicmobstargeterextends.targeters.impl;

import com.blank038.ayparty.bukkit.AyPartyApi;
import com.blank038.ayparty.bukkit.data.PartyData;
import com.blank038.mythicmobstargeterextends.targeters.annotations.TargeterDepend;
import io.lumine.xikage.mythicmobs.MythicMobs;
import io.lumine.xikage.mythicmobs.adapters.AbstractEntity;
import io.lumine.xikage.mythicmobs.adapters.AbstractPlayer;
import io.lumine.xikage.mythicmobs.io.MythicLineConfig;
import io.lumine.xikage.mythicmobs.skills.SkillCaster;
import io.lumine.xikage.mythicmobs.skills.SkillMetadata;
import io.lumine.xikage.mythicmobs.skills.targeters.IEntitySelector;
import io.lumine.xikage.mythicmobs.util.annotations.MythicTargeter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.util.HashSet;

@TargeterDepend(plugin = {"AyPartyBukkit"})
@MythicTargeter(author = "Blank038", name = "ayPartyPlayerInRadius", aliases = {"appir"}, description = "Targets the team players in a radius around the caster")
public class AyPartyPlayerInRadiusTargeterImpl extends IEntitySelector {
    private final double radius;

    public AyPartyPlayerInRadiusTargeterImpl(MythicLineConfig mlc) {
        super(mlc);
        this.radius = mlc.getDouble(new String[]{"radius", "r"}, 5.0);
    }

    @Override
    public HashSet<AbstractEntity> getEntities(SkillMetadata data) {
        HashSet<AbstractEntity> targets = new HashSet<>();
        // 获取玩家队伍
        Player player = Bukkit.getPlayer(data.getCaster().getEntity().getUniqueId());
        if (player == null || !player.isOnline()) {
            return targets;
        }
        PartyData partyData = AyPartyApi.getPlayerParty(player);
        if (partyData == null) {
            targets.add(data.getCaster().getEntity());
            return targets;
        }
        SkillCaster am = data.getCaster();
        double radiusSq = this.radius * this.radius;
        for (AbstractPlayer p : MythicMobs.inst().getEntityManager().getPlayers(am.getEntity().getWorld())) {
            if (!p.getWorld().equals(am.getEntity().getWorld()) || !partyData.hasPlayer(p.getName())
                    || am.getEntity().getLocation().distanceSquared(p.getLocation()) >= radiusSq) {
                continue;
            }
            targets.add(p);
        }
        return targets;
    }
}

三、结尾

这不是教程文章,只是一篇代码样例文章,也是给自己保留一份代码,以后用到时方便查阅。

Last Modified: October 16, 2023