Skip to content

Commit

Permalink
Implemented ServerLevel, ServerPlayer, Level, ClientLevel for Phase 1…
Browse files Browse the repository at this point in the history
… functionality
  • Loading branch information
seelderr committed Jan 21, 2024
1 parent abd7ddd commit cb864a8
Show file tree
Hide file tree
Showing 19 changed files with 700 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.opencubicchunks.cubicchunks;

public interface CanBeCubic {
boolean cc_isCubic();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package io.github.opencubicchunks.cubicchunks;

public interface MarkableAsCubic {
public interface MarkableAsCubic extends CanBeCubic {
void cc_setCubic();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@

import io.github.opencubicchunks.cubicchunks.MarkableAsCubic;
import io.github.opencubicchunks.cubicchunks.client.multiplayer.CubicClientLevel;
import io.github.opencubicchunks.cubicchunks.mixin.core.common.world.level.MixinLevel;
import net.minecraft.client.multiplayer.ClientLevel;
import org.spongepowered.asm.mixin.Mixin;

@Mixin(ClientLevel.class)
public class MixinClientLevel implements CubicClientLevel, MarkableAsCubic {
public abstract class MixinClientLevel extends MixinLevel implements CubicClientLevel, MarkableAsCubic {
protected boolean cc_isCubic;

@Override
public void cc_setCubic() { cc_isCubic = true;}

@Override public boolean cc_isCubic() {
return cc_isCubic;
}

@Override public boolean cc_hasCube(int x, int y, int z) {
return true;
}

// unload
// TODO: Phase 2 - this interacts with the lighting engine and will need to change to support cubes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
public abstract class MixinChunkTaskPriorityQueue implements MarkableAsCubic {
protected boolean cc_isCubic;

@Override
public void cc_setCubic() {
@Override public void cc_setCubic() {
cc_isCubic = true;
}

@Override public boolean cc_isCubic() {
return cc_isCubic;
}

@Inject(method = "resortChunkTasks", at = @At("HEAD"))
private void cc_onResortChunkTasks(int p_140522_, ChunkPos p_140523_, int p_140524_, CallbackInfo ci) {
assert !cc_isCubic;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,14 @@
public abstract class MixinChunkTaskPriorityQueueSorter implements CubicTaskPriorityQueueSorter, MarkableAsCubic {
protected boolean cc_isCubic;

@Override
public void cc_setCubic() {
@Override public void cc_setCubic() {
cc_isCubic = true;
}

@Override public boolean cc_isCubic() {
return cc_isCubic;
}

/**
* This is a method that is only used for debugging, so we don't currently test it.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public void cc_setCubic() {
cc_noChunkLevel = levelCount-1;
}

@Override public boolean cc_isCubic() {
return cc_isCubic;
}

@Redirect(method="*", at = @At(value = "FIELD", target = "Lnet/minecraft/world/level/ChunkPos;INVALID_CHUNK_POS:J"))
private long cc_sentinelValue() {
if (cc_isCubic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ public void cc_setCubic() {
cc_isCubic = true;
}

@Override public boolean cc_isCubic() {
return cc_isCubic;
}

@Inject(method = {"addTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V",
"removeTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V",
"addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,21 @@ public void cc_setCubic() {
cc_isCubic = true;
}

// isNaturalSpawningAllowed - mixin? new function?
@Override
public boolean cc_isCubic() {
return cc_isCubic;
}

// TODO: phase 3 - isNaturalSpawningAllowed

// invalidateCapabilites - phase 3, neoforge api
// TODO: phase 3 - invalidateCapabilites, neoforge api

// tickCube - new function
// TODO: phase 2 - tickCube - new function

// setCubeForced - new function
// TODO: phase 4 - setCubeForced - new function

// saveDebugReport - mixins, debug only, low priority
// TODO: saveDebugReport - mixins, debug only, low priority, if we really really really really need it

// isPositionEntityTicking - mixin
// TODO: phase 2 - isPositionEntityTicking - mixin

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ public void cc_setCubic() {
cc_isCubic = true;
}

@Override public boolean cc_isCubic() {
return cc_isCubic;
}

/**
* This mixin steals the x/y/z coordinates from a call to ChunkPos and replaces the ChunkPos in the addRegionTicketCall with a CloPos instead.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,209 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.level;

import javax.annotation.Nullable;

import com.llamalad7.mixinextras.injector.WrapWithCondition;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import com.llamalad7.mixinextras.sugar.Share;
import io.github.opencubicchunks.cc_core.utils.Coords;
import io.github.opencubicchunks.cubicchunks.MarkableAsCubic;
import io.github.opencubicchunks.cubicchunks.mixin.TransformFrom;
import io.github.opencubicchunks.cubicchunks.world.level.CubicLevelReader;
import io.github.opencubicchunks.cubicchunks.world.level.cube.CubicChunkSource;
import io.github.opencubicchunks.cubicchunks.world.level.CubicLevel;
import io.github.opencubicchunks.cubicchunks.world.level.cube.CubeAccess;
import io.github.opencubicchunks.cubicchunks.world.level.cube.LevelCube;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.material.FluidState;
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.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(Level.class)
public class MixinLevel implements CubicLevel, MarkableAsCubic {
protected boolean cc_isCubic;

@Override
public void cc_setCubic() { cc_isCubic = true;}

// getCubeAt - new function

// getCube (LevelChunk) - new function

// getCube (ChunkAccess) - new function

// setBlock - mixin
public abstract class MixinLevel implements CubicLevel, MarkableAsCubic, LevelAccessor {
@Shadow @Nullable public abstract ChunkAccess getChunk(int p_46502_, int p_46503_, ChunkStatus p_46504_, boolean p_46505_);

// markAndNotifyBlock - maybe?
@Shadow public abstract long getDayTime();

// getBlockState - mixin

// getBlockEntity - mixin

// setBlockEntity - mixin

// removeBlockEntity - mixin

// isLoaded - mixin
protected boolean cc_isCubic;

// loadedAndEntityCanStandOnFace - mixin
@Override
public void cc_setCubic() {
cc_isCubic = true;
}

// getChunkForCollisions - mixin
@Override public boolean cc_isCubic() {
return cc_isCubic;
}

// blockEntityChanged - mixin
public LevelCube cc_getCubeAt(BlockPos blockPos) {
return (LevelCube)((CubicLevelReader)this).cc_getCube(Coords.blockToCube(blockPos.getX()), Coords.blockToCube(blockPos.getY()),
Coords.blockToCube(blockPos.getZ()));
}

// getCurrentDifficultyAt - mixin
public LevelCube cc_getCube(int x, int y, int z) {
return (LevelCube)this.cc_getCube(x, y, z, ChunkStatus.FULL);
}

// TODO: Phase 3 low priority: Add a method to modify isOutsideSpawnableHeight to go from -30 mil to 30 mil, not -20 mil to 20 mil
@Nullable
@Override
public CubeAccess cc_getCube(int cubeX, int cubeY, int cubeZ, ChunkStatus status, boolean forceLoad) {
CubeAccess cubeaccess = ((CubicChunkSource)this.getChunkSource()).cc_getCube(cubeX, cubeY, cubeZ, status, forceLoad);
if (cubeaccess == null && forceLoad) {
throw new IllegalStateException("Should always be able to create a cube!");
} else {
return cubeaccess;
}
}

// setBlock
@WrapOperation(method = "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level"
+ "/Level;getChunkAt(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/chunk/LevelChunk;"))
private LevelChunk cc_replaceLevelChunkInGetChunkAt(Level level, BlockPos blockPos, Operation<LevelChunk> original, @Share("levelCube") LocalRef<LevelCube> levelCubeLocalRef) {
if(cc_isCubic) {
levelCubeLocalRef.set(this.cc_getCubeAt(blockPos));
return null;
}
return original.call(level, blockPos);
}

@WrapOperation(method = "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;setBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Z)Lnet/minecraft/world/level/block/state/BlockState;"))
private BlockState cc_replaceLevelChunkInSetBlockState(LevelChunk levelChunk, BlockPos blockPos, BlockState blockState, boolean flag1, Operation<BlockState> original,
@Share("levelCube") LocalRef<LevelCube> levelCubeLocalRef) {
if(cc_isCubic) {
levelCubeLocalRef.get().setBlockState(blockPos, blockState, flag1);
return null;
}
return original.call(levelChunk, blockPos, blockState, flag1);
}

@WrapWithCondition(method = "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;markAndNotifyBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;II)V"))
private boolean cc_replaceLevelChunkInMarkAndNotifyBlock(Level level, BlockPos blockPos, LevelChunk levelChunk, BlockState blockStatePrev, BlockState blockStateNew, int flags,
int p_46607_, @Share("levelCube") LocalRef<LevelCube> levelCubeLocalRef) {
if(cc_isCubic) {
this.markAndNotifyBlock(blockPos, levelCubeLocalRef.get(), blockStatePrev, blockStateNew, flags, p_46607_);
return false;
}
return true;
}

@TransformFrom("markAndNotifyBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;II)V")
public native void markAndNotifyBlock(BlockPos blockPos, @Nullable LevelCube levelCube, BlockState blockStatePrev, BlockState blockStateNew, int flags, int p_46608_);

// getBlockState
@Inject(method = "getBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getChunk(II)Lnet/minecraft/world/level/chunk/LevelChunk;"))
private void cc_replaceLevelChunkInGetBlockState(BlockPos blockPos, CallbackInfoReturnable<BlockState> cir, @Share("levelCube") LocalRef<LevelCube> levelCubeLocalRef) {
if(cc_isCubic) {
levelCubeLocalRef.set(this.cc_getCubeAt(blockPos));
}
}

@WrapOperation(method = "getBlockState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;getBlockState(Lnet/minecraft/core/BlockPos;)"
+ "Lnet/minecraft/world/level/block/state/BlockState;"))
private BlockState cc_replaceLevelChunkInGetBlockState(LevelChunk levelChunk, BlockPos blockPos, Operation<BlockState> original,
@Share("levelCube") LocalRef<LevelCube> levelCubeLocalRef) {
if(cc_isCubic) {
return levelCubeLocalRef.get().getBlockState(blockPos);
}
return original.call(levelChunk, blockPos);
}

// getBlockEntity
@Inject(method = "getBlockEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getChunkAt(Lnet/minecraft/core/BlockPos;)"
+ "Lnet/minecraft/world/level/chunk/LevelChunk;"), cancellable = true)
private void cc_replaceGetChunkAtInSetBlockEntity(BlockPos blockPos, CallbackInfoReturnable<BlockEntity> cir) {
if(cc_isCubic) {
cir.setReturnValue(this.cc_getCubeAt(blockPos).getBlockEntity(blockPos, LevelChunk.EntityCreationType.IMMEDIATE));
}
}

// getFluidState
@WrapOperation(method = "getFluidState", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/chunk/LevelChunk;getFluidState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/material/FluidState;"))
private FluidState cc_replaceGetChunkAtInGetFluidState(LevelChunk levelChunk, BlockPos blockPos, Operation<FluidState> original) {
if(cc_isCubic) {
return this.cc_getCubeAt(blockPos).getFluidState(blockPos);
}
return original.call(levelChunk, blockPos);
}

// setBlockEntity
@Inject(method = "setBlockEntity", at = @At(value="INVOKE", target="Lnet/minecraft/world/level/Level;getChunkAt(Lnet/minecraft/core/BlockPos;)"
+ "Lnet/minecraft/world/level/chunk/LevelChunk;"), cancellable=true)
private void cc_replaceLevelChunkInSetBlockEntity(BlockEntity blockEntity, CallbackInfo ci, @Local(ordinal = 0) BlockPos blockPos) {
if(cc_isCubic) {
this.cc_getCubeAt(blockPos).addAndRegisterBlockEntity(blockEntity);
ci.cancel();
}
}

// removeBlockEntity
@Inject(method = "removeBlockEntity", at = @At(value="INVOKE", target="Lnet/minecraft/world/level/Level;getChunkAt(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/chunk/LevelChunk;"), cancellable=true)
private void cc_replaceGetChunkAtInRemoveBlockEntity(BlockPos blockPos, CallbackInfo ci) {
if(cc_isCubic) {
this.cc_getCubeAt(blockPos).removeBlockEntity(blockPos);
ci.cancel();
}
}

// isLoaded
@WrapOperation(method = "isLoaded", at = @At(value="INVOKE", target="Lnet/minecraft/world/level/chunk/ChunkSource;hasChunk(II)Z"))
private boolean cc_replaceHasChunkInIsLoaded(ChunkSource chunkSource, int x, int z, Operation<Boolean> original, BlockPos blockPos) {
if(cc_isCubic) {
return ((CubicChunkSource)this.getChunkSource()).cc_hasCube(Coords.blockToCube(blockPos.getX()), Coords.blockToCube(blockPos.getY()), Coords.blockToCube(blockPos.getZ()));
}
return false;
}

// loadedAndEntityCanStandOnFace
@Inject(method = "loadedAndEntityCanStandOnFace", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;getChunk(IILnet/minecraft/world/level/chunk/ChunkStatus;Z)"
+ "Lnet/minecraft/world/level/chunk/ChunkAccess;"), cancellable = true)
private void cc_replaceGetChunkAtInLoadedAndEntityCanStandOnFace(BlockPos blockPos, Entity entity, Direction direction, CallbackInfoReturnable<Boolean> cir) {
if(cc_isCubic) {
CubeAccess cubeAccess = this.cc_getCube(Coords.blockToCube(blockPos.getX()), Coords.blockToCube(blockPos.getY()), Coords.blockToCube(blockPos.getZ()), ChunkStatus.FULL, false);
cir.setReturnValue(cubeAccess == null ? false : cubeAccess.getBlockState(blockPos).entityCanStandOnFace(this, blockPos, entity, direction));
}
}

// blockEntityChanged
@Inject(method = "blockEntityChanged", at = @At(value = "HEAD"), cancellable = true)
private void cc_replaceBlockEntityChanged(BlockPos blockPos, CallbackInfo ci) {
if(cc_isCubic) {
if (this.cc_hasCubeAt(blockPos)) {
this.cc_getCubeAt(blockPos).setUnsaved(true);
}
ci.cancel();
}
}

// getCurrentDifficultyAt
@Inject(method = "getCurrentDifficultyAt", at = @At(value = "HEAD"), cancellable = true)
private void cc_replaceGetCurrentDifficultyAt(BlockPos blockPos, CallbackInfoReturnable<DifficultyInstance> cir) {
if(cc_isCubic) {
long i = 0L;
float f = 0.0F;
if (this.cc_hasCubeAt(blockPos)) {
f = this.getMoonBrightness();
i = this.cc_getCubeAt(blockPos).getInhabitedTime();
}
cir.setReturnValue(new DifficultyInstance(this.getDifficulty(), this.getDayTime(), i, f));
}
}
// TODO: Phase 3 low priority: Add a method to modify isOutsideSpawnableHeight to respect the limits of the packing for CloPos
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.world.level;

import io.github.opencubicchunks.cubicchunks.world.level.CubicLevelReader;
import net.minecraft.world.level.LevelReader;
import org.spongepowered.asm.mixin.Mixin;

@Mixin(LevelReader.class)
public interface MixinLevelReader extends CubicLevelReader {}
Loading

0 comments on commit cb864a8

Please sign in to comment.