Merge pull request #44 from gnembon/fast_redstone

Fast redstone
This commit is contained in:
gnembon authored and GitHub committed 2019-07-03 13:02:05 -03:00
commit 0b6732fa93
5 files changed
+200 -17

No files matched your search

@@ -0,0 +1,11 @@
package carpet.fakes;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public interface RedstoneWireBlockInterface {
BlockState updateLogicPublic(World world_1, BlockPos blockPos_1, BlockState blockState_1);
void setWiresGivePower(boolean wiresGivePower);
boolean getWiresGivePower();
}
@@ -7,11 +7,17 @@ import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ThreadLocalRandom;
import carpet.fakes.RedstoneWireBlockInterface;
import net.minecraft.block.Block;
import net.minecraft.block.RedstoneWireBlock;
import net.minecraft.block.BlockState;
import net.minecraft.entity.ItemEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.loot.context.LootContext;
import net.minecraft.world.loot.context.LootContextParameter;
import net.minecraft.world.loot.context.LootContextParameters;
public class RedstoneWireTurbo
{
@@ -319,10 +325,10 @@ public class RedstoneWireTurbo
// others are processed internally by the breadth first search
// algorithm. To preserve this game behavior, this check must
// be replicated here.
if (!oldState.isValidPosition(worldIn, pos)) {
if (!oldState.canPlaceAt(worldIn, pos)) {
// Pop off the redstone dust
oldState.dropBlockAsItem(worldIn, pos, 0);
worldIn.removeBlock(pos);
Block.dropStacks(oldState, worldIn, pos);
worldIn.clearBlockState(pos, false);
// Mark this position as not being redstone wire
upd1.type = UpdateNode.Type.OTHER;
@@ -436,7 +442,7 @@ public class RedstoneWireTurbo
// UpdateNode object.
BlockState newState;
if (old_current_change) {
newState = wire.func_212568_b(worldIn, pos, oldState);
newState = ((RedstoneWireBlockInterface)wire).updateLogicPublic(worldIn, pos, oldState);
} else {
// Looking up block state is slow. This accelerator includes a version of
// calculateCurrentChanges that uses cahed wire values for a
@@ -661,7 +667,7 @@ public class RedstoneWireTurbo
// already keeping track of all of the neighbor positions
// that need to be updated. All on its own, handling neighbors
// this way reduces block updates by 1/3 (24 instead of 36).
worldIn.neighborChanged(upd.self, wire, upd.parent);
worldIn.updateNeighbor(upd.self, wire, upd.parent);
}
}
@@ -765,7 +771,7 @@ public class RedstoneWireTurbo
// Check this block's neighbors and see if its power level needs to change
// Use the calculateCurrentChanges method in RedstoneWireBlock since we have no
// cached block states at this point.
final BlockState newState = wire.func_212568_b(worldIn, pos, state);
final BlockState newState = ((RedstoneWireBlockInterface)wire).updateLogicPublic(worldIn, pos, state);
// If no change, exit
if (newState == state) {
@@ -835,17 +841,17 @@ public class RedstoneWireTurbo
BlockState state = upd.currentState;
final int i = state.get(RedstoneWireBlock.POWER);
int j = 0;
j = this.getMaxCurrentStrength(upd, j);
j = getMaxCurrentStrength(upd, j);
int l = 0;
wire.setCanProvidePower(false);
((RedstoneWireBlockInterface)wire).setWiresGivePower(false);
// Unfortunately, World.isBlockIndirectlyGettingPowered is complicated,
// and I'm not ready to try to replicate even more functionality from
// elsewhere in Minecraft into this accelerator. So sadly, we must
// suffer the performance hit of this very expensive call. If there
// is consistency to what this call returns, we may be able to cache it.
final int k = worldIn.getRedstonePowerFromNeighbors(upd.self);
wire.setCanProvidePower(true);
final int k = worldIn.getReceivedRedstonePower(upd.self);
((RedstoneWireBlockInterface)wire).setWiresGivePower(true);
// The variable 'k' holds the maximum redstone power value of any adjacent blocks.
// If 'k' has the highest level of all neighbors, then the power level of this
@@ -863,7 +869,7 @@ public class RedstoneWireTurbo
// position directly above the node being calculated is always
// at index 1.
UpdateNode center_up = upd.neighbor_nodes[1];
boolean center_up_is_cube = center_up.currentState.isNormalCube();
boolean center_up_is_cube = center_up.currentState.isSimpleFullBlock(worldIn, center_up.self);
for (int m=0; m<4; m++) {
// Get the neighbor array index of each of the four cardinal
@@ -873,18 +879,18 @@ public class RedstoneWireTurbo
// Get the max redstone power level of each of the cardinal
// neighbors
UpdateNode neighbor = upd.neighbor_nodes[n];
l = this.getMaxCurrentStrength(neighbor, l);
l = getMaxCurrentStrength(neighbor, l);
// Also check the positions above and below the cardinal
// neighbors
boolean neighbor_is_cube = neighbor.currentState.isNormalCube();
boolean neighbor_is_cube = neighbor.currentState.isSimpleFullBlock(worldIn, neighbor.self);
if (!neighbor_is_cube) {
UpdateNode neighbor_down = upd.neighbor_nodes[rs_neighbors_dn[m]];
l = this.getMaxCurrentStrength(neighbor_down, l);
l = getMaxCurrentStrength(neighbor_down, l);
} else
if (!center_up_is_cube) {
UpdateNode neighbor_up = upd.neighbor_nodes[rs_neighbors_up[m]];
l = this.getMaxCurrentStrength(neighbor_up, l);
l = getMaxCurrentStrength(neighbor_up, l);
}
}
}
@@ -0,0 +1,166 @@
package carpet.mixins;
import carpet.settings.CarpetSettings;
import carpet.fakes.RedstoneWireBlockInterface;
import carpet.helpers.RedstoneWireTurbo;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.RedstoneWireBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Accessor;
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 java.util.Iterator;
import java.util.Set;
import static net.minecraft.block.RedstoneWireBlock.POWER;
@Mixin(RedstoneWireBlock.class)
public abstract class RedstoneWireBlockMixin implements RedstoneWireBlockInterface {
// =
@Shadow
private boolean wiresGivePower;
@Shadow
@Final
private Set<BlockPos> affectedNeighbors;
@Shadow
private int increasePower(int int_1, BlockState blockState_1) { return 0; };
@Shadow
private BlockState update(World world_1, BlockPos blockPos_1, BlockState blockState_1) { return null; };
// =
@Override
public BlockState updateLogicPublic(World world_1, BlockPos blockPos_1, BlockState blockState_1) {
return updateLogic(world_1, blockPos_1, blockState_1);
}
@Override
@Accessor("wiresGivePower")
public abstract void setWiresGivePower(boolean wiresGivePower);
@Override
@Accessor("wiresGivePower")
public abstract boolean getWiresGivePower();
// =
private RedstoneWireTurbo wireTurbo = null;
@Inject(method = "<init>", at = @At("RETURN"))
private void onRedstoneWireBlockCTOR(Block.Settings settings, CallbackInfo ci) {
//noinspection ConstantConditions
wireTurbo = new RedstoneWireTurbo((RedstoneWireBlock) (Object) this);
}
// =
public BlockState fastUpdate(World world, BlockPos pos, BlockState state, BlockPos source) {
// [CM] fastRedstoneDust -- update based on carpet rule
if (CarpetSettings.fastRedstoneDust) {
return wireTurbo.updateSurroundingRedstone(world, pos, state, source);
}
return update(world, pos, state);
}
/**
* @author theosib, soykaf, gnembon
*/
@Overwrite
private BlockState updateLogic(World world_1, BlockPos blockPos_1, BlockState blockState_1) {
BlockState blockState_2 = blockState_1;
int int_1 = (Integer)blockState_1.get(POWER); // i
this.wiresGivePower = false;
int int_2 = world_1.getReceivedRedstonePower(blockPos_1); // k
this.wiresGivePower = true;
int int_3 = 0; // l
if (!CarpetSettings.fastRedstoneDust || int_2 < 15) {
Iterator var8 = Direction.Type.HORIZONTAL.iterator();
label43:
while(true) {
while(true) {
if (!var8.hasNext()) {
break label43;
}
Direction direction_1 = (Direction)var8.next();
BlockPos blockPos_2 = blockPos_1.offset(direction_1);
BlockState blockState_3 = world_1.getBlockState(blockPos_2);
int_3 = this.increasePower(int_3, blockState_3);
BlockPos blockPos_3 = blockPos_1.up();
if (blockState_3.isSimpleFullBlock(world_1, blockPos_2) && !world_1.getBlockState(blockPos_3).isSimpleFullBlock(world_1, blockPos_3)) {
int_3 = this.increasePower(int_3, world_1.getBlockState(blockPos_2.up()));
} else if (!blockState_3.isSimpleFullBlock(world_1, blockPos_2)) {
int_3 = this.increasePower(int_3, world_1.getBlockState(blockPos_2.down()));
}
}
}
}
int int_4 = int_3 - 1;
if (int_2 > int_4) int_4 = int_2;
if (int_1 != int_4) {
blockState_1 = (BlockState)blockState_1.with(POWER, int_4);
if (world_1.getBlockState(blockPos_1) == blockState_2) {
world_1.setBlockState(blockPos_1, blockState_1, 2);
}
if (!CarpetSettings.fastRedstoneDust) {
this.affectedNeighbors.add(blockPos_1);
Direction[] var14 = Direction.values();
int var15 = var14.length;
for (int var16 = 0; var16 < var15; ++var16) {
Direction direction_2 = var14[var16];
this.affectedNeighbors.add(blockPos_1.offset(direction_2));
}
}
}
return blockState_1;
}
// =
@Redirect(method = "onBlockAdded", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/RedstoneWireBlock;update(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/block/BlockState;"))
private BlockState redirectOnBlockAddedUpdate(RedstoneWireBlock self, World world_1, BlockPos blockPos_1, BlockState blockState_1) {
return fastUpdate(world_1, blockPos_1, blockState_1, null);
}
@Redirect(method = "onBlockRemoved", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/RedstoneWireBlock;update(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/block/BlockState;"))
private BlockState redirectOnBlockRemovedUpdate(RedstoneWireBlock self, World world_1, BlockPos blockPos_1, BlockState blockState_1) {
return fastUpdate(world_1, blockPos_1, blockState_1, null);
}
@Redirect(method = "neighborUpdate", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/RedstoneWireBlock;update(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/block/BlockState;"))
private BlockState redirectNeighborUpdateUpdate(
RedstoneWireBlock self,
World world_1,
BlockPos blockPos_1,
BlockState blockState_1,
BlockState blockState_2,
World world_2,
BlockPos blockPos_2,
Block block_1,
BlockPos blockPos_3,
boolean boolean_1) {
return fastUpdate(world_1, blockPos_1, blockState_1, blockPos_3);
}
}
@@ -92,8 +92,7 @@ public class CarpetSettings
@Rule(
desc = "Lag optimizations for redstone dust",
extra = "by Theosib",
category = {EXPERIMENTAL, OPTIMIZATION},
validate = Validator.WIP.class
category = {EXPERIMENTAL, OPTIMIZATION}
)
public static boolean fastRedstoneDust = false;
+1
View File
@@ -32,6 +32,7 @@
"PlayerActionC2SPacketMixin",
"ServerPlayerEntityMixin",
"PlayerManagerMixin",
"RedstoneWireBlockMixin",
"CarpetBlockMixin",
"SummonCommandMixin",
"PistonHandler_pushLimitMixin",