Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
0a8ee3e
Begin coding enhanced delivery logic
Jakubk15 Mar 15, 2025
3a530b4
Remove delivery object from repo after task completion
Jakubk15 Mar 15, 2025
ea9ed8e
use ParcelSendTask
Jakubk15 Mar 29, 2025
51d55f5
add DurationComposer
Jakubk15 Apr 18, 2025
a850247
Reorder methods
Jakubk15 Apr 20, 2025
5a963fd
Bump cdn, fix composer registration
Jakubk15 Apr 22, 2025
c7e4d38
Use DeliveryWrapper class in database instead of Delivery
Jakubk15 Apr 22, 2025
c3765cb
Remove duplicate code, bump deps, downgrade spigot-api to 1.21.4 due …
Jakubk15 Apr 26, 2025
7a3d50f
Temporarily change default parcel delivery delay
Jakubk15 Apr 26, 2025
00d68c3
Do not return immutable list if optional is empty
Jakubk15 Apr 26, 2025
555800d
Make debug commands executable from console
Jakubk15 Apr 26, 2025
fc3170f
Remove Vault left-overs
Jakubk15 Apr 26, 2025
23657ed
changes in gradle config
Jakubk15 Apr 26, 2025
0c03083
Adjust colors in debug messages
Jakubk15 Apr 26, 2025
9a5c0dc
Remove unnecessary messages, fix GUI items propagation
Jakubk15 Apr 26, 2025
d2c8673
Merge branch 'master' into enhanced-delivery-logic
Jakubk15 Apr 26, 2025
abbe0f3
Update build.gradle.kts
Jakubk15 Apr 26, 2025
2cd7bac
Update src/main/java/com/eternalcode/parcellockers/configuration/comp…
Jakubk15 Apr 26, 2025
29c6081
Refactor sendParcel to Result
Jakubk15 Apr 26, 2025
5466356
Merge remote-tracking branch 'origin/enhanced-delivery-logic' into en…
Jakubk15 Apr 26, 2025
eb918f6
More robust result handling, fix GUI slot painting
Jakubk15 Jun 7, 2025
65f6ed4
Rewrite DurationComposer
Jakubk15 Jun 7, 2025
e1f16b1
Add Copilot-generated unit test
Jakubk15 Jun 7, 2025
1561d73
Enhance serialize() method
Jakubk15 Jun 7, 2025
0043483
Disallow negative durations
Jakubk15 Jun 7, 2025
c092a5c
Delete redundant DurationUtil, remove debug breadcrumbs, properly par…
Jakubk15 Jun 22, 2025
a134365
Fix unit test
Jakubk15 Jun 22, 2025
f7d0f63
Fix unit test
Jakubk15 Jun 22, 2025
7c1f572
Merge remote-tracking branch 'origin/enhanced-delivery-logic' into en…
Jakubk15 Jun 22, 2025
798d7e9
Remove debug main method
Jakubk15 Jun 22, 2025
de3c6b8
Merge branch 'master' into enhanced-delivery-logic
Jakubk15 Jun 22, 2025
b8224e6
Update src/main/java/com/eternalcode/parcellockers/command/debug/Debu…
Jakubk15 Jul 2, 2025
2b4f9d5
Update src/main/java/com/eternalcode/parcellockers/parcel/task/Parcel…
Jakubk15 Jul 2, 2025
1784c5b
Update src/main/java/com/eternalcode/parcellockers/parcel/task/Parcel…
Jakubk15 Jul 2, 2025
67a9b70
Update src/main/java/com/eternalcode/parcellockers/command/debug/Debu…
Jakubk15 Jul 2, 2025
519191a
Update src/main/java/com/eternalcode/parcellockers/command/debug/Debu…
Jakubk15 Jul 2, 2025
8f901cc
Update src/main/java/com/eternalcode/parcellockers/command/debug/Debu…
Jakubk15 Jul 2, 2025
9c31a0e
Update src/main/java/com/eternalcode/parcellockers/command/debug/Debu…
Jakubk15 Jul 2, 2025
5d1c24e
Update src/main/java/com/eternalcode/parcellockers/gui/implementation…
Jakubk15 Jul 2, 2025
08a58a9
Apply DMK's suggestions
Jakubk15 Jul 2, 2025
3011663
Fix build, don't use deprecated methods in SkullAPI
Jakubk15 Jul 2, 2025
9bd4b6a
Merge branch 'master' into enhanced-delivery-logic
Jakubk15 Jul 2, 2025
040478b
Fix unit tests loading
Jakubk15 Jul 2, 2025
5f2d275
bump minecraft to 1.21.7 and update papermc repo url
Jakubk15 Jul 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,8 @@ repositories {

maven { url = uri("https://repo.panda-lang.org/releases") }
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/") }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
maven { url = uri("https://oss.sonatype.org/content/repositories/central") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/") }
maven { url = uri("https://repo.papermc.io/repository/maven-public/") }
maven { url = uri("https://repo.eternalcode.pl/releases") }
maven { url = uri("https://repository.minecodes.pl/releases") }
maven { url = uri("https://jitpack.io") }
}

dependencies {
Expand All @@ -38,11 +34,8 @@ dependencies {
implementation("dev.triumphteam:triumph-gui:3.1.11")
implementation("de.rapha149.signgui:signgui:2.5.0")

// economy
compileOnly("com.github.MilkBowl:VaultAPI:1.7.1")

// CDN
implementation("net.dzikoysk:cdn:1.14.6")
implementation("net.dzikoysk:cdn:1.14.8")

// expressible
implementation("org.panda-lang:expressible:1.3.6")
Expand All @@ -55,7 +48,7 @@ dependencies {
implementation("io.sentry:sentry:8.0.0")

// database
implementation("com.zaxxer:HikariCP:6.2.1")
implementation("com.zaxxer:HikariCP:6.3.0")
implementation("com.j256.ormlite:ormlite-jdbc:6.1")
implementation("com.h2database:h2:2.3.232")
implementation("org.postgresql:postgresql:42.7.5")
Expand Down Expand Up @@ -119,17 +112,10 @@ tasks {
minecraftVersion("1.21.4")
}

cleanPaperPluginsCache {
clean {
doLast {
project.file("run/plugins").deleteRecursively()
}
}

cleanPaperCache {
doLast {
project.file("run/cache").deleteRecursively()
project.file("run/logs").deleteRecursively()
project.file("run/versions").deleteRecursively()
}
}

Expand All @@ -138,7 +124,7 @@ tasks {
}

shadowJar {
archiveFileName.set("ParcelLockers v${project.version} (MC 1.21.3-1.21.4).jar")
archiveFileName.set("ParcelLockers v${project.version}.jar")

exclude(
"org/intellij/lang/annotations/**",
Expand Down
57 changes: 28 additions & 29 deletions src/main/java/com/eternalcode/parcellockers/ParcelLockers.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import com.eternalcode.parcellockers.content.repository.ParcelContentRepository;
import com.eternalcode.parcellockers.content.repository.ParcelContentRepositoryOrmLite;
import com.eternalcode.parcellockers.database.DatabaseManager;
import com.eternalcode.parcellockers.delivery.Delivery;
import com.eternalcode.parcellockers.delivery.repository.DeliveryRepositoryOrmLite;
import com.eternalcode.parcellockers.gui.implementation.locker.LockerMainGui;
import com.eternalcode.parcellockers.gui.implementation.remote.MainGui;
import com.eternalcode.parcellockers.gui.implementation.remote.ParcelListGui;
Expand All @@ -27,10 +29,12 @@
import com.eternalcode.parcellockers.notification.NotificationAnnouncer;
import com.eternalcode.parcellockers.parcel.Parcel;
import com.eternalcode.parcellockers.parcel.ParcelManager;
import com.eternalcode.parcellockers.parcel.ParcelStatus;
import com.eternalcode.parcellockers.parcel.command.ParcelCommand;
import com.eternalcode.parcellockers.parcel.command.argument.ParcelArgument;
import com.eternalcode.parcellockers.parcel.repository.ParcelCache;
import com.eternalcode.parcellockers.parcel.repository.ParcelRepositoryOrmLite;
import com.eternalcode.parcellockers.parcel.task.ParcelSendTask;
import com.eternalcode.parcellockers.updater.UpdaterService;
import com.eternalcode.parcellockers.user.UserManager;
import com.eternalcode.parcellockers.user.controller.LoadUserController;
Expand All @@ -52,16 +56,16 @@
import io.sentry.Sentry;
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.milkbowl.vault.economy.Economy;
import org.bstats.bukkit.Metrics;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;

import java.sql.SQLException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -75,7 +79,7 @@ public final class ParcelLockers extends JavaPlugin {
private LiteCommands<CommandSender> liteCommands;
private BukkitAudiences audiences;
private SkullAPI skullAPI;
private Economy economy;

private DatabaseManager databaseManager;

@Override
Expand Down Expand Up @@ -141,15 +145,16 @@ public void onEnable() {
ParcelRepositoryOrmLite parcelRepository = new ParcelRepositoryOrmLite(databaseManager, scheduler, parcelCache);
parcelRepository.updateCaches();

DeliveryRepositoryOrmLite deliveryRepository = new DeliveryRepositoryOrmLite(databaseManager, scheduler);

ParcelContentRepository parcelContentRepository = new ParcelContentRepositoryOrmLite(databaseManager, scheduler);
ParcelManager parcelManager = new ParcelManager(config, announcer, parcelRepository, parcelContentRepository, scheduler);
ParcelManager parcelManager = new ParcelManager(config, announcer, parcelRepository, deliveryRepository, parcelContentRepository, scheduler);

ItemStorageRepository itemStorageRepository = new ItemStorageRepositoryOrmLite(databaseManager, scheduler);

UserRepository userRepository = new UserRepositoryOrmLite(databaseManager, scheduler);
UserManager userManager = new UserManager(userRepository);


MainGui mainGUI = new MainGui(this, server, miniMessage, config, parcelRepository, lockerRepository, userManager);
ParcelListGui parcelListGUI = new ParcelListGui(this, server, miniMessage, config, parcelRepository, lockerRepository, userManager, mainGUI);

Expand All @@ -168,12 +173,6 @@ public void onEnable() {
.missingPermission(new PermissionMessage(announcer, config))
.build();

/*if (!this.setupEconomy()) {
this.getLogger().severe("Disabling due to no Vault dependency or its implementator(s) found!");
server.getPluginManager().disablePlugin(this);
return;
}*/

LockerMainGui lockerMainGUI = new LockerMainGui(this, miniMessage, config, itemStorageRepository, parcelRepository, lockerRepository, announcer, parcelContentRepository, userRepository, this.skullAPI, parcelManager);

Stream.of(
Expand All @@ -187,6 +186,24 @@ public void onEnable() {
new Metrics(this, 17677);
new UpdaterService(this.getDescription());

parcelRepository.findAll().thenAccept(optional -> {
List<Parcel> parcels = optional.orElse(new ArrayList<>());
parcels.removeIf(parcel -> parcel.status() == ParcelStatus.DELIVERED);
for (Parcel parcel : parcels) {
deliveryRepository.find(parcel.uuid()).thenAccept(optionalDelivery -> {
Delivery delivery = optionalDelivery.get();
long delay = delivery.deliveryTimestamp() - System.currentTimeMillis();

if (delay < 0) {
delay = 0;
}

System.out.println("scheduled parcel from db: " + parcel);
scheduler.runLaterAsync(new ParcelSendTask(parcel, delivery, parcelRepository, deliveryRepository, config), Duration.ofMillis(delay));
});
}
});

long millis = started.elapsed(TimeUnit.MILLISECONDS);
this.getLogger().log(Level.INFO, "Successfully enabled ParcelLockers in {0}ms", millis);
}
Expand Down Expand Up @@ -227,24 +244,6 @@ private void softwareCheck() {
logger.info("Your server is running on supported software, congratulations!");
logger.info("Server version: " + this.getServer().getVersion());
}

private boolean setupEconomy() {
if (this.getServer().getPluginManager().getPlugin("Vault") == null) {
return false;
}

RegisteredServiceProvider<Economy> rsp = this.getServer().getServicesManager().getRegistration(Economy.class);
if (rsp == null) {
return false; // Vault is installed but no economy plugin is registered (e.g. EssentialsX) - majk
}

this.economy = rsp.getProvider();
return true;
}

public Economy getEconomy() {
return this.economy;
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public ParcelLockersCommand(ConfigurationManager configManager, PluginConfigurat
}

@Async
@Execute(name = "reload", aliases = { "rl" })
@Execute(name = "reload")
void reload(@Context CommandSender sender) {
this.configManager.reload();
this.announcer.sendMessage(sender, this.config.messages.reload);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import dev.rollczi.litecommands.annotations.execute.Execute;
import dev.rollczi.litecommands.annotations.permission.Permission;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;

Expand Down Expand Up @@ -38,43 +39,43 @@ public DebugCommand(ParcelRepository parcelRepository, LockerRepository lockerRe
}

@Execute(name = "deleteparcels")
void deleteParcels(@Context Player player) {
void deleteParcels(@Context CommandSender sender) {
this.parcelRepository.removeAll().exceptionally(throwable -> {
this.announcer.sendMessage(player, "&cFailed to delete parcels");
this.announcer.sendMessage(sender, "&4Failed to delete parcels");
return null;
}).thenRun(() -> this.announcer.sendMessage(player, "&aParcels deleted"));
}).thenRun(() -> this.announcer.sendMessage(sender, "&cParcels deleted"));
}

@Execute(name = "deletelockers")
void deleteLockers(@Context Player player) {
void deleteLockers(@Context CommandSender sender) {
this.lockerRepository.removeAll().exceptionally(throwable -> {
this.announcer.sendMessage(player, "&cFailed to delete lockers");
this.announcer.sendMessage(sender, "&4Failed to delete lockers");
return null;
}).thenRun(() -> this.announcer.sendMessage(player, "&aLockers deleted"));
}).thenRun(() -> this.announcer.sendMessage(sender, "&cLockers deleted"));
}

@Execute(name = "deleteitemstorages")
void deleteItemStorages(@Context Player player) {
void deleteItemStorages(@Context CommandSender sender) {
this.itemStorageRepository.removeAll().exceptionally(throwable -> {
this.announcer.sendMessage(player, "&cFailed to delete item storages");
this.announcer.sendMessage(sender, "&4Failed to delete item storages");
return null;
}).thenRun(() -> this.announcer.sendMessage(player, "&aItem storages deleted"));
}).thenRun(() -> this.announcer.sendMessage(sender, "&cItem storages deleted"));
}

@Execute(name = "deleteparcelcontents")
void deleteParcelContents(@Context Player player) {
void deleteParcelContents(@Context CommandSender sender) {
this.contentRepository.removeAll().exceptionally(throwable -> {
this.announcer.sendMessage(player, "&cFailed to delete parcel contents");
this.announcer.sendMessage(sender, "&4Failed to delete parcel contents");
return null;
}).thenRun(() -> this.announcer.sendMessage(player, "&aParcel contents deleted"));
}).thenRun(() -> this.announcer.sendMessage(sender, "&cParcel contents deleted"));
}

@Execute(name = "deleteall")
void deleteAll(@Context Player player) {
this.deleteItemStorages(player);
this.deleteLockers(player);
this.deleteParcels(player);
this.deleteParcelContents(player);
void deleteAll(@Context CommandSender sender) {
this.deleteItemStorages(sender);
this.deleteLockers(sender);
this.deleteParcels(sender);
this.deleteParcelContents(sender);
}

@Execute(name = "getrandomitem")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.eternalcode.parcellockers.configuration;

import com.eternalcode.parcellockers.configuration.composer.DurationComposer;
import com.eternalcode.parcellockers.configuration.composer.PositionComposer;
import com.eternalcode.parcellockers.shared.Position;
import net.dzikoysk.cdn.Cdn;
import net.dzikoysk.cdn.CdnFactory;

import java.io.File;
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;

Expand All @@ -13,7 +16,8 @@ public class ConfigurationManager {
private static final Cdn CDN = CdnFactory
.createYamlLike()
.getSettings()
.withComposer(PositionComposer.class, new PositionComposer())
.withComposer(Position.class, new PositionComposer())
.withComposer(Duration.class, new DurationComposer())
.build();

private final Set<ReloadableConfig> configs = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.eternalcode.parcellockers.configuration.composer;

import panda.std.Result;

import java.time.Duration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DurationComposer implements SimpleComposer<Duration> {

// Regex to match each time component individually
private static final Pattern TIME_PATTERN = Pattern.compile(
"(-?\\d+(?:\\.\\d+)?)\\s*([dhms])",
Pattern.CASE_INSENSITIVE);

@Override
public Result<String, Exception> serialize(Duration duration) {
if (duration == null) {
return Result.error(new IllegalArgumentException("Duration cannot be null"));
}
return Result.ok(duration.toString()
.substring(2) // Remove the PT prefix
.replaceAll("(\\d[HMS])(?!$)", "$1 ") // Add spaces between components
.toLowerCase());
}

@Override
public Result<Duration, Exception> deserialize(String input) {
try {
if (input == null || input.isBlank()) {
return Result.error(new IllegalArgumentException("Input cannot be null or blank"));
}

// If input is already in ISO-8601 format
if (input.toUpperCase().startsWith("P")) {
return Result.ok(Duration.parse(input));
}

// For simple case: just a number (assume seconds)
if (input.matches("-?\\d+(\\.\\d+)?")) {
return Result.ok(Duration.ofSeconds(Long.parseLong(input)));
}

// Parse custom format (e.g., "1d 2h 3m 4.5s")
Duration duration = Duration.ZERO;
Matcher matcher = TIME_PATTERN.matcher(input);

boolean foundMatch = false;
while (matcher.find()) {
foundMatch = true;
String value = matcher.group(1);
String unit = matcher.group(2).toLowerCase();

switch (unit) {
case "d":
duration = duration.plusDays(Long.parseLong(value));
break;
case "h":
duration = duration.plusHours(Long.parseLong(value));
break;
case "m":
duration = duration.plusMinutes(Long.parseLong(value));
break;
case "s":
if (value.contains(".")) {
double seconds = Double.parseDouble(value);
long wholeSeconds = (long) seconds;
long nanos = (long) ((seconds - wholeSeconds) * 1_000_000_000);
duration = duration.plusSeconds(wholeSeconds).plusNanos(nanos);
} else {
duration = duration.plusSeconds(Long.parseLong(value));
}
break;
}
}

if (!foundMatch) {
return Result.error(new IllegalArgumentException(
"Invalid duration format. Expected format like '1d 2h 3m 4s' or ISO-8601 duration."));
}

return Result.ok(duration);

} catch (Exception e) {
return Result.error(new IllegalArgumentException("Failed to parse duration: " + e.getMessage(), e));
}
}
}
Loading