chore: downgrade compile target to Java 11

Uses <release>11</release> in maven-compiler-plugin (recommended over
source/target to guarantee bytecode and API surface match Java 11).

Code changes to drop Java 12-16 features:
- records (TeamRanking, PlayerRanking, internal tuples in
  SqliteTeamRepository) become hand-written immutable classes; same
  accessor names (rank()/team()/score()/...) so call sites are unchanged.
- instanceof X x pattern matching becomes classic instanceof + cast in
  CommandContext.requirePlayer and Database.normalize.
- switch expressions with -> arrows become classic switch + break, or
  if/else chains, in BaseCommand.handleResult, ArgumentTypes.BOOLEAN and
  TeamScoreSubCommand.execute.

docs/setup.md, features.md and decisions.md updated to reflect Java 11.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Antone Barbaud
2026-06-09 12:18:43 +02:00
parent 7ee349f206
commit 5bd6e227d3
12 changed files with 209 additions and 43 deletions
@@ -46,11 +46,14 @@ public final class ArgumentTypes {
public static final ArgumentType<Boolean> BOOLEAN = new ArgumentType<>() {
@Override
public Boolean parse(String input) {
return switch (input.toLowerCase()) {
case "true", "yes", "y", "1", "on" -> true;
case "false", "no", "n", "0", "off" -> false;
default -> throw new CommandException("Invalid boolean: " + input);
};
String lc = input.toLowerCase();
if (lc.equals("true") || lc.equals("yes") || lc.equals("y") || lc.equals("1") || lc.equals("on")) {
return true;
}
if (lc.equals("false") || lc.equals("no") || lc.equals("n") || lc.equals("0") || lc.equals("off")) {
return false;
}
throw new CommandException("Invalid boolean: " + input);
}
@Override
@@ -48,17 +48,25 @@ public abstract class BaseCommand extends AbstractCommand
*/
protected void handleResult(CommandSender sender, CommandResult result) {
switch (result.getType()) {
case SUCCESS -> {
case SUCCESS:
if (result.getMessage() != null) {
sender.sendMessage(ChatColor.GREEN + result.getMessage());
}
}
case FAILURE -> sender.sendMessage(ChatColor.RED +
(result.getMessage() != null ? result.getMessage() : "Command failed."));
case INVALID_USAGE -> sender.sendMessage(ChatColor.RED +
(result.getMessage() != null ? result.getMessage() : "Invalid usage."));
case NO_PERMISSION -> sender.sendMessage(ChatColor.RED + "Vous n'avez pas la permission.");
case PLAYER_ONLY -> sender.sendMessage(ChatColor.RED + "Seul un joueur peut utiliser cette commande.");
break;
case FAILURE:
sender.sendMessage(ChatColor.RED +
(result.getMessage() != null ? result.getMessage() : "Command failed."));
break;
case INVALID_USAGE:
sender.sendMessage(ChatColor.RED +
(result.getMessage() != null ? result.getMessage() : "Invalid usage."));
break;
case NO_PERMISSION:
sender.sendMessage(ChatColor.RED + "Vous n'avez pas la permission.");
break;
case PLAYER_ONLY:
sender.sendMessage(ChatColor.RED + "Seul un joueur peut utiliser cette commande.");
break;
}
}
}
@@ -45,10 +45,10 @@ public class CommandContext {
}
public Player requirePlayer() {
if (!(sender instanceof Player player)) {
if (!(sender instanceof Player)) {
throw new CommandException("This command can only be used by a player.");
}
return player;
return (Player) sender;
}
@SuppressWarnings("unchecked")
@@ -40,11 +40,14 @@ public class TeamScoreSubCommand extends SubCommand {
String op = ctx.get("op");
int value = ctx.get("value");
int result = switch (op) {
case "add" -> service.addScore(team.getId(), name, value);
case "set" -> service.setScore(team.getId(), name, value);
default -> throw new IllegalStateException("unreachable: " + op);
};
int result;
if ("add".equals(op)) {
result = service.addScore(team.getId(), name, value);
} else if ("set".equals(op)) {
result = service.setScore(team.getId(), name, value);
} else {
throw new IllegalStateException("unreachable: " + op);
}
return CommandResult.success("Score " + name + " de " + team.getName() + " = " + result);
}
}
@@ -199,9 +199,9 @@ public class Database implements AutoCloseable {
/** Convertit les valeurs Java non-natives SQL en types utilisables par JDBC. */
private static Object normalize(Object value) {
if (value == null) return null;
if (value instanceof UUID uuid) return uuid.toString();
if (value instanceof Enum<?> e) return e.name();
if (value instanceof Boolean b) return b ? 1 : 0;
if (value instanceof UUID) return value.toString();
if (value instanceof Enum<?>) return ((Enum<?>) value).name();
if (value instanceof Boolean) return ((Boolean) value) ? 1 : 0;
return value;
}
}
@@ -2,12 +2,56 @@ package fr.luc.crcore.player;
import java.util.Objects;
public record PlayerRanking(int rank, PlayerProfile profile, int score) {
/**
* Entrée d'un classement de joueurs : rang (1-based), profil, score effectif
* sur le critère trié.
*
* <p>Classe immutable. Volontairement écrite "à la main" plutôt qu'en
* {@code record} (Java 16+) pour rester compatible Java 11.
*/
public final class PlayerRanking {
public PlayerRanking {
private final int rank;
private final PlayerProfile profile;
private final int score;
public PlayerRanking(int rank, PlayerProfile profile, int score) {
Objects.requireNonNull(profile, "profile");
if (rank < 1) {
throw new IllegalArgumentException("rank must be >= 1, got " + rank);
}
this.rank = rank;
this.profile = profile;
this.score = score;
}
public int rank() {
return rank;
}
public PlayerProfile profile() {
return profile;
}
public int score() {
return score;
}
@Override
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof PlayerRanking)) return false;
PlayerRanking that = (PlayerRanking) other;
return rank == that.rank && score == that.score && profile.equals(that.profile);
}
@Override
public int hashCode() {
return Objects.hash(rank, profile, score);
}
@Override
public String toString() {
return "PlayerRanking[rank=" + rank + ", playerId=" + profile.getId() + ", score=" + score + "]";
}
}
@@ -197,13 +197,49 @@ public class SqliteTeamRepository extends InMemoryTeamRepository {
);
}
// Tuples internes pour le load.
private record TeamRow(
UUID id, String name, String tag, TeamColor color,
UUID leaderId, TeamVisibility visibility,
String spawnWorld, Double spawnX, Double spawnY, Double spawnZ,
Float spawnYaw, Float spawnPitch
) {}
// Tuples internes pour le load. Classes immutables manuelles (Java 11 compat).
private static final class TeamRow {
final UUID id;
final String name;
final String tag;
final TeamColor color;
final UUID leaderId;
final TeamVisibility visibility;
final String spawnWorld;
final Double spawnX;
final Double spawnY;
final Double spawnZ;
final Float spawnYaw;
final Float spawnPitch;
private record MemberRow(UUID playerId, TeamRole role, Instant joinedAt) {}
TeamRow(UUID id, String name, String tag, TeamColor color,
UUID leaderId, TeamVisibility visibility,
String spawnWorld, Double spawnX, Double spawnY, Double spawnZ,
Float spawnYaw, Float spawnPitch) {
this.id = id;
this.name = name;
this.tag = tag;
this.color = color;
this.leaderId = leaderId;
this.visibility = visibility;
this.spawnWorld = spawnWorld;
this.spawnX = spawnX;
this.spawnY = spawnY;
this.spawnZ = spawnZ;
this.spawnYaw = spawnYaw;
this.spawnPitch = spawnPitch;
}
}
private static final class MemberRow {
final UUID playerId;
final TeamRole role;
final Instant joinedAt;
MemberRow(UUID playerId, TeamRole role, Instant joinedAt) {
this.playerId = playerId;
this.role = role;
this.joinedAt = joinedAt;
}
}
}
@@ -2,12 +2,56 @@ package fr.luc.crcore.team;
import java.util.Objects;
public record TeamRanking(int rank, Team team, int score) {
/**
* Entrée d'un classement d'équipes : rang (1-based), équipe, score effectif
* sur le critère trié.
*
* <p>Classe immutable. Volontairement écrite "à la main" plutôt qu'en
* {@code record} (Java 16+) pour rester compatible Java 11.
*/
public final class TeamRanking {
public TeamRanking {
private final int rank;
private final Team team;
private final int score;
public TeamRanking(int rank, Team team, int score) {
Objects.requireNonNull(team, "team");
if (rank < 1) {
throw new IllegalArgumentException("rank must be >= 1, got " + rank);
}
this.rank = rank;
this.team = team;
this.score = score;
}
public int rank() {
return rank;
}
public Team team() {
return team;
}
public int score() {
return score;
}
@Override
public boolean equals(Object other) {
if (this == other) return true;
if (!(other instanceof TeamRanking)) return false;
TeamRanking that = (TeamRanking) other;
return rank == that.rank && score == that.score && team.equals(that.team);
}
@Override
public int hashCode() {
return Objects.hash(rank, team, score);
}
@Override
public String toString() {
return "TeamRanking[rank=" + rank + ", team=" + team.getName() + ", score=" + score + "]";
}
}