This commit is contained in:
yuyu 2024-08-15 09:22:34 +08:00
parent d21bf4b7f5
commit 9c23f5fc3d
10 changed files with 524 additions and 324 deletions

5
.idea/compiler.xml generated
View File

@ -11,4 +11,9 @@
</profile>
</annotationProcessing>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="SrWildEntity" options="-extdirs lib" />
</option>
</component>
</project>

10
.idea/libraries/lib__4_.xml generated Normal file
View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="lib (4)">
<CLASSES>
<root url="file://$PROJECT_DIR$/lib" />
</CLASSES>
<JAVADOC />
<SOURCES />
<jarDirectory url="file://$PROJECT_DIR$/lib" recursive="false" />
</library>
</component>

14
pom.xml
View File

@ -6,7 +6,7 @@
<groupId>com.yuyu</groupId>
<artifactId>SrWildEntity</artifactId>
<version>1.0-SNAPSHOT</version>
<version>2.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SrWildEntity</name>
@ -17,7 +17,19 @@
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<extdirs>lib</extdirs><!--指定外部lib-->
</compilerArguments>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>

View File

@ -4,7 +4,7 @@ import com.yuyu.srwildentity.JDBC.JdbcSqlClass;
import com.yuyu.srwildentity.config.ConfigManager;
import com.yuyu.srwildentity.listener.AreaRefershListener;
import com.yuyu.srwildentity.listener.EntityRefreshListener;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
@ -26,7 +26,6 @@ public final class SrWildEntity extends JavaPlugin implements CommandExecutor {
private EntityRefreshListener entityRefreshListener;
private AreaRefershListener areaRefershListener;
public static Plugin getInance(){
return Bukkit.getPluginManager().getPlugin("SrWildEntity");
@ -47,9 +46,9 @@ public final class SrWildEntity extends JavaPlugin implements CommandExecutor {
Bukkit.getPluginManager().registerEvents(areaRefershListener,this);
//注册定时任务
this.getServer().getScheduler().scheduleSyncRepeatingTask
(this,this.entityRefreshListener::timedRdfreshEneity,
0,this.entityRefreshListener.getConfigManager().getRefreshTime()*20);
// this.getServer().getScheduler().scheduleSyncRepeatingTask
// (this,this.entityRefreshListener::timedRdfreshEneity,
// 0,this.entityRefreshListener.getConfigManager().getRefreshTime()*20);
getLogger().info(ChatColor.DARK_GREEN+"SrWildEntity定时任务触发");
@ -97,7 +96,7 @@ public final class SrWildEntity extends JavaPlugin implements CommandExecutor {
if (strings[0].equalsIgnoreCase("reload")){
getLogger().info(ChatColor.GOLD+"SrWildEntity定时任务关闭");
Bukkit.getScheduler().cancelTasks(this);
// Bukkit.getScheduler().cancelTasks(this);
getLogger().info(ChatColor.AQUA+"SrWildEntity重新读取配置文件");
commandSender.sendMessage(ChatColor.YELLOW+"SrWildEntity重新读取配置文件");
@ -105,11 +104,7 @@ public final class SrWildEntity extends JavaPlugin implements CommandExecutor {
entityRefreshListener.setConfigManager(onload);
areaRefershListener.setConfigManager(onload);
//注册定时任务
this.getServer().getScheduler().scheduleSyncRepeatingTask
(this,this.entityRefreshListener::timedRdfreshEneity,
0,this.entityRefreshListener.getConfigManager().getRefreshTime()*20);
//todo(此处要重新注册定时任务)
getLogger().info(ChatColor.DARK_GREEN+"SrWildEntity定时任务触发");
}

View File

@ -1,5 +1,6 @@
package com.yuyu.srwildentity.conditionCheck;
import com.palmergames.compress.compressors.lz77support.LZ77Compressor;
import com.yuyu.srwildentity.config.condition.EntityCondition;
import com.yuyu.srwildentity.config.condition.EntitySite;
import org.bukkit.Location;
@ -59,15 +60,14 @@ public class ConditionCheck {
if (entitySite == EntitySite.ON_GROUND){
//实体的刷新位置
Block block = world.getBlockAt(location);
//实体的落脚点
//实体的落脚点\
Block blockAt = world.getBlockAt(new Location(world,location.getBlockX(),location.getBlockY() + 1,location.getBlockZ()));
Block blockAt0 = world.getBlockAt(new Location(world,location.getBlockX(),location.getBlockY() + 2,location.getBlockZ()));
Block blockAt0 = world.getBlockAt(new Location(world,location.getBlockX(),location.getBlockY() - 2,location.getBlockZ()));
Block b = world.getBlockAt(new Location(world,location.getBlockX(),location.getBlockY() - 1,location.getBlockZ()));
return (noEntityCollision.contains(block.getType()) &&
noEntityCollision.contains(blockAt.getType()) &&
!noEntityCollision.contains(b.getType()) &&
noEntityCollision.contains(blockAt0.getType()));
!noEntityCollision.contains(blockAt0.getType()));
}
if (entitySite == EntitySite.NULL){

View File

@ -72,7 +72,7 @@ public class ConfigManager {
private void loadEntityCheck() {
ConditionCheck.noEntityCollision.add(Material.AIR);
ConditionCheck.noEntityCollision.add(Material.GRASS);
// ConditionCheck.noEntityCollision.add(Material.GRASS);
ConditionCheck.noEntityCollision.add(Material.SAPLING);
ConditionCheck.noEntityCollision.add(Material.WATER);
ConditionCheck.noEntityCollision.add(Material.STATIONARY_WATER);

View File

@ -1,30 +1,18 @@
package com.yuyu.srwildentity.listener;
import com.germ.germplugin.GermPlugin;
import com.palmergames.bukkit.towny.TownyAPI;
import com.palmergames.bukkit.towny.event.PlayerEnterTownEvent;
import com.palmergames.bukkit.towny.event.PlayerLeaveTownEvent;
import com.palmergames.bukkit.towny.object.Town;
import com.yuyu.srwildentity.conditionCheck.ConditionCheck;
import com.yuyu.srwildentity.config.ConfigManager;
import com.yuyu.srwildentity.config.condition.EntityCondition;
import com.yuyu.srwildentity.config.condition.EntitySite;
import com.yuyu.srwildentity.config.condition.LevelRefresh;
import com.yuyu.srwildentity.config.condition.SpawnEntityType;
import com.yuyu.srwildentity.pojo.BlackListArea;
import com.yuyu.srwildentity.pojo.PlayerRefreshinfo;
import io.lumine.xikage.mythicmobs.MythicMobs;
import io.lumine.xikage.mythicmobs.api.exceptions.InvalidMobTypeException;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -51,43 +39,80 @@ import java.util.logging.Logger;
public class EntityRefreshListener implements Listener, CommandExecutor {
private ConfigManager configManager;//配置相关
private boolean flag; //用于验证entity是否刷新
private Logger logger;//日志打印
public static Logger log;
public static boolean logBool;
public static boolean flag; //用于验证entity是否刷新
private Random random;//生成随机数,随机实体的定位
private HashMap<UUID,String> entityUUIDToPlayer;
private HashMap<String, PlayerRefreshinfo> refreshPlayer;
public static HashMap<UUID,String> entityUUIDToPlayer = new HashMap<>();//uuid定位到玩家刷新对象
private List<String> noRefreshPlayer;//记录不需要刷新的玩家
private HashMap<String,PlayerRefreshLintener> refreshPlayer;//用来注册事件
private Plugin plugin;
private MythicMobs mythicMobs;
private GermPlugin germPlugin;
public EntityRefreshListener(Logger logger, ConfigManager configManager, Plugin plugin){
this.entityUUIDToPlayer = new HashMap<>();
this.refreshPlayer = new HashMap<>();
this.configManager = configManager;
this.random = new Random();
this.logger = logger;
EntityRefreshListener.log = logger;
this.flag = true;
this.noRefreshPlayer = new ArrayList<>();
this.plugin = plugin;
logBool = false;
//用于获取MM插件和萌芽的实例对象
this.mythicMobs = MythicMobs.inst();
this.germPlugin = GermPlugin.getPlugin();
}
/**
* 注册监听事件
* @param name
*/
public void regRefreshEvent(String name){
if (!refreshPlayer.containsKey(name)){
if (logBool){
log.info(ChatColor.RED+name+"玩家不在刷新列表!");
}
PlayerRefreshLintener playerRefreshLintener = new PlayerRefreshLintener(name,configManager);
refreshPlayer.put(name, playerRefreshLintener);
}
if (!refreshPlayer.get(name).isFlag()) {
int workId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, refreshPlayer.get(name)::timedRdfreshEneity, 0,
configManager.getRefreshTime() * 20);
//把线程id记录到类中
refreshPlayer.get(name).setWorkId(workId);
refreshPlayer.get(name).setFlag(true);
if (refreshPlayer.get(name).isFlag() && logBool) {
log.info(ChatColor.GOLD+name+"被加入刷新集合");
}
}
}
/**
* 取消注册的监听事件
* @param name
*/
public void cancleRefreshEvent(String name){
if (!refreshPlayer.containsKey(name)){
if (logBool){
log.info(ChatColor.RED+name+"玩家不在刷新列表!");
}
return;
}
if (refreshPlayer.get(name).isFlag()) {
plugin.getServer().getScheduler().cancelTask(refreshPlayer.get(name).getWorkId());
refreshPlayer.get(name).setFlag(false);
}
}
/**
* 此类用于获取玩家的危险度
* @param player
*/
public int prRisk(Player player){
public static int prRisk(Player player){
if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) {
String placeholder = PlaceholderAPI.setPlaceholders(player, "%prisk_level%");
int level = Integer.parseInt(placeholder);
@ -107,6 +132,16 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
return false;
}
if (strings.length == 1 && strings[0].equalsIgnoreCase("log")){
logBool = !logBool;
if (logBool){
commandSender.sendMessage(ChatColor.GREEN+"实体刷新开启日志");
}else {
commandSender.sendMessage(ChatColor.GREEN+"实体刷新关闭日志");
}
return true;
}
if (commandSender.isOp()){
if (strings.length == 0){
//只输入despawn,直接停止刷新
@ -117,10 +152,18 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
for (Player player : onlinePlayers){
String name = player.getName();
if (!this.playerStayTown(player.getLocation())){
PlayerRefreshinfo playerRefreshinfo = new PlayerRefreshinfo(name, 0, new ArrayList<>());
refreshPlayer.put(name, playerRefreshinfo);
PlayerRefreshLintener playerRefreshLintener = new PlayerRefreshLintener(name,configManager);
refreshPlayer.put(name, playerRefreshLintener);
//注册监听事件
this.regRefreshEvent(name);
}
if (flag) {
log.info(ChatColor.GREEN + "所有在野外的玩家开始刷新实体");
}else {
log.info(ChatColor.GREEN+"实体刷新停止");
entityUUIDToPlayer.clear();
refreshPlayer.clear();
}
logger.info(ChatColor.GREEN+"所有在野外的玩家开始刷新实体");
commandSender.sendMessage(ChatColor.GREEN+"所有在野外的玩家开始刷新实体");
return true;
}
@ -128,7 +171,9 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
//flag=false清空所有集合停止刷新实体
entityUUIDToPlayer.clear();
refreshPlayer.clear();
logger.info(ChatColor.AQUA+"所有玩家停止刷新实体");
if (logBool) {
log.info(ChatColor.AQUA + "所有玩家停止刷新实体");
}
commandSender.sendMessage(ChatColor.AQUA+"所有玩家停止刷新实体");
return true;
}
@ -143,8 +188,9 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
return true;
}else {
noRefreshPlayer.remove(strings[1]);
PlayerRefreshinfo playerRefreshinfo = new PlayerRefreshinfo(strings[1], 0, new ArrayList<>());
PlayerRefreshLintener playerRefreshinfo = new PlayerRefreshLintener(strings[1],configManager);
refreshPlayer.put(strings[1], playerRefreshinfo);
this.regRefreshEvent(strings[1]);
commandSender.sendMessage(ChatColor.YELLOW+strings[1]+"开始刷怪");
return true;
}
@ -157,13 +203,16 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
//玩家不为空
refreshPlayer.remove(strings[1]);
noRefreshPlayer.add(strings[1]);
this.cancleRefreshEvent(strings[1]);
commandSender.sendMessage(ChatColor.YELLOW+strings[1]+"停止刷怪");
return true;
}
}else if (choice.equalsIgnoreCase("clear")){
//清空刷新的怪物
this.clearRefreshEntity();
logger.info(ChatColor.GOLD+"SrWildEntity刷新的所有实体被清除!");
if (logBool) {
log.info(ChatColor.GOLD + "SrWildEntity刷新的所有实体被清除!");
}
commandSender.sendMessage(ChatColor.GOLD+"SrWildEntity刷新的所有实体被清除!");
return true;
}else if (choice.equalsIgnoreCase("location")){
@ -173,8 +222,10 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
String blockname = location.getBlock().getType().name();
player.sendMessage(ChatColor.GREEN+"x:"+location.getBlockX()+"\ty:"
+location.getBlockY()+"\tz:"+location.getBlockZ()+"\tworld:"+location.getWorld().getName()+"\t"+blockname);
logger.info(ChatColor.GREEN+"x:"+location.getBlockX()+"\ty:"
+location.getBlockY()+"\tz:"+location.getBlockZ()+"\tworld:"+location.getWorld().getName()+"\t"+blockname);
if (logBool) {
log.info(ChatColor.GREEN + "x:" + location.getBlockX() + "\ty:"
+ location.getBlockY() + "\tz:" + location.getBlockZ() + "\tworld:" + location.getWorld().getName() + "\t" + blockname);
}
return true;
}else {
return false;
@ -196,26 +247,34 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
String name = player.getName();
Town town = TownyAPI.getInstance().getTown(player.getLocation());
if (town == null){
PlayerRefreshinfo playerRefreshinfo = new PlayerRefreshinfo(name, 0, new ArrayList<>());
PlayerRefreshLintener playerRefreshinfo = new PlayerRefreshLintener(name, configManager);
refreshPlayer.put(name, playerRefreshinfo);
}
logger.info(ChatColor.GREEN+"所有在野外的玩家开始刷新实体");
if (logBool) {
log.info(ChatColor.GREEN + "所有在野外的玩家开始刷新实体");
}
}
}
/**
* 玩家进入城镇,
* 玩家进入城镇,取消玩家的监听事件
* @param event
*/
@EventHandler
public void onPlayerInTown(PlayerEnterTownEvent event) {
if (flag){
String name = event.getPlayer().getName();
refreshPlayer.remove(name);
logger.info(name + "开始停止怪物");
}
this.cancleRefreshEvent(name);
if (logBool) {
log.info(name + "开始停止怪物");
}
}
/**
* 玩家复活
* @param event
*/
@EventHandler
public void playerRevive(PlayerRespawnEvent event){
Location respawnLocation = event.getRespawnLocation();
@ -223,7 +282,9 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
// 返回true则表示在城镇不用管
//反之增加
String name = event.getPlayer().getName();
this.playerRefreshEntiyt(name);
this.regRefreshEvent(name);
}else {
this.cancleRefreshEvent(event.getPlayer().getName());
}
}
@ -233,10 +294,8 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
*/
@EventHandler
public void onPlayerLeaveTown(PlayerLeaveTownEvent event) {
if (flag) {
String name = event.getPlayer().getName();
this.playerRefreshEntiyt(name);
}
this.regRefreshEvent(name);
}
/**
@ -245,13 +304,12 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
*/
@EventHandler
public void onPlayerJoinGame(PlayerJoinEvent event) {
if (flag){
Player player = event.getPlayer();
String name = player.getName();
if (!this.playerStayTown(player.getLocation()) && !noRefreshPlayer.contains(name)) {
this.playerRefreshEntiyt(name);
this.regRefreshEvent(name);
}
}
}
/**
@ -260,13 +318,24 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
*/
@EventHandler
public void onPlayerOffOnline(PlayerQuitEvent event) {
if (flag) {
Player player = event.getPlayer();
String name = player.getName();
refreshPlayer.remove(name);
logger.info(ChatColor.GOLD + "玩家被移出刷新集合");
this.cancleRefreshEvent(name);
if (!refreshPlayer.containsKey(name)){
if (logBool){
log.info(ChatColor.RED+name+"玩家不在刷新列表!");
}
return;
}
if (refreshPlayer.get(name).isFlag()) {
plugin.getServer().getScheduler().cancelTask(refreshPlayer.get(name).getWorkId());
refreshPlayer.get(name).setFlag(false);
}
if (logBool) {
log.info(ChatColor.GOLD + "玩家被移出刷新集合");
}
}
/**
@ -281,7 +350,7 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
if (entityUUIDToPlayer.containsKey(uniqueId) && refreshPlayer.containsKey(entityUUIDToPlayer.get(uniqueId))) {
//通过死亡实体的uuid获取玩家姓名然后删除uuid
String playerName = entityUUIDToPlayer.get(uniqueId);
refreshPlayer.get(playerName).delEntityList(uniqueId);
refreshPlayer.get(playerName).getPlayerRefreshinfo().delEntityList(uniqueId);
entityUUIDToPlayer.remove(uniqueId);
}
}
@ -305,226 +374,13 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
String name = entityUUIDToPlayer.get(uniqueId);
if (refreshPlayer.containsKey(name)) {
refreshPlayer.get(name).delEntityList(uniqueId);
refreshPlayer.get(name).getPlayerRefreshinfo().delEntityList(uniqueId);
}
}
}
}
/**
* 定时任务每隔一段时间在玩家附近刷新实体
*/
public void timedRdfreshEneity(){
if (flag) {
int num = configManager.getNum();//每次执行时刷新的总数
//遍历需要刷新的玩家
tag:
for (String name : refreshPlayer.keySet()) {
if (noRefreshPlayer.contains(name)){
continue;
}
int attempts = 0;
int sum = 0;//用于记录此次刷新生成的总数
//获取玩家信息
Player player = plugin.getServer().getPlayer(name);
PlayerRefreshinfo playerRefreshinfo = refreshPlayer.get(name);
Location playerlocation = player.getLocation();
World world = playerlocation.getWorld();
String worldName = world.getName();
boolean pass = false;
//如果黑名单的set集合里面包含有该世界的名字则跳过该玩家
if (configManager.getBlacklistWorldSet().contains(worldName)){
continue;
}
if (configManager.getBlackListAreaMap().containsKey(worldName)){
List<BlackListArea> blackListAreas = configManager.getBlackListAreaMap().get(worldName);
for (BlackListArea blackListArea : blackListAreas){
int blockX = playerlocation.getBlockX();
int blockZ = playerlocation.getBlockZ();
if (blackListArea.getX1() >= blockX && blockX >= blackListArea.getX2()
&& blackListArea.getY1() >= blockZ && blockZ >= blackListArea.getY2()){
//tag为循环标志此处会直接结束tag标志处的循环
continue tag;
}
}
}
//玩家危险度,用于刷新实体的等级
int riskLevel = this.prRisk(player);
if (riskLevel == 0){
//等于0不刷新怪物,直接跳过
continue;
}
LevelRefresh refreshList = null;
List<LevelRefresh> levelRefreshesList = configManager.getBiomeEntityRefreshSettings().getLevelRefreshesList();
for (LevelRefresh levelRefresh : levelRefreshesList){
if (riskLevel > levelRefresh.getRiskMin() && riskLevel <= levelRefresh.getRiskMax()){
refreshList = levelRefresh;
}
}
if (refreshList == null){
logger.info(ChatColor.MAGIC+name+"所在群系"+"没有危险度为:"+riskLevel+"时适配的刷新列表");
continue;
}
//获取玩家位置信息
int blockZ = playerlocation.getBlockZ();
int blockX = playerlocation.getBlockX();
int blockY = playerlocation.getBlockY();
Biome biome = world.getBiome(blockX, blockZ);
String biomeName = biome.name();
List<EntityCondition> entityConditionList = null;
HashMap<String, List<EntityCondition>> entityConditionHashMap = refreshList.getEntityConditionHashMap();
for (String refreshBiome : entityConditionHashMap.keySet()){
if (biomeName.contains(refreshBiome)){
entityConditionList = entityConditionHashMap.get(refreshBiome);
}
}
if (entityConditionList == null){
logger.info(ChatColor.RED+"没有配置"+biomeName+"群系的实体刷新案例");
continue;
}
for (EntityCondition entityCondition : entityConditionList){
int yMin = entityCondition.getyMin();
int yMax = entityCondition.getyMax();
//如果玩家所在位置不再设置的y轴高度内则不刷新此entity
if (yMin > blockY || yMax < blockY){
// logger.info(ChatColor.RED+"刷新高度不通过"+entityCondition.getEntityName());
continue;
}
float v = random.nextFloat();
if ( entityCondition.getWeight() < v){
//刷新不通过,进入下一个验证的实体
// logger.info(ChatColor.RED+"刷新权重不通过"+entityCondition.getEntityName()+"权重:"+entityCondition.getWeight()+"\t"+v);
continue;
}
int nums = entityCondition.getNums();//当前实体需要刷新的数量
for (int i = 0;i<nums &&
playerRefreshinfo.getEntityList().size() < configManager.getTotal()
&& sum <= num
&& attempts <= configManager.getAttempts(); i++) {
// 生成x和y坐标,会随机在玩家方圆15个方块的距离内随机生成
int x =blockX + random.nextInt(30) - 15; // 生成0到60之间的随机数然后减去30得到-30到30的范围
int z =blockZ + random.nextInt(30) - 15; // 同上,在玩家附近随机位置生成
int y =blockY + random.nextInt(3) - 2; //在玩家Y轴上下3格尝试刷新
//刷新在地上直接获取最高的x z 最高处的坐标
if (entityCondition.getEntitySite() == EntitySite.ON_GROUND) {
Location location = new Location(world, x, y , z);
//判断位置是否符合
if (ConditionCheck.checkEntityRefresh(world, location, entityCondition)) {
//通过则生成
// Entity entity = world.spawnEntity(location, EntityType.valueOf(entityCondition.getEntityName()));
Entity entity;
//MC原生实体
if (entityCondition.getEntityType() == SpawnEntityType.PROTOGENESIS){
entity = world.spawnEntity(location, EntityType.valueOf(entityCondition.getEntityName()));
}else {
//刷新MM怪物
try {
entity = mythicMobs.getAPIHelper().spawnMythicMob(entityCondition.getEntityName(),location,riskLevel);
} catch (InvalidMobTypeException e) {
throw new RuntimeException(e);
}
}
logger.info(ChatColor.GOLD + "" + x + " " + y + " " + z + "位置刷新了" + entityCondition.getEntityName());
UUID uniqueId = entity.getUniqueId();
//存入玩家对应的刷新的实体集合便于寻找
entityUUIDToPlayer.put(uniqueId, name);
//存入
playerRefreshinfo.addEntityList(uniqueId);
attempts++;
sum++;
}
} else {
//不刷新在地上在定义的范围内随机高度概率生成实体
for (int c = 0; i<nums && c < 10 && sum <= num &&
playerRefreshinfo.getEntityList().size() < configManager.getTotal();
c++) {
//循环十次验证刷新位置
y = blockY + random.nextInt(3) - 3;//在玩家所在高度的上下三格内生成便于当玩家在洞穴时定位洞穴
x = blockX + random.nextInt(30) - 15; // 生成0到60之间的随机数然后减去30得到-30到30的范围
z = blockZ + random.nextInt(30) - 15; // 同上,在玩家附近随机位置生成
if (entityCondition.getEntitySite() == EntitySite.ON_GROUND) {
y = world.getHighestBlockYAt(x,z);
}
Location location = new Location(world, x, y + 1, z);
//判断位置是否符合
if (ConditionCheck.checkEntityRefresh(world, location, entityCondition)) {
//通过则生成
Entity entity;
//MC原生实体
if (entityCondition.getEntityType() == SpawnEntityType.PROTOGENESIS){
entity = world.spawnEntity(location, EntityType.valueOf(entityCondition.getEntityName()));
}else {
//刷新MM怪物
try {
entity = mythicMobs.getAPIHelper().spawnMythicMob(entityCondition.getEntityName(), location);
} catch (InvalidMobTypeException e) {
throw new RuntimeException(e);
}
}
logger.info(ChatColor.GOLD + "" + x + " " + y + " " + z + "位置刷新了" + entityCondition.getEntityName());
UUID uniqueId = entity.getUniqueId();
//存入玩家对应的刷新的实体集合便于寻找
entityUUIDToPlayer.put(uniqueId, name);
//存入
playerRefreshinfo.addEntityList(uniqueId);
i++;
sum++;
attempts++;
}
}
}
}
}
}
}
}
public ConfigManager getConfigManager() {
return configManager;
}
public List<String> getNoRefreshPlayer() {
return noRefreshPlayer;
}
public void setConfigManager(ConfigManager configManager) {
this.configManager = configManager;
}
/**
@ -532,10 +388,11 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
*/
public void clearRefreshEntity(){
Server server = plugin.getServer();
Collection<? extends Player> onlinePlayers = server.getOnlinePlayers();
for (Player player : onlinePlayers){
String name = player.getName();
List<UUID> entityList = refreshPlayer.get(name).getEntityList();
// Collection<? extends Player> onlinePlayers = server.getOnlinePlayers();
for (PlayerRefreshLintener player : refreshPlayer.values()){
List<UUID> entityList = player.getPlayerRefreshinfo().getEntityList();
for (UUID uuid : entityList){
Entity entity = server.getEntity(uuid);
if (entity != null){
@ -550,16 +407,18 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
}
}
//entity清除完后
refreshPlayer.get(name).setEntityList(new ArrayList<>());
player.getPlayerRefreshinfo().setEntityList(new ArrayList<>());
}
for (UUID uuid : entityUUIDToPlayer.keySet()){
Entity entity = plugin.getServer().getEntity(uuid);
if (entity != null){
entity.remove();
entityUUIDToPlayer.remove(uuid);
}else {
entityUUIDToPlayer.remove(uuid);
if(!entityUUIDToPlayer.isEmpty()) {
for (UUID uuid : entityUUIDToPlayer.keySet()) {
Entity entity = plugin.getServer().getEntity(uuid);
if (entity != null) {
entity.remove();
entityUUIDToPlayer.remove(uuid);
} else {
entityUUIDToPlayer.remove(uuid);
}
}
}
}
@ -567,9 +426,11 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
public void playerRefreshEntiyt(String name){
if (!noRefreshPlayer.contains(name) && !entityUUIDToPlayer.containsValue(name)) {
PlayerRefreshinfo playerRefreshinfo = new PlayerRefreshinfo(name, 0, new ArrayList<>());
PlayerRefreshLintener playerRefreshinfo = new PlayerRefreshLintener(name, configManager);
refreshPlayer.put(name, playerRefreshinfo);
logger.info(name + "开始刷新实体");
if (logBool) {
log.info(name + "开始刷新实体");
}
}else {
List<UUID> uuidList = new ArrayList<>();
for (UUID uuid : entityUUIDToPlayer.keySet()){
@ -578,9 +439,11 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
uuidList.add(uuid);
}
}
PlayerRefreshinfo playerRefreshinfo = new PlayerRefreshinfo(name,0, uuidList);
PlayerRefreshLintener playerRefreshinfo = new PlayerRefreshLintener(name, configManager);
refreshPlayer.put(name, playerRefreshinfo);
logger.info(name + "开始刷新实体");
if (logBool) {
log.info(name + "开始刷新实体");
}
}
}
@ -598,4 +461,21 @@ public class EntityRefreshListener implements Listener, CommandExecutor {
return true;
}
}
public ConfigManager getConfigManager() {
return configManager;
}
public List<String> getNoRefreshPlayer() {
return noRefreshPlayer;
}
public void setConfigManager(ConfigManager configManager) {
this.configManager = configManager;
for (String name : refreshPlayer.keySet()){
refreshPlayer.get(name).setConfigManager(configManager);
}
}
}

View File

@ -0,0 +1,312 @@
package com.yuyu.srwildentity.listener;
import com.yuyu.srwildentity.conditionCheck.ConditionCheck;
import com.yuyu.srwildentity.config.ConfigManager;
import com.yuyu.srwildentity.config.condition.EntityCondition;
import com.yuyu.srwildentity.config.condition.EntitySite;
import com.yuyu.srwildentity.config.condition.LevelRefresh;
import com.yuyu.srwildentity.config.condition.SpawnEntityType;
import com.yuyu.srwildentity.pojo.AreaRefresh;
import com.yuyu.srwildentity.pojo.BlackListArea;
import com.yuyu.srwildentity.pojo.PlayerRefreshinfo;
import io.lumine.xikage.mythicmobs.MythicMobs;
import io.lumine.xikage.mythicmobs.api.exceptions.InvalidMobTypeException;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import java.util.*;
/**
* @author
* @version 1.0
* @project SrWildEntityNew
* @date 2024/8/3 19:35:39
* @description 针对单个玩家的监听类注意这里要在实体刷新的监听类中统一管理
*/
public class PlayerRefreshLintener {
private String playerName;
private ConfigManager configManager;
private Random random;
private PlayerRefreshinfo playerRefreshinfo;
private Integer workId;
private boolean flag = false;
private MythicMobs mythicMobs;
public PlayerRefreshLintener(String player, ConfigManager configManager) {
this.playerRefreshinfo = new PlayerRefreshinfo(playerName,0,new ArrayList<>());
this.playerName = player;
this.configManager = configManager;
this.random = new Random();
this.mythicMobs = MythicMobs.inst();
}
/**
* 定时任务每隔一段时间在玩家附近刷新实体
*/
public void timedRdfreshEneity(){
if (EntityRefreshListener.flag) {
if (!flag){
return;
}
if (EntityRefreshListener.logBool){
EntityRefreshListener.log.info(ChatColor.GOLD+playerName+"执行刷新任务");
}
int num = configManager.getNum();//每次执行时刷新的总数
int attempts = 0;
int sum = 0;//用于记录此次刷新生成的总数
//获取玩家信息
Player player = Bukkit.getPlayer(playerName);
//玩家不在线
if (player == null){
if (EntityRefreshListener.logBool){
EntityRefreshListener.log.info(ChatColor.RED + "Player " + playerName + " not found");
}
//返回之前取消定时任务
Bukkit.getScheduler().cancelTask(this.workId);
return;
}
Location playerlocation = player.getLocation();
World world = playerlocation.getWorld();
String worldName = world.getName();
boolean pass = false;
//如果黑名单的set集合里面包含有该世界的名字则跳过
if (configManager.getBlacklistWorldSet().contains(worldName)){
if (EntityRefreshListener.logBool){
EntityRefreshListener.log.info(ChatColor.RED + "黑名单世界 " + worldName+"\t"+playerName);
}
return;
}
if (configManager.getBlackListAreaMap().containsKey(worldName)){
List<BlackListArea> blackListAreas = configManager.getBlackListAreaMap().get(worldName);
for (BlackListArea blackListArea : blackListAreas){
int blockX = playerlocation.getBlockX();
int blockZ = playerlocation.getBlockZ();
if (blackListArea.getX1() >= blockX && blockX >= blackListArea.getX2()
&& blackListArea.getY1() >= blockZ && blockZ >= blackListArea.getY2()){
//tag为循环标志此处会直接结束tag标志处的循环
if (EntityRefreshListener.logBool){
EntityRefreshListener.log.info(ChatColor.RED + "黑名单区域 " + worldName+"\t"+playerName);
}
return;
}
}
}
//玩家危险度,用于刷新实体的等级
int riskLevel = EntityRefreshListener.prRisk(player);
if (riskLevel == 0){
//等于0不刷新怪物,直接跳过
if (EntityRefreshListener.logBool){
EntityRefreshListener.log.info(ChatColor.RED+playerName+"危险度为0");
}
return;
}
LevelRefresh refreshList = null;
List<LevelRefresh> levelRefreshesList = configManager.getBiomeEntityRefreshSettings().getLevelRefreshesList();
for (LevelRefresh levelRefresh : levelRefreshesList){
if (riskLevel > levelRefresh.getRiskMin() && riskLevel <= levelRefresh.getRiskMax()){
refreshList = levelRefresh;
}
}
if (refreshList == null){
if ( EntityRefreshListener.logBool) {
EntityRefreshListener.log.info(ChatColor.MAGIC + playerName + "所在群系" + "没有危险度为:" + riskLevel + "时适配的刷新列表");
}
return;
}
//获取玩家位置信息
int blockZ = playerlocation.getBlockZ();
int blockX = playerlocation.getBlockX();
int blockY = playerlocation.getBlockY();
Biome biome = world.getBiome(blockX, blockZ);
String biomeName = biome.name();
List<EntityCondition> entityConditionList = null;
HashMap<String, List<EntityCondition>> entityConditionHashMap = refreshList.getEntityConditionHashMap();
for (String refreshBiome : entityConditionHashMap.keySet()){
if (biomeName.contains(refreshBiome)){
entityConditionList = entityConditionHashMap.get(refreshBiome);
}
}
if (entityConditionList == null){
if (EntityRefreshListener.logBool) {
EntityRefreshListener.log.info(ChatColor.RED + "没有配置" + biomeName + "群系的实体刷新案例");
}
return;
}
for (EntityCondition entityCondition : entityConditionList){
int yMin = entityCondition.getyMin();
int yMax = entityCondition.getyMax();
//如果玩家所在位置不再设置的y轴高度内则不刷新此entity
if (yMin > blockY || yMax < blockY){
if (EntityRefreshListener.logBool) {
EntityRefreshListener.log.info(ChatColor.RED + "刷新高度不通过" + entityCondition.getEntityName()+"\tyMax="+yMax+"\tyMin="+yMin+"\tblockY="+blockY);
}
continue;
}
float v = random.nextFloat();
if ( entityCondition.getWeight() <= v){
if (EntityRefreshListener.logBool) {
//刷新不通过,进入下一个验证的实体
EntityRefreshListener.log.info(ChatColor.RED + "刷新权重不通过" + entityCondition.getEntityName() + "权重:" + entityCondition.getWeight() + "\t" + v);
}
continue;
}
int nums = entityCondition.getNums();//当前实体需要刷新的数量
for (int i = 0;i<nums &&
playerRefreshinfo.getEntityList().size() < configManager.getTotal()
&& sum <= num
&& attempts <= configManager.getAttempts(); i++) {
// 生成x和y坐标,会随机在玩家方圆15个方块的距离内随机生成
int x =blockX + random.nextInt(30) - 15; // 生成0到60之间的随机数然后减去30得到-30到30的范围
int z =blockZ + random.nextInt(30) - 15; // 同上,在玩家附近随机位置生成
int y =blockY + random.nextInt(3) - 3; //在玩家Y轴上下3格尝试刷新
//刷新在地上直接获取最高的x z 最高处的坐标
if (entityCondition.getEntitySite() == EntitySite.ON_GROUND) {
Location location = new Location(world, x, y , z);
//判断位置是否符合
if (ConditionCheck.checkEntityRefresh(world, location, entityCondition)) {
//通过则生成
// Entity entity = world.spawnEntity(location, EntityType.valueOf(entityCondition.getEntityName()));
Entity entity;
//MC原生实体
if (entityCondition.getEntityType() == SpawnEntityType.PROTOGENESIS){
entity = world.spawnEntity(location, EntityType.valueOf(entityCondition.getEntityName()));
}else {
//刷新MM怪物
try {
entity = mythicMobs.getAPIHelper().spawnMythicMob(entityCondition.getEntityName(),location,riskLevel);
} catch (InvalidMobTypeException e) {
throw new RuntimeException(e);
}
}
if (EntityRefreshListener.logBool) {
EntityRefreshListener.log.info(ChatColor.GOLD + "" + x + " " + y + " " + z + "位置刷新了" + entityCondition.getEntityName());
}
UUID uniqueId = entity.getUniqueId();
//存入玩家对应的刷新的实体集合便于寻找
EntityRefreshListener.entityUUIDToPlayer.put(uniqueId, playerName);
//存入
playerRefreshinfo.addEntityList(uniqueId);
attempts++;
sum++;
}
} else {
//不刷新在地上在定义的范围内随机高度概率生成实体
for (int c = 0; i<nums && c < 10 && sum <= num &&
playerRefreshinfo.getEntityList().size() < configManager.getTotal();
c++) {
//循环十次验证刷新位置
y = blockY + random.nextInt(3) - 3;//在玩家所在高度的上下三格内生成便于当玩家在洞穴时定位洞穴
x = blockX + random.nextInt(30) - 15; // 生成0到60之间的随机数然后减去30得到-30到30的范围
z = blockZ + random.nextInt(30) - 15; // 同上,在玩家附近随机位置生成
if (entityCondition.getEntitySite() == EntitySite.ON_GROUND) {
y = world.getHighestBlockYAt(x,z);
}
Location location = new Location(world, x, y + 1, z);
//判断位置是否符合
if (ConditionCheck.checkEntityRefresh(world, location, entityCondition)) {
//通过则生成
Entity entity;
//MC原生实体
if (entityCondition.getEntityType() == SpawnEntityType.PROTOGENESIS){
entity = world.spawnEntity(location, EntityType.valueOf(entityCondition.getEntityName()));
}else {
//刷新MM怪物
try {
entity = MythicMobs.inst().getAPIHelper().spawnMythicMob(entityCondition.getEntityName(), location);
} catch (InvalidMobTypeException e) {
throw new RuntimeException(e);
}
}
if (EntityRefreshListener.logBool) {
EntityRefreshListener.log.info(ChatColor.GOLD + "" + x + " " + y + " " + z + "位置刷新了" + entityCondition.getEntityName());
}
UUID uniqueId = entity.getUniqueId();
//存入玩家对应的刷新的实体集合便于寻找
EntityRefreshListener.entityUUIDToPlayer.put(uniqueId, playerName);
//存入
playerRefreshinfo.addEntityList(uniqueId);
i++;
sum++;
attempts++;
}
}
}
}
}
}
}
public Integer getWorkId() {
return workId;
}
public void setWorkId(Integer workId) {
this.workId = workId;
}
public ConfigManager getConfigManager() {
return configManager;
}
public void setConfigManager(ConfigManager configManager) {
this.configManager = configManager;
}
public PlayerRefreshinfo getPlayerRefreshinfo() {
return playerRefreshinfo;
}
public void setPlayerRefreshinfo(PlayerRefreshinfo playerRefreshinfo) {
this.playerRefreshinfo = playerRefreshinfo;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}

View File

@ -1,18 +1,8 @@
RISK_MAX: 10 #当最大危险度为多少时读取这个yml文件10的时候会读取
RISK_MIN: 0 #当最小危险度为多少时读取这个yml文件0的时候不会读取
#RISK_MAX: 10 #当最大危险度为多少时读取这个yml文件10的时候会读取
#RISK_MIN: 0 #当最小危险度为多少时读取这个yml文件0的时候不会读取
DESERT:
ZOMBIE: #指出entity在该群系的刷新条件
type: 0 #0表示生成mc原生实体1表示生成MM怪物,不能为空!
site: 1 #刷新位置,数字代表不同的刷新位置
light: 15 #刷新亮度
startTiming: 0 #刷新怪物的时间注意这里需要用mc中的时间格式来表示而不是现实中的时间
endTiming: 20000 #结束刷新的时间,怪物会在这个区间内刷新
nums: 2 #entity的刷新数量注意这里的数量会和通群系中其他entity相关总数不会超过config.yml中的定义
yMax: 150 #极限刷新高度
yMin: 60 #最小刷新高度
riskMax: 10 #刷新危险度的范围
riskMin: 0 #条件是小于等于riskMin大于riskMax即riskMin<= risklevel < riskMax 才会刷新
weight: 1.0 #权重越高刷新的概率越高最高为1.0
Matching_direction: ROOFED_FOREST_ZOMBIE #群系_怪物 会直接读取该实体的刷新配置
ROOFED_FOREST:
ZOMBIE: #指出entity在该群系的刷新条件
type: 0 #0表示生成mc原生实体1表示生成MM怪物2表示生成萌芽怪物
@ -25,14 +15,4 @@ ROOFED_FOREST:
yMin: 60 #最小刷新高度
riskMax: 10 #刷新危险度的范围
riskMin: 0
PIG_ZOMBIE: #指出entity在该群系的刷新条件
type: 0 #0表示生成mc原生实体1表示生成MM怪物2表示生成萌芽怪物
site: 1 #刷新位置,数字代表不同的刷新位置
light: 15 #刷新亮度
startTiming: 0 #刷新怪物的时间注意这里需要用mc中的时间格式来表示而不是现实中的时间
endTiming: 24000 #结束刷新的时间,怪物会在这个区间内刷新
nums: 2 #entity的刷新数量注意这里的数量会和通群系中其他entity相关总数不会超过config.yml中的定义
yMax: 150 #极限刷新高度
yMin: 60 #最小刷新高度
riskMax: 10 #刷新危险度的范围
riskMin: 0

View File

@ -2,6 +2,12 @@ name: SrWildEntity
version: '${project.version}'
main: com.yuyu.srwildentity.SrWildEntity
description: 实体刷新插件
depend:
- Towny
- PlaceholderAPI
- PlayerRisk
- MythicMobs
- GermPlugin
authors: [Yuyu]
commands:
despawn: