From 0d95936273e02189ab673fe525adefa0f6b3e238 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 19 Mar 2026 09:09:42 +0000 Subject: [PATCH] Refactor voxelmap integration from reflection to mixins --- mod/common/build.gradle | 3 +- .../mapsync/common/MixinManager.java | 86 ++++++++ .../minecraft/mapsync/common/RenderQueue.java | 8 +- .../common/integration/VoxelMapHelper.java | 26 --- .../integration/VoxelMapHelperReal.java | 193 ------------------ .../journeymap}/JourneyMapHelper.java | 2 +- .../journeymap}/JourneyMapHelperReal.java | 2 +- .../integrations/voxelmap/VoxelMapHelper.java | 20 ++ .../voxelmap/VoxelMapInternals.java | 140 +++++++++++++ .../xaerosmap}/XaerosWorldMapHelper.java | 2 +- .../xaerosmap}/XaerosWorldMapHelperReal.java | 2 +- .../mixins/voxelmap/CachedRegionAccessor.java | 53 +++++ .../voxelmap/PersistentMapAccessor.java | 29 +++ .../common/mixins/voxelmap/VoxelMapMixin.java | 25 +++ .../main/resources/mapsync.common.mixins.json | 5 + mod/fabric/build.gradle | 3 + 16 files changed, 371 insertions(+), 228 deletions(-) create mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/MixinManager.java delete mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelper.java delete mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelperReal.java rename mod/common/src/main/java/gjum/minecraft/mapsync/common/{integration => integrations/journeymap}/JourneyMapHelper.java (95%) rename mod/common/src/main/java/gjum/minecraft/mapsync/common/{integration => integrations/journeymap}/JourneyMapHelperReal.java (98%) create mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapHelper.java create mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapInternals.java rename mod/common/src/main/java/gjum/minecraft/mapsync/common/{integration => integrations/xaerosmap}/XaerosWorldMapHelper.java (92%) rename mod/common/src/main/java/gjum/minecraft/mapsync/common/{integration => integrations/xaerosmap}/XaerosWorldMapHelperReal.java (99%) create mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/CachedRegionAccessor.java create mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/PersistentMapAccessor.java create mode 100644 mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/VoxelMapMixin.java diff --git a/mod/common/build.gradle b/mod/common/build.gradle index 8f399fbd..2250d011 100644 --- a/mod/common/build.gradle +++ b/mod/common/build.gradle @@ -9,7 +9,8 @@ dependencies { modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" // https://modrinth.com/mod/voxelmap-updated/version/1.21.11-1.15.13 - modCompileOnly("maven.modrinth:voxelmap-updated:tRdGJKGE") + // Don't forget to update the version in the fabric version + modCompileOnly("maven.modrinth:voxelmap-updated:At2wqJfr") // https://modrinth.com/mod/journeymap/version/1.21.11-6.0.0-beta.56+fabric modCompileOnly("maven.modrinth:journeymap:OSpjUIEM") // https://modrinth.com/mod/xaeros-world-map/version/fabric-1.21.11-1.40.11 diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/MixinManager.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/MixinManager.java new file mode 100644 index 00000000..81227ce0 --- /dev/null +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/MixinManager.java @@ -0,0 +1,86 @@ +package gjum.minecraft.mapsync.common; + +import java.util.List; +import java.util.Set; +import net.fabricmc.loader.api.FabricLoader; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; +import org.spongepowered.asm.service.MixinService; + +public final class MixinManager implements IMixinConfigPlugin { + private String mixinPackage = ""; + private boolean isVoxelMapLoaded; + + @Override + public void onLoad( + final @NotNull String mixinPackage + ) { + this.mixinPackage = mixinPackage; + this.isVoxelMapLoaded = hasClass("com.mamiyaotaru.voxelmap.VoxelConstants"); + } + + /// This could be replaced with a [FabricLoader#isModLoaded(String)] if this was a fabric-only mod but alas, no. + private static boolean hasClass( + final @NotNull String className + ) { + try { + MixinService.getService().getClassProvider().findClass(className, false); + return true; + } + catch (final ClassNotFoundException e) { + return false; + } + } + + @Override + public boolean shouldApplyMixin( + final @NotNull String targetClassName, + final @NotNull String mixinClassName + ) { + if (mixinClassName.startsWith(this.mixinPackage + ".voxelmap.")) { + return this.isVoxelMapLoaded; + } + return true; + } + + @Override + public @Nullable String getRefMapperConfig() { + return null; + } + + @Override + public void acceptTargets( + final @NotNull Set<@NotNull String> myTargets, + final @NotNull Set<@NotNull String> otherTargets + ) { + + } + + @Override + public @Nullable List<@NotNull String> getMixins() { + return null; + } + + @Override + public void preApply( + final @NotNull String targetClassName, + final @NotNull ClassNode targetClass, + final @NotNull String mixinClassName, + final @NotNull IMixinInfo mixinInfo + ) { + + } + + @Override + public void postApply( + final @NotNull String targetClassName, + final @NotNull ClassNode targetClass, + final @NotNull String mixinClassName, + final @NotNull IMixinInfo mixinInfo + ) { + + } +} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/RenderQueue.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/RenderQueue.java index d5679330..d2fa8384 100644 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/RenderQueue.java +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/RenderQueue.java @@ -1,9 +1,9 @@ package gjum.minecraft.mapsync.common; import gjum.minecraft.mapsync.common.data.ChunkTile; -import gjum.minecraft.mapsync.common.integration.JourneyMapHelper; -import gjum.minecraft.mapsync.common.integration.VoxelMapHelper; -import gjum.minecraft.mapsync.common.integration.XaerosWorldMapHelper; +import gjum.minecraft.mapsync.common.integrations.journeymap.JourneyMapHelper; +import gjum.minecraft.mapsync.common.integrations.voxelmap.VoxelMapHelper; +import gjum.minecraft.mapsync.common.integrations.xaerosmap.XaerosWorldMapHelper; import net.minecraft.client.Minecraft; import org.jetbrains.annotations.NotNull; @@ -57,7 +57,7 @@ private void renderLoop() { } if (!JourneyMapHelper.isJourneyMapNotAvailable && !JourneyMapHelper.isMapping() - || !VoxelMapHelper.isVoxelMapNotAvailable && !VoxelMapHelper.isMapping() + || VoxelMapHelper.isModAvailable && !VoxelMapHelper.isMapping() || !XaerosWorldMapHelper.isXaerosWorldMapNotAvailable && !XaerosWorldMapHelper.isMapping() ) { debugLog("render is waiting til map mod is ready"); diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelper.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelper.java deleted file mode 100644 index fcaa5923..00000000 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelper.java +++ /dev/null @@ -1,26 +0,0 @@ -package gjum.minecraft.mapsync.common.integration; - -import gjum.minecraft.mapsync.common.data.ChunkTile; - -public class VoxelMapHelper { - public static boolean isVoxelMapNotAvailable; - - static { - try { - Class.forName("com.mamiyaotaru.voxelmap.interfaces.AbstractMapData"); - isVoxelMapNotAvailable = false; - } catch (NoClassDefFoundError | ClassNotFoundException ignored) { - isVoxelMapNotAvailable = true; - } - } - - public static boolean isMapping() { - if (isVoxelMapNotAvailable) return false; - return VoxelMapHelperReal.isMapping(); - } - - public static boolean updateWithChunkTile(ChunkTile chunkTile) { - if (isVoxelMapNotAvailable) return false; - return VoxelMapHelperReal.updateWithChunkTile(chunkTile); - } -} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelperReal.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelperReal.java deleted file mode 100644 index a327ab73..00000000 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/VoxelMapHelperReal.java +++ /dev/null @@ -1,193 +0,0 @@ -package gjum.minecraft.mapsync.common.integration; - -import com.mamiyaotaru.voxelmap.VoxelConstants; -import com.mamiyaotaru.voxelmap.persistent.*; -import gjum.minecraft.mapsync.common.data.BlockInfo; -import gjum.minecraft.mapsync.common.data.ChunkTile; -import net.minecraft.client.multiplayer.ClientLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.level.block.Blocks; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.*; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; - -public class VoxelMapHelperReal { - // TODO use mixins to access package-/private fields/methods - - private static Field cachedRegionsField; - private static Field cachedRegionsPoolField; - private static Field worldField; - - private static Field regionDataField; - private static Field liveChunksUpdatedField; - private static Field dataUpdatedField; - private static Field regionLoadedField; - private static Method regionLoadMethod; - - private static Field threadLockField; - - static { - try { - cachedRegionsField = PersistentMap.class.getDeclaredField("cachedRegions"); - cachedRegionsField.setAccessible(true); - cachedRegionsPoolField = PersistentMap.class.getDeclaredField("cachedRegionsPool"); - cachedRegionsPoolField.setAccessible(true); - worldField = PersistentMap.class.getDeclaredField("world"); - worldField.setAccessible(true); - - regionDataField = CachedRegion.class.getDeclaredField("data"); - regionDataField.setAccessible(true); - liveChunksUpdatedField = CachedRegion.class.getDeclaredField("liveChunksUpdated"); - liveChunksUpdatedField.setAccessible(true); - dataUpdatedField = CachedRegion.class.getDeclaredField("dataUpdated"); - dataUpdatedField.setAccessible(true); - regionLoadedField = CachedRegion.class.getDeclaredField("loaded"); - regionLoadedField.setAccessible(true); - regionLoadMethod = CachedRegion.class.getDeclaredMethod("load"); - regionLoadMethod.setAccessible(true); - - threadLockField = CachedRegion.class.getDeclaredField("threadLock"); - threadLockField.setAccessible(true); - } catch (Throwable e) { - e.printStackTrace(); - } - } - - static boolean isMapping() { - if (worldField == null) return false; - try { - PersistentMap map = VoxelConstants.getVoxelMapInstance().getPersistentMap(); - var world = (ClientLevel) worldField.get(map); - return world != null; - } catch (IllegalAccessException ignored) { - return false; - } - } - - // TODO update multiple chunks in one region at once - // TODO which thread should this run on? - static boolean updateWithChunkTile(ChunkTile chunkTile) { - try { - if (!isMapping()) return false; - - int rx = chunkTile.x() >> 4; - int rz = chunkTile.z() >> 4; - var region = getRegion(rx, rz); - - var lock = (ReentrantLock) threadLockField.get(region); - lock.lock(); - try { - var mapData = (CompressibleMapData) regionDataField.get(region); - - int x0 = (chunkTile.x() * 16) & 0xff; - int z0 = (chunkTile.z() * 16) & 0xff; - - int i = 0; - for (int z = z0; z < z0 + 16; ++z) { - for (int x = x0; x < x0 + 16; ++x) { - var col = chunkTile.columns()[i++]; - - mapData.setBiome(x, z, col.biome()); - - int light = 0xf0 | col.light(); - mapData.setTransparentLight(x, z, light); - mapData.setFoliageLight(x, z, light); - mapData.setLight(x, z, light); - mapData.setOceanFloorLight(x, z, light); - - setLayerStates(mapData, x, z, col.layers()); - } - } - - liveChunksUpdatedField.set(region, true); - dataUpdatedField.set(region, true); - - // render imagery - region.refresh(false); - } finally { - lock.unlock(); - } - - return true; - } catch (Throwable e) { - e.printStackTrace(); - return false; - } - } - - private static final BlockInfo EMPTY = new BlockInfo(0, Blocks.AIR.defaultBlockState()); - - private static void setLayerStates(CompressibleMapData mapData, int x, int z, List layers) { - BlockInfo transparent = EMPTY; - BlockInfo foliage = EMPTY; - BlockInfo surface = EMPTY; - BlockInfo seafloor = EMPTY; - - // XXX - if (layers.size() > 1) transparent = layers.get(0); - surface = layers.get(layers.size() - 1); - // trees hack - if (layers.get(0).state().is(BlockTags.LEAVES)) { - surface = layers.get(0); - } - - mapData.setTransparentHeight(x, z, transparent.y()); - mapData.setTransparentBlockstate(x, z, transparent.state()); - mapData.setFoliageHeight(x, z, foliage.y()); - mapData.setFoliageBlockstate(x, z, foliage.state()); - mapData.setHeight(x, z, surface.y()); - mapData.setBlockstate(x, z, surface.state()); - mapData.setOceanFloorHeight(x, z, seafloor.y()); - mapData.setOceanFloorBlockstate(x, z, seafloor.state()); - } - - @NotNull - private static CachedRegion getRegion(int rx, int rz) - throws IllegalAccessException, InvocationTargetException { - PersistentMap map = VoxelConstants.getVoxelMapInstance().getPersistentMap(); - - @SuppressWarnings("unchecked") - var cachedRegions = (ConcurrentHashMap) cachedRegionsField.get(map); - - @SuppressWarnings("unchecked") - var cachedRegionsPool = (List) cachedRegionsPoolField.get(map); - - var world = (ClientLevel) worldField.get(map); - - String worldName = VoxelConstants.getVoxelMapInstance().getWaypointManager().getCurrentWorldName(); - String subWorldName = VoxelConstants.getVoxelMapInstance().getWaypointManager().getCurrentSubworldDescriptor(false); - - String key = rx + "," + rz; - - @Nullable CachedRegion region; - - // the following synchronized{} section matches VoxelMap's internal logic - // see com.mamiyaotaru.voxelmap.persistent.PersistentMap.getRegions - //noinspection SynchronizationOnLocalVariableOrMethodParameter - synchronized (cachedRegions) { - region = cachedRegions.get(key); - // could be race condition if the region is not fully loaded at this point - if (region == null || region instanceof EmptyCachedRegion) { - region = new CachedRegion(map, key, world, worldName, subWorldName, rx, rz); - - cachedRegions.put(key, region); - - //noinspection SynchronizationOnLocalVariableOrMethodParameter - synchronized (cachedRegionsPool) { - cachedRegionsPool.add(region); - } - } - } - - // TODO which thread should this run on? - if (!((Boolean) regionLoadedField.get(region))) { - regionLoadMethod.invoke(region); - } - - return region; - } -} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/JourneyMapHelper.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/journeymap/JourneyMapHelper.java similarity index 95% rename from mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/JourneyMapHelper.java rename to mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/journeymap/JourneyMapHelper.java index 9b46e737..ea380c89 100644 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/JourneyMapHelper.java +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/journeymap/JourneyMapHelper.java @@ -1,4 +1,4 @@ -package gjum.minecraft.mapsync.common.integration; +package gjum.minecraft.mapsync.common.integrations.journeymap; import java.util.regex.Pattern; diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/JourneyMapHelperReal.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/journeymap/JourneyMapHelperReal.java similarity index 98% rename from mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/JourneyMapHelperReal.java rename to mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/journeymap/JourneyMapHelperReal.java index f4312913..ddc7cec9 100644 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/JourneyMapHelperReal.java +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/journeymap/JourneyMapHelperReal.java @@ -1,4 +1,4 @@ -package gjum.minecraft.mapsync.common.integration; +package gjum.minecraft.mapsync.common.integrations.journeymap; import gjum.minecraft.mapsync.common.data.BlockColumn; import gjum.minecraft.mapsync.common.data.BlockInfo; diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapHelper.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapHelper.java new file mode 100644 index 00000000..c1308ab7 --- /dev/null +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapHelper.java @@ -0,0 +1,20 @@ +package gjum.minecraft.mapsync.common.integrations.voxelmap; + +import gjum.minecraft.mapsync.common.data.ChunkTile; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +public final class VoxelMapHelper { + @ApiStatus.Internal + public static boolean isModAvailable = false; + + public static boolean isMapping() { + return isModAvailable && VoxelMapInternals.isMapping(); + } + + public static boolean updateWithChunkTile( + final @NotNull ChunkTile chunkTile + ) { + return isModAvailable && VoxelMapInternals.updateWithChunkTile(chunkTile); + } +} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapInternals.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapInternals.java new file mode 100644 index 00000000..77d3da07 --- /dev/null +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/voxelmap/VoxelMapInternals.java @@ -0,0 +1,140 @@ +package gjum.minecraft.mapsync.common.integrations.voxelmap; +import com.mamiyaotaru.voxelmap.VoxelConstants; +import com.mamiyaotaru.voxelmap.WaypointManager; +import com.mamiyaotaru.voxelmap.persistent.CachedRegion; +import com.mamiyaotaru.voxelmap.persistent.CompressibleMapData; +import com.mamiyaotaru.voxelmap.persistent.EmptyCachedRegion; +import com.mamiyaotaru.voxelmap.persistent.PersistentMap; +import gjum.minecraft.mapsync.common.data.BlockColumn; +import gjum.minecraft.mapsync.common.data.BlockInfo; +import gjum.minecraft.mapsync.common.data.ChunkTile; +import gjum.minecraft.mapsync.common.mixins.voxelmap.CachedRegionAccessor; +import gjum.minecraft.mapsync.common.mixins.voxelmap.PersistentMapAccessor; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.level.block.Blocks; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +final class VoxelMapInternals { + static boolean isMapping() { + return ((PersistentMapAccessor) VoxelConstants.getVoxelMapInstance().getPersistentMap()).mapsync$getWorld() != null; + } + + // TODO update multiple chunks in one region at once + // TODO which thread should this run on? + static boolean updateWithChunkTile( + final @NotNull ChunkTile chunkTile + ) { + final PersistentMap map = VoxelConstants.getVoxelMapInstance().getPersistentMap(); + final var mapAccessor = (PersistentMapAccessor) map; + final ClientLevel currentLevel = mapAccessor.mapsync$getWorld(); + if (currentLevel == null) { + return false; + } + + @Nullable CachedRegion cachedRegion; { + final WaypointManager waypointManager = VoxelConstants.getVoxelMapInstance().getWaypointManager(); + final String worldName = waypointManager.getCurrentWorldName(); + final String subWorldName = waypointManager.getCurrentSubworldDescriptor(false); + + final int regionX = chunkTile.x() >> 4; + final int regionZ = chunkTile.z() >> 4; + final String regionKey = regionX + "," + regionZ; + + final ConcurrentHashMap cachedRegions = mapAccessor.mapsync$getCachedRegions(); + synchronized (cachedRegions) { + cachedRegion = cachedRegions.get(regionKey); + // could be race condition if the region is not fully loaded at this point + if (cachedRegion == null || cachedRegion instanceof EmptyCachedRegion) { + cachedRegions.put(regionKey, cachedRegion = new CachedRegion( + map, + regionKey, + currentLevel, + worldName, + subWorldName, + regionX, + regionZ + )); + + final List cachedRegionsPool = mapAccessor.mapsync$getCachedRegionsPool(); + synchronized (cachedRegionsPool) { + cachedRegionsPool.add(cachedRegion); + } + } + } + } + + final var regionAccessor = (CachedRegionAccessor) cachedRegion; + if (!regionAccessor.mapsync$isLoaded()) { + regionAccessor.mapsync$load(); + } + + final ReentrantLock lock = regionAccessor.mapsync$getThreadLock(); lock.lock(); try { + final CompressibleMapData data = regionAccessor.mapsync$getData(); + + final int x0 = (chunkTile.x() << 4) & 0xFF; + final int z0 = (chunkTile.z() << 4) & 0xFF; + + int i = 0; + for (int z = z0; z < z0 + 16; ++z) for (int x = x0; x < x0 + 16; ++x) { + final BlockColumn blockColumn = chunkTile.columns()[i++]; + if (blockColumn.layers().isEmpty()) { + continue; + } + + data.setBiome(x, z, blockColumn.biome()); + + final int light = 0xF0 | blockColumn.light(); + data.setLight(x, z, light); + data.setTransparentLight(x, z, light); + data.setFoliageLight(x, z, light); + data.setOceanFloorLight(x, z, light); + + BlockInfo transparent = newAirBlock(); + BlockInfo foliage = newAirBlock(); + BlockInfo surface = newAirBlock(); + BlockInfo seafloor = newAirBlock(); + + final List blockColumnLayers = blockColumn.layers(); + + // XXX + final BlockInfo zerothBlock = blockColumnLayers.getFirst(); + if (blockColumnLayers.size() > 1) { + transparent = zerothBlock; + } + surface = blockColumnLayers.getLast(); + // trees hack + if (zerothBlock.state().is(BlockTags.LEAVES)) { + surface = zerothBlock; + } + + data.setTransparentHeight(x, z, transparent.y()); + data.setTransparentBlockstate(x, z, transparent.state()); + data.setFoliageHeight(x, z, foliage.y()); + data.setFoliageBlockstate(x, z, foliage.state()); + data.setHeight(x, z, surface.y()); + data.setBlockstate(x, z, surface.state()); + data.setOceanFloorHeight(x, z, seafloor.y()); + data.setOceanFloorBlockstate(x, z, seafloor.state()); + } + + regionAccessor.mapsync$setLiveChunksUpdated(true); + regionAccessor.mapsync$setDataUpdated(true); + + // render imagery + cachedRegion.refresh(false); + } + finally { + lock.unlock(); + } + return true; + } + + private static @NotNull BlockInfo newAirBlock() { + return new BlockInfo(0, Blocks.AIR.defaultBlockState()); + } +} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/XaerosWorldMapHelper.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/xaerosmap/XaerosWorldMapHelper.java similarity index 92% rename from mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/XaerosWorldMapHelper.java rename to mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/xaerosmap/XaerosWorldMapHelper.java index ddae895e..0b28bbc0 100644 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/XaerosWorldMapHelper.java +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/xaerosmap/XaerosWorldMapHelper.java @@ -1,4 +1,4 @@ -package gjum.minecraft.mapsync.common.integration; +package gjum.minecraft.mapsync.common.integrations.xaerosmap; import gjum.minecraft.mapsync.common.data.ChunkTile; diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/XaerosWorldMapHelperReal.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/xaerosmap/XaerosWorldMapHelperReal.java similarity index 99% rename from mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/XaerosWorldMapHelperReal.java rename to mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/xaerosmap/XaerosWorldMapHelperReal.java index 2b194835..8bcc0b83 100644 --- a/mod/common/src/main/java/gjum/minecraft/mapsync/common/integration/XaerosWorldMapHelperReal.java +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/integrations/xaerosmap/XaerosWorldMapHelperReal.java @@ -1,4 +1,4 @@ -package gjum.minecraft.mapsync.common.integration; +package gjum.minecraft.mapsync.common.integrations.xaerosmap; import gjum.minecraft.mapsync.common.data.BlockColumn; import gjum.minecraft.mapsync.common.data.BlockInfo; diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/CachedRegionAccessor.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/CachedRegionAccessor.java new file mode 100644 index 00000000..a68bb0a4 --- /dev/null +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/CachedRegionAccessor.java @@ -0,0 +1,53 @@ +package gjum.minecraft.mapsync.common.mixins.voxelmap; + +import com.mamiyaotaru.voxelmap.persistent.CachedRegion; +import com.mamiyaotaru.voxelmap.persistent.CompressibleMapData; +import java.util.concurrent.locks.ReentrantLock; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.UnknownNullability; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(CachedRegion.class) +public interface CachedRegionAccessor { + @Accessor( + value = "data", + remap = false + ) + public @UnknownNullability CompressibleMapData mapsync$getData(); + + @Accessor( + value = "loaded", + remap = false + ) + public boolean mapsync$isLoaded(); + + @Invoker( + value = "load", + remap = false + ) + public void mapsync$load(); + + @Accessor( + value = "threadLock", + remap = false + ) + public @NotNull ReentrantLock mapsync$getThreadLock(); + + @Accessor( + value = "liveChunksUpdated", + remap = false + ) + public void mapsync$setLiveChunksUpdated( + boolean liveChunksUpdated + ); + + @Accessor( + value = "dataUpdated", + remap = false + ) + public void mapsync$setDataUpdated( + boolean dataUpdated + ); +} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/PersistentMapAccessor.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/PersistentMapAccessor.java new file mode 100644 index 00000000..4038ada3 --- /dev/null +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/PersistentMapAccessor.java @@ -0,0 +1,29 @@ +package gjum.minecraft.mapsync.common.mixins.voxelmap; + +import com.mamiyaotaru.voxelmap.persistent.CachedRegion; +import com.mamiyaotaru.voxelmap.persistent.PersistentMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import net.minecraft.client.multiplayer.ClientLevel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(PersistentMap.class) +public interface PersistentMapAccessor { + @Accessor("world") + public @Nullable ClientLevel mapsync$getWorld(); + + @Accessor( + value = "cachedRegions", + remap = false + ) + public @NotNull ConcurrentHashMap mapsync$getCachedRegions(); + + @Accessor( + value = "cachedRegionsPool", + remap = false + ) + public @NotNull List mapsync$getCachedRegionsPool(); +} diff --git a/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/VoxelMapMixin.java b/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/VoxelMapMixin.java new file mode 100644 index 00000000..bec160c6 --- /dev/null +++ b/mod/common/src/main/java/gjum/minecraft/mapsync/common/mixins/voxelmap/VoxelMapMixin.java @@ -0,0 +1,25 @@ +package gjum.minecraft.mapsync.common.mixins.voxelmap; + +import com.mamiyaotaru.voxelmap.VoxelMap; +import gjum.minecraft.mapsync.common.integrations.voxelmap.VoxelMapHelper; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(VoxelMap.class) +public abstract class VoxelMapMixin { + @Inject( + method = "lateInit", + at = @At("TAIL"), + remap = false + ) + protected void mapsync$lateInit( + final boolean showUnderMenus, + final boolean isFair, + final @NotNull CallbackInfo ci + ) { + VoxelMapHelper.isModAvailable = true; + } +} diff --git a/mod/common/src/main/resources/mapsync.common.mixins.json b/mod/common/src/main/resources/mapsync.common.mixins.json index 0e91d177..9f0582d1 100644 --- a/mod/common/src/main/resources/mapsync.common.mixins.json +++ b/mod/common/src/main/resources/mapsync.common.mixins.json @@ -3,7 +3,12 @@ "minVersion": "0.8", "package": "gjum.minecraft.mapsync.common.mixins", "compatibilityLevel": "JAVA_21", + "plugin": "gjum.minecraft.mapsync.common.MixinManager", "client": [ + "voxelmap.CachedRegionAccessor", + "voxelmap.PersistentMapAccessor", + "voxelmap.VoxelMapMixin", + "MixinClientPacketListener" ], "injectors": { diff --git a/mod/fabric/build.gradle b/mod/fabric/build.gradle index 38b76fc4..c612ea66 100644 --- a/mod/fabric/build.gradle +++ b/mod/fabric/build.gradle @@ -26,6 +26,9 @@ dependencies { // https://modrinth.com/mod/modmenu/version/3.2.5 (3.2.5 fabric) modCompileOnly("maven.modrinth:modmenu:nVxObSbX") + + // This needs to be included or otherwise the mixins cannot compile + modCompileOnly("maven.modrinth:voxelmap-updated:At2wqJfr") } processResources {