diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6c9b3cbc..a60a2b64 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,7 @@ jobs: run: | mkdir run echo "eula=true" > run/eula.txt - timeout 10 ./gradlew runServer || true + timeout 60 ./gradlew runServer || true - name: Test no crashes happend run: | diff --git a/.gitignore b/.gitignore index 40fb5e4a..fe92f881 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ whitelist.json *.ipr *.iws src/main/resources/mixins.*.json +dependencies/voxelmap*.jar +/data/ *.bat diff --git a/BON2-2.5.0.CUSTOM-all.jar b/BON2-2.5.0.CUSTOM-all.jar new file mode 100644 index 00000000..0445b5ed Binary files /dev/null and b/BON2-2.5.0.CUSTOM-all.jar differ diff --git a/README.md b/README.md index a2c539a4..fd549da7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ### For Minecraft 1.7.10 -This mod is intended for player convenience, but may also be used as API, since it provides the location of all GT ore veins in a cache. VisualProspecting tracks all GT Ore Veins a player has found and visualizes them in JourneyMap and/or XaeroWorldMap (optional, if installed). It also visualizes tracked Thaumcraft aura nodes if TCNodeTracker if installed. +This mod is intended for player convenience, but may also be used as API, since it provides the location of all GT ore veins in a cache. VisualProspecting tracks all GT Ore Veins a player has found and visualizes them in JourneyMap and/or XaeroWorldMap (optional, if installed). It also visualizes tracked Thaumcraft aura nodes if TCNodeTracker if installed. VoxelMap will add waypoints for prospected ore veins and fluids. VisualProspecting tracks all ores that a player interacted with, by right or by left click. It also integrates prospecting data from GTs _Advanced Seismic Prospector_, although only books that are created after this mod was added will provide integration. You may share your findings with other players by crafting a _Prospector's Log_. @@ -52,6 +52,7 @@ You may use JourneyMap's Actions Menu to achieve this or type `/visualprospectin Does VisualProspecting run with other maps? - I runs just fine, but it has no visualization or GUI integration. If you like to add integration into other maps yourself, feel free to contact me or open a Pull Request. - [TheLastKumquat](https://github.com/kumquat-ir) integrated XaeroWorldMap and XaeroMiniMap + - [glowredman](https://github.com/glowredman) integrated VoxelMap ### Dependencies @@ -77,6 +78,9 @@ Does VisualProspecting run with other maps? - I runs just fine, but it has no vi - Injected class: [_GT_Worldgenerator_Space_](https://github.com/SinTh0r4s/VisualProspecting/blob/master/src/main/java/com/sinthoras/visualprospecting/mixins/galacticgreg/GT_Worldgenerator_SpaceMixin.java) - [Bartworks](https://github.com/GTNewHorizons/bartworks): Injects a notification call into ore vein generation. - Injected class: [_BW_WordGenerator.WorldGenContainer_](https://github.com/SinTh0r4s/VisualProspecting/blob/master/src/main/java/com/sinthoras/visualprospecting/mixins/bartworks/WorldGenContainerMixin.java) + - [IFU](https://github.com/GTNewHorizons/IFU): Injects a notification call to add found ore veins by the ore finder wand. + - Injected class: [_ItemOreFinderTool_](https://github.com/SinTh0r4s/VisualProspecting/blob/master/src/main/java/com/sinthoras/visualprospecting/mixins/ifu/ItemOreFinderToolMixin.java) + - [VoxelMap](https://www.curseforge.com/minecraft/mc-mods/voxelmap/files/2462146): Automatically adds waypoints for prospected ore veins and fluids. ### Add Visual Prospecting as API diff --git a/addon.gradle b/addon.gradle new file mode 100644 index 00000000..ed7fac06 --- /dev/null +++ b/addon.gradle @@ -0,0 +1,37 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'de.undercouch:gradle-download-task:4.1.2' + } +} + +import de.undercouch.gradle.tasks.download.Download + +def voxelMapFile = file("data/voxelmap_1.7.0b.jar") +def voxelMapFileDeobf = file("dependencies/voxelmap_1.7.0b-deobf.jar") + +task getVoxelMap(type: Download) { + onlyIf { + !voxelMapFile.exists() + } + src "https://media.forgecdn.net/files/2462/146/mod_voxelMap_1.7.0b_for_1.7.10.litemod" //direct link to VoxelMap on CurseForge + dest voxelMapFile + mustRunAfter "deobfBinJar" + mustRunAfter "repackMinecraft" +} + +task deobfVoxelMap(dependsOn: getVoxelMap, type: Exec) { + onlyIf { + !voxelMapFileDeobf.exists() + } + // VoxelMap uese Notch names, so we have to deobfuscate them + // Source for the BON2 version used: https://github.com/glowredman/BON2/tree/Official + commandLine 'java', '-jar', 'BON2-2.5.0.CUSTOM-all.jar', '--inputJar', voxelMapFile, '--outputJar', voxelMapFileDeobf, '--mcVer', '1.7.10', '--mappingsVer', 'stable_12-1.7.10', '--notch' +} + +tasks.setupCIWorkspace.dependsOn deobfVoxelMap +tasks.setupDevWorkspace.dependsOn deobfVoxelMap +tasks.setupDecompWorkspace.dependsOn deobfVoxelMap +tasks.compileJava.dependsOn deobfVoxelMap diff --git a/dependencies.gradle b/dependencies.gradle index f4090f78..b4033245 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,12 +1,14 @@ dependencies { shadowImplementation("com.github.SinTh0r4s:Enklume:master-SNAPSHOT") + compile("com.github.GTNewHorizons:GT5-Unofficial:master-SNAPSHOT:dev") compile("com.github.GTNewHorizons:TCNodeTracker:master-SNAPSHOT:dev") compile("curse.maven:journeymap-32274:2367915") - compile files("libs/Xaeros_Minimap_21.10.11_Forge_1.7.10-deobf") - compile files("libs/XaerosWorldMap_1.14.1.10_Forge_1.7.10-deobf") + compile files("dependencies/Xaeros_Minimap_21.10.14_Forge_1.7.10-deobf.jar") + compile files("dependencies/XaerosWorldMap_1.14.1.11_Forge_1.7.10-deobf.jar") + compileOnly files("dependencies/voxelmap_1.7.0b-deobf.jar") compileOnly("com.github.GTNewHorizons:IFU:master-SNAPSHOT:dev") { transitive = false diff --git a/libs/XaerosWorldMap_1.14.1.10_Forge_1.7.10-deobf.jar b/dependencies/XaerosWorldMap_1.14.1.11_Forge_1.7.10-deobf.jar similarity index 85% rename from libs/XaerosWorldMap_1.14.1.10_Forge_1.7.10-deobf.jar rename to dependencies/XaerosWorldMap_1.14.1.11_Forge_1.7.10-deobf.jar index 4b685a6e..e2a0822d 100644 Binary files a/libs/XaerosWorldMap_1.14.1.10_Forge_1.7.10-deobf.jar and b/dependencies/XaerosWorldMap_1.14.1.11_Forge_1.7.10-deobf.jar differ diff --git a/libs/Xaeros_Minimap_21.10.11_Forge_1.7.10-deobf.jar b/dependencies/Xaeros_Minimap_21.10.14_Forge_1.7.10-deobf.jar similarity index 82% rename from libs/Xaeros_Minimap_21.10.11_Forge_1.7.10-deobf.jar rename to dependencies/Xaeros_Minimap_21.10.14_Forge_1.7.10-deobf.jar index a51e02f6..c31265a8 100644 Binary files a/libs/Xaeros_Minimap_21.10.11_Forge_1.7.10-deobf.jar and b/dependencies/Xaeros_Minimap_21.10.14_Forge_1.7.10-deobf.jar differ diff --git a/src/main/java/com/sinthoras/visualprospecting/Config.java b/src/main/java/com/sinthoras/visualprospecting/Config.java index 5f983653..100a85f9 100644 --- a/src/main/java/com/sinthoras/visualprospecting/Config.java +++ b/src/main/java/com/sinthoras/visualprospecting/Config.java @@ -17,12 +17,14 @@ private static class Defaults { public static final int minZoomLevelForUndergroundFluidDetails = 2; public static final int uploadBandwidthBytes = 2000000; public static final int maxTransferCacheSizeMB = 50; + public static final boolean enableVoxelMapWaypointsByDefault = false; public static final int maxDimensionSizeMBForFastScanning = 10000; } private static class Categories { public static final String general = "general"; public static final String network = "network"; + public static final String integration = "integration"; public static final String caching = "caching"; } @@ -37,6 +39,7 @@ private static class Categories { public static double uploadBandwidthBytes = Defaults.uploadBandwidthBytes; public static int uploadSizePerPacket = (int)(uploadBandwidthBytes / uploadPacketsPerSecond); public static int maxTransferCacheSizeMB = Defaults.maxTransferCacheSizeMB; + public static boolean enableVoxelMapWaypointsByDefault = Defaults.enableVoxelMapWaypointsByDefault; public static int maxDimensionSizeMBForFastScanning = Defaults.maxDimensionSizeMBForFastScanning; @@ -84,6 +87,10 @@ public static void syncronizeConfiguration(File configFile) { if(recacheVeins) { recacheVeinsProperty.set(false); } + + Property enableVoxelMapWaypointsByDefaultProperty = configuration.get(Categories.integration, "enableVoxelMapWaypointsByDefault", Defaults.enableVoxelMapWaypointsByDefault, + "[CLIENT / VoxelMap] Enable waypoints added by prospecting GT ore veins or underground fluids by default"); + enableVoxelMapWaypointsByDefault = enableVoxelMapWaypointsByDefaultProperty.getBoolean(); Property maxDimensionSizeMBForFastScanningProperty = configuration.get(Categories.caching, "maxDimensionSizeMBForFastScanning", Defaults.maxDimensionSizeMBForFastScanning, "[Client + Server] Define the maximum size of a " + diff --git a/src/main/java/com/sinthoras/visualprospecting/Utils.java b/src/main/java/com/sinthoras/visualprospecting/Utils.java index 36eef6a7..f5fe456a 100644 --- a/src/main/java/com/sinthoras/visualprospecting/Utils.java +++ b/src/main/java/com/sinthoras/visualprospecting/Utils.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.sinthoras.visualprospecting.hooks.HooksClient; + import cpw.mods.fml.common.Loader; import net.minecraft.client.Minecraft; import net.minecraft.launchwrapper.Launch; @@ -44,6 +45,17 @@ public static boolean isJourneyMapInstalled() { public static boolean isXaerosWorldMapInstalled() { return Loader.isModLoaded("XaeroWorldMap"); } + + public static boolean isVoxelMapInstalled() { + try { + // If a LiteLoader mod is present cannot be checked by calling Loader#isModLoaded. + // Instead, we check if the VoxelMap main class is present. + Class.forName("com.thevoxelbox.voxelmap.litemod.LiteModVoxelMap"); + return true; + } catch (Exception e) { + return false; + } + } public static int coordBlockToChunk(int blockCoord) { return blockCoord < 0 ? -((-blockCoord - 1) >> 4) - 1 : blockCoord >> 4; diff --git a/src/main/java/com/sinthoras/visualprospecting/database/ClientCache.java b/src/main/java/com/sinthoras/visualprospecting/database/ClientCache.java index 644ad089..ea7e23f3 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/ClientCache.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/ClientCache.java @@ -1,6 +1,7 @@ package com.sinthoras.visualprospecting.database; import com.sinthoras.visualprospecting.*; +import com.sinthoras.visualprospecting.hooks.ProspectingNotificationEvent; import com.sinthoras.visualprospecting.network.ProspectingRequest; import gregtech.common.blocks.GT_TileEntity_Ores; import net.minecraft.client.Minecraft; @@ -12,6 +13,7 @@ import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; import java.io.File; import java.util.ArrayList; @@ -44,6 +46,7 @@ public void putOreVeins(List oreVeinPositions) { if(oreVeinPositions.size() == 1) { final OreVeinPosition oreVeinPosition = oreVeinPositions.get(0); if(putOreVein(oreVeinPosition) != DimensionCache.UpdateResult.AlreadyKnown) { + MinecraftForge.EVENT_BUS.post(new ProspectingNotificationEvent.OreVein(oreVeinPosition)); notifyNewOreVein(oreVeinPosition); } } @@ -51,6 +54,7 @@ else if(oreVeinPositions.size() > 1) { int newOreVeins = 0; for(OreVeinPosition oreVeinPosition : oreVeinPositions) { if(putOreVein(oreVeinPosition) != DimensionCache.UpdateResult.AlreadyKnown) { + MinecraftForge.EVENT_BUS.post(new ProspectingNotificationEvent.OreVein(oreVeinPosition)); newOreVeins++; } } @@ -73,9 +77,11 @@ public void putUndergroundFluids(List undergroundFluid for(UndergroundFluidPosition undergroundFluidPosition : undergroundFluids) { DimensionCache.UpdateResult updateResult = putUndergroundFluids(undergroundFluidPosition); if(updateResult == DimensionCache.UpdateResult.New) { + MinecraftForge.EVENT_BUS.post(new ProspectingNotificationEvent.UndergroundFluid(undergroundFluidPosition)); newUndergroundFluids++; } - if(updateResult == DimensionCache.UpdateResult.Updated) { + else if(updateResult == DimensionCache.UpdateResult.Updated) { + MinecraftForge.EVENT_BUS.post(new ProspectingNotificationEvent.UndergroundFluid(undergroundFluidPosition)); updatedUndergroundFluids++; } } diff --git a/src/main/java/com/sinthoras/visualprospecting/database/OreVeinPosition.java b/src/main/java/com/sinthoras/visualprospecting/database/OreVeinPosition.java index a1c3134e..f2ecd2a6 100644 --- a/src/main/java/com/sinthoras/visualprospecting/database/OreVeinPosition.java +++ b/src/main/java/com/sinthoras/visualprospecting/database/OreVeinPosition.java @@ -39,7 +39,7 @@ public int getBlockZ() { } public boolean isDepleted() { - return depleted; + return depleted; } public void toggleDepleted() { diff --git a/src/main/java/com/sinthoras/visualprospecting/hooks/HooksClient.java b/src/main/java/com/sinthoras/visualprospecting/hooks/HooksClient.java index 8929a569..d3702b6a 100644 --- a/src/main/java/com/sinthoras/visualprospecting/hooks/HooksClient.java +++ b/src/main/java/com/sinthoras/visualprospecting/hooks/HooksClient.java @@ -1,7 +1,10 @@ package com.sinthoras.visualprospecting.hooks; +import com.sinthoras.visualprospecting.Utils; import com.sinthoras.visualprospecting.VP; import com.sinthoras.visualprospecting.database.ResetClientCacheCommand; +import com.sinthoras.visualprospecting.integration.voxelmap.VoxelMapEventHandler; + import cpw.mods.fml.client.registry.ClientRegistry; import cpw.mods.fml.common.event.FMLInitializationEvent; import cpw.mods.fml.common.event.FMLPostInitializationEvent; @@ -13,6 +16,8 @@ import cpw.mods.fml.common.event.FMLServerStoppingEvent; import net.minecraft.client.settings.KeyBinding; import net.minecraftforge.client.ClientCommandHandler; +import net.minecraftforge.common.MinecraftForge; + import org.lwjgl.input.Keyboard; public class HooksClient extends HooksShared { @@ -37,6 +42,9 @@ public void fmlLifeCycleEvent(FMLInitializationEvent event) { public void fmlLifeCycleEvent(FMLPostInitializationEvent event) { super.fmlLifeCycleEvent(event); ClientCommandHandler.instance.registerCommand(new ResetClientCacheCommand()); + if(Utils.isVoxelMapInstalled()) { + MinecraftForge.EVENT_BUS.register(new VoxelMapEventHandler()); + } } @Override diff --git a/src/main/java/com/sinthoras/visualprospecting/hooks/ProspectingNotificationEvent.java b/src/main/java/com/sinthoras/visualprospecting/hooks/ProspectingNotificationEvent.java new file mode 100644 index 00000000..448f05df --- /dev/null +++ b/src/main/java/com/sinthoras/visualprospecting/hooks/ProspectingNotificationEvent.java @@ -0,0 +1,43 @@ +package com.sinthoras.visualprospecting.hooks; + +import com.sinthoras.visualprospecting.database.OreVeinPosition; +import com.sinthoras.visualprospecting.database.UndergroundFluidPosition; + +import cpw.mods.fml.common.eventhandler.Event; + +public class ProspectingNotificationEvent extends Event { + + @Override + public boolean isCancelable() { + return false; + } + + public static class OreVein extends ProspectingNotificationEvent { + + private final OreVeinPosition position; + + public OreVein(OreVeinPosition position) { + this.position = position; + } + + public OreVeinPosition getPosition() { + return this.position; + } + + } + + public static class UndergroundFluid extends ProspectingNotificationEvent { + + private final UndergroundFluidPosition position; + + public UndergroundFluid(UndergroundFluidPosition position) { + this.position = position; + } + + public UndergroundFluidPosition getPosition() { + return this.position; + } + + } + +} diff --git a/src/main/java/com/sinthoras/visualprospecting/integration/voxelmap/IWaypointManagerReflection.java b/src/main/java/com/sinthoras/visualprospecting/integration/voxelmap/IWaypointManagerReflection.java new file mode 100644 index 00000000..68d915a0 --- /dev/null +++ b/src/main/java/com/sinthoras/visualprospecting/integration/voxelmap/IWaypointManagerReflection.java @@ -0,0 +1,31 @@ +package com.sinthoras.visualprospecting.integration.voxelmap; + +import java.lang.reflect.Method; + +import com.sinthoras.visualprospecting.VP; +import com.thevoxelbox.voxelmap.interfaces.IWaypointManager; + +public class IWaypointManagerReflection { + + private static Method getCurrentSubworldDescriptor; + + public static String getCurrentSubworldDescriptor(IWaypointManager obj, boolean arg) { + try { + return (String) getCurrentSubworldDescriptor.invoke(obj, arg); + } catch (Exception e) { + VP.error("Could not invoke IWaypointManager#if. If it failed due to a NullPointerException, look for an error message starting with \"Getting the method IWaypointManager#if failed\" further up."); + e.printStackTrace(); + } + return ""; + } + + static { + try { + getCurrentSubworldDescriptor = IWaypointManager.class.getMethod("if", boolean.class); + } catch (Exception e) { + VP.error("Getting the method IWaypointManager#if failed, any calls to IWaypointManagerReflection#getCurrentSubworldDescriptor will return an empty String."); + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/sinthoras/visualprospecting/integration/voxelmap/VoxelMapEventHandler.java b/src/main/java/com/sinthoras/visualprospecting/integration/voxelmap/VoxelMapEventHandler.java new file mode 100644 index 00000000..da609e09 --- /dev/null +++ b/src/main/java/com/sinthoras/visualprospecting/integration/voxelmap/VoxelMapEventHandler.java @@ -0,0 +1,86 @@ +package com.sinthoras.visualprospecting.integration.voxelmap; + +import java.util.TreeSet; + +import com.sinthoras.visualprospecting.Config; +import com.sinthoras.visualprospecting.Utils; +import com.sinthoras.visualprospecting.database.OreVeinPosition; +import com.sinthoras.visualprospecting.database.UndergroundFluidPosition; +import com.sinthoras.visualprospecting.hooks.ProspectingNotificationEvent; +import com.thevoxelbox.voxelmap.interfaces.AbstractVoxelMap; +import com.thevoxelbox.voxelmap.interfaces.IWaypointManager; +import com.thevoxelbox.voxelmap.util.Waypoint; + +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import gregtech.api.GregTech_API; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityClientPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.util.StatCollector; + +public class VoxelMapEventHandler { + + @SubscribeEvent + public void onVeinProspected(ProspectingNotificationEvent.OreVein event) { + if(event.isCanceled()) { + return; + } + + OreVeinPosition pos = event.getPosition(); + IWaypointManager waypointManager = AbstractVoxelMap.getInstance().getWaypointManager(); + short[] color = GregTech_API.sGeneratedMaterials[pos.veinType.primaryOreMeta].getRGBA(); + TreeSet dim = new TreeSet<>(); + dim.add(pos.dimensionId); + + waypointManager.addWaypoint(new Waypoint( + StatCollector.translateToLocal(pos.veinType.name), // name + pos.getBlockX(), // X + pos.getBlockZ(), // Z + getY(), // Y + Config.enableVoxelMapWaypointsByDefault, // enabled + (float) color[0] / 255.0f, // red + (float) color[1] / 255.0f, // green + (float) color[2] / 255.0f, // blue + "Pickaxe", // icon + IWaypointManagerReflection.getCurrentSubworldDescriptor(waypointManager, false), // world + dim)); // dimension + } + + @SubscribeEvent + public void onFluidProspected(ProspectingNotificationEvent.UndergroundFluid event) { + if(event.isCanceled()) { + return; + } + + UndergroundFluidPosition pos = event.getPosition(); + IWaypointManager waypointManager = AbstractVoxelMap.getInstance().getWaypointManager(); + int x = Utils.coordChunkToBlock(pos.chunkX); + int z = Utils.coordChunkToBlock(pos.chunkZ); + int color = pos.fluid.getColor(); + TreeSet dim = new TreeSet<>(); + dim.add(pos.dimensionId); + + waypointManager.addWaypoint(new Waypoint( + pos.fluid.getLocalizedName(), // name + x, // X + z, // Z + Minecraft.getMinecraft().theWorld.getHeightValue(x, z), // Y + Config.enableVoxelMapWaypointsByDefault, // enabled + (float) (color >> 16 & 0xFF) / 255.0f, // red + (float) (color >> 8 & 0xFF) / 255.0f, // green + (float) (color & 0xFF) / 255.0f, // blue + "Science", // icon + IWaypointManagerReflection.getCurrentSubworldDescriptor(waypointManager, false), // world + dim)); // dimension + } + + private static int getY() { + EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer; + ItemStack heldItem = player.getHeldItem(); + if(heldItem == null || !heldItem.getUnlocalizedName().contains("gt.detrav.metatool.01")) { + return (int) player.posY; + } + return 65; + } + +} diff --git a/src/main/java/com/sinthoras/visualprospecting/mixinplugin/TargetedMod.java b/src/main/java/com/sinthoras/visualprospecting/mixinplugin/TargetedMod.java index 39103d84..84813210 100644 --- a/src/main/java/com/sinthoras/visualprospecting/mixinplugin/TargetedMod.java +++ b/src/main/java/com/sinthoras/visualprospecting/mixinplugin/TargetedMod.java @@ -38,7 +38,7 @@ public boolean isMatchingJar(Path path) { final String nameLowerCase = Files.getNameWithoutExtension(pathString).toLowerCase(); final String fileExtension = Files.getFileExtension(pathString); - return nameLowerCase.startsWith(jarNamePrefixLowercase) && "jar".equals(fileExtension); + return nameLowerCase.startsWith(jarNamePrefixLowercase) && ("jar".equals(fileExtension) || "litemod".equals(fileExtension)); } @Override