Skip to content

Commit

Permalink
Fix some old code, cache more stuff on client
Browse files Browse the repository at this point in the history
  • Loading branch information
Patbox committed Aug 8, 2021
1 parent d466779 commit a9c5341
Show file tree
Hide file tree
Showing 20 changed files with 156 additions and 72 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies {
```

After that, it's as easy as making your items implement `VirtualItem`, blocks `VirtualBlock` or
`VirtualHeadBlock` and entities `VirtualEntity`. Additionally, you need to implement `VirtualObject` on your enchantments and recipe serializers.
`VirtualHeadBlock` and entities `VirtualEntity`. Additionally, you need to implement `VirtualObject` on your enchantments and recipes.
It's also recommended registering block entities with `PolymerMod.registerVirtualBlockEntity(Identifier)`.

### Limitations
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G
loader_version=0.11.3

# Mod Properties
mod_version = 0.1.0-rc.2+1.17.1
mod_version = 0.1.0-rc.3+1.17.1
maven_group = eu.pb4
archives_base_name = polymer

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/eu/pb4/polymer/block/BlockHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import eu.pb4.polymer.mixin.block.AbstractBlockAccessor;
import eu.pb4.polymer.mixin.block.AbstractBlockSettingAccessor;
import eu.pb4.polymer.other.MineEvent;
import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;

import java.util.function.ToIntFunction;

public class BlockHelper {
private static Object2BooleanArrayMap<Block> IS_LIGHT_SOURCE_CACHE = new Object2BooleanArrayMap();
public static final MineEvent SERVER_SIDE_MINING_CHECK = new MineEvent();
private static final Object2BooleanArrayMap<Block> IS_LIGHT_SOURCE_CACHE = new Object2BooleanArrayMap();

public static boolean isLightSource(Block block) {
if (BlockHelper.IS_LIGHT_SOURCE_CACHE.containsKey(block)) {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/eu/pb4/polymer/block/VirtualBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ default BlockState getDefaultVirtualBlockState() {

/**
* Main method used for replacing BlockStates on client
* It also controls some server side things like collisions
*
* @param state Server side/real BlockState
* @return BlockState visible on client
*/
default BlockState getVirtualBlockState(BlockState state) {
return this.getDefaultVirtualBlockState();
};
}

/**
* This method can be used to send additional packets after block is send to client
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package eu.pb4.polymer.mixin.block;

import eu.pb4.polymer.block.VirtualBlock;
import eu.pb4.polymer.other.client.ClientUtils;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Block;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.packet.s2c.play.BlockEventS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
Expand All @@ -26,23 +25,18 @@ public class BlockEventS2CPacketMixin {
@Unique private Block oldBlock = null;

@Environment(EnvType.CLIENT)
@Inject(method = "getBlock", at = @At("TAIL"), cancellable = true)
@Inject(method = "getBlock", at = @At("HEAD"), cancellable = true)
private void replaceBlockClient(CallbackInfoReturnable<Block> cir) {
if (MinecraftClient.getInstance().getServer() != null) {
ServerPlayerEntity player = MinecraftClient.getInstance().getServer().getPlayerManager().getPlayer(MinecraftClient.getInstance().player.getUuid());
if (this.oldBlock instanceof VirtualBlock virtualBlock) {
cir.setReturnValue(virtualBlock.getVirtualBlock(this.pos, player.getServerWorld()));
}
if (ClientUtils.isSingleplayer() && this.oldBlock == null && this.block instanceof VirtualBlock virtualBlock) {
this.oldBlock = this.block;
this.block = virtualBlock.getVirtualBlock(this.pos, ClientUtils.getPlayer().getServerWorld());
}
}

@Inject(method = "write", at = @At("TAIL"))
@Inject(method = "write", at = @At("HEAD"))
private void replaceBlock(PacketByteBuf byteBuf, CallbackInfo ci) {
if (oldBlock == null) {
if (oldBlock == null && this.block instanceof VirtualBlock virtualBlock) {
this.oldBlock = block;
}

if (this.oldBlock instanceof VirtualBlock virtualBlock) {
this.block = virtualBlock.getVirtualBlock(this.pos, PacketContext.get().getTarget().getServerWorld());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
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.ModifyArg;
Expand All @@ -16,6 +17,9 @@
public class BlockUpdateS2CPacketMixin {
@Shadow private BlockState state;

@Environment(EnvType.CLIENT)
@Unique private BlockState cachedBlockState = null;

@ModifyArg(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getRawIdFromState(Lnet/minecraft/block/BlockState;)I"))
private BlockState replaceWithVirtualBlockState(BlockState state) {
if (state.getBlock() instanceof VirtualBlock) {
Expand All @@ -28,8 +32,12 @@ private BlockState replaceWithVirtualBlockState(BlockState state) {
@Environment(EnvType.CLIENT)
@Inject(method = "getState", at = @At("HEAD"), cancellable = true)
public void replaceWithVirtualState(CallbackInfoReturnable<BlockState> cir) {
if (this.state.getBlock() instanceof VirtualBlock) {
cir.setReturnValue(((VirtualBlock) this.state.getBlock()).getVirtualBlockState(this.state));
if (this.state.getBlock() instanceof VirtualBlock virtualBlock) {
if (this.cachedBlockState == null) {
this.cachedBlockState = virtualBlock.getVirtualBlockState(this.state);
}

cir.setReturnValue(this.cachedBlockState);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import net.minecraft.block.BlockState;
import net.minecraft.network.packet.s2c.play.ChunkDeltaUpdateS2CPacket;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;

Expand All @@ -22,8 +23,8 @@ private BlockState replaceWithVirtualBlockState(BlockState state) {
@Environment(EnvType.CLIENT)
@ModifyArg(method = "visitUpdates", at = @At(value = "INVOKE", target = "Ljava/util/function/BiConsumer;accept(Ljava/lang/Object;Ljava/lang/Object;)V"), index = 1)
private Object replaceBlockStateOnClient(Object state) {
if (((BlockState) state).getBlock() instanceof VirtualBlock) {
return ((VirtualBlock) ((BlockState) state).getBlock()).getVirtualBlockState(((BlockState) state));
if (((BlockState) state).getBlock() instanceof VirtualBlock virtualBlock) {
return virtualBlock.getVirtualBlockState(((BlockState) state));
}
return state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public class FallingBlockEntityMixin {

@ModifyArg(method = "createSpawnPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getRawIdFromState(Lnet/minecraft/block/BlockState;)I"))
private BlockState replaceWithVirtual(BlockState state) {
if (state.getBlock() instanceof VirtualBlock) {
return ((VirtualBlock) state.getBlock()).getVirtualBlockState(state);
if (state.getBlock() instanceof VirtualBlock virtualBlock) {
return virtualBlock.getVirtualBlockState(state);
} else {
return state;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.spongepowered.asm.mixin.Final;
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.ModifyArg;
Expand All @@ -17,10 +18,15 @@
public class PlayerActionResponseS2CPacketMixin {
@Shadow @Final private BlockState state;

@Unique BlockState cachedBlockState = null;

@ModifyArg(method = "write", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;getRawIdFromState(Lnet/minecraft/block/BlockState;)I"))
private BlockState replaceWithVirtualBlockState(BlockState state) {
if (state.getBlock() instanceof VirtualBlock) {
return ((VirtualBlock) state.getBlock()).getVirtualBlockState(state);
if (state.getBlock() instanceof VirtualBlock virtualBlock) {
if (this.cachedBlockState == null) {
this.cachedBlockState = virtualBlock.getVirtualBlockState(state);
}
return this.cachedBlockState;
}
return state;
}
Expand All @@ -30,7 +36,10 @@ private BlockState replaceWithVirtualBlockState(BlockState state) {
@Inject(method = "getBlockState", at = @At("HEAD"), cancellable = true)
public void replaceWithVirtualState(CallbackInfoReturnable<BlockState> cir) {
if (this.state.getBlock() instanceof VirtualBlock virtualBlock) {
cir.setReturnValue(virtualBlock.getVirtualBlockState(this.state));
if (this.cachedBlockState == null) {
this.cachedBlockState = virtualBlock.getVirtualBlockState(state);
}
cir.setReturnValue(this.cachedBlockState);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package eu.pb4.polymer.mixin.block;

import eu.pb4.polymer.block.BlockHelper;
import eu.pb4.polymer.block.VirtualBlock;
import eu.pb4.polymer.item.VirtualItem;
import net.minecraft.block.AbstractFireBlock;
Expand All @@ -8,7 +9,9 @@
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.effect.StatusEffects;
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
import net.minecraft.network.packet.s2c.play.*;
import net.minecraft.network.packet.s2c.play.BlockBreakingProgressS2CPacket;
import net.minecraft.network.packet.s2c.play.EntityStatusEffectS2CPacket;
import net.minecraft.network.packet.s2c.play.RemoveEntityStatusEffectS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.network.ServerPlayerInteractionManager;
import net.minecraft.server.world.ServerWorld;
Expand All @@ -17,6 +20,7 @@
import org.apache.logging.log4j.Logger;
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.Redirect;
Expand All @@ -27,22 +31,27 @@

@Mixin(ServerPlayerInteractionManager.class)
public abstract class ServerPlayerInteractionManagerMixin {
@Shadow public ServerPlayerEntity player;
@Shadow private int tickCounter;
@Shadow private int startMiningTime;

@Shadow
public abstract void finishMining(BlockPos pos, PlayerActionC2SPacket.Action action, String reason);

@Shadow public ServerWorld world;
public ServerPlayerEntity player;
@Shadow
public ServerWorld world;
@Shadow
private int tickCounter;
@Shadow
private int startMiningTime;
@Unique
private int blockBreakingCooldown;
@Unique
private final boolean isCustom = false;

@Shadow
public abstract void finishMining(BlockPos pos, PlayerActionC2SPacket.Action action, String reason);

@Inject(method = "continueMining", at = @At("TAIL"))
private void breakIfTakingTooLong(BlockState state, BlockPos pos, int i, CallbackInfoReturnable<Float> cir) {
if (state.getBlock() instanceof VirtualBlock || this.player.getMainHandStack().getItem() instanceof VirtualItem) {
if (this.shouldMineServerSide(pos, state)) {
int j = this.tickCounter - i;
float f = state.calcBlockBreakingDelta(this.player, this.player.world, pos) * (float)(j);
float f = state.calcBlockBreakingDelta(this.player, this.player.world, pos) * (float) (j);

if (this.blockBreakingCooldown > 0) {
--this.blockBreakingCooldown;
Expand All @@ -63,18 +72,18 @@ private void breakIfTakingTooLong(BlockState state, BlockPos pos, int i, Callbac

@Inject(method = "continueMining", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/world/ServerWorld;setBlockBreakingInfo(ILnet/minecraft/util/math/BlockPos;I)V"))
private void onUpdateBreakStatus(BlockState state, BlockPos pos, int i, CallbackInfoReturnable<Float> cir) {
if (state.getBlock() instanceof VirtualBlock || this.player.getMainHandStack().getItem() instanceof VirtualItem) {
if (this.shouldMineServerSide(pos, state)) {
int j = tickCounter - i;
float f = state.calcBlockBreakingDelta(this.player, this.player.world, pos) * (float)(j + 1);
int k = (int)(f * 10.0F);
float f = state.calcBlockBreakingDelta(this.player, this.player.world, pos) * (float) (j + 1);
int k = (int) (f * 10.0F);

this.player.networkHandler.sendPacket(new BlockBreakingProgressS2CPacket(-1, pos, k));
}
}

@Inject(method = "processBlockBreakingAction", at = @At("HEAD"))
private void packetReceivedInject(BlockPos pos, PlayerActionC2SPacket.Action action, Direction direction, int worldHeight, CallbackInfo ci) {
if (this.player.getServerWorld().getBlockState(pos).getBlock() instanceof VirtualBlock || this.player.getMainHandStack().getItem() instanceof VirtualItem) {
if (this.shouldMineServerSide(pos, this.player.getServerWorld().getBlockState(pos))) {
if (action == PlayerActionC2SPacket.Action.START_DESTROY_BLOCK) {
this.player.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(this.player.getId(), new StatusEffectInstance(StatusEffects.MINING_FATIGUE, 20, -1, true, false)));
} else if (action == PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK) {
Expand All @@ -90,7 +99,7 @@ private void packetReceivedInject(BlockPos pos, PlayerActionC2SPacket.Action act

@Inject(method = "processBlockBreakingAction", at = @At("TAIL"))
private void enforceBlockBreakingCooldown(BlockPos pos, PlayerActionC2SPacket.Action action, Direction direction, int worldHeight, CallbackInfo ci) {
if (this.player.getServerWorld().getBlockState(pos).getBlock() instanceof VirtualBlock || this.player.getMainHandStack().getItem() instanceof VirtualItem) {
if (this.shouldMineServerSide(pos, this.player.getServerWorld().getBlockState(pos))) {
if (action == PlayerActionC2SPacket.Action.START_DESTROY_BLOCK) {
this.startMiningTime += blockBreakingCooldown;
}
Expand All @@ -99,16 +108,20 @@ private void enforceBlockBreakingCooldown(BlockPos pos, PlayerActionC2SPacket.Ac

@Inject(method = "finishMining", at = @At("HEAD"))
private void clearEffects(BlockPos pos, PlayerActionC2SPacket.Action action, String reason, CallbackInfo ci) {
if (this.player.getServerWorld().getBlockState(pos).getBlock() instanceof VirtualBlock || this.player.getMainHandStack().getItem() instanceof VirtualItem) {
this.player.networkHandler.sendPacket(new RemoveEntityStatusEffectS2CPacket(player.getId(), StatusEffects.MINING_FATIGUE));
if (this.player.hasStatusEffect(StatusEffects.MINING_FATIGUE)) {
StatusEffectInstance effectInstance = this.player.getStatusEffect(StatusEffects.MINING_FATIGUE);
this.player.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(this.player.getId(), effectInstance));
}
this.player.networkHandler.sendPacket(new RemoveEntityStatusEffectS2CPacket(player.getId(), StatusEffects.MINING_FATIGUE));
if (this.player.hasStatusEffect(StatusEffects.MINING_FATIGUE)) {
StatusEffectInstance effectInstance = this.player.getStatusEffect(StatusEffects.MINING_FATIGUE);
this.player.networkHandler.sendPacket(new EntityStatusEffectS2CPacket(this.player.getId(), effectInstance));
}
}


@Redirect(method = "processBlockBreakingAction", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"))
private void noOneCaresAboutMismatch(Logger logger, String message, Object p0, Object p1) {}
private boolean shouldMineServerSide(BlockPos pos, BlockState state) {
return state.getBlock() instanceof VirtualBlock || this.player.getMainHandStack().getItem() instanceof VirtualItem || BlockHelper.SERVER_SIDE_MINING_CHECK.invoke(this.player, pos, state);
}


@Redirect(method = "processBlockBreakingAction", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;warn(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"), require = 0)
private void noOneCaresAboutMismatch(Logger logger, String message, Object p0, Object p1) {
}
}
Loading

0 comments on commit a9c5341

Please sign in to comment.