Compare commits

...

20 Commits

Author SHA1 Message Date
323e316f0f fixed bloodmoon sleep / time skip issue, added endermite hordes for end, fixed server restart during bloodmoon issue 2026-01-17 17:09:54 +01:00
0a16e1e049 added missing setting check for bloodmoon warning messages 2026-01-09 19:25:10 +01:00
c371893407 added support for portable stonecutter alongside crafting table, renamed listener for clarity 2026-01-02 22:29:27 +01:00
f2bf8f1858 fixed username validation to allow exceptions for Bedrock players due to specific naming constraints 2025-12-29 09:05:57 +01:00
a0a33f1f56 filtered null and duplicate player names in ReportCommand responses for improved reliability 2025-12-28 17:36:01 +01:00
164a160dbb fixed bloodmoon hordes for players with deactivated setting 2025-12-28 17:21:33 +01:00
efdbc6fe9f updated feedback link behavior, disabled outdated appliances, adjusted infection spawn and silverfish mechanics 2025-12-28 11:40:21 +01:00
7ac02b4ec4 added missing return for /event 2025-12-27 11:35:20 +01:00
93971650ce adjusted strike punishment durations for better balance and scaling 2025-12-27 11:08:47 +01:00
336e3f934c remove wrong location description 2025-12-27 00:47:13 +01:00
91e350ee62 disabled worldmuseum for craftattack 8 2025-12-26 19:50:59 +01:00
8736e78adf Merge remote-tracking branch 'origin/master' 2025-12-25 22:49:19 +01:00
329ec8e1da renamed adminPermission constant to adminmarker for improved clarity and consistency 2025-12-25 22:49:15 +01:00
ebf392b024 fixed bloodmoon progress bar trying updates when inactive 2025-12-24 14:26:23 +01:00
33d00e97c6 fixed recovery compass at project start 2025-12-24 01:07:53 +01:00
1fdcc11211 Merge pull request 'master-big-events' (#11) from master-big-events into master
Reviewed-on: #11
2025-12-23 23:54:14 +00:00
e0ed7ecdf5 Merge branch 'master' into master-big-events 2025-12-23 23:53:42 +00:00
2ca97c88fc made score staying the highest ever reached 2025-12-24 00:49:50 +01:00
fc502e3da8 fixed player join when no event is loaded 2025-12-24 00:16:22 +01:00
5e3db1e78c fixed event commands, removed infinite saturation, added player join check 2025-12-23 23:40:58 +01:00
27 changed files with 202 additions and 78 deletions

View File

@@ -14,7 +14,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class AdminMarker extends Appliance implements DisplayName.Colored {
public final static String adminPermission = "admin";
public final static String adminPermission = "adminmarker";
@Override
public @Nullable TextColor getNameColor(Player player) {

View File

@@ -19,7 +19,7 @@ public class HelpCommand extends ApplianceCommand<Help> {
Component.text("Willkommen auf Craftattack!", NamedTextColor.GOLD)
.appendNewline()
.append(Component.text("Wenn du hilfe benötigst kannst du dich jederzeit an einen Admin wenden." +
" Weitere Informationen zu Funktionen und Befehlen erhältst du zudem im Turm am Spawn.", NamedTextColor.GRAY))
" Weitere Informationen zu Funktionen und Befehlen erhältst du zudem am Spawn.", NamedTextColor.GRAY))
);
}
}

View File

