1.3.8
This commit is contained in:
parent
d1fc0be07f
commit
228725300e
|
@ -13,7 +13,6 @@ import com.yaohun.demonskills.gui.SkillsGui;
|
|||
import com.yaohun.demonskills.listener.PlayerListener;
|
||||
import com.yaohun.demonskills.listener.SkillKeyListener;
|
||||
import com.yaohun.demonskills.manage.PlayerManager;
|
||||
import com.yaohun.demonskills.util.AsyncPlayerDataSaver;
|
||||
import com.yaohun.demonskills.util.CDTimeAPI;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import org.bukkit.Bukkit;
|
||||
|
@ -50,8 +49,6 @@ public class SkillsMain extends JavaPlugin {
|
|||
}
|
||||
Bukkit.getConsoleSender().sendMessage("§b[魂式技能] §a插件成功载入Server!");
|
||||
Bukkit.getConsoleSender().sendMessage("§b[魂式技能] §a妖魂QQ: §b1763917516");
|
||||
|
||||
new AsyncPlayerDataSaver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package com.yaohun.demonskills.data;
|
||||
|
||||
import com.yaohun.demonskills.SkillsMain;
|
||||
import com.yaohun.demonskills.core.Skill;
|
||||
import me.Demon.DemonPlugin.DemonAPI;
|
||||
import me.Demon.DemonPlugin.data.NbtItem;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
@ -13,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PlayerData {
|
||||
|
||||
|
@ -63,38 +60,20 @@ public class PlayerData {
|
|||
}
|
||||
}
|
||||
|
||||
public void SavePlayerData() {
|
||||
// ✅ 1. 主线程内抓取快照,避免异步直接访问成员变量
|
||||
int magicMaxSnapshot = this.magicMax;
|
||||
|
||||
// 复制键盘映射(注意深拷贝 ItemStack)
|
||||
Map<Integer, ItemStack> keyboardSnapshot = new HashMap<>();
|
||||
for (Map.Entry<Integer, ItemStack> entry : this.keyBoardStackMap.entrySet()) {
|
||||
keyboardSnapshot.put(entry.getKey(), entry.getValue().clone());
|
||||
public void SavePlayerData(){
|
||||
this.configuration.set("Magic",this.magicMax);
|
||||
this.configuration.set("KeyBoard",null);
|
||||
for (Integer keyBoard : keyBoardStackMap.keySet()) {
|
||||
ItemStack keyBoardStack = keyBoardStackMap.get(keyBoard);
|
||||
this.configuration.set("KeyBoard."+keyBoard,keyBoardStack);
|
||||
}
|
||||
|
||||
// 创建配置快照
|
||||
File fileSnapshot = this.file;
|
||||
YamlConfiguration configSnapshot = new YamlConfiguration();
|
||||
|
||||
// ✅ 2. 异步保存,使用快照对象,避免线程冲突
|
||||
Bukkit.getScheduler().runTaskAsynchronously(SkillsMain.inst(), () -> {
|
||||
configSnapshot.set("Magic", magicMaxSnapshot);
|
||||
configSnapshot.set("KeyBoard", null);
|
||||
|
||||
for (Map.Entry<Integer, ItemStack> entry : keyboardSnapshot.entrySet()) {
|
||||
configSnapshot.set("KeyBoard." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
try {
|
||||
configSnapshot.save(fileSnapshot);
|
||||
this.configuration.save(this.file);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public String getPlayerName() {
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,8 @@ public class StoneEquipGui implements Listener {
|
|||
player.closeInventory();
|
||||
PlayerManager playerManager = SkillsMain.getPlayerManager();
|
||||
PlayerData playerData = playerManager.getPlayerData(playerName);
|
||||
|
||||
// 设置完成后保存玩家数据
|
||||
playerData.SavePlayerData();
|
||||
SkillsGui.checkItemSetBindKeyBoard(playerData, skillStone, rawSlot);
|
||||
player.playSound(player.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1);
|
||||
new BukkitRunnable() {
|
||||
|
|
|
@ -68,44 +68,44 @@ public class Skill_赤焰旋风斩 {
|
|||
new DelayComponent(8L, Arrays.asList(
|
||||
new PotionEffectComponent(PotionEffectType.SLOW,70,2),
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L, Arrays.asList(
|
||||
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L, Arrays.asList(
|
||||
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L, Arrays.asList(
|
||||
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L, Arrays.asList(
|
||||
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L,Arrays.asList(
|
||||
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L,Arrays.asList(
|
||||
|
||||
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5)),
|
||||
new ProjectileAdvanceComponent(0.5,0.2,new NearestEnemiesSelector(5,true)),
|
||||
new SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
|
||||
new DelayComponent(10L,Arrays.asList(
|
||||
// 播放爆炸音效
|
||||
new SoundComponent("ENTITY_GENERIC_EXPLODE",1.0f,1.0f),
|
||||
// 播放 跟随岩浆粒子 5次
|
||||
new ParticlesComponent(Particle.LAVA,5,0.2,5),
|
||||
new ProjectileAdvanceComponent(0.6,0.8,new NearestEnemiesSelector(3))
|
||||
new ProjectileAdvanceComponent(0.6,0.8,new NearestEnemiesSelector(3,true))
|
||||
))
|
||||
))
|
||||
))
|
||||
|
|
|
@ -9,7 +9,6 @@ import com.yaohun.demonskills.component.dragoncore.ParticleSpawnCommponent;
|
|||
import com.yaohun.demonskills.component.dragoncore.PlayerAnimationComponent;
|
||||
import com.yaohun.demonskills.component.dragoncore.StandAnimationComponent;
|
||||
import com.yaohun.demonskills.component.particles.ParticlesComponent;
|
||||
import com.yaohun.demonskills.component.projectile.ProjectileAdvanceComponent;
|
||||
import com.yaohun.demonskills.core.Skill;
|
||||
import com.yaohun.demonskills.data.PlayerData;
|
||||
import com.yaohun.demonskills.manage.PlayerManager;
|
||||
|
|
|
@ -92,7 +92,7 @@ public class Skill_逐影破空斩 {
|
|||
new PotionEffectComponent(PotionEffectType.SLOW,10,5,new ConeEnemiesSelector(10.0,45)),
|
||||
new SoundComponent("挥舞剑气1.ogg", 0.6f, 1.0f),
|
||||
new DelayComponent(8L,Arrays.asList(
|
||||
new ProjectileAdvanceComponent(-2,0.2,new ConeEnemiesSelector(10.0,45)),
|
||||
new ProjectileAdvanceComponent(-2,0.2,new ConeEnemiesSelector(10.0,45,true)),
|
||||
new DamageComponent(damage * 0.2,new ConeEnemiesSelector(10.0,45))
|
||||
))
|
||||
))
|
||||
|
|
|
@ -18,12 +18,19 @@ public class ConeEnemiesSelector implements TargetSelector {
|
|||
private final double radius; // 范围
|
||||
private final double angle; // 角度(如 60°)
|
||||
private int limit = -1;
|
||||
private boolean playerImmune = false;
|
||||
|
||||
public ConeEnemiesSelector(double radius, double angle) {
|
||||
this.radius = radius;
|
||||
this.angle = angle;
|
||||
}
|
||||
|
||||
public ConeEnemiesSelector(double radius, double angle,boolean playerImmune) {
|
||||
this.radius = radius;
|
||||
this.angle = angle;
|
||||
this.playerImmune = playerImmune;
|
||||
}
|
||||
|
||||
public ConeEnemiesSelector(double radius, double angle, int limit) {
|
||||
this.radius = radius;
|
||||
this.angle = angle;
|
||||
|
@ -40,6 +47,11 @@ public class ConeEnemiesSelector implements TargetSelector {
|
|||
if (!(entity instanceof LivingEntity) || entity.equals(caster)) continue;
|
||||
if (entity instanceof ArmorStand) continue;
|
||||
if (CitizensAPI.getNPCRegistry().isNPC(entity)) continue;
|
||||
if(playerImmune){
|
||||
if(entity instanceof Player){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Vector toTarget = entity.getLocation().toVector().subtract(eyeVec);
|
||||
toTarget.setY(0);
|
||||
|
|
|
@ -10,15 +10,23 @@ import org.bukkit.entity.Player;
|
|||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class NearestEnemiesSelector implements TargetSelector {
|
||||
private final double radius;
|
||||
private int limit = 0;
|
||||
// 是否让玩家免疫(不作为目标)
|
||||
private boolean playerImmune = false;
|
||||
|
||||
public NearestEnemiesSelector(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public NearestEnemiesSelector(double radius,boolean playerImmune) {
|
||||
this.radius = radius;
|
||||
this.playerImmune = playerImmune;
|
||||
}
|
||||
|
||||
public NearestEnemiesSelector(double radius, int limit) {
|
||||
this.radius = radius;
|
||||
this.limit = limit;
|
||||
|
@ -26,20 +34,20 @@ public class NearestEnemiesSelector implements TargetSelector {
|
|||
|
||||
@Override
|
||||
public List<Entity> selectTargets(Player caster) {
|
||||
if(limit != 0) {
|
||||
return caster.getNearbyEntities(radius, radius, radius).stream()
|
||||
Stream<Entity> stream = caster.getNearbyEntities(radius, radius, radius).stream()
|
||||
.filter(e -> !(e instanceof ArmorStand))
|
||||
.filter(e -> e instanceof LivingEntity && !e.equals(caster))
|
||||
.filter(e -> !CitizensAPI.getNPCRegistry().isNPC(e)) // 排除NPC
|
||||
.sorted(Comparator.comparingDouble(e -> e.getLocation().distanceSquared(caster.getLocation())))
|
||||
.limit(limit)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
return caster.getNearbyEntities(radius, radius, radius).stream()
|
||||
.filter(e -> !(e instanceof ArmorStand))
|
||||
.filter(e -> !CitizensAPI.getNPCRegistry().isNPC(e)) // 排除NPC
|
||||
.filter(e -> e instanceof LivingEntity && !e.equals(caster))
|
||||
.collect(Collectors.toList());
|
||||
.filter(e -> !CitizensAPI.getNPCRegistry().isNPC(e)); // 排除NPC
|
||||
|
||||
if (playerImmune) {
|
||||
stream = stream.filter(e -> !(e instanceof Player)); // 玩家免疫
|
||||
}
|
||||
|
||||
stream = stream.sorted(Comparator.comparingDouble(e -> e.getLocation().distanceSquared(caster.getLocation())));
|
||||
|
||||
if (limit > 0) {
|
||||
stream = stream.limit(limit);
|
||||
}
|
||||
return stream.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package com.yaohun.demonskills.util;
|
||||
|
||||
import com.yaohun.demonskills.SkillsMain;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class AsyncPlayerDataSaver {
|
||||
|
||||
private final SkillsMain plugin;
|
||||
private final int batchSize = 5;
|
||||
private final int delayBetweenBatches = 20; // 每批延迟1秒(20tick)
|
||||
|
||||
public AsyncPlayerDataSaver(SkillsMain plugin) {
|
||||
this.plugin = plugin;
|
||||
startAutoSave();
|
||||
}
|
||||
|
||||
public void startAutoSave() {
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<Player> onlinePlayers = new ArrayList<>(Bukkit.getOnlinePlayers());
|
||||
if (onlinePlayers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int total = onlinePlayers.size();
|
||||
int batches = (int) Math.ceil((double) total / batchSize);
|
||||
|
||||
for (int i = 0; i < batches; i++) {
|
||||
final int batchIndex = i;
|
||||
|
||||
new BukkitRunnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int start = batchIndex * batchSize;
|
||||
int end = Math.min(start + batchSize, total);
|
||||
|
||||
for (int j = start; j < end; j++) {
|
||||
Player p = onlinePlayers.get(j);
|
||||
Bukkit.getScheduler().runTaskAsynchronously(SkillsMain.inst(), () -> {
|
||||
savePlayerData(p); // 你的保存方法(异步安全)
|
||||
});
|
||||
}
|
||||
}
|
||||
}.runTaskLater(SkillsMain.inst(), (long) delayBetweenBatches * i);
|
||||
}
|
||||
}
|
||||
}.runTaskTimer(SkillsMain.inst(), 20 * 60 * 10, 20 * 60 * 10); // 每5分钟执行一次
|
||||
}
|
||||
|
||||
private void savePlayerData(Player player) {
|
||||
// TODO: 将你的数据写入YAML或数据库
|
||||
// 注意线程安全,例如避免直接操作 Bukkit API,只处理内存数据快照
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
name: DemonSkills
|
||||
main: com.yaohun.demonskills.SkillsMain
|
||||
version: 1.3.6
|
||||
version: 1.3.8
|
||||
depend:
|
||||
- DemonAPI
|
||||
commands:
|
||||
|
|
Loading…
Reference in New Issue
Block a user