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:
@@ -323,6 +323,30 @@ Format léger : une décision = un titre + contexte + choix + raison.
|
|||||||
même fichier SQLite (par défaut `<dataFolder>/crcore.db`) ; le préfixe
|
même fichier SQLite (par défaut `<dataFolder>/crcore.db`) ; le préfixe
|
||||||
isole proprement.
|
isole proprement.
|
||||||
|
|
||||||
|
## 2026-06-09 — Bascule Java 16 → Java 11 (révision)
|
||||||
|
|
||||||
|
- **Révision** de la décision "Java 16" du 2026-06-08.
|
||||||
|
- **Choix** : `maven.compiler.source/target = 11`. Le code se compile et
|
||||||
|
s'exécute sur tout JDK 11+.
|
||||||
|
- **Raison** : Java 11 reste très répandu côté serveurs Bukkit/Paper 1.16.5,
|
||||||
|
et le coût de revenir en arrière est faible. On garde une cible plus
|
||||||
|
conservatrice pour maximiser la compatibilité d'exécution.
|
||||||
|
- **Conséquences sur le code** :
|
||||||
|
- Les `record` (Java 16) → classes immutables manuelles, avec mêmes noms
|
||||||
|
d'accesseurs (`rank()`, `team()`, etc.) pour ne pas casser l'API
|
||||||
|
publique. Concerné : `TeamRanking`, `PlayerRanking`, plus deux tuples
|
||||||
|
internes (`TeamRow`, `MemberRow`) dans `SqliteTeamRepository`.
|
||||||
|
- Le **pattern matching `instanceof X x`** (Java 16) → classique
|
||||||
|
`instanceof X` + cast explicite. Concerné : `CommandContext.requirePlayer`,
|
||||||
|
`Database.normalize`.
|
||||||
|
- Les **switch expressions à flèche** (`case X -> ...`, Java 14) →
|
||||||
|
`switch (...) { case X: ...; break; }` classique, ou chaînes if/else.
|
||||||
|
Concerné : `BaseCommand.handleResult`, `ArgumentTypes.BOOLEAN.parse`,
|
||||||
|
`TeamScoreSubCommand.execute`.
|
||||||
|
- **Ce qui reste utilisé de Java 11** : `var` (Java 10+), `List.of()` /
|
||||||
|
`Map.of()` (Java 9+), interfaces avec méthodes `default`, lambdas, method
|
||||||
|
references.
|
||||||
|
|
||||||
## 2026-06-09 — Enregistrement dynamique de la commande (plugin.yml optionnel)
|
## 2026-06-09 — Enregistrement dynamique de la commande (plugin.yml optionnel)
|
||||||
|
|
||||||
- **Choix** : `CRCore.registerCommand()` tente d'abord
|
- **Choix** : `CRCore.registerCommand()` tente d'abord
|
||||||
|
|||||||
+2
-2
@@ -111,7 +111,7 @@ Le service expose deux types de classements :
|
|||||||
| `getTopRankingByScore(name, n)` | Top N par score. |
|
| `getTopRankingByScore(name, n)` | Top N par score. |
|
||||||
| `getTopGlobalRanking(n)` | Top N global. |
|
| `getTopGlobalRanking(n)` | Top N global. |
|
||||||
|
|
||||||
Le résultat est une `List<TeamRanking>` (record Java 16) avec `rank` (1-based),
|
Le résultat est une `List<TeamRanking>` (classe immutable, accesseurs `rank()`/`team()`/`score()`) avec `rank` (1-based),
|
||||||
`team` et `score`. Tiebreaker : ordre alphabétique sur le nom de l'équipe
|
`team` et `score`. Tiebreaker : ordre alphabétique sur le nom de l'équipe
|
||||||
(insensible à la casse).
|
(insensible à la casse).
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ les méthodes de scoring (`getScore`, `addScore`, `setScore`, `resetScore`,
|
|||||||
|
|
||||||
### `PlayerRanking`
|
### `PlayerRanking`
|
||||||
|
|
||||||
Record Java 16 : `record PlayerRanking(int rank, PlayerProfile profile, int score)`.
|
Classe immutable : `PlayerRanking(int rank, PlayerProfile profile, int score)` avec accesseurs `rank()`/`profile()`/`score()`.
|
||||||
Mêmes règles que `TeamRanking` (rank 1-based, tri descendant, tiebreaker par
|
Mêmes règles que `TeamRanking` (rank 1-based, tri descendant, tiebreaker par
|
||||||
UUID pour rester déterministe).
|
UUID pour rester déterministe).
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
- **Type** : librairie Java (`jar`) — pas un plugin Bukkit
|
- **Type** : librairie Java (`jar`) — pas un plugin Bukkit
|
||||||
- **artifactId Maven** : `CR-Core`
|
- **artifactId Maven** : `CR-Core`
|
||||||
- **Build** : Maven, Java 16
|
- **Build** : Maven, Java 11
|
||||||
- **API serveur (provided)** : Paper 1.16.5
|
- **API serveur (provided)** : Paper 1.16.5
|
||||||
- **SQLite (compile)** : `org.xerial:sqlite-jdbc:3.45.3.0`
|
- **SQLite (compile)** : `org.xerial:sqlite-jdbc:3.45.3.0`
|
||||||
- **Package racine** : `fr.luc.crcore`
|
- **Package racine** : `fr.luc.crcore`
|
||||||
|
|||||||
@@ -13,8 +13,13 @@
|
|||||||
<description>Reusable core library for CR Minecraft game plugins (teams, players, scores, commands, events, SQLite persistence).</description>
|
<description>Reusable core library for CR Minecraft game plugins (teams, players, scores, commands, events, SQLite persistence).</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>16</maven.compiler.source>
|
<!--
|
||||||
<maven.compiler.target>16</maven.compiler.target>
|
On utilise <release> plutôt que <source>+<target> pour garantir
|
||||||
|
que les références à des API ne sont pas accidentellement plus
|
||||||
|
récentes que Java 11 (ex. List.copyOf en Java 10+ : OK ;
|
||||||
|
Stream.toList en Java 16+ : refusé par javac).
|
||||||
|
-->
|
||||||
|
<maven.compiler.release>11</maven.compiler.release>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<sqlite.version>3.45.3.0</sqlite.version>
|
<sqlite.version>3.45.3.0</sqlite.version>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -83,8 +88,7 @@
|
|||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.11.0</version>
|
<version>3.11.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${maven.compiler.source}</source>
|
<release>${maven.compiler.release}</release>
|
||||||
<target>${maven.compiler.target}</target>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
@@ -121,7 +125,7 @@
|
|||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.6.3</version>
|
<version>3.6.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${maven.compiler.source}</source>
|
<source>${maven.compiler.release}</source>
|
||||||
<doclint>none</doclint>
|
<doclint>none</doclint>
|
||||||
<quiet>true</quiet>
|
<quiet>true</quiet>
|
||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
|
|||||||
@@ -46,11 +46,14 @@ public final class ArgumentTypes {
|
|||||||
public static final ArgumentType<Boolean> BOOLEAN = new ArgumentType<>() {
|
public static final ArgumentType<Boolean> BOOLEAN = new ArgumentType<>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean parse(String input) {
|
public Boolean parse(String input) {
|
||||||
return switch (input.toLowerCase()) {
|
String lc = input.toLowerCase();
|
||||||
case "true", "yes", "y", "1", "on" -> true;
|
if (lc.equals("true") || lc.equals("yes") || lc.equals("y") || lc.equals("1") || lc.equals("on")) {
|
||||||
case "false", "no", "n", "0", "off" -> false;
|
return true;
|
||||||
default -> throw new CommandException("Invalid boolean: " + input);
|
}
|
||||||
};
|
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
|
@Override
|
||||||
|
|||||||
@@ -48,17 +48,25 @@ public abstract class BaseCommand extends AbstractCommand
|
|||||||
*/
|
*/
|
||||||
protected void handleResult(CommandSender sender, CommandResult result) {
|
protected void handleResult(CommandSender sender, CommandResult result) {
|
||||||
switch (result.getType()) {
|
switch (result.getType()) {
|
||||||
case SUCCESS -> {
|
case SUCCESS:
|
||||||
if (result.getMessage() != null) {
|
if (result.getMessage() != null) {
|
||||||
sender.sendMessage(ChatColor.GREEN + result.getMessage());
|
sender.sendMessage(ChatColor.GREEN + result.getMessage());
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
case FAILURE -> sender.sendMessage(ChatColor.RED +
|
case FAILURE:
|
||||||
(result.getMessage() != null ? result.getMessage() : "Command failed."));
|
sender.sendMessage(ChatColor.RED +
|
||||||
case INVALID_USAGE -> sender.sendMessage(ChatColor.RED +
|
(result.getMessage() != null ? result.getMessage() : "Command failed."));
|
||||||
(result.getMessage() != null ? result.getMessage() : "Invalid usage."));
|
break;
|
||||||
case NO_PERMISSION -> sender.sendMessage(ChatColor.RED + "Vous n'avez pas la permission.");
|
case INVALID_USAGE:
|
||||||
case PLAYER_ONLY -> sender.sendMessage(ChatColor.RED + "Seul un joueur peut utiliser cette commande.");
|
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() {
|
public Player requirePlayer() {
|
||||||
if (!(sender instanceof Player player)) {
|
if (!(sender instanceof Player)) {
|
||||||
throw new CommandException("This command can only be used by a player.");
|
throw new CommandException("This command can only be used by a player.");
|
||||||
}
|
}
|
||||||
return player;
|
return (Player) sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|||||||
@@ -40,11 +40,14 @@ public class TeamScoreSubCommand extends SubCommand {
|
|||||||
String op = ctx.get("op");
|
String op = ctx.get("op");
|
||||||
int value = ctx.get("value");
|
int value = ctx.get("value");
|
||||||
|
|
||||||
int result = switch (op) {
|
int result;
|
||||||
case "add" -> service.addScore(team.getId(), name, value);
|
if ("add".equals(op)) {
|
||||||
case "set" -> service.setScore(team.getId(), name, value);
|
result = service.addScore(team.getId(), name, value);
|
||||||
default -> throw new IllegalStateException("unreachable: " + op);
|
} 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);
|
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. */
|
/** Convertit les valeurs Java non-natives SQL en types utilisables par JDBC. */
|
||||||
private static Object normalize(Object value) {
|
private static Object normalize(Object value) {
|
||||||
if (value == null) return null;
|
if (value == null) return null;
|
||||||
if (value instanceof UUID uuid) return uuid.toString();
|
if (value instanceof UUID) return value.toString();
|
||||||
if (value instanceof Enum<?> e) return e.name();
|
if (value instanceof Enum<?>) return ((Enum<?>) value).name();
|
||||||
if (value instanceof Boolean b) return b ? 1 : 0;
|
if (value instanceof Boolean) return ((Boolean) value) ? 1 : 0;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,56 @@ package fr.luc.crcore.player;
|
|||||||
|
|
||||||
import java.util.Objects;
|
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");
|
Objects.requireNonNull(profile, "profile");
|
||||||
if (rank < 1) {
|
if (rank < 1) {
|
||||||
throw new IllegalArgumentException("rank must be >= 1, got " + rank);
|
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.
|
// Tuples internes pour le load. Classes immutables manuelles (Java 11 compat).
|
||||||
private record TeamRow(
|
private static final class TeamRow {
|
||||||
UUID id, String name, String tag, TeamColor color,
|
final UUID id;
|
||||||
UUID leaderId, TeamVisibility visibility,
|
final String name;
|
||||||
String spawnWorld, Double spawnX, Double spawnY, Double spawnZ,
|
final String tag;
|
||||||
Float spawnYaw, Float spawnPitch
|
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;
|
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");
|
Objects.requireNonNull(team, "team");
|
||||||
if (rank < 1) {
|
if (rank < 1) {
|
||||||
throw new IllegalArgumentException("rank must be >= 1, got " + rank);
|
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 + "]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user