diff --git a/src/test/java/net/modificationstation/sltest/achievement/AchievementListener.java b/src/test/java/net/modificationstation/sltest/achievement/AchievementListener.java index f2d3ab2c9..c7ea56135 100644 --- a/src/test/java/net/modificationstation/sltest/achievement/AchievementListener.java +++ b/src/test/java/net/modificationstation/sltest/achievement/AchievementListener.java @@ -6,6 +6,7 @@ import net.modificationstation.sltest.item.ItemListener; import net.modificationstation.stationapi.api.client.gui.screen.achievement.AchievementPage; import net.modificationstation.stationapi.api.event.achievement.AchievementRegisterEvent; +import net.modificationstation.stationapi.api.template.achievement.TemplateAchievement; import static net.modificationstation.sltest.SLTest.NAMESPACE; @@ -18,8 +19,8 @@ public class AchievementListener { @EventListener public void registerAchievements(AchievementRegisterEvent event) { testAchievementPage = new AchievementPageTest(NAMESPACE.id("testPage")); - testAchievement = new Achievement(69696969, "sltest.testAchievement", 0, 0, ItemListener.testItem, null); - testAchievementChild = new Achievement(69696970, "sltest.testAchievementChild", 0, 2, Item.GOLDEN_APPLE, testAchievement); + testAchievement = new TemplateAchievement(NAMESPACE.id("test_achievement"), "sltest.testAchievement", 0, 0, ItemListener.testItem, null); + testAchievementChild = new TemplateAchievement(NAMESPACE.id("test_achievement_child"), "sltest.testAchievementChild", 0, 2, Item.GOLDEN_APPLE, testAchievement); event.achievements.add(testAchievement); event.achievements.add(testAchievementChild); testAchievementPage.addAchievements(testAchievement, testAchievementChild); diff --git a/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/StatsMixin.java b/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/StatsMixin.java deleted file mode 100644 index c31f5a5c6..000000000 --- a/station-blocks-v0/src/main/java/net/modificationstation/stationapi/mixin/block/StatsMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.modificationstation.stationapi.mixin.block; - -import net.minecraft.item.Item; -import net.minecraft.stat.Stat; -import net.minecraft.stat.Stats; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Stats.class) -class StatsMixin { - @Redirect( - method = "initializeItemStats", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/stat/Stats;initItemsUsedStats([Lnet/minecraft/stat/Stat;Ljava/lang/String;III)[Lnet/minecraft/stat/Stat;" - ) - ) - private static Stat[] stationapi_stop1(Stat[] statArray, String translationKey, int startId, int statAmount, int arrayLength) { - return new Stat[Item.ITEMS.length]; - } - - @Redirect( - method = "initializeItemStats", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/stat/Stats;initializeBrokenItemStats([Lnet/minecraft/stat/Stat;Ljava/lang/String;III)[Lnet/minecraft/stat/Stat;" - ) - ) - private static Stat[] stationapi_stop2(Stat[] statArray, String translationKey, int startId, int statAmount, int arrayLength) { - return new Stat[Item.ITEMS.length]; - } - - @Redirect( - method = "initializeExtendedItemStats", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/stat/Stats;initItemsUsedStats([Lnet/minecraft/stat/Stat;Ljava/lang/String;III)[Lnet/minecraft/stat/Stat;" - ) - ) - private static Stat[] stationapi_stop3(Stat[] statArray, String translationKey, int startId, int statAmount, int arrayLength) { - return new Stat[Item.ITEMS.length]; - } - - @Redirect( - method = "initializeExtendedItemStats", - at = @At( - value = "INVOKE", - target = "Lnet/minecraft/stat/Stats;initializeBrokenItemStats([Lnet/minecraft/stat/Stat;Ljava/lang/String;III)[Lnet/minecraft/stat/Stat;" - ) - ) - private static Stat[] stop4(Stat[] statArray, String translationKey, int startId, int statAmount, int arrayLength) { - return new Stat[Item.ITEMS.length]; - } -} diff --git a/station-blocks-v0/src/main/resources/station-blocks-v0.mixins.json b/station-blocks-v0/src/main/resources/station-blocks-v0.mixins.json index 109b74423..2951760da 100644 --- a/station-blocks-v0/src/main/resources/station-blocks-v0.mixins.json +++ b/station-blocks-v0/src/main/resources/station-blocks-v0.mixins.json @@ -8,8 +8,7 @@ "BlockMixin", "FireBlockMixin", "LeavesBlockMixin", - "SecondaryBlockItemMixin", - "StatsMixin" + "SecondaryBlockItemMixin" ], "injectors": { "defaultRequire": 1 diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/StatRegistryEvent.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/StatRegistryEvent.java new file mode 100644 index 000000000..a42c43f42 --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/event/registry/StatRegistryEvent.java @@ -0,0 +1,13 @@ +package net.modificationstation.stationapi.api.event.registry; + +import net.mine_diver.unsafeevents.event.EventPhases; +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.registry.StatRegistry; + +@EventPhases(StationAPI.INTERNAL_PHASE) +public class StatRegistryEvent extends RegistryEvent.EntryTypeBound { + public StatRegistryEvent() { + super(StatRegistry.INSTANCE); + } +} \ No newline at end of file diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/registry/StatRegistry.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/registry/StatRegistry.java new file mode 100644 index 000000000..b05dcd82a --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/registry/StatRegistry.java @@ -0,0 +1,24 @@ +package net.modificationstation.stationapi.api.registry; + +import com.mojang.serialization.Lifecycle; +import it.unimi.dsi.fastutil.ints.Int2IntFunction; +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.event.registry.RegistryAttribute; +import net.modificationstation.stationapi.api.event.registry.RegistryAttributeHolder; + +import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE; + +public class StatRegistry extends SimpleRegistry { + public static final RegistryKey> KEY = RegistryKey.ofRegistry(NAMESPACE.id("stats")); + public static final StatRegistry INSTANCE = Registries.create(KEY, new StatRegistry(), Lifecycle.experimental()); + + public static final int ACHIEVEMENT_ID_SHIFT = 0x500000; + public static final Int2IntFunction SHIFTED_ACHIEVEMENT_ID = id -> id - ACHIEVEMENT_ID_SHIFT; + public static final int ACHIEVEMENT_AUTO_ID = SHIFTED_ACHIEVEMENT_ID.applyAsInt(AUTO_ID); + + private StatRegistry() { + super(KEY, Lifecycle.experimental(), true); + RegistryAttributeHolder.get(this).addAttribute(RegistryAttribute.SYNCED); + nextId = 0x1040000; + } +} \ No newline at end of file diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/stat/StationFlatteningStat.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/stat/StationFlatteningStat.java new file mode 100644 index 000000000..d7e075610 --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/api/stat/StationFlatteningStat.java @@ -0,0 +1,17 @@ +package net.modificationstation.stationapi.api.stat; + +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.registry.RegistryEntry; +import net.modificationstation.stationapi.api.registry.RemappableRawIdHolder; +import net.modificationstation.stationapi.api.util.Util; + +public interface StationFlatteningStat extends RemappableRawIdHolder { + @Override + default void setRawId(int rawId) { + Util.assertImpl(); + } + + default RegistryEntry.Reference getRegistryEntry() { + return Util.assertImpl(); + } +} \ No newline at end of file diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/stat/ModdedStatsSerializingIterator.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/stat/ModdedStatsSerializingIterator.java new file mode 100644 index 000000000..1fa4bd3e2 --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/impl/stat/ModdedStatsSerializingIterator.java @@ -0,0 +1,97 @@ +package net.modificationstation.stationapi.impl.stat; + +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.util.Namespace; + +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +import static net.modificationstation.stationapi.api.StationAPI.NAMESPACE; + +/** + * Iterates over a set of stats, filtering out modded ones and serializing them separately. + */ +public final class ModdedStatsSerializingIterator implements Iterator { + public static final String STATIONAPI_STATS_CHANGE_KEY = NAMESPACE.id("stats-change").toString(); + + private final Iterator source; + private final StringBuilder moddedStatsSerialized; + private final Map statCounts; + + private Stat nextVanillaStat; + private boolean firstModdedStat = true; + + public ModdedStatsSerializingIterator( + Iterator source, StringBuilder moddedStatsSerialized, Map statCounts + ) { + this.source = source; + this.moddedStatsSerialized = moddedStatsSerialized; + this.statCounts = statCounts; + + moddedStatsSerialized.append(" \"").append(STATIONAPI_STATS_CHANGE_KEY).append("\":["); + + advance(); + } + + /** + * Searches for the next vanilla stat in the set and serializes all modded stats found on the way. + */ + private void advance() { + nextVanillaStat = null; + + // Searching for the next vanilla stat in the set + // and serializing all modded stats found on the way + while (source.hasNext()) { + Stat candidate = source.next(); + + if (candidate.getRegistryEntry().registryKey().getValue().namespace == Namespace.MINECRAFT) { + nextVanillaStat = candidate; + return; + } + + serializeModded(candidate); + } + } + + /** + * Serializes the given stat under the modded stats array. + * + * @param stat the stat to serialize under the modded stats array + */ + private void serializeModded(Stat stat) { + if (!firstModdedStat) moddedStatsSerialized.append("},"); + else firstModdedStat = false; + + moddedStatsSerialized.append("\r\n {\""); + moddedStatsSerialized.append(stat.getRegistryEntry().registryKey().getValue()).append("\":").append(statCounts.get(stat)); + } + + @Override + public boolean hasNext() { + if (nextVanillaStat != null) + return true; + + // If there are no more stats from the source iterator, + // finish serializing modded stats and terminate the loop + if (!firstModdedStat) + moddedStatsSerialized.append("}"); + moddedStatsSerialized.append("\r\n ],\r\n"); + return false; + } + + /** + * Returns the next vanilla {@link Stat} and advances the source iterator via {@link #advance()}. + * + * @return the next vanilla {@link Stat} from the source iterator + * @throws NoSuchElementException if there are no more vanilla stats + */ + @Override + public Stat next() { + if (nextVanillaStat == null) throw new NoSuchElementException(); + + final Stat stat = nextVanillaStat; + advance(); + return stat; + } +} diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/StatMixin.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/StatMixin.java new file mode 100644 index 000000000..0d11af5dd --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/StatMixin.java @@ -0,0 +1,44 @@ +package net.modificationstation.stationapi.mixin.flattening; + +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.registry.RegistryEntry; +import net.modificationstation.stationapi.api.registry.StatRegistry; +import net.modificationstation.stationapi.api.stat.StationFlatteningStat; +import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyVariable; + +@Mixin(Stat.class) +class StatMixin implements StationFlatteningStat { + @Mutable + @Shadow @Final public int id; + @Unique + private RegistryEntry.Reference stationapi_registryEntry; + + @ModifyVariable( + method = "(ILjava/lang/String;Lnet/minecraft/stat/StatFormatter;)V", + index = 1, + at = @At( + value = "CONSTANT", + args = "intValue=0", + ordinal = 0 + ), + argsOnly = true + ) + private int stationapi_ensureCapacity(int rawId) { + return (stationapi_registryEntry = StatRegistry.INSTANCE.createReservedEntry(rawId, (Stat) (Object) this)).reservedRawId(); + } + + @SuppressWarnings("AddedMixinMembersNamePattern") + @Override + @Unique + public void setRawId(int rawId) { + id = rawId; + } + + @SuppressWarnings("AddedMixinMembersNamePattern") + @Override + public RegistryEntry.Reference getRegistryEntry() { + return stationapi_registryEntry; + } +} \ No newline at end of file diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/StatsMixin.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/StatsMixin.java new file mode 100644 index 000000000..7d727c813 --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/StatsMixin.java @@ -0,0 +1,290 @@ +package net.modificationstation.stationapi.mixin.flattening; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import lombok.val; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.stat.ItemOrBlockStat; +import net.minecraft.stat.Stat; +import net.minecraft.stat.Stats; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.registry.StatRegistryEvent; +import net.modificationstation.stationapi.api.item.BlockItemForm; +import net.modificationstation.stationapi.api.registry.BlockRegistry; +import net.modificationstation.stationapi.api.registry.ItemRegistry; +import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.registry.StatRegistry; +import net.modificationstation.stationapi.api.registry.sync.trackers.Int2ObjectMapTracker; +import net.modificationstation.stationapi.api.registry.sync.trackers.ObjectArrayTracker; +import net.modificationstation.stationapi.api.util.Namespace; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.*; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Map; + +@Mixin(Stats.class) +class StatsMixin { + @Shadow public static Stat[] CRAFTED; + + @Shadow public static Stat[] MINE_BLOCK; + + @Shadow public static Stat[] USED; + + @Shadow public static Stat[] BROKEN; + + @Shadow private static boolean hasExtendedItemStatsInitialized; + + @Shadow private static boolean hasBasicItemStatsInitialized; + + @Shadow protected static Map ID_TO_STAT; + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/stat/Stats;ID_TO_STAT:Ljava/util/Map;", + opcode = Opcodes.PUTSTATIC, + shift = At.Shift.AFTER + ) + ) + private static void stationapi_syncMap(CallbackInfo ci) { + Int2ObjectMapTracker.register(StatRegistry.INSTANCE, "Stats.ID_TO_STAT", ID_TO_STAT, true); + } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/stat/Stats;MINE_BLOCK:[Lnet/minecraft/stat/Stat;", + opcode = Opcodes.PUTSTATIC, + shift = At.Shift.AFTER + ) + ) + private static void stationapi_syncMined(CallbackInfo ci) { + ObjectArrayTracker.register(BlockRegistry.INSTANCE, () -> MINE_BLOCK, array -> MINE_BLOCK = array, false); + } + + @Inject( + method = "initializeItemStats", + at = @At("HEAD") + ) + private static void stationapi_syncUsedAndBroken(CallbackInfo ci) { + if (!hasExtendedItemStatsInitialized) { + ObjectArrayTracker.register(ItemRegistry.INSTANCE, () -> USED, array -> USED = array, false); + ObjectArrayTracker.register(ItemRegistry.INSTANCE, () -> BROKEN, array -> BROKEN = array, false); + } + } + + @Redirect( + method = "initializeItemStats", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/block/Block;BLOCKS:[Lnet/minecraft/block/Block;", + opcode = Opcodes.GETSTATIC, + args = "array=length", + ordinal = 0 + ) + ) + private static int stationapi_initAll(Block[] blocks) { + return Item.ITEMS.length; + } + + @Inject( + method = "initializeExtendedItemStats", + at = @At("HEAD") + ) + private static void stationapi_syncUsedAndBrokenExtended(CallbackInfo ci) { + if (!hasBasicItemStatsInitialized) { + ObjectArrayTracker.register(ItemRegistry.INSTANCE, () -> USED, array -> USED = array, false); + ObjectArrayTracker.register(ItemRegistry.INSTANCE, () -> BROKEN, array -> BROKEN = array, false); + } + } + + @WrapOperation( + method = "initializeExtendedItemStats", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/stat/Stats;initItemsUsedStats([Lnet/minecraft/stat/Stat;Ljava/lang/String;III)[Lnet/minecraft/stat/Stat;" + ) + ) + private static Stat[] stationapi_stopBlockUsedStats(Stat[] stats, String name, int id, int minId, int maxId, Operation original) { + return new Stat[maxId]; + } + + @Inject( + method = "initializeCraftedItemStats", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/stat/Stats;CRAFTED:[Lnet/minecraft/stat/Stat;", + opcode = Opcodes.PUTSTATIC + ) + ) + private static void stationapi_syncCrafted(CallbackInfo ci) { + ObjectArrayTracker.register(ItemRegistry.INSTANCE, () -> CRAFTED, array -> CRAFTED = array, false); + } + + @Inject( + method = "", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/stat/Stats;FISH_CAUGHT:Lnet/minecraft/stat/Stat;", + opcode = Opcodes.PUTSTATIC, + shift = At.Shift.AFTER + ) + ) + private static void stationapi_afterStatRegister(CallbackInfo ci) { + StationAPI.EVENT_BUS.post(new StatRegistryEvent()); + } + + @Inject( + method = "initializeCraftedItemStats", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/stat/ItemOrBlockStat;addStat()Lnet/minecraft/stat/Stat;", + shift = At.Shift.BY, + by = 2 + ) + ) + private static void stationapi_registerCraftedStats( + CallbackInfo ci, + @Local(index = 2) Integer index + ) { + val stat = CRAFTED[index]; + Registry.register(StatRegistry.INSTANCE, stat.id, Item.ITEMS[index].getRegistryEntry().registryKey().getValue().withSuffixedPath("_crafted"), stat); + } + + @Inject( + method = "initBlocksMined", + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private static void stationapi_registerMinedStats( + String string, int i, CallbackInfoReturnable cir, + @Local(index = 2) Stat[] statArray, @Local(index = 3) int index + ) { + val stat = statArray[index]; + Registry.register(StatRegistry.INSTANCE, stat.id, Block.BLOCKS[index].getRegistryEntry().registryKey().getValue().withSuffixedPath("_mined"), stat); + } + + @Inject( + method = "initItemsUsedStats", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/stat/ItemOrBlockStat;addStat()Lnet/minecraft/stat/Stat;", + shift = At.Shift.BY, + by = 2 + ) + ) + private static void stationapi_registerUsedStats( + Stat[] stats, String string, int i, int j, int k, CallbackInfoReturnable cir, + @Local(index = 5) int index + ) { + val stat = stats[index]; + Registry.register(StatRegistry.INSTANCE, stat.id, Item.ITEMS[index].getRegistryEntry().registryKey().getValue().withSuffixedPath("_used"), stat); + } + + @Inject( + method = "initializeBrokenItemStats", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/stat/ItemOrBlockStat;addStat()Lnet/minecraft/stat/Stat;", + shift = At.Shift.BY, + by = 2 + ) + ) + private static void stationapi_registerBrokenStats( + Stat[] stats, String string, int i, int j, int k, CallbackInfoReturnable cir, + @Local(index = 5) int index + ) { + val stat = stats[index]; + Registry.register(StatRegistry.INSTANCE, stat.id, Item.ITEMS[index].getRegistryEntry().registryKey().getValue().withSuffixedPath("_broken"), stat); + } + + @ModifyConstant( + method = "initBlocksMined", + constant = @Constant(intValue = 256) + ) + private static int stationapi_getBlocksSize(int constant) { + return Block.BLOCKS.length; + } + + @ModifyConstant( + method = { + "initializeItemStats", + "initializeExtendedItemStats", + "initializeCraftedItemStats", + "initItemsUsedStats", + "initializeBrokenItemStats" + }, + constant = @Constant(intValue = 32000) + ) + private static int stationapi_getItemsSize(int constant) { + return Item.ITEMS.length; + } + + @WrapOperation( + method = { + "initializeCraftedItemStats", + "initItemsUsedStats", + "initializeBrokenItemStats" + }, + at = @At( + value = "NEW", + target = "(ILjava/lang/String;I)Lnet/minecraft/stat/ItemOrBlockStat;" + ) + ) + private static ItemOrBlockStat stationapi_removeIdReservationFromModdedItemStats( + int rawId, String translationKey, int itemIdOrBlockId, Operation original + ) { + return original.call( + ItemRegistry.INSTANCE.getId(itemIdOrBlockId).orElseThrow().getNamespace() == Namespace.MINECRAFT + ? rawId + : StatRegistry.AUTO_ID, + translationKey, + itemIdOrBlockId + ); + } + + @WrapOperation( + method = "initBlocksMined", + at = @At( + value = "NEW", + target = "(ILjava/lang/String;I)Lnet/minecraft/stat/ItemOrBlockStat;" + ) + ) + private static ItemOrBlockStat stationapi_removeIdReservationFromModdedBlockStats( + int rawId, String translationKey, int itemIdOrBlockId, Operation original + ) { + return original.call( + BlockRegistry.INSTANCE.getId(itemIdOrBlockId).orElseThrow().getNamespace() == Namespace.MINECRAFT + ? rawId + : StatRegistry.AUTO_ID, + translationKey, + itemIdOrBlockId + ); + } + + @Redirect( + method = "initItemsUsedStats", + at = @At( + value = "FIELD", + target = "Lnet/minecraft/block/Block;BLOCKS:[Lnet/minecraft/block/Block;", + opcode = Opcodes.GETSTATIC, + args = "array=length" + ) + ) + private static int stationapi_fixBlockCheck( + Block[] array, + @Local(index = 5) int id + ) { + return Item.ITEMS[id] instanceof BlockItemForm ? id + 1 : id; + } +} \ No newline at end of file diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/client/stats/BlockItemFormTranslationMixin.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/client/stats/BlockItemFormTranslationMixin.java new file mode 100644 index 000000000..faac15057 --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/client/stats/BlockItemFormTranslationMixin.java @@ -0,0 +1,49 @@ +package net.modificationstation.stationapi.mixin.flattening.client.stats; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import net.minecraft.block.Block; +import net.minecraft.stat.ItemOrBlockStat; +import net.minecraft.stat.Stats; +import net.modificationstation.stationapi.api.util.Util; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(targets = { + "net.minecraft.client.gui.screen.StatsScreen$AbstractStatsListWidget", + "net.minecraft.client.gui.screen.StatsScreen$BlockStatsListWidget" +}) +class BlockItemFormTranslationMixin { + @Unique + private final Reference2IntMap stationapi_idCache = Util.make( + new Reference2IntOpenHashMap<>(), + map -> map.defaultReturnValue(-1) + ); + + @WrapOperation( + method = "*", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/stat/ItemOrBlockStat;getItemOrBlockId()I" + ), + require = 0 + ) + private int stationapi_translateToBlockItemForm(ItemOrBlockStat instance, Operation original) { + var cachedId = stationapi_idCache.getInt(instance); + if (cachedId > -1) + return cachedId; + + int id = original.call(instance); + if (Stats.BLOCK_MINED_STATS.contains(instance)) { + var item = Block.BLOCKS[id].asItem(); + if (item != null) + id = item.id; + } + + stationapi_idCache.put(instance, id); + return id; + } +} diff --git a/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/client/stats/PlayerStatsMixin.java b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/client/stats/PlayerStatsMixin.java new file mode 100644 index 000000000..2c534de53 --- /dev/null +++ b/station-flattening-v0/src/main/java/net/modificationstation/stationapi/mixin/flattening/client/stats/PlayerStatsMixin.java @@ -0,0 +1,84 @@ +package net.modificationstation.stationapi.mixin.flattening.client.stats; + +import argo.jdom.JsonNode; +import argo.jdom.JsonRootNode; +import argo.jdom.JsonStringNode; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalRef; +import net.minecraft.stat.PlayerStats; +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.registry.StatRegistry; +import net.modificationstation.stationapi.api.util.Identifier; +import net.modificationstation.stationapi.impl.stat.ModdedStatsSerializingIterator; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.*; + +@Mixin(PlayerStats.class) +class PlayerStatsMixin { + @Inject( + method = "deserialize", + at = @At( + value = "NEW", + target = "(Ljava/lang/String;)Lnet/minecraft/util/MD5MessageDigest;" + ) + ) + private static void stationapi_deserializeModdedStats( + String data, CallbackInfoReturnable> cir, + @Local(index = 1) HashMap statCounts, @Local(index = 4) JsonRootNode statsRoot + ) { + //noinspection unchecked + for (final JsonNode node : (List) statsRoot.getArrayNode(ModdedStatsSerializingIterator.STATIONAPI_STATS_CHANGE_KEY)) { + @SuppressWarnings("unchecked") final Map statCountNodes = node.getFields(); + final Map.Entry statCountNode = statCountNodes.entrySet().iterator().next(); + final Identifier statId = Identifier.tryParse(statCountNode.getKey().getText()); + final Stat stat = StatRegistry.INSTANCE.get(statId); + final int count = Integer.parseInt(statCountNode.getValue().getText()); + if (stat == null) + System.out.println(statId + " is not a valid stat"); + else + statCounts.put(stat, count); + } + } + + @WrapOperation( + method = "serialize", + at = @At( + value = "INVOKE", + target = "Ljava/util/Set;iterator()Ljava/util/Iterator;" + ) + ) + private static Iterator stationapi_filterOutModdedStats( + Set instance, Operation> original, + @Local(index = 2, argsOnly = true) Map statCounts, + @Share("moddedStats") LocalRef moddedStatsRef + ) { + final StringBuilder moddedStats = new StringBuilder(); + moddedStatsRef.set(moddedStats); + + return new ModdedStatsSerializingIterator(original.call(instance), moddedStats, statCounts); + } + + @Inject( + method = "serialize", + at = @At( + value = "INVOKE", + target = "Ljava/lang/StringBuilder;append(Ljava/lang/String;)Ljava/lang/StringBuilder;", + ordinal = 17, + shift = At.Shift.AFTER + ) + ) + private static void stationapi_appendModdedStats( + String playerName, String sessionId, Map stats, CallbackInfoReturnable cir, + @Local(index = 3) StringBuilder statsJson, + @Share("moddedStats") LocalRef moddedStatsRef + ) { + statsJson.append(moddedStatsRef.get()); + } +} diff --git a/station-flattening-v0/src/main/resources/fabric.mod.json b/station-flattening-v0/src/main/resources/fabric.mod.json index 73e6844e1..a2127702e 100644 --- a/station-flattening-v0/src/main/resources/fabric.mod.json +++ b/station-flattening-v0/src/main/resources/fabric.mod.json @@ -77,6 +77,9 @@ ], "net/minecraft/class_50": [ "net/modificationstation/stationapi/api/world/dimension/StationDimension" + ], + "net/minecraft/class_139": [ + "net/modificationstation/stationapi/api/stat/StationFlatteningStat" ] } } diff --git a/station-flattening-v0/src/main/resources/station-flattening-v0.mixins.json b/station-flattening-v0/src/main/resources/station-flattening-v0.mixins.json index 144e5e46a..52806c5a9 100644 --- a/station-flattening-v0/src/main/resources/station-flattening-v0.mixins.json +++ b/station-flattening-v0/src/main/resources/station-flattening-v0.mixins.json @@ -35,6 +35,8 @@ "RegionFileAccessor", "SecondaryBlockItemMixin", "SkylandsChunkGeneratorMixin", + "StatMixin", + "StatsMixin", "WorldMixin", "WorldPropertiesMixin" ], @@ -48,7 +50,9 @@ "client.MultiplayerInteractionManagerMixin", "client.PlayerEntityRendererMixin", "client.SingleplayerInteractionManagerMixin", - "client.WorldRendererMixin" + "client.WorldRendererMixin", + "client.stats.BlockItemFormTranslationMixin", + "client.stats.PlayerStatsMixin" ], "injectors": { "defaultRequire": 1 diff --git a/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/StatsMixin.java b/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/StatsMixin.java index 69e413e75..75dabc0de 100644 --- a/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/StatsMixin.java +++ b/station-items-v0/src/main/java/net/modificationstation/stationapi/mixin/item/StatsMixin.java @@ -1,26 +1,15 @@ package net.modificationstation.stationapi.mixin.item; -import net.minecraft.item.Item; import net.minecraft.stat.Stats; import net.modificationstation.stationapi.api.StationAPI; import net.modificationstation.stationapi.api.event.registry.AfterBlockAndItemRegisterEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Constant; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.ModifyConstant; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Stats.class) class StatsMixin { - @ModifyConstant( - method = "initializeCraftedItemStats", - constant = @Constant(intValue = 32000) - ) - private static int stationapi_getItemsSize(int constant) { - return Item.ITEMS.length; - } - @Inject( method = "initializeCraftedItemStats", at = @At( diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/Int2ObjectMapTracker.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/Int2ObjectMapTracker.java index 7d240b0b7..1324d5e83 100644 --- a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/Int2ObjectMapTracker.java +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/Int2ObjectMapTracker.java @@ -1,6 +1,7 @@ package net.modificationstation.stationapi.api.registry.sync.trackers; import com.google.common.base.Joiner; +import com.mojang.datafixers.util.Either; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -13,11 +14,14 @@ import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager; import net.modificationstation.stationapi.api.registry.ListenableRegistry; import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.registry.RemappableRawIdHolder; import net.modificationstation.stationapi.api.util.Identifier; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.function.Function; import static net.modificationstation.stationapi.api.StationAPI.LOGGER; @@ -26,17 +30,29 @@ public class Int2ObjectMapTracker { EntrypointManager.registerLookup(MethodHandles.lookup()); } + @FunctionalInterface private interface Put { T put(int key, T value); } + @FunctionalInterface private interface ContainsKey { boolean containsKey(int key); } + private final String name; - private final Int2ObjectMap mappers; + private final Either, Int2ObjectMap> mappers; private final Reference2ObjectMap removedMapperCache = new Reference2ObjectOpenHashMap<>(); + private final boolean remapValues; - private Int2ObjectMapTracker(String name, Int2ObjectMap mappers) { + private Int2ObjectMapTracker(String name, Either, Int2ObjectMap> mappers, boolean remapValues) { this.name = name; this.mappers = mappers; + this.remapValues = remapValues; + } + + public static & ListenableRegistry> void register(R registry, String name, Map mappers, boolean remapValues) { + register(registry, new Int2ObjectMapTracker<>(name, Either.left(mappers), remapValues)); + } + + public static & ListenableRegistry> void register(R registry, String name, Int2ObjectMap mappers, boolean remapValues) { + register(registry, new Int2ObjectMapTracker<>(name, Either.right(mappers), remapValues)); } - public static & ListenableRegistry> void register(R registry, String name, Int2ObjectMap mappers) { - Int2ObjectMapTracker tracker = new Int2ObjectMapTracker<>(name, mappers); + private static & ListenableRegistry> void register(R registry, Int2ObjectMapTracker tracker) { registry.getEventBus().register(Listener.object() .listener(tracker) .build()); @@ -45,26 +61,31 @@ public static & ListenableRegistry> void register( @EventListener private void onEntryAdded(RegistryEntryAddedEvent event) { if (removedMapperCache.containsKey(event.id)) - mappers.put(event.rawId, removedMapperCache.get(event.id)); + mappers.>map(map -> map::put, map -> map::put).put(event.rawId, removedMapperCache.get(event.id)); } @EventListener private void onRemap(RegistryIdRemapEvent event) { - Int2ObjectMap oldMappers = new Int2ObjectOpenHashMap<>(mappers); + Int2ObjectMap oldMappers = mappers.map(Int2ObjectOpenHashMap::new, Int2ObjectOpenHashMap::new); Int2IntMap remapMap = event.state.getRawIdChangeMap(); List errors = null; - mappers.clear(); + mappers.map(Function.identity(), Function.identity()).clear(); for (int i : oldMappers.keySet()) { int newI = remapMap.getOrDefault(i, Integer.MIN_VALUE); if (newI >= 0) { - if (mappers.containsKey(newI)) { + if (mappers.map(map -> map::containsKey, map -> map::containsKey).containsKey(newI)) { if (errors == null) errors = new ArrayList<>(); errors.add(" - Map contained two equal IDs " + newI + " (" + event.state.getIdFromOld(i) + "/" + i + " -> " + event.state.getIdFromNew(newI) + "/" + newI + ")!"); - } else mappers.put(newI, oldMappers.get(i)); + } else { + final OV value = oldMappers.get(i); + mappers.>map(map -> map::put, map -> map::put).put(newI, value); + if (remapValues && value instanceof RemappableRawIdHolder holder) + holder.setRawId(newI); + } } else { LOGGER.warn("Int2ObjectMap " + name + " is dropping mapping for integer ID " + i + " (" + event.state.getIdFromOld(i) + ") - should not happen!"); removedMapperCache.put(event.state.getIdFromOld(i), oldMappers.get(i)); diff --git a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/ObjectArrayTracker.java b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/ObjectArrayTracker.java index c18059018..e3e95da35 100644 --- a/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/ObjectArrayTracker.java +++ b/station-registry-api-v0/src/main/java/net/modificationstation/stationapi/api/registry/sync/trackers/ObjectArrayTracker.java @@ -25,13 +25,15 @@ public class ObjectArrayTracker { private final Supplier arrayGetter; private final Consumer arraySetter; + private final boolean remapValues; public static & ListenableRegistry> void register( R registry, Supplier arrayGetter, - Consumer arraySetter + Consumer arraySetter, + boolean remapValues ) { - ObjectArrayTracker tracker = new ObjectArrayTracker<>(arrayGetter, arraySetter); + ObjectArrayTracker tracker = new ObjectArrayTracker<>(arrayGetter, arraySetter, remapValues); registry.getEventBus().register(Listener.object() .listener(tracker) .build()); @@ -39,10 +41,12 @@ public static & ListenableRegistry> void register( private ObjectArrayTracker( Supplier arrayGetter, - Consumer arraySetter + Consumer arraySetter, + boolean remapValues ) { this.arrayGetter = arrayGetter; this.arraySetter = arraySetter; + this.remapValues = remapValues; } public static boolean shouldGrow(V[] array, int highestExpectedRawId) { @@ -74,7 +78,7 @@ private void onRemap(RegistryIdRemapEvent event) { if (shouldGrow(array, newId)) array = grow(array, newId); array[newId] = value; - if (value instanceof RemappableRawIdHolder holder) + if (remapValues && value instanceof RemappableRawIdHolder holder) holder.setRawId(newId); } diff --git a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java index c4a5f15d2..72254708b 100644 --- a/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java +++ b/station-renderer-api-v0/src/main/java/net/modificationstation/stationapi/api/client/render/item/ItemModels.java @@ -30,8 +30,8 @@ public class ItemModels { public ItemModels(BakedModelManager modelManager) { this.modelManager = modelManager; ITEM_MODELS.add(this); - Int2ObjectMapTracker.register(ItemRegistry.INSTANCE, "ItemModels.modelIds", modelIds); - Int2ObjectMapTracker.register(ItemRegistry.INSTANCE, "ItemModels.models", models); + Int2ObjectMapTracker.register(ItemRegistry.INSTANCE, "ItemModels.modelIds", modelIds, false); + Int2ObjectMapTracker.register(ItemRegistry.INSTANCE, "ItemModels.models", models, false); } public BakedModel getModel(ItemStack stack) { diff --git a/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/achievement/AchievementTemplate.java b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/achievement/AchievementTemplate.java new file mode 100644 index 000000000..38c1f6d2c --- /dev/null +++ b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/achievement/AchievementTemplate.java @@ -0,0 +1,16 @@ +package net.modificationstation.stationapi.api.template.achievement; + +import net.minecraft.achievement.Achievement; +import net.modificationstation.stationapi.api.registry.StatRegistry; +import net.modificationstation.stationapi.api.template.stat.StatTemplate; +import net.modificationstation.stationapi.api.util.Identifier; + +public interface AchievementTemplate extends StatTemplate { + static int getNextId() { + return StatRegistry.SHIFTED_ACHIEVEMENT_ID.get(StatTemplate.getNextId()); + } + + static void onConstructor(Achievement achievement, Identifier id) { + StatTemplate.onConstructor(achievement, id); + } +} diff --git a/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/achievement/TemplateAchievement.java b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/achievement/TemplateAchievement.java new file mode 100644 index 000000000..6f41151a0 --- /dev/null +++ b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/achievement/TemplateAchievement.java @@ -0,0 +1,36 @@ +package net.modificationstation.stationapi.api.template.achievement; + +import net.minecraft.achievement.Achievement; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.modificationstation.stationapi.api.util.Identifier; + +public class TemplateAchievement extends Achievement implements AchievementTemplate { + public TemplateAchievement(Identifier identifier, String key, int column, int row, Item displayItem, Achievement parent) { + this(AchievementTemplate.getNextId(), key, column, row, displayItem, parent); + AchievementTemplate.onConstructor(this, identifier); + } + + public TemplateAchievement(Identifier identifier, String key, int column, int row, Block displayBlock, Achievement parent) { + this(AchievementTemplate.getNextId(), key, column, row, displayBlock, parent); + AchievementTemplate.onConstructor(this, identifier); + } + + public TemplateAchievement(Identifier identifier, String key, int column, int row, ItemStack icon, Achievement parent) { + this(AchievementTemplate.getNextId(), key, column, row, icon, parent); + AchievementTemplate.onConstructor(this, identifier); + } + + public TemplateAchievement(int id, String key, int column, int row, Item displayItem, Achievement parent) { + super(id, key, column, row, displayItem, parent); + } + + public TemplateAchievement(int id, String key, int column, int row, Block displayBlock, Achievement parent) { + super(id, key, column, row, displayBlock, parent); + } + + public TemplateAchievement(int id, String key, int column, int row, ItemStack icon, Achievement parent) { + super(id, key, column, row, icon, parent); + } +} \ No newline at end of file diff --git a/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/StatTemplate.java b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/StatTemplate.java new file mode 100644 index 000000000..8ad357924 --- /dev/null +++ b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/StatTemplate.java @@ -0,0 +1,16 @@ +package net.modificationstation.stationapi.api.template.stat; + +import net.minecraft.stat.Stat; +import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.registry.StatRegistry; +import net.modificationstation.stationapi.api.util.Identifier; + +public interface StatTemplate { + static int getNextId() { + return StatRegistry.AUTO_ID; + } + + static void onConstructor(Stat stat, Identifier id) { + Registry.register(StatRegistry.INSTANCE, stat.id, id, stat); + } +} \ No newline at end of file diff --git a/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateItemOrBlockStat.java b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateItemOrBlockStat.java new file mode 100644 index 000000000..1eaf058f2 --- /dev/null +++ b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateItemOrBlockStat.java @@ -0,0 +1,15 @@ +package net.modificationstation.stationapi.api.template.stat; + +import net.minecraft.stat.ItemOrBlockStat; +import net.modificationstation.stationapi.api.util.Identifier; + +public class TemplateItemOrBlockStat extends ItemOrBlockStat implements StatTemplate { + public TemplateItemOrBlockStat(Identifier identifier, String translationKey, int itemIdOrBlockId) { + this(StatTemplate.getNextId(), translationKey, itemIdOrBlockId); + StatTemplate.onConstructor(this, identifier); + } + + public TemplateItemOrBlockStat(int statId, String translationKey, int itemIdOrBlockId) { + super(statId, translationKey, itemIdOrBlockId); + } +} \ No newline at end of file diff --git a/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateSimpleStat.java b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateSimpleStat.java new file mode 100644 index 000000000..1c64d2f17 --- /dev/null +++ b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateSimpleStat.java @@ -0,0 +1,25 @@ +package net.modificationstation.stationapi.api.template.stat; + +import net.minecraft.stat.SimpleStat; +import net.minecraft.stat.StatFormatter; +import net.modificationstation.stationapi.api.util.Identifier; + +public class TemplateSimpleStat extends SimpleStat implements StatTemplate { + public TemplateSimpleStat(Identifier identifier, String stringId, StatFormatter statTypeProvider) { + this(StatTemplate.getNextId(), stringId, statTypeProvider); + StatTemplate.onConstructor(this, identifier); + } + + public TemplateSimpleStat(Identifier identifier, String stringId) { + this(StatTemplate.getNextId(), stringId); + StatTemplate.onConstructor(this, identifier); + } + + public TemplateSimpleStat(int id, String stringId, StatFormatter statTypeProvider) { + super(id, stringId, statTypeProvider); + } + + public TemplateSimpleStat(int id, String stringId) { + super(id, stringId); + } +} \ No newline at end of file diff --git a/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateStat.java b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateStat.java new file mode 100644 index 000000000..c2b85259e --- /dev/null +++ b/station-templates-v0/src/main/java/net/modificationstation/stationapi/api/template/stat/TemplateStat.java @@ -0,0 +1,25 @@ +package net.modificationstation.stationapi.api.template.stat; + +import net.minecraft.stat.Stat; +import net.minecraft.stat.StatFormatter; +import net.modificationstation.stationapi.api.util.Identifier; + +public class TemplateStat extends Stat implements StatTemplate { + public TemplateStat(Identifier identifier, String stringId, StatFormatter statTypeProvider) { + this(StatTemplate.getNextId(), stringId, statTypeProvider); + StatTemplate.onConstructor(this, identifier); + } + + public TemplateStat(Identifier identifier, String stringId) { + this(StatTemplate.getNextId(), stringId); + StatTemplate.onConstructor(this, identifier); + } + + public TemplateStat(int id, String stringId, StatFormatter statTypeProvider) { + super(id, stringId, statTypeProvider); + } + + public TemplateStat(int id, String stringId) { + super(id, stringId); + } +} \ No newline at end of file diff --git a/station-vanilla-fix-v0/build.gradle.kts b/station-vanilla-fix-v0/build.gradle.kts index 524049ee2..086f9e285 100644 --- a/station-vanilla-fix-v0/build.gradle.kts +++ b/station-vanilla-fix-v0/build.gradle.kts @@ -1,5 +1,6 @@ -import net.modificationstation.stationapi.gradle.SubprojectHelpers.getSubprojectVersion import net.modificationstation.stationapi.gradle.SubprojectHelpers.addModuleDependencies +import net.modificationstation.stationapi.gradle.SubprojectHelpers.getSubprojectVersion + base.archivesName.set("station-vanilla-fix-v0") version = getSubprojectVersion(project, "1.0.0") @@ -20,5 +21,6 @@ addModuleDependencies(project, "station-nbt-v0", "station-localization-api-v0", "station-gui-api-v0", - "station-renderer-api-v0" + "station-renderer-api-v0", + "station-achievements-v0" ) \ No newline at end of file diff --git a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/achievement/VanillaAchievementFixImpl.java b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/achievement/VanillaAchievementFixImpl.java new file mode 100644 index 000000000..56f25087b --- /dev/null +++ b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/achievement/VanillaAchievementFixImpl.java @@ -0,0 +1,48 @@ +package net.modificationstation.stationapi.impl.vanillafix.achievement; + +import net.mine_diver.unsafeevents.listener.EventListener; +import net.minecraft.achievement.Achievement; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.achievement.AchievementRegisterEvent; +import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; +import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager; +import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; +import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.registry.StatRegistry; + +import java.lang.invoke.MethodHandles; + +import static net.minecraft.achievement.Achievements.*; +import static net.modificationstation.stationapi.api.util.Identifier.of; + +@Entrypoint(eventBus = @EventBusPolicy(registerInstance = false)) +@EventListener(phase = StationAPI.INTERNAL_PHASE) +public final class VanillaAchievementFixImpl { + static { + EntrypointManager.registerLookup(MethodHandles.lookup()); + } + + @EventListener + private static void registerStats(AchievementRegisterEvent event) { + register("open_inventory", OPEN_INVENTORY); + register("mine_wood", MINE_WOOD); + register("craft_workbench", CRAFT_WORKBENCH); + register("craft_pickaxe", CRAFT_PICKAXE); + register("craft_furnace", CRAFT_FURNACE); + register("acquire_iron", ACQUIRE_IRON); + register("craft_hoe", CRAFT_HOE); + register("craft_bread", CRAFT_BREAD); + register("craft_cake", CRAFT_CAKE); + register("craft_stone_pickaxe", CRAFT_STONE_PICKAXE); + register("cook_fish", COOK_FISH); + register("craft_rail", CRAFT_RAIL); + register("craft_sword", CRAFT_SWORD); + register("kill_enemy", KILL_ENEMY); + register("kill_cow", KILL_COW); + register("fly_pig", FLY_PIG); + } + + private static void register(String id, Achievement achievement) { + Registry.register(StatRegistry.INSTANCE, achievement.id, of(id), achievement); + } +} \ No newline at end of file diff --git a/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/stat/VanillaStatFixImpl.java b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/stat/VanillaStatFixImpl.java new file mode 100644 index 000000000..19ca1a6c8 --- /dev/null +++ b/station-vanilla-fix-v0/src/main/java/net/modificationstation/stationapi/impl/vanillafix/stat/VanillaStatFixImpl.java @@ -0,0 +1,57 @@ +package net.modificationstation.stationapi.impl.vanillafix.stat; + +import net.mine_diver.unsafeevents.listener.EventListener; +import net.minecraft.stat.Stat; +import net.minecraft.stat.Stats; +import net.modificationstation.stationapi.api.StationAPI; +import net.modificationstation.stationapi.api.event.registry.StatRegistryEvent; +import net.modificationstation.stationapi.api.mod.entrypoint.Entrypoint; +import net.modificationstation.stationapi.api.mod.entrypoint.EntrypointManager; +import net.modificationstation.stationapi.api.mod.entrypoint.EventBusPolicy; +import net.modificationstation.stationapi.api.registry.Registry; +import net.modificationstation.stationapi.api.registry.StatRegistry; + +import java.lang.invoke.MethodHandles; + +import static net.modificationstation.stationapi.api.util.Identifier.of; + +@Entrypoint(eventBus = @EventBusPolicy(registerInstance = false)) +@EventListener(phase = StationAPI.INTERNAL_PHASE) +public final class VanillaStatFixImpl { + static { + EntrypointManager.registerLookup(MethodHandles.lookup()); + } + + @EventListener + private static void registerStats(StatRegistryEvent event) { + StatRegistry registry = event.registry; + + register(registry, "start_game", Stats.START_GAME); + register(registry, "create_world", Stats.CREATE_WORLD); + register(registry, "load_world", Stats.LOAD_WORLD); + register(registry, "join_multiplayer", Stats.JOIN_MULTIPLAYER); + register(registry, "leave_game", Stats.LEAVE_GAME); + register(registry, "play_one_minute", Stats.PLAY_ONE_MINUTE); + register(registry, "walk_one_cm", Stats.WALK_ONE_CM); + register(registry, "swim_one_cm", Stats.SWIM_ONE_CM); + register(registry, "fall_one_cm", Stats.FALL_ONE_CM); + register(registry, "climb_one_cm", Stats.CLIMB_ONE_CM); + register(registry, "fly_one_cm", Stats.FLY_ONE_CM); + register(registry, "dive_one_cm", Stats.DIVE_ONE_CM); + register(registry, "minecart_one_cm", Stats.MINECART_ONE_CM); + register(registry, "boat_one_cm", Stats.BOAT_ONE_CM); + register(registry, "pig_one_cm", Stats.PIG_ONE_CM); + register(registry, "jump", Stats.JUMP); + register(registry, "drop", Stats.DROP); + register(registry, "damage_dealt", Stats.DAMAGE_DEALT); + register(registry, "damage_taken", Stats.DAMAGE_TAKEN); + register(registry, "deaths", Stats.DEATHS); + register(registry, "mob_kills", Stats.MOB_KILLS); + register(registry, "player_kills", Stats.PLAYER_KILLS); + register(registry, "fish_caught", Stats.FISH_CAUGHT); + } + + private static void register(Registry registry, String id, Stat stat) { + Registry.register(registry, stat.id, of(id), stat); + } +} \ No newline at end of file diff --git a/station-vanilla-fix-v0/src/main/resources/fabric.mod.json b/station-vanilla-fix-v0/src/main/resources/fabric.mod.json index c795cf13d..dffd34acd 100644 --- a/station-vanilla-fix-v0/src/main/resources/fabric.mod.json +++ b/station-vanilla-fix-v0/src/main/resources/fabric.mod.json @@ -24,7 +24,9 @@ "net.modificationstation.stationapi.impl.vanillafix.item.VanillaItemFixImpl", "net.modificationstation.stationapi.impl.vanillafix.dimension.VanillaDimensionFixImpl", "net.modificationstation.stationapi.impl.vanillafix.recipe.VanillaFuelItemFixImpl", - "net.modificationstation.stationapi.impl.vanillafix.datafixer.VanillaDataFixerImpl" + "net.modificationstation.stationapi.impl.vanillafix.datafixer.VanillaDataFixerImpl", + "net.modificationstation.stationapi.impl.vanillafix.stat.VanillaStatFixImpl", + "net.modificationstation.stationapi.impl.vanillafix.achievement.VanillaAchievementFixImpl" ], "stationapi:event_bus_client": [ "net.modificationstation.stationapi.impl.vanillafix.client.gui.screen.EditWorldScreenImpl",