This commit is contained in:
yaohunya 2025-08-10 04:54:05 +08:00
parent d1fc0be07f
commit 228725300e
10 changed files with 57 additions and 122 deletions

View File

@ -13,7 +13,6 @@ import com.yaohun.demonskills.gui.SkillsGui;
import com.yaohun.demonskills.listener.PlayerListener; import com.yaohun.demonskills.listener.PlayerListener;
import com.yaohun.demonskills.listener.SkillKeyListener; import com.yaohun.demonskills.listener.SkillKeyListener;
import com.yaohun.demonskills.manage.PlayerManager; import com.yaohun.demonskills.manage.PlayerManager;
import com.yaohun.demonskills.util.AsyncPlayerDataSaver;
import com.yaohun.demonskills.util.CDTimeAPI; import com.yaohun.demonskills.util.CDTimeAPI;
import me.Demon.DemonPlugin.DemonAPI; import me.Demon.DemonPlugin.DemonAPI;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -50,8 +49,6 @@ public class SkillsMain extends JavaPlugin {
} }
Bukkit.getConsoleSender().sendMessage("§b[魂式技能] §a插件成功载入Server"); Bukkit.getConsoleSender().sendMessage("§b[魂式技能] §a插件成功载入Server");
Bukkit.getConsoleSender().sendMessage("§b[魂式技能] §a妖魂QQ: §b1763917516"); Bukkit.getConsoleSender().sendMessage("§b[魂式技能] §a妖魂QQ: §b1763917516");
new AsyncPlayerDataSaver(this);
} }
@Override @Override

View File

@ -1,10 +1,8 @@
package com.yaohun.demonskills.data; package com.yaohun.demonskills.data;
import com.yaohun.demonskills.SkillsMain;
import com.yaohun.demonskills.core.Skill; import com.yaohun.demonskills.core.Skill;
import me.Demon.DemonPlugin.DemonAPI; import me.Demon.DemonPlugin.DemonAPI;
import me.Demon.DemonPlugin.data.NbtItem; import me.Demon.DemonPlugin.data.NbtItem;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
@ -13,7 +11,6 @@ import org.bukkit.inventory.ItemStack;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
public class PlayerData { public class PlayerData {
@ -64,37 +61,19 @@ public class PlayerData {
} }
public void SavePlayerData(){ public void SavePlayerData(){
// 1. 主线程内抓取快照避免异步直接访问成员变量 this.configuration.set("Magic",this.magicMax);
int magicMaxSnapshot = this.magicMax; this.configuration.set("KeyBoard",null);
for (Integer keyBoard : keyBoardStackMap.keySet()) {
// 复制键盘映射注意深拷贝 ItemStack ItemStack keyBoardStack = keyBoardStackMap.get(keyBoard);
Map<Integer, ItemStack> keyboardSnapshot = new HashMap<>(); this.configuration.set("KeyBoard."+keyBoard,keyBoardStack);
for (Map.Entry<Integer, ItemStack> entry : this.keyBoardStackMap.entrySet()) {
keyboardSnapshot.put(entry.getKey(), entry.getValue().clone());
} }
// 创建配置快照
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 { try {
configSnapshot.save(fileSnapshot); this.configuration.save(this.file);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); throw new RuntimeException(e);
} }
});
} }
public String getPlayerName() { public String getPlayerName() {
return name; return name;
} }

View File

