├── withSettingsOn.png ├── withoutSettingsOn.png ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── settings.gradle ├── src └── main │ ├── java │ └── ca │ │ └── fxco │ │ └── betterblockstates │ │ ├── common │ │ ├── patches │ │ │ ├── blockEntitySkipable.java │ │ │ ├── BlockTicker.java │ │ │ ├── TickableGameEventListener.java │ │ │ ├── BlockListener.java │ │ │ └── WorldListeners.java │ │ ├── BetterBlockStates.java │ │ ├── config │ │ │ ├── Option.java │ │ │ └── Config.java │ │ └── classes │ │ │ └── StateSystem.java │ │ └── mixin │ │ ├── skippable_block_entity │ │ ├── BlockEntity_skippableMixin.java │ │ └── ChunkSerializer_skippableMixin.java │ │ ├── blockstate_listeners │ │ ├── WorldChunkGameEvents.java │ │ ├── WorldChunk_stateListenersMixin.java │ │ └── World_stateListenersMixin.java │ │ ├── blockstate_tickers │ │ └── World_stateTickerMixin.java │ │ ├── blocks │ │ ├── comparator │ │ │ ├── ComparatorBlockEntity_bypassMixin.java │ │ │ └── ComparatorBlock_BElessMixin.java │ │ ├── sculk_sensor │ │ │ ├── SculkSensorBlockEntity_bypassMixin.java │ │ │ ├── movable │ │ │ │ └── PistonBlock_movableSculkMixin.java │ │ │ ├── SculkSensorEventListener_tickableMixin.java │ │ │ └── SculkSensorBlock_BElessMixin.java │ │ └── daylight_detector │ │ │ └── DaylightDetectorBlock_tickableMixin.java │ │ └── MixinPlugin.java │ └── resources │ ├── fabric.mod.json │ └── betterblockstates.mixins.json ├── gradle.properties ├── README.md ├── LICENSE └── .gitignore /withSettingsOn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FxMorin/BetterBlockStates/HEAD/withSettingsOn.png -------------------------------------------------------------------------------- /withoutSettingsOn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FxMorin/BetterBlockStates/HEAD/withoutSettingsOn.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | gradlePluginPortal() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/patches/blockEntitySkipable.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common.patches; 2 | 3 | public interface blockEntitySkipable { 4 | 5 | default boolean shouldSkip() { 6 | return false; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/patches/BlockTicker.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common.patches; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.util.math.BlockPos; 5 | import net.minecraft.world.World; 6 | 7 | public interface BlockTicker { 8 | void tick(World world, BlockState state, BlockPos pos); 9 | } 10 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs=-Xmx16G 3 | # Fabric Properties 4 | # check these on https://modmuss50.me/fabric.html 5 | minecraft_version=1.18.1 6 | yarn_mappings=1.18.1+build.2 7 | loader_version=0.12.10 8 | # Mod Properties 9 | mod_version=1.0-SNAPSHOT 10 | maven_group=ca.fxco 11 | archives_base_name=betterBlockStates 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/patches/TickableGameEventListener.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common.patches; 2 | 3 | import net.minecraft.world.World; 4 | import net.minecraft.world.event.listener.GameEventListener; 5 | 6 | public interface TickableGameEventListener extends GameEventListener { 7 | 8 | boolean canTick(); 9 | 10 | void tick(World world); 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/skippable_block_entity/BlockEntity_skippableMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.skippable_block_entity; 2 | 3 | import ca.fxco.betterblockstates.common.patches.blockEntitySkipable; 4 | import net.minecraft.block.entity.BlockEntity; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | 7 | @Mixin(BlockEntity.class) 8 | public class BlockEntity_skippableMixin implements blockEntitySkipable {} 9 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/patches/BlockListener.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common.patches; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | import net.minecraft.util.math.ChunkPos; 5 | import net.minecraft.world.World; 6 | import net.minecraft.world.chunk.Chunk; 7 | 8 | public interface BlockListener { 9 | void createListener(World world, Chunk chunk, ChunkPos chunkPos, BlockPos pos); 10 | void removeListener(World world, Chunk chunk, BlockPos pos); 11 | } 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BetterBlockStates 2 | An experimental mod that converts some block entities to blockstates. This is done for performance & functionality reasons. 3 | 4 | **Current performance results:** 5 | 6 | 3x3 chunks of sculk sensors (-61 to 319) [3,420 blocks] 7 | 8 | Without BetterBlockStates: 9 | 10 | ![Without optimization](https://github.com/fxmorin/BetterBlockStates/blob/master/withoutSettingsOn.png) 11 | 12 | With BetterBlockStates: 13 | 14 | ![With optimization](https://github.com/fxmorin/BetterBlockStates/blob/master/withSettingsOn.png) 15 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blockstate_listeners/WorldChunkGameEvents.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blockstate_listeners; 2 | 3 | import it.unimi.dsi.fastutil.ints.Int2ObjectMap; 4 | import net.minecraft.world.chunk.WorldChunk; 5 | import net.minecraft.world.event.listener.GameEventDispatcher; 6 | import org.spongepowered.asm.mixin.Mixin; 7 | import org.spongepowered.asm.mixin.gen.Accessor; 8 | 9 | @Mixin(WorldChunk.class) 10 | public interface WorldChunkGameEvents { 11 | @Accessor("gameEventDispatchers") 12 | public Int2ObjectMap getGameEventDispatchers(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/BetterBlockStates.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common; 2 | 3 | import ca.fxco.betterblockstates.common.classes.StateSystem; 4 | import ca.fxco.betterblockstates.common.config.Config; 5 | import net.fabricmc.api.ModInitializer; 6 | 7 | public class BetterBlockStates implements ModInitializer { 8 | public static Config CONFIG; 9 | 10 | @Override 11 | public void onInitialize() { 12 | if (CONFIG == null) { 13 | throw new IllegalStateException("The mixin plugin did not initialize the config! Did it not load?"); 14 | } 15 | StateSystem.onInitialize(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "betterblockstates", 4 | "version": "${version}", 5 | "name": "BetterBlockStates", 6 | "description": "A mod which changes some blockEntities to blockStates for performance & functionality reasons", 7 | "authors": [ 8 | "FX - PR0CESS" 9 | ], 10 | "contact": {}, 11 | "license": "MIT", 12 | "icon": "assets/betterBlockStates/icon.png", 13 | "environment": "*", 14 | "entrypoints": { 15 | "main": [ 16 | "ca.fxco.betterblockstates.common.BetterBlockStates" 17 | ] 18 | }, 19 | "mixins": [ 20 | "betterblockstates.mixins.json" 21 | ], 22 | "depends": { 23 | "fabricloader": ">=0.12.10", 24 | "minecraft": [ 25 | "1.18", 26 | "1.18.1" 27 | ] 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/patches/WorldListeners.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common.patches; 2 | 3 | import net.minecraft.util.math.BlockPos; 4 | import net.minecraft.util.math.ChunkPos; 5 | import net.minecraft.world.event.listener.GameEventListener; 6 | 7 | public interface WorldListeners { 8 | 9 | public void addListener(GameEventListener listener, ChunkPos chunkPos, BlockPos pos); 10 | 11 | public void addListener(GameEventListener listener, BlockPos pos); 12 | 13 | public void addTickingListener(GameEventListener listener); 14 | 15 | public GameEventListener removeListener(ChunkPos chunkPos, BlockPos pos); 16 | 17 | public GameEventListener removeListener(BlockPos pos); 18 | 19 | public void removeListenersChunk(ChunkPos chunkPos); 20 | 21 | public void removeTickingListener(GameEventListener listener); 22 | 23 | public void tickListeners(); 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blockstate_tickers/World_stateTickerMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blockstate_tickers; 2 | 3 | import ca.fxco.betterblockstates.common.classes.StateSystem; 4 | import net.minecraft.world.World; 5 | import org.spongepowered.asm.mixin.Mixin; 6 | import org.spongepowered.asm.mixin.Shadow; 7 | import org.spongepowered.asm.mixin.injection.At; 8 | import org.spongepowered.asm.mixin.injection.Inject; 9 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 10 | 11 | @Mixin(World.class) 12 | public abstract class World_stateTickerMixin { 13 | 14 | @Shadow public abstract boolean shouldTickBlocksInChunk(long chunkPos); 15 | 16 | private final World self = (World)(Object)this; 17 | 18 | @Inject( 19 | method = "tickBlockEntities()V", 20 | at = @At( 21 | value = "HEAD", 22 | shift = At.Shift.AFTER 23 | ) 24 | ) 25 | protected void tickBlockTickers(CallbackInfo ci) { 26 | StateSystem.onTick(self); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2021 FX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/resources/betterblockstates.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "minVersion": "0.8", 4 | "package": "ca.fxco.betterblockstates.mixin", 5 | "plugin": "ca.fxco.betterblockstates.mixin.MixinPlugin", 6 | "compatibilityLevel": "JAVA_16", 7 | "mixins": [ 8 | "blocks.comparator.ComparatorBlock_BElessMixin", 9 | "blocks.comparator.ComparatorBlockEntity_bypassMixin", 10 | "blocks.daylight_detector.DaylightDetectorBlock_tickableMixin", 11 | "blocks.sculk_sensor.SculkSensorBlock_BElessMixin", 12 | "blocks.sculk_sensor.SculkSensorBlockEntity_bypassMixin", 13 | "blocks.sculk_sensor.SculkSensorEventListener_tickableMixin", 14 | "blocks.sculk_sensor.movable.PistonBlock_movableSculkMixin", 15 | "blockstate_listeners.World_stateListenersMixin", 16 | "blockstate_listeners.WorldChunk_stateListenersMixin", 17 | "blockstate_listeners.WorldChunkGameEvents", 18 | "blockstate_tickers.World_stateTickerMixin", 19 | "skippable_block_entity.BlockEntity_skippableMixin", 20 | "skippable_block_entity.ChunkSerializer_skippableMixin" 21 | ], 22 | "injectors": { 23 | "defaultRequire": 1 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/skippable_block_entity/ChunkSerializer_skippableMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.skippable_block_entity; 2 | 3 | import ca.fxco.betterblockstates.common.patches.blockEntitySkipable; 4 | import net.minecraft.block.entity.BlockEntity; 5 | import net.minecraft.world.ChunkSerializer; 6 | import net.minecraft.world.chunk.WorldChunk; 7 | import org.spongepowered.asm.mixin.Mixin; 8 | import org.spongepowered.asm.mixin.injection.At; 9 | import org.spongepowered.asm.mixin.injection.Redirect; 10 | 11 | @Mixin(ChunkSerializer.class) 12 | public abstract class ChunkSerializer_skippableMixin { 13 | 14 | 15 | @Redirect( 16 | method = "method_39797(Lnet/minecraft/nbt/NbtList;Lnet/minecraft/server/world/ServerWorld;Lnet/minecraft/nbt/NbtList;Lnet/minecraft/world/chunk/WorldChunk;)V", 17 | at = @At( 18 | value = "INVOKE", 19 | target = "Lnet/minecraft/world/chunk/WorldChunk;setBlockEntity(Lnet/minecraft/block/entity/BlockEntity;)V" 20 | ) 21 | ) 22 | private static void getEntityLoadingCallback(WorldChunk instance, BlockEntity blockEntity) { 23 | if (!((blockEntitySkipable)(blockEntity)).shouldSkip()) { 24 | instance.setBlockEntity(blockEntity); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blocks/comparator/ComparatorBlockEntity_bypassMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blocks.comparator; 2 | 3 | import ca.fxco.betterblockstates.common.patches.blockEntitySkipable; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.entity.BlockEntity; 6 | import net.minecraft.block.entity.BlockEntityType; 7 | import net.minecraft.block.entity.ComparatorBlockEntity; 8 | import net.minecraft.nbt.NbtCompound; 9 | import net.minecraft.state.property.IntProperty; 10 | import net.minecraft.util.math.BlockPos; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | 13 | @Mixin(ComparatorBlockEntity.class) 14 | public abstract class ComparatorBlockEntity_bypassMixin extends BlockEntity implements blockEntitySkipable { 15 | 16 | public ComparatorBlockEntity_bypassMixin(BlockEntityType type, BlockPos pos, BlockState state) {super(type, pos, state);} 17 | 18 | private static final IntProperty OUTPUT_SIGNAL = IntProperty.of("output_signal", 0, 1023); 19 | 20 | 21 | @Override 22 | public boolean shouldSkip() { 23 | return true; 24 | } 25 | 26 | 27 | @Override 28 | public void readNbt(NbtCompound nbt) { 29 | super.readNbt(nbt); 30 | this.setCachedState(this.getCachedState().with(OUTPUT_SIGNAL, nbt.getInt("OutputSignal"))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blocks/sculk_sensor/SculkSensorBlockEntity_bypassMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blocks.sculk_sensor; 2 | 3 | import ca.fxco.betterblockstates.common.patches.blockEntitySkipable; 4 | import net.minecraft.block.BlockState; 5 | import net.minecraft.block.entity.BlockEntity; 6 | import net.minecraft.block.entity.BlockEntityType; 7 | import net.minecraft.block.entity.SculkSensorBlockEntity; 8 | import net.minecraft.nbt.NbtCompound; 9 | import net.minecraft.state.property.IntProperty; 10 | import net.minecraft.util.math.BlockPos; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | 13 | @Mixin(SculkSensorBlockEntity.class) 14 | public abstract class SculkSensorBlockEntity_bypassMixin extends BlockEntity implements blockEntitySkipable { 15 | 16 | public SculkSensorBlockEntity_bypassMixin(BlockEntityType type, BlockPos pos, BlockState state) {super(type, pos, state);} 17 | 18 | private static final IntProperty LAST_FREQUENCY = IntProperty.of("last_frequency", 0, 15); 19 | 20 | 21 | @Override 22 | public boolean shouldSkip() { 23 | return true; 24 | } 25 | 26 | 27 | @Override 28 | public void readNbt(NbtCompound nbt) { 29 | super.readNbt(nbt); 30 | this.setCachedState(this.getCachedState().with(LAST_FREQUENCY, nbt.getInt("last_vibration_frequency"))); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blocks/sculk_sensor/movable/PistonBlock_movableSculkMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blocks.sculk_sensor.movable; 2 | 3 | import net.minecraft.block.BlockState; 4 | import net.minecraft.block.Blocks; 5 | import net.minecraft.block.PistonBlock; 6 | import net.minecraft.util.math.BlockPos; 7 | import net.minecraft.util.math.Direction; 8 | import net.minecraft.world.World; 9 | import org.spongepowered.asm.mixin.Mixin; 10 | import org.spongepowered.asm.mixin.injection.At; 11 | import org.spongepowered.asm.mixin.injection.Inject; 12 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 13 | 14 | @Mixin(PistonBlock.class) 15 | public class PistonBlock_movableSculkMixin { 16 | 17 | @Inject( 18 | method = "isMovable(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;ZLnet/minecraft/util/math/Direction;)Z", 19 | at = @At( 20 | value = "INVOKE", 21 | target = "Lnet/minecraft/block/BlockState;hasBlockEntity()Z", 22 | shift = At.Shift.BEFORE 23 | ), 24 | cancellable = true 25 | ) 26 | private static void makeSculkMovable(BlockState state, World world, BlockPos pos, Direction direction, boolean canBreak, Direction pistonDir, CallbackInfoReturnable cir) { 27 | if (state.getBlock() == Blocks.SCULK_SENSOR) cir.setReturnValue(true); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blockstate_listeners/WorldChunk_stateListenersMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blockstate_listeners; 2 | 3 | import ca.fxco.betterblockstates.common.classes.StateSystem; 4 | import net.minecraft.util.math.ChunkPos; 5 | import net.minecraft.world.World; 6 | import net.minecraft.world.chunk.ChunkSection; 7 | import net.minecraft.world.chunk.UpgradeData; 8 | import net.minecraft.world.chunk.WorldChunk; 9 | import net.minecraft.world.gen.chunk.BlendingData; 10 | import net.minecraft.world.tick.ChunkTickScheduler; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(WorldChunk.class) 17 | public class WorldChunk_stateListenersMixin { 18 | 19 | private final WorldChunk self = (WorldChunk)(Object)this; 20 | 21 | 22 | @Inject( 23 | method = "(Lnet/minecraft/world/World;Lnet/minecraft/util/math/ChunkPos;Lnet/minecraft/world/chunk/UpgradeData;Lnet/minecraft/world/tick/ChunkTickScheduler;Lnet/minecraft/world/tick/ChunkTickScheduler;J[Lnet/minecraft/world/chunk/ChunkSection;Lnet/minecraft/world/chunk/WorldChunk$EntityLoader;Lnet/minecraft/world/gen/chunk/BlendingData;)V", 24 | at = @At("RETURN") 25 | ) 26 | public void onChunkGenerated(World world, ChunkPos pos, UpgradeData upgradeData, ChunkTickScheduler blockTickScheduler, ChunkTickScheduler fluidTickScheduler, long inhabitedTime, ChunkSection[] sectionArrayInitializer, WorldChunk.EntityLoader entityLoader, BlendingData blendingData, CallbackInfo ci) { 27 | StateSystem.onChunkLoad(self.getWorld(), self); 28 | } 29 | 30 | 31 | @Inject( 32 | method = "setLoadedToWorld(Z)V", 33 | at = @At("HEAD") 34 | ) 35 | public void setLoadedToWorld(boolean loaded, CallbackInfo ci) { 36 | if (!loaded) { 37 | StateSystem.onChunkUnload(self.getWorld(), self); 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blocks/daylight_detector/DaylightDetectorBlock_tickableMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blocks.daylight_detector; 2 | 3 | import ca.fxco.betterblockstates.common.classes.StateSystem; 4 | import ca.fxco.betterblockstates.common.patches.BlockTicker; 5 | import net.minecraft.block.Block; 6 | import net.minecraft.block.BlockState; 7 | import net.minecraft.block.Blocks; 8 | import net.minecraft.block.DaylightDetectorBlock; 9 | import net.minecraft.block.entity.BlockEntity; 10 | import net.minecraft.util.math.BlockPos; 11 | import net.minecraft.world.World; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Shadow; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 17 | 18 | import java.util.HashSet; 19 | import java.util.Map; 20 | 21 | @Mixin(DaylightDetectorBlock.class) 22 | public abstract class DaylightDetectorBlock_tickableMixin extends Block implements BlockTicker { 23 | 24 | protected DaylightDetectorBlock_tickableMixin(Settings settings) {super(settings);} 25 | 26 | @Shadow private static void updateState(BlockState state, World world, BlockPos pos) {} 27 | 28 | static { 29 | StateSystem.blockTickersOnLoad.add(() -> Map.ofEntries(Map.entry((world) -> !world.isClient && world.getDimension().hasSkyLight() && world.getTime() % 20L == 0L,new HashSet<>(Blocks.DAYLIGHT_DETECTOR.getStateManager().getStates())))); 30 | } 31 | 32 | @Override 33 | public void tick(World world, BlockState state, BlockPos pos) { 34 | updateState(state,world,pos); 35 | } 36 | 37 | 38 | @Inject( 39 | method = "createBlockEntity(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)Lnet/minecraft/block/entity/BlockEntity;", 40 | at = @At("HEAD"), 41 | cancellable = true 42 | ) 43 | public void createBlockEntity(BlockPos pos, BlockState state, CallbackInfoReturnable cir) { 44 | cir.setReturnValue(null); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/mixin/blocks/sculk_sensor/SculkSensorEventListener_tickableMixin.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.mixin.blocks.sculk_sensor; 2 | 3 | import ca.fxco.betterblockstates.common.patches.TickableGameEventListener; 4 | import ca.fxco.betterblockstates.common.patches.WorldListeners; 5 | import net.minecraft.util.math.BlockPos; 6 | import net.minecraft.world.World; 7 | import net.minecraft.world.event.GameEvent; 8 | import net.minecraft.world.event.listener.SculkSensorListener; 9 | import org.spongepowered.asm.mixin.Final; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.Shadow; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | import java.util.Optional; 17 | 18 | @Mixin(SculkSensorListener.class) 19 | public abstract class SculkSensorEventListener_tickableMixin implements TickableGameEventListener { 20 | 21 | @Shadow protected Optional event; 22 | @Shadow protected int delay; 23 | @Shadow @Final protected SculkSensorListener.Callback callback; 24 | @Shadow protected int distance; 25 | private final SculkSensorListener self = (SculkSensorListener)(Object)this; 26 | 27 | @Inject( 28 | method = "listen(Lnet/minecraft/world/World;Lnet/minecraft/world/event/GameEvent;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/BlockPos;)V", 29 | at = @At("HEAD") 30 | ) 31 | private void listen(World world, GameEvent event, BlockPos pos, BlockPos sourcePos, CallbackInfo ci) { 32 | ((WorldListeners)world).addTickingListener(self); 33 | } 34 | 35 | @Override 36 | public boolean canTick() { 37 | return this.event.isPresent(); 38 | } 39 | 40 | @Override 41 | public void tick(World world) { 42 | --this.delay; 43 | if (this.delay <= 0) { 44 | this.delay = 0; 45 | this.callback.accept(world, this, this.event.get(), this.distance); 46 | this.event = Optional.empty(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | # mpeltonen/sbt-idea plugin 11 | .idea_modules/ 12 | 13 | # JIRA plugin 14 | atlassian-ide-plugin.xml 15 | 16 | # Compiled class file 17 | *.class 18 | 19 | # Log file 20 | *.log 21 | 22 | # BlueJ files 23 | *.ctxt 24 | 25 | # Package Files # 26 | *.jar 27 | *.war 28 | *.nar 29 | *.ear 30 | *.zip 31 | *.tar.gz 32 | *.rar 33 | 34 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 35 | hs_err_pid* 36 | 37 | *~ 38 | 39 | # temporary files which can be created if a process still has a handle open of a deleted file 40 | .fuse_hidden* 41 | 42 | # KDE directory preferences 43 | .directory 44 | 45 | # Linux trash folder which might appear on any partition or disk 46 | .Trash-* 47 | 48 | # .nfs files are created when an open file is removed but is still being accessed 49 | .nfs* 50 | 51 | # General 52 | .DS_Store 53 | .AppleDouble 54 | .LSOverride 55 | 56 | # Icon must end with two \r 57 | Icon 58 | 59 | # Thumbnails 60 | ._* 61 | 62 | # Files that might appear in the root of a volume 63 | .DocumentRevisions-V100 64 | .fseventsd 65 | .Spotlight-V100 66 | .TemporaryItems 67 | .Trashes 68 | .VolumeIcon.icns 69 | .com.apple.timemachine.donotpresent 70 | 71 | # Directories potentially created on remote AFP share 72 | .AppleDB 73 | .AppleDesktop 74 | Network Trash Folder 75 | Temporary Items 76 | .apdisk 77 | 78 | # Windows thumbnail cache files 79 | Thumbs.db 80 | Thumbs.db:encryptable 81 | ehthumbs.db 82 | ehthumbs_vista.db 83 | 84 | # Dump file 85 | *.stackdump 86 | 87 | # Folder config file 88 | [Dd]esktop.ini 89 | 90 | # Recycle Bin used on file shares 91 | $RECYCLE.BIN/ 92 | 93 | # Windows Installer files 94 | *.cab 95 | *.msi 96 | *.msix 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | 103 | .gradle 104 | build/ 105 | 106 | # Ignore Gradle GUI config 107 | gradle-app.setting 108 | 109 | # Cache of project 110 | .gradletasknamecache 111 | 112 | **/build/ 113 | 114 | # Common working directory 115 | run/ 116 | 117 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 118 | !gradle-wrapper.jar 119 | -------------------------------------------------------------------------------- /src/main/java/ca/fxco/betterblockstates/common/config/Option.java: -------------------------------------------------------------------------------- 1 | package ca.fxco.betterblockstates.common.config; 2 | 3 | import it.unimi.dsi.fastutil.objects.Object2BooleanLinkedOpenHashMap; 4 | import it.unimi.dsi.fastutil.objects.Object2BooleanMap; 5 | import org.apache.logging.log4j.Logger; 6 | 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | import java.util.LinkedHashSet; 10 | import java.util.Set; 11 | 12 | public class Option { 13 | private final String name; 14 | 15 | private Object2BooleanLinkedOpenHashMap