8 Commits

Author SHA1 Message Date
Motschen
afac024e9e Client side implementation of the jukebox overhaul
Uses a mixin into the sound system to determine the sound played at the position of the jukebox, then tries to get the record item of the sound.
If it fails it will fall back to the server side implementation.
2021-03-28 12:07:47 +02:00
Motschen
f802e803b9 Fix #9 2021-03-15 13:43:38 +01:00
Motschen
0d008e40d9 Fix puddles connecting weirdly
The cause of the bug cannot be easily fixed and would cause issues with certain renderers, so I just made puddles unable to be placed when the corners or sides of the block above or below already have a fluid.
2021-03-15 13:32:28 +01:00
Motschen
e43e483567 VisualOverhaul 3.0.0 - Puddles & Colors
Switched to MidnightConfig
(No need to seperately download AutoConfig & ClothConfig anymore)

Adds puddles which spawn during rain and can be used to fill a water bottle.
(Game rule: "puddleSpawnRate")
Also, snow layers can now pile up during snow storms.
(Game rule: "snowStackChance")

Items which are colored in their block form also show the color corresponding to the biome as an item. (Toggleable via config)
2021-03-14 21:22:06 +01:00
Motschen
920bb6958e Bump version 2021-01-23 19:59:56 +01:00
Motschen
c2306d7fa6 Fix ClassCastExeption 2021-01-23 19:58:36 +01:00
Motschen
792e81f4ca Fancy Furnace, better packet handling, config translations 2021-01-23 19:37:41 +01:00
Motschen
fe5c2a7e1b Canvas compat (Closes #2), Fix Z-Fighting 2021-01-23 10:47:14 +01:00
39 changed files with 1355 additions and 75 deletions

View File

@@ -25,12 +25,6 @@ dependencies {
modCompile "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
modImplementation ("me.sargunvohra.mcmods:autoconfig1u:${project.auto_config_version}") {
exclude group: "net.fabricmc.fabric-api"
}
modImplementation ("me.shedaniel.cloth:config-2:${project.cloth_config_version}") {
exclude group: "net.fabricmc.fabric-api"
}
modImplementation ("io.github.prospector:modmenu:${project.mod_menu_version}") {
exclude group: "net.fabricmc.fabric-api"
}

View File

@@ -3,19 +3,17 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/use
minecraft_version=1.16.4
yarn_mappings=1.16.4+build.7
loader_version=0.10.8
minecraft_version=1.16.5
yarn_mappings=1.16.5+build.3
loader_version=0.11.1
# Mod Properties
mod_version = 1.0.0
mod_version = 3.1.0
maven_group = eu.midnightdust
archives_base_name = visualoverhaul
# Dependencies
# currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api
fabric_version=0.28.4+1.16
fabric_version=0.29.4+1.16
auto_config_version = 3.2.0-unstable
cloth_config_version = 4.7.0-unstable
mod_menu_version = 1.14.6+build.31

View File

@@ -1,8 +1,33 @@
package eu.midnightdust.visualoverhaul;
import eu.midnightdust.visualoverhaul.block.PuddleBlock;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory;
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.minecraft.block.Block;
import net.minecraft.block.Material;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.GameRules;
public class VisualOverhaul implements ModInitializer {
public static final String MOD_ID = "visualoverhaul";
public static final Block Puddle = new PuddleBlock(Fluids.WATER, FabricBlockSettings.of(Material.WATER));
public static GameRules.Key<GameRules.IntRule> PUDDLE_SPAWN_RATE;
public static GameRules.Key<GameRules.IntRule> SNOW_STACK_CHANCE;
public class VisualOverhaul {
public static final Identifier UPDATE_POTION_BOTTLES = new Identifier("visualoverhaul", "brewingstand");
public static final Identifier UPDATE_RECORD = new Identifier("visualoverhaul", "record");
public static final Identifier UPDATE_FURNACE_ITEMS = new Identifier("visualoverhaul", "furnace");
public void onInitialize() {
PUDDLE_SPAWN_RATE = GameRuleRegistry.register("puddleSpawnRate", GameRules.Category.SPAWNING, GameRuleFactory.createIntRule(1));
SNOW_STACK_CHANCE = GameRuleRegistry.register("snowStackChance", GameRules.Category.SPAWNING, GameRuleFactory.createIntRule(1));
Registry.register(Registry.BLOCK, new Identifier(MOD_ID,"puddle"), Puddle);
Registry.register(Registry.ITEM, new Identifier(MOD_ID,"puddle"), new BlockItem(Puddle, new Item.Settings()));
}
}

View File

@@ -2,46 +2,63 @@ package eu.midnightdust.visualoverhaul;
import eu.midnightdust.visualoverhaul.block.JukeboxTop;
import eu.midnightdust.visualoverhaul.block.renderer.BrewingStandBlockEntityRenderer;
import eu.midnightdust.visualoverhaul.block.renderer.FurnaceBlockEntityRenderer;
import eu.midnightdust.visualoverhaul.block.renderer.JukeboxBlockEntityRenderer;
import eu.midnightdust.visualoverhaul.config.VOConfig;
import me.sargunvohra.mcmods.autoconfig1u.AutoConfig;
import me.sargunvohra.mcmods.autoconfig1u.serializer.JanksonConfigSerializer;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.rendereregistry.v1.BlockEntityRendererRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.impl.blockrenderlayer.BlockRenderLayerMapImpl;
import net.fabricmc.fabric.impl.client.rendering.ColorProviderRegistryImpl;
import net.fabricmc.fabric.impl.networking.ClientSidePacketRegistryImpl;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.block.Block;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.block.entity.BrewingStandBlockEntity;
import net.minecraft.block.entity.FurnaceBlockEntity;
import net.minecraft.block.entity.JukeboxBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.MusicDiscItem;
import net.minecraft.potion.PotionUtil;
import net.minecraft.potion.Potions;
import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DefaultedList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BuiltinBiomes;
import static eu.midnightdust.visualoverhaul.VisualOverhaul.UPDATE_POTION_BOTTLES;
import static eu.midnightdust.visualoverhaul.VisualOverhaul.UPDATE_RECORD;
import java.util.Objects;
import static eu.midnightdust.visualoverhaul.VisualOverhaul.*;
@SuppressWarnings("deprecation")
public class VisualOverhaulClient implements ClientModInitializer {
public static VOConfig VO_CONFIG;
public static Block JukeBoxTop = new JukeboxTop();
public static Block JukeBoxTop = new JukeboxTop();
private final MinecraftClient client = MinecraftClient.getInstance();
@Override
public void onInitializeClient() {
AutoConfig.register(VOConfig.class, JanksonConfigSerializer::new);
VO_CONFIG = AutoConfig.getConfigHolder(VOConfig.class).getConfig();
VOConfig.init("visualoverhaul", VOConfig.class);
// Block only registered on client, because it's just used for the renderer //
Registry.register(Registry.BLOCK, new Identifier("visualoverhaul","jukebox_top"), JukeBoxTop);
BlockRenderLayerMapImpl.INSTANCE.putBlock(Blocks.JUKEBOX, RenderLayer.getCutout());
BlockRenderLayerMapImpl.INSTANCE.putBlock(JukeBoxTop, RenderLayer.getCutout());
BlockRenderLayerMapImpl.INSTANCE.putBlock(Blocks.FURNACE, RenderLayer.getCutout());
BlockEntityRendererRegistry.INSTANCE.register(BlockEntityType.BREWING_STAND, BrewingStandBlockEntityRenderer::new);
BlockEntityRendererRegistry.INSTANCE.register(BlockEntityType.JUKEBOX, JukeboxBlockEntityRenderer::new);
BlockEntityRendererRegistry.INSTANCE.register(BlockEntityType.FURNACE, FurnaceBlockEntityRenderer::new);
Registry.ITEM.forEach((item) -> {
if(item instanceof MusicDiscItem) {
@@ -57,12 +74,14 @@ public class VisualOverhaulClient implements ClientModInitializer {
inv.set(i, attachedData.readItemStack());
}
packetContext.getTaskQueue().execute(() -> {
BrewingStandBlockEntity blockEntity = (BrewingStandBlockEntity) MinecraftClient.getInstance().world.getBlockEntity(pos);
blockEntity.setStack(0,inv.get(0));
blockEntity.setStack(1,inv.get(1));
blockEntity.setStack(2,inv.get(2));
blockEntity.setStack(3,inv.get(3));
blockEntity.setStack(4,inv.get(4));
if (client.world != null && client.world.getBlockEntity(pos) != null && client.world.getBlockEntity(pos) instanceof BrewingStandBlockEntity) {
BrewingStandBlockEntity blockEntity = (BrewingStandBlockEntity) client.world.getBlockEntity(pos);
blockEntity.setStack(0, inv.get(0));
blockEntity.setStack(1, inv.get(1));
blockEntity.setStack(2, inv.get(2));
blockEntity.setStack(3, inv.get(3));
blockEntity.setStack(4, inv.get(4));
}
});
});
ClientSidePacketRegistryImpl.INSTANCE.register(UPDATE_RECORD,
@@ -70,13 +89,68 @@ public class VisualOverhaulClient implements ClientModInitializer {
BlockPos pos = attachedData.readBlockPos();
ItemStack record = attachedData.readItemStack();
packetContext.getTaskQueue().execute(() -> {
JukeboxBlockEntity blockEntity = (JukeboxBlockEntity)MinecraftClient.getInstance().world.getBlockEntity(pos);
if (client.world != null && client.world.getBlockEntity(pos) != null && client.world.getBlockEntity(pos) instanceof JukeboxBlockEntity) {
JukeboxBlockEntity blockEntity = (JukeboxBlockEntity) client.world.getBlockEntity(pos);
blockEntity.setRecord(record);
}
});
});
ClientSidePacketRegistryImpl.INSTANCE.register(UPDATE_FURNACE_ITEMS,
(packetContext, attachedData) -> {
BlockPos pos = attachedData.readBlockPos();
DefaultedList<ItemStack> inv = DefaultedList.ofSize(3, ItemStack.EMPTY);
for (int i = 0; i < 2; i++) {
inv.set(i, attachedData.readItemStack());
}
packetContext.getTaskQueue().execute(() -> {
if (client.world != null && client.world.getBlockEntity(pos) != null && client.world.getBlockEntity(pos) instanceof FurnaceBlockEntity) {
FurnaceBlockEntity blockEntity = (FurnaceBlockEntity) client.world.getBlockEntity(pos);
blockEntity.setStack(0, inv.get(0));
blockEntity.setStack(1, inv.get(1));
blockEntity.setStack(2, inv.get(2));
}
});
});
// Register builtin resourcepacks
FabricLoader.getInstance().getModContainer("visualoverhaul").ifPresent(modContainer -> {
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("visualoverhaul:nobottles"), "resourcepacks/visualoverhaul", modContainer, true);
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("visualoverhaul:nobottles"), "resourcepacks/nobrewingbottles", modContainer, true);
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("visualoverhaul:fancyfurnace"), "resourcepacks/fancyfurnace", modContainer, true);
ResourceManagerHelper.registerBuiltinResourcePack(new Identifier("visualoverhaul:coloredwaterbucket"), "resourcepacks/coloredwaterbucket", modContainer, true);
});
// Context Colored Items
if (VOConfig.coloredItems) {
ClientTickEvents.END_CLIENT_TICK.register(client -> {
int waterColor;
int foliageColor;
if (client.world != null) {
Biome biome = client.world.getBiome(client.player.getBlockPos());
waterColor = biome.getWaterColor();
foliageColor = biome.getFoliageColor();
} else {
waterColor = BuiltinBiomes.PLAINS.getWaterColor();
foliageColor = BuiltinBiomes.PLAINS.getFoliageColor();
}
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> waterColor, VisualOverhaul.Puddle);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> tintIndex == 0 ? -1 : waterColor, Items.WATER_BUCKET);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> foliageColor, Items.GRASS_BLOCK);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> foliageColor, Items.ACACIA_LEAVES);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> foliageColor, Items.DARK_OAK_LEAVES);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> foliageColor, Items.JUNGLE_LEAVES);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> foliageColor, Items.OAK_LEAVES);
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> {
if (PotionUtil.getPotion(stack) == Potions.WATER && tintIndex == 0) {
return waterColor;
}
return tintIndex > 0 ? -1 : PotionUtil.getColor(stack);
}, Items.POTION);
});
}
// Else just register a static color for our puddle item
else {
ColorProviderRegistry.ITEM.register((stack, tintIndex) -> BuiltinBiomes.PLAINS.getWaterColor(), Puddle);
}
ColorProviderRegistry.BLOCK.register((state, view, pos, tintIndex) -> Objects.requireNonNull(ColorProviderRegistryImpl.BLOCK.get(Blocks.WATER)).getColor(state, view, pos, tintIndex), Puddle);
}
}

View File

@@ -0,0 +1,166 @@
package eu.midnightdust.visualoverhaul.block;
import eu.midnightdust.visualoverhaul.VisualOverhaul;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.*;
import net.minecraft.entity.ai.pathing.NavigationType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.*;
import net.minecraft.item.*;
import net.minecraft.loot.context.LootContext;
import net.minecraft.potion.PotionUtil;
import net.minecraft.potion.Potions;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.stat.Stats;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.WorldView;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@SuppressWarnings("deprecation")
public class PuddleBlock extends Block {
protected final FlowableFluid fluid;
public static final VoxelShape COLLISION_SHAPE;
public PuddleBlock(FlowableFluid fluid, AbstractBlock.Settings settings) {
super(settings);
this.fluid = fluid;
}
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
ItemStack itemStack = player.getStackInHand(hand);
if (itemStack.isEmpty()) {
return ActionResult.PASS;
} else {
Item item = itemStack.getItem();
ItemStack waterBottleStack;
if (item == Items.GLASS_BOTTLE) {
if (!world.isClient) {
if (!player.abilities.creativeMode) {
waterBottleStack = PotionUtil.setPotion(new ItemStack(Items.POTION), Potions.WATER);
player.incrementStat(Stats.USE_CAULDRON);
itemStack.decrement(1);
if (itemStack.isEmpty()) {
player.setStackInHand(hand, waterBottleStack);
} else if (!player.inventory.insertStack(waterBottleStack)) {
player.dropItem(waterBottleStack, false);
} else if (player instanceof ServerPlayerEntity) {
((ServerPlayerEntity)player).refreshScreenHandler(player.playerScreenHandler);
}
}
world.playSound(null, pos, SoundEvents.ITEM_BOTTLE_FILL, SoundCategory.BLOCKS, 1.0F, 1.0F);
world.setBlockState(pos, Blocks.AIR.getDefaultState());
}
return ActionResult.success(world.isClient);
}
else return ActionResult.FAIL;
}
}
@Override
public boolean hasRandomTicks(BlockState state) {
return true;
}
@Override
public void randomTick(BlockState state, ServerWorld world, BlockPos pos, Random random) {
if (!world.isRaining() && random.nextInt(2000) == 0) {
world.setBlockState(pos, Blocks.AIR.getDefaultState());
}
this.scheduledTick(state, world, pos, random);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return context.isAbove(COLLISION_SHAPE, pos, true) ? COLLISION_SHAPE : VoxelShapes.empty();
}
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return COLLISION_SHAPE;
}
@Override
public VoxelShape getCullingShape(BlockState state, BlockView world, BlockPos pos) {
return VoxelShapes.empty();
}
public boolean canPathfindThrough(BlockState state, BlockView world, BlockPos pos, NavigationType type) {
return true;
}
public FluidState getFluidState(BlockState state) {
return fluid.getFlowing(1,false);
}
@Environment(EnvType.CLIENT)
public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) {
return stateFrom.getFluidState().getFluid().matchesType(this.fluid);
}
public BlockRenderType getRenderType(BlockState state) {
return BlockRenderType.INVISIBLE;
}
public List<ItemStack> getDroppedStacks(BlockState state, LootContext.Builder builder) {
return Collections.emptyList();
}
public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) {
if (world.getBlockState(pos) == Blocks.AIR.getDefaultState() || world.getBlockState(pos) == VisualOverhaul.Puddle.getDefaultState()) {
int i;
// Check if there are fluids on the sides or corners of the block above
for (i = 2; i < 6; ++i) {
BlockPos pos1 = pos.up();
BlockPos pos2 = pos1.offset(Direction.byId(i));
if (!world.getFluidState(pos1.offset(Direction.byId(i))).isEmpty()) {
// When sides of the block above have water don't place the puddle
return false;
}
if (!world.getFluidState(pos2.offset(Direction.byId(i).rotateYClockwise())).isEmpty()) {
// When corners of the block above have water don't place the puddle
return false;
}
}
// Check if there are fluids on the sides or corners of the block below
for (i = 2; i < 6; ++i) {
BlockPos pos1 = pos.down();
BlockPos pos2 = pos1.offset(Direction.byId(i));
if (!world.getFluidState(pos1.offset(Direction.byId(i))).isEmpty()) {
// When sides of the block below have water don't place the puddle
return false;
}
if (!world.getFluidState(pos2.offset(Direction.byId(i).rotateYClockwise())).isEmpty()) {
// When corners of the block below have water don't place the puddle
return false;
}
}
return world.getBlockState(pos.down()).isSideSolidFullSquare(world, pos, Direction.UP);
}
// When there's already another block at the position don't place the puddle
else return false;
}
public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState newState, WorldAccess world, BlockPos pos, BlockPos posFrom) {
return !state.canPlaceAt(world, pos) ? Blocks.AIR.getDefaultState() : super.getStateForNeighborUpdate(state, direction, newState, world, pos, posFrom);
}
static {
COLLISION_SHAPE = net.minecraft.block.Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 0.5D, 16.0D);
}
}

