Skip to content
28 changes: 28 additions & 0 deletions src/main/java/com/cardinalstar/cubicchunks/mixin/Mixins.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,22 @@ public enum Mixins implements IMixins {
new MixinBuilder("Allowing lilypads to stay above 256 adn below 0.").addCommonMixins("common.MixinBlockLilyPad")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_BEACON_HEIGHT(
new MixinBuilder("Validate beacon pyramids below zero").addCommonMixins("common.MixinTileEntityBeacon")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_VINE_HEIGHT(new MixinBuilder("Allow vines to grow across the physical height range")
.addCommonMixins("common.MixinBlockVine_Height")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_PORTAL_FRAME_HEIGHT(
new MixinBuilder("Validate portal frames below zero").addCommonMixins("common.MixinBlockPortalSize")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_PISTON_HEIGHT(new MixinBuilder("Keep vanilla piston movement inside physical bounds")
.addCommonMixins("common.MixinBlockPistonBase_Height")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_S01PACKET_JOIN_GAME(new MixinBuilder("Giving the packet info to initialize cubicWorlds for clients.")
.addCommonMixins("common.vanillaclient.MixinS01PacketJoinGame")
.setPhase(Phase.EARLY)
Expand All @@ -89,6 +105,10 @@ public enum Mixins implements IMixins {
.addCommonMixins("common.MixinS28PacketEffect")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_S0A_HEIGHT_LIMITS(new MixinBuilder("Changing packet S0A to read and write full integer Y values.")
.addCommonMixins("common.MixinS0APacketUseBed")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_S07PACKET_RESPAWN(new MixinBuilder("Giving respawn packets info to initialize cubicWorlds for clients.")
.addCommonMixins("common.vanillaclient.MixinS07PacketRespawn")
.setPhase(Phase.EARLY)
Expand Down Expand Up @@ -246,6 +266,14 @@ public enum Mixins implements IMixins {
.addCommonMixins("common.MixinNetHandlerPlayServer")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_SPAWN_COMMAND_HEIGHT(new MixinBuilder("Accept explicit spawn coordinates within physical world bounds")
.addCommonMixins("common.MixinCommandSetSpawnpoint", "common.MixinCommandSetDefaultSpawnpoint")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),
MIXIN_SPREAD_PLAYER_HEIGHT(new MixinBuilder("Find safe spread-player surfaces at signed heights with bounded work")
.addCommonMixins("common.MixinSpreadPlayerPosition")
.setPhase(Phase.EARLY)
.setApplyIf(() -> true)),

// =============================================================
// Client Mixins
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,44 @@
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 com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.llamalad7.mixinextras.expression.Definition;
import com.llamalad7.mixinextras.expression.Expression;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;

@Mixin(Entity.class)
public class MixinEntity {
public abstract class MixinEntity {

@Shadow
public World worldObj;

@Shadow
public double posX;

@Shadow
public double posZ;

@Shadow
public abstract void setPosition(double x, double y, double z);

@Definition(id = "posY", field = "Lnet/minecraft/entity/Entity;posY:D")
@Expression("this.posY > 0.0")
@WrapOperation(method = "preparePlayerToSpawn", at = @At("MIXINEXTRAS:EXPRESSION"), require = 1)
private boolean cc$canClearSpawnCollision(double y, double zero, Operation<Boolean> original) {
// Include the first air layer above the build ceiling, then stop even if obstructed.
return y <= ((ICubicWorld) this.worldObj).getMaxHeight();
}

@Inject(method = "preparePlayerToSpawn", at = @At("RETURN"), require = 1)
private void cc$finishSpawnPosition(CallbackInfo ci) {
if (this.worldObj != null) {
this.setPosition(this.posX, this.posY, this.posZ);
}
}

@Shadow
public double posY;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.block.BlockPistonBase;
import net.minecraft.world.World;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.llamalad7.mixinextras.expression.Expression;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;

@Mixin(BlockPistonBase.class)
public class MixinBlockPistonBase_Height {

// Like vanilla's y <= 0, nothing moves into the lowest layer of the world.
@Expression("? <= 0")
@WrapOperation(method = "canExtend", at = @At("MIXINEXTRAS:EXPRESSION"), require = 1)
private static boolean cc$canExtendBelowFloor(int y, int zero, Operation<Boolean> original,
@Local(argsOnly = true) World world) {
return y <= ((ICubicWorld) world).getMinHeight();
}

@Expression("? <= 0")
@WrapOperation(method = "tryExtend", at = @At("MIXINEXTRAS:EXPRESSION"), require = 1)
private boolean cc$tryExtendBelowFloor(int y, int zero, Operation<Boolean> original,
@Local(argsOnly = true) World world) {
return y <= ((ICubicWorld) world).getMinHeight();
}

@Redirect(
method = "canExtend",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getHeight()I"),
require = 1)
private static int cc$canExtendCeiling(World world) {
return ((ICubicWorld) world).getMaxHeight();
}

@Redirect(
method = "tryExtend",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getHeight()I"),
require = 1)
private int cc$tryExtendCeiling(World world) {
return ((ICubicWorld) world).getMaxHeight();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.block.BlockPortal;
import net.minecraft.world.World;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;

import com.cardinalstar.cubicchunks.world.ICubicWorld;

@Mixin(BlockPortal.Size.class)
public class MixinBlockPortalSize {

@ModifyConstant(
method = "<init>",
constant = @Constant(expandZeroConditions = Constant.Condition.GREATER_THAN_ZERO),
require = 1)
private int cc$frameFloor(int vanillaMinimum, World world, int x, int y, int z, int axis) {
return ((ICubicWorld) world).getMinHeight();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import java.util.Random;

import net.minecraft.block.BlockVine;
import net.minecraft.world.World;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;

import com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.llamalad7.mixinextras.expression.Definition;
import com.llamalad7.mixinextras.expression.Expression;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;

@Mixin(BlockVine.class)
public class MixinBlockVine_Height {

@ModifyConstant(method = "updateTick", constant = @Constant(intValue = 255), require = 1)
private int cc$growthCeiling(int vanillaMaximum, World world, int x, int y, int z, Random random) {
return ((ICubicWorld) world).getMaxHeight() - 1;
}

@Definition(id = "y", local = @Local(argsOnly = true, ordinal = 1, type = int.class))
@Expression("y > 1")
@WrapOperation(method = "updateTick", at = @At("MIXINEXTRAS:EXPRESSION"), require = 1)
private boolean cc$canGrowDown(int y, int vanillaMinimum, Operation<Boolean> original,
@Local(argsOnly = true) World world) {
// Like vanilla's y > 1, vines do not grow into the lowest layer of the world.
return y > ((ICubicWorld) world).getMinHeight() + 1;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.command.ICommandSender;
import net.minecraft.command.server.CommandSetDefaultSpawnpoint;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;

@Mixin(CommandSetDefaultSpawnpoint.class)
public class MixinCommandSetDefaultSpawnpoint {

@WrapOperation(
method = "processCommand",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/command/server/CommandSetDefaultSpawnpoint;parseIntBounded(Lnet/minecraft/command/ICommandSender;Ljava/lang/String;II)I",
ordinal = 1),
require = 1)
private int cc$parseHeight(ICommandSender sender, String value, int minimum, int maximum,
Operation<Integer> original) {
ICubicWorld world = (ICubicWorld) sender.getEntityWorld();
return original.call(sender, value, world.getMinHeight(), world.getMaxHeight() - 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.command.CommandSetSpawnpoint;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import com.cardinalstar.cubicchunks.world.ICubicWorld;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;

@Mixin(CommandSetSpawnpoint.class)
public class MixinCommandSetSpawnpoint {

@WrapOperation(
method = "processCommand",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/command/CommandSetSpawnpoint;parseIntBounded(Lnet/minecraft/command/ICommandSender;Ljava/lang/String;II)I",
ordinal = 1),
require = 1)
private int cc$parseHeight(ICommandSender sender, String value, int minimum, int maximum,
Operation<Integer> original, @Local EntityPlayerMP player) {
ICubicWorld world = (ICubicWorld) player.worldObj;
return original.call(sender, value, world.getMinHeight(), world.getMaxHeight() - 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.server.S0APacketUseBed;

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;

import io.netty.buffer.ByteBuf;

@Mixin(S0APacketUseBed.class)
public class MixinS0APacketUseBed {

@Shadow
private int field_149096_c;

@Redirect(
method = "readPacketData",
at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketBuffer;readByte()B"),
require = 1)
private byte skipVanillaYRead(PacketBuffer data) {
return 0;
}

@Inject(
method = "readPacketData",
at = @At(value = "INVOKE", target = "Lnet/minecraft/network/PacketBuffer;readInt()I", ordinal = 2),
require = 1)
private void readFullY(PacketBuffer data, CallbackInfo ci) {
this.field_149096_c = data.readInt();
}

@Redirect(
method = "writePacketData",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/network/PacketBuffer;writeByte(I)Lio/netty/buffer/ByteBuf;"),
require = 1)
private ByteBuf writeFullY(PacketBuffer data, int ignored) {
return data.writeInt(this.field_149096_c);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.util.MathHelper;
import net.minecraft.world.World;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import com.cardinalstar.cubicchunks.util.SpreadPlayerSurface;
import com.cardinalstar.cubicchunks.world.cube.ICubeProvider;

@Mixin(targets = "net.minecraft.command.CommandSpreadPlayers$Position")
public class MixinSpreadPlayerPosition {

@Shadow
double field_111101_a;

@Shadow
double field_111100_b;

@Inject(method = "func_111098_b", at = @At("HEAD"), cancellable = true, require = 1)
private void cc$checkSurface(World world, CallbackInfoReturnable<Boolean> cir) {
if (world.getChunkProvider() instanceof ICubeProvider) {
int landing = this.cc$landing(world);
// Where the loaded terrain does not decide, vanilla's check runs, as without this fix.
if (landing != SpreadPlayerSurface.NOT_LOADED) {
cir.setReturnValue(landing != SpreadPlayerSurface.UNSAFE);
}
}
}

@Inject(method = "func_111092_a", at = @At("HEAD"), cancellable = true, require = 1)
private void cc$landingHeight(World world, CallbackInfoReturnable<Integer> cir) {
if (world.getChunkProvider() instanceof ICubeProvider) {
int landing = this.cc$landing(world);
// A check that vanilla decided, or a teammate's landing, may have loaded unsafe terrain since: then land
// like vanilla, as the check did not reject it.
if (landing != SpreadPlayerSurface.NOT_LOADED && landing != SpreadPlayerSurface.UNSAFE) {
cir.setReturnValue(landing);
}
}
}

@Unique
private int cc$landing(World world) {
return SpreadPlayerSurface
.find(world, MathHelper.floor_double(this.field_111101_a), MathHelper.floor_double(this.field_111100_b));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.cardinalstar.cubicchunks.mixin.early.common;

import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityBeacon;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;

import com.cardinalstar.cubicchunks.world.ICubicWorld;

@Mixin(TileEntityBeacon.class)
public abstract class MixinTileEntityBeacon extends TileEntity {

@ModifyConstant(
method = "func_146003_y",
constant = @Constant(expandZeroConditions = Constant.Condition.LESS_THAN_ZERO),
require = 1)
private int cc$pyramidFloor(int vanillaMinimum) {
return ((ICubicWorld) this.worldObj).getMinHeight();
}
}
Loading