Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
package com.cardinalstar.cubicchunks.api.world;

import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;

import org.jetbrains.annotations.NotNull;

import com.cardinalstar.cubicchunks.api.IntRange;
import com.cardinalstar.cubicchunks.api.worldgen.IWorldGenerator;

/// Implemented on a [WorldProvider] so that it can directly generate its cubes, instead of going through
/// [VanillaWorldGenerator].
/// Implemented on a [WorldProvider]. This is primarily used by mods to make their dimensions cubic. [ICubicWorldType]
/// takes priority over this interface. When a [WorldProvider] does not implement this interface,
/// [WorldProvider#createChunkGenerator()] is called and the result is wrapped by a [VanillaWorldGenerator].
public interface ICubicWorldProvider {

/// @deprecated New parameter: implement [#createCubeGenerator(IChunkProvider)] instead.
@Deprecated

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why even have this method at this point? Any reason to leave it deprecated instead of removing?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, there are a few projects that use these. Galaxia in specific uses this interface and I don't want it breaking randomly.

@NotNull
IWorldGenerator createWorldGenerator(World world);
default IWorldGenerator createCubeGenerator() {
throw new UnsupportedOperationException();
}

@NotNull
default IWorldGenerator createCubeGenerator(IChunkProvider chunkGenerator) {
return createCubeGenerator();
}

/// @deprecated Renamed: implement [#getGenerationRange()] instead.
@Deprecated
default int getOriginalActualHeight() {
throw new UnsupportedOperationException();
}

default IntRange getGenerationRange() {
return new IntRange(0, getOriginalActualHeight());
}

/// @deprecated Pointless due to public field: safe to remove
@Deprecated
default World getWorld() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,40 @@

import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.IChunkProvider;

import org.jetbrains.annotations.NotNull;

import com.cardinalstar.cubicchunks.api.IntRange;
import com.cardinalstar.cubicchunks.api.worldgen.IWorldGenerator;

/// Implemented on [WorldType] references to override other world generators. World types take priority over
/// [WorldProvider]s that implement [ICubicWorldProvider]. When neither interface is present,
/// [WorldProvider#createChunkGenerator()] is called and the result is wrapped by a [VanillaWorldGenerator].
@ParametersAreNonnullByDefault
public interface ICubicWorldType {

/// @deprecated New parameter: implement [#createCubeGenerator(WorldServer, IChunkProvider)] instead.
@Deprecated
@NotNull
IWorldGenerator createCubeGenerator(World world);
default IWorldGenerator createCubeGenerator(World world) {
throw new UnsupportedOperationException();
}

IntRange calculateGenerationHeightRange(WorldServer world);
@NotNull
default IWorldGenerator createCubeGenerator(WorldServer world, IChunkProvider chunkGenerator) {
return createCubeGenerator(world);
}

/// @deprecated Renamed: implement [#getGenerationRange(World)] instead.
@Deprecated
default IntRange calculateGenerationHeightRange(World world) {
throw new UnsupportedOperationException();
}

default IntRange getGenerationRange(World world) {
return calculateGenerationHeightRange(world);
}

boolean hasCubicGeneratorForWorld(World object);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldType;
import net.minecraft.world.chunk.IChunkProvider;

import org.jetbrains.annotations.NotNull;

import com.cardinalstar.cubicchunks.api.IntRange;
import com.cardinalstar.cubicchunks.api.world.ICubicWorldType;
import com.cardinalstar.cubicchunks.api.worldgen.BuiltinWorldDecorators;
import com.cardinalstar.cubicchunks.api.worldgen.IWorldGenerator;
import com.cardinalstar.cubicchunks.world.ICubicWorldProvider;
import com.cardinalstar.cubicchunks.worldgen.VanillaWorldGenerator;

@ParametersAreNonnullByDefault
Expand All @@ -51,16 +51,13 @@ public static void init() {
}

@Override
public @NotNull IWorldGenerator createCubeGenerator(World world) {
return new VanillaWorldGenerator(
world.provider.createChunkGenerator(),
world,
BuiltinWorldDecorators.CUBIC_VANILLA);
public @NotNull IWorldGenerator createCubeGenerator(WorldServer world, IChunkProvider chunkGenerator) {
return new VanillaWorldGenerator(chunkGenerator, world, BuiltinWorldDecorators.CUBIC_VANILLA);
}

@Override
public IntRange calculateGenerationHeightRange(WorldServer world) {
return new IntRange(0, ((ICubicWorldProvider) world.provider).getOriginalActualHeight());
public IntRange getGenerationRange(World world) {
return new IntRange(0, world.provider.getActualHeight());
}

@Override
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/cardinalstar/cubicchunks/mixin/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,10 @@ public enum Mixins implements IMixins {
new MixinBuilder("Mixin for world settings allowing cubes.").addCommonMixins("common.MixinWorldSettings")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_WORLD_PROVIDER(
new MixinBuilder("Implementing ICubicWorldProvider.").addCommonMixins("common.MixinWorldProvider")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_WORLD_PROVIDER(new MixinBuilder("Intercept WorldProvider getActualHeight + player spawning.")
.addCommonMixins("common.MixinWorldProvider")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_WORLD(new MixinBuilder("Implementing ICubicWorld.").addCommonMixins("common.MixinWorld")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,6 @@ interface Server extends ICubicWorldInternal, ICubicWorldServer {
SpawnCubes getSpawnArea();

void setSpawnArea(SpawnCubes spawn);

void initCubicWorldServer();

// VanillaNetworkHandler getVanillaNetworkHandler();
}

interface Client extends ICubicWorldInternal {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@

import com.cardinalstar.cubicchunks.server.CubicAnvilChunkLoader;
import com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.cardinalstar.cubicchunks.world.ICubicWorldProvider;
import com.cardinalstar.cubicchunks.world.cube.ICubeProviderInternal;

@Mixin(AnvilSaveHandler.class)
Expand All @@ -43,9 +42,9 @@ public abstract class MixinAnvilSaveHandler {
at = @At(value = "NEW", target = "(Ljava/io/File;)Lnet/minecraft/world/chunk/storage/AnvilChunkLoader;"),
remap = false)
private AnvilChunkLoader getChunkLoader(File file, WorldProvider provider) {
ICubicWorld world = ((ICubicWorld) ((ICubicWorldProvider) provider).getWorld());
ICubicWorld world = (ICubicWorld) provider.worldObj;

// Use a supplier because we're in the process of overwriting the vanilla chunk provider.
return new CubicAnvilChunkLoader(file, () -> ((ICubeProviderInternal.Server) world.getCubeCache()));
return new CubicAnvilChunkLoader(file, () -> (ICubeProviderInternal.Server) world.getCubeCache());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import javax.annotation.ParametersAreNonnullByDefault;

import net.minecraft.block.Block;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
Expand Down Expand Up @@ -66,13 +67,14 @@
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import com.cardinalstar.cubicchunks.CubicChunks;
import com.cardinalstar.cubicchunks.api.ICube;
import com.cardinalstar.cubicchunks.api.IntRange;
import com.cardinalstar.cubicchunks.api.util.NotCubicChunksWorldException;
import com.cardinalstar.cubicchunks.api.world.ICubicWorldProvider;
import com.cardinalstar.cubicchunks.api.world.ICubicWorldType;
import com.cardinalstar.cubicchunks.lighting.LightingManager;
import com.cardinalstar.cubicchunks.mixin.api.ICubicWorldInternal;
Expand All @@ -83,22 +85,23 @@
import com.cardinalstar.cubicchunks.util.ReflectionUtil;
import com.cardinalstar.cubicchunks.world.CubicChunksSavedData;
import com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.cardinalstar.cubicchunks.world.ICubicWorldProvider;
import com.cardinalstar.cubicchunks.world.cube.Cube;
import com.cardinalstar.cubicchunks.world.cube.ICubeProvider;
import com.cardinalstar.cubicchunks.world.cube.ICubeProviderInternal;
import com.google.common.collect.ImmutableList;
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;

import cpw.mods.fml.common.FMLCommonHandler;

/**
* Contains implementation of {@link ICubicWorld} interface.
*/
@ParametersAreNonnullByDefault
@Mixin(World.class)
@Implements(@Interface(iface = ICubicWorld.class, prefix = "world$"))
@SuppressWarnings({ "AddedMixinMembersNamePattern" })
public abstract class MixinWorld implements ICubicWorldInternal {

// these have to be here because of mixin limitation, they are used by MixinWorldServer
Expand Down Expand Up @@ -221,14 +224,28 @@ public abstract class MixinWorld implements ICubicWorldInternal {
@Shadow
protected abstract IChunkProvider createChunkProvider();

@Redirect(
@WrapOperation(
method = "<init>(Lnet/minecraft/world/storage/ISaveHandler;Ljava/lang/String;Lnet/minecraft/world/WorldSettings;Lnet/minecraft/world/WorldProvider;Lnet/minecraft/profiler/Profiler;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/World;createChunkProvider()Lnet/minecraft/world/chunk/IChunkProvider;"))
public IChunkProvider noopCreateProvider(World instance) {
// Done below manually
return null;
public IChunkProvider noopCreateProvider(World instance, Operation<IChunkProvider> original) {
boolean isServer = (Object) this instanceof WorldServer;
boolean isClient = false;

if (FMLCommonHandler.instance()
.getSide()
.isClient()) {
if ((Object) this instanceof WorldClient) {
isClient = true;
}
}

if (!isServer && !isClient) {
return original.call(instance);
} else {
return null;
}
}

@Inject(
Expand All @@ -237,35 +254,57 @@ public IChunkProvider noopCreateProvider(World instance) {
public void initWorld(ISaveHandler p_i45369_1_, String p_i45369_2_, WorldSettings p_i45369_3_,
WorldProvider p_i45369_4_, Profiler p_i45369_5_, CallbackInfo ci) {

// Some other world instantiation that we don't care about (fake dummy worlds, for instance)
// noinspection ConstantValue
if (!((Object) this instanceof WorldServer worldServer)) return;

((ICubicWorldInternal.Server) this).initCubicWorldServer();
boolean isServer = (Object) this instanceof WorldServer;
boolean isClient = false;

if (shouldSkipWorld(worldServer)) {
CubicChunks.LOGGER.info(
"Skipping world {} with type {} due to potential compatibility issues",
this,
this.worldInfo.getTerrainType());
return;
if (FMLCommonHandler.instance()
.getSide()
.isClient()) {
if ((Object) this instanceof WorldClient) {
isClient = true;
}
}

CubicChunks.LOGGER.info("Initializing world {} with type {}", this, this.worldInfo.getTerrainType());
// If this is some other World subclass that we don't care about, skip its CC init
// This is usually the case for dummy worlds, and we can't control the lifecycle of those at all so we leave
// them non-cubic
// noinspection ConstantValue
if (!isServer && !isClient) return;

IntRange generationRange = new IntRange(0, ((ICubicWorldProvider) this.provider).getOriginalActualHeight());
IntRange generationRange, heightRange;

WorldType type = this.worldInfo.getTerrainType();

if (type instanceof ICubicWorldType && ((ICubicWorldType) type).hasCubicGeneratorForWorld(worldServer)) {
generationRange = ((ICubicWorldType) type).calculateGenerationHeightRange(worldServer);
World world = (World) (Object) this;

if (type instanceof ICubicWorldType cubicWorldType && cubicWorldType.hasCubicGeneratorForWorld(world)) {
generationRange = cubicWorldType.getGenerationRange(world);
} else if (this.provider instanceof ICubicWorldProvider cubicWorldProvider) {
generationRange = cubicWorldProvider.getGenerationRange();
} else {
generationRange = new IntRange(0, this.provider.getActualHeight());
}

this.chunkProvider = createChunkProvider();
if ((Object) this instanceof WorldServer worldServer) {
CubicChunksSavedData savedData = CubicChunksSavedData.get(worldServer);

CubicChunksSavedData savedData = CubicChunksSavedData.get(worldServer);
heightRange = new IntRange(savedData.minHeight, savedData.maxHeight);
} else {
// Client world, just set some defaults and let the packets update these properly
heightRange = new IntRange(Integer.MIN_VALUE, Integer.MAX_VALUE);
}

this.initCubicWorld(new IntRange(savedData.minHeight, savedData.maxHeight), generationRange);
this.initCubicWorld(heightRange, generationRange);

this.chunkProvider = createChunkProvider();

CubicChunks.LOGGER.info(
"Initialized world {} with type {} (generation range: {}, height: {}, provider: {})",
this,
this.worldInfo.getTerrainType(),
generationRange,
heightRange,
chunkProvider);

this.lightingManager = new LightingManager((World) (Object) this);
}
Expand Down Expand Up @@ -302,12 +341,15 @@ public int getMaxGenerationHeight() {

@Override
public ICubeProviderInternal getCubeCache() {
if (!(this.chunkProvider instanceof ICubeProviderInternal)) {
throw new NotCubicChunksWorldException();
}

return (ICubeProviderInternal) this.chunkProvider;
}

@Override
public LightingManager getLightingManager() {
assert this.lightingManager != null;
return this.lightingManager;
}

Expand Down Expand Up @@ -434,7 +476,8 @@ public void setHeightBounds(int minHeight, int maxHeight) {

@Inject(method = "updateLightByType", at = @At("HEAD"), cancellable = true)
private void updateLightByType(EnumSkyBlock lightType, int x, int y, int z, CallbackInfoReturnable<Boolean> ci) {
ci.setReturnValue(getLightingManager() != null && getLightingManager().checkLightFor(lightType, x, y, z));
if (this.lightingManager == null) return;
ci.setReturnValue(this.lightingManager.checkLightFor(lightType, x, y, z));
}

/**
Expand All @@ -453,6 +496,7 @@ private void updateLightByType(EnumSkyBlock lightType, int x, int y, int z, Call
*/
@Inject(method = "markTileEntityChunkModified", at = @At("HEAD"), cancellable = true)
private void onMarkChunkDirty(int x, int y, int z, TileEntity unusedTileEntity, CallbackInfo ci) {
if (!(this.chunkProvider instanceof ICubeProviderInternal)) return;
Cube cube = this.getCubeCache()
.getLoadedCube(CubePos.fromBlockCoords(x, y, z));
if (cube != null) {
Expand All @@ -466,6 +510,7 @@ private void onMarkChunkDirty(int x, int y, int z, TileEntity unusedTileEntity,

@Inject(method = "getTopSolidOrLiquidBlock", at = @At("HEAD"), cancellable = true)
private void getTopSolidOrLiquidBlockCubicChunks(int x, int z, CallbackInfoReturnable<Integer> cir) {
if (!(this.chunkProvider instanceof ICubeProviderInternal)) return;
Chunk chunk = this.getChunkFromBlockCoords(x, z);
int currentY = getPrecipitationHeight(x, z);
int minY = currentY - 64;
Expand All @@ -490,7 +535,7 @@ public boolean isBlockColumnLoaded(int x, int y, int z) {

@Override
public boolean cubeExists(int x, int y, int z) {
return ((ICubeProvider) this.chunkProvider).cubeExists(x, y, z);
return getCubeCache().cubeExists(x, y, z);
}

@ModifyConstant(method = "getCollidingBoundingBoxes", constant = @Constant(intValue = 64), require = 1)
Expand Down
Loading
Loading