diff --git a/.gitignore b/.gitignore index e844c7f..12f8644 100644 --- a/.gitignore +++ b/.gitignore @@ -1,63 +1,25 @@ -## gradle -/.gradle -/build - -## eclipse -/.settings -/.metadata -/.classpath -/.project -/bin -/run -/eclipse - +# eclipse +bin *.launch +.settings +.metadata +.classpath +.project -#####=== JetBrains ===##### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio - -*.iml - -## Directory-based project format: -.idea/ -# if you remove the above rule, at least ignore the following: - -# User-specific stuff: -# .idea/workspace.xml -# .idea/tasks.xml -# .idea/dictionaries - -# Sensitive or high-churn files: -# .idea/dataSources.ids -# .idea/dataSources.xml -# .idea/sqlDataSources.xml -# .idea/dynamic.xml -# .idea/uiDesigner.xml - -# Gradle: -# .idea/gradle.xml -# .idea/libraries - -# Mongo Explorer plugin: -# .idea/mongoSettings.xml - -## File-based project format: +# idea +out *.ipr *.iws +*.iml +.idea -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml +# gradle +build +.gradle -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties +# other +eclipse +run +# Files from Forge MDK +forge*changelog.txt diff --git a/build.gradle b/build.gradle index 5fb7d29..5d69c91 100644 --- a/build.gradle +++ b/build.gradle @@ -1,54 +1,93 @@ buildscript { repositories { + maven { url = 'https://files.minecraftforge.net/maven' } jcenter() - maven { url = "http://files.minecraftforge.net/maven" } + mavenCentral() } dependencies { - classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT' + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true } } -apply plugin: 'net.minecraftforge.gradle.forge' +apply plugin: 'net.minecraftforge.gradle' +apply plugin: 'eclipse' +apply plugin: 'maven-publish' +apply plugin: 'idea' + Properties props = new Properties() -props.load(new BufferedReader(new FileReader(file('../gradle.properties')))) +props.load(new BufferedReader(new FileReader(file('gradle.properties')))) -version = "${props.get('mc_version')}-1.4.0" -group = "mrriegel.blockdrops" -archivesBaseName = "blockdrops" +version = "${props.get('mc_version')}-2.0.2" +group = 'kdp.blockdrops' +archivesBaseName = 'blockdrops' -sourceCompatibility = targetCompatibility = '1.8' -compileJava { - sourceCompatibility = targetCompatibility = '1.8' -} +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' minecraft { - version = "${props.get('forge_version')}" - runDir = "run" - mappings = "${props.get('mapping')}" -} + mappings channel: 'snapshot', version: "${props.get('mapping')}" + // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. + // accessTransformer = file('build/resources/main/META-INF/accesstransformer.cfg') + runs { + client { + workingDirectory project.file('run') -dependencies { - deobfCompile "${props.get('jei_version')}" -} + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' -processResources { - inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version + property 'forge.logging.console.level', 'debug' - from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' - expand 'version':project.version, 'mcversion':project.minecraft.version - } - - from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' + mods { + blockdrops { + source sourceSets.main + } + } + } + + server { + workingDirectory project.file('run') + + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + + property 'forge.logging.console.level', 'debug' + + mods { + blockdrops { + source sourceSets.main + } + } + } } } - repositories { maven { - url "http://dvs1.progwml6.com/files/maven" + name = "Progwml6 maven" + url = "https://dvs1.progwml6.com/files/maven/" } + maven { + name = "ModMaven" + url = "https://modmaven.k-4u.nl" + } +} + +dependencies { + minecraft "net.minecraftforge:forge:${props.get('mc_version')}-${props.get('forge_version')}" + compile fg.deobf("mezz.jei:jei-${props.get('mc_version')}:${props.get('jei_version')}") } +def reobfFile = file("$buildDir/reobfJar/output.jar") +def reobfArtifact = artifacts.add('default', reobfFile) { + type 'jar' + builtBy 'reobfJar' +} +publishing { + publications { + mavenJava(MavenPublication) { + artifact reobfArtifact + } + } + repositories { + maven { + url "file:///${project.projectDir}/mcmodsrepo" + } + } +} diff --git a/gradle.properties b/gradle.properties index e9b9fd5..e987b12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,9 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false + +mapping=20200723-1.16.1 +mc_version=1.16.1 +forge_version=32.0.108 +jei_version=7.0.1.10 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 30d399d..7a3265e 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 e18cba7..949819d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Mon Sep 14 12:28:28 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip diff --git a/gradlew b/gradlew index 91a7e26..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$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="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat old mode 100755 new mode 100644 index aec9973..e95643d --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/src/main/java/kdp/blockdrops/BlockDrops.java b/src/main/java/kdp/blockdrops/BlockDrops.java new file mode 100644 index 0000000..158926a --- /dev/null +++ b/src/main/java/kdp/blockdrops/BlockDrops.java @@ -0,0 +1,314 @@ +package kdp.blockdrops; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import com.google.common.base.Stopwatch; +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameters; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.JsonToNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.FakePlayer; +import net.minecraftforge.common.util.FakePlayerFactory; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModList; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.server.FMLServerStartingEvent; +import net.minecraftforge.fml.loading.moddiscovery.ModInfo; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.PacketDistributor; +import net.minecraftforge.fml.network.simple.SimpleChannel; +import net.minecraftforge.registries.ForgeRegistries; + +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; + +@Mod(BlockDrops.MOD_ID) +public class BlockDrops { + + public static final String MOD_ID = "blockdrops"; + public static final Logger LOG = LogManager.getLogger(BlockDrops.class); + public static final ResourceLocation RL = new ResourceLocation(MOD_ID, "drops"); + + public static ForgeConfigSpec.BooleanValue all, showChance, showMinMax, allStates; + private static ForgeConfigSpec.IntValue iterations; + private static ForgeConfigSpec.ConfigValue> blacklistedMods; + + public static final UUID uuid = UUID.fromString("1ef41968-f9b8-4350-834e-367f49476a56"); + + private static final Hash.Strategy strategy = new Hash.Strategy() { + @Override + public int hashCode(ItemStack o) { + return o == null || o.isEmpty() ? 0 : o.getItem().hashCode(); + } + + @Override + public boolean equals(ItemStack a, ItemStack b) { + return a != null && b != null && a.getItem() == b.getItem(); + } + }; + private static final Tool toolItem = new Tool(); + + private static Path recipesPath; + + private static final String VERSION = "1.0"; + private static final SimpleChannel simpleChannel = NetworkRegistry + .newSimpleChannel(new ResourceLocation(MOD_ID, "ch1"), () -> VERSION, VERSION::equals, VERSION::equals); + + private static List recipes = Collections.emptyList(); + + public BlockDrops() { + Pair pairCommon = new ForgeConfigSpec.Builder().configure(b -> { + all = b.comment("Show block drops of any block").define("allBlocks", false); + iterations = b + .comment("Amount of calculation iterations. The higher the more precise the calculation results") + .defineInRange("iterations", 4000, 500, 20000); + blacklistedMods = b.comment("Mod IDs of mods that won't be scanned").define("blacklistedMods", + Arrays.asList("flatcoloredblocks", "chisel", "xtones", "wallpapercraft", "sonarcore", + "microblockcbe")); + allStates = b.comment("Only one blockstate of a block is used to calculate the drops", + "Should ordinarily not affect the calculation", "(enable this if you miss some drops)") + .define("allStates", false); + return null; + }); + ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, pairCommon.getValue()); + Pair pairClient = new ForgeConfigSpec.Builder().configure(b -> { + showChance = b.comment("Show chance of drops").define("showChance", true); + showMinMax = b.comment("Show minimum and maximum of drops").define("showMinMax", true); + return null; + }); + ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, pairClient.getValue()); + MinecraftForge.EVENT_BUS.register(this); + + recipesPath = Paths.get("config", MOD_ID + ".txt"); + simpleChannel.registerMessage(0, SyncMessage.class, (m, pb) -> { + ListNBT listNBT = new ListNBT(); + m.recipes.forEach(recipe -> listNBT.add(recipe.serializeNBT())); + CompoundNBT tag = new CompoundNBT(); + tag.put("list", listNBT); + pb.writeCompoundTag(tag); + }, pb -> { + SyncMessage m = new SyncMessage(); + CompoundNBT nbt = pb.readCompoundTag(); + if (nbt != null) { + ListNBT listNBT = (ListNBT) nbt.get("list"); + if (listNBT != null) { + m.recipes = listNBT.stream().map(n -> { + DropRecipe r = new DropRecipe(); + r.deserializeNBT((CompoundNBT) n); + return r; + }).collect(Collectors.toList()); + } + } + return m; + }, (m, s) -> { + s.get().enqueueWork(() -> Plugin.recipes = m.recipes); + s.get().setPacketHandled(true); + }); + } + + public static List getAllRecipes(Set allowedIDs, FMLServerStartingEvent event) { + List result = new ArrayList<>(); + ServerWorld world = event.getServer().getWorld(World.field_234918_g_); + FakePlayer player = FakePlayerFactory.get(world, new GameProfile(uuid, "Hacker")); + Stopwatch sw = Stopwatch.createStarted(); + LOG.info("Block drop calculation started..."); + for (Block block : ForgeRegistries.BLOCKS) { + if (block.getRegistryName() != null && allowedIDs.contains(block.getRegistryName().getNamespace())) { + List validStates = block.getStateContainer().getValidStates(); + if (!allStates.get()) { + validStates = Collections.singletonList(validStates.get(validStates.size() - 1)); + } + if (validStates.size() > 20) { + validStates = Collections.singletonList(block.getDefaultState()); + } + Set dropStrings = new HashSet<>(); + for (BlockState state : validStates) { + List drops = getDrops(state, world, player); + String ds = drops.toString(); + if (drops.isEmpty() || dropStrings.contains(ds)) { + continue; + } + dropStrings.add(ds); + result.add(new DropRecipe(getItemForBlock(state, world), drops)); + } + } + } + LOG.info("Block drop calculation finished after {} milliseconds.", sw.elapsed(TimeUnit.MILLISECONDS)); + return result; + } + + private static List getDrops(BlockState state, ServerWorld world, FakePlayer player) { + try { + List result = new ArrayList<>(); + ItemStack show; + try { + show = getItemForBlock(state, world); + } catch (RuntimeException | NoSuchMethodError e) { + return result; + } + if (show.isEmpty()) { + return result; + } + int iteration = iterations.get(); + Int2ObjectOpenHashMap> resultMap = new Int2ObjectOpenHashMap<>(); + Int2ObjectOpenHashMap>> minmaxs = new Int2ObjectOpenHashMap<>(); + for (int fortune = 0; fortune < 4; fortune++) { + ItemStack tool = new ItemStack(toolItem); + if (fortune > 0) { + tool.addEnchantment(Enchantments.FORTUNE, fortune); + } + TileEntity tile = null; + try { + tile = state.createTileEntity(world); + if (tile != null) tile.setWorldAndPos(world, BlockPos.ZERO); + } catch (Exception ignored) { + } + player.setItemStackToSlot(EquipmentSlotType.MAINHAND, tool); + LootContext.Builder builder = new LootContext.Builder(world)// + .withParameter(LootParameters.POSITION, BlockPos.ZERO)// + .withParameter(LootParameters.BLOCK_STATE, state)// + .withNullableParameter(LootParameters.BLOCK_ENTITY, tile)// + .withNullableParameter(LootParameters.THIS_ENTITY, player)// + .withParameter(LootParameters.TOOL, tool); + Object2IntOpenCustomHashMap stacks = new Object2IntOpenCustomHashMap<>(strategy); + Object2ObjectOpenCustomHashMap> minmax = new Object2ObjectOpenCustomHashMap<>( + strategy); + minmax.defaultReturnValue(MutablePair.of(9999, 0)); + for (int i = 0; i < iteration; i++) { + NonNullList drops = NonNullList.create(); + drops.addAll(state.getDrops(builder)); + for (ItemStack drop : drops) { + if (drop.isEmpty()) continue; + if (all.get() || drop.getItem() != show.getItem() || !(show.getItem() instanceof BlockItem)) { + stacks.addTo(drop, drop.getCount()); + minmax.merge(drop, MutablePair.of(drop.getCount(), drop.getCount()), (pOld, pNew) -> { + pOld.setLeft(Math.min(pNew.getLeft(), pOld.getLeft())); + pOld.setRight(Math.max(pNew.getRight(), pOld.getRight())); + return pOld; + }); + } + } + } + minmaxs.put(fortune, minmax); + resultMap.put(fortune, stacks); + } + ObjectOpenCustomHashSet allStacks = new ObjectOpenCustomHashSet<>(strategy); + resultMap.values().forEach(map -> allStacks.addAll(map.keySet())); + allStacks.stream()// + .sorted(Comparator.comparingInt(s -> Item.getIdFromItem(s.getItem())))// + .forEach(s -> { + Drop drop = new Drop(s); + for (int fortune = 0; fortune < 4; fortune++) { + drop.getChances().put(fortune, resultMap.get(fortune).getInt(s) / (float) iteration); + drop.getMaxs().put(fortune, minmaxs.get(fortune).get(s).getRight().intValue()); + drop.getMins().put(fortune, drop.getChances().get(fortune) < 1F ? + 0 : minmaxs.get(fortune).get(s).getLeft().intValue()); + } + result.add(drop); + }); + return result; + } catch (Exception e) { + LOG.info("Error ({} : {}) while calculating drops for {}", e.getClass().getSimpleName(), e.getMessage(), + state); + return Collections.emptyList(); + } + } + + private static ItemStack getItemForBlock(BlockState state, World world) { + @SuppressWarnings("deprecation") + ItemStack item2 = state.getBlock().getItem(world, BlockPos.ZERO, state); + if (item2.getItem() instanceof BlockItem && ((BlockItem) item2.getItem()).getBlock() == state.getBlock()) { + return item2; + } + return ItemStack.EMPTY; + } + + @SubscribeEvent + public void serverStart(FMLServerStartingEvent event) throws IOException, CommandSyntaxException { + List allRecipes; + String hash = ModList.get().getMods().stream().map(mi -> "{" + mi.getModId() + ":" + mi.getVersion() + "}") + .sorted().collect(Collectors.joining(",")); + List strings = null; + boolean calculate = Files.notExists(recipesPath); + if (!calculate) { + strings = Files.readAllLines(recipesPath); + String stringHash = strings.get(0); + if (!Objects.equals(stringHash, hash)) { + calculate = true; + } + } + if (calculate) { + allRecipes = getAllRecipes(ModList.get().getMods().stream().map(ModInfo::getModId) + .filter(s -> !blacklistedMods.get().contains(s)).collect(Collectors.toSet()), event); + List nbts = allRecipes.stream().map(DropRecipe::serializeNBT).map(Object::toString) + .collect(Collectors.toList()); + nbts.add(0, hash); + Files.write(recipesPath, nbts); + } else { + allRecipes = new ArrayList<>(); + for (int i = 1; i < strings.size(); i++) { + DropRecipe dropRecipe = new DropRecipe(); + dropRecipe.deserializeNBT(JsonToNBT.getTagFromJson(strings.get(i))); + allRecipes.add(dropRecipe); + } + } + recipes = allRecipes; + if (event.getServer().isSinglePlayer()) { + Plugin.recipes = recipes; + } + } + + @SubscribeEvent + public void construct(PlayerEvent.PlayerLoggedInEvent event) { + if (event.getEntity() instanceof ServerPlayerEntity && !((ServerPlayerEntity) event.getEntity()).server + .isSinglePlayer()) { + simpleChannel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) event.getEntity()), + new SyncMessage(recipes)); + } + } +} diff --git a/src/main/java/kdp/blockdrops/Category.java b/src/main/java/kdp/blockdrops/Category.java new file mode 100644 index 0000000..b7f724d --- /dev/null +++ b/src/main/java/kdp/blockdrops/Category.java @@ -0,0 +1,172 @@ +package kdp.blockdrops; + +import java.text.DecimalFormat; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import com.mojang.blaze3d.matrix.MatrixStack; +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.AbstractGui; +import net.minecraft.client.resources.I18n; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; + +import org.apache.commons.lang3.tuple.Pair; +import org.lwjgl.glfw.GLFW; + +import mezz.jei.Internal; +import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.gui.IRecipeLayout; +import mezz.jei.api.gui.drawable.IDrawable; +import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; +import mezz.jei.api.ingredients.IIngredients; +import mezz.jei.api.recipe.category.IRecipeCategory; +import mezz.jei.gui.elements.DrawableBlank; +import mezz.jei.gui.recipes.IRecipeLogicStateListener; + +import javax.annotation.ParametersAreNonnullByDefault; + +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +public class Category implements IRecipeCategory { + private static final ResourceLocation hopper = new ResourceLocation("textures/gui/container/hopper.png"); + private static final DecimalFormat format = new DecimalFormat("#.##"); + private final Map> buttonMap = new IdentityHashMap<>(); + + @Override + public ResourceLocation getUid() { + return BlockDrops.RL; + } + + @Override + public Class getRecipeClass() { + return DropRecipe.class; + } + + @Override + public String getTitle() { + return "Block Drops"; + } + + @Override + public IDrawable getBackground() { + return new DrawableBlank(180, 40); + } + + @Override + public IDrawable getIcon() { + //noinspection ConstantConditions + return null; + } + + + + @Override + public void draw(DropRecipe recipe, MatrixStack matrixStack, double mouseX, double mouseY) { + drawSlot(matrixStack, 81, 1); + for (int i = 9; i < 170; i += 18) drawSlot(matrixStack, i, 20); + Pair pair = buttonMap.get(recipe); + if (pair == null) { + pair = Pair.of(new Button(0, 23, ""), new Button(172, 23, "")); + buttonMap.put(recipe, pair); + } + //pair.getLeft().visible = recipe.getIndex() > 0; + //pair.getRight().visible = recipe.getIndex() < recipe.getMaxIndex(); + if (recipe.getIndex() > 0) pair.getLeft().renderButton(matrixStack, (int) mouseX, (int) mouseY, 0); + if (recipe.getIndex() < recipe.getMaxIndex()) pair.getRight().renderButton(matrixStack, (int) mouseX, (int) mouseY, 0); + } + + private void drawSlot(MatrixStack matrixStack, int x, int y) { + Minecraft.getInstance().getTextureManager().bindTexture(hopper); + AbstractGui.blit(matrixStack, x, y, 43, 19, 18, 18, 256, 256); + } + + @Override + public void setIngredients(DropRecipe recipe, IIngredients ingredients) { + ingredients.setInputs(VanillaTypes.ITEM, recipe.getInputs()); + ingredients.setOutputs(VanillaTypes.ITEM, recipe.getOutputs()); + } + + @Override + public void setRecipe(IRecipeLayout recipeLayout, DropRecipe recipe, IIngredients ingredients) { + IGuiItemStackGroup stackGroup = recipeLayout.getItemStacks(); + stackGroup.init(0, true, 81, 1); + stackGroup.set(0, recipe.getInputs()); + for (int i = 0; i < Math.min(recipe.getOutputs().size(), 9); i++) { + stackGroup.init(i + 1, false, 9 + i * 18, 20); + stackGroup.set(i + 1, recipe.getOutputs().get((i + recipe.getIndex()))); + } + stackGroup.addTooltipCallback((int slotIndex, boolean input, ItemStack ingredient, List tooltip) -> { + if (!input) { + Drop d = recipe.getDropForItem(ingredient); + boolean one = d.getChances().values().stream().distinct().count() == 1; + for (int x = 0; x < (one ? 1 : 4); x++) { + String chance = BlockDrops.showChance.get() ? + format.format(d.getChances().get(x) * 100F) + " % " : + ""; + String minmax = BlockDrops.showMinMax.get() ? + "Min: " + d.getMins().get(x) + " Max: " + d.getMaxs().get(x) : + ""; + if (!chance.isEmpty() || !minmax.isEmpty()) { + String text = ""; + if (!one) text = TextFormatting.BLUE + "Fortune " + (0 != x ? I18n.format("enchantment.level." + x) : 0) + " "; + tooltip.add(new StringTextComponent(text + TextFormatting.GRAY + chance + minmax)); + } + } + } + }); + } + + @Override + public boolean handleClick(DropRecipe recipe, double mouseX, double mouseY, int mouseButton) { + Pair pair = buttonMap.get(recipe); + if (pair != null + && (pair.getLeft().isHovered() + || pair.getRight().isHovered()) + && mouseButton == GLFW.GLFW_MOUSE_BUTTON_1) { + if (pair.getLeft().isHovered()) { + recipe.decreaseIndex(); + } else { + recipe.increaseIndex(); + } + Minecraft.getInstance().enqueue(() -> { + if (Minecraft.getInstance().currentScreen != null) { + ((IRecipeLogicStateListener) Minecraft.getInstance().currentScreen).onStateChange(); + } + }); + + return true; + } + return false; + } + + private static class Button extends net.minecraft.client.gui.widget.button.Button { + + Button(int xPos, int yPos, String displayString) { + super(xPos, yPos, 8, 12, new StringTextComponent(displayString), button -> { }); + } + + @Override + public boolean isHovered() { + return super.isHovered() && visible; + } + + @Override + public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partial) { + super.renderButton(matrixStack, mouseX, mouseY, partial); + if (visible) { + boolean left = this.x == 0; + if (left) { + Internal.getTextures().getArrowPrevious().draw(matrixStack, 0, 24); + } else { + Internal.getTextures().getArrowNext().draw(matrixStack, 171, 24); + } + } + } + } +} diff --git a/src/main/java/kdp/blockdrops/Drop.java b/src/main/java/kdp/blockdrops/Drop.java new file mode 100644 index 0000000..49b3028 --- /dev/null +++ b/src/main/java/kdp/blockdrops/Drop.java @@ -0,0 +1,86 @@ +package kdp.blockdrops; + +import java.util.Arrays; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.IntArrayNBT; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.items.ItemHandlerHelper; + +import it.unimi.dsi.fastutil.ints.Int2FloatLinkedOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2IntLinkedOpenHashMap; + +public class Drop implements INBTSerializable { + private ItemStack out; + private final Int2FloatLinkedOpenHashMap chances = new Int2FloatLinkedOpenHashMap(); + private final Int2IntLinkedOpenHashMap mins = new Int2IntLinkedOpenHashMap(); + private final Int2IntLinkedOpenHashMap maxs = new Int2IntLinkedOpenHashMap(); + public static final Drop EMPTY = new Drop(); + + public Drop(ItemStack out) { + this.out = ItemHandlerHelper.copyStackWithSize(out, 1); + } + + Drop() { + } + + public ItemStack getOut() { + return out; + } + + public Int2FloatLinkedOpenHashMap getChances() { + return chances; + } + + public Int2IntLinkedOpenHashMap getMins() { + return mins; + } + + public Int2IntLinkedOpenHashMap getMaxs() { + return maxs; + } + + @Override + public String toString() { + ResourceLocation name = out.getItem().getRegistryName(); + return name == null ? "" : name.toString(); + } + + @Override + public CompoundNBT serializeNBT() { + CompoundNBT nbt = new CompoundNBT(); + nbt.put("out", out.write(new CompoundNBT())); + IntArrayNBT ck = new IntArrayNBT(chances.keySet().toIntArray()); + IntArrayNBT cv = new IntArrayNBT(chances.values().stream().mapToInt(Float::floatToRawIntBits).toArray()); + IntArrayNBT nk = new IntArrayNBT(mins.keySet().toIntArray()); + IntArrayNBT nv = new IntArrayNBT(mins.values().toIntArray()); + IntArrayNBT xk = new IntArrayNBT(maxs.keySet().toIntArray()); + IntArrayNBT xv = new IntArrayNBT(maxs.values().toIntArray()); + nbt.put("ck", ck); + nbt.put("cv", cv); + nbt.put("nk", nk); + nbt.put("nv", nv); + nbt.put("xk", xk); + nbt.put("xv", xv); + return nbt; + } + + @Override + public void deserializeNBT(CompoundNBT nbt) { + out = ItemStack.read(nbt.getCompound("out")); + int[] ck = nbt.getIntArray("ck"); + Float[] cv = Arrays.stream(nbt.getIntArray("cv")).mapToObj(Float::intBitsToFloat).toArray(Float[]::new); + int[] nk = nbt.getIntArray("nk"); + int[] nv = nbt.getIntArray("nv"); + int[] xk = nbt.getIntArray("xk"); + int[] xv = nbt.getIntArray("xv"); + for (int i = 0; i < 4; i++) { + chances.put(ck[i], cv[i].floatValue()); + mins.put(nk[i], nv[i]); + maxs.put(xk[i], xv[i]); + } + + } +} diff --git a/src/main/java/kdp/blockdrops/DropRecipe.java b/src/main/java/kdp/blockdrops/DropRecipe.java new file mode 100644 index 0000000..1c37b4d --- /dev/null +++ b/src/main/java/kdp/blockdrops/DropRecipe.java @@ -0,0 +1,97 @@ +package kdp.blockdrops; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.math.MathHelper; +import net.minecraftforge.common.util.INBTSerializable; + +public class DropRecipe implements INBTSerializable { + + private ItemStack in; + private List drops; + private final Cache cache = CacheBuilder.newBuilder().build(); + //client only + private int index, maxIndex; + + public DropRecipe(ItemStack in, List drops) { + this.in = in; + this.drops = drops; + this.maxIndex = Math.max(0, drops.size() - 9); + } + + public DropRecipe() { + } + + public List getInputs() { + return Collections.singletonList(in); + } + + public List getOutputs() { + return drops.stream().map(Drop::getOut).collect(Collectors.toList()); + } + + public void setIn(ItemStack in) { + this.in = in; + } + + public void setDrops(List drops) { + this.drops = drops; + this.maxIndex = Math.max(0, drops.size() - 9); + } + + public Drop getDropForItem(ItemStack stack) { + try { + return cache.get(stack, () -> drops.stream().filter(drop -> drop.getOut().isItemEqual(stack)).findFirst().orElse(Drop.EMPTY)); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + + public int getIndex() { + return this.index; + } + + public int getMaxIndex() { + return maxIndex; + } + + public void increaseIndex() { + this.index = MathHelper.clamp(index + 1, 0, maxIndex); + } + + public void decreaseIndex() { + this.index = MathHelper.clamp(index - 1, 0, maxIndex); + } + + @Override + public CompoundNBT serializeNBT() { + CompoundNBT nbt = new CompoundNBT(); + nbt.put("in", in.write(new CompoundNBT())); + ListNBT listNBT = new ListNBT(); + drops.forEach(d -> listNBT.add(d.serializeNBT())); + nbt.put("drops", listNBT); + return nbt; + } + + @Override + public void deserializeNBT(CompoundNBT nbt) { + in = ItemStack.read(nbt.getCompound("in")); + drops = new ArrayList<>(); + nbt.getList("drops", 10).forEach(n -> { + Drop d = new Drop(); + d.deserializeNBT((CompoundNBT) n); + drops.add(d); + }); + maxIndex = Math.max(0, drops.size() - 9); + } +} diff --git a/src/main/java/kdp/blockdrops/Plugin.java b/src/main/java/kdp/blockdrops/Plugin.java new file mode 100644 index 0000000..3d92b17 --- /dev/null +++ b/src/main/java/kdp/blockdrops/Plugin.java @@ -0,0 +1,51 @@ +package kdp.blockdrops; + +import java.util.Comparator; +import java.util.List; + +import mcp.MethodsReturnNonnullByDefault; +import net.minecraft.item.ItemStack; +import net.minecraft.item.PickaxeItem; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.ForgeRegistries; + +import mezz.jei.api.IModPlugin; +import mezz.jei.api.JeiPlugin; +import mezz.jei.api.registration.IRecipeCatalystRegistration; +import mezz.jei.api.registration.IRecipeCategoryRegistration; +import mezz.jei.api.registration.IRecipeRegistration; + +import javax.annotation.ParametersAreNonnullByDefault; + +@JeiPlugin +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class Plugin implements IModPlugin { + + static List recipes = null; + + @Override + public ResourceLocation getPluginUid() { + return BlockDrops.RL; + } + + @Override + public void registerCategories(IRecipeCategoryRegistration registration) { + registration.addRecipeCategories(new Category()); + } + + @Override + public void registerRecipes(IRecipeRegistration registration) { + if (recipes != null) { + registration.addRecipes(recipes, BlockDrops.RL); + } + } + + @Override + public void registerRecipeCatalysts(IRecipeCatalystRegistration registration) { + ForgeRegistries.ITEMS.getValues().stream() + .filter(i -> i instanceof PickaxeItem && i.getRegistryName() != null && i.getRegistryName().getNamespace().equals("minecraft")) + .sorted(Comparator.comparingInt(i -> ((PickaxeItem) i).getTier().getMaxUses()).reversed()) + .forEach(i -> registration.addRecipeCatalyst(new ItemStack(i), BlockDrops.RL)); + } +} diff --git a/src/main/java/kdp/blockdrops/SyncMessage.java b/src/main/java/kdp/blockdrops/SyncMessage.java new file mode 100644 index 0000000..c53a7c8 --- /dev/null +++ b/src/main/java/kdp/blockdrops/SyncMessage.java @@ -0,0 +1,15 @@ +package kdp.blockdrops; + +import java.util.List; + +public class SyncMessage { + + public List recipes; + + public SyncMessage() { + } + + public SyncMessage(List recipes) { + this.recipes = recipes; + } +} diff --git a/src/main/java/kdp/blockdrops/Tool.java b/src/main/java/kdp/blockdrops/Tool.java new file mode 100644 index 0000000..dd13f3b --- /dev/null +++ b/src/main/java/kdp/blockdrops/Tool.java @@ -0,0 +1,55 @@ +package kdp.blockdrops; + +import java.util.Collections; + +import net.minecraft.block.BlockState; +import net.minecraft.item.IItemTier; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ToolItem; +import net.minecraft.item.crafting.Ingredient; + +public class Tool extends ToolItem { + private static final IItemTier tier = new IItemTier() { + @Override + public int getMaxUses() { + return Integer.MAX_VALUE; + } + + @Override + public float getEfficiency() { + return 100F; + } + + @Override + public float getAttackDamage() { + return Integer.MAX_VALUE; + } + + @Override + public int getHarvestLevel() { + return 10; + } + + @Override + public int getEnchantability() { + return Integer.MAX_VALUE; + } + + @Override + @SuppressWarnings("NullableProblems") + public Ingredient getRepairMaterial() { + return null; + } + }; + + public Tool() { + super(1000F, 1000F, tier, Collections.emptySet(), new Item.Properties()); + setRegistryName("tool"); + } + + @Override + public boolean canHarvestBlock(ItemStack stack, BlockState state) { + return true; + } +} diff --git a/src/main/java/mrriegel/blockdrops/BlockDrops.java b/src/main/java/mrriegel/blockdrops/BlockDrops.java deleted file mode 100644 index 75a217c..0000000 --- a/src/main/java/mrriegel/blockdrops/BlockDrops.java +++ /dev/null @@ -1,369 +0,0 @@ -package mrriegel.blockdrops; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.Writer; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -import org.apache.commons.lang3.mutable.MutableBoolean; -import org.apache.commons.lang3.tuple.Pair; -import org.lwjgl.input.Keyboard; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import mezz.jei.gui.recipes.RecipeLayout; -import mezz.jei.gui.recipes.RecipesGui; -import mrriegel.blockdrops.util.Drop; -import mrriegel.blockdrops.util.FakeClientPlayer; -import mrriegel.blockdrops.util.FakeClientWorld; -import mrriegel.blockdrops.util.StackWrapper; -import mrriegel.blockdrops.util.WrapperJson; -import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.client.Minecraft; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraftforge.client.event.GuiScreenEvent.KeyboardInputEvent; -import net.minecraftforge.common.config.Configuration; -import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -import net.minecraftforge.fml.common.Mod.EventHandler; -import net.minecraftforge.fml.common.Mod.Instance; -import net.minecraftforge.fml.common.ProgressManager; -import net.minecraftforge.fml.common.ProgressManager.ProgressBar; -import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.registry.ForgeRegistries; -import net.minecraftforge.fml.relauncher.ReflectionHelper; - -@Mod(modid = BlockDrops.MODID, name = BlockDrops.MODNAME, version = BlockDrops.VERSION, acceptedMinecraftVersions = "[1.12,1.13)", dependencies = "required-after:jei@[4.8.0,);", clientSideOnly = true) -@EventBusSubscriber -public class BlockDrops { - public static final String MODID = "blockdrops"; - public static final String VERSION = "1.4.0"; - public static final String MODNAME = "Block Drops"; - - @Instance(BlockDrops.MODID) - public static BlockDrops instance; - - public static boolean all, showChance, showMinMax, multithreaded; - public static int iteration; - public static Set blacklist; - - public static List recipeWrappers; - public static Gson gson; - - private File recipeWrapFile, modHashFile; - - @EventHandler - public void preInit(FMLPreInitializationEvent event) { - File configDir = new File(event.getModConfigurationDirectory(), "BlockDrops"); - recipeWrapFile = new File(configDir, "blockdrops.txt"); - modHashFile = new File(configDir, "modVersions.txt"); - Configuration config = new Configuration(new File(configDir, "config.cfg")); - config.load(); - all = config.getBoolean("allDrops", Configuration.CATEGORY_CLIENT, false, "Show block drops of any block."); - showChance = config.getBoolean("showChance", Configuration.CATEGORY_CLIENT, true, "Show chance of drops."); - showMinMax = config.getBoolean("showMinMax", Configuration.CATEGORY_CLIENT, true, "Show minimum and maximum of drops."); - multithreaded = config.getBoolean("multithreaded", Configuration.CATEGORY_CLIENT, true, "Multithreaded calculation of drops"); - iteration = config.getInt("iteration", Configuration.CATEGORY_CLIENT, 4000, 1, 99999, "Number of calculation. The higher the more precise the chance."); - blacklist = Sets.newHashSet(config.getStringList("blacklist", Configuration.CATEGORY_CLIENT, new String[] { "flatcoloredblocks", "chisel", "xtones", "wallpapercraft", "sonarcore", "microblockcbe" }, "Mod IDs of mods that won't be scanned.")); - if (config.hasChanged()) - config.save(); - gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(Wrapper.class, new WrapperJson()).create(); - } - - @EventHandler - public void postInit(FMLPostInitializationEvent event) throws IOException { - if (recipeWrapFile.exists()) { - recipeWrappers = gson.fromJson(new BufferedReader(new FileReader(recipeWrapFile)), new TypeToken>() { - }.getType()); - if (recipeWrappers == null) - recipeWrappers = new ArrayList<>(); - } else { - recipeWrappers = Lists.newArrayList(); - recipeWrapFile.createNewFile(); - modHashFile.createNewFile(); - } - Map mods = Maps.newHashMap(); - Loader.instance().getActiveModList().forEach(m -> mods.put(m.getModId(), m.getVersion())); - for (String black : blacklist) - mods.remove(black); - Map fileMods = null; - if (modHashFile.exists()) { - fileMods = gson.fromJson(new BufferedReader(new FileReader(modHashFile)), new TypeToken>() { - }.getType()); - if (fileMods == null) - fileMods = Maps.newHashMap(); - } else { - modHashFile.createNewFile(); - fileMods = Maps.newHashMap(); - } - Set check = Sets.newHashSet(); - for (Map.Entry entry : mods.entrySet()) { - if (!fileMods.containsKey(entry.getKey()) || !fileMods.get(entry.getKey()).equals(entry.getValue())) - check.add(entry.getKey()); - // else { - // if (!fileMods.get(entry.getKey()).equals(entry.getValue())) - // check.add(entry.getKey()); - // } - } - if (!check.isEmpty()) { - recipeWrappers.removeIf(w -> check.contains(w.getIn().getItem().getRegistryName().getResourceDomain())); - recipeWrappers.addAll(Lists.newArrayList(getRecipes(check))); - } - recipeWrappers.removeIf(rw -> rw.getIn().isEmpty()); - recipeWrappers.forEach(rw -> rw.getOut().removeIf(d -> d.out.isEmpty())); - - Writer fw = new BufferedWriter(new FileWriter(modHashFile)); - fw.write(gson.toJson(mods)); - fw.close(); - fw = new BufferedWriter(new FileWriter(recipeWrapFile)); - fw.write(gson.toJson(recipeWrappers)); - fw.close(); - } - - public static List getRecipes(Collection ids) { - List res = Lists.newArrayList(); - Set stateSet = Sets.newHashSet(); - for (Block b : ForgeRegistries.BLOCKS) { - if (!ids.contains(b.getRegistryName().getResourceDomain()) || Item.getItemFromBlock(b) == null) - continue; - NonNullList lis = NonNullList.create(); - b.getSubBlocks(b.getCreativeTabToDisplayOn(), lis); - try { - List stacks = Lists.newArrayList(); - for (int i = 0; i < 16; i++) { - IBlockState st = b.getStateFromMeta(i); - for (ItemStack s : lis) - if (!s.isEmpty() && s.isItemEqual(getStack(st)) && !stacks.stream().anyMatch(ss -> ss.isItemEqual(s))) { - stateSet.add(st); - stacks.add(s); - } - } - } catch (Exception e) { - } - } - List states = Lists.newArrayList(stateSet); - states.sort((IBlockState o1, IBlockState o2) -> { - int id = Integer.compare(Block.getIdFromBlock(o1.getBlock()), Block.getIdFromBlock(o2.getBlock())); - int meta = Integer.compare(o1.getBlock().getMetaFromState(o1), o2.getBlock().getMetaFromState(o2)); - return id != 0 ? id : meta; - }); - - ProgressManager.ProgressBar bar = ProgressManager.push("Analysing Drops", states.size()); - ExecutorService threadPool = Executors.newCachedThreadPool(); // Pool to store all threads - Consumer task = (st) -> { - List drops; - bar.step(st.getBlock().getRegistryName().toString()); - try { - drops = getList(st); - } catch (Throwable e) { - // BlockDrops.logger.error("An error occured while calculating drops for " + st.getBlock().getLocalizedName() + " (" + e.getClass() + ")"); - drops = Collections.emptyList(); - } - if (drops.isEmpty()) - return; - res.add(new Wrapper(getStack(st), drops)); - }; - for (IBlockState st : states) { - if (multithreaded) { - threadPool.execute(() -> task.accept(st)); - } else - task.accept(st); - } - threadPool.shutdown(); - try { - threadPool.awaitTermination(1, TimeUnit.HOURS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - if (bar.getSteps() != bar.getStep()) - ReflectionHelper.setPrivateValue(ProgressBar.class, bar, bar.getSteps(), "step"); - ProgressManager.pop(bar); - return res; - - } - - private static List getList(IBlockState state) { - List drops = Lists.newArrayList(); - if (getStack(state).isEmpty()) - return drops; - List stacks0 = Lists.newArrayList(), stacks1 = Lists.newArrayList(), stacks2 = Lists.newArrayList(), stacks3 = Lists.newArrayList(); - Map> pairs0 = Maps.newHashMap(), pairs1 = Maps.newHashMap(), pairs2 = Maps.newHashMap(), pairs3 = Maps.newHashMap(); - boolean crashed = false; - for (int i = 0; i < BlockDrops.iteration; i++) { - for (int j = 0; j < 4; j++) { - List lis = Lists.newArrayList(state.getBlock().getDrops(FakeClientWorld.getInstance(), BlockPos.ORIGIN, state, j)); - if (!crashed) - try { - net.minecraftforge.event.ForgeEventFactory.fireBlockHarvesting(lis, FakeClientWorld.getInstance(), BlockPos.ORIGIN, state, j, 1f, false, FakeClientPlayer.getInstance()); - } catch (Throwable t) { - crashed = true; - } - lis.removeIf(ItemStack::isEmpty); - switch (j) { - case 0: - add(pairs0, lis); - break; - case 1: - add(pairs1, lis); - break; - case 2: - add(pairs2, lis); - break; - case 3: - add(pairs3, lis); - break; - } - for (ItemStack s : lis) { - switch (j) { - case 0: - add(stacks0, s); - break; - case 1: - add(stacks1, s); - break; - case 2: - add(stacks2, s); - break; - case 3: - add(stacks3, s); - break; - } - } - } - } - - List stacks = Lists.newArrayList(); - for (StackWrapper w : stacks0) - add(stacks, w.stack); - for (StackWrapper w : stacks1) - add(stacks, w.stack); - for (StackWrapper w : stacks2) - add(stacks, w.stack); - for (StackWrapper w : stacks3) - add(stacks, w.stack); - - if (!BlockDrops.all) { - stacks.removeIf(tmp -> tmp.stack.isItemEqual(getStack(state))); - } - stacks.sort((o1, o2) -> { - int id = Integer.compare(Item.getIdFromItem(o1.stack.getItem()), Item.getIdFromItem(o2.stack.getItem())); - int meta = Integer.compare(o1.stack.getItemDamage(), o2.stack.getItemDamage()); - return id != 0 ? id : meta; - }); - - for (int i = 0; i < stacks.size(); i++) { - StackWrapper stack = stacks.get(i); - float s0 = getChance(stacks0, stack.stack); - float s1 = getChance(stacks1, stack.stack); - float s2 = getChance(stacks2, stack.stack); - float s3 = getChance(stacks3, stack.stack); - if (!stack.stack.isEmpty()) - drops.add(new Drop(stack.stack, s0, s1, s2, s3, pairs0.get(stack), pairs1.get(stack), pairs2.get(stack), pairs3.get(stack))); - } - return drops; - - } - - private static float getChance(List stacks, ItemStack stack) { - if (!BlockDrops.showChance) - return 0f; - int con = contains(stacks, stack); - if (con == -1) - return 0F; - return 100F * ((float) stacks.get(con).size / (float) BlockDrops.iteration); - } - - private static int contains(List lis, ItemStack stack) { - for (int i = 0; i < lis.size(); i++) - if (lis.get(i).stack.isItemEqual(stack)) - return i; - return -1; - } - - private static void add(List lis, ItemStack stack) { - int con = contains(lis, stack); - if (con == -1) - lis.add(new StackWrapper(stack, stack.getCount())); - else { - StackWrapper tmp = lis.get(con); - tmp.size += stack.getCount(); - lis.set(con, tmp); - } - } - - private static void add(Map> map, List lis) { - List list = Lists.newArrayList(); - for (ItemStack s : lis) - add(list, s); - for (StackWrapper w : list) { - if (map.get(w) == null) - map.put(w, Pair.of(10000, 0)); - int min = map.get(w).getLeft(); - int max = map.get(w).getRight(); - Pair pair = Pair.of(Math.min(min, w.size), Math.max(max, w.size)); - map.put(w, pair); - } - } - - private static ItemStack getStack(IBlockState state) { - return state.getBlock().getPickBlock(state, new RayTraceResult(FakeClientPlayer.getInstance()), FakeClientWorld.getInstance(), BlockPos.ORIGIN, FakeClientPlayer.getInstance()); - } - - private static Field recipeLayouts, recipeWrapper; - - @SubscribeEvent - public static void key(KeyboardInputEvent.Post event) throws IllegalAccessException { - if (Minecraft.getMinecraft().currentScreen instanceof RecipesGui && Keyboard.getEventKeyState()) { - if (recipeLayouts == null) { - recipeLayouts = ReflectionHelper.findField(RecipesGui.class, "recipeLayouts"); - recipeWrapper = ReflectionHelper.findField(RecipeLayout.class, "recipeWrapper"); - } - MutableBoolean change = new MutableBoolean(false); - ((List) recipeLayouts.get(Minecraft.getMinecraft().currentScreen)).stream().map(rl -> { - try { - return recipeWrapper.get(rl); - } catch (IllegalArgumentException | IllegalAccessException e) { - return null; - } - }).filter(o -> o instanceof Wrapper).map(o -> (Wrapper) o)/*.collect(Collectors.toList())*/.forEach(w -> { - if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) { - w.decreaseIndex(); - change.setTrue(); - } else if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) { - w.increaseIndex(); - change.setTrue(); - } - }); - if (change.isTrue()) - ((RecipesGui) Minecraft.getMinecraft().currentScreen).onStateChange(); - } - } - -} diff --git a/src/main/java/mrriegel/blockdrops/Category.java b/src/main/java/mrriegel/blockdrops/Category.java deleted file mode 100644 index 6dbd33f..0000000 --- a/src/main/java/mrriegel/blockdrops/Category.java +++ /dev/null @@ -1,60 +0,0 @@ -package mrriegel.blockdrops; - -import mezz.jei.api.gui.IDrawable; -import mezz.jei.api.gui.IGuiItemStackGroup; -import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.IRecipeCategory; -import mezz.jei.gui.elements.DrawableBlank; -import net.minecraft.client.Minecraft; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.client.config.GuiUtils; - -public class Category implements IRecipeCategory { - - private ResourceLocation hopper = new ResourceLocation("textures/gui/container/hopper.png"); - - @Override - public String getUid() { - return BlockDrops.MODID; - } - - @Override - public String getTitle() { - return "Block Drops"; - } - - @Override - public IDrawable getBackground() { - return new DrawableBlank(180, 40); - } - - @Override - public void drawExtras(Minecraft minecraft) { - drawSlot(81, 1); - for (int i = 9; i < 170; i += 18) - drawSlot(i, 20); - } - - private void drawSlot(int x, int y) { - Minecraft.getMinecraft().getTextureManager().bindTexture(hopper); - GuiUtils.drawTexturedModalRect(x, y, 43, 19, 18, 18, 0); - } - - @Override - public void setRecipe(IRecipeLayout recipeLayout, Wrapper recipeWrapper, IIngredients ingredients) { - IGuiItemStackGroup itemStacks = recipeLayout.getItemStacks(); - itemStacks.init(0, true, 81, 1); - itemStacks.set(0, recipeWrapper.getInputs()); - itemStacks.addTooltipCallback(recipeWrapper); - for (int i = 0; i < Math.min(recipeWrapper.getOutputs().size(), 9); i++) { - itemStacks.init(i + 1, false, 9 + i * 18, 20); - itemStacks.set(i + 1, recipeWrapper.getOutputs().get((i + recipeWrapper.getIndex()))); - } - } - - @Override - public String getModName() { - return BlockDrops.MODNAME; - } -} \ No newline at end of file diff --git a/src/main/java/mrriegel/blockdrops/Plugin.java b/src/main/java/mrriegel/blockdrops/Plugin.java deleted file mode 100644 index 108a388..0000000 --- a/src/main/java/mrriegel/blockdrops/Plugin.java +++ /dev/null @@ -1,29 +0,0 @@ -package mrriegel.blockdrops; - -import mezz.jei.api.IModPlugin; -import mezz.jei.api.IModRegistry; -import mezz.jei.api.JEIPlugin; -import mezz.jei.api.recipe.IRecipeCategoryRegistration; -import net.minecraft.item.Item; -import net.minecraft.item.ItemPickaxe; -import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.common.registry.ForgeRegistries; - -@JEIPlugin -public class Plugin implements IModPlugin { - @Override - public void register(IModRegistry registry) { - registry.handleRecipes(Wrapper.class, r -> r, BlockDrops.MODID); - registry.addRecipes(BlockDrops.recipeWrappers, BlockDrops.MODID); - for (Item i : ForgeRegistries.ITEMS) { - if (i instanceof ItemPickaxe) - registry.addRecipeCatalyst(new ItemStack(i), BlockDrops.MODID); - } - } - - @Override - public void registerCategories(IRecipeCategoryRegistration registry) { - registry.addRecipeCategories(new Category()); - } - -} diff --git a/src/main/java/mrriegel/blockdrops/Wrapper.java b/src/main/java/mrriegel/blockdrops/Wrapper.java deleted file mode 100644 index 578f254..0000000 --- a/src/main/java/mrriegel/blockdrops/Wrapper.java +++ /dev/null @@ -1,137 +0,0 @@ -package mrriegel.blockdrops; - -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import mezz.jei.api.gui.ITooltipCallback; -import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.IRecipeWrapper; -import mrriegel.blockdrops.util.Drop; -import net.minecraft.client.resources.I18n; -import net.minecraft.item.ItemStack; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.text.TextFormatting; - -public class Wrapper implements IRecipeWrapper, ITooltipCallback { - - private ItemStack in; - private List out; - private int index = 0, maxIndex; - - public Wrapper(ItemStack in, List out) { - this.in = in; - this.out = out; - this.maxIndex = Math.max(0, out.size() - 9); - } - - public List getInputs() { - return Collections.singletonList(in); - } - - public List getOutputs() { - return out.stream().map(d -> d.out).collect(Collectors.toList()); - } - - private float chance(ItemStack s, int fortune) { - for (Drop d : out) - if (d.out.isItemEqual(s)) { - switch (fortune) { - case 0: - return d.chance0; - case 1: - return d.chance1; - case 2: - return d.chance2; - case 3: - return d.chance3; - default: - break; - } - } - return 0f; - } - - @Override - public String toString() { - return "Wrapper [in=" + in + ", out=" + out + "]"; - } - - private Pair pair(ItemStack s, int fortune) { - for (Drop d : out) - if (d.out.isItemEqual(s)) { - switch (fortune) { - case 0: - return d.pair0; - case 1: - return d.pair1; - case 2: - return d.pair2; - case 3: - return d.pair3; - default: - break; - } - } - return MutablePair.of(0, 0); - } - - @Override - public void onTooltip(int slotIndex, boolean input, ItemStack ingredient, List tooltip) { - if (!input) { - boolean one = IntStream.range(0, 4).mapToObj(i -> Float.floatToIntBits(chance(ingredient, i))).distinct().count() == 1; - for (int x = 0; x < (one ? 1 : 4); x++) { - String chance = BlockDrops.showChance ? String.format("%.2f", chance(ingredient, (int) x)) + " % " : ""; - String minmax = BlockDrops.showMinMax ? "Min: " + pair(ingredient, (int) x).getLeft() + " Max: " + pair(ingredient, (int) x).getRight() : ""; - if (BlockDrops.showChance || BlockDrops.showMinMax) - tooltip.add((one ? "" : TextFormatting.BLUE + "Fortune " + (0l != x ? I18n.format("enchantment.level." + x) : 0) + " ") + TextFormatting.GRAY + chance + minmax); - } - if (out.size() > 9) - tooltip.add(TextFormatting.RED + "There are too many possible drops. Use left and right key to cycle."); - } - } - - public ItemStack getIn() { - return in; - } - - public void setIn(ItemStack in) { - this.in = in; - } - - public List getOut() { - return out; - } - - public void setOut(List out) { - this.out = out; - this.maxIndex = Math.max(0, out.size() - 9); - } - - @Override - public void getIngredients(IIngredients ingredients) { - ingredients.setInputs(ItemStack.class, getInputs()); - ingredients.setOutputs(ItemStack.class, getOutputs()); - } - - public int getIndex() { - return index; - } - - public void setIndex(int index) { - this.index = MathHelper.clamp(index, 0, maxIndex); - } - - public void increaseIndex() { - this.index = MathHelper.clamp(index + 1, 0, maxIndex); - } - - public void decreaseIndex() { - this.index = MathHelper.clamp(index - 1, 0, maxIndex); - } - -} \ No newline at end of file diff --git a/src/main/java/mrriegel/blockdrops/util/Drop.java b/src/main/java/mrriegel/blockdrops/util/Drop.java deleted file mode 100644 index 2a27a77..0000000 --- a/src/main/java/mrriegel/blockdrops/util/Drop.java +++ /dev/null @@ -1,69 +0,0 @@ -package mrriegel.blockdrops.util; - -import org.apache.commons.lang3.tuple.Pair; - -import net.minecraft.item.ItemStack; -import net.minecraftforge.items.ItemHandlerHelper; - -public class Drop { - public ItemStack out; - public float chance0, chance1, chance2, chance3; - public Pair pair0, pair1, pair2, pair3; - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Drop other = (Drop) obj; - if (Float.floatToIntBits(chance0) != Float.floatToIntBits(other.chance0)) - return false; - if (Float.floatToIntBits(chance1) != Float.floatToIntBits(other.chance1)) - return false; - if (Float.floatToIntBits(chance2) != Float.floatToIntBits(other.chance2)) - return false; - if (Float.floatToIntBits(chance3) != Float.floatToIntBits(other.chance3)) - return false; - if (out == null) { - if (other.out != null) - return false; - } else if (!out.isItemEqual(other.out)) - return false; - return true; - } - - public Drop(ItemStack out, float chance0, float chance1, float chance2, float chance3, Pair pair0, Pair pair1, Pair pair2, Pair pair3) { - super(); - this.out = ItemHandlerHelper.copyStackWithSize(out, 1); - this.chance0 = chance0; - this.chance1 = chance1; - this.chance2 = chance2; - this.chance3 = chance3; - - this.pair0 = pair0; - if (this.pair0 == null) - this.pair0 = Pair.of(0, 0); - this.pair1 = pair1; - if (this.pair1 == null) - this.pair1 = Pair.of(0, 0); - this.pair2 = pair2; - if (this.pair2 == null) - this.pair2 = Pair.of(0, 0); - this.pair3 = pair3; - if (this.pair3 == null) - this.pair3 = Pair.of(0, 0); - - if (this.chance0 < 100) - this.pair0 = Pair.of(0, this.pair0.getRight()); - if (this.chance1 < 100) - this.pair1 = Pair.of(0, this.pair1.getRight()); - if (this.chance2 < 100) - this.pair2 = Pair.of(0, this.pair2.getRight()); - if (this.chance3 < 100) - this.pair3 = Pair.of(0, this.pair3.getRight()); - } - -} diff --git a/src/main/java/mrriegel/blockdrops/util/FakeClientPlayer.java b/src/main/java/mrriegel/blockdrops/util/FakeClientPlayer.java deleted file mode 100644 index 84fb123..0000000 --- a/src/main/java/mrriegel/blockdrops/util/FakeClientPlayer.java +++ /dev/null @@ -1,40 +0,0 @@ -package mrriegel.blockdrops.util; - -import java.util.UUID; - -import javax.annotation.Nullable; - -import com.mojang.authlib.GameProfile; - -import net.minecraft.entity.player.EntityPlayer; - -/** - * - * @author mezz - * - */ -public class FakeClientPlayer extends EntityPlayer { - @Nullable - private static FakeClientPlayer INSTANCE; - - public static FakeClientPlayer getInstance() { - if (INSTANCE == null) { - INSTANCE = new FakeClientPlayer(); - } - return INSTANCE; - } - - private FakeClientPlayer() { - super(FakeClientWorld.getInstance(), new GameProfile(new UUID(0, 0), "JEI_Fake")); - } - - @Override - public boolean isSpectator() { - return false; - } - - @Override - public boolean isCreative() { - return false; - } -} \ No newline at end of file diff --git a/src/main/java/mrriegel/blockdrops/util/FakeClientWorld.java b/src/main/java/mrriegel/blockdrops/util/FakeClientWorld.java deleted file mode 100644 index 782e18b..0000000 --- a/src/main/java/mrriegel/blockdrops/util/FakeClientWorld.java +++ /dev/null @@ -1,98 +0,0 @@ -package mrriegel.blockdrops.util; - -import javax.annotation.Nullable; - -import net.minecraft.block.state.IBlockState; -import net.minecraft.init.Blocks; -import net.minecraft.profiler.Profiler; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.DimensionType; -import net.minecraft.world.GameType; -import net.minecraft.world.World; -import net.minecraft.world.WorldProvider; -import net.minecraft.world.WorldSettings; -import net.minecraft.world.WorldType; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.EmptyChunk; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.storage.ISaveHandler; -import net.minecraft.world.storage.SaveDataMemoryStorage; -import net.minecraft.world.storage.SaveHandlerMP; -import net.minecraft.world.storage.WorldInfo; - -/** - * - * @author mezz - * - */ -public class FakeClientWorld extends World { - private static final WorldSettings worldSettings = new WorldSettings(0, GameType.SURVIVAL, false, false, WorldType.DEFAULT); - private static final WorldInfo worldInfo = new WorldInfo(worldSettings, "jei_fake"); - private static final ISaveHandler saveHandler = new SaveHandlerMP(); - private static final WorldProvider worldProvider = new WorldProvider() { - @Override - public DimensionType getDimensionType() { - return DimensionType.OVERWORLD; - } - }; - @Nullable - private static FakeClientWorld INSTANCE; - - public static FakeClientWorld getInstance() { - if (INSTANCE == null) { - INSTANCE = new FakeClientWorld(); - } - return INSTANCE; - } - - private FakeClientWorld() { - super(saveHandler, worldInfo, worldProvider, new Profiler(), /*hacky*/false); - this.provider.setWorld(this); - this.mapStorage = new SaveDataMemoryStorage(); - } - - @Override - public BlockPos getSpawnPoint() { - return new BlockPos(0, 0, 0); - } - - @Override - public IBlockState getBlockState(BlockPos pos) { - return Blocks.AIR.getDefaultState(); - } - - @Override - protected IChunkProvider createChunkProvider() { - return new IChunkProvider() { - @Override - public Chunk getLoadedChunk(int x, int z) { - return new EmptyChunk(FakeClientWorld.this, x, z); - } - - @Override - public Chunk provideChunk(int x, int z) { - return new EmptyChunk(FakeClientWorld.this, x, z); - } - - @Override - public boolean tick() { - return false; - } - - @Override - public String makeString() { - return ""; - } - - @Override - public boolean isChunkGeneratedAt(int p_191062_1_, int p_191062_2_) { - return false; - } - }; - } - - @Override - protected boolean isChunkLoaded(int x, int z, boolean allowEmpty) { - return false; - } -} diff --git a/src/main/java/mrriegel/blockdrops/util/StackWrapper.java b/src/main/java/mrriegel/blockdrops/util/StackWrapper.java deleted file mode 100644 index 8acf9c9..0000000 --- a/src/main/java/mrriegel/blockdrops/util/StackWrapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package mrriegel.blockdrops.util; - -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraftforge.items.ItemHandlerHelper; - -public class StackWrapper { - public ItemStack stack; - public int size; - - @Override - public boolean equals(Object obj) { - if (obj instanceof StackWrapper) - return ItemHandlerHelper.canItemStacksStack(stack, ((StackWrapper) obj).stack); - return false; - } - - public StackWrapper(ItemStack stack, int num) { - super(); - this.stack = stack; - this.size = num; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + Item.getIdFromItem(stack.getItem()); - result = prime * result + stack.getItemDamage(); - result = prime * result + (stack.getTagCompound() == null ? 0 : stack.getTagCompound().hashCode()); - return result; - } -} diff --git a/src/main/java/mrriegel/blockdrops/util/WrapperJson.java b/src/main/java/mrriegel/blockdrops/util/WrapperJson.java deleted file mode 100644 index e410ff5..0000000 --- a/src/main/java/mrriegel/blockdrops/util/WrapperJson.java +++ /dev/null @@ -1,86 +0,0 @@ -package mrriegel.blockdrops.util; - -import java.lang.reflect.Type; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.lang3.tuple.MutablePair; - -import com.google.common.collect.Lists; -import com.google.common.reflect.TypeToken; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; - -import mrriegel.blockdrops.BlockDrops; -import mrriegel.blockdrops.Wrapper; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.fml.common.registry.ForgeRegistries; - -public class WrapperJson implements JsonDeserializer, JsonSerializer { - - @Override - public JsonElement serialize(Wrapper src, Type typeOfSrc, JsonSerializationContext context) { - JsonObject json = new JsonObject(); - ItemStack stack = src.getIn(); - json.addProperty("name", stack.getItem().getRegistryName().toString()); - json.addProperty("meta", stack.getItemDamage()); - json.addProperty("length", src.getOut().size()); - for (int i = 0; i < src.getOut().size(); i++) { - Drop d = src.getOut().get(i); - json.addProperty("name" + i, d.out.getItem().getRegistryName().toString()); - json.addProperty("meta" + i, d.out.getItemDamage()); - json.addProperty("0chance" + i, d.chance0); - json.addProperty("1chance" + i, d.chance1); - json.addProperty("2chance" + i, d.chance2); - json.addProperty("3chance" + i, d.chance3); - json.addProperty("0pair" + i, BlockDrops.gson.toJson(d.pair0)); - json.addProperty("1pair" + i, BlockDrops.gson.toJson(d.pair1)); - json.addProperty("2pair" + i, BlockDrops.gson.toJson(d.pair2)); - json.addProperty("3pair" + i, BlockDrops.gson.toJson(d.pair3)); - } - - return json; - } - - @SuppressWarnings("serial") - @Override - public Wrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - Wrapper wrap = new Wrapper(null, Collections.EMPTY_LIST); - String name = json.getAsJsonObject().get("name").getAsString(); - int meta = json.getAsJsonObject().get("meta").getAsInt(); - ItemStack stack = new ItemStack(ForgeRegistries.ITEMS.getValue(new ResourceLocation(name)), 1, meta); - wrap.setIn(stack); - - int length = json.getAsJsonObject().get("length").getAsInt(); - List lis = Lists.newArrayList(); - for (int i = 0; i < length; i++) { - Drop d = new Drop(ItemStack.EMPTY, 0, 0, 0, 0, null, null, null, null); - String n = json.getAsJsonObject().get("name" + i).getAsString(); - int m = json.getAsJsonObject().get("meta" + i).getAsInt(); - ItemStack st = new ItemStack(ForgeRegistries.ITEMS.getValue(new ResourceLocation(n)), 1, m); - d.out = st; - d.chance0 = json.getAsJsonObject().get("0chance" + i).getAsFloat(); - d.chance1 = json.getAsJsonObject().get("1chance" + i).getAsFloat(); - d.chance2 = json.getAsJsonObject().get("2chance" + i).getAsFloat(); - d.chance3 = json.getAsJsonObject().get("3chance" + i).getAsFloat(); - d.pair0 = BlockDrops.gson.fromJson(json.getAsJsonObject().get("0pair" + i).getAsString(), new TypeToken>() { - }.getType()); - d.pair1 = BlockDrops.gson.fromJson(json.getAsJsonObject().get("1pair" + i).getAsString(), new TypeToken>() { - }.getType()); - d.pair2 = BlockDrops.gson.fromJson(json.getAsJsonObject().get("2pair" + i).getAsString(), new TypeToken>() { - }.getType()); - d.pair3 = BlockDrops.gson.fromJson(json.getAsJsonObject().get("3pair" + i).getAsString(), new TypeToken>() { - }.getType()); - lis.add(d); - } - wrap.setOut(lis); - return wrap; - } - -} diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..9a96083 --- /dev/null +++ b/src/main/resources/META-INF/mods.toml @@ -0,0 +1,33 @@ +modLoader="javafml" +loaderVersion="[32,)" +issueTrackerURL="http://my.issue.tracker/" + +[[mods]] +modId="blockdrops" +version="2.0.2" +displayName="Block Drops" +displayURL="https://www.curseforge.com/minecraft/mc-mods/blockdrops" +credits="Thanks for this example mod goes to Java" +authors="KidsDontPlay, MorningSage" +description=''' + +''' + +[[dependencies.blockdrops]] + modId="forge" + mandatory=true + versionRange="[32,)" + ordering="NONE" + side="BOTH" +[[dependencies.blockdrops]] + modId="minecraft" + mandatory=true + versionRange="[1.16,)" + ordering="NONE" + side="BOTH" +[[dependencies.blockdrops]] + modId="jei" + mandatory=true + versionRange="[7.0.1.10,)" + ordering="NONE" + side="BOTH" \ No newline at end of file diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info deleted file mode 100644 index e145db4..0000000 --- a/src/main/resources/mcmod.info +++ /dev/null @@ -1,16 +0,0 @@ -[ -{ - "modid": "blockdrops", - "name": "Block Drops", - "description": "Block Drops (JEI Addon)", - "version": "${version}", - "mcversion": "${mcversion}", - "url": "", - "updateUrl": "", - "authorList": ["MrRiegel"], - "credits": "The Forge and FML guys", - "logoFile": "", - "screenshots": [], - "dependencies": ["jei"] -} -] diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..1147d8a --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,7 @@ +{ + "pack": { + "description": "blockdrops", + "pack_format": 4, + "_comment": "A pack_format of 4 requires json lang files. Note: we require v4 pack meta for all mods." + } +}