Skip to content

Commit d7bdaf0

Browse files
committed
Implement folia support
1 parent 4818f37 commit d7bdaf0

File tree

6 files changed

+213
-40
lines changed

6 files changed

+213
-40
lines changed

worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
189189

190190
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q"));
191191
fieldRemove.setAccessible(true);
192-
193192
boolean chunkRewrite;
194193
try {
195194
ServerLevel.class.getDeclaredMethod("getEntityLookup");
@@ -274,9 +273,7 @@ public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int c
274273
} else {
275274
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
276275
if (nmsChunk != null) {
277-
if(!FOLIA_SUPPORT) {// TODO: Dirty folia workaround - Needs be discussed with FAWE members
278-
addTicket(serverLevel, chunkX, chunkZ);
279-
}
276+
addTicket(serverLevel, chunkX, chunkZ);
280277
return nmsChunk;
281278
}
282279
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
@@ -321,10 +318,17 @@ public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int c
321318
}
322319

323320
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
324-
// Ensure chunk is definitely loaded before applying a ticket
325-
io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
326-
.getChunkSource()
327-
.addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
321+
if (FOLIA_SUPPORT) {
322+
TaskManager.taskManager().taskNowMain(() -> serverLevel
323+
.getChunkSource()
324+
.addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
325+
} else {
326+
// Ensure chunk is definitely loaded before applying a ticket
327+
io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
328+
.getChunkSource()
329+
.addRegionTicket(TicketType.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
330+
}
331+
328332
}
329333

330334
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
@@ -464,12 +468,16 @@ public static LevelChunkSection newChunkSection(
464468
}
465469

466470
// Create palette with data
467-
@SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot
471+
@SuppressWarnings("deprecation")
472+
// constructor is deprecated on paper, but needed to keep compatibility with spigot
468473
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blockStatePalettedContainer =
469474
new PalettedContainer<>(
470475
Block.BLOCK_STATE_REGISTRY,
471476
PalettedContainer.Strategy.SECTION_STATES,
472-
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry),
477+
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(
478+
Block.BLOCK_STATE_REGISTRY,
479+
bitsPerEntry
480+
),
473481
nmsBits,
474482
palette
475483
);
@@ -660,7 +668,9 @@ static List<Entity> getEntities(LevelChunk chunk) {
660668
if (POST_CHUNK_REWRITE) {
661669
try {
662670
//noinspection unchecked
663-
return (List<Entity>) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ));
671+
return (List<Entity>) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level
672+
.getEntityLookup()
673+
.getChunk(chunk.locX, chunk.locZ));
664674
} catch (IllegalAccessException | InvocationTargetException e) {
665675
throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e);
666676
}

worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
173173
private final Field chunkProviderExecutorField;
174174
private final Watchdog watchdog;
175175

176+
private final Boolean folia;
177+
176178
// ------------------------------------------------------------------------
177179
// Code that may break between versions of Minecraft
178180
// ------------------------------------------------------------------------
@@ -186,6 +188,16 @@ public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException {
186188
throw new UnsupportedClassVersionError("Not 1.20(.1)!");
187189
}
188190

191+
boolean isFolia = false;
192+
try {
193+
// Assume API is present
194+
Class.forName("io.papermc.paper.threadedregions.scheduler.EntityScheduler");
195+
isFolia = true;
196+
} catch (Exception unused) {
197+
198+
}
199+
this.folia = isFolia;
200+
189201
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
190202
serverWorldsField.setAccessible(true);
191203

@@ -222,6 +234,10 @@ public PaperweightAdapter() throws NoSuchFieldException, NoSuchMethodException {
222234
}
223235
}
224236

237+
public Boolean isFolia() {
238+
return folia;
239+
}
240+
225241
@Override
226242
public DataFixer getDataFixer() {
227243
return PaperweightDataConverters.INSTANCE;

worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweAdapter.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@
8585
import org.bukkit.entity.Player;
8686

8787
import javax.annotation.Nullable;
88+
import java.lang.invoke.MethodHandle;
89+
import java.lang.invoke.MethodHandles;
8890
import java.lang.ref.WeakReference;
8991
import java.lang.reflect.Field;
9092
import java.lang.reflect.InvocationTargetException;
@@ -126,8 +128,47 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
126128
private boolean initialised = false;
127129
private Map<String, List<Property<?>>> allBlockProperties = null;
128130

131+
// Folia - START
132+
private MethodHandle currentWorldData;
133+
134+
private Class<?> regionizedWorldData;
135+
136+
private Field captureTreeGeneration;
137+
private Field captureBlockStates;
138+
private Field capturedBlockStates;
139+
140+
129141
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
130142
this.parent = new PaperweightAdapter();
143+
144+
if (this.parent.isFolia()) {
145+
Method getCurrentWorldData = ServerLevel.class.getSuperclass().getDeclaredMethod(
146+
"getCurrentWorldData"
147+
);
148+
getCurrentWorldData.setAccessible(true);
149+
try {
150+
currentWorldData = MethodHandles.lookup().unreflect(getCurrentWorldData);
151+
} catch (IllegalAccessException e) {
152+
}
153+
154+
try {
155+
regionizedWorldData = Class.forName("io.papermc.paper.threadedregions.RegionizedWorldData");
156+
} catch (ClassNotFoundException e) {
157+
}
158+
if (regionizedWorldData != null) {
159+
final Field captureTreeGeneration = regionizedWorldData.getDeclaredField("captureTreeGeneration");
160+
captureTreeGeneration.setAccessible(true);
161+
this.captureTreeGeneration = captureTreeGeneration;
162+
163+
final Field captureBlockStates = regionizedWorldData.getDeclaredField("captureBlockStates");
164+
captureBlockStates.setAccessible(true);
165+
this.captureBlockStates = captureBlockStates;
166+
167+
final Field capturedBlockStates = regionizedWorldData.getDeclaredField("capturedBlockStates");
168+
capturedBlockStates.setAccessible(true);
169+
this.capturedBlockStates = capturedBlockStates;
170+
}
171+
}
131172
}
132173

133174
@Nullable

worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightFaweWorldNativeAccess.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.fastasyncworldedit.core.util.TaskManager;
66
import com.fastasyncworldedit.core.util.task.RunnableVal;
77
import com.sk89q.worldedit.bukkit.BukkitAdapter;
8+
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter;
89
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
910
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
1011
import com.sk89q.worldedit.util.SideEffect;
@@ -27,6 +28,8 @@
2728
import org.bukkit.event.block.BlockPhysicsEvent;
2829

2930
import javax.annotation.Nullable;
31+
import java.lang.invoke.MethodHandle;
32+
import java.lang.invoke.MethodHandles;
3033
import java.lang.ref.WeakReference;
3134
import java.util.Collections;
3235
import java.util.HashSet;
@@ -52,14 +55,42 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
5255
private final AtomicInteger lastTick;
5356
private final Set<CachedChange> cachedChanges = new HashSet<>();
5457
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
58+
59+
private final MethodHandle globalTickData;
60+
private final Class<?> regionScheduleHandleClass;
61+
private final Class<?> regionizedServerClass;
62+
private final MethodHandle globalCurrentTick;
63+
5564
private SideEffectSet sideEffectSet;
5665

5766
public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference<Level> level) {
5867
this.paperweightFaweAdapter = paperweightFaweAdapter;
5968
this.level = level;
6069
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
6170
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
62-
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
71+
PaperweightAdapter adapter = (PaperweightAdapter) paperweightFaweAdapter.getParent();
72+
if (adapter.isFolia()) {
73+
try {
74+
regionizedServerClass = Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
75+
regionScheduleHandleClass = Class.forName(
76+
"io.papermc.paper.threadedregions.TickRegionScheduler$RegionScheduleHandle");
77+
globalTickData = MethodHandles.lookup().unreflect(regionizedServerClass.getDeclaredMethod("getGlobalTickData"));
78+
var data = globalTickData.invoke();
79+
globalCurrentTick = MethodHandles.lookup().unreflect(regionScheduleHandleClass.getDeclaredMethod(
80+
"getCurrentTick"));
81+
final long tick = (long) globalCurrentTick.invoke(data);
82+
this.lastTick = new AtomicInteger((int) tick);
83+
} catch (Throwable e) {
84+
throw new RuntimeException(e);
85+
}
86+
87+
} else {
88+
this.globalTickData = null;
89+
this.regionScheduleHandleClass = null;
90+
this.regionizedServerClass = null;
91+
this.globalCurrentTick = null;
92+
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
93+
}
6394
}
6495

