diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1fc365f..2ca3795 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,17 +15,18 @@ jobs: 17, # Current Java LTS & minimum supported by Minecraft ] # and run on both Linux and Windows - os: [ubuntu-20.04, windows-2022] + os: [ubuntu-22.04, windows-2022] runs-on: ${{ matrix.os }} steps: - name: checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: validate gradle wrapper uses: gradle/wrapper-validation-action@v1 - name: setup jdk ${{ matrix.java }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: java-version: ${{ matrix.java }} + distribution: 'microsoft' - name: make gradle wrapper executable if: ${{ runner.os != 'Windows' }} run: chmod +x ./gradlew @@ -33,7 +34,7 @@ jobs: run: ./gradlew build - name: capture build artifacts if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Artifacts - path: build/libs/ + path: build/libs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore index 09cd281..c476faf 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,10 @@ bin/ # fabric run/ + +# java + +hs_err_*.log +replay_*.log +*.hprof +*.jfr diff --git a/LICENSE.txt b/LICENSE.txt index a235843..8589bd3 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2017-2021 Domi and contributors +Copyright (c) 2017-2023 Domi and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/build.gradle b/build.gradle index f2d5db1..3cb4142 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,22 @@ plugins { - id 'fabric-loom' version '0.10-SNAPSHOT' + id 'fabric-loom' version '1.2-SNAPSHOT' id 'maven-publish' } -sourceCompatibility = JavaVersion.VERSION_17 -targetCompatibility = JavaVersion.VERSION_17 - -archivesBaseName = project.archives_base_name version = project.mod_version group = project.maven_group +base { + archivesName = project.archives_base_name +} + repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. + maven { + url = "https://maven.terraformersmc.com/releases/" + content { + includeGroup "com.terraformersmc" + } + } } dependencies { @@ -26,6 +27,11 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}" + + include modApi("teamreborn:energy:${project.reborn_energy_version}") + modRuntimeOnly "TechReborn:TechReborn-1.20:${project.tech_reborn_version}", { exclude(group: "me.shedaniel") } } processResources { @@ -37,21 +43,16 @@ processResources { } tasks.withType(JavaCompile).configureEach { - // Minecraft 1.18 (1.18-pre2) upwards uses Java 17. it.options.release = 17 } java { - // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task - // if it is present. - // If you remove this line, sources will not be generated. - withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } jar { - from("LICENSE") { - rename { "${it}_${project.archivesBaseName}"} - } + from "LICENSE.txt" } // configure the maven publication @@ -69,4 +70,4 @@ publishing { // The repositories here will be used for publishing your artifact, not for // retrieving dependencies. } -} +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index d87a4a4..fa54994 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,16 +1,21 @@ # Done to increase the memory available to gradle. org.gradle.jvmargs=-Xmx1G +org.gradle.parallel=true # Fabric Properties - # check these on https://fabricmc.net/versions.html - minecraft_version=1.18 - yarn_mappings=1.18+build.1 - loader_version=0.12.6 +# check these on https://fabricmc.net/develop +minecraft_version=1.20.1 +yarn_mappings=1.20.1+build.1 +loader_version=0.14.21 # Mod Properties - mod_version = 7.2+1.18 - maven_group = re.domi - archives_base_name = invisiblights-fabric +mod_version=7.3+1.20 +maven_group=re.domi +archives_base_name=invisiblights # Dependencies - fabric_version=0.43.1+1.18 +fabric_version=0.83.0+1.20.1 + +mod_menu_version=7.1.0 +reborn_energy_version=3.0.0 +tech_reborn_version=5.8.3 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180..c1962a7 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102..37aef8d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787..aeb74cb 100644 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -143,12 +140,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in @@ -205,6 +210,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd3..93e3f59 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle index b02216b..56266b4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -7,4 +7,4 @@ pluginManagement { mavenCentral() gradlePluginPortal() } -} +} \ No newline at end of file diff --git a/src/main/java/re/domi/invisiblights/InvisibLights.java b/src/main/java/re/domi/invisiblights/InvisibLights.java index 31780f5..bcf1331 100644 --- a/src/main/java/re/domi/invisiblights/InvisibLights.java +++ b/src/main/java/re/domi/invisiblights/InvisibLights.java @@ -1,20 +1,45 @@ package re.domi.invisiblights; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.minecraft.block.Block; import net.minecraft.item.Item; +import net.minecraft.item.ItemGroups; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.state.property.BooleanProperty; import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; +import re.domi.invisiblights.config.Config; @SuppressWarnings("WeakerAccess") public class InvisibLights implements ModInitializer { - public static final int GLOWSTONE_COST = 2; + public static BooleanProperty FROM_POWERED_ROD = BooleanProperty.of("from_powered_rod"); public static Item LightRod; + public static PoweredLightRodItem PoweredLightRod; + public static Block LightSource; @Override public void onInitialize() { - LightRod = Registry.register(Registry.ITEM, new Identifier("invisiblights", "light_rod"), new LightRodItem()); + Config.read(); + + LightRod = Registry.register(Registries.ITEM, new Identifier("invisiblights", "light_rod"), new LightRodItem()); + PoweredLightRod = Registry.register(Registries.ITEM, new Identifier("invisiblights", "powered_light_rod"), new PoweredLightRodItem()); + + LightSource = Registry.register(Registries.BLOCK, new Identifier("invisiblights", "light_source"), new LightSourceBlock()); + + ItemGroupEvents.modifyEntriesEvent(ItemGroups.TOOLS).register(entries -> + { + entries.add(new ItemStack(LightRod)); + entries.add(new ItemStack(PoweredLightRod)); + + ItemStack fullyCharged = new ItemStack(PoweredLightRod); + PoweredLightRod.setStoredEnergy(fullyCharged, PoweredLightRod.getEnergyCapacity(fullyCharged)); + + entries.add(fullyCharged); + }); } } diff --git a/src/main/java/re/domi/invisiblights/InvisibLightsClient.java b/src/main/java/re/domi/invisiblights/InvisibLightsClient.java new file mode 100644 index 0000000..a9a8b8b --- /dev/null +++ b/src/main/java/re/domi/invisiblights/InvisibLightsClient.java @@ -0,0 +1,16 @@ +package re.domi.invisiblights; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; +import net.minecraft.client.render.RenderLayer; + +public class InvisibLightsClient implements ClientModInitializer +{ + public static boolean LightSourcesHidden = true; + + @Override + public void onInitializeClient() + { + BlockRenderLayerMap.INSTANCE.putBlock(InvisibLights.LightSource, RenderLayer.getTranslucent()); + } +} diff --git a/src/main/java/re/domi/invisiblights/LightRodItem.java b/src/main/java/re/domi/invisiblights/LightRodItem.java index 5dd1315..fef2995 100644 --- a/src/main/java/re/domi/invisiblights/LightRodItem.java +++ b/src/main/java/re/domi/invisiblights/LightRodItem.java @@ -1,7 +1,9 @@ package re.domi.invisiblights; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.*; @@ -9,18 +11,37 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.BlockSoundGroup; import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import re.domi.invisiblights.config.Config; @SuppressWarnings("WeakerAccess") public class LightRodItem extends Item { public LightRodItem() { - super(new Settings().group(ItemGroup.TOOLS).maxCount(1)); + super(new Settings().maxCount(1)); + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) + { + if (world.isClient && user.isSneaking()) + { + InvisibLightsClient.LightSourcesHidden = !InvisibLightsClient.LightSourcesHidden; + MinecraftClient.getInstance().worldRenderer.reload(); + + Vec3d pos = user.getPos(); + world.playSound(pos.x, pos.y, pos.z, SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.PLAYERS, 0.8F, InvisibLightsClient.LightSourcesHidden ? 0.9F : 1F, false); + } + + return new TypedActionResult<>(ActionResult.SUCCESS, user.getStackInHand(hand)); } @Override @@ -29,7 +50,7 @@ public ActionResult useOnBlock(ItemUsageContext context) World world = context.getWorld(); PlayerEntity player = context.getPlayer(); - if (world.isClient || player == null) + if (world.isClient || player == null || player.isSneaking()) { return ActionResult.PASS; } @@ -39,12 +60,14 @@ public ActionResult useOnBlock(ItemUsageContext context) Hand hand = context.getHand(); ItemStack heldItemStack = player.getStackInHand(hand); + Block preferredBlock = Config.PlaceVanillaLightSourceBlock ? Blocks.LIGHT : InvisibLights.LightSource; + if ((player.isCreative() || this.canAffordLightSource(player.getInventory(), heldItemStack)) - && player.canPlaceOn(newPos, side, heldItemStack) - && world.getBlockState(newPos).canReplace(new ItemPlacementContext(context)) - && world.getBlockState(newPos).getBlock() != Blocks.LIGHT) + && player.canPlaceOn(newPos, side, heldItemStack) + && world.getBlockState(newPos).canReplace(new ItemPlacementContext(context)) + && world.getBlockState(newPos).getBlock() != preferredBlock) { - BlockState state = this.getPlacementBlockState(Blocks.LIGHT.getPlacementState(new ItemPlacementContext(context) + BlockState state = this.getPlacementBlockState(preferredBlock.getPlacementState(new ItemPlacementContext(context) { private final BlockPos realPos = newPos; @@ -55,7 +78,7 @@ public BlockPos getBlockPos() } })); - if (world.setBlockState(newPos, state, 11)) + if (world.setBlockState(newPos, state, Block.REDRAW_ON_MAIN_THREAD | Block.NOTIFY_ALL)) { BlockSoundGroup soundGroup = state.getBlock().getSoundGroup(state); world.playSound(null, newPos, soundGroup.getPlaceSound(), SoundCategory.BLOCKS, (soundGroup.volume + 1F) / 2F, soundGroup.pitch * 0.8F); @@ -74,9 +97,13 @@ public BlockPos getBlockPos() return ActionResult.PASS; } - @SuppressWarnings("unused") public boolean canAffordLightSource(PlayerInventory inv, ItemStack heldItemStack) { + if (Config.LightSourceGlowstoneCost == 0) + { + return true; + } + int invCount = 0; for (ItemStack stack : inv.main) @@ -84,7 +111,7 @@ public boolean canAffordLightSource(PlayerInventory inv, ItemStack heldItemStack if (stack.getItem() == Items.GLOWSTONE_DUST) { invCount += stack.getCount(); - if (invCount >= InvisibLights.GLOWSTONE_COST) + if (invCount >= Config.LightSourceGlowstoneCost) { return true; } @@ -99,10 +126,9 @@ public BlockState getPlacementBlockState(BlockState original) return original; } - @SuppressWarnings("unused") public void postPlace(PlayerInventory inv, ItemStack heldItemStack) { - int remaining = InvisibLights.GLOWSTONE_COST; + int remaining = Config.LightSourceGlowstoneCost; for (int i = 0; i < inv.main.size(); i++) { diff --git a/src/main/java/re/domi/invisiblights/LightSourceBlock.java b/src/main/java/re/domi/invisiblights/LightSourceBlock.java new file mode 100644 index 0000000..e162237 --- /dev/null +++ b/src/main/java/re/domi/invisiblights/LightSourceBlock.java @@ -0,0 +1,100 @@ +package re.domi.invisiblights; + +import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings; +import net.minecraft.block.*; +import net.minecraft.fluid.FluidState; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.loot.context.LootContextParameterSet; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.Properties; +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.WorldAccess; +import re.domi.invisiblights.config.Config; + +import java.util.ArrayList; +import java.util.List; + +@SuppressWarnings("deprecation") +public class LightSourceBlock extends Block implements Waterloggable +{ + public LightSourceBlock() + { + super(FabricBlockSettings.of().hardness(0.2F).resistance(0.2F).luminance(15).replaceable().noCollision()); + this.setDefaultState(this.getStateManager().getDefaultState().with(InvisibLights.FROM_POWERED_ROD, false).with(Properties.WATERLOGGED, false)); + } + + @Override + public float getAmbientOcclusionLightLevel(BlockState state, BlockView world, BlockPos pos) + { + return 1.0F; + } + + @Override + public boolean isSideInvisible(BlockState state, BlockState stateFrom, Direction direction) + { + return InvisibLightsClient.LightSourcesHidden || stateFrom.getBlock() == this; + } + + @Override + public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) + { + return InvisibLightsClient.LightSourcesHidden || world instanceof ServerWorld ? VoxelShapes.empty() : VoxelShapes.fullCube(); + } + + @Override + public boolean isTransparent(BlockState state, BlockView world, BlockPos pos) + { + return !state.get(Properties.WATERLOGGED); + } + + @Override + public FluidState getFluidState(BlockState state) + { + return state.get(Properties.WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state); + } + + @Override + public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) + { + if (state.get(Properties.WATERLOGGED)) + { + world.scheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world)); + } + + return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos); + } + + @Override + public List getDroppedStacks(BlockState state, LootContextParameterSet.Builder builder) + { + List drops = new ArrayList<>(1); + + if (!state.get(InvisibLights.FROM_POWERED_ROD) && Config.LightSourceGlowstoneCost > 0) + { + drops.add(new ItemStack(Items.GLOWSTONE_DUST, Config.LightSourceGlowstoneCost)); + } + + return drops; + } + + @SuppressWarnings("ConstantConditions") + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) + { + return super.getPlacementState(ctx).with(Properties.WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER); + } + + @Override + protected void appendProperties(StateManager.Builder builder) + { + builder.add(InvisibLights.FROM_POWERED_ROD, Properties.WATERLOGGED); + } +} diff --git a/src/main/java/re/domi/invisiblights/PoweredLightRodItem.java b/src/main/java/re/domi/invisiblights/PoweredLightRodItem.java new file mode 100644 index 0000000..a0931ff --- /dev/null +++ b/src/main/java/re/domi/invisiblights/PoweredLightRodItem.java @@ -0,0 +1,88 @@ +package re.domi.invisiblights; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.ColorHelper; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import re.domi.invisiblights.config.Config; +import team.reborn.energy.api.base.SimpleEnergyItem; + +import java.util.List; + +public class PoweredLightRodItem extends LightRodItem implements SimpleEnergyItem +{ + @Override + public boolean canAffordLightSource(PlayerInventory inv, ItemStack heldItemStack) + { + return this.getStoredEnergy(heldItemStack) >= Config.PoweredLightSourceCost; + } + + @Override + public BlockState getPlacementBlockState(BlockState original) + { + if (original.getBlock() == Blocks.LIGHT) + { + original = InvisibLights.LightSource.getStateWithProperties(original); + } + + return original.with(InvisibLights.FROM_POWERED_ROD, true); + } + + @Override + public void postPlace(PlayerInventory inv, ItemStack heldItemStack) + { + this.tryUseEnergy(heldItemStack, Config.PoweredLightSourceCost); + } + + @Override + public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext context) + { + long stored = this.getStoredEnergy(stack); + long cap = this.getEnergyCapacity(stack); + + tooltip.add(Text.translatable("item.invisiblights.powered_light_rod.tooltip", stored, cap, (int)(100.0 * stored / cap)).formatted(Formatting.GRAY)); + } + + @Override + public boolean isItemBarVisible(ItemStack stack) + { + return true; + } + + @Override + public int getItemBarStep(ItemStack stack) + { + return Math.round(13.0F * this.getStoredEnergy(stack) / this.getEnergyCapacity(stack)); + } + + @Override + public int getItemBarColor(ItemStack stack) + { + float fillLevel = this.getStoredEnergy(stack) / (float)this.getEnergyCapacity(stack); + return ColorHelper.Argb.getArgb(0, 128 + (int)(fillLevel * 127), 111 + (int)(fillLevel * 110), 60 + (int)(fillLevel * 59)); + } + + @Override + public long getEnergyCapacity(ItemStack stack) + { + return Config.PoweredLightRodCapacity; + } + + @Override + public long getEnergyMaxInput(ItemStack stack) + { + return Config.PoweredLightRodChargeRate; + } + + @Override + public long getEnergyMaxOutput(ItemStack stack) + { + return 0; + } +} \ No newline at end of file diff --git a/src/main/java/re/domi/invisiblights/config/Config.java b/src/main/java/re/domi/invisiblights/config/Config.java new file mode 100644 index 0000000..2305772 --- /dev/null +++ b/src/main/java/re/domi/invisiblights/config/Config.java @@ -0,0 +1,68 @@ +package re.domi.invisiblights.config; + +import net.fabricmc.loader.api.FabricLoader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +public class Config +{ + public static boolean PlaceVanillaLightSourceBlock = false; + public static int LightSourceGlowstoneCost = 2; + public static long PoweredLightRodCapacity = 640000; + public static long PoweredLightRodChargeRate = 6400; + public static long PoweredLightSourceCost = 2000; + + private static final File CONFIG_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "invisiblights.properties"); + private static final String CONFIG_COMMENT = "InvisibLights config file"; + + public static void read() + { + try + { + if (CONFIG_FILE.createNewFile()) + { + write(); + return; + } + + Properties p = new Properties(); + p.load(new FileInputStream(CONFIG_FILE)); + + PlaceVanillaLightSourceBlock = Boolean.toString(true).equals(p.getProperty("PlaceVanillaLightSourceBlock")); + LightSourceGlowstoneCost = Integer.parseInt(p.getProperty("LightSourceGlowstoneCost")); + + PoweredLightRodCapacity = Long.parseLong(p.getProperty("PoweredLightRodCapacity")); + PoweredLightRodChargeRate = Long.parseLong(p.getProperty("PoweredLightRodChargeRate")); + PoweredLightSourceCost = Long.parseLong(p.getProperty("PoweredLightSourceCost")); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + public static void write() + { + try + { + Properties p = new Properties(); + + p.setProperty("PlaceVanillaLightSourceBlock", Boolean.toString(PlaceVanillaLightSourceBlock)); + p.setProperty("LightSourceGlowstoneCost", Integer.toString(LightSourceGlowstoneCost)); + + p.setProperty("PoweredLightRodCapacity", Long.toString(PoweredLightRodCapacity)); + p.setProperty("PoweredLightRodChargeRate", Long.toString(PoweredLightRodChargeRate)); + p.setProperty("PoweredLightSourceCost", Long.toString(PoweredLightSourceCost)); + + p.store(new FileOutputStream(CONFIG_FILE), CONFIG_COMMENT); + } + catch (IOException e) + { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/re/domi/invisiblights/config/ConfigScreen.java b/src/main/java/re/domi/invisiblights/config/ConfigScreen.java new file mode 100644 index 0000000..a63ec0e --- /dev/null +++ b/src/main/java/re/domi/invisiblights/config/ConfigScreen.java @@ -0,0 +1,165 @@ +package re.domi.invisiblights.config; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.*; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; + +public class ConfigScreen extends Screen +{ + private static final Text SCREEN_TITLE = Text.literal("InvisibLights config"); + + private static final Text PLACE_VANILLA_LIGHT_SOURCE_BLOCK = Text.translatable("options.invisiblights.place_vanilla_light_source_block"); + private static final Text LIGHT_SOURCE_GLOWSTONE_COST = Text.translatable("options.invisiblights.light_source_glowstone_cost"); + private static final Text POWERED_LIGHT_ROD_CAPACITY = Text.translatable("options.invisiblights.powered_light_rod_capacity"); + private static final Text POWERED_LIGHT_ROD_CHARGE_RATE = Text.translatable("options.invisiblights.powered_light_rod_charge_rate"); + private static final Text POWERED_LIGHT_SOURCE_COST = Text.translatable("options.invisiblights.powered_light_rod_source_cost"); + + private boolean placeVanillaLightSourceBlock = Config.PlaceVanillaLightSourceBlock; + private TextFieldWidget lightSourceGlowstoneCostWidget; + private TextFieldWidget poweredLightRodCapacityWidget; + private TextFieldWidget poweredLightRodChargeRateWidget; + private TextFieldWidget poweredLightSourceCostWidget; + + private final Screen parent; + + protected ConfigScreen(Screen parent) + { + super(SCREEN_TITLE); + this.parent = parent; + } + + @Override + protected void init() + { + GridWidget grid = new GridWidget(); + grid.getMainPositioner().marginX(5).marginBottom(4).alignRight(); + GridWidget.Adder adder = grid.createAdder(2); + + adder.add(this.createTextWidget(PLACE_VANILLA_LIGHT_SOURCE_BLOCK)); + adder.add(new ButtonWidget.Builder(this.placeVanillaLightSourceBlock ? ScreenTexts.YES : ScreenTexts.NO, button -> + { + this.placeVanillaLightSourceBlock = !this.placeVanillaLightSourceBlock; + button.setMessage(this.placeVanillaLightSourceBlock ? ScreenTexts.YES : ScreenTexts.NO); + }).dimensions(0, 0, 100, 20).build()); + + adder.add(this.createTextWidget(LIGHT_SOURCE_GLOWSTONE_COST)); + this.lightSourceGlowstoneCostWidget = this.createIntTextFieldWidget(Config.LightSourceGlowstoneCost); + adder.add(this.lightSourceGlowstoneCostWidget); + + adder.add(this.createTextWidget(POWERED_LIGHT_ROD_CAPACITY)); + this.poweredLightRodCapacityWidget = this.createLongTextFieldWidget(Config.PoweredLightRodCapacity); + adder.add(this.poweredLightRodCapacityWidget); + + adder.add(this.createTextWidget(POWERED_LIGHT_ROD_CHARGE_RATE)); + this.poweredLightRodChargeRateWidget = this.createLongTextFieldWidget(Config.PoweredLightRodChargeRate); + adder.add(this.poweredLightRodChargeRateWidget); + + adder.add(this.createTextWidget(POWERED_LIGHT_SOURCE_COST)); + this.poweredLightSourceCostWidget = this.createLongTextFieldWidget(Config.PoweredLightSourceCost); + adder.add(this.poweredLightSourceCostWidget); + + grid.refreshPositions(); + SimplePositioningWidget.setPos(grid, 0, this.height / 6 - 12, this.width, this.height - 50, 0.5F, 0.0F); + grid.forEachChild(this::addDrawableChild); + + this.addDrawableChild(new ButtonWidget.Builder(ScreenTexts.DONE, button -> + { + Config.PlaceVanillaLightSourceBlock = this.placeVanillaLightSourceBlock; + + if (!this.lightSourceGlowstoneCostWidget.getText().isEmpty()) + { + Config.LightSourceGlowstoneCost = Integer.parseInt(this.lightSourceGlowstoneCostWidget.getText()); + } + + if (!this.poweredLightRodCapacityWidget.getText().isEmpty()) + { + Config.PoweredLightRodCapacity = Long.parseLong(this.poweredLightRodCapacityWidget.getText()); + } + if (!this.poweredLightRodChargeRateWidget.getText().isEmpty()) + { + Config.PoweredLightRodChargeRate = Long.parseLong(this.poweredLightRodChargeRateWidget.getText()); + } + if (!this.poweredLightSourceCostWidget.getText().isEmpty()) + { + Config.PoweredLightSourceCost = Long.parseLong(this.poweredLightSourceCostWidget.getText()); + } + + Config.write(); + this.close(); + }) + .dimensions(this.width / 2 - 105, this.height - 40, 100, 20) + .build()); + + this.addDrawableChild(new ButtonWidget.Builder(ScreenTexts.CANCEL, button -> this.close()) + .dimensions(this.width / 2 + 5, this.height - 40, 100, 20) + .build()); + } + + @Override + public void close() + { + if (this.client != null) + { + this.client.setScreen(this.parent); + } + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) + { + this.renderBackground(context); + super.render(context, mouseX, mouseY, delta); + } + + private Widget createTextWidget(Text text) + { + return new TextWidget(0, 0, this.textRenderer.getWidth(text), 20, text, this.textRenderer); + } + + private TextFieldWidget createIntTextFieldWidget(int initialValue) + { + TextFieldWidget w = new TextFieldWidget(this.textRenderer, 0, 0, 100, 18, ScreenTexts.EMPTY); + w.setText(Integer.toString(initialValue)); + w.setTextPredicate(s -> + { + if (s.isEmpty()) + { + return true; + } + + try + { + int i = Integer.parseInt(s); + return i >= 0; + } + catch (NumberFormatException e) + { + return false; + } + }); + + return w; + } + + private TextFieldWidget createLongTextFieldWidget(long initialValue) + { + TextFieldWidget w = new TextFieldWidget(this.textRenderer, 0, 0, 100, 18, ScreenTexts.EMPTY); + w.setText(Long.toString(initialValue)); + w.setTextPredicate(s -> + { + try + { + long l = Long.parseLong(s); + return l >= 0; + } + catch (NumberFormatException e) + { + return false; + } + }); + + return w; + } +} diff --git a/src/main/java/re/domi/invisiblights/config/ModMenuImpl.java b/src/main/java/re/domi/invisiblights/config/ModMenuImpl.java new file mode 100644 index 0000000..460dc9e --- /dev/null +++ b/src/main/java/re/domi/invisiblights/config/ModMenuImpl.java @@ -0,0 +1,13 @@ +package re.domi.invisiblights.config; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; + +public class ModMenuImpl implements ModMenuApi +{ + @Override + public ConfigScreenFactory getModConfigScreenFactory() + { + return ConfigScreen::new; + } +} diff --git a/src/main/java/re/domi/invisiblights/mixin/ClientWorldMixin.java b/src/main/java/re/domi/invisiblights/mixin/ClientWorldMixin.java index 927e6a4..ecc7f93 100644 --- a/src/main/java/re/domi/invisiblights/mixin/ClientWorldMixin.java +++ b/src/main/java/re/domi/invisiblights/mixin/ClientWorldMixin.java @@ -6,13 +6,12 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import re.domi.invisiblights.InvisibLights; +import re.domi.invisiblights.LightRodItem; @Mixin(ClientWorld.class) public class ClientWorldMixin @@ -26,7 +25,7 @@ private void getBlockParticle(CallbackInfoReturnable cir) Item mainHandItem = player.getMainHandStack().getItem(); Item offHandItem = player.getOffHandStack().getItem(); - if (mainHandItem == InvisibLights.LightRod || offHandItem == InvisibLights.LightRod || mainHandItem == Items.GLOWSTONE_DUST) + if (mainHandItem instanceof LightRodItem || offHandItem instanceof LightRodItem || mainHandItem == Items.GLOWSTONE_DUST) { cir.setReturnValue(Blocks.LIGHT); } diff --git a/src/main/java/re/domi/invisiblights/mixin/LightBlockMixin.java b/src/main/java/re/domi/invisiblights/mixin/LightBlockMixin.java index 17a60c1..aedd6a9 100644 --- a/src/main/java/re/domi/invisiblights/mixin/LightBlockMixin.java +++ b/src/main/java/re/domi/invisiblights/mixin/LightBlockMixin.java @@ -10,7 +10,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUsageContext; import net.minecraft.item.Items; -import net.minecraft.loot.context.LootContext; +import net.minecraft.loot.context.LootContextParameterSet; import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; import net.minecraft.util.hit.BlockHitResult; @@ -23,8 +23,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import re.domi.invisiblights.config.Config; import re.domi.invisiblights.InvisibLights; -import re.domi.invisiblights.LightRodItem; import java.util.ArrayList; import java.util.List; @@ -40,7 +40,7 @@ public LightBlockMixin(Settings settings) @Inject(method = "getOutlineShape", at = @At("HEAD"), cancellable = true) private void getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context, CallbackInfoReturnable cir) { - if (context.isHolding(InvisibLights.LightRod) || context.isHolding(Items.GLOWSTONE_DUST)) + if (context.isHolding(InvisibLights.LightRod) || context.isHolding(InvisibLights.PoweredLightRod) || context.isHolding(Items.GLOWSTONE_DUST)) { cir.setReturnValue(VoxelShapes.fullCube()); } @@ -58,10 +58,10 @@ public void onUse(BlockState state, World world, BlockPos pos, PlayerEntity play @SuppressWarnings("deprecation") @Override - public List getDroppedStacks(BlockState state, LootContext.Builder builder) + public List getDroppedStacks(BlockState state, LootContextParameterSet.Builder builder) { List drops = new ArrayList<>(1); - drops.add(new ItemStack(Items.GLOWSTONE_DUST, InvisibLights.GLOWSTONE_COST)); + drops.add(new ItemStack(Items.GLOWSTONE_DUST, Config.LightSourceGlowstoneCost)); return drops; } diff --git a/src/main/resources/assets/invisiblights/lang/de_de.json b/src/main/resources/assets/invisiblights/lang/de_de.json index 44bafa0..ab84e1d 100644 --- a/src/main/resources/assets/invisiblights/lang/de_de.json +++ b/src/main/resources/assets/invisiblights/lang/de_de.json @@ -1,4 +1,11 @@ { "block.invisiblights.light_source": "Lichtquelle", - "item.invisiblights.light_rod": "Stab des Lichts" + "item.invisiblights.light_rod": "Stab des Lichts", + "item.invisiblights.powered_light_rod": "Stab des Lichts (Energiebetrieben)", + "item.invisiblights.powered_light_rod.tooltip": "Energie: %1$d/%2$d E [%3$d%%]", + "options.invisiblights.place_vanilla_light_source_block": "Vanilla-Lichtquellen platzieren:", + "options.invisiblights.light_source_glowstone_cost": "Lichtquelle Glowstone-Kosten:", + "options.invisiblights.powered_light_rod_capacity": "E-Stab des Lichts Energiekapazität:", + "options.invisiblights.powered_light_rod_charge_rate": "E-Stab des Lichts Laderate:", + "options.invisiblights.powered_light_rod_source_cost": "E-Lichtquelle Kosten:" } diff --git a/src/main/resources/assets/invisiblights/lang/en_us.json b/src/main/resources/assets/invisiblights/lang/en_us.json index 7c40e42..ed192bd 100644 --- a/src/main/resources/assets/invisiblights/lang/en_us.json +++ b/src/main/resources/assets/invisiblights/lang/en_us.json @@ -1,4 +1,11 @@ { "block.invisiblights.light_source": "Light Source", - "item.invisiblights.light_rod": "Rod of Light" + "item.invisiblights.light_rod": "Rod of Light", + "item.invisiblights.powered_light_rod": "Rod of Light (Powered)", + "item.invisiblights.powered_light_rod.tooltip": "Energy: %1$d/%2$d E [%3$d%%]", + "options.invisiblights.place_vanilla_light_source_block": "Place vanilla light source block:", + "options.invisiblights.light_source_glowstone_cost": "Light source glowstone cost:", + "options.invisiblights.powered_light_rod_capacity": "Powered light rod capacity:", + "options.invisiblights.powered_light_rod_charge_rate": "Powered light rod charge rate:", + "options.invisiblights.powered_light_rod_source_cost": "Powered light source cost:" } diff --git a/src/main/resources/assets/invisiblights/models/item/powered_light_rod.json b/src/main/resources/assets/invisiblights/models/item/powered_light_rod.json new file mode 100644 index 0000000..3511519 --- /dev/null +++ b/src/main/resources/assets/invisiblights/models/item/powered_light_rod.json @@ -0,0 +1,6 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "invisiblights:item/powered_light_rod" + } +} diff --git a/src/main/resources/assets/invisiblights/textures/block/light_source.png b/src/main/resources/assets/invisiblights/textures/block/light_source.png index d1f21af..1da42fa 100644 Binary files a/src/main/resources/assets/invisiblights/textures/block/light_source.png and b/src/main/resources/assets/invisiblights/textures/block/light_source.png differ diff --git a/src/main/resources/assets/invisiblights/textures/block/light_source_old.png b/src/main/resources/assets/invisiblights/textures/block/light_source_old.png new file mode 100644 index 0000000..d1f21af Binary files /dev/null and b/src/main/resources/assets/invisiblights/textures/block/light_source_old.png differ diff --git a/src/main/resources/assets/invisiblights/textures/item/powered_light_rod.png b/src/main/resources/assets/invisiblights/textures/item/powered_light_rod.png new file mode 100644 index 0000000..486be44 Binary files /dev/null and b/src/main/resources/assets/invisiblights/textures/item/powered_light_rod.png differ diff --git a/src/main/resources/data/invisiblights/advancements/light_rod.json b/src/main/resources/data/invisiblights/advancements/recipes/light_rod.json similarity index 88% rename from src/main/resources/data/invisiblights/advancements/light_rod.json rename to src/main/resources/data/invisiblights/advancements/recipes/light_rod.json index 3fc7f74..ca328f5 100644 --- a/src/main/resources/data/invisiblights/advancements/light_rod.json +++ b/src/main/resources/data/invisiblights/advancements/recipes/light_rod.json @@ -11,7 +11,7 @@ "conditions": { "items": [ { - "item": "minecraft:glowstone" + "items": ["minecraft:glowstone"] } ] } @@ -21,7 +21,7 @@ "conditions": { "items": [ { - "item": "minecraft:glowstone_dust" + "items": ["minecraft:glowstone_dust"] } ] } diff --git a/src/main/resources/data/invisiblights/advancements/recipes/powered_light_rod.json b/src/main/resources/data/invisiblights/advancements/recipes/powered_light_rod.json new file mode 100644 index 0000000..9b46e1a --- /dev/null +++ b/src/main/resources/data/invisiblights/advancements/recipes/powered_light_rod.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "invisiblights:powered_light_rod" + ] + }, + "criteria": { + "has_rod": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": ["invisiblights:light_rod"] + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "invisiblights:powered_light_rod" + } + } + }, + "requirements": [ + [ + "has_rod", + "has_the_recipe" + ] + ] +} diff --git a/src/main/resources/data/invisiblights/recipes/powered_light_rod.json b/src/main/resources/data/invisiblights/recipes/powered_light_rod.json new file mode 100644 index 0000000..f0f6d20 --- /dev/null +++ b/src/main/resources/data/invisiblights/recipes/powered_light_rod.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " rb", + " lr", + "d " + ], + "key": { + "r": { + "item": "minecraft:redstone" + }, + "b": { + "item": "minecraft:redstone_block" + }, + "l": { + "item": "invisiblights:light_rod" + }, + "d": { + "item": "minecraft:diamond" + } + }, + "result": { + "item": "invisiblights:powered_light_rod" + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 9195b50..8763c50 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -9,7 +9,7 @@ "Domi", "Rongmario" ], "contact": { - "homepage": "https://www.curseforge.com/minecraft/mc-mods/invisiblights", + "homepage": "https://domi.re/mc-mods/lights", "sources": "https://github.com/FakeDomi/InvisibLights", "issues": "https://github.com/FakeDomi/InvisibLights/issues" }, @@ -23,6 +23,10 @@ "re.domi.invisiblights.InvisibLights" ], "client": [ + "re.domi.invisiblights.InvisibLightsClient" + ], + "modmenu": [ + "re.domi.invisiblights.config.ModMenuImpl" ] }, "mixins": [ @@ -30,11 +34,8 @@ ], "depends": { - "fabricloader": "*", - "fabric": "*", - "minecraft": ">=1.17" - }, - "suggests": { - "flamingo": "*" + "fabricloader": ">=0.9.0", + "fabric-api": "*", + "minecraft": ">=1.20" } } diff --git a/src/main/resources/invisiblights.mixins.json b/src/main/resources/invisiblights.mixins.json index b00315e..fd4558b 100644 --- a/src/main/resources/invisiblights.mixins.json +++ b/src/main/resources/invisiblights.mixins.json @@ -2,7 +2,7 @@ "required": true, "minVersion": "0.8", "package": "re.domi.invisiblights.mixin", - "compatibilityLevel": "JAVA_16", + "compatibilityLevel": "JAVA_17", "mixins": [ "BlocksMixin", "LightBlockMixin"