diff --git a/build.gradle b/build.gradle index 3e048de..b183ec9 100644 --- a/build.gradle +++ b/build.gradle @@ -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" } diff --git a/gradle.properties b/gradle.properties index a60a31b..af0639b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G loader_version=0.11.1 # Mod Properties - mod_version = 2.0.1 + mod_version = 3.0.0 maven_group = eu.midnightdust archives_base_name = visualoverhaul @@ -16,6 +16,4 @@ org.gradle.jvmargs=-Xmx1G # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api 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 \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaul.java b/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaul.java index c0649b3..571a069 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaul.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaul.java @@ -1,9 +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 PUDDLE_SPAWN_RATE; + public static GameRules.Key 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())); + } } diff --git a/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaulClient.java b/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaulClient.java index f30d510..f349eb2 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaulClient.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/VisualOverhaulClient.java @@ -5,13 +5,14 @@ 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; @@ -23,23 +24,30 @@ 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 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); @@ -58,7 +66,6 @@ public void onInitializeClient() { } }); - ClientSidePacketRegistryImpl.INSTANCE.register(UPDATE_POTION_BOTTLES, (packetContext, attachedData) -> { BlockPos pos = attachedData.readBlockPos(); @@ -67,12 +74,14 @@ public void onInitializeClient() { 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, @@ -80,8 +89,10 @@ public void onInitializeClient() { BlockPos pos = attachedData.readBlockPos(); ItemStack record = attachedData.readItemStack(); packetContext.getTaskQueue().execute(() -> { - JukeboxBlockEntity blockEntity = (JukeboxBlockEntity)MinecraftClient.getInstance().world.getBlockEntity(pos); - blockEntity.setRecord(record); + 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, @@ -92,16 +103,54 @@ public void onInitializeClient() { inv.set(i, attachedData.readItemStack()); } packetContext.getTaskQueue().execute(() -> { - FurnaceBlockEntity blockEntity = (FurnaceBlockEntity)MinecraftClient.getInstance().world.getBlockEntity(pos); - blockEntity.setStack(0,inv.get(0)); - blockEntity.setStack(1,inv.get(1)); - blockEntity.setStack(2,inv.get(2)); + 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/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); } } diff --git a/src/main/java/eu/midnightdust/visualoverhaul/block/PuddleBlock.java b/src/main/java/eu/midnightdust/visualoverhaul/block/PuddleBlock.java new file mode 100644 index 0000000..3a063b1 --- /dev/null +++ b/src/main/java/eu/midnightdust/visualoverhaul/block/PuddleBlock.java @@ -0,0 +1,134 @@ +package eu.midnightdust.visualoverhaul.block; + +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.BlockSoundGroup; +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; + +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 getDroppedStacks(BlockState state, LootContext.Builder builder) { + return Collections.emptyList(); + } + + public boolean canPlaceAt(BlockState state, WorldView world, BlockPos pos) { + return world.getBlockState(pos.down()).isSideSolidFullSquare(world,pos,Direction.UP); + } + 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); + } +} + diff --git a/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/BrewingStandBlockEntityRenderer.java b/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/BrewingStandBlockEntityRenderer.java index 26fe784..4b03b40 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/BrewingStandBlockEntityRenderer.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/BrewingStandBlockEntityRenderer.java @@ -1,6 +1,6 @@ package eu.midnightdust.visualoverhaul.block.renderer; -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; @@ -25,7 +25,7 @@ public BrewingStandBlockEntityRenderer(BlockEntityRenderDispatcher blockEntityRe @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); diff --git a/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/FurnaceBlockEntityRenderer.java b/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/FurnaceBlockEntityRenderer.java index e956034..355d6df 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/FurnaceBlockEntityRenderer.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/FurnaceBlockEntityRenderer.java @@ -1,6 +1,6 @@ package eu.midnightdust.visualoverhaul.block.renderer; -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.*; @@ -62,7 +62,7 @@ public FurnaceBlockEntityRenderer(BlockEntityRenderDispatcher blockEntityRenderD @Override public void render(FurnaceBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) { - if (VisualOverhaulClient.VO_CONFIG.furnace && blockEntity.getCachedState().getBlock().is(Blocks.FURNACE)) { + 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); diff --git a/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/JukeboxBlockEntityRenderer.java b/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/JukeboxBlockEntityRenderer.java index 7ee25e5..fb0314b 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/JukeboxBlockEntityRenderer.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/block/renderer/JukeboxBlockEntityRenderer.java @@ -1,6 +1,7 @@ package eu.midnightdust.visualoverhaul.block.renderer; 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.JukeboxBlockEntity; @@ -28,7 +29,7 @@ public JukeboxBlockEntityRenderer(BlockEntityRenderDispatcher blockEntityRenderD @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(); record.setCount(2); @@ -41,7 +42,7 @@ public void render(JukeboxBlockEntity blockEntity, float tickDelta, MatrixStack 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) { matrices.push(); matrices.translate(0f, 1f, 0f); if (record == ItemStack.EMPTY) { diff --git a/src/main/java/eu/midnightdust/visualoverhaul/config/MidnightConfig.java b/src/main/java/eu/midnightdust/visualoverhaul/config/MidnightConfig.java new file mode 100644 index 0000000..1028f9a --- /dev/null +++ b/src/main/java/eu/midnightdust/visualoverhaul/config/MidnightConfig.java @@ -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 entries = new ArrayList<>(); + + protected static class EntryInfo { + Field field; + Object widget; + int width; + Method dynamicTooltip; + Map.Entry 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 func = value -> new LiteralText((Boolean) value ? "True" : "False").formatted((Boolean) value ? Formatting.GREEN : Formatting.RED); + info.widget = new AbstractMap.SimpleEntry>(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 func = value -> new TranslatableText(translationPrefix + "enum." + type.getSimpleName() + "." + info.value.toString()); + info.widget = new AbstractMap.SimpleEntry>( 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 f, Pattern pattern, double min, double max, boolean cast) { + boolean isNumber = pattern != null; + info.widget = (BiFunction>) (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> widget = (Map.Entry>) 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 processor = ((BiFunction>) 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) 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 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; + } +} \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/visualoverhaul/config/ModMenuIntegration.java b/src/main/java/eu/midnightdust/visualoverhaul/config/ModMenuIntegration.java index 37094f4..2f88b11 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/config/ModMenuIntegration.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/config/ModMenuIntegration.java @@ -2,7 +2,6 @@ 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); } } \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/visualoverhaul/config/VOConfig.java b/src/main/java/eu/midnightdust/visualoverhaul/config/VOConfig.java index 0650b57..c532cea 100644 --- a/src/main/java/eu/midnightdust/visualoverhaul/config/VOConfig.java +++ b/src/main/java/eu/midnightdust/visualoverhaul/config/VOConfig.java @@ -1,13 +1,14 @@ package eu.midnightdust.visualoverhaul.config; -import me.sargunvohra.mcmods.autoconfig1u.ConfigData; -import me.sargunvohra.mcmods.autoconfig1u.annotation.Config; - -@Config(name = "visualoverhaul") -public class VOConfig implements ConfigData { - - public boolean brewingstand = true; - public boolean jukebox = true; - public boolean jukebox_fake_block = true; - public boolean furnace = 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; } diff --git a/src/main/java/eu/midnightdust/visualoverhaul/mixin/MixinServerWorld.java b/src/main/java/eu/midnightdust/visualoverhaul/mixin/MixinServerWorld.java new file mode 100644 index 0000000..bcbc6a8 --- /dev/null +++ b/src/main/java/eu/midnightdust/visualoverhaul/mixin/MixinServerWorld.java @@ -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 registryRef, DimensionType dimensionType, Supplier 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(); + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/visualoverhaul/blockstates/puddle.json b/src/main/resources/assets/visualoverhaul/blockstates/puddle.json new file mode 100644 index 0000000..1e87399 --- /dev/null +++ b/src/main/resources/assets/visualoverhaul/blockstates/puddle.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "visualoverhaul:block/puddle" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/visualoverhaul/lang/en_us.json b/src/main/resources/assets/visualoverhaul/lang/en_us.json index 902e3d3..8075cd2 100644 --- a/src/main/resources/assets/visualoverhaul/lang/en_us.json +++ b/src/main/resources/assets/visualoverhaul/lang/en_us.json @@ -1,7 +1,10 @@ { - "text.autoconfig.visualoverhaul.title":"Visual Overhaul Config", - "text.autoconfig.visualoverhaul.option.brewingstand":"Enable Brewing Stand Enhancements", - "text.autoconfig.visualoverhaul.option.jukebox":"Enable Jukebox Enhancements", - "text.autoconfig.visualoverhaul.option.jukebox_fake_block":"Enable fake block on jukebox top", - "text.autoconfig.visualoverhaul.option.furnace":"Enable Furnace Enhancements" + "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" } \ No newline at end of file diff --git a/src/main/resources/assets/visualoverhaul/models/block/puddle.json b/src/main/resources/assets/visualoverhaul/models/block/puddle.json new file mode 100644 index 0000000..2df7f06 --- /dev/null +++ b/src/main/resources/assets/visualoverhaul/models/block/puddle.json @@ -0,0 +1,7 @@ +{ + "credit": "made by Motschen", + "parent": "block/block", + "textures": { + "particle": "block/water_still" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/visualoverhaul/models/item/puddle.json b/src/main/resources/assets/visualoverhaul/models/item/puddle.json new file mode 100644 index 0000000..ad258f4 --- /dev/null +++ b/src/main/resources/assets/visualoverhaul/models/item/puddle.json @@ -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} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 3b76d1a..cfc1f63 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -20,6 +20,9 @@ "environment": "*", "entrypoints": { + "main": [ + "eu.midnightdust.visualoverhaul.VisualOverhaul" + ], "client": [ "eu.midnightdust.visualoverhaul.VisualOverhaulClient" ], @@ -34,7 +37,6 @@ "depends": { "fabric": ">=0.28.4", - "autoconfig1u": "*", - "cloth-config2": "*" + "minecraft": "1.16.x" } } diff --git a/src/main/resources/resourcepacks/coloredwaterbucket/assets/minecraft/models/item/water_bucket.json b/src/main/resources/resourcepacks/coloredwaterbucket/assets/minecraft/models/item/water_bucket.json new file mode 100644 index 0000000..5bc648c --- /dev/null +++ b/src/main/resources/resourcepacks/coloredwaterbucket/assets/minecraft/models/item/water_bucket.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer1": "item/water_bucket_overlay", + "layer0": "item/water_bucket" + } +} diff --git a/src/main/resources/resourcepacks/coloredwaterbucket/assets/minecraft/textures/item/water_bucket_overlay.png b/src/main/resources/resourcepacks/coloredwaterbucket/assets/minecraft/textures/item/water_bucket_overlay.png new file mode 100644 index 0000000..0acab27 Binary files /dev/null and b/src/main/resources/resourcepacks/coloredwaterbucket/assets/minecraft/textures/item/water_bucket_overlay.png differ diff --git a/src/main/resources/resourcepacks/coloredwaterbucket/pack.mcmeta b/src/main/resources/resourcepacks/coloredwaterbucket/pack.mcmeta new file mode 100644 index 0000000..9a5d970 --- /dev/null +++ b/src/main/resources/resourcepacks/coloredwaterbucket/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 6, + "description": "Makes the water bucket also change it's color based on biome color" + } +} diff --git a/src/main/resources/resourcepacks/coloredwaterbucket/pack.png b/src/main/resources/resourcepacks/coloredwaterbucket/pack.png new file mode 100644 index 0000000..1cc7cc2 Binary files /dev/null and b/src/main/resources/resourcepacks/coloredwaterbucket/pack.png differ diff --git a/src/main/resources/visualoverhaul.mixins.json b/src/main/resources/visualoverhaul.mixins.json index aac6a60..aa0110b 100644 --- a/src/main/resources/visualoverhaul.mixins.json +++ b/src/main/resources/visualoverhaul.mixins.json @@ -5,7 +5,8 @@ "mixins": [ "MixinBrewingStandBlockEntity", "MixinJukeboxBlockEntity", - "MixinAbstractFurnaceBlockEntity" + "MixinAbstractFurnaceBlockEntity", + "MixinServerWorld" ], "injectors": { "defaultRequire": 1