Update to 1.21.3, fix tests

This commit is contained in:
embeddedt 2024-10-24 10:26:16 -04:00
parent e0d24d4cdb
commit f374bcbb3a
No known key found for this signature in database
GPG Key ID: A69433EC199B5613
15 changed files with 16 additions and 410 deletions

View File

@ -1,7 +1,7 @@
package org.embeddedt.modernfix.fabric.mixin.core;
package org.embeddedt.modernfix.common.mixin.core;
import net.minecraft.client.multiplayer.ClientPacketListener;
import org.embeddedt.modernfix.ModernFixClientFabric;
import org.embeddedt.modernfix.ModernFixClient;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -13,6 +13,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class ClientPlayNetHandlerMixin {
@Inject(method = "handleUpdateRecipes", at = @At("RETURN"))
private void signalRecipes(CallbackInfo ci) {
ModernFixClientFabric.commonMod.onRecipesUpdated();
ModernFixClient.INSTANCE.onRecipesUpdated();
}
}

View File

@ -1,97 +0,0 @@
package net.minecraft.world.level.block.state;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import org.embeddedt.modernfix.duck.IBlockState;
import org.embeddedt.modernfix.testing.util.BootstrapMinecraft;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
@BootstrapMinecraft
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlockStateCacheTest {
@BeforeEach
public void rebuildCache() {
Blocks.rebuildCache();
}
/**
* Initially, the cache should be invalid, and null.
*/
@Test
@Order(1)
public void testCacheNullInitially() {
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
assertTrue(((IBlockState)stoneBlock).isCacheInvalid());
assertNull(stoneBlock.cache);
// make sure lazy cache correctly handles solid
assertTrue(stoneBlock.isSolid());
}
/**
* When an API that needs the cache is called, it should be built and the invalid flag
* becomes false.
*/
@Test
@Order(2)
public void testCacheBuiltByRequest() {
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
stoneBlock.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
assertFalse(((IBlockState)stoneBlock).isCacheInvalid());
assertNotNull(stoneBlock.cache);
}
/**
* When a second rebuild occurs, the invalid flag should be set to true, but the old cache
* is not set to null, in order to prevent NPEs if a second thread is accessing the cache
* when this takes place.
*/
@Test
@Order(3)
public void testCacheInvalidatedByLateRebuild() {
BlockState stoneBlock = Blocks.STONE.defaultBlockState();
stoneBlock.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
Blocks.rebuildCache();
assertTrue(((IBlockState)stoneBlock).isCacheInvalid());
assertNotNull(stoneBlock.cache);
}
/**
* Tests that the fluidState and isRandomlyTicking caching fields added by Mojang to blockstates are correctly
* handled by the dynamic cache system.
*/
@Test
@Order(4)
public void testExtraFieldCachingCorrect() {
Block[] blocksToCheck = new Block[] { Blocks.WATER, Blocks.FARMLAND };
for(Block block : blocksToCheck) {
for(BlockState state : block.getStateDefinition().getPossibleStates()) {
// check that the fluid states match
assertEquals(block.getFluidState(state), state.getFluidState(), "mismatched fluid state on " + state);
// check that random ticking flag matches
assertEquals(block.isRandomlyTicking(state), state.isRandomlyTicking(), "mismatched random tick state on " + state);
}
}
}
/*
@Test
@Order(5)
public void checkRecursiveFluidState() {
Block b = new Block(BlockBehaviour.Properties.copy(Blocks.STONE)) {
@Override
public FluidState getFluidState(BlockState state) {
return state.getFluidState();
}
};
BlockState state = b.getStateDefinition().any();
((IBlockState)state).clearCache();
// this should not throw
state.getFluidState();
}
*/
}

View File