View File

@@ -1,7 +1,6 @@
package eu.midnightdust.visualoverhaul.block.renderer;
import eu.midnightdust.visualoverhaul.VisualOverhaul;
import eu.midnightdust.visualoverhaul.VisualOverhaulClient;
import eu.midnightdust.visualoverhaul.config.VOConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.entity.BrewingStandBlockEntity;
@@ -26,7 +25,7 @@ public class BrewingStandBlockEntityRenderer extends BlockEntityRenderer<Brewing
@Override
public void render(BrewingStandBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
if (VisualOverhaulClient.VO_CONFIG.brewingstand) {
if (VOConfig.brewingstand) {
int lightAtBlock = WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos());
ItemStack item1 = blockEntity.getStack(0);
ItemStack item2 = blockEntity.getStack(1);

View File

@@ -0,0 +1,116 @@
package eu.midnightdust.visualoverhaul.block.renderer;
import eu.midnightdust.visualoverhaul.config.VOConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.*;
import net.minecraft.block.entity.FurnaceBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.WorldRenderer;
import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher;
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.item.ItemStack;
import net.minecraft.tag.ItemTags;
import net.minecraft.util.Identifier;
@Environment(EnvType.CLIENT)
public class FurnaceBlockEntityRenderer extends BlockEntityRenderer<FurnaceBlockEntity> {
private static final ModelPart bb_main;
private static final ModelPart cube_r1;
private static final ModelPart cube_r2;
private static final ModelPart cube_r3;
static {
bb_main = new ModelPart(16, 16, 0, 0);
bb_main.setPivot(0.0F, 24.0F, 0.0F);
cube_r1 = new ModelPart(16, 16, 0, 0);
cube_r1.setPivot(6.0F, 1.0F, -2.0F);
bb_main.addChild(cube_r1);
setRotationAngle(cube_r1, 0.0F, -0.5672F, 0.0F);
cube_r1.setTextureOffset(0, 0).addCuboid(-10.0F, -3.0F, 0.0F, 10.0F, 1.0F, 1.0F, 0.0F, false);
cube_r2 = new ModelPart(16, 16, 0, 0);
cube_r2.setPivot(5.0F, 0.0F, -5.0F);
bb_main.addChild(cube_r2);
setRotationAngle(cube_r2, 0.0F, -0.1309F, 0.0F);
cube_r2.setTextureOffset(0, 0).addCuboid(-10.0F, -2.5F, 0.0F, 10.0F, 2.0F, 2.0F, 0.0F, false);
cube_r3 = new ModelPart(16, 16, 0, 0);
cube_r3.setPivot(5.0F, -1.0F, -7.0F);
bb_main.addChild(cube_r3);
setRotationAngle(cube_r3, 0.0F, 0.2618F, 0.0F);
cube_r3.setTextureOffset(0, 0).addCuboid(-10.0F, -2.0F, 0.0F, 10.0F, 2.0F, 2.0F, 0.0F, false);
}
public static void setRotationAngle(ModelPart bone, float x, float y, float z) {
bone.pitch = x;
bone.yaw = y;
bone.roll = z;
}
public FurnaceBlockEntityRenderer(BlockEntityRenderDispatcher blockEntityRenderDispatcher) {
super(blockEntityRenderDispatcher);
}
@Override
public void render(FurnaceBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
if (VOConfig.furnace && blockEntity.getCachedState().getBlock().is(Blocks.FURNACE)) {
BlockState blockState = blockEntity.getCachedState();
int lightAtBlock = WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos().offset(blockState.get(AbstractFurnaceBlock.FACING)));
ItemStack item1 = blockEntity.getStack(0);
ItemStack item2 = blockEntity.getStack(1);
float angle = (blockState.get(AbstractFurnaceBlock.FACING)).asRotation();
matrices.push();
matrices.translate(0.5f, 0.58f, 0.5f);
matrices.scale(1f, 1f, 1f);
matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(angle * 3 + 180));
matrices.translate(0.0f, 0.0f, -0.4f);
matrices.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(90));
MinecraftClient.getInstance().getItemRenderer().renderItem(item1, ModelTransformation.Mode.GROUND, lightAtBlock, overlay, matrices, vertexConsumers);
matrices.pop();
if (!item2.getItem().isIn(ItemTags.LOGS_THAT_BURN) && !item2.getItem().isIn(ItemTags.PLANKS)) {
matrices.push();
matrices.translate(0.5f, 0.08f, 0.5f);
matrices.scale(1f, 1f, 1f);
matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(angle * 3 + 180));
matrices.translate(0.0f, 0.0f, -0.4f);
matrices.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(90));
MinecraftClient.getInstance().getItemRenderer().renderItem(item2, ModelTransformation.Mode.GROUND, lightAtBlock, overlay, matrices, vertexConsumers);
matrices.pop();
}
if (item2.getItem().isIn(ItemTags.LOGS_THAT_BURN) || item2.getItem().isIn(ItemTags.PLANKS)) {
matrices.push();
BlockState state = Block.getBlockFromItem(item2.getItem()).getDefaultState();
Sprite texture = MinecraftClient.getInstance().getBlockRenderManager().getModel(state).getSprite();
VertexConsumer vertexConsumer = vertexConsumers.getBuffer(RenderLayer.getEntityCutoutNoCull(spriteToTexture(texture)));
matrices.translate(0.5f, -1.3f, 0.5f);
matrices.scale(1f, 1f, 1f);
matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(angle * 3 + 180));
bb_main.render(matrices, vertexConsumer, lightAtBlock, overlay);
matrices.pop();
}
}
}
public static Identifier spriteToTexture(Sprite sprite) {
String texture = sprite.getId().getPath();
return new Identifier(sprite.getId().getNamespace(), "textures/" + texture + ".png");
}
}

