Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
077d5ef
INIT
P1otrulla Sep 14, 2026
6e35c6d
Add a missing label
P1otrulla Sep 14, 2026
20ad6f4
Add controllers
P1otrulla Sep 14, 2026
535e885
🥲
P1otrulla Sep 14, 2026
b2e98bf
Add KickCommand and normally use Permissions
P1otrulla Sep 14, 2026
869bcb1
Add KickAll logic
P1otrulla Sep 14, 2026
24e6465
fix typo
P1otrulla Sep 14, 2026
f550305
Add ip saving system
P1otrulla Sep 15, 2026
2c7109c
IP system has been improved.
P1otrulla Sep 15, 2026
9466fc7
cleanUp
P1otrulla Sep 15, 2026
57adbc6
Add banned player join notification and IP evasion handling and fix s…
P1otrulla Sep 16, 2026
215d511
Add banned player join notification and IP evasion handling and fix s…
P1otrulla Sep 16, 2026
ba78e0e
Add punishment commands, warning escalations, and history pagination
P1otrulla Sep 16, 2026
ee95629
Make plugin run
CitralFlo Sep 16, 2026
67be256
Add logging for punishment commands and introduce `DurationReasonParser`
P1otrulla Sep 16, 2026
82d1bff
Merge remote-tracking branch 'origin/ficzer/punishmenty' into ficzer/…
P1otrulla Sep 16, 2026
7f63902
Refine punishment commands to exclude console operators from bypass p…
P1otrulla Sep 16, 2026
5cb0e90
Remove `UnbanIpCommand` and associated IP unban messages
P1otrulla Sep 16, 2026
11aa029
Add `docker-compose.yml` for PostgreSQL setup and remove extraneous n…
P1otrulla Sep 17, 2026
1d9fb7b
Introduce punishment history GUI with improved flexibility and IP unb…
P1otrulla Sep 17, 2026
8c6abe8
Add IP address validator, punishment expiration support, and new mute…
P1otrulla Sep 17, 2026
16256f1
Downgrade `INV_UI` dependency to version 2.3.2
P1otrulla Sep 17, 2026
2099101
Add duration support for warnings, enhance permissions, and refactor …
P1otrulla Sep 17, 2026
e54a449
Update punishment history GUI to include expiration details in entry …
P1otrulla Sep 17, 2026
c869dd2
Refactor punishment system: switch to Java records, simplify reposito…
P1otrulla Sep 20, 2026
ea90878
Update JOOQ dependency to version 3.21.8
P1otrulla Sep 20, 2026
8f95859
Remove xenondevs repository from eternalcore-repositories configuration
P1otrulla Sep 20, 2026
d580c05
Remove `InstantPersister`, simplify null validation in `AltAccount` a…
P1otrulla Sep 20, 2026
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
3 changes: 1 addition & 2 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ object Versions {
const val ADVENTURE_TEXT_MINIMESSAGE = "4.26.1"
const val OKAERI_CONFIGS = "6.0.0-beta.27"

const val JOOQ = "3.21.8"
const val MARIA_DB = "3.5.9"
const val POSTGRESQL = "42.7.13"
const val H2 = "2.4.240"
Expand All @@ -26,8 +27,6 @@ object Versions {
const val GUAVA = "33.6.0-jre"
const val GSON = "2.14.0"

const val EXPRESSIBLE = "1.3.6"
const val PANDA_UTILITIES = "0.5.3-alpha"
const val APACHE_COMMONS = "2.22.0"

const val TRIUMPH_GUI = "3.1.13"
Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/eternalcode-java.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ group = "com.eternalcode"
version = "2.0.1-SNAPSHOT"

java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
}

tasks.compileJava {
options.compilerArgs = listOf("-Xlint:deprecation", "-parameters")
options.encoding = "UTF-8"
options.release = 21
options.release = 25
}
15 changes: 15 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
services:
postgres:
image: postgres:16
container_name: eternalcore-postgres
environment:
POSTGRES_DB: eternalcore
POSTGRES_USER: eternalcore
POSTGRES_PASSWORD: eternalcore
ports:
- "5432:5432"
volumes:
- eternalcore-postgres-data:/var/lib/postgresql/data

volumes:
eternalcore-postgres-data:
2 changes: 1 addition & 1 deletion eternalcore-api-example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ bukkit {
}

java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
}

tasks.withType<JavaCompile> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.eternalcode.core.feature.punishment;

import java.time.Instant;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