@ -19,7 +19,7 @@ public class DynamicModelCacheTest {
@Test
public void testCacheFunctions() {
BakedModel model = new BuiltInModel(null, null, null, false);
BakedModel model = new BuiltInModel(null, null, false);
DynamicModelCache<Item> cache = new DynamicModelCache(k -> model, true);
assertEquals(model, cache.get(Items.STONE));
}

View File

@ -5,9 +5,9 @@ junit_version=5.10.0-M1
mixinextras_version=0.3.2
mod_id=modernfix
minecraft_version=1.21.2-rc1
enabled_platforms=fabric
forge_version=21.1.15
minecraft_version=1.21.3
enabled_platforms=fabric,neoforge
forge_version=21.3.1-beta
parchment_version=2024.07.07
parchment_mc_version=1.21
refined_storage_version=4392788
@ -18,8 +18,8 @@ kubejs_version=1902.6.0-build.142
rhino_version=1902.2.2-build.268
supported_minecraft_versions=1.21.1
fabric_loader_version=0.16.6
fabric_api_version=0.106.0+1.21.2
fabric_loader_version=0.16.7
fabric_api_version=0.106.1+1.21.3
continuity_version=3.0.0-beta.4+1.20.2

View File

@ -8,7 +8,7 @@ import com.google.common.graph.GraphBuilder;
import com.google.common.graph.MutableGraph;
import net.minecraft.client.renderer.block.BlockModelShaper;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.MissingBlockModel;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
@ -125,7 +125,7 @@ public class ModelBakeEventHelper {
if(modIdsToInclude.stream().noneMatch(INCOMPATIBLE_MODS::contains))
return createWarningRegistry(modId);
Set<ModelResourceLocation> ourModelLocations = Sets.filter(this.topLevelModelLocations, loc -> modIdsToInclude.contains(loc.id().getNamespace()));
BakedModel missingModel = modelRegistry.get(ModelBakery.MISSING_MODEL_VARIANT);
BakedModel missingModel = modelRegistry.get(MissingBlockModel.VARIANT);
return new ForwardingMap<ModelResourceLocation, BakedModel>() {
@Override
protected Map<ModelResourceLocation, BakedModel> delegate() {

View File

@ -13,7 +13,6 @@ import net.neoforged.fml.ModLoadingIssue;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent;
import net.neoforged.neoforge.client.event.RecipesUpdatedEvent;
import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent;
import net.neoforged.neoforge.client.event.RenderFrameEvent;
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
@ -87,7 +86,7 @@ public class ModernFixClientForge {
public void onDisconnect(LevelEvent.Unload event) {
if(event.getLevel().isClientSide()) {
DebugScreenOverlay overlay = Minecraft.getInstance().getDebugOverlay();
Minecraft.getInstance().tell(overlay::clearChunkCache);
Minecraft.getInstance().execute(overlay::clearChunkCache);
}
}
@ -101,11 +100,6 @@ public class ModernFixClientForge {
commonMod.onRenderTickEnd();
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onRecipes(RecipesUpdatedEvent e) {
commonMod.onRecipesUpdated();
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onTags(TagsUpdatedEvent e) {
commonMod.onTagsUpdated();

View File

@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(LivingEntityRenderer.class)
@ClientOnlyMixin
public class LivingEntityRendererMixin {
@Redirect(method = "render(Lnet/minecraft/world/entity/LivingEntity;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;", ordinal = 0))
@Redirect(method = "render(Lnet/minecraft/client/renderer/entity/state/LivingEntityRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;", ordinal = 0))
private Event fireCheckingPoseStack(IEventBus instance, Event event) {
PoseStack stack = ((RenderLivingEvent)event).getPoseStack();
int size = ((PoseStackAccessor)stack).getPoseStack().size();

View File

@ -13,7 +13,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(PlayerRenderer.class)
@ClientOnlyMixin
public class PlayerRendererMixin {
@Redirect(method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;", ordinal = 0))
@Redirect(method = "render(Lnet/minecraft/client/renderer/entity/state/PlayerRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V", at = @At(value = "INVOKE", target = "Lnet/neoforged/bus/api/IEventBus;post(Lnet/neoforged/bus/api/Event;)Lnet/neoforged/bus/api/Event;", ordinal = 0), remap = false)
private Event fireCheckingPoseStack(IEventBus instance, Event event) {
PoseStack stack = ((RenderPlayerEvent)event).getPoseStack();
int size = ((PoseStackAccessor)stack).getPoseStack().size();

View File

@ -1,15 +0,0 @@
package org.embeddedt.modernfix.neoforge.mixin.perf.datapack_reload_exceptions;
import net.minecraft.world.item.crafting.RecipeManager;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(value = RecipeManager.class, priority = 2000)
public class RecipeManagerMixin {
@Redirect(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V", remap = false), require = 0)
private void silenceException(Logger instance, String s, Object location, Object exc) {
instance.error(s + ": {}", location, exc.toString());
}
}

View File

@ -1,91 +0,0 @@
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
import net.minecraft.client.renderer.ItemModelShaper;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.neoforged.neoforge.client.model.RegistryAwareItemModelShaper;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.dynamicresources.DynamicModelCache;
import org.embeddedt.modernfix.dynamicresources.ModelLocationCache;
import org.embeddedt.modernfix.util.ItemMesherMap;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.HashMap;
import java.util.Map;
@Mixin(RegistryAwareItemModelShaper.class)
@ClientOnlyMixin
public abstract class ItemModelMesherForgeMixin extends ItemModelShaper {
@Shadow(remap = false) @Final @Mutable private Map<Item, ModelResourceLocation> locations;
private Map<Item, ModelResourceLocation> overrideLocations;
private final DynamicModelCache<Item> mfix$modelCache = new DynamicModelCache<>(k -> this.mfix$getModelSlow((Item)k), true);
public ItemModelMesherForgeMixin(ModelManager arg) {
super(arg);
}
private static final ModelResourceLocation SENTINEL = new ModelResourceLocation(ResourceLocation.fromNamespaceAndPath("modernfix", "sentinel"), "sentinel");
@Inject(method = "<init>", at = @At("RETURN"))
private void replaceLocationMap(CallbackInfo ci) {
overrideLocations = new HashMap<>();
// need to replace this map because mods query locations through it
locations = new ItemMesherMap<>(this::mfix$getLocationForge);
}
@Unique
private ModelResourceLocation mfix$getLocationForge(Item item) {
ModelResourceLocation map = overrideLocations.getOrDefault(item, SENTINEL);
if(map == SENTINEL) {
/* generate the appropriate location from our cache */
map = ModelLocationCache.get(item);
}
return map;
}
private BakedModel mfix$getModelSlow(Item key) {
ModelResourceLocation map = mfix$getLocationForge(key);
return map == null ? null : getModelManager().getModel(map);
}
/**
* @author embeddedt
* @reason Get the stored location for that item and meta, and get the model
* from that location from the model manager.
**/
@Overwrite
@Override
public BakedModel getItemModel(Item item) {
return this.mfix$modelCache.get(item);
}
/**
* @author embeddedt
* @reason Don't get all models during init (with dynamic loading, that would
* generate them all). Just store location instead.
**/
@Overwrite
@Override
public void register(Item item, ModelResourceLocation location) {
overrideLocations.put(item, location);
}
/**
* @author embeddedt
* @reason Disable cache rebuilding (with dynamic loading, that would generate
* all models).
**/
@Overwrite
@Override
public void rebuildCache() {
this.mfix$modelCache.clear();
}
}

View File

@ -1,28 +0,0 @@
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.UnbakedModel;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.duck.IExtendedModelBakery;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
@Mixin(targets = {"net/minecraft/client/resources/model/ModelBakery$ModelBakerImpl"})
@ClientOnlyMixin
public class ModelBakerImplMixin {
@Shadow @Final private ModelBakery field_40571;
/**
* @author embeddedt
* @reason Handle dynamic model loading
*/
@Overwrite(remap = false)
public UnbakedModel getTopLevelModel(ModelResourceLocation location) {
IExtendedModelBakery bakery = (IExtendedModelBakery)this.field_40571;
UnbakedModel model = bakery.mfix$loadUnbakedModelDynamic(location);
return model == bakery.mfix$getMissingModel() ? null : model;
}
}

View File

@ -1,16 +0,0 @@
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.ctm;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.client.resources.model.ModelBakery;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Map;
@Mixin(ModelBakery.class)
@ClientOnlyMixin
public interface CTMModelBakeryAccessor {
@Accessor("bakedCache")
Map<ModelBakery.BakedCacheKey, BakedModel> mfix$getBakedCache();
}

View File

@ -1,114 +0,0 @@
package org.embeddedt.modernfix.neoforge.mixin.perf.dynamic_resources.ctm;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.resources.model.*;
import net.minecraft.resources.ResourceLocation;
import org.embeddedt.modernfix.ModernFixClient;
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
import org.embeddedt.modernfix.annotation.RequiresMod;
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import team.chisel.ctm.CTM;
import team.chisel.ctm.api.model.IModelCTM;
import team.chisel.ctm.client.model.AbstractCTMBakedModel;
import team.chisel.ctm.client.model.ModelCTM;
import team.chisel.ctm.client.texture.IMetadataSectionCTM;
import team.chisel.ctm.client.util.ResourceUtil;
import team.chisel.ctm.client.util.TextureMetadataHandler;
import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.*;
@Mixin(TextureMetadataHandler.class)
@RequiresMod("ctm")
@ClientOnlyMixin
public abstract class TextureMetadataHandlerMixin implements ModernFixClientIntegration {
@Shadow(remap = false) @Nonnull protected abstract BakedModel wrap(UnbakedModel model, BakedModel object) throws IOException;
@Shadow(remap = false) @Final private Multimap<ResourceLocation, Material> scrapedTextures;
@Inject(method = "<init>", at = @At("RETURN"))
private void subscribeDynamic(CallbackInfo ci) {
ModernFixClient.CLIENT_INTEGRATIONS.add(this);
}
@Inject(method = { "onModelBake(Lnet/neoforged/neoforge/client/event/ModelEvent$BakingCompleted;)V", "onModelBake(Lnet/neoforged/neoforge/client/event/ModelEvent$ModifyBakingResult;)V" }, at = @At("HEAD"), cancellable = true, remap = false)
private void noIteration(CallbackInfo ci) {
ci.cancel();
}
@Override
public BakedModel onBakedModelLoad(ModelResourceLocation mrl, UnbakedModel rootModel, BakedModel baked, ModelState state, ModelBakery bakery, ModelBakery.TextureGetter getter) {
if (!(baked instanceof AbstractCTMBakedModel) && !baked.isCustomRenderer()) {
Deque<ResourceLocation> dependencies = new ArrayDeque<>();
Set<ResourceLocation> seenModels = new HashSet<>();
dependencies.push(mrl.id());
seenModels.add(mrl.id());
boolean shouldWrap = false;
Set<Pair<String, String>> errors = new HashSet<>();
// Breadth-first loop through dependencies, exiting as soon as a CTM texture is found, and skipping duplicates/cycles
while (!shouldWrap && !dependencies.isEmpty()) {
ResourceLocation dep = dependencies.pop();
UnbakedModel model;
try {
model = dep == mrl.id() ? rootModel : bakery.getModel(dep);
} catch (Exception e) {
continue;
}
Collection<Material> textures = Sets.newHashSet(scrapedTextures.get(dep));
Collection<ResourceLocation> newDependencies = model.getDependencies();
for (Material tex : textures) {
IMetadataSectionCTM meta = null;
// Cache all dependent texture metadata
try {
meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(tex.texture())).orElse(null); // TODO, lazy
} catch (IOException e) {} // Fallthrough
if (meta != null) {
// At least one texture has CTM metadata, so we should wrap this model
shouldWrap = true;
}
}
for (ResourceLocation newDep : newDependencies) {
if (seenModels.add(newDep)) {
dependencies.push(newDep);
}
}
}
if (shouldWrap) {
try {
baked = wrap(rootModel, baked);
handleInit(mrl, baked, bakery, getter);
dependencies.clear();
} catch (IOException e) {
CTM.logger.error("Could not wrap model " + mrl + ". Aborting...", e);
}
}
}
return baked;
}
private void handleInit(ModelResourceLocation key, BakedModel wrappedModel, ModelBakery bakery, ModelBakery.TextureGetter spriteGetter) {
if(wrappedModel instanceof AbstractCTMBakedModel baked) {
IModelCTM var10 = baked.getModel();
if (var10 instanceof ModelCTM ctmModel) {
if (!ctmModel.isInitialized()) {
// Clear the baked cache as upstream CTM does
((CTMModelBakeryAccessor)bakery).mfix$getBakedCache().clear();
ModelBakery.ModelBakerImpl baker = bakery.new ModelBakerImpl(spriteGetter, key);
ctmModel.bake(baker, Material::sprite, BlockModelRotation.X0_Y0);
}
}
}
}
}

View File

@ -1,27 +0,0 @@
package org.embeddedt.modernfix.neoforge.mixin.perf.reduce_blockstate_cache_rebuilds;
import com.google.common.collect.ImmutableList;
import net.minecraft.core.Registry;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(targets = { "net/neoforged/neoforge/registries/NeoForgeRegistryCallbacks$BlockCallbacks" })
public class BlockCallbacksMixin {
@Redirect(method = "onBake", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/StateDefinition;getPossibleStates()Lcom/google/common/collect/ImmutableList;", ordinal = 0))
private ImmutableList<BlockState> skipCache(StateDefinition<Block, BlockState> definition) {
// prevent initCache from being called on these blockstates
return ImmutableList.of();
}
@Inject(method = "onBake", at = @At(value = "TAIL"), remap = false)
private void computeCaches(Registry<Block> registry, CallbackInfo ci) {
BlockStateCacheHandler.rebuildParallel(false);
}
}

View File

@ -47,7 +47,7 @@ modId = "neoforge" #mandatory
# Does this dependency have to exist - if not, ordering below must be specified
type = "required" #mandatory
# The version range of the dependency
versionRange = "[21.0.111-beta,)" #mandatory
versionRange = "[21.3.1-beta,)" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering = "NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
@ -57,7 +57,7 @@ side = "BOTH"
modId = "minecraft"
type = "required"
# This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange = "[1.21, 1.22)"
versionRange = "[1.21.3, 1.22)"
ordering = "NONE"
side = "BOTH"
[[dependencies.modernfix]]