View File

@@ -1,8 +1,11 @@
package eu.midnightdust.visualoverhaul.block.renderer;
import eu.midnightdust.visualoverhaul.VisualOverhaulClient;
import eu.midnightdust.visualoverhaul.config.VOConfig;
import eu.midnightdust.visualoverhaul.util.sound.SoundTest;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.JukeboxBlockEntity;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.RenderLayer;
@@ -15,11 +18,15 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.util.math.Vector3f;
import net.minecraft.item.ItemStack;
import net.minecraft.state.property.Properties;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import java.util.Random;
@Environment(EnvType.CLIENT)
public class JukeboxBlockEntityRenderer extends BlockEntityRenderer<JukeboxBlockEntity> {
private ItemStack record;
private Identifier discItem;
public JukeboxBlockEntityRenderer(BlockEntityRenderDispatcher blockEntityRenderDispatcher) {
super(blockEntityRenderDispatcher);
@@ -28,9 +35,28 @@ public class JukeboxBlockEntityRenderer extends BlockEntityRenderer<JukeboxBlock
@Override
public void render(JukeboxBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
if (VisualOverhaulClient.VO_CONFIG.jukebox) {
if (VOConfig.jukebox) {
int lightAbove = WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos().up());
ItemStack record = blockEntity.getRecord();
// Gets the record sound played at the position of the jukebox //
if (SoundTest.getSound(blockEntity.getPos()) != null) {
// Converts the Sound Id to the item id of the approprieate disc (minecraft:music_disc.cat -> minecraft:music_disc_cat) //
discItem = new Identifier(String.valueOf(SoundTest.getSound(blockEntity.getPos())).replace(".", "_"));
}
// If the sound is stopped or no sound is playing, the stack is set to an empty stack //
if (SoundTest.getSound(blockEntity.getPos()) == null) {
discItem = null;
record = ItemStack.EMPTY;
}
// Tries to get the disc item from the registry //
else if (Registry.ITEM.getOrEmpty(discItem).isPresent()) {
record = new ItemStack(Registry.ITEM.get(discItem));
}
// Fallback to serverside implementation if the id doesn't match an item //
else {
record = blockEntity.getRecord();
}
record.setCount(2);
matrices.push();
@@ -41,7 +67,7 @@ public class JukeboxBlockEntityRenderer extends BlockEntityRenderer<JukeboxBlock
MinecraftClient.getInstance().getItemRenderer().renderItem(record, ModelTransformation.Mode.GROUND, lightAbove, overlay, matrices, vertexConsumers);
matrices.pop();
if (VisualOverhaulClient.VO_CONFIG.jukebox_fake_block) {
if (VOConfig.jukebox_fake_block && blockEntity.getWorld().getBlockState(blockEntity.getPos().up()).getBlock() == Blocks.AIR) {
matrices.push();
matrices.translate(0f, 1f, 0f);
if (record == ItemStack.EMPTY) {

View File

@@ -0,0 +1,288 @@
package eu.midnightdust.visualoverhaul.config;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ScreenTexts;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TextFieldWidget;
import net.minecraft.client.resource.language.I18n;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.*;
import net.minecraft.util.Formatting;
import java.lang.annotation.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Pattern;
// MidnightConfig v0.1.0 //
/* Based on https://github.com/Minenash/TinyConfig
Credits to Minenash - CC0-1.0
You can copy this class to get a standalone version of MidnightConfig */
@SuppressWarnings("rawtypes")
public class MidnightConfig {
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
private static final List<EntryInfo> entries = new ArrayList<>();
protected static class EntryInfo {
Field field;
Object widget;
int width;
Method dynamicTooltip;
Map.Entry<TextFieldWidget,Text> error;
Object defaultValue;
Object value;
String tempValue;
boolean inLimits = true;
}
private static Class configClass;
private static String translationPrefix;
private static Path path;
private static final Gson gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.TRANSIENT)
.excludeFieldsWithModifiers(Modifier.PRIVATE)
.setPrettyPrinting()
.create();
public static void init(String modid, Class<?> config) {
translationPrefix = modid + ".midnightconfig.";
path = FabricLoader.getInstance().getConfigDir().resolve(modid + ".json");
configClass = config;
for (Field field : config.getFields()) {
Class<?> type = field.getType();
EntryInfo info = new EntryInfo();
Entry e;
try { e = field.getAnnotation(Entry.class); }
catch (Exception ignored) { continue; }
info.width = e.width();
info.field = field;
if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true);
else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(),false);
else if (type == String.class) textField(info, String::length, null, Math.min(e.min(),0), Math.max(e.max(),1),true);
else if (type == boolean.class) {
Function<Object,Text> func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED);
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object, Text>>(button -> {
info.value = !(Boolean) info.value;
button.setMessage(func.apply(info.value));
}, func);
}
else if (type.isEnum()) {
List<?> values = Arrays.asList(field.getType().getEnumConstants());
Function<Object,Text> func = value -> new TranslatableText(translationPrefix + "enum." + type.getSimpleName() + "." + info.value.toString());
info.widget = new AbstractMap.SimpleEntry<ButtonWidget.PressAction, Function<Object,Text>>( button -> {
int index = values.indexOf(info.value) + 1;
info.value = values.get(index >= values.size()? 0 : index);
button.setMessage(func.apply(info.value));
}, func);
}
else
continue;
entries.add(info);
try { info.defaultValue = field.get(null); }
catch (IllegalAccessException ignored) {}
try {
info.dynamicTooltip = config.getMethod(e.dynamicTooltip());
info.dynamicTooltip.setAccessible(true);
} catch (Exception ignored) {}
}
try { gson.fromJson(Files.newBufferedReader(path), config); }
catch (Exception e) { write(); }
for (EntryInfo info : entries) {
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
}
catch (IllegalAccessException ignored) {}
}
}
private static void textField(EntryInfo info, Function<String,Number> f, Pattern pattern, double min, double max, boolean cast) {
boolean isNumber = pattern != null;
info.widget = (BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) (t, b) -> s -> {
s = s.trim();
if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches()))
return false;
Number value = 0;
boolean inLimits = false;
System.out.println(((isNumber ^ s.isEmpty())));
System.out.println(!s.equals("-") && !s.equals("."));
info.error = null;
if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) {
value = f.apply(s);
inLimits = value.doubleValue() >= min && value.doubleValue() <= max;
info.error = inLimits? null : new AbstractMap.SimpleEntry<>(t, new LiteralText(value.doubleValue() < min ?
"§cMinimum " + (isNumber? "value" : "length") + (cast? " is " + (int)min : " is " + min) :
"§cMaximum " + (isNumber? "value" : "length") + (cast? " is " + (int)max : " is " + max)));
}
info.tempValue = s;
t.setEditableColor(inLimits? 0xFFFFFFFF : 0xFFFF7777);
info.inLimits = inLimits;
b.active = entries.stream().allMatch(e -> e.inLimits);
if (inLimits)
info.value = isNumber? value : s;
return true;
};
}
public static void write() {
try {
if (!Files.exists(path)) Files.createFile(path);
Files.write(path, gson.toJson(configClass.newInstance()).getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
public Screen getScreen(Screen parent) {
return new TinyConfigScreen(parent);
}
private static class TinyConfigScreen extends Screen {
protected TinyConfigScreen(Screen parent) {
super(new TranslatableText(MidnightConfig.translationPrefix + "title"));
this.parent = parent;
}
private final Screen parent;
// Real Time config update //
@Override
public void tick() {
for (EntryInfo info : entries)
try { info.field.set(null, info.value); }
catch (IllegalAccessException ignore) {}
}
@Override
protected void init() {
super.init();
this.addButton(new ButtonWidget(this.width / 2 - 154, this.height - 28, 150, 20, ScreenTexts.CANCEL, button -> {
try { gson.fromJson(Files.newBufferedReader(path), configClass); }
catch (Exception e) { write(); }
for (EntryInfo info : entries) {
try {
info.value = info.field.get(null);
info.tempValue = info.value.toString();
}
catch (IllegalAccessException ignored) {}
}
Objects.requireNonNull(client).openScreen(parent);
}));
ButtonWidget done = this.addButton(new ButtonWidget(this.width / 2 + 4, this.height - 28, 150, 20, ScreenTexts.DONE, (button) -> {
for (EntryInfo info : entries)
try { info.field.set(null, info.value); }
catch (IllegalAccessException ignore) {}
write();
Objects.requireNonNull(client).openScreen(parent);
}));
int y = 45;
for (EntryInfo info : entries) {
addButton(new ButtonWidget(width - 155, y, 40,20, new LiteralText("Reset").formatted(Formatting.RED), (button -> {
info.value = info.defaultValue;
info.tempValue = info.value.toString();
Objects.requireNonNull(client).openScreen(this);
})));
if (info.widget instanceof Map.Entry) {
Map.Entry<ButtonWidget.PressAction,Function<Object,Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget;
addButton(new ButtonWidget(width-110,y,info.width,20, widget.getValue().apply(info.value), widget.getKey()));
}
else {
TextFieldWidget widget = addButton(new TextFieldWidget(textRenderer, width-110, y, info.width, 20, null));
widget.setText(info.tempValue);
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget,done);
widget.setTextPredicate(processor);
children.add(widget);
}
y += 25;
}
}
int aniX = this.width / 2;
@Override
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
this.renderBackground(matrices);
if (aniX < this.width / 2) {
aniX = aniX +40;
}
int stringWidth = (int) (title.getString().length() * 2.75f);
this.fillGradient(matrices, this.width / 2 - stringWidth, 10, this.width /2 + stringWidth, 29, -1072689136, -804253680);
this.fillGradient(matrices, this.width / 2 - aniX, 35, width/2 + aniX, this.height - 40, -1072689136, -804253680);
super.render(matrices, mouseX, mouseY, delta);
drawCenteredText(matrices, textRenderer, title, width/2, 15, 0xFFFFFF);
int y = 40;
for (EntryInfo info : entries) {
drawTextWithShadow(matrices, textRenderer, new TranslatableText(translationPrefix + info.field.getName()), 12, y + 10, 0xFFFFFF);
if (info.error != null && info.error.getKey().isMouseOver(mouseX,mouseY))
renderTooltip(matrices, info.error.getValue(), mouseX, mouseY);
else if (mouseY >= y && mouseY < (y + 25)) {
if (info.dynamicTooltip != null) {
try {
renderTooltip(matrices, (List<Text>) info.dynamicTooltip.invoke(null, entries), mouseX, mouseY);
y += 25;
continue;
} catch (Exception e) { e.printStackTrace(); }
}
String key = translationPrefix + info.field.getName() + ".tooltip";
if (I18n.hasTranslation(key)) {
List<Text> list = new ArrayList<>();
for (String str : I18n.translate(key).split("\n"))
list.add(new LiteralText(str));
renderTooltip(matrices, list, mouseX, mouseY);
}
}
y += 25;
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Entry {
String dynamicTooltip() default "";
int width() default 100;
double min() default Double.MIN_NORMAL;
double max() default Double.MAX_VALUE;
}
}

View File

@@ -2,7 +2,6 @@ package eu.midnightdust.visualoverhaul.config;
import io.github.prospector.modmenu.api.ConfigScreenFactory;
import io.github.prospector.modmenu.api.ModMenuApi;
import me.sargunvohra.mcmods.autoconfig1u.AutoConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
@@ -11,6 +10,6 @@ public class ModMenuIntegration implements ModMenuApi {
@Override
public ConfigScreenFactory<?> getModConfigScreenFactory() {
return parent -> AutoConfig.getConfigScreen(VOConfig.class, parent).get();
return parent -> new VOConfig().getScreen(parent);
}
}

View File

@@ -1,16 +1,14 @@
package eu.midnightdust.visualoverhaul.config;
import me.sargunvohra.mcmods.autoconfig1u.ConfigData;
import me.sargunvohra.mcmods.autoconfig1u.annotation.Config;
import me.sargunvohra.mcmods.autoconfig1u.shadowed.blue.endless.jankson.Comment;
import java.util.ArrayList;
import java.util.List;
@Config(name = "visualoverhaul")
public class VOConfig implements ConfigData {
public boolean brewingstand = true;
public boolean jukebox = true;
public boolean jukebox_fake_block = true;
public class VOConfig extends MidnightConfig {
@Entry
public static boolean brewingstand = true;
@Entry
public static boolean jukebox = true;
@Entry
public static boolean jukebox_fake_block = true;
@Entry
public static boolean furnace = true;
@Entry
public static boolean coloredItems = true;
}

View File

@@ -0,0 +1,56 @@
package eu.midnightdust.visualoverhaul.mixin;
import eu.midnightdust.visualoverhaul.VisualOverhaul;
import io.netty.buffer.Unpooled;
import net.fabricmc.fabric.api.server.PlayerStream;
import net.fabricmc.fabric.impl.networking.ServerSidePacketRegistryImpl;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.collection.DefaultedList;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.stream.Stream;
@Mixin(AbstractFurnaceBlockEntity.class)
public abstract class MixinAbstractFurnaceBlockEntity extends LockableContainerBlockEntity {
@Shadow protected DefaultedList<ItemStack> inventory;
Boolean invUpdate = true;
int playerUpdate = -1;
private MixinAbstractFurnaceBlockEntity(BlockEntityType<?> blockEntityType) {
super(blockEntityType);
}
@Inject(at = @At("TAIL"), method = "tick")
public void tick(CallbackInfo ci) {
if (this.world.getBlockState(this.pos).getBlock().is(Blocks.FURNACE)) {
if (!this.world.isClient && (invUpdate || world.getPlayers().size() == playerUpdate)) {
Stream<PlayerEntity> watchingPlayers = PlayerStream.watching(world, getPos());
PacketByteBuf passedData = new PacketByteBuf(Unpooled.buffer());
passedData.writeBlockPos(pos);
passedData.writeItemStack(inventory.get(0));
passedData.writeItemStack(inventory.get(1));
passedData.writeItemStack(inventory.get(2));
passedData.writeString(String.valueOf(inventory));
watchingPlayers.forEach(player -> ServerSidePacketRegistryImpl.INSTANCE.sendToPlayer(player, VisualOverhaul.UPDATE_FURNACE_ITEMS, passedData));
invUpdate = false;
}
playerUpdate = world.getPlayers().size();
}
}
@Inject(at = @At("RETURN"), method = "getStack", cancellable = true)
public void getStack(int slot, CallbackInfoReturnable cir) {
this.invUpdate = true;
}
}

View File

@@ -23,25 +23,17 @@ import java.util.stream.Stream;
@Mixin(BrewingStandBlockEntity.class)
public abstract class MixinBrewingStandBlockEntity extends LockableContainerBlockEntity {
@Shadow private DefaultedList<ItemStack> inventory;
public ItemStack item1;
public ItemStack item2;
public ItemStack item3;
Boolean sendData = true;
Boolean invUpdate = true;
int playerUpdate = -1;
private MixinBrewingStandBlockEntity(BlockEntityType<?> blockEntityType) {
super(blockEntityType);
}
@Inject(at = @At("TAIL"), method = "tick")
public void tick(CallbackInfo ci) {
item1 = inventory.get(0);
item2 = inventory.get(1);
item3 = inventory.get(2);
if (!this.world.isClient) {
if (!this.world.isClient && (invUpdate || world.getPlayers().size() == playerUpdate)) {
Stream<PlayerEntity> watchingPlayers = PlayerStream.watching(world, getPos());
PacketByteBuf passedData = new PacketByteBuf(Unpooled.buffer());
passedData.writeBlockPos(pos);
@@ -53,12 +45,13 @@ public abstract class MixinBrewingStandBlockEntity extends LockableContainerBloc
passedData.writeString(String.valueOf(inventory));
watchingPlayers.forEach(player -> ServerSidePacketRegistryImpl.INSTANCE.sendToPlayer(player, VisualOverhaul.UPDATE_POTION_BOTTLES, passedData));
sendData = false;
invUpdate = false;
}
playerUpdate = world.getPlayers().size();
}
@Inject(at = @At("RETURN"), method = "getStack", cancellable = true)
public void getStack(int slot, CallbackInfoReturnable cir) {
this.sendData = true;
this.invUpdate = true;
}
}

View File

@@ -21,30 +21,30 @@ import java.util.stream.Stream;
@Mixin(JukeboxBlockEntity.class)
public abstract class MixinJukeboxBlockEntity extends BlockEntity implements Tickable {
@Shadow private ItemStack record;
Boolean sendData = true;
Boolean invUpdate = true;
int playerUpdate = -1;
private MixinJukeboxBlockEntity(BlockEntityType<?> blockEntityType) {
super(blockEntityType);
}
@Unique
public void tick() {
if (!this.world.isClient) {
if (!this.world.isClient && (invUpdate || world.getPlayers().size() == playerUpdate)) {
Stream<PlayerEntity> watchingPlayers = PlayerStream.watching(world, getPos());
PacketByteBuf passedData = new PacketByteBuf(Unpooled.buffer());
passedData.writeBlockPos(pos);
passedData.writeItemStack(record);
watchingPlayers.forEach(player -> ServerSidePacketRegistryImpl.INSTANCE.sendToPlayer(player, VisualOverhaul.UPDATE_RECORD, passedData));
sendData = false;
invUpdate = false;
}
playerUpdate = world.getPlayers().size();
}
@Inject(at = @At("RETURN"), method = "getRecord", cancellable = true)
public void getRecord(CallbackInfoReturnable cir) {
this.sendData = true;
this.invUpdate = true;
}
}

View File

@@ -0,0 +1,63 @@
package eu.midnightdust.visualoverhaul.mixin;
import eu.midnightdust.visualoverhaul.VisualOverhaul;
import net.minecraft.block.Blocks;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.profiler.Profiler;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.*;
import net.minecraft.world.chunk.WorldChunk;
import net.minecraft.world.dimension.DimensionType;
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 java.util.function.Supplier;
@Mixin(ServerWorld.class)
public abstract class MixinServerWorld extends World {
protected MixinServerWorld(MutableWorldProperties properties, RegistryKey<World> registryRef, DimensionType dimensionType, Supplier<Profiler> profiler, boolean isClient, boolean debugWorld, long seed) {
super(properties, registryRef, dimensionType, profiler, isClient, debugWorld, seed);
}
@Shadow protected abstract BlockPos getSurface(BlockPos pos);
@Inject(at = @At("TAIL"),method = "tickChunk")
public void tickChunk(WorldChunk chunk, int randomTickSpeed, CallbackInfo ci) {
ChunkPos chunkPos = chunk.getPos();
boolean bl = this.isRaining();
int x = chunkPos.getStartX();
int z = chunkPos.getStartZ();
Profiler profiler = this.getProfiler();
BlockPos pos;
if (this.getGameRules().getInt(VisualOverhaul.PUDDLE_SPAWN_RATE) != 0) {
profiler.push("puddles");
if (bl && random.nextInt(10000 / this.getGameRules().getInt(VisualOverhaul.PUDDLE_SPAWN_RATE)) == 0) {
pos = this.getSurface(getRandomPosInChunk(x, 0, z, 15));
if (this.hasRain(pos) && getBlockState(pos.down()).isSideSolidFullSquare(this, pos, Direction.UP)) {
setBlockState(pos, VisualOverhaul.Puddle.getDefaultState());
}
}
profiler.pop();
}
if (this.getGameRules().getInt(VisualOverhaul.SNOW_STACK_CHANCE) != 0) {
profiler.push("extra_snow");
if (bl && random.nextInt(10000 / this.getGameRules().getInt(VisualOverhaul.SNOW_STACK_CHANCE)) == 0) {
pos = this.getSurface(getRandomPosInChunk(x, 0, z, 15));
if (this.getBlockState(pos).getBlock() == Blocks.SNOW && getBlockState(pos.down()).isSideSolidFullSquare(this, pos, Direction.UP)) {
int layer = getBlockState(pos).get(Properties.LAYERS);
setBlockState(pos, Blocks.SNOW.getDefaultState().with(Properties.LAYERS, layer + 1));
}
}
profiler.pop();
}
}
}

View File

@@ -0,0 +1,36 @@
package eu.midnightdust.visualoverhaul.mixin;
import eu.midnightdust.visualoverhaul.util.sound.SoundTest;
import net.minecraft.client.sound.SoundInstance;
import net.minecraft.client.sound.SoundSystem;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.math.BlockPos;
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;
@Mixin(SoundSystem.class)
public abstract class MixinSoundSystem {
@Shadow private boolean started;
private BlockPos jukeboxPos;
@Inject(at = @At("TAIL"),method = "play(Lnet/minecraft/client/sound/SoundInstance;)V")
public void onPlayRecordSound(SoundInstance soundInstance, CallbackInfo ci) {
if (soundInstance.getCategory().equals(SoundCategory.RECORDS) && this.started) {
jukeboxPos = new BlockPos(soundInstance.getX(),soundInstance.getY(),soundInstance.getZ());
SoundTest.soundPos.put(jukeboxPos, soundInstance.getId());
}
}
@Inject(at = @At("TAIL"),method = "stop(Lnet/minecraft/client/sound/SoundInstance;)V")
public void onStopRecordSound(SoundInstance soundInstance, CallbackInfo ci) {
if (soundInstance.getCategory().equals(SoundCategory.RECORDS) && SoundTest.soundPos.containsKey(new BlockPos(soundInstance.getX(),soundInstance.getY(),soundInstance.getZ()))) {
jukeboxPos = new BlockPos(soundInstance.getX(),soundInstance.getY(),soundInstance.getZ());
SoundTest.soundPos.remove(jukeboxPos,soundInstance.getId());
}
}
}

View File

@@ -0,0 +1,23 @@
package eu.midnightdust.visualoverhaul.util.sound;
import com.google.common.collect.Maps;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
public class SoundTest {
public static Map<BlockPos, Identifier> soundPos = Maps.newHashMap();
/**
* Returns the Sound provided in MixinSoundSystem
* {@link eu.midnightdust.visualoverhaul.mixin.MixinSoundSystem}
*/
public static Identifier getSound(BlockPos pos) {
if (soundPos.containsKey(pos)) {
return soundPos.get(pos);
}
return null;
}
}

View File

@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "visualoverhaul:block/puddle"
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,10 @@
{
"visualoverhaul.midnightconfig.title":"Visual Overhaul Config",
"visualoverhaul.midnightconfig.brewingstand":"Enable Brewing Stand Enhancements",
"visualoverhaul.midnightconfig.jukebox":"Enable Jukebox Enhancements",
"visualoverhaul.midnightconfig.jukebox_fake_block":"Enable fake block on jukebox top",
"visualoverhaul.midnightconfig.furnace":"Enable Furnace Enhancements",
"visualoverhaul.midnightconfig.coloredItems":"Enable biome-based item colors",
"visualoverhaul.midnightconfig.coloredItems.tooltip":"Needs restart!",
"block.visualoverhaul.puddle":"Puddle"
}

View File

@@ -10,7 +10,7 @@
"elements": [
{
"from": [0, 0, 0],
"to": [16, 0.001, 16],
"to": [16, 0.01, 16],
"faces": {
"up": {"uv": [0, 0, 16, 16], "texture": "#3"}
}

View File

@@ -10,7 +10,7 @@
"elements": [
{
"from": [0, 0, 0],
"to": [16, 0.001, 16],
"to": [16, 0.01, 16],
"faces": {
"up": {"uv": [0, 0, 16, 16], "texture": "#3"}
}

View File

@@ -0,0 +1,7 @@
{
"credit": "made by Motschen",
"parent": "block/block",
"textures": {
"particle": "block/water_still"
}
}

View File

@@ -0,0 +1,22 @@
{
"credit": "made by Motschen",
"parent": "block/block",
"textures": {
"0": "block/water_still",
"particle": "block/water_still"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 1, 16],
"faces": {
"north": {"uv": [0, 0, 16, 1], "texture": "#0", "tintindex": 0},
"east": {"uv": [0, 0, 16, 1], "texture": "#0", "tintindex": 0},
"south": {"uv": [0, 0, 16, 1], "texture": "#0", "tintindex": 0},
"west": {"uv": [0, 0, 16, 1], "texture": "#0", "tintindex": 0},
"up": {"uv": [0, 0, 16, 16], "texture": "#0", "tintindex": 0},
"down": {"uv": [0, 0, 16, 16], "texture": "#0", "tintindex": 0}
}
}
]
}

View File

@@ -20,6 +20,9 @@
"environment": "*",
"entrypoints": {
"main": [
"eu.midnightdust.visualoverhaul.VisualOverhaul"
],
"client": [
"eu.midnightdust.visualoverhaul.VisualOverhaulClient"
],
@@ -33,6 +36,7 @@
],
"depends": {
"fabric": "*"
"fabric": ">=0.28.4",
"minecraft": "1.16.x"
}
}

View File

@@ -0,0 +1,7 @@
{
"parent": "item/generated",
"textures": {
"layer1": "item/water_bucket_overlay",
"layer0": "item/water_bucket"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

View File

@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 6,
"description": "Makes the water bucket also change it's color based on biome color"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

View File

@@ -0,0 +1,34 @@
{
"variants": {
"facing=east,lit=false": {
"model": "minecraft:block/furnace",
"y": 90
},
"facing=east,lit=true": {
"model": "minecraft:block/furnace_on",
"y": 90
},
"facing=north,lit=false": {
"model": "minecraft:block/furnace"
},
"facing=north,lit=true": {
"model": "minecraft:block/furnace_on"
},
"facing=south,lit=false": {
"model": "minecraft:block/furnace",
"y": 180
},
"facing=south,lit=true": {
"model": "minecraft:block/furnace_on",
"y": 180
},
"facing=west,lit=false": {
"model": "minecraft:block/furnace",
"y": 270
},
"facing=west,lit=true": {
"model": "minecraft:block/furnace_on",
"y": 270
}
}
}

View File

@@ -0,0 +1,14 @@
{
"defaultMap": {
"spriteMap": [
{
"sprite": "minecraft:block/furnace_front_on",
"material": "canvas:warm_glow"
},
{
"sprite": "minecraft:block/campfire_fire",
"material": "canvas:warm_glow"
}
]
}
}

View File

@@ -0,0 +1,148 @@
{
"credit": "made by Motschen",
"parent": "block/block",
"textures": {
"0": "block/furnace_front",
"1": "block/furnace_side",
"2": "block/furnace_top",
"3": "block/smooth_stone",
"4": "block/furnace_front",
"5": "block/campfire_fire",
"particle": "block/furnace_front"
},
"elements": [
{
"from": [0, 0, 6],
"to": [16, 16, 16],
"faces": {
"north": {"uv": [0, 0, 16, 16], "texture": "#4"},
"east": {"uv": [0, 0, 10, 16], "texture": "#1"},
"south": {"uv": [0, 0, 16, 16], "texture": "#1"},
"west": {"uv": [6, 0, 16, 16], "texture": "#1"},
"up": {"uv": [0, 6, 16, 16], "texture": "#2"},
"down": {"uv": [0, 0, 16, 10], "texture": "#3"}
}
},
{
"from": [13, 0, 0],
"to": [16, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, -2]},
"faces": {
"north": {"uv": [0, 0, 3, 16], "texture": "#0"},
"east": {"uv": [10, 0, 16, 16], "texture": "#1"},
"west": {"uv": [0, 0, 6, 16], "texture": "#1"},
"up": {"uv": [13, 0, 16, 6], "texture": "#2"},
"down": {"uv": [13, 10, 16, 16], "texture": "#3"}
}
},
{
"from": [12, 11, 0],
"to": [13, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 8, -2]},
"faces": {
"north": {"uv": [3, 0, 4, 5], "texture": "#0"},
"west": {"uv": [1, 9, 7, 14], "texture": "#1"},
"up": {"uv": [12, 0, 13, 6], "texture": "#2"},
"down": {"uv": [12, 10, 13, 16], "texture": "#3"}
}
},
{
"from": [3, 11, 0],
"to": [4, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, -2]},
"faces": {
"north": {"uv": [3, 0, 4, 5], "texture": "#0"},
"east": {"uv": [1, 9, 7, 14], "texture": "#1"},
"west": {"uv": [1, 8, 7, 13], "texture": "#1"},
"up": {"uv": [12, 0, 13, 6], "texture": "#2"},
"down": {"uv": [3, 10, 4, 16], "texture": "#3"}
}
},
{
"from": [4, 12, 0],
"to": [12, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [3, 8, -2]},
"faces": {
"north": {"uv": [4, 0, 12, 4], "texture": "#0"},
"up": {"uv": [4, 0, 12, 6], "texture": "#2"},
"down": {"uv": [4, 10, 12, 16], "texture": "#3"}
}
},
{
"from": [0, 0, 0],
"to": [3, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-5, 8, -2]},
"faces": {
"north": {"uv": [13, 0, 16, 16], "texture": "#0"},
"east": {"uv": [10, 0, 16, 16], "texture": "#1"},
"west": {"uv": [0, 0, 6, 16], "texture": "#1"},
"up": {"uv": [0, 0, 3, 6], "texture": "#2"},
"down": {"uv": [0, 10, 3, 16], "texture": "#3"}
}
},
{
"from": [12, 3, 0],
"to": [13, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 8, -2]},
"faces": {
"north": {"uv": [3, 7, 4, 13], "texture": "#0"},
"west": {"uv": [1, 8, 7, 14], "texture": "#1"},
"up": {"uv": [3, 0, 4, 6], "texture": "#2"},
"down": {"uv": [3, 10, 4, 16], "texture": "#3"}
}
},
{
"from": [3, 3, 0],
"to": [4, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, -2]},
"faces": {
"north": {"uv": [12, 7, 13, 13], "texture": "#0"},
"east": {"uv": [9, 8, 15, 14], "texture": "#1"},
"up": {"uv": [12, 0, 13, 6], "texture": "#2"},
"down": {"uv": [12, 10, 13, 16], "texture": "#3"}
}
},
{
"from": [11, 4, 0],
"to": [12, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [4, 8, -2]},
"faces": {
"north": {"uv": [4, 7, 5, 12], "texture": "#0"},
"west": {"uv": [1, 9, 7, 14], "texture": "#1"},
"up": {"uv": [4, 0, 5, 6], "texture": "#2"},
"down": {"uv": [4, 10, 5, 16], "texture": "#3"}
}
},
{
"from": [4, 4, 0],
"to": [5, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-3, 8, -2]},
"faces": {
"north": {"uv": [11, 7, 12, 12], "texture": "#0"},
"east": {"uv": [10, 9, 16, 14], "texture": "#1"},
"up": {"uv": [11, 0, 12, 6], "texture": "#2"},
"down": {"uv": [11, 10, 12, 16], "texture": "#3"}
}
},
{
"from": [5, 5, 0],
"to": [11, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [3, 8, -2]},
"faces": {
"north": {"uv": [5, 7, 11, 11], "texture": "#0"},
"up": {"uv": [5, 0, 11, 6], "texture": "#2"},
"down": {"uv": [5, 10, 11, 16], "texture": "#3"}
}
},
{
"from": [3, 0, 0],
"to": [13, 1, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 5, -2]},
"faces": {
"north": {"uv": [3, 15, 13, 16], "texture": "#0"},
"up": {"uv": [3, 0, 13, 6], "texture": "#2"},
"down": {"uv": [3, 10, 13, 16], "texture": "#3"}
}
}
]
}

View File

@@ -0,0 +1,156 @@
{
"credit": "made by Motschen",
"parent": "block/block",
"textures": {
"0": "block/furnace_front",
"1": "block/furnace_side",
"2": "block/furnace_top",
"3": "block/smooth_stone",
"4": "block/furnace_front_on",
"5": "block/campfire_fire",
"particle": "block/furnace_front"
},
"elements": [
{
"from": [0, 0, 6],
"to": [16, 16, 16],
"faces": {
"north": {"uv": [0, 0, 16, 16], "texture": "#4"},
"east": {"uv": [0, 0, 10, 16], "texture": "#1"},
"south": {"uv": [0, 0, 16, 16], "texture": "#1"},
"west": {"uv": [6, 0, 16, 16], "texture": "#1"},
"up": {"uv": [0, 6, 16, 16], "texture": "#2"},
"down": {"uv": [0, 0, 16, 10], "texture": "#3"}
}
},
{
"from": [13, 0, 0],
"to": [16, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, -2]},
"faces": {
"north": {"uv": [0, 0, 3, 16], "texture": "#0"},
"east": {"uv": [10, 0, 16, 16], "texture": "#1"},
"west": {"uv": [0, 0, 6, 16], "texture": "#1"},
"up": {"uv": [13, 0, 16, 6], "texture": "#2"},
"down": {"uv": [13, 10, 16, 16], "texture": "#3"}
}
},
{
"from": [12, 11, 0],
"to": [13, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 8, -2]},
"faces": {
"north": {"uv": [3, 0, 4, 5], "texture": "#0"},
"west": {"uv": [1, 9, 7, 14], "texture": "#1"},
"up": {"uv": [12, 0, 13, 6], "texture": "#2"},
"down": {"uv": [12, 10, 13, 16], "texture": "#3"}
}
},
{
"from": [3, 11, 0],
"to": [4, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, -2]},
"faces": {
"north": {"uv": [3, 0, 4, 5], "texture": "#0"},
"east": {"uv": [1, 9, 7, 14], "texture": "#1"},
"west": {"uv": [1, 8, 7, 13], "texture": "#1"},
"up": {"uv": [12, 0, 13, 6], "texture": "#2"},
"down": {"uv": [3, 10, 4, 16], "texture": "#3"}
}
},
{
"from": [4, 12, 0],
"to": [12, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [3, 8, -2]},
"faces": {
"north": {"uv": [4, 0, 12, 4], "texture": "#0"},
"up": {"uv": [4, 0, 12, 6], "texture": "#2"},
"down": {"uv": [4, 10, 12, 16], "texture": "#3"}
}
},
{
"from": [0, 0, 0],
"to": [3, 16, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-5, 8, -2]},
"faces": {
"north": {"uv": [13, 0, 16, 16], "texture": "#0"},
"east": {"uv": [10, 0, 16, 16], "texture": "#1"},
"west": {"uv": [0, 0, 6, 16], "texture": "#1"},
"up": {"uv": [0, 0, 3, 6], "texture": "#2"},
"down": {"uv": [0, 10, 3, 16], "texture": "#3"}
}
},
{
"from": [12, 3, 0],
"to": [13, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 8, -2]},
"faces": {
"north": {"uv": [3, 7, 4, 13], "texture": "#0"},
"west": {"uv": [1, 8, 7, 14], "texture": "#1"},
"up": {"uv": [3, 0, 4, 6], "texture": "#2"},
"down": {"uv": [3, 10, 4, 16], "texture": "#3"}
}
},
{
"from": [3, 3, 0],
"to": [4, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-4, 8, -2]},
"faces": {
"north": {"uv": [12, 7, 13, 13], "texture": "#0"},
"east": {"uv": [9, 8, 15, 14], "texture": "#1"},
"up": {"uv": [12, 0, 13, 6], "texture": "#2"},
"down": {"uv": [12, 10, 13, 16], "texture": "#3"}
}
},
{
"from": [11, 4, 0],
"to": [12, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [4, 8, -2]},
"faces": {
"north": {"uv": [4, 7, 5, 12], "texture": "#0"},
"west": {"uv": [1, 9, 7, 14], "texture": "#1"},
"up": {"uv": [4, 0, 5, 6], "texture": "#2"},
"down": {"uv": [4, 10, 5, 16], "texture": "#3"}
}
},
{
"from": [4, 4, 0],
"to": [5, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [-3, 8, -2]},
"faces": {
"north": {"uv": [11, 7, 12, 12], "texture": "#0"},
"east": {"uv": [10, 9, 16, 14], "texture": "#1"},
"up": {"uv": [11, 0, 12, 6], "texture": "#2"},
"down": {"uv": [11, 10, 12, 16], "texture": "#3"}
}
},
{
"from": [5, 5, 0],
"to": [11, 9, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [3, 8, -2]},
"faces": {
"north": {"uv": [5, 7, 11, 11], "texture": "#0"},
"up": {"uv": [5, 0, 11, 6], "texture": "#2"},
"down": {"uv": [5, 10, 11, 16], "texture": "#3"}
}
},
{
"from": [3, 0, 0],
"to": [13, 1, 6],
"rotation": {"angle": 0, "axis": "y", "origin": [5, 5, -2]},
"faces": {
"north": {"uv": [3, 15, 13, 16], "texture": "#0"},
"up": {"uv": [3, 0, 13, 6], "texture": "#2"},
"down": {"uv": [3, 10, 13, 16], "texture": "#3"}
}
},
{
"from": [4, 1, 2],
"to": [12, 3, 2],
"rotation": {"angle": 0, "axis": "y", "origin": [14, 9, 10]},
"faces": {
"north": {"uv": [4, 0, 12, 2], "texture": "#5"}
}
}
]
}

View File

@@ -0,0 +1,6 @@
{
"pack": {
"pack_format": 6,
"description": "§2Changes the model of the furnace to be 3D"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 710 B

After

Width:  |  Height:  |  Size: 710 B

View File

@@ -4,7 +4,12 @@
"compatibilityLevel": "JAVA_8",
"mixins": [
"MixinBrewingStandBlockEntity",
"MixinJukeboxBlockEntity"
"MixinJukeboxBlockEntity",
"MixinAbstractFurnaceBlockEntity",
"MixinServerWorld"
],
"client": [
"MixinSoundSystem"
],
"injectors": {
"defaultRequire": 1