6596
private Level getLevel() {
@@ -95,7 +126,18 @@ public synchronized net.minecraft.world.level.block.state.BlockState setBlockSta
95126
LevelChunk levelChunk, BlockPos blockPos,
96127
net.minecraft.world.level.block.state.BlockState blockState
97128
) {
98-
int currentTick = MinecraftServer.currentTick;
129+
int currentTick;
130+
PaperweightAdapter adapter = (PaperweightAdapter) paperweightFaweAdapter.getParent();
131+
if (adapter.isFolia()) {
132+
try {
133+
var data = globalTickData.invoke();
134+
currentTick = (int) globalCurrentTick.invoke(data);
135+
} catch (Throwable e) {
136+
throw new RuntimeException(e);
137+
}
138+
} else {
139+
currentTick = MinecraftServer.currentTick;
140+
}
99141
if (Fawe.isMainThread()) {
100142
return levelChunk.setBlockState(blockPos, blockState,
101143
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE)

worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightGetBlocks.java

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,23 @@
1212
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
1313
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
1414
import com.fastasyncworldedit.core.util.MathMan;
15+
import com.fastasyncworldedit.core.util.TaskManager;
1516
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
1617
import com.google.common.base.Suppliers;
1718
import com.sk89q.jnbt.CompoundTag;
1819
import com.sk89q.jnbt.ListTag;
1920
import com.sk89q.jnbt.StringTag;
2021
import com.sk89q.jnbt.Tag;
2122
import com.sk89q.worldedit.bukkit.BukkitAdapter;
23+
import com.sk89q.worldedit.bukkit.BukkitWorld;
2224
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
25+
import com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightAdapter;
2326
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
2427
import com.sk89q.worldedit.internal.Constants;
2528
import com.sk89q.worldedit.internal.util.LogManagerCompat;
2629
import com.sk89q.worldedit.math.BlockVector3;
30+
import com.sk89q.worldedit.math.Vector3;
31+
import com.sk89q.worldedit.util.Location;
2732
import com.sk89q.worldedit.world.biome.BiomeType;
2833
import com.sk89q.worldedit.world.biome.BiomeTypes;
2934
import com.sk89q.worldedit.world.block.BlockTypesCache;
@@ -82,6 +87,7 @@
8287
import java.util.concurrent.locks.ReentrantLock;
8388
import java.util.concurrent.locks.ReentrantReadWriteLock;
8489
import java.util.function.Function;
90+
import java.util.function.Supplier;
8591
import java.util.stream.Collectors;
8692

8793
import static net.minecraft.core.registries.Registries.BIOME;
@@ -256,13 +262,31 @@ public void removeSectionLighting(int layer, boolean sky) {
256262

257263
@Override
258264
public CompoundTag getTile(int x, int y, int z) {
259-
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
260-
chunkX << 4), y, (z & 15) + (
261-
chunkZ << 4)));
262-
if (blockEntity == null) {
263-
return null;
265+
PaperweightAdapter adapter = (PaperweightAdapter) this.adapter.getParent();
266+
if (adapter.isFolia()) {
267+
Supplier<BlockEntity> entity = () -> {
268+
var pos = new BlockPos((x & 15) + (
269+
chunkX << 4), y, (z & 15) + (
270+
chunkZ << 4));
271+
return getChunk().getBlockEntity(pos);
272+
};
273+
274+
if (entity == null) {
275+
return null;
276+
}
277+
return new PaperweightLazyCompoundTag(Suppliers.memoize(TaskManager.taskManager().syncAt(
278+
entity,
279+
new Location(new BukkitWorld(serverLevel.getWorld()), Vector3.at(x, y, z))
280+
)::saveWithId));
281+
} else {
282+
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
283+
chunkX << 4), y, (z & 15) + (
284+
chunkZ << 4)));
285+
if (blockEntity == null) {
286+
return null;
287+
}
288+
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId));
264289
}
265-
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId));
266290
}
267291

268292
@Override
@@ -788,7 +812,8 @@ public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finaliz
788812
final int z = blockHash.getZ() + bz;
789813
final BlockPos pos = new BlockPos(x, y, z);
790814

791-
synchronized (nmsWorld) {
815+
PaperweightAdapter adapter = (PaperweightAdapter) this.adapter.getParent();
816+
if (adapter.isFolia()) {
792817
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
793818
if (tileEntity == null || tileEntity.isRemoved()) {
794819
nmsWorld.removeBlockEntity(pos);
@@ -802,6 +827,22 @@ public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finaliz
802827
tag.put("z", IntTag.valueOf(z));
803828
tileEntity.load(tag);
804829
}
830+
} else {
831+
synchronized (nmsWorld) {
832+
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
833+
if (tileEntity == null || tileEntity.isRemoved()) {
834+
nmsWorld.removeBlockEntity(pos);
835+
tileEntity = nmsWorld.getBlockEntity(pos);
836+
}
837+
if (tileEntity != null) {
838+
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
839+
nativeTag);
840+
tag.put("x", IntTag.valueOf(x));
841+
tag.put("y", IntTag.valueOf(y));
842+
tag.put("z", IntTag.valueOf(z));
843+
tileEntity.load(tag);
844+
}
845+
}
805846
}
806847
}
807848
};

0 commit comments

Comments
 (0)