/**
* Immutable punishmentapi record. Active state is derived, never stored:
* a punishment is active when it is not revoked and not expired.
* KICK is instantaneous and has no meaningful active state.
*
* @param expiresAt null = permanent
* @param revokedAt null = not revoked
*/
public record Punishment(
UUID id,
PunishmentTarget target,
PunishmentTarget operator,
PunishmentType type,
String reason,
Instant createdAt,
Instant expiresAt,
Instant revokedAt
) {

public Punishment {
if (expiresAt != null && expiresAt.isBefore(createdAt)) {
throw new IllegalArgumentException("expiresAt cannot be before createdAt");
}
if (revokedAt != null && revokedAt.isBefore(createdAt)) {
throw new IllegalArgumentException("revokedAt cannot be before createdAt");
}
}

public Optional<Instant> expiresAtOptional() {
return Optional.ofNullable(this.expiresAt);
}

public Optional<Instant> revokedAtOptional() {
return Optional.ofNullable(this.revokedAt);
}

public boolean isPermanent() {
return this.expiresAt == null;
}

public boolean isRevoked() {
return this.revokedAt != null;
}

public boolean isExpired(Instant now) {
return this.expiresAt != null && !now.isBefore(this.expiresAt);
}

public boolean isActive(Instant now) {
return !this.isRevoked() && !this.isExpired(now);
}

public boolean isActive() {
return this.isActive(Instant.now());
}

public Punishment revoke(Instant revokedAt) {
if (this.isRevoked()) {
throw new IllegalStateException("Punishment " + this.id + " is already revoked");
}

return new Punishment(
this.id,
this.target,
this.operator,
this.type,
this.reason,
this.createdAt,
this.expiresAt,
revokedAt
);
}

public static Builder builder() {
return new Builder();
}

public static final class Builder {

private UUID id = UUID.randomUUID();
private PunishmentTarget target;
private PunishmentTarget operator;
private PunishmentType type;
private String reason;
private Instant createdAt = Instant.now();
private Instant expiresAt;
private Instant revokedAt;

public Builder id(UUID id) {
this.id = id;
return this;
}

public Builder target(PunishmentTarget target) {
this.target = target;
return this;
}

public Builder operator(PunishmentTarget operator) {
this.operator = operator;
return this;
}

public Builder type(PunishmentType type) {
this.type = type;
return this;
}

public Builder reason(String reason) {
this.reason = reason;
return this;
}

public Builder createdAt(Instant createdAt) {
this.createdAt = createdAt;
return this;
}

public Builder expiresAt(Instant expiresAt) {
this.expiresAt = expiresAt;
return this;
}

public Builder revokedAt(Instant revokedAt) {
this.revokedAt = revokedAt;
return this;
}

public Punishment build() {
return new Punishment(
this.id,
this.target,
this.operator,
this.type,
this.reason,
this.createdAt,
this.expiresAt,
this.revokedAt
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.eternalcode.core.feature.punishment;

import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import net.kyori.adventure.text.Component;

public interface PunishmentService {

Punishment ban(PunishmentTarget target, PunishmentTarget operator, String reason, Instant expiresAt, List<Component> kickMessage);
void unban(PunishmentTarget target, PunishmentTarget operator);

Punishment mute(PunishmentTarget target, PunishmentTarget operator, String reason, Instant expiresAt);
void unmute(PunishmentTarget target, PunishmentTarget operator);

Punishment warn(PunishmentTarget target, PunishmentTarget operator, String reason, Instant expiresAt);

void kick(PunishmentTarget target, PunishmentTarget operator, String reason, List<Component> kickMessage, boolean massKick);

boolean isBanned(UUID targetUuid);

boolean isMuted(UUID targetUuid);

Optional<Punishment> getActiveBan(UUID targetUuid);

Optional<Punishment> getActiveMute(UUID targetUuid);

List<Punishment> findActive(UUID targetUuid);

List<Punishment> activeBans();
List<Punishment> activeMutes();
List<Punishment> activeWarns();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.eternalcode.core.feature.punishment;

import java.util.UUID;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

public record PunishmentTarget(UUID uuid, String name) {

public static final UUID CONSOLE_UUID = UUID.nameUUIDFromBytes("CONSOLE_UUID".getBytes());

public static PunishmentTarget of(OfflinePlayer player) {
return new PunishmentTarget(player.getUniqueId(), player.getName());
}

public static PunishmentTarget of(Player player) {
return new PunishmentTarget(player.getUniqueId(), player.getName());
}

public static PunishmentTarget of(CommandSender sender) {
if (sender instanceof Player player) {
return of(player);
}

return new PunishmentTarget(CONSOLE_UUID, sender.getName());
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}

return obj instanceof PunishmentTarget other && this.uuid.equals(other.uuid);
}

@Override
public int hashCode() {
return this.uuid.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.eternalcode.core.feature.punishment;

public enum PunishmentType {

BAN,
KICK,
MUTE,
WARN

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.eternalcode.core.feature.punishment.history;

import com.eternalcode.core.feature.punishment.PunishmentTarget;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;

public record PunishmentHistoryEntry(
UUID id,
UUID punishmentId,
PunishmentTarget target,
PunishmentTarget operator,
HistoryAction action,
String reason,
Instant timestamp,
Instant expiresAt
) {
public Optional<Instant> expiresAtOptional() {
return Optional.ofNullable(this.expiresAt);
}

public boolean isPermanent() {
return this.expiresAt == null;
}

public enum HistoryAction {
BAN, UNBAN, KICK, KICK_ALL, MUTE, UNMUTE, WARN, EXPIRE, BAN_IP, UNBAN_IP
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.eternalcode.core.feature.punishment.history;

import java.util.List;
import java.util.UUID;

public interface PunishmentHistoryService {

void record(PunishmentHistoryEntry entry);

List<PunishmentHistoryEntry> findByTarget(UUID targetUuid, int page, int pageSize);

List<PunishmentHistoryEntry> findRecent(int page, int pageSize);
}
Loading