@ -72,7 +72,8 @@ public class StoneEquipGui implements Listener {
player.closeInventory(); player.closeInventory();
PlayerManager playerManager = SkillsMain.getPlayerManager(); PlayerManager playerManager = SkillsMain.getPlayerManager();
PlayerData playerData = playerManager.getPlayerData(playerName); PlayerData playerData = playerManager.getPlayerData(playerName);
// 设置完成后保存玩家数据
playerData.SavePlayerData();
SkillsGui.checkItemSetBindKeyBoard(playerData, skillStone, rawSlot); SkillsGui.checkItemSetBindKeyBoard(playerData, skillStone, rawSlot);
player.playSound(player.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1); player.playSound(player.getLocation(), Sound.BLOCK_COMPARATOR_CLICK,1,1);
new BukkitRunnable() { new BukkitRunnable() {

View File

@ -68,44 +68,44 @@ public class Skill_赤焰旋风斩 {
new DelayComponent(8L, Arrays.asList( new DelayComponent(8L, Arrays.asList(
new PotionEffectComponent(PotionEffectType.SLOW,70,2), new PotionEffectComponent(PotionEffectType.SLOW,70,2),
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L, Arrays.asList( new DelayComponent(10L, Arrays.asList(
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L, Arrays.asList( new DelayComponent(10L, Arrays.asList(
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L, Arrays.asList( new DelayComponent(10L, Arrays.asList(
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L, Arrays.asList( new DelayComponent(10L, Arrays.asList(
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L,Arrays.asList( new DelayComponent(10L,Arrays.asList(
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L,Arrays.asList( new DelayComponent(10L,Arrays.asList(
new DamageComponent(damage*0.2,new NearestEnemiesSelector(5)), 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 SoundComponent("战士音效/旋风斩音效.ogg", 0.5f, 1.0f,10),
new DelayComponent(10L,Arrays.asList( new DelayComponent(10L,Arrays.asList(
// 播放爆炸音效 // 播放爆炸音效
new SoundComponent("ENTITY_GENERIC_EXPLODE",1.0f,1.0f), new SoundComponent("ENTITY_GENERIC_EXPLODE",1.0f,1.0f),
// 播放 跟随岩浆粒子 5次 // 播放 跟随岩浆粒子 5次
new ParticlesComponent(Particle.LAVA,5,0.2,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))
)) ))
)) ))
)) ))

View File

@ -9,7 +9,6 @@ import com.yaohun.demonskills.component.dragoncore.ParticleSpawnCommponent;
import com.yaohun.demonskills.component.dragoncore.PlayerAnimationComponent; import com.yaohun.demonskills.component.dragoncore.PlayerAnimationComponent;
import com.yaohun.demonskills.component.dragoncore.StandAnimationComponent; import com.yaohun.demonskills.component.dragoncore.StandAnimationComponent;
import com.yaohun.demonskills.component.particles.ParticlesComponent; import com.yaohun.demonskills.component.particles.ParticlesComponent;
import com.yaohun.demonskills.component.projectile.ProjectileAdvanceComponent;
import com.yaohun.demonskills.core.Skill; import com.yaohun.demonskills.core.Skill;
import com.yaohun.demonskills.data.PlayerData; import com.yaohun.demonskills.data.PlayerData;
import com.yaohun.demonskills.manage.PlayerManager; import com.yaohun.demonskills.manage.PlayerManager;

View File

@ -92,7 +92,7 @@ public class Skill_逐影破空斩 {
new PotionEffectComponent(PotionEffectType.SLOW,10,5,new ConeEnemiesSelector(10.0,45)), new PotionEffectComponent(PotionEffectType.SLOW,10,5,new ConeEnemiesSelector(10.0,45)),
new SoundComponent("挥舞剑气1.ogg", 0.6f, 1.0f), new SoundComponent("挥舞剑气1.ogg", 0.6f, 1.0f),
new DelayComponent(8L,Arrays.asList( 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)) new DamageComponent(damage * 0.2,new ConeEnemiesSelector(10.0,45))
)) ))
)) ))

View File

@ -18,12 +18,19 @@ public class ConeEnemiesSelector implements TargetSelector {
private final double radius; // 范围 private final double radius; // 范围
private final double angle; // 角度 60° private final double angle; // 角度 60°
private int limit = -1; private int limit = -1;
private boolean playerImmune = false;
public ConeEnemiesSelector(double radius, double angle) { public ConeEnemiesSelector(double radius, double angle) {
this.radius = radius; this.radius = radius;
this.angle = angle; 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) { public ConeEnemiesSelector(double radius, double angle, int limit) {
this.radius = radius; this.radius = radius;
this.angle = angle; this.angle = angle;
@ -40,6 +47,11 @@ public class ConeEnemiesSelector implements TargetSelector {
if (!(entity instanceof LivingEntity) || entity.equals(caster)) continue; if (!(entity instanceof LivingEntity) || entity.equals(caster)) continue;
if (entity instanceof ArmorStand) continue; if (entity instanceof ArmorStand) continue;
if (CitizensAPI.getNPCRegistry().isNPC(entity)) continue; if (CitizensAPI.getNPCRegistry().isNPC(entity)) continue;
if(playerImmune){
if(entity instanceof Player){
continue;
}
}
Vector toTarget = entity.getLocation().toVector().subtract(eyeVec); Vector toTarget = entity.getLocation().toVector().subtract(eyeVec);
toTarget.setY(0); toTarget.setY(0);

View File

@ -10,15 +10,23 @@ import org.bukkit.entity.Player;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
public class NearestEnemiesSelector implements TargetSelector { public class NearestEnemiesSelector implements TargetSelector {
private final double radius; private final double radius;
private int limit = 0; private int limit = 0;
// 是否让玩家免疫不作为目标
private boolean playerImmune = false;
public NearestEnemiesSelector(double radius) { public NearestEnemiesSelector(double radius) {
this.radius = radius; this.radius = radius;
} }
public NearestEnemiesSelector(double radius,boolean playerImmune) {
this.radius = radius;
this.playerImmune = playerImmune;
}
public NearestEnemiesSelector(double radius, int limit) { public NearestEnemiesSelector(double radius, int limit) {
this.radius = radius; this.radius = radius;
this.limit = limit; this.limit = limit;
@ -26,20 +34,20 @@ public class NearestEnemiesSelector implements TargetSelector {
@Override @Override
public List<Entity> selectTargets(Player caster) { public List<Entity> selectTargets(Player caster) {
if(limit != 0) { Stream<Entity> stream = caster.getNearbyEntities(radius, radius, radius).stream()
return caster.getNearbyEntities(radius, radius, radius).stream()
.filter(e -> !(e instanceof ArmorStand)) .filter(e -> !(e instanceof ArmorStand))
.filter(e -> e instanceof LivingEntity && !e.equals(caster)) .filter(e -> e instanceof LivingEntity && !e.equals(caster))
.filter(e -> !CitizensAPI.getNPCRegistry().isNPC(e)) // 排除NPC .filter(e -> !CitizensAPI.getNPCRegistry().isNPC(e)); // 排除NPC
.sorted(Comparator.comparingDouble(e -> e.getLocation().distanceSquared(caster.getLocation())))
.limit(limit) if (playerImmune) {
.collect(Collectors.toList()); stream = stream.filter(e -> !(e instanceof Player)); // 玩家免疫
} else { }
return caster.getNearbyEntities(radius, radius, radius).stream()
.filter(e -> !(e instanceof ArmorStand)) stream = stream.sorted(Comparator.comparingDouble(e -> e.getLocation().distanceSquared(caster.getLocation())));
.filter(e -> !CitizensAPI.getNPCRegistry().isNPC(e)) // 排除NPC
.filter(e -> e instanceof LivingEntity && !e.equals(caster)) if (limit > 0) {
.collect(Collectors.toList()); stream = stream.limit(limit);
} }
return stream.collect(Collectors.toList());
} }
} }

View File

@ -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只处理内存数据快照
}
}

View File

@ -1,6 +1,6 @@
name: DemonSkills name: DemonSkills
main: com.yaohun.demonskills.SkillsMain main: com.yaohun.demonskills.SkillsMain
version: 1.3.6 version: 1.3.8
depend: depend:
- DemonAPI - DemonAPI
commands: commands: