Skip to content

Commit

Permalink
Partially implemented MixinMinecraftServer (tests are still not funct…
Browse files Browse the repository at this point in the history
…ional)
  • Loading branch information
seelderr committed Jan 24, 2024
1 parent daffd35 commit 6ebf857
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
package io.github.opencubicchunks.cubicchunks.mixin.core.common.server;

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.Share;
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
import io.github.opencubicchunks.cc_core.api.CubePos;
import io.github.opencubicchunks.cc_core.api.CubicConstants;
import io.github.opencubicchunks.cc_core.world.SpawnPlaceFinder;
import io.github.opencubicchunks.cubicchunks.CanBeCubic;
import io.github.opencubicchunks.cubicchunks.MarkableAsCubic;
import net.minecraft.core.BlockPos;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.storage.ServerLevelData;
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;

@Mixin(MinecraftServer.class)
public abstract class MixinMinecraftServer {
@Shadow public abstract ServerLevel overworld();

@Shadow public abstract boolean isRunning();

@Shadow protected long nextTickTimeNanos;

@Shadow protected abstract void waitUntilNextTick();

@Inject(method = "setInitialSpawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/ChunkPos;<init>(Lnet/minecraft/core/BlockPos;)V"))
private static void cc_replaceChunkPosInSetInitialSpawn(ServerLevel serverLevel, ServerLevelData serverLevelData, boolean generateBonusChest, boolean debug, CallbackInfo ci, @Share(
"cubePos") LocalRef<CubePos> cubePosLocalRef) {
if(((CanBeCubic) serverLevel).cc_isCubic()) {
if (((CanBeCubic) serverLevel).cc_isCubic()) {
CubePos cubePos = new CubePos(serverLevel.getChunkSource().randomState().sampler().findSpawnPosition());
cubePosLocalRef.set(cubePos);
}
Expand All @@ -31,16 +46,53 @@ private static void cc_replaceChunkPosInSetInitialSpawn(ServerLevel serverLevel,
@WrapOperation(method = "setInitialSpawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/ChunkPos;getWorldPosition()Lnet/minecraft/core/BlockPos;"))
private static BlockPos cc_replaceGetWorldPositionInSetInitialSpawn(ChunkPos chunkPos, Operation<BlockPos> original, ServerLevel serverLevel, @Share(
"cubePos") LocalRef<CubePos> cubePosLocalRef) {
if(((CanBeCubic) serverLevel).cc_isCubic()) {
if (((CanBeCubic) serverLevel).cc_isCubic()) {
return cubePosLocalRef.get().asChunkPos().getWorldPosition();
}
return null;
}

// change getheight to funny algorithm that barteks wrote
@WrapOperation(method = "setInitialSpawn",
at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;getHeight(Lnet/minecraft/world/level/levelgen/Heightmap$Types;II)I"))
private static int cc_replaceGetHeightWithSpawnPlaceFinder(ServerLevel serverLevel, Heightmap.Types heightmapType, int x, int z, Operation<Integer> original,
@Share("cubePos") LocalRef<CubePos> cubePosLocalRef) {
if (((CanBeCubic) serverLevel).cc_isCubic()) {
BlockPos topBlockBisect = SpawnPlaceFinder.getTopBlockBisect(serverLevel, cubePosLocalRef.get().asBlockPos(), false,
pos -> serverLevel.getBlockState(pos).is(BlockTags.VALID_SPAWN),
pos -> serverLevel.getBlockState(pos).getCollisionShape(serverLevel, pos).isEmpty());
if (topBlockBisect != null) {
return topBlockBisect.getY();
} else {
return serverLevel.getSeaLevel() + 1;
}
}
return original.call(serverLevel, heightmapType, x, z);
}

// setInitialSpawn - mixin
// TODO: Fix this when ServerChunkCache exists
@WrapWithCondition(method = "prepareLevels", at = @At(value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"))
private <T> boolean cc_replaceAddRegionTicketInPrepareLevels(ServerChunkCache serverChunkCache, TicketType<T> ticketType, ChunkPos chunkPos, int originalSpawnRadius, T unit,
@Share("spawnRadius") LocalRef<Integer> spawnRadiusRef) {
if (((CanBeCubic) serverChunkCache).cc_isCubic()) {
int spawnRadius = (int) Math.ceil(10 * (16 / (float) CubicConstants.DIAMETER_IN_BLOCKS)); //vanilla is 10, 32: 5, 64: 3
spawnRadiusRef.set(spawnRadius);
//(CubicServerChunkCache)serverChunkCache.addRegionTicket(CubicTicketType.START, CloPos.cube(overworld().getSharedSpawnPos()), spawnRadius + 1, unit);
return false;
}
return true;
}

// prepareLevels - mixin
@Inject(method = "prepareLevels", at = @At(value = "FIELD", target = "Lnet/minecraft/server/MinecraftServer;nextTickTimeNanos:J"))
private void cc_waitUntilCubicGenerationComplete(CallbackInfo ci, @Share("spawnRadius") LocalRef<Integer> spawnRadiusRef) {
if (((CanBeCubic) overworld().getChunkSource()).cc_isCubic()) {
int d = spawnRadiusRef.get() * 2 + 1;
//while (this.isRunning() && ((CubicServerChunkCache) overworld().getChunkSource()).getTickingGeneratedCubes() < d * d * d) {
// this.nextTickTimeNanos = Util.getMillis() + 10L;
// this.waitUntilNextTick();
//}
}
}

// TODO: forced cubes will need to be implemented for prepareLevels as well in the same way as above
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ private static void getOverworldRespawnPos(ServerLevel level, int posX, int posZ
return;
}
cir.setReturnValue(SpawnPlaceFinder.getTopBlockBisect(level, new BlockPos(posX, 0, posZ), false,
pos -> level.getBlockState((BlockPos) pos).is(BlockTags.VALID_SPAWN),
pos -> level.getBlockState((BlockPos) pos).getCollisionShape(level, (BlockPos) pos).isEmpty()));
pos -> level.getBlockState(pos).is(BlockTags.VALID_SPAWN),
pos -> level.getBlockState(pos).getCollisionShape(level, pos).isEmpty()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.github.opencubicchunks.cubicchunks.mixin.test.common.server.level;

import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.level.storage.ServerLevelData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;

@Mixin(MinecraftServer.class)
public interface MinecraftServerTestAccess {

@Invoker(value = "prepareLevels")
void invoke_prepareLevels(ChunkProgressListener chunkProgressListener);

@Invoker(value = "setInitialSpawn")
void invoke_setInitialSpawn(ServerLevel serverLevel, ServerLevelData serverLevelData, boolean p_177899_, boolean p_177900_);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,26 @@

import static io.github.opencubicchunks.cubicchunks.testutils.Setup.setupTests;

import static io.github.opencubicchunks.cubicchunks.testutils.Misc.setupServerLevel;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;

import io.github.opencubicchunks.cubicchunks.MarkableAsCubic;
import io.github.opencubicchunks.cubicchunks.mixin.test.common.server.level.MinecraftServerTestAccess;
import io.github.opencubicchunks.cubicchunks.testutils.CloseableReference;
import net.minecraft.client.server.IntegratedServer;
import net.minecraft.core.registries.Registries;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.WorldStem;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.dimension.LevelStem;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.mockito.Answers;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestMinecraftServer {
Expand All @@ -13,11 +30,24 @@ public static void setup() {
setupTests();
}

@Test public void testSetInitialSpawnVanilla() {
// TODO
private MinecraftServer setupServer() {
WorldStem worldStemMock = mock(WorldStem.class, withSettings().defaultAnswer(Answers.RETURNS_DEEP_STUBS));
when(worldStemMock.registries().compositeAccess().registryOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)).thenReturn(true);
return new IntegratedServer(mock(RETURNS_DEEP_STUBS), mock(RETURNS_DEEP_STUBS), mock(RETURNS_DEEP_STUBS), mock(RETURNS_DEEP_STUBS), worldStemMock, mock(RETURNS_DEEP_STUBS),
mock(RETURNS_DEEP_STUBS));
}

//TODO: These tests are disabled for now since MinecraftServer creates a ServerFunctionManager which eventually tries to copy a null array. Not sure how to mock that right now.
@Test @Disabled public void testSetInitialSpawnVanilla() throws Exception {
try (CloseableReference<ServerLevel> serverLevelReference = setupServerLevel()) {
((MarkableAsCubic)serverLevelReference.value()).cc_setCubic();
((MinecraftServerTestAccess)setupServer()).invoke_setInitialSpawn(serverLevelReference.value(), mock(RETURNS_DEEP_STUBS), false, false);
}
}

@Test public void testPrepareLevelsVanilla() {
// TODO
@Test @Disabled public void testPrepareLevelsVanilla() throws Exception {
MinecraftServer server = setupServer();
((MarkableAsCubic)server.overworld()).cc_setCubic();
((MinecraftServerTestAccess)setupServer()).invoke_prepareLevels(mock());
}
}
3 changes: 2 additions & 1 deletion src/test/resources/cubicchunks.mixins.test.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
},
"mixins": [
"common.server.level.ChunkTrackerTestAccess",
"common.server.level.CubicDistanceManagerTestAccess"
"common.server.level.CubicDistanceManagerTestAccess",
"common.server.level.MinecraftServerTestAccess"
],
"client": [],
"server": []
Expand Down

0 comments on commit 6ebf857

Please sign in to comment.