Skip to content

Commit

Permalink
ChunkHolder and partial implementation for ChunkMap
Browse files Browse the repository at this point in the history
  • Loading branch information
CursedFlames committed Feb 20, 2024
1 parent 6f05c43 commit 6a485b9
Show file tree
Hide file tree
Showing 19 changed files with 1,176 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/forge/resources/cubicchunks.mixins.forge.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"required": true,
"package": "io.github.opencubicchunks.cubicchunks.mixin.forge",
"refmap": "CubicChunks-refmap.json",
"plugin": "io.github.opencubicchunks.cubicchunks.mixin.ASMConfigPlugin",
"compatibilityLevel": "JAVA_17",
"minVersion": "0.8",
"injectors": {
Expand All @@ -10,8 +11,7 @@
"overwrites": {
"conformVisibility": true
},
"mixins": [
],
"mixins": [],
"client": [],
"server": []
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
package io.github.opencubicchunks.cubicchunks.mixin;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.function.Function;

import com.mojang.datafixers.util.Either;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.ConstructorToFactoryRedirect;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.FieldRedirect;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.FieldToMethodRedirect;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.MethodRedirect;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.TypeRedirect;
import io.github.notstirred.dasm.api.annotations.redirect.sets.RedirectContainer;
import io.github.notstirred.dasm.api.annotations.redirect.sets.RedirectSet;
import io.github.notstirred.dasm.api.annotations.selector.ConstructorMethodSig;
import io.github.notstirred.dasm.api.annotations.selector.FieldSig;
import io.github.notstirred.dasm.api.annotations.selector.MethodSig;
import io.github.notstirred.dasm.api.annotations.selector.Ref;
import io.github.opencubicchunks.cubicchunks.server.level.CubicChunkHolder;
import io.github.opencubicchunks.cubicchunks.server.level.CubicTicketType;
import io.github.opencubicchunks.cubicchunks.server.level.progress.CubicChunkProgressListener;
import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloAccess;
import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloPos;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.TicketType;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;

/**
* Generally should not be used directly for DASM transforms; prefer using {@link GeneralSet} instead.
Expand Down Expand Up @@ -59,6 +73,20 @@ abstract class ChunkTicketType_to_CloTicketType_redirects {
public static TicketType<CloPos> UNKNOWN;
}

@RedirectContainer(owner = @Ref(ChunkStatus.class))
abstract class ChunkStatus_redirects {
@MethodRedirect(@MethodSig("generate(Ljava/util/concurrent/Executor;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/chunk/ChunkGenerator;Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplateManager;Lnet/minecraft/server/level/ThreadedLevelLightEngine;Ljava/util/function/Function;Ljava/util/List;)Ljava/util/concurrent/CompletableFuture;"))
public abstract CompletableFuture<Either<CloAccess, ChunkHolder.ChunkLoadingFailure>> cc_generate(
Executor pExectutor,
ServerLevel pLevel,
ChunkGenerator pChunkGenerator,
StructureTemplateManager pStructureTemplateManager,
ThreadedLevelLightEngine pLightEngine,
Function<CloAccess, CompletableFuture<Either<CloAccess, ChunkHolder.ChunkLoadingFailure>>> pTask,
List<CloAccess> pCache
);
}

@TypeRedirect(from = @Ref(ChunkProgressListener.class), to = @Ref(CubicChunkProgressListener.class))
interface ChunkProgressListener_to_CubicChunkProgressListener_redirects { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.server.level;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

import javax.annotation.Nullable;

import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.datafixers.util.Either;
import io.github.notstirred.dasm.api.annotations.Dasm;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.AddFieldToSets;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.AddMethodToSets;
import io.github.notstirred.dasm.api.annotations.redirect.redirects.AddTransformToSets;
import io.github.notstirred.dasm.api.annotations.selector.FieldSig;
import io.github.notstirred.dasm.api.annotations.selector.MethodSig;
import io.github.notstirred.dasm.api.annotations.selector.Ref;
import io.github.notstirred.dasm.api.annotations.transform.TransformFromMethod;
import io.github.opencubicchunks.cc_core.utils.Coords;
import io.github.opencubicchunks.cubicchunks.mixin.GeneralSet;
import io.github.opencubicchunks.cubicchunks.server.level.CubicChunkHolder;
import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloAccess;
import io.github.opencubicchunks.cubicchunks.world.level.chunklike.CloPos;
import io.github.opencubicchunks.cubicchunks.world.level.chunklike.ImposterProtoClo;
import io.github.opencubicchunks.cubicchunks.world.level.chunklike.LevelClo;
import io.github.opencubicchunks.cubicchunks.world.level.cube.LevelCube;
import it.unimi.dsi.fastutil.shorts.ShortSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundSectionBlocksUpdatePacket;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunkSection;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Dasm(GeneralSet.class)
@Mixin(ChunkHolder.class)
public abstract class MixinChunkHolder implements CubicChunkHolder {
private boolean cc_isCubic;

@AddFieldToSets(sets = GeneralSet.class, owner = @Ref(ChunkHolder.class), field = @FieldSig(name = "pos", type = @Ref(ChunkPos.class)))
private CloPos cc_cloPos;

@AddFieldToSets(sets = GeneralSet.class, owner = @Ref(ChunkHolder.class), field = @FieldSig(name = "onLevelChange", type = @Ref(ChunkHolder.LevelChangeListener.class)))
private final CubicChunkHolder.LevelChangeListener cc_onLevelChange;
@AddFieldToSets(sets = GeneralSet.class, owner = @Ref(ChunkHolder.class), field = @FieldSig(name = "playerProvider", type = @Ref(ChunkHolder.PlayerProvider.class)))
private final CubicChunkHolder.PlayerProvider cc_playerProvider;

@AddMethodToSets(sets = GeneralSet.class, owner = @Ref(ChunkHolder.class), method = @MethodSig("getPos()Lnet/minecraft/world/level/ChunkPos;"))
@Override public CloPos cc_getPos() {
return cc_cloPos;
}

@Shadow private boolean hasChangedSections;
@Shadow @Final private final ShortSet[] changedBlocksPerSection;

@Shadow protected abstract void broadcastBlockEntityIfNeeded(List<ServerPlayer> pPlayers, Level pLevel, BlockPos pPos, BlockState pState);

@Shadow protected abstract void broadcast(List<ServerPlayer> pPlayers, Packet<?> pPacket);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("<init>(Lnet/minecraft/world/level/ChunkPos;ILnet/minecraft/world/level/LevelHeightAccessor;Lnet/minecraft/world/level/lighting/LevelLightEngine;"
+ "Lnet/minecraft/server/level/ChunkHolder$LevelChangeListener;Lnet/minecraft/server/level/ChunkHolder$PlayerProvider;)V"))
public MixinChunkHolder() {
throw new IllegalStateException("dasm failed to apply");
}

@Dynamic @Inject(at = @At("RETURN"), method = "cc_dasm$__init__(Lio/github/opencubicchunks/cubicchunks/world/level/chunklike/CloPos;ILnet/minecraft/world/level/LevelHeightAccessor;"
+ "Lnet/minecraft/world/level/lighting/LevelLightEngine;Lio/github/opencubicchunks/cubicchunks/server/level/CubicChunkHolder$LevelChangeListener;"
+ "Lio/github/opencubicchunks/cubicchunks/server/level/CubicChunkHolder$PlayerProvider;)V")
private void onCcInit(CallbackInfo ci) {
// TODO redirect changedBlocksPerSection construction for chunks
cc_isCubic = true;
}

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("getTickingChunk()Lnet/minecraft/world/level/chunk/LevelChunk;"))
@Nullable public native LevelClo cc_getTickingChunk();

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("getChunkToSend()Lnet/minecraft/world/level/chunk/LevelChunk;"))
@Nullable public native LevelClo cc_getChunkToSend();

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("getFullChunk()Lnet/minecraft/world/level/chunk/LevelChunk;"))
@Nullable public native LevelClo cc_getFullChunk();

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("getLastAvailable()Lnet/minecraft/world/level/chunk/ChunkAccess;"))
@Nullable public native CloAccess cc_getLastAvailable();

// dasm + mixin
@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("blockChanged(Lnet/minecraft/core/BlockPos;)V"))
public native void cc_blockChanged(BlockPos pos);

/**
* Only handle block changes for cubes, as this should not be tracked on columns
*/
@Dynamic @Inject(method = "cc_dasm$cc_blockChanged",
at = @At(value = "INVOKE_ASSIGN", shift = At.Shift.AFTER,
target = "Lnet/minecraft/server/level/ChunkHolder;cc_getTickingChunk()Lio/github/opencubicchunks/cubicchunks/world/level/chunklike/LevelClo;"
),
cancellable = true)
private void cc_blockChanged_checkCubic(BlockPos pos, CallbackInfo ci, @Local LevelClo clo) {
if (clo instanceof ChunkAccess) ci.cancel();
}

/**
* Redirect to use cube section indexing instead of chunk section indexing
*/
@Dynamic @Redirect(method = "cc_dasm$cc_blockChanged", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/LevelHeightAccessor;getSectionIndex(I)I"))
private int cc_blockChanged_sectionIndex(LevelHeightAccessor instance, int y, BlockPos pos) {
return Coords.blockToIndex(pos);
}

// We want a different signature (see below); can't automatically redirect this one
@Inject(method = "sectionLightChanged", at = @At("HEAD"))
private void onSectionLightChanged(LightLayer pType, int pSectionY, CallbackInfo ci) {
// We should be calling the cubic signature instead
assert !cc_isCubic;
}

@AddMethodToSets(sets = GeneralSet.class, owner = @Ref(ChunkHolder.class), method = @MethodSig("sectionLightChanged(Lnet/minecraft/world/level/LightLayer;I)V"))
public void cc_sectionLightChanged(LightLayer pType, SectionPos pos) {
// TODO (P2) lighting
}

@AddMethodToSets(sets = GeneralSet.class, owner = @Ref(ChunkHolder.class), method = @MethodSig("broadcastChanges(Lnet/minecraft/world/level/chunk/LevelChunk;)V"))
public void cc_broadcastChanges(LevelClo clo) {
// TODO (P2) also handle lighting - see vanilla method
// TODO seems like this should only run for cubes; is that correct?
if (this.hasChangedSections && clo instanceof LevelCube cube) {
Level level = cube.getLevel();

List<ServerPlayer> list1 = this.cc_playerProvider.getPlayers(this.cc_cloPos, false);

for(int j = 0; j < this.changedBlocksPerSection.length; ++j) {
ShortSet shortset = this.changedBlocksPerSection[j];
if (shortset != null) {
this.changedBlocksPerSection[j] = null;
if (!list1.isEmpty()) {
SectionPos sectionpos = Coords.sectionPosByIndex(cube.cc_getCloPos().cubePos(), j);
if (shortset.size() == 1) {
BlockPos blockpos = sectionpos.relativeToBlockPos(shortset.iterator().nextShort());
BlockState blockstate = level.getBlockState(blockpos);
this.broadcast(list1, new ClientboundBlockUpdatePacket(blockpos, blockstate));
this.broadcastBlockEntityIfNeeded(list1, level, blockpos, blockstate);
} else {
LevelChunkSection levelchunksection = cube.getSection(j);
ClientboundSectionBlocksUpdatePacket clientboundsectionblocksupdatepacket = new ClientboundSectionBlocksUpdatePacket(
sectionpos, shortset, levelchunksection
);
this.broadcast(list1, clientboundsectionblocksupdatepacket);
clientboundsectionblocksupdatepacket.runUpdates(
(p_288761_, p_288762_) -> this.broadcastBlockEntityIfNeeded(list1, level, p_288761_, p_288762_)
);
}
}
}
}

this.hasChangedSections = false;
}
}

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("getOrScheduleFuture(Lnet/minecraft/world/level/chunk/ChunkStatus;Lnet/minecraft/server/level/ChunkMap;)Ljava/util/concurrent/CompletableFuture;"))
@Override public native CompletableFuture<Either<CloAccess, ChunkHolder.ChunkLoadingFailure>> cc_getOrScheduleFuture(ChunkStatus status, ChunkMap map);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("addSaveDependency(Ljava/lang/String;Ljava/util/concurrent/CompletableFuture;)V"))
protected native void cc_addSaveDependency(String source, CompletableFuture<?> future);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("updateChunkToSave(Ljava/util/concurrent/CompletableFuture;Ljava/lang/String;)V"))
private native void cc_updateChunkToSave(CompletableFuture<? extends Either<? extends CloAccess, ChunkHolder.ChunkLoadingFailure>> future, String source);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("scheduleFullChunkPromotion(Lnet/minecraft/server/level/ChunkMap;Ljava/util/concurrent/CompletableFuture;Ljava/util/concurrent/Executor;Lnet/minecraft/server/level/FullChunkStatus;)V"))
private native void cc_scheduleFullChunkPromotion(
ChunkMap chunkMap, CompletableFuture<Either<LevelClo, ChunkHolder.ChunkLoadingFailure>> future, Executor executor, FullChunkStatus fullChunkStatus
);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("demoteFullChunk(Lnet/minecraft/server/level/ChunkMap;Lnet/minecraft/server/level/FullChunkStatus;)V"))
private native void cc_demoteFullChunk(ChunkMap chunkMap, FullChunkStatus fullChunkStatus);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("updateFutures(Lnet/minecraft/server/level/ChunkMap;Ljava/util/concurrent/Executor;)V"))
protected native void cc_updateFutures(ChunkMap chunkMap, Executor executor);

@AddTransformToSets(GeneralSet.class) @TransformFromMethod(
value = @MethodSig("replaceProtoChunk(Lnet/minecraft/world/level/chunk/ImposterProtoChunk;)V"))
public native void cc_replaceProtoChunk(ImposterProtoClo imposter);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.server.level;

import io.github.opencubicchunks.cubicchunks.world.level.chunklike.LevelClo;
import net.minecraft.server.level.ChunkHolder;
import org.spongepowered.asm.mixin.Mixin;

// FIXME should be in forge sourceset once tests run against forge
@Mixin(ChunkHolder.class)
public class MixinChunkHolder_Forge {
// Field added by Forge
LevelClo currentlyLoading;
}
Loading

0 comments on commit 6a485b9

Please sign in to comment.