mirror of
https://github.com/PaperMC/Paper.git
synced 2026-11-04 08:52:01 -05:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
73116ac9dd | ||
|
|
eddc7b48f3 | ||
|
|
6abf5f0b74 | ||
|
|
12d8fe0beb | ||
|
|
09e9afd295 | ||
|
|
af71568bb3 | ||
|
|
e2ca477396 | ||
|
|
c2bb144fd5 | ||
|
|
76753219c4 | ||
|
|
a838a886dc |
No files matched your search
+1
-1
@@ -61,7 +61,7 @@ subprojects {
|
||||
|
||||
extensions.configure<PublishingExtension> {
|
||||
repositories {
|
||||
maven("https://repo.papermc.io/repository/maven-snapshots/") {
|
||||
maven("https://artifactory.papermc.io/artifactory/snapshots/") {
|
||||
name = "paperSnapshots"
|
||||
credentials(PasswordCredentials::class)
|
||||
}
|
||||
|
||||
+33
-1
@@ -41,7 +41,7 @@ import org.slf4j.LoggerFactory;
|
||||
* MavenLibraryResolver resolver = new MavenLibraryResolver();
|
||||
* resolver.addDependency(new Dependency(new DefaultArtifact("org.jooq:jooq:3.17.7"), null));
|
||||
* resolver.addRepository(new RemoteRepository.Builder(
|
||||
* "central", "default", "https://repo1.maven.org/maven2/"
|
||||
* "central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR
|
||||
* ).build());
|
||||
* }</pre>
|
||||
* <p>
|
||||
@@ -50,6 +50,21 @@ import org.slf4j.LoggerFactory;
|
||||
@NullMarked
|
||||
public class MavenLibraryResolver implements ClassPathLibrary {
|
||||
|
||||
/**
|
||||
* The default Maven Central mirror, configurable through the {@code PAPER_DEFAULT_CENTRAL_REPOSITORY} environment
|
||||
* variable. Use this instead of Maven Central directly when you do not have your own mirror, as using
|
||||
* Maven Central as a CDN is against the Maven Central Terms of Service, and you will cause users to hit
|
||||
* rate limits.
|
||||
*
|
||||
* <p>This repository is also used by the legacy {@link org.bukkit.plugin.java.LibraryLoader}.</p>
|
||||
*/
|
||||
public static final String MAVEN_CENTRAL_DEFAULT_MIRROR = getDefaultMavenCentralMirror();
|
||||
private static final List<String> MAVEN_CENTRAL_URLS = List.of(
|
||||
"https://repo1.maven.org/maven2",
|
||||
"http://repo1.maven.org/maven2",
|
||||
"https://repo.maven.apache.org/maven2",
|
||||
"http://repo.maven.apache.org/maven2"
|
||||
);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("MavenLibraryResolver");
|
||||
|
||||
private final RepositorySystem repository;
|
||||
@@ -105,6 +120,12 @@ public class MavenLibraryResolver implements ClassPathLibrary {
|
||||
* dependencies from
|
||||
*/
|
||||
public void addRepository(final RemoteRepository remoteRepository) {
|
||||
if (MAVEN_CENTRAL_URLS.stream().anyMatch(remoteRepository.getUrl()::startsWith)) {
|
||||
LOGGER.warn(
|
||||
"Use of Maven Central as a CDN is against the Maven Central Terms of Service. Use MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR instead.",
|
||||
new RuntimeException("Plugin used Maven Central for library resolution")
|
||||
);
|
||||
}
|
||||
this.repositories.add(remoteRepository);
|
||||
}
|
||||
|
||||
@@ -130,4 +151,15 @@ public class MavenLibraryResolver implements ClassPathLibrary {
|
||||
store.addLibrary(file.toPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static String getDefaultMavenCentralMirror() {
|
||||
String central = System.getenv("PAPER_DEFAULT_CENTRAL_REPOSITORY");
|
||||
if (central == null) {
|
||||
central = System.getProperty("org.bukkit.plugin.java.LibraryLoader.centralURL");
|
||||
}
|
||||
if (central == null) {
|
||||
central = "https://maven-central.storage-download.googleapis.com/maven2";
|
||||
}
|
||||
return central;
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,9 @@ public class PlayerRespawnEvent extends PlayerEvent {
|
||||
private Location respawnLocation;
|
||||
private final boolean isBedSpawn;
|
||||
private final boolean isAnchorSpawn;
|
||||
private final boolean missingRespawnBlock;
|
||||
private final RespawnReason respawnReason;
|
||||
private final java.util.Set<RespawnFlag> respawnFlags; // Paper
|
||||
private final java.util.Set<RespawnFlag> respawnFlags;
|
||||
|
||||
@Deprecated(since = "1.16.1", forRemoval = true)
|
||||
public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn) {
|
||||
@@ -33,23 +34,20 @@ public class PlayerRespawnEvent extends PlayerEvent {
|
||||
|
||||
@Deprecated(forRemoval = true)
|
||||
public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn, @NotNull final RespawnReason respawnReason) {
|
||||
// Paper start
|
||||
this(respawnPlayer, respawnLocation, isBedSpawn, isAnchorSpawn, respawnReason, com.google.common.collect.ImmutableSet.builder());
|
||||
this(respawnPlayer, respawnLocation, isBedSpawn, isAnchorSpawn, false, respawnReason, com.google.common.collect.ImmutableSet.builder());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn, @NotNull final RespawnReason respawnReason, @NotNull final com.google.common.collect.ImmutableSet.Builder<org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag> respawnFlags) {
|
||||
// Paper end
|
||||
public PlayerRespawnEvent(@NotNull final Player respawnPlayer, @NotNull final Location respawnLocation, final boolean isBedSpawn, final boolean isAnchorSpawn, final boolean missingRespawnBlock, @NotNull final RespawnReason respawnReason, @NotNull final com.google.common.collect.ImmutableSet.Builder<org.bukkit.event.player.PlayerRespawnEvent.RespawnFlag> respawnFlags) {
|
||||
super(respawnPlayer);
|
||||
this.respawnLocation = respawnLocation;
|
||||
this.isBedSpawn = isBedSpawn;
|
||||
this.isAnchorSpawn = isAnchorSpawn;
|
||||
this.respawnReason = respawnReason;
|
||||
// Paper start
|
||||
this.missingRespawnBlock = missingRespawnBlock;
|
||||
if (this.isBedSpawn) { respawnFlags.add(RespawnFlag.BED_SPAWN); }
|
||||
if (this.isAnchorSpawn) { respawnFlags.add(RespawnFlag.ANCHOR_SPAWN); }
|
||||
this.respawnFlags = respawnFlags.build();
|
||||
// Paper end
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +90,19 @@ public class PlayerRespawnEvent extends PlayerEvent {
|
||||
return isAnchorSpawn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the player is missing a valid respawn block.
|
||||
* <p>
|
||||
* This will occur if the players respawn block is obstructed,
|
||||
* or it is the first death after it was either destroyed or
|
||||
* in case of a respawn anchor, ran out of charges.
|
||||
*
|
||||
* @return whether the player is missing a valid respawn block
|
||||
*/
|
||||
public boolean isMissingRespawnBlock() {
|
||||
return this.missingRespawnBlock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reason this respawn event was called.
|
||||
*
|
||||
@@ -132,7 +143,6 @@ public class PlayerRespawnEvent extends PlayerEvent {
|
||||
PLUGIN;
|
||||
}
|
||||
|
||||
// Paper start
|
||||
/**
|
||||
* Get the set of flags that apply to this respawn.
|
||||
*
|
||||
@@ -157,5 +167,4 @@ public class PlayerRespawnEvent extends PlayerEvent {
|
||||
*/
|
||||
END_PORTAL,
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
// CHECKSTYLE:OFF
|
||||
package org.bukkit.plugin.java;
|
||||
|
||||
import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -49,6 +49,10 @@ public class LibraryLoader
|
||||
public static java.util.function.BiFunction<URL[], ClassLoader, URLClassLoader> LIBRARY_LOADER_FACTORY; // Paper - rewrite reflection in libraries
|
||||
public static java.util.function.Function<List<java.nio.file.Path>, List<java.nio.file.Path>> REMAPPER; // Paper - remap libraries
|
||||
|
||||
private static List<RemoteRepository> getRepositories() {
|
||||
return List.of(new RemoteRepository.Builder("central", "default", MavenLibraryResolver.MAVEN_CENTRAL_DEFAULT_MIRROR).build());
|
||||
}
|
||||
|
||||
public LibraryLoader(@NotNull Logger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
@@ -78,7 +82,7 @@ public class LibraryLoader
|
||||
session.setSystemProperties( System.getProperties() );
|
||||
session.setReadOnly();
|
||||
|
||||
this.repositories = repository.newResolutionRepositories( session, Arrays.asList( new RemoteRepository.Builder( "central", "default", "https://repo.maven.apache.org/maven2" ).build() ) );
|
||||
this.repositories = repository.newResolutionRepositories( session, getRepositories() );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -11,7 +11,7 @@ plugins {
|
||||
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||
|
||||
dependencies {
|
||||
mache("io.papermc:mache:1.21.4+build.7")
|
||||
mache("io.papermc:mache:1.21.4+build.8")
|
||||
paperclip("io.papermc:paperclip:3.0.3")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||
}
|
||||
@@ -143,8 +143,7 @@ dependencies {
|
||||
implementation("io.netty:netty-codec-haproxy:4.1.115.Final") // Add support for proxy protocol
|
||||
implementation("org.apache.logging.log4j:log4j-iostreams:2.24.1")
|
||||
implementation("org.ow2.asm:asm-commons:9.7.1")
|
||||
implementation("org.spongepowered:configurate-yaml:4.2.0-20250225.064233-199")
|
||||
implementation("org.spongepowered:configurate-core:4.2.0-20250225.064233-204") // Pinned dependency of above pinned yaml snapshot.
|
||||
implementation("org.spongepowered:configurate-yaml:4.2.0")
|
||||
implementation("commons-lang:commons-lang:2.6")
|
||||
runtimeOnly("org.xerial:sqlite-jdbc:3.47.0.0")
|
||||
runtimeOnly("com.mysql:mysql-connector-j:9.1.0")
|
||||
|
||||
@@ -1112,7 +1112,7 @@ index 0000000000000000000000000000000000000000..a814512fcfb85312474ae2c2c2144384
|
||||
+}
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..1acea58838f057ab87efd103cbecb6f5aeaef393
|
||||
index 0000000000000000000000000000000000000000..25bceb88f7d040034a740c18ed5a3aab50b0c72b
|
||||
--- /dev/null
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
|
||||
@@ -0,0 +1,1700 @@
|
||||
@@ -2261,7 +2261,7 @@ index 0000000000000000000000000000000000000000..1acea58838f057ab87efd103cbecb6f5
|
||||
+ LOGGER.error("Failed to decompress chunk data for task: " + this.toString(), thr);
|
||||
+ }
|
||||
+
|
||||
+ if (compoundTag == null) {
|
||||
+ if (throwable == null && compoundTag == null) {
|
||||
+ // need to re-try from the start
|
||||
+ this.scheduleReadIO();
|
||||
+ return;
|
||||
@@ -27496,7 +27496,7 @@ index d1f235ebd835f58cf0c703c3a64d29825d98e183..080091efc19bc768bb9a660f366c42e8
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 0bb610f12e3ddda649ecb5ad62ffdc7bfd243223..19428343b37c9b739b3d28984d52e257f85f253f 100644
|
||||
index 6e2dcbf45fa424e910a01dd44c85af72d3a35a36..5f08126b011d945af0c330f5477351e1e31866bb 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -178,7 +178,7 @@ import net.minecraft.world.scores.Team;
|
||||
@@ -27508,7 +27508,7 @@ index 0bb610f12e3ddda649ecb5ad62ffdc7bfd243223..19428343b37c9b739b3d28984d52e257
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32;
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
@@ -395,6 +395,36 @@ public class ServerPlayer extends Player {
|
||||
@@ -388,6 +388,36 @@ public class ServerPlayer extends Player {
|
||||
public @Nullable String clientBrandName = null; // Paper - Brand support
|
||||
public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - Add API for quit reason; there are a lot of changes to do if we change all methods leading to the event
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ index 409c1134327bfcc338c3ac5e658a83cc396645d1..cc2d442682496197d29ace79b22e6cf6
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
this.runAllTasks(); // Paper - move runAllTasks() into full server tick (previously for timings)
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 42995dac38248032b6abecc27124adfe12ec4cab..28a67294c3e678e01d5dfd68b950234213d8e55c 100644
|
||||
index e77e111cad399da8b6885418337c8e495328dc71..0651a536ad38c3c6d1ac2423b6d351738719339f 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1318,6 +1318,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -64,7 +64,7 @@ index 42995dac38248032b6abecc27124adfe12ec4cab..28a67294c3e678e01d5dfd68b9502342
|
||||
+ }
|
||||
+
|
||||
+ if (doFull) {
|
||||
+ this.saveLevelData(true);
|
||||
+ this.saveLevelData(false);
|
||||
+ }
|
||||
+ // chunk autosave is already called by the ChunkSystem during unload processing (ChunkMap#processUnloads)
|
||||
+ // Copied from save()
|
||||
@@ -83,7 +83,7 @@ index 42995dac38248032b6abecc27124adfe12ec4cab..28a67294c3e678e01d5dfd68b9502342
|
||||
// Paper start - add close param
|
||||
this.save(progress, flush, skipSave, false);
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index f44600604a7bf68c990cd74a1ac2d7900ff6e88e..69b8074e18775c846d5991f40bc2e0a5186500ac 100644
|
||||
index 2e54c38272ed93286678baaaf18a234be65f28f0..a5e9e0e7d60ed79db01bd526f039ca07440826c1 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -180,6 +180,7 @@ import org.slf4j.Logger;
|
||||
@@ -95,7 +95,7 @@ index f44600604a7bf68c990cd74a1ac2d7900ff6e88e..69b8074e18775c846d5991f40bc2e0a5
|
||||
private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10;
|
||||
private static final int FLY_STAT_RECORDING_SPEED = 25;
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 7d1d4abfb04829d8c4722e326c6c6b8fb2ab91f4..5a4960fdbd97d830ac79845697eea9372c48a13b 100644
|
||||
index 065f4c810439dde464529b54ae300ecfcb1c2c31..c9dbe659374e3ce140316116e05110567e44b810 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -482,6 +482,7 @@ public abstract class PlayerList {
|
||||
|
||||
@@ -78,10 +78,10 @@ index 87d4291a3944f706a694536da6de0f28c548ab8d..5576bf1d1d70ab7a010653d3207909b5
|
||||
profiler.popPush("spawnAndTick");
|
||||
boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 02fb30a3adf92de0795aee213caf94a228b01ca0..67f6e40216e0be063a3cfb61427f095f7c74d785 100644
|
||||
index 37134adbe1e669be74543b3d5407fe1fa610ece9..ca542eb32cf14f15104235fa924cc3579657dc96 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -375,6 +375,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -368,6 +368,10 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public boolean queueHealthUpdatePacket;
|
||||
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
|
||||
// Paper end - cancellable death event
|
||||
|
||||
+2
-2
@@ -60,10 +60,10 @@ index 5576bf1d1d70ab7a010653d3207909b5de867e70..6540b2d6a1062d883811ce240c49d30d
|
||||
spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
} else {
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 67f6e40216e0be063a3cfb61427f095f7c74d785..3de65c4025be91d938a350c884975cb6edc234d3 100644
|
||||
index ca542eb32cf14f15104235fa924cc3579657dc96..60966b42131c4802e49e838451ff688665e7301e 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -379,6 +379,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -372,6 +372,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
|
||||
public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS];
|
||||
// Paper end - Optional per player mob spawns
|
||||
|
||||
+6
-6
@@ -6,7 +6,7 @@ Subject: [PATCH] Optimise collision checking in player move packet handling
|
||||
Move collision logic to just the hasNewCollision call instead of getCubes + hasNewCollision
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e9876667fd1807 100644
|
||||
index 73ca5aff2365df4f31c960989778b245a7f7bcd3..a0fea6f87000e17d1affc377d2b7e617ce345db6 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -563,7 +563,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -88,7 +88,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1371,7 +1403,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1372,7 +1404,7 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
|
||||
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||
@@ -1410,6 +1442,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1411,6 +1443,7 @@ public class ServerGamePacketListenerImpl
|
||||
boolean flag1 = this.player.verticalCollisionBelow;
|
||||
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||
this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||
@@ -105,7 +105,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
|
||||
// Paper start - prevent position desync
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
return; // ... thanks Mojang for letting move calls teleport across dimensions.
|
||||
@@ -1442,7 +1475,17 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1443,7 +1476,17 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
// Paper start - Add fail move event
|
||||
@@ -124,7 +124,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
|
||||
if (teleportBack) {
|
||||
io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.CLIPPED_INTO_BLOCK,
|
||||
toX, toY, toZ, toYaw, toPitch, false);
|
||||
@@ -1578,7 +1621,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1579,7 +1622,7 @@ public class ServerGamePacketListenerImpl
|
||||
|
||||
private boolean updateAwaitingTeleport() {
|
||||
if (this.awaitingPositionFromClient != null) {
|
||||
@@ -133,7 +133,7 @@ index 12c83cb084563a4e3f7f357d8b600941544ef2b0..90e582ca30851857add5e2d830e98766
|
||||
this.awaitingTeleportTime = this.tickCount;
|
||||
this.teleport(
|
||||
this.awaitingPositionFromClient.x,
|
||||
@@ -1597,6 +1640,33 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1598,6 +1641,33 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ a portal in spectator mode and then later switching to creative mode
|
||||
would portal the player.
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 90e582ca30851857add5e2d830e9876667fd1807..c569cdfa4cba4f65892ffd4045c611837049f440 100644
|
||||
index a0fea6f87000e17d1affc377d2b7e617ce345db6..a2c70d36f79b7f8560923e098e52fa7f82ca7416 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -659,7 +659,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -23,7 +23,7 @@ index 90e582ca30851857add5e2d830e9876667fd1807..c569cdfa4cba4f65892ffd4045c61183
|
||||
Vec3 vec3 = new Vec3(rootVehicle.getX() - x, rootVehicle.getY() - y, rootVehicle.getZ() - z);
|
||||
this.handlePlayerKnownMovement(vec3);
|
||||
rootVehicle.setOnGroundWithMovement(packet.onGround(), vec3);
|
||||
@@ -1577,7 +1577,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -1578,7 +1578,7 @@ public class ServerGamePacketListenerImpl
|
||||
Vec3 vec3 = new Vec3(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
|
||||
this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3);
|
||||
this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.isOnGround());
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
@Nullable
|
||||
private Vec3 startingToFallPosition;
|
||||
@Nullable
|
||||
@@ -258,6 +_,20 @@
|
||||
@@ -258,6 +_,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,6 @@
|
||||
+ ServerPlayer.this.connection.send(new ClientboundContainerSetSlotPacket(ServerPlayer.this.inventoryMenu.containerId, ServerPlayer.this.inventoryMenu.incrementStateId(), net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT, ServerPlayer.this.inventoryMenu.getSlot(net.minecraft.world.inventory.InventoryMenu.SHIELD_SLOT).getItem().copy()));
|
||||
+ }
|
||||
+ // Paper end - Sync offhand slot in menus
|
||||
+
|
||||
+ // Paper start - add flag to simplify remote matching logic
|
||||
+ @Override
|
||||
+ public ServerPlayer player() {
|
||||
+ return ServerPlayer.this;
|
||||
+ }
|
||||
+ // Paper end - add flag to simplify remote matching logic
|
||||
+
|
||||
@Override
|
||||
public void sendSlotChange(AbstractContainerMenu container, int slot, ItemStack itemStack) {
|
||||
@@ -518,7 +511,7 @@
|
||||
BlockPos respawnPosition = this.getRespawnPosition();
|
||||
float respawnAngle = this.getRespawnAngle();
|
||||
boolean isRespawnForced = this.isRespawnForced();
|
||||
@@ -973,13 +_,66 @@
|
||||
@@ -973,13 +_,67 @@
|
||||
Optional<ServerPlayer.RespawnPosAngle> optional = findRespawnAndUseSpawnBlock(level, respawnPosition, respawnAngle, isRespawnForced, useCharge);
|
||||
if (optional.isPresent()) {
|
||||
ServerPlayer.RespawnPosAngle respawnPosAngle = optional.get();
|
||||
@@ -560,6 +553,7 @@
|
||||
+ location,
|
||||
+ isBedSpawn,
|
||||
+ isAnchorSpawn,
|
||||
+ teleportTransition.missingRespawnBlock(),
|
||||
+ respawnReason,
|
||||
+ builder
|
||||
+ );
|
||||
|
||||
+8
-1
@@ -396,7 +396,14 @@
|
||||
this.player.setClientLoaded(true);
|
||||
}
|
||||
|
||||
@@ -521,6 +_,7 @@
|
||||
@@ -515,12 +_,14 @@
|
||||
|
||||
@Override
|
||||
public void handleBundleItemSelectedPacket(ServerboundSelectBundleItemPacket packet) {
|
||||
+ PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // Paper
|
||||
this.player.containerMenu.setSelectedBundleItemIndex(packet.slotId(), packet.selectedItemIndex());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRecipeBookChangeSettingsPacket(ServerboundRecipeBookChangeSettingsPacket packet) {
|
||||
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
|
||||
|
||||
-35
@@ -72,41 +72,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +_,7 @@
|
||||
private void synchronizeSlotToRemote(int slotIndex, ItemStack stack, Supplier<ItemStack> supplier) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
ItemStack itemStack = this.remoteSlots.get(slotIndex);
|
||||
- if (!ItemStack.matches(itemStack, stack)) {
|
||||
+ if (!this.matchesRemote(itemStack, stack)) { // Paper - add flag to simplify remote matching logic
|
||||
ItemStack itemStack1 = supplier.get();
|
||||
this.remoteSlots.set(slotIndex, itemStack1);
|
||||
if (this.synchronizer != null) {
|
||||
@@ -267,7 +_,7 @@
|
||||
|
||||
private void synchronizeCarriedToRemote() {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
- if (!ItemStack.matches(this.getCarried(), this.remoteCarried)) {
|
||||
+ if (!this.matchesRemote(this.getCarried(), this.remoteCarried)) { // Paper - add flag to simplify remote matching logic
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
|
||||
@@ -276,6 +_,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start - add flag to simplify remote matching logic
|
||||
+ private boolean matchesRemote(final ItemStack stack, final ItemStack other) {
|
||||
+ if (this.synchronizer != null && this.synchronizer.player() != null && this.synchronizer.player().getBukkitEntity().simplifyContainerDesyncCheck()) {
|
||||
+ // Only check the item type and count
|
||||
+ return stack == other || (stack.getCount() == other.getCount() && ItemStack.isSameItem(stack, other));
|
||||
+ }
|
||||
+ return ItemStack.matches(stack, other);
|
||||
+ }
|
||||
+ // Paper end - add flag to simplify remote matching logic
|
||||
+
|
||||
public void setRemoteSlot(int slot, ItemStack stack) {
|
||||
this.remoteSlots.set(slot, stack.copy());
|
||||
}
|
||||
@@ -343,6 +_,7 @@
|
||||
this.resetQuickCraft();
|
||||
}
|
||||
|
||||
+1
-7
@@ -1,15 +1,9 @@
|
||||
--- a/net/minecraft/world/inventory/ContainerSynchronizer.java
|
||||
+++ b/net/minecraft/world/inventory/ContainerSynchronizer.java
|
||||
@@ -11,4 +_,12 @@
|
||||
@@ -11,4 +_,6 @@
|
||||
void sendCarriedChange(AbstractContainerMenu containerMenu, ItemStack stack);
|
||||
|
||||
void sendDataChange(AbstractContainerMenu container, int id, int value);
|
||||
+
|
||||
+ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus
|
||||
+
|
||||
+ // Paper start - add flag to simplify remote matching logic
|
||||
+ default net.minecraft.server.level.@org.jspecify.annotations.Nullable ServerPlayer player() {
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end - add flag to simplify remote matching logic
|
||||
}
|
||||
+25
@@ -36,3 +36,28 @@
|
||||
return Math.max(fraction.divideBy(BundleContents.getWeight(stack)).intValue(), 0);
|
||||
}
|
||||
|
||||
@@ -206,15 +_,21 @@
|
||||
}
|
||||
|
||||
public void toggleSelectedItem(int selectedItem) {
|
||||
- this.selectedItem = this.selectedItem != selectedItem && selectedItem < this.items.size() ? selectedItem : -1;
|
||||
- }
|
||||
+ this.selectedItem = !indexIsOutsideAllowedBounds(selectedItem) ? selectedItem : -1; // Paper
|
||||
+ }
|
||||
+
|
||||
+ // Paper start
|
||||
+ private boolean indexIsOutsideAllowedBounds(int param0) {
|
||||
+ return param0 < 0 || param0 >= this.items.size();
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
@Nullable
|
||||
public ItemStack removeOne() {
|
||||
if (this.items.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
- int i = this.selectedItem != -1 && this.selectedItem < this.items.size() ? this.selectedItem : 0;
|
||||
+ int i = !indexIsOutsideAllowedBounds(this.selectedItem) ? this.selectedItem : 0; // Paper
|
||||
ItemStack itemStack = this.items.remove(i).copy();
|
||||
this.weight = this.weight.subtract(BundleContents.getWeight(itemStack).multiplyBy(Fraction.getFraction(itemStack.getCount(), 1)));
|
||||
this.toggleSelectedItem(-1);
|
||||
@@ -3,6 +3,7 @@ package io.papermc.paper.configuration;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.papermc.paper.FeatureHooks;
|
||||
import io.papermc.paper.configuration.constraint.Constraints;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.WriteKeyBack;
|
||||
import io.papermc.paper.configuration.type.number.DoubleOr;
|
||||
import io.papermc.paper.configuration.type.number.IntOr;
|
||||
import io.papermc.paper.util.ItemObfuscationBinding;
|
||||
@@ -28,7 +29,7 @@ import java.util.Set;
|
||||
@SuppressWarnings({"CanBeFinal", "FieldCanBeLocal", "FieldMayBeFinal", "NotNullFieldNotInitialized", "InnerClassMayBeStatic"})
|
||||
public class GlobalConfiguration extends ConfigurationPart {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
static final int CURRENT_VERSION = 29; // (when you change the version, change the comment, so it conflicts on rebases): <insert changes here>
|
||||
static final int CURRENT_VERSION = 30; // (when you change the version, change the comment, so it conflicts on rebases): upgrade packet to use ids
|
||||
private static GlobalConfiguration instance;
|
||||
public static boolean isFirstStart = false;
|
||||
public static GlobalConfiguration get() {
|
||||
@@ -185,8 +186,6 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public CompressionFormat compressionFormat = CompressionFormat.ZLIB;
|
||||
@Comment("This setting controls if equipment should be updated when handling certain player actions.")
|
||||
public boolean updateEquipmentOnPlayerActions = true;
|
||||
@Comment("Only checks an item's amount and type instead of its full data during inventory desync checks.")
|
||||
public boolean simplifyRemoteItemMatching = false;
|
||||
|
||||
public enum CompressionFormat {
|
||||
GZIP,
|
||||
@@ -276,7 +275,7 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public class PacketLimiter extends ConfigurationPart {
|
||||
public Component kickMessage = Component.translatable("disconnect.exceeded_packet_rate", NamedTextColor.RED);
|
||||
public PacketLimit allPackets = new PacketLimit(7.0, 500.0, PacketLimit.ViolateAction.KICK);
|
||||
public Map<Class<? extends Packet<?>>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP));
|
||||
public Map<@WriteKeyBack Class<? extends Packet<?>>, PacketLimit> overrides = Map.of(ServerboundPlaceRecipePacket.class, new PacketLimit(4.0, 5.0, PacketLimit.ViolateAction.DROP));
|
||||
|
||||
@ConfigSerializable
|
||||
public record PacketLimit(@Required double interval, @Required double maxPacketRate, ViolateAction action) {
|
||||
|
||||
@@ -5,21 +5,25 @@ import com.google.common.collect.Table;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
|
||||
import io.papermc.paper.configuration.mapping.Definition;
|
||||
import io.papermc.paper.configuration.mapping.FieldProcessor;
|
||||
import io.papermc.paper.configuration.mapping.InnerClassFieldDiscoverer;
|
||||
import io.papermc.paper.configuration.mapping.MergeMap;
|
||||
import io.papermc.paper.configuration.serializer.ComponentSerializer;
|
||||
import io.papermc.paper.configuration.serializer.EnumValueSerializer;
|
||||
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
|
||||
import io.papermc.paper.configuration.serializer.PacketClassSerializer;
|
||||
import io.papermc.paper.configuration.serializer.ServerboundPacketClassSerializer;
|
||||
import io.papermc.paper.configuration.serializer.ResourceLocationSerializer;
|
||||
import io.papermc.paper.configuration.serializer.StringRepresentableSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.FastutilMapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.TableSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.TableSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.FastutilMapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.MapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.registry.RegistryHolderSerializer;
|
||||
import io.papermc.paper.configuration.serializer.registry.RegistryValueSerializer;
|
||||
import io.papermc.paper.configuration.transformation.Transformations;
|
||||
import io.papermc.paper.configuration.transformation.global.LegacyPaperConfig;
|
||||
import io.papermc.paper.configuration.transformation.global.versioned.V29_LogIPs;
|
||||
import io.papermc.paper.configuration.transformation.global.versioned.V30_PacketIds;
|
||||
import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
|
||||
import io.papermc.paper.configuration.transformation.world.LegacyPaperWorldConfig;
|
||||
import io.papermc.paper.configuration.transformation.world.versioned.V29_ZeroWorldHeight;
|
||||
@@ -41,10 +45,12 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
@@ -192,7 +198,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
}
|
||||
|
||||
private static ObjectMapper.Factory.Builder defaultGlobalFactoryBuilder(ObjectMapper.Factory.Builder builder) {
|
||||
return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig());
|
||||
return builder.addDiscoverer(InnerClassFieldDiscoverer.globalConfig(defaultFieldProcessors()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -205,7 +211,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
return options
|
||||
.header(GLOBAL_HEADER)
|
||||
.serializers(builder -> builder
|
||||
.register(new PacketClassSerializer())
|
||||
.register(new ServerboundPacketClassSerializer())
|
||||
.register(new RegistryValueSerializer<>(new TypeToken<DataComponentType<?>>() {}, registryAccess, Registries.DATA_COMPONENT_TYPE, false))
|
||||
);
|
||||
}
|
||||
@@ -228,7 +234,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
return super.createWorldObjectMapperFactoryBuilder(contextMap)
|
||||
.addNodeResolver(new RequiresSpigotInitialization.Factory(contextMap.require(SPIGOT_WORLD_CONFIG_CONTEXT_KEY).get()))
|
||||
.addNodeResolver(new NestedSetting.Factory())
|
||||
.addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap)));
|
||||
.addDiscoverer(InnerClassFieldDiscoverer.worldConfig(createWorldConfigInstance(contextMap), defaultFieldProcessors()));
|
||||
}
|
||||
|
||||
private static WorldConfiguration createWorldConfigInstance(ContextMap contextMap) {
|
||||
@@ -287,6 +293,7 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
|
||||
final ConfigurationTransformation.VersionedBuilder versionedBuilder = Transformations.versionedBuilder();
|
||||
V29_LogIPs.apply(versionedBuilder);
|
||||
V30_PacketIds.apply(versionedBuilder);
|
||||
// ADD FUTURE VERSIONED TRANSFORMS TO versionedBuilder HERE
|
||||
versionedBuilder.build().apply(node);
|
||||
}
|
||||
@@ -330,6 +337,12 @@ public class PaperConfigurations extends Configurations<GlobalConfiguration, Wor
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Definition<? extends Annotation, ?, ? extends FieldProcessor.Factory<?, ?>>> defaultFieldProcessors() {
|
||||
return List.of(
|
||||
MergeMap.DEFINITION
|
||||
);
|
||||
}
|
||||
|
||||
private static ContextMap createWorldContextMap(ServerLevel level) {
|
||||
return createWorldContextMap(level.levelStorageAccess.levelDirectory.path(), level.serverLevelData.getLevelName(), level.dimension().location(), level.spigotConfig, level.registryAccess(), level.getGameRules());
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.papermc.paper.configuration.legacy.MaxEntityCollisionsInitializer;
|
||||
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
|
||||
import io.papermc.paper.configuration.mapping.MergeMap;
|
||||
import io.papermc.paper.configuration.serializer.NbtPathSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.ThrowExceptions;
|
||||
import io.papermc.paper.configuration.transformation.world.FeatureSeedsGeneration;
|
||||
import io.papermc.paper.configuration.type.BooleanOrDefault;
|
||||
import io.papermc.paper.configuration.type.DespawnRange;
|
||||
@@ -191,15 +191,14 @@ public class WorldConfiguration extends ConfigurationPart {
|
||||
}
|
||||
}
|
||||
|
||||
@MapSerializer.ThrowExceptions
|
||||
public Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
|
||||
public @ThrowExceptions Reference2ObjectMap<EntityType<?>, IntOr.Disabled> despawnTime = Util.make(new Reference2ObjectOpenHashMap<>(), map -> {
|
||||
map.put(EntityType.SNOWBALL, IntOr.Disabled.DISABLED);
|
||||
map.put(EntityType.LLAMA_SPIT, IntOr.Disabled.DISABLED);
|
||||
});
|
||||
|
||||
@PostProcess
|
||||
public void precomputeDespawnDistances() throws SerializationException {
|
||||
for (Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
|
||||
for (final Map.Entry<MobCategory, DespawnRangePair> entry : this.despawnRanges.entrySet()) {
|
||||
final MobCategory category = entry.getKey();
|
||||
final DespawnRangePair range = entry.getValue();
|
||||
range.hard().preComputed(category.getDespawnDistance(), category.getSerializedName());
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public record Definition<A extends Annotation, T, F>(Class<A> annotation, TypeToken<T> type, F factory) {
|
||||
|
||||
public Definition(final Class<A> annotation, final Class<T> type, final F factory) {
|
||||
this(annotation, TypeToken.get(type), factory);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
public record DeserializedFieldInfo<V>(AnnotatedType fieldType, Object deserializedValue, @Nullable FieldProcessor<V> processor) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public @Nullable V runProcessor(final @Nullable Object valueInField, final @Nullable Object deserializedValue) throws SerializationException {
|
||||
checkState(this.processor != null, "processor is null");
|
||||
return this.processor.process(this.fieldType, (V) deserializedValue, (V) valueInField);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public interface FieldProcessor<V> {
|
||||
|
||||
@Nullable V process(final AnnotatedType target, @Nullable V deserializedValue, @Nullable V valueInField) throws SerializationException;
|
||||
|
||||
interface Factory<A extends Annotation, T> {
|
||||
|
||||
FieldProcessor<T> make(A data, AnnotatedType annotatedType);
|
||||
}
|
||||
}
|
||||
+66
-15
@@ -1,52 +1,103 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.papermc.paper.configuration.ConfigurationPart;
|
||||
import io.papermc.paper.configuration.WorldConfiguration;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SequencedMap;
|
||||
import java.util.function.Supplier;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||
import static java.util.Objects.requireNonNullElseGet;
|
||||
|
||||
public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, Object>> {
|
||||
public final class InnerClassFieldDiscoverer implements FieldDiscoverer<Map<Field, DeserializedFieldInfo<?>>> {
|
||||
|
||||
private final InnerClassInstanceSupplier instanceSupplier;
|
||||
private final FieldDiscoverer<Map<Field, Object>> delegate;
|
||||
private final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public InnerClassFieldDiscoverer(final Map<Class<?>, Object> initialOverrides) {
|
||||
this.instanceSupplier = new InnerClassInstanceSupplier(initialOverrides);
|
||||
this.delegate = (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(this.instanceSupplier);
|
||||
private InnerClassFieldDiscoverer(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer<Map<Field, Object>> delegate, final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> fieldProcessors) {
|
||||
this.instanceSupplier = instanceSupplier;
|
||||
this.delegate = delegate;
|
||||
this.fieldProcessors = fieldProcessors;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public @Nullable <V> InstanceFactory<Map<Field, Object>> discover(final AnnotatedType target, final FieldCollector<Map<Field, Object>, V> collector) throws SerializationException {
|
||||
public @Nullable <V> InstanceFactory<Map<Field, DeserializedFieldInfo<?>>> discover(final AnnotatedType target, final FieldCollector<Map<Field, DeserializedFieldInfo<?>>, V> collector) throws SerializationException {
|
||||
final Class<?> clazz = erase(target.getType());
|
||||
if (ConfigurationPart.class.isAssignableFrom(clazz)) {
|
||||
final FieldDiscoverer.@Nullable InstanceFactory<Map<Field, Object>> instanceFactoryDelegate = this.delegate.<V>discover(target, (name, type, annotations, deserializer, serializer) -> {
|
||||
if (!erase(type.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
|
||||
collector.accept(name, type, annotations, deserializer, serializer);
|
||||
// we don't care about the returned instance factory, we just need to call it to collect fields
|
||||
final Object dummyInstance = this.delegate.<V>discover(target, (name, fieldType, container, deserializer, serializer) -> {
|
||||
if (!erase(fieldType.getType()).equals(clazz.getEnclosingClass())) { // don't collect synth fields for inner classes
|
||||
FieldProcessor<?> processor = null;
|
||||
processor: for (final Annotation annotation : container.getAnnotations()) {
|
||||
final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> definitions = this.fieldProcessors.get(annotation.annotationType());
|
||||
if (definitions != null) {
|
||||
for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> def : definitions) {
|
||||
if (GenericTypeReflector.isSuperType(def.type().getType(), GenericTypeReflector.box(fieldType.getType()))) {
|
||||
processor = ((FieldProcessor.Factory)def.factory()).make(annotation, fieldType);
|
||||
break processor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final FieldProcessor<?> finalProcessor = processor;
|
||||
collector.accept(
|
||||
name,
|
||||
fieldType,
|
||||
container,
|
||||
(intermediate, newValue, implicitInitializer) -> {
|
||||
// we only create this map to collect the field, it should only ever have 1 entry
|
||||
final SequencedMap<Field, Object> map = new LinkedHashMap<>();
|
||||
deserializer.accept(map, newValue, implicitInitializer);
|
||||
final Object deserializedValue;
|
||||
deserializedValue = requireNonNullElseGet(newValue, () -> new ImplicitProvider(implicitInitializer));
|
||||
intermediate.put(map.firstEntry().getKey(), new DeserializedFieldInfo<>(fieldType, deserializedValue, finalProcessor));
|
||||
},
|
||||
serializer
|
||||
);
|
||||
}
|
||||
});
|
||||
if (instanceFactoryDelegate instanceof MutableInstanceFactory<Map<Field, Object>> mutableInstanceFactoryDelegate) {
|
||||
return new InnerClassInstanceFactory(this.instanceSupplier, mutableInstanceFactoryDelegate, target);
|
||||
if (dummyInstance == null) {
|
||||
return null;
|
||||
}
|
||||
return new InnerClassInstanceFactory(this.instanceSupplier, target);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FieldDiscoverer<?> worldConfig(WorldConfiguration worldConfiguration) {
|
||||
record ImplicitProvider(Supplier<Object> provider) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static InnerClassFieldDiscoverer create(final Map<Class<?>, Object> overrides, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
|
||||
final Map<Class<? extends Annotation>, List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>>> processors = new LinkedHashMap<>();
|
||||
for (final Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>> definition : fieldProcessors) {
|
||||
processors.computeIfAbsent(definition.annotation(), k -> new ArrayList<>()).add(definition);
|
||||
}
|
||||
final InnerClassInstanceSupplier instanceSupplier = new InnerClassInstanceSupplier(overrides);
|
||||
return new InnerClassFieldDiscoverer(instanceSupplier, (FieldDiscoverer<Map<Field, Object>>) FieldDiscoverer.object(instanceSupplier), processors);
|
||||
}
|
||||
|
||||
public static FieldDiscoverer<?> worldConfig(final WorldConfiguration worldConfiguration, final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
|
||||
final Map<Class<?>, Object> overrides = Map.of(
|
||||
WorldConfiguration.class, worldConfiguration
|
||||
);
|
||||
return new InnerClassFieldDiscoverer(overrides);
|
||||
return create(overrides, fieldProcessors);
|
||||
}
|
||||
|
||||
public static FieldDiscoverer<?> globalConfig() {
|
||||
return new InnerClassFieldDiscoverer(Collections.emptyMap());
|
||||
public static FieldDiscoverer<?> globalConfig(final List<Definition<?, ?, ? extends FieldProcessor.Factory<?, ?>>> fieldProcessors) {
|
||||
return create(Collections.emptyMap(), fieldProcessors);
|
||||
}
|
||||
}
|
||||
+37
-25
@@ -2,56 +2,68 @@ package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
import org.spongepowered.configurate.objectmapping.FieldDiscoverer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||
|
||||
final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> {
|
||||
final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstanceFactory<Map<Field, DeserializedFieldInfo<?>>> {
|
||||
|
||||
private final InnerClassInstanceSupplier instanceSupplier;
|
||||
private final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback;
|
||||
private final AnnotatedType targetType;
|
||||
|
||||
InnerClassInstanceFactory(final InnerClassInstanceSupplier instanceSupplier, final FieldDiscoverer.MutableInstanceFactory<Map<Field, Object>> fallback, final AnnotatedType targetType) {
|
||||
InnerClassInstanceFactory(
|
||||
final InnerClassInstanceSupplier instanceSupplier,
|
||||
final AnnotatedType targetType
|
||||
) {
|
||||
this.instanceSupplier = instanceSupplier;
|
||||
this.fallback = fallback;
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Field, Object> begin() {
|
||||
return this.fallback.begin();
|
||||
public Map<Field, DeserializedFieldInfo<?>> begin() {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void complete(final Object instance, final Map<Field, Object> intermediate) throws SerializationException {
|
||||
final Iterator<Map.Entry<Field, Object>> iter = intermediate.entrySet().iterator();
|
||||
try {
|
||||
while (iter.hasNext()) { // manually merge any mergeable maps
|
||||
Map.Entry<Field, Object> entry = iter.next();
|
||||
if (entry.getKey().isAnnotationPresent(MergeMap.class) && Map.class.isAssignableFrom(entry.getKey().getType()) && intermediate.get(entry.getKey()) instanceof Map<?, ?> map) {
|
||||
iter.remove();
|
||||
Map<Object, Object> existingMap = (Map<Object, Object>) entry.getKey().get(instance);
|
||||
if (existingMap != null) {
|
||||
existingMap.putAll(map);
|
||||
} else {
|
||||
entry.getKey().set(instance, entry.getValue());
|
||||
public void complete(final Object instance, final Map<Field, DeserializedFieldInfo<?>> intermediate) throws SerializationException {
|
||||
// modeled off of native ObjectFieldDiscoverer
|
||||
for (final Map.Entry<Field, DeserializedFieldInfo<?>> entry : intermediate.entrySet()) {
|
||||
final boolean hasProcessor = entry.getValue().processor() != null;
|
||||
try {
|
||||
final Object valueInField = entry.getKey().get(instance);
|
||||
if (entry.getValue().deserializedValue() instanceof InnerClassFieldDiscoverer.ImplicitProvider(final Supplier<Object> provider)) {
|
||||
Object newFieldValue = provider.get();
|
||||
if (hasProcessor) {
|
||||
newFieldValue = entry.getValue().runProcessor(valueInField, newFieldValue);
|
||||
}
|
||||
if (newFieldValue != null) {
|
||||
if (valueInField == null) {
|
||||
entry.getKey().set(instance, newFieldValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Object newFieldValue = entry.getValue().deserializedValue();
|
||||
if (hasProcessor) {
|
||||
newFieldValue = entry.getValue().runProcessor(valueInField, newFieldValue);
|
||||
}
|
||||
entry.getKey().set(instance, newFieldValue);
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new SerializationException(this.targetType.getType(), e);
|
||||
} catch (final SerializationException ex) {
|
||||
ex.initType(entry.getValue().fieldType());
|
||||
|
||||
}
|
||||
} catch (final IllegalAccessException e) {
|
||||
throw new SerializationException(this.targetType.getType(), e);
|
||||
}
|
||||
this.fallback.complete(instance, intermediate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object complete(final Map<Field, Object> intermediate) throws SerializationException {
|
||||
public Object complete(final Map<Field, DeserializedFieldInfo<?>> intermediate) throws SerializationException {
|
||||
final Object targetInstance = Objects.requireNonNull(this.instanceSupplier.instanceMap().get(erase(this.targetType.getType())), () -> this.targetType.getType() + " must already have an instance created");
|
||||
this.complete(targetInstance, intermediate);
|
||||
return targetInstance;
|
||||
@@ -59,6 +71,6 @@ final class InnerClassInstanceFactory implements FieldDiscoverer.MutableInstance
|
||||
|
||||
@Override
|
||||
public boolean canCreateInstances() {
|
||||
return this.fallback.canCreateInstances();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -57,7 +57,7 @@ final class InnerClassInstanceSupplier implements CheckedFunction<AnnotatedType,
|
||||
final Object instance = instanceSupplier.get();
|
||||
this.instanceMap.put(type, instance);
|
||||
return () -> instance;
|
||||
} catch (ReflectiveOperationException e) {
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new SerializationException(ConfigurationPart.class, target + " must be a valid ConfigurationPart", e);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
package io.papermc.paper.configuration.mapping;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.papermc.paper.configuration.ConfigurationPart;
|
||||
import io.papermc.paper.configuration.serializer.collection.map.MapSerializer;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
/**
|
||||
* For use in maps inside {@link ConfigurationPart}s that have default keys that shouldn't be removed by users
|
||||
@@ -17,4 +26,39 @@ import java.lang.annotation.Target;
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MergeMap {
|
||||
|
||||
Logger LOGGER = LogUtils.getClassLogger();
|
||||
Definition<MergeMap, Map<?, ?>, Factory> DEFINITION = new Definition<>(MergeMap.class, MapSerializer.TYPE, new Factory());
|
||||
|
||||
/**
|
||||
* If marked as restricted, the field won't allow new keys beyond what
|
||||
* is already in the field when deserializing.
|
||||
*
|
||||
* @return True if restricted
|
||||
*/
|
||||
boolean restricted() default true;
|
||||
|
||||
final class Factory implements FieldProcessor.Factory<MergeMap, Map<?, ?>> {
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Override
|
||||
public FieldProcessor<Map<?, ?>> make(final MergeMap data, final AnnotatedType annotatedType) {
|
||||
return (target, deserializedValue, valueInField) -> {
|
||||
if (valueInField != null && deserializedValue != null) {
|
||||
if (data.restricted()) {
|
||||
final Set<?> invalidKeys = Sets.difference(deserializedValue.keySet(), valueInField.keySet()).immutableCopy();
|
||||
for (final Object invalidKey : invalidKeys) {
|
||||
LOGGER.error("The key {} is not allowed to be added to the field {}", invalidKey, target);
|
||||
}
|
||||
((Map) deserializedValue).keySet().removeAll(invalidKeys);
|
||||
}
|
||||
((Map) valueInField).putAll(deserializedValue);
|
||||
return valueInField;
|
||||
} else {
|
||||
checkState(!data.restricted() || valueInField != null, "If marked as restricted, field must have a value");
|
||||
return deserializedValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -1,26 +1,25 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.function.Predicate;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ComponentSerializer extends ScalarSerializer<Component> {
|
||||
public class ComponentSerializer extends ScalarSerializer.Annotated<Component> {
|
||||
|
||||
public ComponentSerializer() {
|
||||
super(Component.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component deserialize(Type type, Object obj) throws SerializationException {
|
||||
public Component deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
return MiniMessage.miniMessage().deserialize(obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(Component component, Predicate<Class<?>> typeSupported) {
|
||||
return MiniMessage.miniMessage().serialize(component);
|
||||
protected Object serialize(final AnnotatedType type, final Component item, final Predicate<Class<?>> typeSupported) {
|
||||
return MiniMessage.miniMessage().serialize(item);
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -1,11 +1,10 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import io.papermc.paper.configuration.type.EngineMode;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
|
||||
|
||||
@@ -14,11 +13,11 @@ public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineMode deserialize(Type type, Object obj) throws SerializationException {
|
||||
if (obj instanceof Integer id) {
|
||||
public EngineMode deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
if (obj instanceof final Integer id) {
|
||||
try {
|
||||
return EngineMode.valueOf(id);
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (final IllegalArgumentException e) {
|
||||
throw new SerializationException(id + " is not a valid id for type " + type + " for this node");
|
||||
}
|
||||
}
|
||||
@@ -27,7 +26,7 @@ public final class EngineModeSerializer extends ScalarSerializer<EngineMode> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(EngineMode item, Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final EngineMode item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.getId();
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -2,7 +2,7 @@ package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
@@ -17,7 +17,7 @@ import static io.leangen.geantyref.GenericTypeReflector.erase;
|
||||
/**
|
||||
* Enum serializer that lists options if fails and accepts `-` as `_`.
|
||||
*/
|
||||
public class EnumValueSerializer extends ScalarSerializer<Enum<?>> {
|
||||
public class EnumValueSerializer extends ScalarSerializer.Annotated<Enum<?>> {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
|
||||
@@ -27,23 +27,23 @@ public class EnumValueSerializer extends ScalarSerializer<Enum<?>> {
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public @Nullable Enum<?> deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
public @Nullable Enum<?> deserialize(final AnnotatedType annotatedType, final Object obj) throws SerializationException {
|
||||
final String enumConstant = obj.toString();
|
||||
final Class<? extends Enum> typeClass = erase(type).asSubclass(Enum.class);
|
||||
final Class<? extends Enum> typeClass = erase(annotatedType.getType()).asSubclass(Enum.class);
|
||||
Enum<?> ret = EnumLookup.lookupEnum(typeClass, enumConstant);
|
||||
if (ret == null) {
|
||||
ret = EnumLookup.lookupEnum(typeClass, enumConstant.replace("-", "_"));
|
||||
}
|
||||
if (ret == null) {
|
||||
boolean longer = typeClass.getEnumConstants().length > 10;
|
||||
List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList();
|
||||
final boolean longer = typeClass.getEnumConstants().length > 10;
|
||||
final List<String> options = Arrays.stream(typeClass.getEnumConstants()).limit(10L).map(Enum::name).toList();
|
||||
LOGGER.error("Invalid enum constant provided, expected one of [{}{}], but got {}", String.join(", ", options), longer ? ", ..." : "", enumConstant);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object serialize(final Enum<?> item, final Predicate<Class<?>> typeSupported) {
|
||||
public Object serialize(final AnnotatedType type, final Enum<?> item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.name();
|
||||
}
|
||||
}
|
||||
+15
-15
@@ -3,7 +3,7 @@ package io.papermc.paper.configuration.serializer;
|
||||
import com.destroystokyo.paper.util.SneakyThrow;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
@@ -11,7 +11,7 @@ import net.minecraft.commands.arguments.NbtPathArgument;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath> {
|
||||
public class NbtPathSerializer extends ScalarSerializer.Annotated<NbtPathArgument.NbtPath> {
|
||||
|
||||
public static final NbtPathSerializer SERIALIZER = new NbtPathSerializer();
|
||||
private static final NbtPathArgument DUMMY_ARGUMENT = new NbtPathArgument();
|
||||
@@ -20,23 +20,13 @@ public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath>
|
||||
super(NbtPathArgument.NbtPath.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtPathArgument.NbtPath deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
return fromString(obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final NbtPathArgument.NbtPath item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.toString();
|
||||
}
|
||||
|
||||
public static List<NbtPathArgument.NbtPath> fromString(final List<String> tags) {
|
||||
List<NbtPathArgument.NbtPath> paths = new ArrayList<>();
|
||||
final List<NbtPathArgument.NbtPath> paths = new ArrayList<>();
|
||||
try {
|
||||
for (final String tag : tags) {
|
||||
paths.add(fromString(tag));
|
||||
}
|
||||
} catch (SerializationException ex) {
|
||||
} catch (final SerializationException ex) {
|
||||
SneakyThrow.sneaky(ex);
|
||||
}
|
||||
return List.copyOf(paths);
|
||||
@@ -45,8 +35,18 @@ public class NbtPathSerializer extends ScalarSerializer<NbtPathArgument.NbtPath>
|
||||
private static NbtPathArgument.NbtPath fromString(final String tag) throws SerializationException {
|
||||
try {
|
||||
return DUMMY_ARGUMENT.parse(new StringReader(tag));
|
||||
} catch (CommandSyntaxException e) {
|
||||
} catch (final CommandSyntaxException e) {
|
||||
throw new SerializationException(NbtPathArgument.NbtPath.class, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NbtPathArgument.NbtPath deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
return fromString(obj.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final AnnotatedType type, final NbtPathArgument.NbtPath item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import io.papermc.paper.configuration.serializer.collections.MapSerializer;
|
||||
import io.papermc.paper.util.MappingEnvironment;
|
||||
import io.papermc.paper.util.ObfHelper;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@SuppressWarnings("Convert2Diamond")
|
||||
public final class PacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> implements MapSerializer.WriteBack {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private static final TypeToken<Class<? extends Packet<?>>> TYPE = new TypeToken<Class<? extends Packet<?>>>() {};
|
||||
private static final List<String> SUBPACKAGES = List.of("game", "handshake", "login", "status");
|
||||
private static final BiMap<String, String> MOJANG_TO_OBF;
|
||||
|
||||
static {
|
||||
final ImmutableBiMap.Builder<String, String> builder = ImmutableBiMap.builder();
|
||||
final @Nullable Map<String, ObfHelper.ClassMapping> classMappingMap = ObfHelper.INSTANCE.mappingsByMojangName();
|
||||
if (classMappingMap != null) {
|
||||
classMappingMap.forEach((mojMap, classMapping) -> {
|
||||
if (mojMap.startsWith("net.minecraft.network.protocol.")) {
|
||||
builder.put(classMapping.mojangName(), classMapping.obfName());
|
||||
}
|
||||
});
|
||||
}
|
||||
MOJANG_TO_OBF = builder.build();
|
||||
}
|
||||
|
||||
public PacketClassSerializer() {
|
||||
super(TYPE);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
Class<?> packetClass = null;
|
||||
for (final String subpackage : SUBPACKAGES) {
|
||||
final String fullClassName = "net.minecraft.network.protocol." + subpackage + "." + obj;
|
||||
try {
|
||||
packetClass = Class.forName(fullClassName);
|
||||
break;
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
final String spigotClassName = MOJANG_TO_OBF.get(fullClassName);
|
||||
if (spigotClassName != null) {
|
||||
try {
|
||||
packetClass = Class.forName(spigotClassName);
|
||||
} catch (final ClassNotFoundException ignore) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (packetClass == null || !Packet.class.isAssignableFrom(packetClass)) {
|
||||
throw new SerializationException("Could not deserialize a packet from " + obj);
|
||||
}
|
||||
return (Class<? extends Packet<?>>) packetClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {
|
||||
final String name = packetClass.getName();
|
||||
@Nullable String mojName = ObfHelper.INSTANCE.mappingsByMojangName() == null || !MappingEnvironment.reobf() ? name : MOJANG_TO_OBF.inverse().get(name); // if the mappings are null, running on moj-mapped server
|
||||
if (mojName == null && MOJANG_TO_OBF.containsKey(name)) {
|
||||
mojName = name;
|
||||
}
|
||||
if (mojName != null) {
|
||||
int pos = mojName.lastIndexOf('.');
|
||||
if (pos != -1 && pos != mojName.length() - 1) {
|
||||
return mojName.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.error("Could not serialize {} into a mojang-mapped packet class name", packetClass);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -1,12 +1,13 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public class ResourceLocationSerializer extends ScalarSerializer<ResourceLocation> {
|
||||
public class ResourceLocationSerializer extends ScalarSerializer.Annotated<ResourceLocation> {
|
||||
|
||||
public static final ScalarSerializer<ResourceLocation> INSTANCE = new ResourceLocationSerializer();
|
||||
|
||||
@@ -15,12 +16,12 @@ public class ResourceLocationSerializer extends ScalarSerializer<ResourceLocatio
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
public ResourceLocation deserialize(final AnnotatedType annotatedType, final Object obj) throws SerializationException {
|
||||
return ResourceLocation.read(obj.toString()).getOrThrow(s -> new SerializationException(ResourceLocation.class, s));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final ResourceLocation item, final Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType annotatedType, final ResourceLocation item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package io.papermc.paper.configuration.serializer;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.PacketType;
|
||||
import net.minecraft.network.protocol.common.CommonPacketTypes;
|
||||
import net.minecraft.network.protocol.configuration.ConfigurationPacketTypes;
|
||||
import net.minecraft.network.protocol.cookie.CookiePacketTypes;
|
||||
import net.minecraft.network.protocol.game.GamePacketTypes;
|
||||
import net.minecraft.network.protocol.handshake.HandshakePacketTypes;
|
||||
import net.minecraft.network.protocol.login.LoginPacketTypes;
|
||||
import net.minecraft.network.protocol.ping.PingPacketTypes;
|
||||
import net.minecraft.network.protocol.status.StatusPacketTypes;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@SuppressWarnings("Convert2Diamond")
|
||||
public final class ServerboundPacketClassSerializer extends ScalarSerializer<Class<? extends Packet<?>>> {
|
||||
|
||||
private static final Logger LOGGER = LogUtils.getClassLogger();
|
||||
private static final TypeToken<Class<? extends Packet<?>>> TYPE = new TypeToken<Class<? extends Packet<?>>>() {};
|
||||
static final Set<Class<?>> PACKET_CLASS_HOLDERS = Set.of(
|
||||
PingPacketTypes.class,
|
||||
HandshakePacketTypes.class,
|
||||
StatusPacketTypes.class,
|
||||
LoginPacketTypes.class,
|
||||
ConfigurationPacketTypes.class,
|
||||
CommonPacketTypes.class,
|
||||
CookiePacketTypes.class,
|
||||
GamePacketTypes.class
|
||||
);
|
||||
private static final Map<ResourceLocation, PacketInfo> ID_TO_INFO;
|
||||
private static final Map<Class<?>, PacketInfo> CLASS_TO_INFO;
|
||||
|
||||
static {
|
||||
try {
|
||||
final ImmutableMap.Builder<ResourceLocation, PacketInfo> idBuilder = ImmutableMap.builder();
|
||||
final ImmutableMap.Builder<Class<?>, PacketInfo> classBuilder = ImmutableMap.builder();
|
||||
for (final Class<?> holder : PACKET_CLASS_HOLDERS) {
|
||||
for (final Field field : holder.getDeclaredFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers()) || !Modifier.isFinal(field.getModifiers()) || !field.getType().equals(PacketType.class)) {
|
||||
continue;
|
||||
}
|
||||
final Type genericType = field.getGenericType();
|
||||
if (!(genericType instanceof final ParameterizedType parameterizedType)) {
|
||||
throw new RuntimeException("Unexpected generic type: " + genericType);
|
||||
}
|
||||
final PacketType<?> type = (PacketType<?>) field.get(null);
|
||||
if (type.flow() != PacketFlow.SERVERBOUND) {
|
||||
// we only care about serverbound for rate limiting
|
||||
continue;
|
||||
}
|
||||
final Class<?> packetClass = GenericTypeReflector.erase(parameterizedType.getActualTypeArguments()[0]);
|
||||
final PacketInfo info = new PacketInfo(packetClass.asSubclass(Packet.class), type);
|
||||
idBuilder.put(type.id(), info);
|
||||
classBuilder.put(packetClass, info);
|
||||
}
|
||||
}
|
||||
ID_TO_INFO = idBuilder.buildOrThrow();
|
||||
CLASS_TO_INFO = classBuilder.buildOrThrow();
|
||||
Preconditions.checkState(ID_TO_INFO.size() == 72, "Packet class map must have 74 entries");
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
throw new RuntimeException("Could not create packet class map", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ServerboundPacketClassSerializer() {
|
||||
super(TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Packet<?>> deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
final ResourceLocation location = ResourceLocation.tryParse(obj.toString());
|
||||
if (location == null) {
|
||||
throw new SerializationException(ResourceLocation.class, "Could not deserialize a packet from " + obj);
|
||||
}
|
||||
final PacketInfo info = ID_TO_INFO.get(location);
|
||||
if (info == null) {
|
||||
throw new SerializationException("Could not deserialize a packet from " + obj);
|
||||
}
|
||||
return info.packetClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Object serialize(final Class<? extends Packet<?>> packetClass, final Predicate<Class<?>> typeSupported) {
|
||||
final PacketInfo info = CLASS_TO_INFO.get(packetClass);
|
||||
if (info == null) {
|
||||
LOGGER.error("Could not serialize {} into a packet identifier", packetClass);
|
||||
return null;
|
||||
} else {
|
||||
return info.type().id().toString();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
record PacketInfo(Class<? extends Packet> clazz, PacketType<?> type) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<? extends Packet<?>> packetClass() {
|
||||
return (Class<? extends Packet<?>>) this.clazz;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-10
@@ -12,6 +12,7 @@ import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public final class StringRepresentableSerializer extends ScalarSerializer<StringRepresentable> {
|
||||
|
||||
private static final Map<Type, Function<String, StringRepresentable>> TYPES = Collections.synchronizedMap(Map.ofEntries(
|
||||
createEntry(MobCategory.class)
|
||||
));
|
||||
@@ -24,20 +25,22 @@ public final class StringRepresentableSerializer extends ScalarSerializer<String
|
||||
return TYPES.containsKey(type);
|
||||
}
|
||||
|
||||
private static <E extends Enum<E> & StringRepresentable> Map.Entry<Type, Function<String, @Nullable StringRepresentable>> createEntry(Class<E> type) {
|
||||
return Map.entry(type, s -> {
|
||||
for (E value : type.getEnumConstants()) {
|
||||
if (value.getSerializedName().equals(s)) {
|
||||
return value;
|
||||
private static <E extends Enum<E> & StringRepresentable> Map.Entry<Type, Function<String, @Nullable StringRepresentable>> createEntry(final Class<E> type) {
|
||||
return Map.entry(
|
||||
type, s -> {
|
||||
for (final E value : type.getEnumConstants()) {
|
||||
if (value.getSerializedName().equals(s)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringRepresentable deserialize(Type type, Object obj) throws SerializationException {
|
||||
Function<String, StringRepresentable> function = TYPES.get(type);
|
||||
public StringRepresentable deserialize(final Type type, final Object obj) throws SerializationException {
|
||||
final Function<String, StringRepresentable> function = TYPES.get(type);
|
||||
if (function == null) {
|
||||
throw new SerializationException(type + " isn't registered");
|
||||
}
|
||||
@@ -45,7 +48,7 @@ public final class StringRepresentableSerializer extends ScalarSerializer<String
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(StringRepresentable item, Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final StringRepresentable item, final Predicate<Class<?>> typeSupported) {
|
||||
return item.getSerializedName();
|
||||
}
|
||||
}
|
||||
+28
-19
@@ -1,9 +1,11 @@
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
package io.papermc.paper.configuration.serializer.collection;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
import com.google.common.collect.Table;
|
||||
import io.leangen.geantyref.TypeFactory;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
@@ -15,33 +17,34 @@ import org.spongepowered.configurate.ConfigurationOptions;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
|
||||
public class TableSerializer implements TypeSerializer.Annotated<Table<?, ?, ?>> {
|
||||
private static final int ROW_TYPE_ARGUMENT_INDEX = 0;
|
||||
private static final int COLUMN_TYPE_ARGUMENT_INDEX = 1;
|
||||
private static final int VALUE_TYPE_ARGUMENT_INDEX = 2;
|
||||
|
||||
@Override
|
||||
public Table<?, ?, ?> deserialize(final Type type, final ConfigurationNode node) throws SerializationException {
|
||||
public Table<?, ?, ?> deserialize(final AnnotatedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final Table<?, ?, ?> table = HashBasedTable.create();
|
||||
if (!node.empty() && node.isMap()) {
|
||||
this.deserialize0(table, (ParameterizedType) type, node);
|
||||
this.deserialize0(table, (AnnotatedParameterizedType) type, node);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <R, C, V> void deserialize0(final Table<R, C, V> table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
private <R, C, V> void deserialize0(final Table<R, C, V> table, final AnnotatedParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final AnnotatedType rowType = type.getAnnotatedActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType columnType = type.getAnnotatedActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType valueType = type.getAnnotatedActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
|
||||
final TypeSerializer<R> rowKeySerializer = (TypeSerializer<R>) node.options().serializers().get(rowType);
|
||||
if (rowKeySerializer == null) {
|
||||
throw new SerializationException("Could not find serializer for table row type " + rowType);
|
||||
}
|
||||
|
||||
final Type mapType = TypeFactory.parameterizedClass(Map.class, columnType, valueType);
|
||||
final TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(mapType);
|
||||
final ParameterizedType mapType = (ParameterizedType) TypeFactory.parameterizedClass(Map.class, columnType.getType(), valueType.getType());
|
||||
final AnnotatedParameterizedType annotatedMapType = TypeFactory.parameterizedAnnotatedType(mapType, type.getAnnotations(), columnType.getAnnotations(), valueType.getAnnotations());
|
||||
final TypeSerializer<Map<C, V>> columnValueSerializer = (TypeSerializer<Map<C, V>>) node.options().serializers().get(annotatedMapType);
|
||||
if (columnValueSerializer == null) {
|
||||
throw new SerializationException("Could not find serializer for table column-value map " + type);
|
||||
}
|
||||
@@ -56,17 +59,21 @@ public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(final Type type, final @Nullable Table<?, ?, ?> table, final ConfigurationNode node) throws SerializationException {
|
||||
if (table != null) {
|
||||
this.serialize0(table, (ParameterizedType) type, node);
|
||||
public void serialize(
|
||||
final AnnotatedType type,
|
||||
final @Nullable Table<?, ?, ?> obj,
|
||||
final ConfigurationNode node
|
||||
) throws SerializationException {
|
||||
if (obj != null) {
|
||||
this.serialize0(obj, (AnnotatedParameterizedType) type, node);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private <R, C, V> void serialize0(final Table<R, C, V> table, final ParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final Type rowType = type.getActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final Type columnType = type.getActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final Type valueType = type.getActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
private <R, C, V> void serialize0(final Table<R, C, V> table, final AnnotatedParameterizedType type, final ConfigurationNode node) throws SerializationException {
|
||||
final AnnotatedType rowType = type.getAnnotatedActualTypeArguments()[ROW_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType columnType = type.getAnnotatedActualTypeArguments()[COLUMN_TYPE_ARGUMENT_INDEX];
|
||||
final AnnotatedType valueType = type.getAnnotatedActualTypeArguments()[VALUE_TYPE_ARGUMENT_INDEX];
|
||||
|
||||
final TypeSerializer rowKeySerializer = node.options().serializers().get(rowType);
|
||||
if (rowKeySerializer == null) {
|
||||
@@ -77,12 +84,14 @@ public class TableSerializer implements TypeSerializer<Table<?, ?, ?>> {
|
||||
for (final R key : table.rowKeySet()) {
|
||||
rowKeySerializer.serialize(rowType, key, rowKeyNode.set(key));
|
||||
final Object keyObj = Objects.requireNonNull(rowKeyNode.raw());
|
||||
node.node(keyObj).set(TypeFactory.parameterizedClass(Map.class, columnType, valueType), table.row(key));
|
||||
final ParameterizedType mapType = (ParameterizedType) TypeFactory.parameterizedClass(Map.class, columnType.getType(), valueType.getType());
|
||||
final AnnotatedParameterizedType annotatedMapType = TypeFactory.parameterizedAnnotatedType(mapType, type.getAnnotations(), columnType.getAnnotations(), valueType.getAnnotations());
|
||||
node.node(keyObj).set(annotatedMapType, table.row(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Table<?, ?, ?> emptyValue(Type specificType, ConfigurationOptions options) {
|
||||
public @Nullable Table<?, ?, ?> emptyValue(final Type specificType, final ConfigurationOptions options) {
|
||||
return ImmutableTable.of();
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import io.leangen.geantyref.GenericTypeReflector;
|
||||
import io.leangen.geantyref.TypeFactory;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
+35
-41
@@ -1,11 +1,9 @@
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import com.mojang.logging.LogUtils;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@@ -36,56 +34,54 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
private final boolean clearInvalids;
|
||||
private final TypeSerializer<Map<?, ?>> fallback;
|
||||
|
||||
public MapSerializer(boolean clearInvalids) {
|
||||
public MapSerializer(final boolean clearInvalids) {
|
||||
this.clearInvalids = clearInvalids;
|
||||
this.fallback = requireNonNull(TypeSerializerCollection.defaults().get(TYPE), "Could not find default Map<?, ?> serializer");
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ThrowExceptions {}
|
||||
|
||||
@Override
|
||||
public Map<?, ?> deserialize(AnnotatedType annotatedType, ConfigurationNode node) throws SerializationException {
|
||||
public Map<?, ?> deserialize(final AnnotatedType annotatedType, final ConfigurationNode node) throws SerializationException {
|
||||
if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
|
||||
return this.fallback.deserialize(annotatedType, node);
|
||||
}
|
||||
final Map<Object, Object> map = new LinkedHashMap<>();
|
||||
final Type type = annotatedType.getType();
|
||||
if (node.isMap()) {
|
||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
||||
if (!(annotatedType instanceof final AnnotatedParameterizedType annotatedParameterizedType)) {
|
||||
throw new SerializationException(type, "Raw types are not supported for collections");
|
||||
}
|
||||
if (parameterizedType.getActualTypeArguments().length != 2) {
|
||||
if (annotatedParameterizedType.getAnnotatedActualTypeArguments().length != 2) {
|
||||
throw new SerializationException(type, "Map expected two type arguments!");
|
||||
}
|
||||
final Type key = parameterizedType.getActualTypeArguments()[0];
|
||||
final Type value = parameterizedType.getActualTypeArguments()[1];
|
||||
final @Nullable TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final @Nullable TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
final AnnotatedType key = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0];
|
||||
final AnnotatedType value = annotatedParameterizedType.getAnnotatedActualTypeArguments()[1];
|
||||
final TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
if (keySerializer == null) {
|
||||
throw new SerializationException(type, "No type serializer available for key type " + key);
|
||||
}
|
||||
if (valueSerializer == null) {
|
||||
throw new SerializationException(type, "No type serializer available for value type " + value);
|
||||
}
|
||||
final boolean writeKeyBack = key.isAnnotationPresent(WriteKeyBack.class);
|
||||
|
||||
final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options());
|
||||
final Set<Object> keysToClear = new HashSet<>();
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> ent : node.childrenMap().entrySet()) {
|
||||
final @Nullable Object deserializedKey = deserialize(key, keySerializer, "key", keyNode.set(ent.getKey()), node.path());
|
||||
final @Nullable Object deserializedValue = deserialize(value, valueSerializer, "value", ent.getValue(), ent.getValue().path());
|
||||
for (final Map.Entry<Object, ? extends ConfigurationNode> ent : node.childrenMap().entrySet()) {
|
||||
final Object deserializedKey = this.deserialize(key.getType(), keySerializer, "key", keyNode.set(ent.getKey()), node.path());
|
||||
final Object deserializedValue = this.deserialize(value.getType(), valueSerializer, "value", ent.getValue(), ent.getValue().path());
|
||||
if (deserializedKey == null || deserializedValue == null) {
|
||||
continue;
|
||||
}
|
||||
if (keySerializer instanceof WriteBack) {
|
||||
if (serialize(key, keySerializer, deserializedKey, "key", keyNode, node.path()) && !ent.getKey().equals(requireNonNull(keyNode.raw(), "Key must not be null!"))) {
|
||||
if (writeKeyBack) {
|
||||
if (this.serialize(key.getType(), keySerializer, deserializedKey, "key", keyNode, node.path()) && !ent.getKey().equals(requireNonNull(keyNode.raw(), "Key must not be null!"))) {
|
||||
keysToClear.add(ent.getKey());
|
||||
}
|
||||
}
|
||||
map.put(deserializedKey, deserializedValue);
|
||||
}
|
||||
if (keySerializer instanceof WriteBack) { // supports cleaning keys which deserialize to the same value
|
||||
for (Object keyToClear : keysToClear) {
|
||||
if (writeKeyBack) { // supports cleaning keys which deserialize to the same value
|
||||
for (final Object keyToClear : keysToClear) {
|
||||
node.node(keyToClear).raw(null);
|
||||
}
|
||||
}
|
||||
@@ -93,10 +89,10 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
return map;
|
||||
}
|
||||
|
||||
private @Nullable Object deserialize(Type type, TypeSerializer<?> serializer, String mapPart, ConfigurationNode node, NodePath path) {
|
||||
private @Nullable Object deserialize(final Type type, final TypeSerializer<?> serializer, final String mapPart, final ConfigurationNode node, final NodePath path) {
|
||||
try {
|
||||
return serializer.deserialize(type, node);
|
||||
} catch (SerializationException ex) {
|
||||
} catch (final SerializationException ex) {
|
||||
ex.initPath(node::path);
|
||||
LOGGER.error("Could not deserialize {} {} into {} at {}: {}", mapPart, node.raw(), type, path, ex.rawMessage());
|
||||
}
|
||||
@@ -104,22 +100,22 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(AnnotatedType annotatedType, @Nullable Map<?, ?> obj, ConfigurationNode node) throws SerializationException {
|
||||
public void serialize(final AnnotatedType annotatedType, final @Nullable Map<?, ?> obj, final ConfigurationNode node) throws SerializationException {
|
||||
if (annotatedType.isAnnotationPresent(ThrowExceptions.class)) {
|
||||
this.fallback.serialize(annotatedType, obj, node);
|
||||
return;
|
||||
}
|
||||
final Type type = annotatedType.getType();
|
||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
||||
if (!(annotatedType instanceof final AnnotatedParameterizedType annotatedParameterizedType)) {
|
||||
throw new SerializationException(type, "Raw types are not supported for collections");
|
||||
}
|
||||
if (parameterizedType.getActualTypeArguments().length != 2) {
|
||||
if (annotatedParameterizedType.getAnnotatedActualTypeArguments().length != 2) {
|
||||
throw new SerializationException(type, "Map expected two type arguments!");
|
||||
}
|
||||
final Type key = parameterizedType.getActualTypeArguments()[0];
|
||||
final Type value = parameterizedType.getActualTypeArguments()[1];
|
||||
final @Nullable TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final @Nullable TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
final AnnotatedType key = annotatedParameterizedType.getAnnotatedActualTypeArguments()[0];
|
||||
final AnnotatedType value = annotatedParameterizedType.getAnnotatedActualTypeArguments()[1];
|
||||
final TypeSerializer<?> keySerializer = node.options().serializers().get(key);
|
||||
final TypeSerializer<?> valueSerializer = node.options().serializers().get(value);
|
||||
|
||||
if (keySerializer == null) {
|
||||
throw new SerializationException(type, "No type serializer available for key type " + key);
|
||||
@@ -135,22 +131,22 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
final Set<Object> unvisitedKeys;
|
||||
if (node.empty()) {
|
||||
node.raw(Collections.emptyMap());
|
||||
unvisitedKeys = Collections.emptySet();
|
||||
unvisitedKeys = new HashSet<>();
|
||||
} else {
|
||||
unvisitedKeys = new HashSet<>(node.childrenMap().keySet());
|
||||
}
|
||||
final BasicConfigurationNode keyNode = BasicConfigurationNode.root(node.options());
|
||||
for (Map.Entry<?, ?> ent : obj.entrySet()) {
|
||||
if (!serialize(key, keySerializer, ent.getKey(), "key", keyNode, node.path())) {
|
||||
for (final Map.Entry<?, ?> ent : obj.entrySet()) {
|
||||
if (!this.serialize(key.getType(), keySerializer, ent.getKey(), "key", keyNode, node.path())) {
|
||||
continue;
|
||||
}
|
||||
final Object keyObj = requireNonNull(keyNode.raw(), "Key must not be null!");
|
||||
final ConfigurationNode child = node.node(keyObj);
|
||||
serialize(value, valueSerializer, ent.getValue(), "value", child, child.path());
|
||||
this.serialize(value.getType(), valueSerializer, ent.getValue(), "value", child, child.path());
|
||||
unvisitedKeys.remove(keyObj);
|
||||
}
|
||||
if (this.clearInvalids) {
|
||||
for (Object unusedChild : unvisitedKeys) {
|
||||
for (final Object unusedChild : unvisitedKeys) {
|
||||
node.removeChild(unusedChild);
|
||||
}
|
||||
}
|
||||
@@ -158,11 +154,11 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private boolean serialize(Type type, TypeSerializer serializer, Object object, String mapPart, ConfigurationNode node, NodePath path) {
|
||||
private boolean serialize(final Type type, final TypeSerializer serializer, final Object object, final String mapPart, final ConfigurationNode node, final NodePath path) {
|
||||
try {
|
||||
serializer.serialize(type, object, node);
|
||||
return true;
|
||||
} catch (SerializationException ex) {
|
||||
} catch (final SerializationException ex) {
|
||||
ex.initPath(node::path);
|
||||
LOGGER.error("Could not serialize {} {} from {} at {}: {}", mapPart, object, type, path, ex.rawMessage());
|
||||
}
|
||||
@@ -170,13 +166,11 @@ public class MapSerializer implements TypeSerializer.Annotated<Map<?, ?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Map<?, ?> emptyValue(AnnotatedType specificType, ConfigurationOptions options) {
|
||||
public @Nullable Map<?, ?> emptyValue(final AnnotatedType specificType, final ConfigurationOptions options) {
|
||||
if (specificType.isAnnotationPresent(ThrowExceptions.class)) {
|
||||
return this.fallback.emptyValue(specificType, options);
|
||||
}
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public interface WriteBack { // marker interface
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ThrowExceptions {}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface WriteKeyBack {}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.configuration.serializer.collection.map;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.configuration.serializer.collection;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
@NullMarked
|
||||
package io.papermc.paper.configuration.serializer.collections;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
+16
-5
@@ -1,6 +1,7 @@
|
||||
package io.papermc.paper.configuration.serializer.registry;
|
||||
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.function.Predicate;
|
||||
import net.minecraft.core.Registry;
|
||||
@@ -10,20 +11,30 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer<T> {
|
||||
abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer.Annotated<T> {
|
||||
|
||||
private final RegistryAccess registryAccess;
|
||||
private final ResourceKey<? extends Registry<R>> registryKey;
|
||||
private final boolean omitMinecraftNamespace;
|
||||
|
||||
protected RegistryEntrySerializer(TypeToken<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<R>> registryKey, boolean omitMinecraftNamespace) {
|
||||
protected RegistryEntrySerializer(
|
||||
final TypeToken<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<R>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type);
|
||||
this.registryAccess = registryAccess;
|
||||
this.registryKey = registryKey;
|
||||
this.omitMinecraftNamespace = omitMinecraftNamespace;
|
||||
}
|
||||
|
||||
protected RegistryEntrySerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<R>> registryKey, boolean omitMinecraftNamespace) {
|
||||
protected RegistryEntrySerializer(
|
||||
final Class<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<R>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type);
|
||||
this.registryAccess = registryAccess;
|
||||
this.registryKey = registryKey;
|
||||
@@ -37,14 +48,14 @@ abstract class RegistryEntrySerializer<T, R> extends ScalarSerializer<T> {
|
||||
protected abstract T convertFromResourceKey(ResourceKey<R> key) throws SerializationException;
|
||||
|
||||
@Override
|
||||
public final T deserialize(Type type, Object obj) throws SerializationException {
|
||||
public final T deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
return this.convertFromResourceKey(this.deserializeKey(obj));
|
||||
}
|
||||
|
||||
protected abstract ResourceKey<R> convertToResourceKey(T value);
|
||||
|
||||
@Override
|
||||
protected final Object serialize(T item, Predicate<Class<?>> typeSupported) {
|
||||
protected final Object serialize(final AnnotatedType type, final T item, final Predicate<Class<?>> typeSupported) {
|
||||
final ResourceKey<R> key = this.convertToResourceKey(item);
|
||||
if (this.omitMinecraftNamespace && key.location().getNamespace().equals(ResourceLocation.DEFAULT_NAMESPACE)) {
|
||||
return key.location().getPath();
|
||||
|
||||
+14
-4
@@ -13,22 +13,32 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||
public final class RegistryHolderSerializer<T> extends RegistryEntrySerializer<Holder<T>, T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public RegistryHolderSerializer(TypeToken<T> typeToken, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryHolderSerializer(
|
||||
final TypeToken<T> typeToken,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super((TypeToken<Holder<T>>) TypeToken.get(TypeFactory.parameterizedClass(Holder.class, typeToken.getType())), registryAccess, registryKey, omitMinecraftNamespace);
|
||||
}
|
||||
|
||||
public RegistryHolderSerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryHolderSerializer(
|
||||
final Class<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
this(TypeToken.get(type), registryAccess, registryKey, omitMinecraftNamespace);
|
||||
Preconditions.checkArgument(type.getTypeParameters().length == 0, "%s must have 0 type parameters", type);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Holder<T> convertFromResourceKey(ResourceKey<T> key) throws SerializationException {
|
||||
protected Holder<T> convertFromResourceKey(final ResourceKey<T> key) throws SerializationException {
|
||||
return this.registry().get(key).orElseThrow(() -> new SerializationException("Missing holder in " + this.registry().key() + " with key " + key));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceKey<T> convertToResourceKey(Holder<T> value) {
|
||||
protected ResourceKey<T> convertToResourceKey(final Holder<T> value) {
|
||||
return value.unwrap().map(Function.identity(), r -> this.registry().getResourceKey(r).orElseThrow());
|
||||
}
|
||||
}
|
||||
+14
-4
@@ -11,16 +11,26 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||
*/
|
||||
public final class RegistryValueSerializer<T> extends RegistryEntrySerializer<T, T> {
|
||||
|
||||
public RegistryValueSerializer(TypeToken<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryValueSerializer(
|
||||
final TypeToken<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type, registryAccess, registryKey, omitMinecraftNamespace);
|
||||
}
|
||||
|
||||
public RegistryValueSerializer(Class<T> type, final RegistryAccess registryAccess, ResourceKey<? extends Registry<T>> registryKey, boolean omitMinecraftNamespace) {
|
||||
public RegistryValueSerializer(
|
||||
final Class<T> type,
|
||||
final RegistryAccess registryAccess,
|
||||
final ResourceKey<? extends Registry<T>> registryKey,
|
||||
final boolean omitMinecraftNamespace
|
||||
) {
|
||||
super(type, registryAccess, registryKey, omitMinecraftNamespace);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T convertFromResourceKey(ResourceKey<T> key) throws SerializationException {
|
||||
protected T convertFromResourceKey(final ResourceKey<T> key) throws SerializationException {
|
||||
final T value = this.registry().getValue(key);
|
||||
if (value == null) {
|
||||
throw new SerializationException("Missing value in " + this.registry() + " with key " + key.location());
|
||||
@@ -29,7 +39,7 @@ public final class RegistryValueSerializer<T> extends RegistryEntrySerializer<T,
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceKey<T> convertToResourceKey(T value) {
|
||||
protected ResourceKey<T> convertToResourceKey(final T value) {
|
||||
return this.registry().getResourceKey(value).orElseThrow();
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package io.papermc.paper.configuration.transformation.global.versioned;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static org.spongepowered.configurate.NodePath.path;
|
||||
|
||||
public class V30_PacketIds implements TransformAction {
|
||||
|
||||
public static final V30_PacketIds INSTANCE = new V30_PacketIds();
|
||||
private static final int VERSION = 30;
|
||||
|
||||
private static final Gson GSON = new Gson();
|
||||
private static final Map<String, ResourceLocation> MOJANG_TO_ID;
|
||||
|
||||
static {
|
||||
final ImmutableMap.Builder<String, ResourceLocation> builder2 = ImmutableMap.builder();
|
||||
final InputStream input = V30_PacketIds.class.getResourceAsStream("/config-data/packet-limiter-upgrade-data.json");
|
||||
if (input == null) {
|
||||
throw new RuntimeException("Failed to load packet limiter upgrade data");
|
||||
}
|
||||
try (final Reader reader = new InputStreamReader(new BufferedInputStream(input))) {
|
||||
final JsonArray array = GSON.fromJson(reader, JsonArray.class);
|
||||
for (final JsonElement element : array) {
|
||||
final JsonObject obj = element.getAsJsonObject();
|
||||
builder2.put(obj.get("simple_class_name").getAsString(), ResourceLocation.parse(obj.get("id").getAsString()));
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException("Failed to load packet limiter upgrade data", e);
|
||||
}
|
||||
MOJANG_TO_ID = builder2.build();
|
||||
}
|
||||
|
||||
public static void apply(final ConfigurationTransformation.VersionedBuilder builder) {
|
||||
builder.addVersion(VERSION, ConfigurationTransformation.builder().addAction(path("packet-limiter", "overrides", ConfigurationTransformation.WILDCARD_OBJECT), INSTANCE).build());
|
||||
}
|
||||
|
||||
private V30_PacketIds() {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) {
|
||||
final String oldClassName = path.get(path.size() - 1).toString();
|
||||
if (MOJANG_TO_ID.containsKey(oldClassName)) {
|
||||
return path.with(path.size() - 1, MOJANG_TO_ID.get(oldClassName).toString()).array();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
package io.papermc.paper.configuration.type;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
@@ -9,38 +9,38 @@ import org.spongepowered.configurate.serialize.ScalarSerializer;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
public record BooleanOrDefault(@Nullable Boolean value) {
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final BooleanOrDefault USE_DEFAULT = new BooleanOrDefault(null);
|
||||
public static final ScalarSerializer<BooleanOrDefault> SERIALIZER = new Serializer();
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
|
||||
public boolean or(boolean fallback) {
|
||||
public boolean or(final boolean fallback) {
|
||||
return this.value == null ? fallback : this.value;
|
||||
}
|
||||
|
||||
private static final class Serializer extends ScalarSerializer<BooleanOrDefault> {
|
||||
private static final class Serializer extends ScalarSerializer.Annotated<BooleanOrDefault> {
|
||||
Serializer() {
|
||||
super(BooleanOrDefault.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BooleanOrDefault deserialize(Type type, Object obj) throws SerializationException {
|
||||
if (obj instanceof String string) {
|
||||
public BooleanOrDefault deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
if (obj instanceof final String string) {
|
||||
if (DEFAULT_VALUE.equalsIgnoreCase(string)) {
|
||||
return USE_DEFAULT;
|
||||
}
|
||||
try {
|
||||
return new BooleanOrDefault(BooleanUtils.toBoolean(string.toLowerCase(Locale.ROOT), "true", "false"));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
} catch (final IllegalArgumentException ex) {
|
||||
throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'", ex);
|
||||
}
|
||||
} else if (obj instanceof Boolean bool) {
|
||||
} else if (obj instanceof final Boolean bool) {
|
||||
return new BooleanOrDefault(bool);
|
||||
}
|
||||
throw new SerializationException(BooleanOrDefault.class, obj + "(" + type + ") is not a boolean or '" + DEFAULT_VALUE + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(BooleanOrDefault item, Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType type, final BooleanOrDefault item, final Predicate<Class<?>> typeSupported) {
|
||||
final Boolean value = item.value;
|
||||
if (value != null) {
|
||||
return value.toString();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.papermc.paper.configuration.type.number;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.function.DoublePredicate;
|
||||
import java.util.function.Function;
|
||||
@@ -20,17 +21,17 @@ public interface DoubleOr {
|
||||
}
|
||||
|
||||
record Default(OptionalDouble value) implements DoubleOr {
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final Default USE_DEFAULT = new Default(OptionalDouble.empty());
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final ScalarSerializer<Default> SERIALIZER = new Serializer<>(Default.class, Default::new, DEFAULT_VALUE, USE_DEFAULT);
|
||||
}
|
||||
|
||||
record Disabled(OptionalDouble value) implements DoubleOr {
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final Disabled DISABLED = new Disabled(OptionalDouble.empty());
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final ScalarSerializer<Disabled> SERIALIZER = new Serializer<>(Disabled.class, Disabled::new, DISABLED_VALUE, DISABLED);
|
||||
|
||||
public boolean test(DoublePredicate predicate) {
|
||||
public boolean test(final DoublePredicate predicate) {
|
||||
return this.value.isPresent() && predicate.test(this.value.getAsDouble());
|
||||
}
|
||||
|
||||
@@ -40,12 +41,12 @@ public interface DoubleOr {
|
||||
}
|
||||
|
||||
final class Serializer<T extends DoubleOr> extends OptionalNumSerializer<T, OptionalDouble> {
|
||||
Serializer(final Class<T> classOfT, final Function<OptionalDouble, T> factory, String emptySerializedValue, T emptyValue) {
|
||||
Serializer(final Class<T> classOfT, final Function<OptionalDouble, T> factory, final String emptySerializedValue, final T emptyValue) {
|
||||
super(classOfT, emptySerializedValue, emptyValue, OptionalDouble::empty, OptionalDouble::isEmpty, factory, double.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final T item, final Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType type, final T item, final Predicate<Class<?>> typeSupported) {
|
||||
final OptionalDouble value = item.value();
|
||||
if (value.isPresent()) {
|
||||
return value.getAsDouble();
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.papermc.paper.configuration.type.number;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntPredicate;
|
||||
@@ -28,17 +29,17 @@ public interface IntOr {
|
||||
}
|
||||
|
||||
record Default(OptionalInt value) implements IntOr {
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final Default USE_DEFAULT = new Default(OptionalInt.empty());
|
||||
private static final String DEFAULT_VALUE = "default";
|
||||
public static final ScalarSerializer<Default> SERIALIZER = new Serializer<>(Default.class, Default::new, DEFAULT_VALUE, USE_DEFAULT);
|
||||
}
|
||||
|
||||
record Disabled(OptionalInt value) implements IntOr {
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final Disabled DISABLED = new Disabled(OptionalInt.empty());
|
||||
private static final String DISABLED_VALUE = "disabled";
|
||||
public static final ScalarSerializer<Disabled> SERIALIZER = new Serializer<>(Disabled.class, Disabled::new, DISABLED_VALUE, DISABLED);
|
||||
|
||||
public boolean test(IntPredicate predicate) {
|
||||
public boolean test(final IntPredicate predicate) {
|
||||
return this.value.isPresent() && predicate.test(this.value.getAsInt());
|
||||
}
|
||||
|
||||
@@ -49,7 +50,7 @@ public interface IntOr {
|
||||
|
||||
final class Serializer<T extends IntOr> extends OptionalNumSerializer<T, OptionalInt> {
|
||||
|
||||
private Serializer(Class<T> classOfT, Function<OptionalInt, T> factory, String emptySerializedValue, T emptyValue) {
|
||||
private Serializer(final Class<T> classOfT, final Function<OptionalInt, T> factory, final String emptySerializedValue, final T emptyValue) {
|
||||
super(classOfT, emptySerializedValue, emptyValue, OptionalInt::empty, OptionalInt::isEmpty, factory, int.class);
|
||||
}
|
||||
|
||||
@@ -73,7 +74,7 @@ public interface IntOr {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object serialize(final T item, final Predicate<Class<?>> typeSupported) {
|
||||
protected Object serialize(final AnnotatedType type, final T item, final Predicate<Class<?>> typeSupported) {
|
||||
final OptionalInt value = item.value();
|
||||
if (value.isPresent()) {
|
||||
return value.getAsInt();
|
||||
|
||||
+11
-3
@@ -17,7 +17,15 @@ public abstract class OptionalNumSerializer<T, O> extends ScalarSerializer.Annot
|
||||
private final Function<O, T> factory;
|
||||
private final Class<?> number;
|
||||
|
||||
protected OptionalNumSerializer(final Class<T> classOfT, final String emptySerializedValue, final T emptyValue, final Supplier<O> empty, final Predicate<O> isEmpty, final Function<O, T> factory, final Class<?> number) {
|
||||
protected OptionalNumSerializer(
|
||||
final Class<T> classOfT,
|
||||
final String emptySerializedValue,
|
||||
final T emptyValue,
|
||||
final Supplier<O> empty,
|
||||
final Predicate<O> isEmpty,
|
||||
final Function<O, T> factory,
|
||||
final Class<?> number
|
||||
) {
|
||||
super(classOfT);
|
||||
this.emptySerializedValue = emptySerializedValue;
|
||||
this.emptyValue = emptyValue;
|
||||
@@ -30,7 +38,7 @@ public abstract class OptionalNumSerializer<T, O> extends ScalarSerializer.Annot
|
||||
@Override
|
||||
public final T deserialize(final AnnotatedType type, final Object obj) throws SerializationException {
|
||||
final O value;
|
||||
if (obj instanceof String string) {
|
||||
if (obj instanceof final String string) {
|
||||
if (this.emptySerializedValue.equalsIgnoreCase(string)) {
|
||||
value = this.empty.get();
|
||||
} else if (NumberUtils.isParsable(string)) {
|
||||
@@ -38,7 +46,7 @@ public abstract class OptionalNumSerializer<T, O> extends ScalarSerializer.Annot
|
||||
} else {
|
||||
throw new SerializationException("%s (%s) is not a(n) %s or '%s'".formatted(obj, type, this.number.getSimpleName(), this.emptySerializedValue));
|
||||
}
|
||||
} else if (obj instanceof Number num) {
|
||||
} else if (obj instanceof final Number num) {
|
||||
value = this.full(num);
|
||||
} else {
|
||||
throw new SerializationException("%s (%s) is not a(n) %s or '%s'".formatted(obj, type, this.number.getSimpleName(), this.emptySerializedValue));
|
||||
|
||||
@@ -41,6 +41,7 @@ import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.imageio.ImageIO;
|
||||
// import jline.console.ConsoleReader;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
@@ -2333,7 +2334,11 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public GameMode getDefaultGameMode() {
|
||||
return GameMode.getByValue(this.console.getLevel(net.minecraft.world.level.Level.OVERWORLD).serverLevelData.getGameType().getId());
|
||||
return GameMode.getByValue(Optionull.mapOrDefault(
|
||||
this.console.getLevel(net.minecraft.world.level.Level.OVERWORLD),
|
||||
l -> l.serverLevelData.getGameType(),
|
||||
this.console.getProperties().gamemode
|
||||
).getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -221,7 +221,6 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
private BorderChangeListener clientWorldBorderListener = this.createWorldBorderListener();
|
||||
public org.bukkit.event.player.PlayerResourcePackStatusEvent.Status resourcePackStatus; // Paper - more resource pack API
|
||||
private static final boolean DISABLE_CHANNEL_LIMIT = System.getProperty("paper.disableChannelLimit") != null; // Paper - add a flag to disable the channel limit
|
||||
private boolean simplifyContainerDesyncCheck = GlobalConfiguration.get().unsupportedSettings.simplifyRemoteItemMatching;
|
||||
private long lastSaveTime; // Paper - getLastPlayed replacement API
|
||||
|
||||
public CraftPlayer(CraftServer server, ServerPlayer entity) {
|
||||
@@ -3603,20 +3602,4 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
public void setDeathScreenScore(final int score) {
|
||||
getHandle().setScore(score);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether container desync checks should skip the full item comparison of remote carried and changed slots
|
||||
* and should instead only check their type and amount.
|
||||
* <p>
|
||||
* This is useful if the client is not able to produce the same item stack (or as of 1.21.5, its data hashes) as the server.
|
||||
*
|
||||
* @return whether to simplify container desync checks
|
||||
*/
|
||||
public boolean simplifyContainerDesyncCheck() {
|
||||
return simplifyContainerDesyncCheck;
|
||||
}
|
||||
|
||||
public void setSimplifyContainerDesyncCheck(final boolean simplifyContainerDesyncCheck) {
|
||||
this.simplifyContainerDesyncCheck = simplifyContainerDesyncCheck;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[{"id":"minecraft:finish_configuration","fq_class_name":"net.minecraft.network.protocol.configuration.ServerboundFinishConfigurationPacket","simple_class_name":"ServerboundFinishConfigurationPacket"},{"id":"minecraft:select_known_packs","fq_class_name":"net.minecraft.network.protocol.configuration.ServerboundSelectKnownPacks","simple_class_name":"ServerboundSelectKnownPacks"},{"id":"minecraft:ping_request","fq_class_name":"net.minecraft.network.protocol.ping.ServerboundPingRequestPacket","simple_class_name":"ServerboundPingRequestPacket"},{"id":"minecraft:intention","fq_class_name":"net.minecraft.network.protocol.handshake.ClientIntentionPacket","simple_class_name":"ClientIntentionPacket"},{"id":"minecraft:cookie_response","fq_class_name":"net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket","simple_class_name":"ServerboundCookieResponsePacket"},{"id":"minecraft:client_information","fq_class_name":"net.minecraft.network.protocol.common.ServerboundClientInformationPacket","simple_class_name":"ServerboundClientInformationPacket"},{"id":"minecraft:custom_payload","fq_class_name":"net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket","simple_class_name":"ServerboundCustomPayloadPacket"},{"id":"minecraft:keep_alive","fq_class_name":"net.minecraft.network.protocol.common.ServerboundKeepAlivePacket","simple_class_name":"ServerboundKeepAlivePacket"},{"id":"minecraft:pong","fq_class_name":"net.minecraft.network.protocol.common.ServerboundPongPacket","simple_class_name":"ServerboundPongPacket"},{"id":"minecraft:resource_pack","fq_class_name":"net.minecraft.network.protocol.common.ServerboundResourcePackPacket","simple_class_name":"ServerboundResourcePackPacket"},{"id":"minecraft:custom_click_action","fq_class_name":"net.minecraft.network.protocol.common.ServerboundCustomClickActionPacket","simple_class_name":"ServerboundCustomClickActionPacket"},{"id":"minecraft:accept_teleportation","fq_class_name":"net.minecraft.network.protocol.game.ServerboundAcceptTeleportationPacket","simple_class_name":"ServerboundAcceptTeleportationPacket"},{"id":"minecraft:block_entity_tag_query","fq_class_name":"net.minecraft.network.protocol.game.ServerboundBlockEntityTagQueryPacket","simple_class_name":"ServerboundBlockEntityTagQueryPacket"},{"id":"minecraft:bundle_item_selected","fq_class_name":"net.minecraft.network.protocol.game.ServerboundSelectBundleItemPacket","simple_class_name":"ServerboundSelectBundleItemPacket"},{"id":"minecraft:change_difficulty","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChangeDifficultyPacket","simple_class_name":"ServerboundChangeDifficultyPacket"},{"id":"minecraft:change_game_mode","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChangeGameModePacket","simple_class_name":"ServerboundChangeGameModePacket"},{"id":"minecraft:chat_ack","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatAckPacket","simple_class_name":"ServerboundChatAckPacket"},{"id":"minecraft:chat_command","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatCommandPacket","simple_class_name":"ServerboundChatCommandPacket"},{"id":"minecraft:chat_command_signed","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatCommandSignedPacket","simple_class_name":"ServerboundChatCommandSignedPacket"},{"id":"minecraft:chat","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatPacket","simple_class_name":"ServerboundChatPacket"},{"id":"minecraft:chat_session_update","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChatSessionUpdatePacket","simple_class_name":"ServerboundChatSessionUpdatePacket"},{"id":"minecraft:chunk_batch_received","fq_class_name":"net.minecraft.network.protocol.game.ServerboundChunkBatchReceivedPacket","simple_class_name":"ServerboundChunkBatchReceivedPacket"},{"id":"minecraft:client_command","fq_class_name":"net.minecraft.network.protocol.game.ServerboundClientCommandPacket","simple_class_name":"ServerboundClientCommandPacket"},{"id":"minecraft:client_tick_end","fq_class_name":"net.minecraft.network.protocol.game.ServerboundClientTickEndPacket","simple_class_name":"ServerboundClientTickEndPacket"},{"id":"minecraft:command_suggestion","fq_class_name":"net.minecraft.network.protocol.game.ServerboundCommandSuggestionPacket","simple_class_name":"ServerboundCommandSuggestionPacket"},{"id":"minecraft:configuration_acknowledged","fq_class_name":"net.minecraft.network.protocol.game.ServerboundConfigurationAcknowledgedPacket","simple_class_name":"ServerboundConfigurationAcknowledgedPacket"},{"id":"minecraft:container_button_click","fq_class_name":"net.minecraft.network.protocol.game.ServerboundContainerButtonClickPacket","simple_class_name":"ServerboundContainerButtonClickPacket"},{"id":"minecraft:container_click","fq_class_name":"net.minecraft.network.protocol.game.ServerboundContainerClickPacket","simple_class_name":"ServerboundContainerClickPacket"},{"id":"minecraft:container_close","fq_class_naLine truncated
|
||||
Reference in new issue
Block a user