Compare commits

..
Author SHA1 Message Date
Michał Wojtas 520196417b Use already defined versions of plugins in runServer script
Signed-off-by: Michał Wojtas <wojtas.michal90@gmail.com>
2026-06-21 12:17:23 +02:00
46 changed files with 91 additions and 786 deletions

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: '25'
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '25'
java-version: '21'
distribution: 'temurin'
- name: Setup Gradle
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
- name: Set up JDK 21
uses: actions/setup-java@v5
with:
java-version: '25'
java-version: '21'
distribution: 'temurin'
- name: Setup Gradle
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 25
java-version: 17
cache: 'gradle'
- name: Grant execute permission for gradlew
+7 -11
View File
@@ -25,7 +25,7 @@
## EternalCombat requires PacketEvents plugin to work.
You can download it from [here](https://modrinth.com/plugin/packetevents)
EternalCombat 2.0 has been tested on Minecraft versions **1.17.1 to 26.2**, but it should work seamlessly on most
EternalCombat 2.0 has been tested on Minecraft versions **1.17.1 to 26.1.2**, but it should work seamlessly on most
other versions too.
If you run into any compatibility issues, please let us know in
the [Issues tab](https://github.com/EternalCodeTeam/EternalCombat/issues).
@@ -45,13 +45,9 @@ fair, heart-pounding battles that keep players on their toes. Here’s a rundown
in action:
<img alt="Combat log anti logout feature" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/combatlog.gif?raw=true" width="420">
- **Support for newest features**
Our plugin features cooldown and delays for tridents, spears and much more. With **out of the box** configurable feats.
<img alt="Trident and spear cooldown feature" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/spear.gif?raw=true" width="420">
- **Customize combat experience**
Add custom effects to players in combat or death. Everything should be configurable and user-friendly:
<img alt="Lightning strikes when players die" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/lightning.gif?raw=true" width="420">
- **Customize combat experience**
Add custom effects to players in combat or death. Everything should be configurable and user-friendly:
<img alt="Lightning strikes when players die" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/lightning.gif?raw=true" width="420">
<img alt="Flare indicates players death location" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/flare.gif?raw=true" width="420">
- **Spawn Protection (Configurable)**
@@ -61,7 +57,7 @@ fair, heart-pounding battles that keep players on their toes. Here’s a rundown
- **Crystal PvP support**
Engage in intense Crystal PvP battles without worrying about players logging out mid-fight! EternalCombat keeps
everyone in the game until the last anchor hit. Check it out:
everyone in the game until the last anchor hit. Check it out:
<img alt="Crystal PvP showcase" src="https://github.com/EternalCodeTeam/EternalCombat/blob/master/assets/crystals.gif?raw=true" width="420">
- **Fully Customizable Combat**
@@ -143,7 +139,7 @@ With Maven:
With Gradle:
```kts
compileOnly("com.eternalcode:eternalcombat-api:2.6.0-SNAPSHOT")
compileOnly("com.eternalcode:eternalcombat-api:2.5.2-SNAPSHOT")
```
With Maven:
@@ -153,7 +149,7 @@ With Maven:
<dependency>
<groupId>com.eternalcode</groupId>
<artifactId>eternalcombat-api</artifactId>
<version>2.6.0-SNAPSHOT</version>
<version>2.5.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
```
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 MiB

+4 -4
View File
@@ -8,12 +8,12 @@ repositories {
}
dependencies {
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.6.1")
implementation("com.modrinth.minotaur:com.modrinth.minotaur.gradle.plugin:2.10.0")
implementation("com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.4.2")
implementation("com.modrinth.minotaur:com.modrinth.minotaur.gradle.plugin:2.9.0")
implementation("io.papermc.hangar-publish-plugin:io.papermc.hangar-publish-plugin.gradle.plugin:0.1.4")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.4.20")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.4.0")
implementation("net.minecrell:plugin-yml:0.6.0")
implementation("xyz.jpenilla:run-task:3.1.0")
implementation("xyz.jpenilla:run-task:3.0.2")
}
sourceSets {
+12 -9
View File
@@ -3,15 +3,15 @@ object Versions {
// Keep this version for best compatibility.
const val PAPER_API = "1.19.3-R0.1-SNAPSHOT"
const val JUNIT_JUPITER_API = "6.1.3"
const val JUNIT_JUPITER_PARAMS = "6.1.3"
const val JUNIT_JUPITER_ENGINE = "6.1.3"
const val JUNIT_JUPITER_API = "6.1.0"
const val JUNIT_JUPITER_PARAMS = "6.1.0"
const val JUNIT_JUPITER_ENGINE = "6.1.0"
const val JETBRAINS_ANNOTATIONS = "26.1.0"
const val ETERNALCODE_COMMONS = "1.4.1"
const val MULTIFICATION = "1.2.5-SNAPSHOT"
const val PACKETS_EVENTS = "2.13.0"
const val PACKETS_EVENTS = "2.12.2"
const val LITE_COMMANDS = "3.11.0"
const val OKAERI_CONFIGS_SERDES_COMMONS = "5.0.13"
@@ -19,16 +19,19 @@ object Versions {
const val XSERIES = "13.8.0"
const val CAFFEINE = "3.3.0"
const val CAFFEINE = "3.2.4"
const val B_STATS_BUKKIT = "3.2.1"
const val WORLD_GUARD_BUKKIT = "7.0.17"
const val PLACEHOLDER_API = "2.12.3"
const val PLACEHOLDER_API = "2.12.2"
const val LANDS_API = "7.25.4"
const val GRIEF_PREVENTION = "16.18.7"
const val WORLDEDIT = "3ISh7ADm" //cannot use numeric version bc of duplicated version on modrinth
const val PACKETEVENTS = "2.14.0"
//runServer task
const val FAST_ASYNC_WORLD_EDIT = "2.15.2"
const val PACKETEVENTS = "2.12.2+spigot"
const val WORLDGUARD = "7.0.17"
const val LUCKPERMS = "v5.5.53-bukkit"
}
@@ -3,7 +3,7 @@ plugins {
}
group = "com.eternalcode"
version = "2.6.0-SNAPSHOT"
version = "2.5.2-SNAPSHOT"
tasks.compileJava {
options.compilerArgs = listOf("-Xlint:deprecation", "-parameters")
@@ -4,7 +4,7 @@ plugins {
}
group = "com.eternalcode"
version = "2.6.0-SNAPSHOT"
version = "2.5.2-SNAPSHOT"
java {
withSourcesJar()
@@ -13,11 +13,10 @@ tasks {
languageVersion.set(JavaLanguageVersion.of(25))
})
minecraftVersion("26.3")
downloadPlugins.modrinth("WorldEdit", "7.4.6")
downloadPlugins.modrinth("PacketEvents", "2.14.0+spigot")
downloadPlugins.modrinth("WorldGuard", "7.0.20")
downloadPlugins.modrinth("LuckPerms", "v5.5.53-bukkit")
downloadPlugins.modrinth("GriefPrevention", Versions.GRIEF_PREVENTION)
minecraftVersion("26.1.2")
downloadPlugins.modrinth("FastAsyncWorldEdit", Versions.FAST_ASYNC_WORLD_EDIT)
downloadPlugins.modrinth("PacketEvents", Versions.PACKETEVENTS)
downloadPlugins.modrinth("WorldGuard", Versions.WORLDGUARD)
downloadPlugins.modrinth("LuckPerms", Versions.LUCKPERMS)
}
}
@@ -34,11 +34,6 @@ public enum CauseOfTag {
ENDER_PEARL,
/**
* The player's combat tag was kept active because they were below the void combat height.
*/
VOID,
/**
* A custom cause, typically defined by external plugins or systems, applied the combat tag.
*/
@@ -5,9 +5,7 @@ import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import java.util.UUID;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* This event is triggered when a player is tagged in a fight.
@@ -17,25 +15,14 @@ public class FightTagEvent extends Event implements Cancellable {
private static final HandlerList HANDLER_LIST = new HandlerList();
private final UUID player;
private final CauseOfTag cause;
private final UUID tagger;
private boolean cancelled = false;
private CancelTagReason cancelReason;
/**
* @deprecated use {@link #FightTagEvent(UUID, CauseOfTag, UUID)} instead, which also carries the tagger.
*/
@Deprecated
@ApiStatus.ScheduledForRemoval
public FightTagEvent(UUID player, CauseOfTag cause) {
this(player, cause, null);
}
public FightTagEvent(UUID player, CauseOfTag cause, @Nullable UUID tagger) {
super(false);
this.player = player;
this.cause = cause;
this.tagger = tagger;
}
/**
@@ -56,16 +43,6 @@ public class FightTagEvent extends Event implements Cancellable {
return this.cause;
}
/**
* Gets the UUID of the player who caused this tag, if any.
*
* @return The UUID of the tagger, or {@code null} if the tag was not caused by another player.
*/
@Nullable
public UUID getTagger() {
return this.tagger;
}
@Override
public boolean isCancelled() {
return this.cancelled;
@@ -1,11 +0,0 @@
package com.eternalcode.combat.fight.spear;
import java.time.Duration;
import java.util.UUID;
public interface SpearService {
boolean isOnCooldown(UUID player);
void saveCooldown(UUID player);
Duration getRemainingCooldown(UUID player);
void removeCooldown(UUID player);
}
-16
View File
@@ -62,11 +62,6 @@ dependencies {
// Lands
compileOnly("com.github.angeschossen:LandsAPI:${Versions.LANDS_API}")
// GriefPrevention
compileOnly("com.github.GriefPrevention:GriefPrevention:${Versions.GRIEF_PREVENTION}") {
isTransitive = false
}
// Multification
implementation("com.eternalcode:multification-paper:${Versions.MULTIFICATION}")
implementation("com.eternalcode:multification-okaeri:${Versions.MULTIFICATION}")
@@ -101,11 +96,6 @@ paper {
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
}
register("GriefPrevention") {
required = false
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
}
register("PlaceholderAPI") {
required = false
load = PaperPluginDescription.RelativeLoadOrder.BEFORE
@@ -117,12 +107,6 @@ tasks {
named("generatePaperPluginDescription") {
notCompatibleWithConfigurationCache("The plugin-yml paper generator reads Task.project during execution.")
}
runPaper.folia.registerTask {
minecraftVersion("26.3")
downloadPlugins.modrinth("PacketEvents", "${Versions.PACKETEVENTS}+spigot")
}
}
tasks.shadowJar {
@@ -8,8 +8,8 @@ import com.eternalcode.combat.border.animation.particle.ParticleController;
import com.eternalcode.combat.bridge.BridgeService;
import com.eternalcode.combat.config.ConfigService;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.crystalpvp.EndCrystalController;
import com.eternalcode.combat.fight.crystalpvp.RespawnAnchorController;
import com.eternalcode.combat.crystalpvp.EndCrystalListener;
import com.eternalcode.combat.crystalpvp.RespawnAnchorListener;
import com.eternalcode.combat.event.EventManager;
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.fight.FightManagerImpl;
@@ -36,12 +36,10 @@ import com.eternalcode.combat.fight.drop.DropServiceImpl;
import com.eternalcode.combat.fight.drop.impl.PercentDropModifier;
import com.eternalcode.combat.fight.drop.impl.PlayersHealthDropModifier;
import com.eternalcode.combat.fight.blocker.PlaceBlockBlocker;
import com.eternalcode.combat.fight.blocker.SignEditingBlocker;
import com.eternalcode.combat.fight.effect.FightEffectController;
import com.eternalcode.combat.fight.effect.FightEffectService;
import com.eternalcode.combat.fight.effect.FightEffectServiceImpl;
import com.eternalcode.combat.fight.firework.FireworkController;
import com.eternalcode.combat.fight.knockback.KnockbackMountController;
import com.eternalcode.combat.fight.knockback.KnockbackRegionController;
import com.eternalcode.combat.fight.knockback.KnockbackService;
import com.eternalcode.combat.fight.logout.LogoutController;
@@ -49,9 +47,6 @@ import com.eternalcode.combat.fight.logout.LogoutService;
import com.eternalcode.combat.fight.pearl.PearlController;
import com.eternalcode.combat.fight.pearl.PearlService;
import com.eternalcode.combat.fight.pearl.PearlServiceImpl;
import com.eternalcode.combat.fight.spear.SpearLungeController;
import com.eternalcode.combat.fight.spear.SpearService;
import com.eternalcode.combat.fight.spear.SpearServiceImpl;
import com.eternalcode.combat.fight.tagout.FightTagOutCommand;
import com.eternalcode.combat.fight.tagout.FightTagOutController;
import com.eternalcode.combat.fight.tagout.FightTagOutService;
@@ -154,8 +149,6 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
BorderService borderService = new BorderServiceImpl(scheduler, server, regionProvider, eventManager, () -> pluginConfig.border);
KnockbackService knockbackService = new KnockbackService(pluginConfig, scheduler, regionProvider);
SpearService spearService = new SpearServiceImpl(pluginConfig.spear);
this.liteCommands = LiteBukkitFactory.builder(FALLBACK_PREFIX, this, server)
.message(LiteBukkitMessages.PLAYER_NOT_FOUND, pluginConfig.messagesSettings.playerNotFound)
.message(LiteBukkitMessages.PLAYER_ONLY, pluginConfig.messagesSettings.admin.onlyForPlayers)
@@ -207,11 +200,10 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
new BorderTriggerController(borderService, () -> pluginConfig.border, fightManager, server, scheduler),
new ParticleController(borderService, () -> pluginConfig.border.particle, scheduler, server),
new BorderBlockController(borderService, () -> pluginConfig.border.block, scheduler, server),
new EndCrystalController(this, this.fightManager, pluginConfig),
new RespawnAnchorController(this, this.fightManager, pluginConfig),
new EndCrystalListener(this, this.fightManager, pluginConfig),
new RespawnAnchorListener(this, this.fightManager, pluginConfig),
new FireworkController(this.fightManager, pluginConfig, noticeService),
new InventoryContainersBlocker(this.fightManager, pluginConfig, noticeService),
new SignEditingBlocker(this.fightManager, pluginConfig),
new CommandsBlocker(this.fightManager, noticeService, pluginConfig),
new ElytraBlocker(this.fightManager, pluginConfig),
new ElytraEquipBlocker(this.fightManager, noticeService, pluginConfig, server),
@@ -219,10 +211,6 @@ public final class CombatPlugin extends JavaPlugin implements EternalCombatApi {
new PlaceBlockBlocker(this.fightManager, noticeService, pluginConfig)
);
new KnockbackMountController(noticeService, this.regionProvider, this.fightManager).register(this);
new SpearLungeController(this, fightManager, spearService, pluginConfig, noticeService);
eventManager.subscribe(
PlayerDeathEvent.class,
pluginConfig.drop.dropEventPriority,
@@ -8,6 +8,8 @@ import org.bukkit.plugin.Plugin;
public final class CombatSchedulerAdapter {
private static final String FOLIA_CLASS = "io.papermc.paper.threadedregions.RegionizedServer";
private CombatSchedulerAdapter() {
throw new UnsupportedOperationException("This is an utility class and cannot be instantiated");
}
@@ -15,12 +17,14 @@ public final class CombatSchedulerAdapter {
public static MinecraftScheduler getAdaptiveScheduler(Plugin plugin) {
Logger logger = plugin.getLogger();
if (FoliaChecker.isFolia()) {
try {
Class.forName(FOLIA_CLASS);
logger.info("» Detected Folia environment. Using FoliaScheduler.");
return new FoliaSchedulerImpl(plugin);
}
logger.info("» Detected Bukkit/Paper environment. Using BukkitScheduler.");
return new BukkitSchedulerImpl(plugin);
catch (ClassNotFoundException exception) {
logger.info("» Detected Bukkit/Paper environment. Using BukkitScheduler.");
return new BukkitSchedulerImpl(plugin);
}
}
}
@@ -1,25 +0,0 @@
package com.eternalcode.combat;
public final class FoliaChecker {
private static final String FOLIA_CLASS = "io.papermc.paper.threadedregions.RegionizedServer";
private static final boolean IS_FOLIA = detectFoliaEnvironment();
private FoliaChecker() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
public static boolean isFolia() {
return IS_FOLIA;
}
private static boolean detectFoliaEnvironment() {
try {
Class.forName(FOLIA_CLASS);
return true;
}
catch (ClassNotFoundException exception) {
return false;
}
}
}
@@ -7,7 +7,6 @@ import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.region.CompositeRegionProvider;
import com.eternalcode.combat.region.bukkit.DefaultRegionProvider;
import com.eternalcode.combat.region.RegionProvider;
import com.eternalcode.combat.region.griefprevention.GriefPreventionRegionProvider;
import com.eternalcode.combat.region.worldguard.WorldGuardRegionProvider;
import java.util.ArrayList;
import java.util.List;
@@ -56,12 +55,6 @@ public class BridgeService {
() -> this.logger.warning("WorldGuard not found; skipping WorldGuardRegionProvider.")
);
this.initialize(
"GriefPrevention",
() -> providers.add(new GriefPreventionRegionProvider(this.config)),
() -> this.logger.warning("GriefPrevention not found; skipping GriefPreventionRegionProvider.")
);
if (providers.isEmpty()) {
providers.add(new DefaultRegionProvider(this.config.regions.restrictedRegionRadius));
this.logger.warning("No region plugin found; using DefaultRegionProvider.");
@@ -90,19 +90,6 @@ public class CombatSettings extends OkaeriConfig {
})
public EventPriority quitPunishmentEventPriority = EventPriority.NORMAL;
@Comment({
"# Keep a player's combat tag continuously active while they are below 'voidCombatHeight'.",
"# This prevents players from evading combat by falling into the void (e.g. in the End).",
"# Set to 'true' to keep resetting the combat timer to its full duration while below that height."
})
public boolean keepCombatActiveInVoid = false;
@Comment({
"# The Y height below which the combat timer is kept active (see 'keepCombatActiveInVoid').",
"# Default: 0, matching the void threshold in worlds such as the End."
})
public double voidCombatHeight = 0;
@Comment({
"# List of kick reasons where players will NOT be punished for combat logging.",
"# If this list is empty, players are ALWAYS punished when kicked during combat.",
@@ -50,12 +50,10 @@ public class MessagesSettings extends OkaeriConfig {
@Comment({
"# Message displayed when a player enters combat.",
"# This message warns the player not to leave the server while in combat.",
"# The {OPPONENT} placeholder is replaced with the name of the player who caused the tag,",
"# or the 'unknownPlayerPlaceholder' variable if the tag was not caused by a player."
"# This message warns the player not to leave the server while in combat."
})
public Notice playerTagged = Notice.chat(
"<gradient:red:yellow>⚠ <white>You are in combat with</white> <yellow>{OPPONENT}</yellow>! <u>Do not leave the server!</gradient>");
"<gradient:red:yellow>⚠ <white>You are in combat!</white> <u>Do not leave the server!</gradient>");
@Comment({
"# Message displayed when a player leaves combat.",
@@ -6,7 +6,6 @@ import com.eternalcode.combat.fight.drop.DropSettings;
import com.eternalcode.combat.fight.effect.FightEffectSettings;
import com.eternalcode.combat.fight.knockback.KnockbackSettings;
import com.eternalcode.combat.fight.pearl.PearlSettings;
import com.eternalcode.combat.fight.spear.SpearSettings;
import com.eternalcode.combat.fight.trident.TridentSettings;
import eu.okaeri.configs.OkaeriConfig;
import eu.okaeri.configs.annotation.Comment;
@@ -45,13 +44,6 @@ public class PluginConfig extends OkaeriConfig {
})
public TridentSettings trident = new TridentSettings();
@Comment({
" ",
"# Settings related to Spears with lunge",
"# Set cooldown for spear lunging"
})
public SpearSettings spear = new SpearSettings();
@Comment({
" ",
"# Custom effects applied during combat.",
@@ -135,13 +127,6 @@ public class PluginConfig extends OkaeriConfig {
})
public InventorySettings inventory = new InventorySettings();
@Comment({
" ",
"# Settings related to sign editing during combat.",
"# Created for sign traps where opening the sign editor can block ender pearl throws."
})
public SignEditingSettings signEditing = new SignEditingSettings();
@Comment({
" ",
"# Settings related to placeholders used in the plugin.",
@@ -13,8 +13,7 @@ public class RegionSettings extends OkaeriConfig {
public List<String> blockedRegions = Collections.singletonList("your_region");
@Comment({
"# Prevent players from entering regions where PVP is disabled by the region plugin",
"# (WorldGuard PVP flag, GriefPrevention no-combat-in-claims settings).",
"# Prevent players from entering regions where PVP is disabled by WorldGuard.",
"# Set to 'true' to enforce this restriction, or 'false' to allow PVP in all regions."
})
public boolean preventPvpInRegions = true;
@@ -1,13 +0,0 @@
package com.eternalcode.combat.config.implementation;
import eu.okaeri.configs.OkaeriConfig;
import eu.okaeri.configs.annotation.Comment;
public class SignEditingSettings extends OkaeriConfig {
@Comment({
"# Prevent players from editing signs during combat.",
"# Disabled by default; created for sign traps where sign editing blocks ender pearl throws."
})
public boolean disableSignEditingDuringCombat = false;
}
@@ -1,4 +1,4 @@
package com.eternalcode.combat.fight.crystalpvp;
package com.eternalcode.combat.crystalpvp;
import java.util.Optional;
import java.util.UUID;
@@ -1,4 +1,4 @@
package com.eternalcode.combat.fight.crystalpvp;
package com.eternalcode.combat.crystalpvp;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
@@ -66,14 +66,12 @@ public class CrystalPvpConstants {
fightManager.tag(
damagerUniqueId,
pluginConfig.settings.combatTimerDuration,
CauseOfTag.CRYSTAL,
victimUniqueId
CauseOfTag.CRYSTAL
);
fightManager.tag(
victimUniqueId,
pluginConfig.settings.combatTimerDuration,
CauseOfTag.CRYSTAL,
damagerUniqueId
CauseOfTag.CRYSTAL
);
}
}
@@ -1,4 +1,4 @@
package com.eternalcode.combat.fight.crystalpvp;
package com.eternalcode.combat.crystalpvp;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
@@ -12,15 +12,15 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.plugin.Plugin;
import static com.eternalcode.combat.fight.crystalpvp.CrystalPvpConstants.CRYSTAL_METADATA;
import static com.eternalcode.combat.crystalpvp.CrystalPvpConstants.CRYSTAL_METADATA;
public class EndCrystalController implements Listener {
public class EndCrystalListener implements Listener {
private final Plugin plugin;
private final FightManager fightManager;
private final PluginConfig pluginConfig;
public EndCrystalController(Plugin plugin, FightManager fightManager, PluginConfig pluginConfig) {
public EndCrystalListener(Plugin plugin, FightManager fightManager, PluginConfig pluginConfig) {
this.plugin = plugin;
this.fightManager = fightManager;
this.pluginConfig = pluginConfig;
@@ -1,4 +1,4 @@
package com.eternalcode.combat.fight.crystalpvp;
package com.eternalcode.combat.crystalpvp;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
@@ -16,16 +16,16 @@ import org.bukkit.event.entity.EntityDamageByBlockEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import static com.eternalcode.combat.fight.crystalpvp.CrystalPvpConstants.ANCHOR_METADATA;
import static com.eternalcode.combat.crystalpvp.CrystalPvpConstants.ANCHOR_METADATA;
public class RespawnAnchorController implements Listener {
public class RespawnAnchorListener implements Listener {
private final Plugin plugin;
private final FightManager fightManager;
private final PluginConfig pluginConfig;
public RespawnAnchorController(Plugin plugin, FightManager fightManager, PluginConfig pluginConfig) {
public RespawnAnchorListener(Plugin plugin, FightManager fightManager, PluginConfig pluginConfig) {
this.plugin = plugin;
this.fightManager = fightManager;
this.pluginConfig = pluginConfig;
@@ -55,7 +55,7 @@ public class FightManagerImpl implements FightManager {
@ApiStatus.Experimental
@Override
public FightTagEvent tag(UUID target, Duration delay, CauseOfTag causeOfTag, @Nullable UUID tagger) {
FightTagEvent event = this.eventManager.publishEvent(new FightTagEvent(target, causeOfTag, tagger));
FightTagEvent event = this.eventManager.publishEvent(new FightTagEvent(target, causeOfTag));
if (event.isCancelled()) {
return event;
@@ -1,9 +1,7 @@
package com.eternalcode.combat.fight;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.event.CauseOfTag;
import com.eternalcode.combat.fight.event.CauseOfUnTag;
import com.eternalcode.combat.fight.event.FightTagEvent;
import com.eternalcode.combat.notification.NoticeService;
import com.eternalcode.combat.util.DurationUtil;
import java.util.Optional;
@@ -43,16 +41,6 @@ public class FightTask implements Runnable {
return;
}
if (this.config.combat.keepCombatActiveInVoid
&& player.getLocation().getY() < this.config.combat.voidCombatHeight
&& !this.config.settings.ignoredWorlds.contains(player.getWorld().getName())) {
FightTagEvent tagEvent = this.fightManager.tag(playerUniqueId, this.config.settings.combatTimerDuration, CauseOfTag.VOID, fightTag.getTagger());
if (!tagEvent.isCancelled()) {
fightTag = this.fightManager.getTag(playerUniqueId);
}
}
Duration remaining = fightTag.getRemainingDuration();
String opponent = Optional.ofNullable(fightTag.getTagger())
@@ -1,63 +0,0 @@
package com.eternalcode.combat.fight.blocker;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
import java.util.UUID;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Event.Result;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
public class SignEditingBlocker implements Listener {
private final FightManager fightManager;
private final PluginConfig config;
public SignEditingBlocker(FightManager fightManager, PluginConfig config) {
this.fightManager = fightManager;
this.config = config;
}
@EventHandler(ignoreCancelled = true)
void onInteract(PlayerInteractEvent event) {
if (!this.config.signEditing.disableSignEditingDuringCombat) {
return;
}
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) {
return;
}
Block clickedBlock = event.getClickedBlock();
if (clickedBlock == null || !isSign(clickedBlock.getType())) {
return;
}
Player player = event.getPlayer();
UUID uniqueId = player.getUniqueId();
if (!this.fightManager.isInCombat(uniqueId)) {
return;
}
event.setUseInteractedBlock(Result.DENY);
ItemStack item = event.getItem();
if (item != null && isEnderPearl(item.getType()) && event.useItemInHand() != Result.DENY) {
event.setUseItemInHand(Result.ALLOW);
}
}
static boolean isSign(Material material) {
return material.name().endsWith("_SIGN");
}
static boolean isEnderPearl(Material material) {
return material == Material.ENDER_PEARL;
}
}
@@ -5,8 +5,6 @@ import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.fight.event.FightTagEvent;
import com.eternalcode.combat.fight.event.FightUntagEvent;
import com.eternalcode.combat.notification.NoticeService;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -39,23 +37,12 @@ public class FightMessageController implements Listener {
return;
}
String opponent = this.resolveOpponentName(event.getTagger(), player.getUniqueId());
this.noticeService.create()
.player(player.getUniqueId())
.notice(this.config.messagesSettings.playerTagged)
.placeholder("{OPPONENT}", opponent)
.send();
}
private String resolveOpponentName(UUID tagger, UUID taggedPlayer) {
return Optional.ofNullable(tagger)
.filter(uuid -> !uuid.equals(taggedPlayer))
.map(this.server::getPlayer)
.map(Player::getName)
.orElse(this.config.messagesSettings.unknownPlayerPlaceholder);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
void onUnTag(FightUntagEvent event) {
Player player = this.server.getPlayer(event.getPlayer());
@@ -1,6 +1,5 @@
package com.eternalcode.combat.fight.controller;
import com.eternalcode.combat.FoliaChecker;
import com.eternalcode.combat.WhitelistBlacklistMode;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
@@ -56,16 +55,6 @@ public class FightTagController implements Listener {
return;
}
UUID targetId = attackedPlayerByPerson.getUniqueId();
UUID attackerId = attacker.getUniqueId();
if (
targetId.equals(attackerId)
&& FoliaChecker.isFolia()
) {
return;
}
if (this.config.combat.disableFlying) {
if (attackedPlayerByPerson.isFlying()) {
attackedPlayerByPerson.setFlying(false);
@@ -79,9 +68,11 @@ public class FightTagController implements Listener {
}
Duration combatTime = this.config.settings.combatTimerDuration;
UUID attackedUniqueId = attackedPlayerByPerson.getUniqueId();
UUID attackerUniqueId = attacker.getUniqueId();
this.fightManager.tag(targetId, combatTime, CauseOfTag.PLAYER, attackerId);
this.fightManager.tag(attackerId, combatTime, CauseOfTag.PLAYER, targetId);
this.fightManager.tag(attackedUniqueId, combatTime, CauseOfTag.PLAYER, attackerUniqueId);
this.fightManager.tag(attackerUniqueId, combatTime, CauseOfTag.PLAYER, attackedUniqueId);
}
@@ -1,6 +1,6 @@
package com.eternalcode.combat.fight.controller;
import com.eternalcode.combat.fight.crystalpvp.CrystalPvpConstants;
import com.eternalcode.combat.crystalpvp.CrystalPvpConstants;
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.fight.event.CauseOfUnTag;
import com.eternalcode.combat.config.implementation.PluginConfig;
@@ -1,129 +0,0 @@
package com.eternalcode.combat.fight.knockback;
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.notification.NoticeService;
import com.eternalcode.combat.region.RegionProvider;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.plugin.Plugin;
// EntityMountEvent moved between org.spigotmc, io.papermc.paper and org.bukkit across versions,
// so we resolve it at runtime to stay compatible without bumping the compile API.
public final class KnockbackMountController implements Listener {
private static final String[] EVENT_CLASS_CANDIDATES = {
"org.bukkit.event.entity.EntityMountEvent",
"io.papermc.paper.event.entity.EntityMountEvent",
"org.spigotmc.event.entity.EntityMountEvent",
};
private final NoticeService noticeService;
private final RegionProvider regionProvider;
private final FightManager fightManager;
private final AtomicBoolean mountFailureLogged = new AtomicBoolean();
public KnockbackMountController(NoticeService noticeService, RegionProvider regionProvider, FightManager fightManager) {
this.noticeService = noticeService;
this.regionProvider = regionProvider;
this.fightManager = fightManager;
}
public void register(Plugin plugin) {
Class<? extends Event> eventClass = null;
for (String candidate : EVENT_CLASS_CANDIDATES) {
try {
eventClass = Class.forName(candidate).asSubclass(Event.class);
break;
} catch (ClassNotFoundException | ClassCastException ignored) {
}
}
if (eventClass == null) {
plugin.getLogger().warning("Could not find any EntityMountEvent class; mount protection in regions is disabled.");
return;
}
MethodHandle getMountHandle;
try {
getMountHandle = this.resolveGetMountHandle(eventClass);
} catch (NoSuchMethodException | IllegalAccessException exception) {
plugin.getLogger().log(Level.WARNING, "EntityMountEvent has incompatible getMount() method; mount protection in regions is disabled.", exception);
return;
}
plugin.getServer().getPluginManager().registerEvent(
eventClass,
this,
EventPriority.HIGHEST,
(listener, event) -> this.handle(event, getMountHandle, plugin),
plugin,
true
);
}
private MethodHandle resolveGetMountHandle(Class<? extends Event> eventClass) throws NoSuchMethodException, IllegalAccessException {
if (!EntityEvent.class.isAssignableFrom(eventClass) || !Cancellable.class.isAssignableFrom(eventClass)) {
throw new NoSuchMethodException(eventClass.getName() + " is not a cancellable entity event");
}
Method getMount = eventClass.getMethod("getMount");
if (!Entity.class.isAssignableFrom(getMount.getReturnType())) {
throw new NoSuchMethodException(eventClass.getName() + "#getMount() does not return Entity");
}
return MethodHandles.publicLookup()
.unreflect(getMount)
.asType(MethodType.methodType(Entity.class, Event.class));
}
private void handle(Event event, MethodHandle getMountHandle, Plugin plugin) {
if (!(event instanceof EntityEvent entityEvent) || !(event instanceof Cancellable cancellable)) {
return;
}
if (!(entityEvent.getEntity() instanceof Player player)) {
return;
}
if (!this.fightManager.isInCombat(player.getUniqueId())) {
return;
}
Entity mount;
try {
mount = (Entity) getMountHandle.invokeExact(event);
} catch (Throwable exception) {
this.logMountFailure(plugin, exception);
return;
}
if (mount == null || !this.regionProvider.isInRegion(mount.getLocation())) {
return;
}
cancellable.setCancelled(true);
this.noticeService.create()
.player(player.getUniqueId())
.notice(config -> config.messagesSettings.cantEnterOnRegion)
.send();
}
private void logMountFailure(Plugin plugin, Throwable exception) {
if (!this.mountFailureLogged.compareAndSet(false, true)) {
return;
}
plugin.getLogger().log(Level.WARNING, "Could not read EntityMountEvent mount; mount protection in regions is skipped.", exception);
}
}
@@ -17,6 +17,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.vehicle.VehicleMoveEvent;
import org.spigotmc.event.entity.EntityMountEvent;
public class KnockbackRegionController implements Listener {
@@ -131,6 +132,27 @@ public class KnockbackRegionController implements Listener {
}
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
void onEntityMount(EntityMountEvent event) {
if (!(event.getEntity() instanceof Player player)) {
return;
}
if (!this.fightManager.isInCombat(player.getUniqueId())) {
return;
}
if (!this.regionProvider.isInRegion(event.getMount().getLocation())) {
return;
}
event.setCancelled(true);
this.noticeService.create()
.player(player.getUniqueId())
.notice(config -> config.messagesSettings.cantEnterOnRegion)
.send();
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
void onTag(FightTagEvent event) {
Player player = this.server.getPlayer(event.getPlayer());
@@ -1,93 +0,0 @@
package com.eternalcode.combat.fight.spear;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.fight.FightManager;
import com.eternalcode.combat.notification.NoticeService;
import com.eternalcode.combat.util.DurationUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.UUID;
public class SpearLungeController implements Listener {
private final SpearService spearService;
public SpearLungeController(
Plugin plugin,
FightManager fightManager,
SpearService spearService,
PluginConfig config,
NoticeService noticeService
) {
this.spearService = spearService;
try {
Class<? extends Event> lungeEventClass = Class.forName("io.papermc.paper.event.entity.EntityLungeEvent").asSubclass(Event.class);
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle getEntityHandle = lookup.findVirtual(lungeEventClass, "getEntity", MethodType.methodType(Entity.class));
MethodHandle setCancelledHandle = lookup.findVirtual(lungeEventClass, "setCancelled", MethodType.methodType(void.class, boolean.class));
Bukkit.getPluginManager().registerEvent(
lungeEventClass,
this,
EventPriority.NORMAL,
(listener, event) -> {
if (!config.spear.lungeCooldown || !lungeEventClass.isInstance(event)) {
return;
}
try {
Entity entity = (Entity) getEntityHandle.invoke(event);
if (!(entity instanceof Player player)) {
return;
}
UUID playerId = player.getUniqueId();
if (config.spear.onlyForFight && !fightManager.isInCombat(playerId)) {
return;
}
if (this.spearService.isOnCooldown(playerId)) {
setCancelledHandle.invoke(event, true);
noticeService.create()
.player(playerId)
.notice(config.spear.lungeOnCooldown)
.placeholder("{TIME}", DurationUtil.format(spearService.getRemainingCooldown(playerId), !config.spear.useMillis))
.send();
return;
}
spearService.saveCooldown(playerId);
} catch (Throwable e) {
plugin.getLogger().warning("Failed to handle EntityLungeEvent: " + e.getMessage());
}
},
plugin
);
} catch (ClassNotFoundException e) {
// Silently ignore: Server version is too old to have EntityLungeEvent
} catch (Throwable e) {
plugin.getLogger().warning("Failed to hook EntityLungeEvent: " + e.getMessage());
}
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
this.spearService.removeCooldown(event.getPlayer().getUniqueId());
}
}
@@ -1,49 +0,0 @@
package com.eternalcode.combat.fight.spear;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class SpearServiceImpl implements SpearService {
private final SpearSettings settings;
private final Map<UUID, Instant> cooldowns = new ConcurrentHashMap<>();
public SpearServiceImpl(SpearSettings settings) {
this.settings = settings;
}
@Override
public boolean isOnCooldown(UUID uuid) {
return !this.getRemainingCooldown(uuid).isZero();
}
@Override
public void saveCooldown(UUID uuid) {
this.cooldowns.put(uuid, Instant.now().plus(this.settings.lungeCooldownDuration));
}
@Override
public Duration getRemainingCooldown(UUID uuid) {
Instant expiration = this.cooldowns.get(uuid);
if (expiration == null) {
return Duration.ZERO;
}
Instant now = Instant.now();
if (now.isAfter(expiration)) {
this.cooldowns.remove(uuid);
return Duration.ZERO;
}
return Duration.between(now, expiration);
}
@Override
public void removeCooldown(UUID uuid) {
this.cooldowns.remove(uuid);
}
}
@@ -1,30 +0,0 @@
package com.eternalcode.combat.fight.spear;
import com.eternalcode.multification.notice.Notice;
import eu.okaeri.configs.OkaeriConfig;
import eu.okaeri.configs.annotation.Comment;
import java.time.Duration;
public class SpearSettings extends OkaeriConfig {
@Comment("# Should spears have lunge cooldown or delay between uses? True for cooldown, False for vanilla mechanics")
public boolean lungeCooldown = false;
@Comment("# Should cooldown be applied only during fights")
public boolean onlyForFight = true;
@Comment("# Duration of cooldown")
public Duration lungeCooldownDuration = Duration.ofSeconds(5);
@Comment("# Should milliseconds be used for last second of cooldown for more precise time")
public boolean useMillis = true;
@Comment({
"# Notice sent to the players that try to use spears before cooldown ends.",
"# Placeholder: {TIME} - time left of cooldown"
})
public Notice lungeOnCooldown = Notice.builder()
.chat("<dark_red>Spear cannot be used for next <red>{TIME}</red></dark_red>")
.build();
}
@@ -1,34 +0,0 @@
package com.eternalcode.combat.region.griefprevention;
import com.eternalcode.combat.region.Point;
import com.eternalcode.combat.region.Region;
import me.ryanhamshire.GriefPrevention.Claim;
import org.bukkit.Location;
import org.bukkit.World;
record GriefPreventionRegion(World world, Claim claim) implements Region {
@Override
public Point getCenter() {
Location min = this.claim.getLesserBoundaryCorner();
Location max = this.claim.getGreaterBoundaryCorner();
double x = (min.getX() + max.getX()) / 2.0;
double z = (min.getZ() + max.getZ()) / 2.0;
return new Point(this.world, x, z);
}
@Override
public Location getMin() {
Location min = this.claim.getLesserBoundaryCorner();
return new Location(this.world, min.getBlockX(), this.world.getMinHeight(), min.getBlockZ());
}
@Override
public Location getMax() {
Location max = this.claim.getGreaterBoundaryCorner();
return new Location(this.world, max.getBlockX(), this.world.getMaxHeight() - 1, max.getBlockZ());
}
}
@@ -1,93 +0,0 @@
package com.eternalcode.combat.region.griefprevention;
import com.eternalcode.combat.config.implementation.PluginConfig;
import com.eternalcode.combat.region.Region;
import com.eternalcode.combat.region.RegionProvider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.Optional;
import java.util.TreeSet;
import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
import org.bukkit.Location;
import org.bukkit.World;
public class GriefPreventionRegionProvider implements RegionProvider {
private final TreeSet<String> claims = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
private final PluginConfig pluginConfig;
public GriefPreventionRegionProvider(PluginConfig pluginConfig) {
this.claims.addAll(pluginConfig.regions.blockedRegions);
this.pluginConfig = pluginConfig;
}
@Override
public Optional<Region> getRegion(Location location) {
Claim claim = GriefPrevention.instance.dataStore.getClaimAt(location, true, null);
if (claim == null || !this.isCombatClaim(claim)) {
return Optional.empty();
}
return Optional.of(new GriefPreventionRegion(location.getWorld(), claim));
}
@Override
public Collection<Region> getRegions(World world) {
List<Region> regions = new ArrayList<>();
for (Claim claim : this.snapshotClaims()) {
if (!world.equals(claim.getLesserBoundaryCorner().getWorld())) {
continue;
}
if (this.isCombatClaim(claim)) {
regions.add(new GriefPreventionRegion(world, claim));
}
}
return regions;
}
private boolean isCombatClaim(Claim claim) {
if (this.claims.contains(String.valueOf(claim.getID()))) {
return true;
}
if (!this.pluginConfig.regions.preventPvpInRegions) {
return false;
}
World world = claim.getLesserBoundaryCorner().getWorld();
GriefPrevention griefPrevention = GriefPrevention.instance;
if (world == null || !griefPrevention.pvpRulesApply(world)) {
return false;
}
if (!claim.isAdminClaim()) {
return griefPrevention.config_pvp_noCombatInPlayerLandClaims;
}
if (claim.parent == null) {
return griefPrevention.config_pvp_noCombatInAdminLandClaims;
}
return griefPrevention.config_pvp_noCombatInAdminSubdivisions;
}
// GriefPrevention returns a live view of its claim list, and the border index reads regions asynchronously.
// A failed snapshot is retried by the next border index refresh, so an empty result is safe here.
private List<Claim> snapshotClaims() {
try {
return List.copyOf(GriefPrevention.instance.dataStore.getClaims());
}
catch (ConcurrentModificationException exception) {
return List.of();
}
}
}
@@ -1,15 +0,0 @@
package com.eternalcode.combat.config.implementation;
import static org.junit.jupiter.api.Assertions.assertFalse;
import org.junit.jupiter.api.Test;
class SignEditingSettingsTest {
@Test
void shouldDisableSignEditingBlockerByDefault() {
SignEditingSettings signEditingSettings = new SignEditingSettings();
assertFalse(signEditingSettings.disableSignEditingDuringCombat);
}
}
@@ -1,34 +0,0 @@
package com.eternalcode.combat.fight.blocker;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.bukkit.Material;
import org.junit.jupiter.api.Test;
class SignEditingBlockerTest {
@Test
void shouldRecognizeStandingSignMaterials() {
assertTrue(SignEditingBlocker.isSign(Material.OAK_SIGN));
assertTrue(SignEditingBlocker.isSign(Material.CRIMSON_SIGN));
}
@Test
void shouldRecognizeWallSignMaterials() {
assertTrue(SignEditingBlocker.isSign(Material.OAK_WALL_SIGN));
assertTrue(SignEditingBlocker.isSign(Material.WARPED_WALL_SIGN));
}
@Test
void shouldIgnoreNonSignMaterials() {
assertFalse(SignEditingBlocker.isSign(Material.CHEST));
assertFalse(SignEditingBlocker.isSign(Material.ENDER_PEARL));
}
@Test
void shouldRecognizeEnderPearlMaterial() {
assertTrue(SignEditingBlocker.isEnderPearl(Material.ENDER_PEARL));
assertFalse(SignEditingBlocker.isEnderPearl(Material.OAK_SIGN));
}
}
+1 -1
View File
@@ -4,4 +4,4 @@ org.gradle.configuration-cache=true
org.gradle.configuration-cache.parallel=true
# Platforms
paperVersion=1.19.3,1.19.4,1.20,1.20.1,1.20.2,1.20.4,1.20.5,1.20.6,1.21,1.21.1,1.21.3,1.21.4,1.21.5,1.21.6,1.21.7,1.21.8,1.21.9,1.21.10,1.21.11,26.1.1,26.1.2,26.2
paperVersion=1.19.3,1.19.4,1.20,1.20.1,1.20.2,1.20.4,1.20.5,1.20.6,1.21,1.21.1,1.21.3,1.21.4,1.21.5,1.21.6,1.21.7,1.21.8,1.21.9,1.21.10,1.21.11,26.1.1,26.1.2
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500