Skip to content

Commit

Permalink
Add NotCollidingItemModelGenerator
Browse files Browse the repository at this point in the history
  • Loading branch information
FirstMegaGame4 committed Jan 11, 2025
1 parent 389a5fe commit 723a704
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 4 deletions.
2 changes: 2 additions & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ pluginManagement {
gradlePluginPortal()
}
}

rootProject.name = "mmodding-library"
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.mmodding.mmodding_lib.library.client.render.model.json;

import com.mojang.datafixers.util.Either;
import net.minecraft.client.render.model.json.ItemModelGenerator;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.render.model.json.ModelElement;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Util;
import org.jetbrains.annotations.ApiStatus;
import org.quiltmc.loader.api.minecraft.ClientOnly;

import java.util.*;
import java.util.function.Function;

/**
* A no-pixel-collision version of the {@link ItemModelGenerator}.
* <br>
* Builtin Model Identifier is <code>mmodding:builtin/not_colliding_generated</code>.
* <br>
* Item Model Identifier is <code>mmodding:item/not_colliding_generated`</code>.
*/
@ClientOnly
public class NotCollidingItemModelGenerator extends ItemModelGenerator {

public static final NotCollidingItemModelGenerator INSTANCE = new NotCollidingItemModelGenerator();

public static final JsonUnbakedModel MARKER = Util.make(
JsonUnbakedModel.deserialize("{\"gui_light\": \"front\"}"),
blockModel -> blockModel.id = "not colliding item model generation marker"
);

@ApiStatus.Internal
public final Map<Integer, List<Frame>> frames = new HashMap<>();

@Override
public JsonUnbakedModel create(Function<SpriteIdentifier, Sprite> textureGetter, JsonUnbakedModel blockModel) {
Map<String, Either<SpriteIdentifier, String>> map = new HashMap<>();
List<ModelElement> list = new ArrayList<>();

// Pre-Collects Frames
// We collect the frames of each layer earlier in order to filter the colliding pixels.
// Usage of super#getFrames in super#addSubComponents is then wrapped in a mixin.
for (int i = 0; i < LAYERS.size(); i++) {
String layer = LAYERS.get(i);
SpriteIdentifier spriteIdentifier = blockModel.resolveSprite(layer);
Sprite sprite = textureGetter.apply(spriteIdentifier);
this.frames.put(i, super.getFrames(sprite));
}

// Removes Colliding Pixels
// Works by picking layers from the top to the bottom, and for each of them it removes all frames of all layers
// that are lower than the current one and that are at the same position as frames of the current one.
for (int i = LAYERS.size() - 1; i >= 0; i--) {
List<Frame> layer = this.frames.get(i);
for (int j = 1; j < i - 1; j++) {
List<Frame> current = this.frames.get(i - j);
for (Frame frame : layer) {
current.removeIf(
currentFrame -> frame.getMin() == currentFrame.getMin()
&& frame.getMax() == currentFrame.getMax()
&& frame.getLevel() == currentFrame.getLevel()
);
}
this.frames.put(i - j, current);
}
this.frames.put(i, layer);
}

for (int i = 0; i < LAYERS.size(); i++) {
String layer = LAYERS.get(i);
if (!blockModel.textureExists(layer)) {
break;
}
SpriteIdentifier spriteIdentifier = blockModel.resolveSprite(layer);
map.put(layer, Either.left(spriteIdentifier));
Sprite sprite = textureGetter.apply(spriteIdentifier);
List<ModelElement> newLayer = this.addLayerElements(i, layer, sprite);
list.addAll(newLayer);
}

map.put("particle", blockModel.textureExists("particle") ? Either.left(blockModel.resolveSprite("particle")) : map.get("layer0"));
JsonUnbakedModel jsonUnbakedModel = new JsonUnbakedModel(
null, list, map, false, blockModel.getGuiLight(), blockModel.getTransformations(), blockModel.getOverrides()
);
jsonUnbakedModel.id = blockModel.id;

return jsonUnbakedModel;
}

// Prevents Frame Expansion
// That is less optimized, I guess, but it allows easier filtering of the frames.
@Override
protected void createOrExpandCurrentCube(List<Frame> cubes, Side side, int x, int y) {
int j = side.isVertical() ? y : x;
int k = side.isVertical() ? x : y;
cubes.add(new Frame(side, k, j));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.mmodding.mmodding_lib.mixin.injectors.client;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import com.mmodding.mmodding_lib.library.client.render.model.json.NotCollidingItemModelGenerator;
import net.minecraft.client.render.model.json.ItemModelGenerator;
import net.minecraft.client.texture.Sprite;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

import java.util.List;

@Mixin(ItemModelGenerator.class)
public class ItemModelGeneratorMixin {

@WrapOperation(method = "addSubComponents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/json/ItemModelGenerator;getFrames(Lnet/minecraft/client/texture/Sprite;)Ljava/util/List;"))
private List<ItemModelGenerator.Frame> wrapFrames(ItemModelGenerator instance, Sprite sprite, Operation<List<ItemModelGenerator.Frame>> original, @Local(argsOnly = true) int layer) {
ItemModelGenerator object = (ItemModelGenerator) (Object) this;
if (object instanceof NotCollidingItemModelGenerator notCollidingItemModelGenerator) {
return notCollidingItemModelGenerator.frames.get(layer);
}
else {
return original.call(instance, sprite);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.mmodding.mmodding_lib.mixin.injectors.client;

import com.mmodding.mmodding_lib.library.client.render.model.json.NotCollidingItemModelGenerator;
import com.mojang.datafixers.util.Pair;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.render.model.json.ItemModelGenerator;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
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.CallbackInfoReturnable;

import java.util.Collection;
import java.util.Set;
import java.util.function.Function;

@Mixin(JsonUnbakedModel.class)
public abstract class JsonUnbakedModelMixin {

@Shadow
public abstract JsonUnbakedModel getRootModel();

@Shadow
public abstract SpriteIdentifier resolveSprite(String spriteName);

@Inject(method = "getTextureDependencies", at = @At("TAIL"), cancellable = true)
private void insertNotCollidingGeneratedModelLogic(Function<Identifier, UnbakedModel> unbakedModelGetter, Set<Pair<String, String>> unresolvedTextureReferences, CallbackInfoReturnable<Collection<SpriteIdentifier>> cir) {
if (this.getRootModel() == NotCollidingItemModelGenerator.MARKER) {
Set<SpriteIdentifier> set2 = (Set<SpriteIdentifier>) cir.getReturnValue();
ItemModelGenerator.LAYERS.forEach(name -> set2.add(this.resolveSprite(name)));
cir.setReturnValue(set2);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
package com.mmodding.mmodding_lib.mixin.injectors.client;

import com.llamalad7.mixinextras.sugar.Local;
import com.mmodding.mmodding_lib.library.client.render.model.InventoryModels;
import com.mmodding.mmodding_lib.library.client.render.model.json.NotCollidingItemModelGenerator;
import net.minecraft.client.color.block.BlockColors;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.render.model.*;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import net.minecraft.util.profiler.Profiler;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Map;

@Mixin(ModelLoader.class)
public abstract class ModelLoaderMixin {

@Shadow
private @Nullable SpriteAtlasManager spriteAtlasManager;

@Shadow
@Final
private Map<Identifier, UnbakedModel> unbakedModels;
Expand All @@ -36,6 +43,22 @@ private void appendModdedModels(ResourceManager resourceManager, BlockColors blo
InventoryModels.REGISTRY.forEach(this::mmodding_lib$addModdedModel);
}

@Inject(method = "bake", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/model/UnbakedModel;bake(Lnet/minecraft/client/render/model/ModelLoader;Ljava/util/function/Function;Lnet/minecraft/client/render/model/ModelBakeSettings;Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/model/BakedModel;"), cancellable = true)
private void useNotCollidingItemModelGeneratorConditionallyInstead(Identifier id, ModelBakeSettings settings, CallbackInfoReturnable<BakedModel> cir, @Local UnbakedModel unbakedModel) {
if (unbakedModel instanceof JsonUnbakedModel jsonUnbakedModel && jsonUnbakedModel.getRootModel() == NotCollidingItemModelGenerator.MARKER) {
assert this.spriteAtlasManager != null;
cir.setReturnValue(NotCollidingItemModelGenerator.INSTANCE.create(this.spriteAtlasManager::getSprite, jsonUnbakedModel)
.bake((ModelLoader) (Object) this, jsonUnbakedModel, this.spriteAtlasManager::getSprite, settings, id, false));
}
}

@Inject(method = "loadModelFromJson", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Identifier;getPath()Ljava/lang/String;", shift = At.Shift.AFTER, ordinal = 0), cancellable = true)
private void insertNotCollidingItemModelGenerationMarkerCondition(Identifier id, CallbackInfoReturnable<JsonUnbakedModel> cir) {
if ("mmodding".equals(id.getNamespace()) && "builtin/not_colliding_generated".equals(id.getPath())) {
cir.setReturnValue(NotCollidingItemModelGenerator.MARKER);
}
}

@Unique
public void mmodding_lib$addModdedModel(Identifier id) {
UnbakedModel unbakedModel = this.getOrLoadModel(id);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"parent": "mmodding:builtin/not_colliding_generated",
"gui_light": "front",
"display": {
"ground": {
"rotation": [ 0, 0, 0 ],
"translation": [ 0, 2, 0],
"scale": [ 0.5, 0.5, 0.5 ]
},
"head": {
"rotation": [ 0, 180, 0 ],
"translation": [ 0, 13, 7],
"scale": [ 1, 1, 1]
},
"thirdperson_righthand": {
"rotation": [ 0, 0, 0 ],
"translation": [ 0, 3, 1 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson_righthand": {
"rotation": [ 0, -90, 25 ],
"translation": [ 1.13, 3.2, 1.13],
"scale": [ 0.68, 0.68, 0.68 ]
},
"fixed": {
"rotation": [ 0, 180, 0 ],
"scale": [ 1, 1, 1 ]
}
}
}
6 changes: 6 additions & 0 deletions src/main/resources/mmodding_lib.accesswidener
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
accessWidener v1 named

accessible class net/minecraft/client/gui/tooltip/BundleTooltipComponent$Sprite
accessible class net/minecraft/client/render/model/json/ItemModelGenerator$Frame
accessible class net/minecraft/client/render/model/json/ItemModelGenerator$Side
accessible class net/minecraft/client/render/RenderPhase$Cull
accessible class net/minecraft/client/render/RenderPhase$DepthTest
accessible class net/minecraft/client/render/RenderPhase$Layering
Expand Down Expand Up @@ -30,12 +32,16 @@ mutable field net/minecraft/world/dimension/AreaHelper width I
mutable field net/minecraft/world/gen/chunk/ChunkNoiseSampler blockStateSampler Lnet/minecraft/world/gen/chunk/ChunkNoiseSampler$BlockStateSampler;

accessible method net/minecraft/block/entity/BlockEntityType$Builder <init> (Lnet/minecraft/block/entity/BlockEntityType$BlockEntityFactory;Ljava/util/Set;)V
accessible method net/minecraft/client/render/model/json/ItemModelGenerator addLayerElements (ILjava/lang/String;Lnet/minecraft/client/texture/Sprite;)Ljava/util/List;
accessible method net/minecraft/client/render/model/json/ItemModelGenerator getFrames (Lnet/minecraft/client/texture/Sprite;)Ljava/util/List;
accessible method net/minecraft/client/render/model/json/ItemModelGenerator$Side isVertical ()Z
accessible method net/minecraft/client/render/RenderLayer$MultiPhase <init> (Ljava/lang/String;Lcom/mojang/blaze3d/vertex/VertexFormat;Lcom/mojang/blaze3d/vertex/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)V
accessible method net/minecraft/client/render/RenderLayer$MultiPhaseParameters <init> (Lnet/minecraft/client/render/RenderPhase$TextureBase;Lnet/minecraft/client/render/RenderPhase$Shader;Lnet/minecraft/client/render/RenderPhase$Transparency;Lnet/minecraft/client/render/RenderPhase$DepthTest;Lnet/minecraft/client/render/RenderPhase$Cull;Lnet/minecraft/client/render/RenderPhase$Lightmap;Lnet/minecraft/client/render/RenderPhase$Overlay;Lnet/minecraft/client/render/RenderPhase$Layering;Lnet/minecraft/client/render/RenderPhase$Target;Lnet/minecraft/client/render/RenderPhase$Texturing;Lnet/minecraft/client/render/RenderPhase$WriteMaskState;Lnet/minecraft/client/render/RenderPhase$LineWidth;Lnet/minecraft/client/render/RenderLayer$OutlineMode;)V
accessible method net/minecraft/recipe/Ingredient$StackEntry <init> (Lnet/minecraft/item/ItemStack;)V
accessible method net/minecraft/recipe/Ingredient$TagEntry <init> (Lnet/minecraft/tag/TagKey;)V
accessible method net/minecraft/world/gen/OreVeinCreator create (Lnet/minecraft/world/gen/DensityFunction;Lnet/minecraft/world/gen/DensityFunction;Lnet/minecraft/world/gen/DensityFunction;Lnet/minecraft/util/random/PositionalRandomFactory;)Lnet/minecraft/world/gen/chunk/ChunkNoiseSampler$BlockStateSampler;

extendable method net/minecraft/client/render/model/json/ItemModelGenerator createOrExpandCurrentCube (Ljava/util/List;Lnet/minecraft/client/render/model/json/ItemModelGenerator$Side;II)V
extendable method net/minecraft/text/MutableText <init> (Lnet/minecraft/text/component/TextComponent;Ljava/util/List;Lnet/minecraft/text/Style;)V
extendable method net/minecraft/world/dimension/AreaHelper getLowerCorner (Lnet/minecraft/util/math/BlockPos;)Lnet/minecraft/util/math/BlockPos;
extendable method net/minecraft/world/dimension/AreaHelper getWidth (Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)I
Expand Down
5 changes: 3 additions & 2 deletions src/main/resources/mmodding_lib.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@
"injectors.ToolItemMixin",
"injectors.TridentItemMixin",
"injectors.WeatherCommandMixin",
"injectors.WorldMixin"
"injectors.WorldMixin",
"injectors.client.ItemModelGeneratorMixin"
],
"client": [
"accessors.SinglePartEntityModelAccessor",
Expand All @@ -122,9 +123,9 @@
"injectors.client.InGameHudMixin",
"injectors.client.ItemRenderContextMixin",
"injectors.client.ItemRendererMixin",
"injectors.client.JsonUnbakedModelMixin",
"injectors.client.LivingEntityRendererMixin",
"injectors.client.ModelLoaderMixin",
"injectors.client.SoundSystemMixin",
"injectors.client.StuckArrowsFeatureRendererMixin",
"injectors.client.StuckObjectsFeatureRendererMixin",
"injectors.client.TridentEntityRendererMixin",
Expand Down

0 comments on commit 723a704

Please sign in to comment.