@@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -46,7 +47,7 @@ class ReportCommand extends ApplianceCommand.PlayerChecked<Report> {
response = Stream.concat(
Bukkit.getOnlinePlayers().stream().map(Player::getName),
Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName)
).toList();
).filter(Objects::nonNull).distinct().toList();
}
if(args.length == 2) {

View File

@@ -7,6 +7,7 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Boat;
@SuppressWarnings("unused")
@Appliance.Flags(enabled = false)
public class AntiBoatFreecam extends Appliance {
private static final float MAX_YAW_OFFSET = 106.0f;

View File

@@ -5,23 +5,18 @@ import eu.mhsl.craftattack.spawn.core.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.commands.BloodmoonCommand;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonEntityDamageListener;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonMonsterDeathListener;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonPlayerJoinListener;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.BloodmoonTimeListener;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener.*;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.util.Ticks;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitTask;
@@ -70,7 +65,6 @@ public class Bloodmoon extends Appliance {
public final double mobHealthMultiplier = 2;
private final ThreadLocalRandom random = ThreadLocalRandom.current();
private boolean isActive = false;
private final BossBar bossBar = BossBar.bossBar(
Component.text("Blutmond", NamedTextColor.DARK_RED),
1f,
@@ -79,6 +73,7 @@ public class Bloodmoon extends Appliance {
Set.of(BossBar.Flag.CREATE_WORLD_FOG, BossBar.Flag.DARKEN_SCREEN)
);
private final boolean hordesEnabled = true;
public final boolean bloodmoonSkippable = true;
private final int hordeSpawnRateTicks = 40 * Ticks.TICKS_PER_SECOND;
private final int hordeSpawnRateVariationTicks = 40 * Ticks.TICKS_PER_SECOND;
private final int hordeMinPopulation = 3;
@@ -90,10 +85,10 @@ public class Bloodmoon extends Appliance {
EntityType.SPIDER
);
private final Map<Player, @Nullable BukkitTask> hordeSpawnTasks = new WeakHashMap<>();
private long lastBloodmoonStartTick = 0;
public final int ticksPerDay = 24000;
public final int bloodmoonLength = this.ticksPerDay / 2;
public final int preStartMessageTicks = Ticks.TICKS_PER_SECOND * 50;
private boolean bossbarActive = false;
private final int bloodmoonFreeDaysAtStart = 3;
private final int bloodmoonStartTime = this.ticksPerDay /2;
private final int bloodmoonDayInterval = 30;
@@ -113,35 +108,71 @@ public class Bloodmoon extends Appliance {
}
public boolean bloodmoonIsActive() {
return this.isActive;
long currentTick = Bukkit.getWorlds().getFirst().getFullTime();
long day = currentTick / this.ticksPerDay;
if(day % this.bloodmoonDayInterval != 0 || day - this.bloodmoonFreeDaysAtStart <= 0) return false;
long time = currentTick % this.ticksPerDay;
return time >= this.bloodmoonStartTime && time <= this.bloodmoonStartTime + this.bloodmoonLength;
}
public void startBloodmoon(long startTick) {
this.lastBloodmoonStartTick = startTick;
this.isActive = true;
public void startBloodmoon() {
this.bossbarActive = true;
Bukkit.getOnlinePlayers().forEach(this::addPlayerToBossBar);
this.startHordeSpawning(this.getRandomHordeSpawnDelay());
this.sendStartMessages();
}
public void stopBloodmoon() {
this.isActive = false;
public void stopBloodmoonIfInactive() {
Bukkit.getScheduler().runTaskLater(
Main.instance(),
() -> {
if(!this.bossbarActive) return;
if(this.bloodmoonIsActive()) return;
this.bossbarActive = false;
Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar));
this.stopHordeSpawning();
this.sendStopMessages();
},
1
);
}
// not working for entity effects and debuffs...
public void forceStopBloodmoon() {
this.bossbarActive = false;
Bukkit.getOnlinePlayers().forEach(player -> player.hideBossBar(this.bossBar));
this.stopHordeSpawning();
this.sendStopMessages();
}
public void updateBossBar() {
long tick = Bukkit.getWorlds().getFirst().getFullTime();
long sinceStart = tick - this.lastBloodmoonStartTick;
long sinceStart = tick - this.lastBloodmoonStartTick();
float progress = 1f - ((float) sinceStart / this.bloodmoonLength);
if(progress < 0) progress = 1f;
this.bossBar.progress(progress);
}
private long lastBloodmoonStartTick() {
long currentTick = Bukkit.getWorlds().getFirst().getFullTime();
long day = currentTick / this.ticksPerDay;
long time = currentTick % this.ticksPerDay;
boolean todayIsBloodmoon = (day % this.bloodmoonDayInterval == 0) && (day > this.bloodmoonFreeDaysAtStart);
if (todayIsBloodmoon && time < this.bloodmoonStartTime) {
day -= this.bloodmoonDayInterval;
} else if (!todayIsBloodmoon) {
day -= (day % this.bloodmoonDayInterval);
}
if (day <= this.bloodmoonFreeDaysAtStart) return -1L;
return day * this.ticksPerDay + this.bloodmoonStartTime;
}
public boolean isStartTick(long tick) {
long day = tick / this.ticksPerDay;
if(day % this.bloodmoonDayInterval != 0 || day - this.bloodmoonFreeDaysAtStart <= 0) return false;
long time = tick - (day * this.ticksPerDay);
if(day % this.bloodmoonDayInterval != 0 || day <= this.bloodmoonFreeDaysAtStart) return false;
long time = tick % this.ticksPerDay;
return time == this.bloodmoonStartTime;
}
@@ -153,7 +184,14 @@ public class Bloodmoon extends Appliance {
Bukkit.getOnlinePlayers().forEach(player -> this.startHordeSpawning(delay, player));
}
private void startHordeSpawning(int delay, Player player) {
private void stopHordeSpawning() {
this.hordeSpawnTasks.forEach((player, bukkitTask) -> {
@Nullable BukkitTask task = this.hordeSpawnTasks.get(player);
if(task != null) task.cancel();
});
}
public void startHordeSpawning(int delay, Player player) {
@Nullable BukkitTask task = this.hordeSpawnTasks.get(player);
if(task != null) task.cancel();
BukkitTask newTask = Bukkit.getScheduler().runTaskLater(
@@ -187,14 +225,17 @@ public class Bloodmoon extends Appliance {
public void spawnRandomHorde(Player player) {
if(!this.hordesEnabled) return;
if(!this.getBloodmoonSetting(player)) return;
if(!player.getGameMode().equals(GameMode.SURVIVAL)) return;
EntityType hordeEntityType = this.hordeMobList.get(this.random.nextInt(this.hordeMobList.size()));
if(player.getLocation().getWorld().getEnvironment().equals(World.Environment.THE_END)) hordeEntityType = EntityType.ENDERMITE;
int hordeSize = this.random.nextInt(this.hordeMinPopulation, this.hordeMaxPopulation + 1);
this.spawnHorde(player, hordeSize, hordeEntityType);
}
public void sendWarningMessage(Player p) {
if(!this.getBloodmoonSetting(p)) return;
p.sendMessage(Component.text("Der Blutmond waltet in diesem Augenblick!", NamedTextColor.RED));
}
@@ -215,7 +256,7 @@ public class Bloodmoon extends Appliance {
Math.cos(spawnRadiant)*this.hordeSpawnDistance
);
mobSpawnLocation.setY(player.getWorld().getHighestBlockYAt(mobSpawnLocation) + 1);
player.getWorld().spawnEntity(mobSpawnLocation, type);
player.getWorld().spawnEntity(mobSpawnLocation, type, CreatureSpawnEvent.SpawnReason.NATURAL);
player.getWorld().strikeLightningEffect(mobSpawnLocation);
}
}
@@ -269,7 +310,8 @@ public class Bloodmoon extends Appliance {
new BloodmoonMonsterDeathListener(),
new BloodmoonPlayerJoinListener(),
new BloodmoonEntityDamageListener(),
new BloodmoonTimeListener()
new BloodmoonTimeListener(),
new BloodmoonTimeSkipListener()
);
}

View File

@@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.comm
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
@@ -23,15 +24,19 @@ public class BloodmoonCommand extends ApplianceCommand<Bloodmoon> {
switch(args[0]) {
case "start": {
this.getAppliance().startBloodmoon(0L);
this.getAppliance().startBloodmoon();
sender.sendMessage("Started bloodmoon.");
break;
}
case "stop": {
this.getAppliance().stopBloodmoon();
this.getAppliance().forceStopBloodmoon();
sender.sendMessage("Stopped bloodmoon.");
break;
}
case "time": {
sender.sendMessage(String.valueOf(Bukkit.getWorlds().getFirst().getFullTime()));
break;
}
default: throw new Error("No such option: '%s' !".formatted(args[0]));
}
}

View File

@@ -2,6 +2,7 @@ package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.list
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
@@ -9,7 +10,9 @@ public class BloodmoonPlayerJoinListener extends ApplianceListener<Bloodmoon> {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if(!this.getAppliance().bloodmoonIsActive()) return;
this.getAppliance().addPlayerToBossBar(event.getPlayer());
this.getAppliance().sendWarningMessage(event.getPlayer());
Player player = event.getPlayer();
this.getAppliance().addPlayerToBossBar(player);
this.getAppliance().startHordeSpawning(1500, player);
this.getAppliance().sendWarningMessage(player);
}
}

View File

@@ -12,14 +12,14 @@ public class BloodmoonTimeListener extends ApplianceListener<Bloodmoon> {
public void onServerTick(ServerTickStartEvent event) {
long currentTime = Bukkit.getWorlds().getFirst().getFullTime();
if(this.getAppliance().isStartTick(currentTime)) {
this.getAppliance().startBloodmoon(currentTime);
this.getAppliance().startBloodmoon();
return;
}
if(this.getAppliance().isStartTick(currentTime - this.getAppliance().bloodmoonLength)) {
this.getAppliance().stopBloodmoon();
this.getAppliance().stopBloodmoonIfInactive();
return;
}
if(currentTime % Ticks.TICKS_PER_SECOND == 0) this.getAppliance().updateBossBar();
if(currentTime % Ticks.TICKS_PER_SECOND == 0 && this.getAppliance().bloodmoonIsActive()) this.getAppliance().updateBossBar();
if(this.getAppliance().isStartTick(currentTime + this.getAppliance().ticksPerDay)) {
this.getAppliance().sendAnnouncementMessages();
return;

View File

@@ -0,0 +1,29 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.listener;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.bloodmoon.Bloodmoon;
import net.kyori.adventure.text.Component;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.world.TimeSkipEvent;
public class BloodmoonTimeSkipListener extends ApplianceListener<Bloodmoon> {
@EventHandler
public void onTimeSkip(TimeSkipEvent event) {
if(this.getAppliance().bloodmoonSkippable || !event.getSkipReason().equals(TimeSkipEvent.SkipReason.NIGHT_SKIP)) {
this.getAppliance().stopBloodmoonIfInactive();
return;
}
event.setCancelled(true);
}
@EventHandler
public void onPlayerSleep(PlayerBedEnterEvent event) {
if(!this.getAppliance().bloodmoonIsActive()) return;
if(this.getAppliance().bloodmoonSkippable) return;
if(!event.getBedEnterResult().equals(PlayerBedEnterEvent.BedEnterResult.OK)) return;
event.setUseBed(Event.Result.DENY);
event.getPlayer().sendActionBar(Component.text("Du kannst während dem Blutmond nicht schlafen"));
}
}

View File

@@ -0,0 +1,20 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.portableCrafting;
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
class OnCraftingBlockUseListener extends ApplianceListener<PortableCrafting> {
@EventHandler
public void inInteract(PlayerInteractEvent event) {
if(!event.getAction().equals(Action.RIGHT_CLICK_AIR)) return;
if(!Settings.instance().getSetting(event.getPlayer(), Settings.Key.EnablePortableCrafting, Boolean.class)) return;
switch(event.getMaterial()) {
case CRAFTING_TABLE -> this.getAppliance().openCraftingTable(event.getPlayer());
case STONECUTTER -> this.getAppliance().openStonecutter(event.getPlayer());
}
}
}

View File

@@ -1,16 +0,0 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.gameplay.portableCrafting;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
class OnCraftingTableUseListener extends ApplianceListener<PortableCrafting> {
@EventHandler
public void inInteract(PlayerInteractEvent event) {
if(!event.getAction().equals(Action.RIGHT_CLICK_AIR)) return;
if(!event.getMaterial().equals(Material.CRAFTING_TABLE)) return;
this.getAppliance().openFor(event.getPlayer());
}
}

View File

@@ -14,13 +14,16 @@ public class PortableCrafting extends Appliance {
Settings.instance().declareSetting(PortableCraftingSetting.class);
}
public void openFor(Player player) {
if(!Settings.instance().getSetting(player, Settings.Key.EnablePortableCrafting, Boolean.class)) return;
public void openCraftingTable(Player player) {
player.openWorkbench(null, true);
}
public void openStonecutter(Player player) {
player.openStonecutter(null, true);
}
@Override
protected @NotNull List<Listener> listeners() {
return List.of(new OnCraftingTableUseListener());
return List.of(new OnCraftingBlockUseListener());
}
}

View File

@@ -18,7 +18,7 @@ public class PortableCraftingSetting extends BoolSetting implements CategorizedS
@Override
protected String description() {
return "Erlaubt das öffnen einer Werkbank in der Hand, ohne sie plazieren zu müssen";
return "Erlaubt das öffnen einer Werkbank oder einer Steinsäge in der Hand, ohne den Block plazieren zu müssen";
}
@Override

View File

@@ -160,6 +160,7 @@ public class Event extends Appliance {
p.sendMessage(Component.text("Betrete...", NamedTextColor.GREEN));
PluginMessage.connect(p, this.localConfig().getString("connect-server-name"));
});
return;
}
PluginMessage.connect(p, "grand-event");

View File

@@ -19,10 +19,10 @@ public class EventOpenSessionCommand extends ApplianceCommand<Event> {
@Override
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
if(args.length == 1) {
if(args.length == 0) {
this.getAppliance().openEvent(Event.EventType.SMALL);
} else {
this.getAppliance().openEvent(Event.EventType.valueOf(args[1]));
this.getAppliance().openEvent(Event.EventType.valueOf(args[0]));
}
sender.sendMessage(Component.text("Event-Server gestartet!", NamedTextColor.GREEN));
}

View File

@@ -9,7 +9,6 @@ import eu.mhsl.craftattack.spawn.core.api.HttpStatus;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.ComponentBuilder;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
@@ -52,7 +51,7 @@ public class Feedback extends Appliance {
message
.append(Component.text("Klicke hier und gib uns Feedback, damit wir dein Spielerlebnis verbessern können!", NamedTextColor.DARK_GREEN)
.hoverEvent(HoverEvent.showText(ComponentUtil.clickLink(feedbackUrl))))
.append(ComponentUtil.clickLink(feedbackUrl)))
.appendNewline()
.append(border);

View File

@@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
@Appliance.Flags(autoload = false, enabled = false)
public class WorldMuseum extends Appliance {
public DisplayVillager.ConfigBound villager;

View File

@@ -131,7 +131,7 @@ public class ProjectStart extends Appliance {
player.setHealth(20);
if(player.getInventory().contains(Material.RECOVERY_COMPASS)) {
player.getInventory().clear();
player.give(new ItemStack(Material.RECOVERY_COMPASS));
player.getInventory().addItem(new ItemStack(Material.RECOVERY_COMPASS));
} else {
player.getInventory().clear();
}

View File

@@ -20,9 +20,10 @@ public class Strikes extends Appliance {
private final Map<Integer, Duration> strikePunishmentMap = Map.of(
1, Duration.ofHours(1),
2, Duration.ofHours(24),
3, Duration.ofDays(3),
4, Duration.ofDays(7)
2, Duration.ofHours(3),
3, Duration.ofDays(1),
4, Duration.ofDays(2),
5, Duration.ofDays(3)
);

View File

@@ -49,7 +49,7 @@ public class Whitelist extends Appliance {
? Floodgate.getBedrockPlayer(player).getUsername()
: player.getName();
if(!user.username().trim().equalsIgnoreCase(purePlayerName))
if(!user.username().trim().equalsIgnoreCase(purePlayerName) && !Floodgate.isBedrock(player)) // TODO: Bedrock Namen mit leerzeichen funktionieren nicht, daher die ausnahme bei der NUtzernamenprüfung
throw new DisconnectInfo.Throwable(
"Nutzername geändert",
String.format("Der Name '%s' stimmt nicht mit '%s' überein.", user.username(), player.getName()),

View File

@@ -12,6 +12,6 @@ class InfectionSpawnListener extends ApplianceListener<ArmadilloInfectionReducer
public void onSpawn(CreatureSpawnEvent event) {
if(!event.getSpawnReason().equals(CreatureSpawnEvent.SpawnReason.POTION_EFFECT)) return;
if(!event.getEntity().getType().equals(EntityType.SILVERFISH)) return;
if(ThreadLocalRandom.current().nextDouble() > 0.7) event.setCancelled(true);
if(ThreadLocalRandom.current().nextDouble() > 0.8) event.setCancelled(true);
}
}

View File

@@ -1,10 +1,12 @@
package eu.mhsl.craftattack.spawn.craftattack.appliances.tweaks.silverfishExpReducer;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDeathEvent;
@Appliance.Flags(enabled = false)
class SilverfishDeathListener extends ApplianceListener<SilverfishExpReducer> {
@EventHandler
public void onDeath(EntityDeathEvent event) {

View File

@@ -127,7 +127,7 @@ public class Deathrun extends Appliance implements Event, Scorable {
public void stop() {
this.getScoreboardBuilder().stopAutomaticUpdates();
Title title = Title.title(Component.text("Ende!"), Component.empty());
this.pvpTask.cancel();
if(this.pvpTask != null) this.pvpTask.cancel();
this.pvpDisabled = true;
Bukkit.getOnlinePlayers().forEach(player -> {
player.showTitle(title);

View File

@@ -6,7 +6,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
public class DeathrunPlayerDamageListener extends ApplianceListener<Deathrun> {
@EventHandler
@@ -23,9 +22,4 @@ public class DeathrunPlayerDamageListener extends ApplianceListener<Deathrun> {
if(!(event.getEntity() instanceof Player)) return;
event.setCancelled(true);
}
@EventHandler
public void onHunger(FoodLevelChangeEvent event) {
if(!this.getAppliance().isBeforeStart()) event.setCancelled(true);
}
}

View File

@@ -18,6 +18,7 @@ import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.GameRule;
import org.bukkit.Statistic;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -81,14 +82,18 @@ public class EventController extends Appliance {
this.selectedEvent = null;
}
public boolean hasLoadedEvent() {
return this.selectedEvent != null;
}
public void scheduleStart(long durationMinutes) {
if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!");
if(!this.hasLoadedEvent()) throw new ApplianceCommand.Error("There is no event selected!");
this.durationMinutes = durationMinutes;
this.countdown.start();
}
public void cancelStart() {
this.countdown.cancel();
if(this.countdown.isRunning()) this.countdown.cancel();
}
private Component format(Countdown.AnnouncementData data) {
@@ -154,7 +159,10 @@ public class EventController extends Appliance {
Bukkit.getScheduler().runTaskLater(
Main.instance(),
() -> Bukkit.getOnlinePlayers().forEach(player -> PluginMessage.connect(player, "craftattack")),
() -> {
Bukkit.getOnlinePlayers().forEach(player -> PluginMessage.connect(player, "craftattack"));
this.unloadEvent();
},
Ticks.TICKS_PER_SECOND * 7
);
}
@@ -181,6 +189,13 @@ public class EventController extends Appliance {
return String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
}
@Override
protected @NotNull List<Listener> listeners() {
return List.of(
new EventPlayerLoginListener()
);
}
@Override
protected @NotNull List<ApplianceCommand<?>> commands() {
return List.of(

View File

@@ -0,0 +1,15 @@
package eu.mhsl.craftattack.spawn.event.appliances.eventController;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener;
import net.kyori.adventure.text.Component;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerJoinEvent;
public class EventPlayerLoginListener extends ApplianceListener<EventController> {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if(event.getPlayer().isOp()) return;
if(this.getAppliance().hasLoadedEvent()) return;
event.getPlayer().kick(Component.text("Es ist kein Event geladen."));
}
}

View File

@@ -53,9 +53,6 @@ public class EventScoreboardBuilder {
objective.numberFormat(NumberFormat.blank());
UUID uuid = p.getUniqueId();
scoreList.removeIf(e -> e.playerUuid().equals(uuid));
scoreList.add(new EventScoreEntry(uuid, p.getName(), this.scorable.getScore(p)));
scoreList.sort(this.scoreComparator);
int size = scoreList.size();
@@ -140,8 +137,19 @@ public class EventScoreboardBuilder {
}
private void updateScore(Player p) {
this.playerScores.removeIf(entry -> entry.playerUuid().equals(p.getUniqueId()));
EventScoreEntry previousEntry = this.playerScores.stream()
.filter(entry -> entry.playerUuid().equals(p.getUniqueId()))
.findFirst()
.orElse(null);
if(previousEntry == null) {
this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.scorable.getScore(p)));
return;
}
int currentScore = this.scorable.getScore(p);
if(previousEntry.score() < currentScore) {
this.playerScores.removeIf(entry -> entry.playerUuid().equals(p.getUniqueId()));
this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), currentScore));
}
}
public void updateScoreboards() {