diff --git a/build.gradle b/build.gradle index 929058c..0752b5f 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ import net.darkhax.curseforgegradle.TaskPublishCurseForge plugins { - id 'fabric-loom' version '1.9-SNAPSHOT' + id 'fabric-loom' version "${loom_version}" id 'maven-publish' id 'net.darkhax.curseforgegradle' version '1.1.25' id "com.modrinth.minotaur" version '2.8.7' @@ -29,6 +29,7 @@ fabricApi { loom { splitEnvironmentSourceSets() + accessWidenerPath = file("src/main/resources/special-model-loader.accesswidener") mods { "special-model-loader" { @@ -99,7 +100,7 @@ dependencies { mappings loom.layered() { officialMojangMappings() - parchment("org.parchmentmc.data:parchment-1.21.4:2025.01.05@zip") + parchment("org.parchmentmc.data:parchment-${project.parchment_version}@zip") } modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" @@ -112,7 +113,7 @@ dependencies { remapJar { archiveClassifier.set(null) - setArchivesBaseName("${rootProject.archives_base_name}-mc${rootProject.minecraft_version}") + archiveBaseName.set("${rootProject.archives_base_name}-mc${rootProject.minecraft_version}") } processResources { @@ -127,6 +128,11 @@ tasks.withType(JavaCompile).configureEach { it.options.release = 21 } +test { + // Test source set is a test mod, not unit tests + enabled = false +} + java { withSourcesJar() diff --git a/gradle.properties b/gradle.properties index df15026..8a1c330 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,15 +2,17 @@ org.gradle.jvmargs=-Xmx3G org.gradle.parallel=true #Minecraft -minecraft_version=1.21.4 -support_versions=1.21.4 +minecraft_version=1.21.11 +support_versions=1.21.11 #Mod archives_base_name=special-model-loader mod_display_name=SpecialModelLoader -mod_version=1.4.0 +mod_version=1.5.0 #Dependencies -loader_version=0.16.9 -fabric_version=0.111.0+1.21.4 +loader_version=0.18.4 +loom_version=1.15-SNAPSHOT +fabric_version=0.141.3+1.21.11 +parchment_version=1.21.11:2025.12.20 #Maven maven_group=dev.felnull maven_put_url=https://maven.felnull.dev/ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e2847c8..19a6bde 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/client/java/dev/felnull/specialmodelloader/api/SpecialModelLoaderAPI.java b/src/client/java/dev/felnull/specialmodelloader/api/SpecialModelLoaderAPI.java index 6114f94..40f11e2 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/SpecialModelLoaderAPI.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/SpecialModelLoaderAPI.java @@ -5,7 +5,7 @@ import dev.felnull.specialmodelloader.api.model.obj.ObjModelLoader; import dev.felnull.specialmodelloader.impl.SpecialModelLoaderAPIImpl; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,29 +26,35 @@ static SpecialModelLoaderAPI getInstance() { * @return ModelLoader list */ @Unmodifiable - @NotNull List getLoaders(); + @NotNull + List getLoaders(); /** * A loader for reading OBJ files * * @return OBJModel Loader */ - @NotNull ObjModelLoader getObjLoader(); + @NotNull + ObjModelLoader getObjLoader(); /** - * Loads a model at a specified location using the resource manager and returns the loaded resource. + * Loads a model at a specified location using the resource manager and returns + * the loaded resource. * * @param resourceManager ResourceManager - * @param modelLocation The location of the JsonModel (e.g. minecraft:item/apple) - * @return The loaded resource instances required to make the model. Null if unable to load. + * @param modelLocation The location of the JsonModel (e.g. + * minecraft:item/apple) + * @return The loaded resource instances required to make the model. Null if + * unable to load. */ @Nullable - LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull ResourceLocation modelLocation); + LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull Identifier modelLocation); /** * Made a model from the loaded resources. * - * @param resource Resources loaded using{@link #loadResource(ResourceManager, ResourceLocation)} + * @param resource Resources loaded + * using{@link #loadResource(ResourceManager, ResourceLocation)} * @return Made model */ @NotNull diff --git a/src/client/java/dev/felnull/specialmodelloader/api/data/SpecialModelDataGenHelper.java b/src/client/java/dev/felnull/specialmodelloader/api/data/SpecialModelDataGenHelper.java index 4269fe1..7075344 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/data/SpecialModelDataGenHelper.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/data/SpecialModelDataGenHelper.java @@ -4,7 +4,7 @@ import dev.felnull.specialmodelloader.impl.SpecialModelLoader; import net.minecraft.client.data.models.model.ModelInstance; import net.minecraft.client.data.models.model.ModelLocationUtils; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import org.jetbrains.annotations.NotNull; @@ -15,11 +15,13 @@ import java.util.function.BiConsumer; public final class SpecialModelDataGenHelper { - private static final ResourceLocation OBJ_LOADER = ResourceLocation.fromNamespaceAndPath(SpecialModelLoader.MODID, "builtin/obj"); + private static final Identifier OBJ_LOADER = Identifier.fromNamespaceAndPath(SpecialModelLoader.MODID, + "builtin/obj"); - public static void generateObjModel(@NotNull ResourceLocation location, @NotNull ResourceLocation objLocation, - boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride, @Unmodifiable @NotNull Map textures, - @Nullable ResourceLocation particle, @NotNull BiConsumer output) { + public static void generateObjModel(@NotNull Identifier location, @NotNull Identifier objLocation, + boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride, + @Unmodifiable @NotNull Map textures, + @Nullable Identifier particle, @NotNull BiConsumer output) { output.accept(location, () -> { var jo = new JsonObject(); @@ -48,15 +50,19 @@ public static void generateObjModel(@NotNull ResourceLocation location, @NotNull }); } - public static void generateObjModel(@NotNull Item item, @NotNull ResourceLocation objLocation, - boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride, @Unmodifiable @NotNull Map textures, - @Nullable ResourceLocation particle, @NotNull BiConsumer output) { - generateObjModel(ModelLocationUtils.getModelLocation(item), objLocation, flipV, useAmbientOcclusion, mtlOverride, textures, particle, output); + public static void generateObjModel(@NotNull Item item, @NotNull Identifier objLocation, + boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride, + @Unmodifiable @NotNull Map textures, + @Nullable Identifier particle, @NotNull BiConsumer output) { + generateObjModel(ModelLocationUtils.getModelLocation(item), objLocation, flipV, useAmbientOcclusion, + mtlOverride, textures, particle, output); } - public static void generateObjModel(@NotNull Block block, @NotNull ResourceLocation objLocation, - boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride, @Unmodifiable @NotNull Map textures, - @Nullable ResourceLocation particle, @NotNull BiConsumer output) { - generateObjModel(ModelLocationUtils.getModelLocation(block), objLocation, flipV, useAmbientOcclusion, mtlOverride, textures, particle, output); + public static void generateObjModel(@NotNull Block block, @NotNull Identifier objLocation, + boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride, + @Unmodifiable @NotNull Map textures, + @Nullable Identifier particle, @NotNull BiConsumer output) { + generateObjModel(ModelLocationUtils.getModelLocation(block), objLocation, flipV, useAmbientOcclusion, + mtlOverride, textures, particle, output); } } diff --git a/src/client/java/dev/felnull/specialmodelloader/api/event/SpecialModelLoaderEvents.java b/src/client/java/dev/felnull/specialmodelloader/api/event/SpecialModelLoaderEvents.java index 95bdc8e..5086b3b 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/event/SpecialModelLoaderEvents.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/event/SpecialModelLoaderEvents.java @@ -2,7 +2,7 @@ import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import java.util.Arrays; @@ -14,41 +14,47 @@ public final class SpecialModelLoaderEvents { public static final Event LOAD_SCOPE = EventFactory.createArrayBacked(LoadScope.class, loadScopes -> { - BiPredicate predicate = Arrays.stream(loadScopes) + BiPredicate predicate = Arrays.stream(loadScopes) .map(LoadScope::provideLoadScopePredicate) .reduce(BiPredicate::or) .orElseGet(() -> (res, loc) -> false); return () -> predicate; }); - public static final Event LOAD_SCOPE_ASYNC = EventFactory.createArrayBacked(AsyncLoadScope.class, loadScopes -> (resourceManager, executor) -> - Arrays.stream(loadScopes) + public static final Event LOAD_SCOPE_ASYNC = EventFactory.createArrayBacked(AsyncLoadScope.class, + loadScopes -> (resourceManager, executor) -> Arrays.stream(loadScopes) .map(it -> it.provideAsyncLoadScopePredicate(resourceManager, executor)) .reduce((cf1, cf2) -> cf1.thenCombineAsync(cf2, Predicate::or, executor)) - .orElseGet(() -> CompletableFuture.completedFuture(loc -> false))); + .orElseGet(() -> CompletableFuture.completedFuture((Predicate) loc -> false))); public interface LoadScope { /** - * It must return a Predicate to check if the given resource location is Load Scope.
- * This method is called from the rendering thread, but the Predicate test is called asynchronously, so be careful not to have side effects. + * It must return a Predicate to check if the given resource location is Load + * Scope.
+ * This method is called from the rendering thread, but the Predicate test is + * called asynchronously, so be careful not to have side effects. * * @return A predicate to check if the location is a Load Scope. */ - BiPredicate provideLoadScopePredicate(); + BiPredicate provideLoadScopePredicate(); } public interface AsyncLoadScope { /** - * Must return a CompletableFuture that obtains a Predicate to check if the given resource location is Load Scope.
- * his method is called from the rendering thread, but the Predicate test is called asynchronously, so be careful not to have side effects. + * Must return a CompletableFuture that obtains a Predicate to check if the + * given resource location is Load Scope.
+ * his method is called from the rendering thread, but the Predicate test is + * called asynchronously, so be careful not to have side effects. * * @param resourceManager Resource Manager * @param executor Executor - * @return A CompletableFuture that takes a predicate to check if the location is a load scope. + * @return A CompletableFuture that takes a predicate to check if the location + * is a load scope. */ - CompletableFuture> provideAsyncLoadScopePredicate(ResourceManager resourceManager, Executor executor); + CompletableFuture> provideAsyncLoadScopePredicate(ResourceManager resourceManager, + Executor executor); } } diff --git a/src/client/java/dev/felnull/specialmodelloader/api/model/ModelLoader.java b/src/client/java/dev/felnull/specialmodelloader/api/model/ModelLoader.java index b5389b7..14403b5 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/model/ModelLoader.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/model/ModelLoader.java @@ -3,7 +3,7 @@ import com.google.gson.JsonObject; import dev.felnull.specialmodelloader.impl.SpecialModelLoader; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,13 +11,15 @@ public interface ModelLoader { /** - * Load the resource needed to create the model from the Resource Manager and Model Json. + * Load the resource needed to create the model from the Resource Manager and + * Model Json. * * @param resourceManager Resource Manager * @param modelJson Model json * @return Loaded Model, null if not loaded. */ - @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull JsonObject modelJson); + @Nullable + LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull JsonObject modelJson); /** * Make model from loaded resources. @@ -25,7 +27,8 @@ public interface ModelLoader { * @param loadedResource Loaded resource * @return UnbakedModel */ - @NotNull UnbakedModel makeModel(@NotNull LoadedResource loadedResource); + @NotNull + UnbakedModel makeModel(@NotNull LoadedResource loadedResource); /** * Load model from Resource Manager and Model Json. @@ -49,7 +52,8 @@ public interface ModelLoader { * * @return ID */ - @Nullable String getId(); + @Nullable + String getId(); /** * Whether the model uses this model loader or not. @@ -57,7 +61,7 @@ public interface ModelLoader { * @param modelLocation Model Location * @return true if this loader is used, false if not. */ - default boolean isLoaderLocation(@NotNull ResourceLocation modelLocation) { + default boolean isLoaderLocation(@NotNull Identifier modelLocation) { if (SpecialModelLoader.MODID.equals(modelLocation.getNamespace()) || "sml".equals(modelLocation.getNamespace())) return modelLocation.getPath().equals("builtin/" + getId()); return false; diff --git a/src/client/java/dev/felnull/specialmodelloader/api/model/ModelOption.java b/src/client/java/dev/felnull/specialmodelloader/api/model/ModelOption.java index ee460c2..3a024cb 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/model/ModelOption.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/model/ModelOption.java @@ -2,16 +2,17 @@ import com.google.gson.JsonObject; import dev.felnull.specialmodelloader.impl.model.ModelOptionImpl; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.Identifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public interface ModelOption { @NotNull - static ModelOption of(boolean useAmbientOcclusion, @Nullable BlockModel.GuiLight guiLight, @Nullable ResourceLocation particle, @NotNull ItemTransforms transforms) { + static ModelOption of(boolean useAmbientOcclusion, @Nullable UnbakedModel.GuiLight guiLight, + @Nullable Identifier particle, @NotNull ItemTransforms transforms) { return new ModelOptionImpl(useAmbientOcclusion, guiLight, particle, transforms); } @@ -23,10 +24,10 @@ static ModelOption parse(@NotNull JsonObject modelJson) { boolean isUseAmbientOcclusion(); @Nullable - BlockModel.GuiLight getGuiLight(); + UnbakedModel.GuiLight getGuiLight(); @Nullable - ResourceLocation getParticle(); + Identifier getParticle(); @NotNull ItemTransforms getTransforms(); diff --git a/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelLoader.java b/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelLoader.java index ddc8586..c1d9c9d 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelLoader.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelLoader.java @@ -3,7 +3,7 @@ import dev.felnull.specialmodelloader.api.model.LoadedResource; import dev.felnull.specialmodelloader.api.model.ModelLoader; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,7 +19,8 @@ public interface ObjModelLoader extends ModelLoader { * @return Loaded Model, null if not loaded. */ @Nullable - LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull ResourceLocation location, @NotNull ObjModelOption option); + LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull Identifier location, + @NotNull ObjModelOption option); /** * Load model from OBJ file location and options. @@ -29,7 +30,8 @@ public interface ObjModelLoader extends ModelLoader { * @param option Model Option * @return UnbakedModel */ - default @Nullable UnbakedModel loadModel(@NotNull ResourceManager resourceManager, @NotNull ResourceLocation location, @NotNull ObjModelOption option) { + default @Nullable UnbakedModel loadModel(@NotNull ResourceManager resourceManager, @NotNull Identifier location, + @NotNull ObjModelOption option) { LoadedResource res = loadResource(resourceManager, location, option); if (res == null) { diff --git a/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelOption.java b/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelOption.java index 0d5131b..d8db39b 100644 --- a/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelOption.java +++ b/src/client/java/dev/felnull/specialmodelloader/api/model/obj/ObjModelOption.java @@ -4,7 +4,7 @@ import com.google.gson.JsonObject; import dev.felnull.specialmodelloader.api.model.ModelOption; import dev.felnull.specialmodelloader.impl.model.obj.ObjModelOptionImpl; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; @@ -15,7 +15,7 @@ public interface ObjModelOption extends ModelOption { @NotNull static ObjModelOption of(@NotNull ModelOption modelOption, boolean flipV, - String mtlOverride, Map textures) { + String mtlOverride, Map textures) { return new ObjModelOptionImpl(modelOption, flipV, mtlOverride, ImmutableMap.copyOf(textures)); } @@ -31,5 +31,5 @@ static ObjModelOption parse(@NotNull JsonObject modelJson) { @Unmodifiable @NotNull - Map getTextures(); + Map getTextures(); } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/SpecialModelLoaderAPIImpl.java b/src/client/java/dev/felnull/specialmodelloader/impl/SpecialModelLoaderAPIImpl.java index 8a13bf6..73f6ef4 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/SpecialModelLoaderAPIImpl.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/SpecialModelLoaderAPIImpl.java @@ -11,7 +11,7 @@ import dev.felnull.specialmodelloader.impl.model.obj.ObjModelLoaderImp; import dev.felnull.specialmodelloader.impl.util.JsonUtils; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.GsonHelper; import org.apache.commons.lang3.tuple.Pair; @@ -32,25 +32,27 @@ public class SpecialModelLoaderAPIImpl implements SpecialModelLoaderAPI { } @Override - public @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull ResourceLocation modelLocation) { + public @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, + @NotNull Identifier modelLocation) { List models = new ArrayList<>(); JsonObject jo = readJson(resourceManager, modelLocation); if (NeoForgeCompat.isEnable()) { - Pair forgeModel = NeoForgeCompat.getObjModelData(jo); + Pair forgeModel = NeoForgeCompat.getObjModelData(jo); if (forgeModel != null) { return getObjLoader().loadResource(resourceManager, forgeModel.getLeft(), forgeModel.getRight()); } } - ResourceLocation location = JsonUtils.getParentLocation(jo); - Set parents = new HashSet<>(); + Identifier location = JsonUtils.getParentLocation(jo); + Set parents = new HashSet<>(); while (location != null) { models.add(jo); if (parents.contains(location)) { - SpecialModelLoader.LOGGER.warn("Model parent specification is looping: '{}', '{}'", modelLocation, location); + SpecialModelLoader.LOGGER.warn("Model parent specification is looping: '{}', '{}'", modelLocation, + location); return null; } @@ -81,7 +83,7 @@ public class SpecialModelLoaderAPIImpl implements SpecialModelLoaderAPI { return loaders; } - private ModelLoader getLoader(ResourceLocation location) { + private ModelLoader getLoader(Identifier location) { return getLoaders().stream() .filter(r -> r.isLoaderLocation(location)) .limit(1) @@ -89,10 +91,12 @@ private ModelLoader getLoader(ResourceLocation location) { .orElse(null); } - private JsonObject readJson(ResourceManager resourceManager, ResourceLocation modelLocation) { - ResourceLocation modelPath = ResourceLocation.fromNamespaceAndPath(modelLocation.getNamespace(), "models/" + modelLocation.getPath() + ".json"); + private JsonObject readJson(ResourceManager resourceManager, Identifier modelLocation) { + Identifier modelPath = Identifier.fromNamespaceAndPath(modelLocation.getNamespace(), + "models/" + modelLocation.getPath() + ".json"); var res = resourceManager.getResource(modelPath); - if (res.isEmpty()) return null; + if (res.isEmpty()) + return null; JsonObject jo; try (var reader = res.get().openAsReader()) { jo = GsonHelper.parse(reader); diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLClientHandler.java b/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLClientHandler.java index 387dbc2..e422aab 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLClientHandler.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLClientHandler.java @@ -7,7 +7,7 @@ import com.google.gson.JsonObject; import dev.felnull.specialmodelloader.api.event.SpecialModelLoaderEvents; import dev.felnull.specialmodelloader.impl.SpecialModelLoader; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.ResourceManager; import java.io.Reader; @@ -26,24 +26,29 @@ public static void init() { SpecialModelLoaderEvents.LOAD_SCOPE_ASYNC.register(SMLClientHandler::provideManualLoadScopePredicate); } - private static CompletableFuture> provideSimpleLoadScopePredicate(ResourceManager resourceManager, Executor executor) { - BiPredicate predicate = SpecialModelLoaderEvents.LOAD_SCOPE.invoker().provideLoadScopePredicate(); + private static CompletableFuture> provideSimpleLoadScopePredicate( + ResourceManager resourceManager, Executor executor) { + BiPredicate predicate = SpecialModelLoaderEvents.LOAD_SCOPE.invoker() + .provideLoadScopePredicate(); return CompletableFuture.supplyAsync(() -> loc -> predicate.test(resourceManager, loc), executor); } - private static CompletableFuture> provideManualLoadScopePredicate(ResourceManager resourceManager, Executor executor) { + private static CompletableFuture> provideManualLoadScopePredicate( + ResourceManager resourceManager, Executor executor) { return CompletableFuture.supplyAsync(() -> { ImmutableSet.Builder patternsBuilder = new ImmutableSet.Builder<>(); - resourceManager.listResources(MANUAL_LOAD_SCOPE_RESOURCE_NAME, loc -> loc.getPath().endsWith(".json")).forEach((location, resource) -> { - try (Reader reader = resource.openAsReader()) { - JsonObject jo = GSON.fromJson(reader, JsonObject.class); - loadManualLoadScope(patternsBuilder, jo); - } catch (Exception e) { - SpecialModelLoader.LOGGER.error("Error occurred while loading model load scope resource json {}", location, e); - } - }); + resourceManager.listResources(MANUAL_LOAD_SCOPE_RESOURCE_NAME, loc -> loc.getPath().endsWith(".json")) + .forEach((location, resource) -> { + try (Reader reader = resource.openAsReader()) { + JsonObject jo = GSON.fromJson(reader, JsonObject.class); + loadManualLoadScope(patternsBuilder, jo); + } catch (Exception e) { + SpecialModelLoader.LOGGER.error( + "Error occurred while loading model load scope resource json {}", location, e); + } + }); final ImmutableSet patterns = patternsBuilder.build(); int size = patterns.size(); @@ -58,7 +63,8 @@ private static CompletableFuture> provideManualLoadS private static void loadManualLoadScope(ImmutableSet.Builder builder, JsonObject jsonObject) { - if (!jsonObject.has("version") || !jsonObject.get("version").isJsonPrimitive() || !jsonObject.getAsJsonPrimitive("version").isNumber()) { + if (!jsonObject.has("version") || !jsonObject.get("version").isJsonPrimitive() + || !jsonObject.getAsJsonPrimitive("version").isNumber()) { throw new IllegalStateException("Unknown version"); } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLModelLoadingHandler.java b/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLModelLoadingHandler.java index 6d256f0..445b0ac 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLModelLoadingHandler.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/handler/SMLModelLoadingHandler.java @@ -8,7 +8,8 @@ import net.fabricmc.fabric.api.client.model.loading.v1.ModelModifier; import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; +import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.ResourceManager; import java.util.Map; @@ -22,9 +23,10 @@ public static void init() { PreparableModelLoadingPlugin.register(SMLModelLoadingHandler::loadPrepareData, new MyModelLoadingPlugin()); } - private static UnbakedModel modifyModelOnLoad(PreparationData data, UnbakedModel original, ModelModifier.OnLoad.Context context) { + private static UnbakedModel modifyModelOnLoad(PreparationData data, UnbakedModel original, + ModelModifier.OnLoad.Context context) { - ResourceLocation resId = context.id(); + Identifier resId = context.id(); if (resId != null) { LoadedResource loadedResource = data.resources().get(resId); if (loadedResource != null) { @@ -35,25 +37,30 @@ private static UnbakedModel modifyModelOnLoad(PreparationData data, UnbakedModel return original; } - private static CompletableFuture loadPrepareData(ResourceManager resourceManager, Executor executor) { - CompletableFuture> loadScopePredicates = SpecialModelLoaderEvents.LOAD_SCOPE_ASYNC.invoker().provideAsyncLoadScopePredicate(resourceManager, executor); + private static CompletableFuture loadPrepareData(PreparableReloadListener.SharedState sharedState, + Executor executor) { + ResourceManager resourceManager = sharedState.resourceManager(); + CompletableFuture> loadScopePredicates = SpecialModelLoaderEvents.LOAD_SCOPE_ASYNC + .invoker().provideAsyncLoadScopePredicate(resourceManager, executor); return loadScopePredicates.thenApplyAsync((lpPre) -> { - ImmutableMap.Builder resBuilder = ImmutableMap.builder(); + ImmutableMap.Builder resBuilder = ImmutableMap.builder(); - resourceManager.listResources("models", loc -> loc.getPath().endsWith(".json")).forEach((location, resource) -> { - String path = location.getPath().substring("models/".length()); - path = path.substring(0, path.length() - ".json".length()); - ResourceLocation modelLoc = ResourceLocation.fromNamespaceAndPath(location.getNamespace(), path); + resourceManager.listResources("models", loc -> loc.getPath().endsWith(".json")) + .forEach((location, resource) -> { + String path = location.getPath().substring("models/".length()); + path = path.substring(0, path.length() - ".json".length()); + Identifier modelLoc = Identifier.fromNamespaceAndPath(location.getNamespace(), path); - if (!lpPre.test(modelLoc)) { - return; - } + if (!lpPre.test(modelLoc)) { + return; + } - LoadedResource res = SpecialModelLoaderAPI.getInstance().loadResource(resourceManager, modelLoc); - if (res != null) { - resBuilder.put(modelLoc, res); - } - }); + LoadedResource res = SpecialModelLoaderAPI.getInstance().loadResource(resourceManager, + modelLoc); + if (res != null) { + resBuilder.put(modelLoc, res); + } + }); return new PreparationData(resBuilder.build()); }, executor); @@ -66,6 +73,6 @@ public void initialize(PreparationData data, ModelLoadingPlugin.Context pluginCo } } - private record PreparationData(Map resources) { + private record PreparationData(Map resources) { } } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/ModelOptionImpl.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/ModelOptionImpl.java index f712345..84f12d9 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/ModelOptionImpl.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/ModelOptionImpl.java @@ -3,15 +3,15 @@ import com.google.gson.JsonObject; import dev.felnull.specialmodelloader.api.model.ModelOption; import dev.felnull.specialmodelloader.impl.mixin.BlockModelAccessor; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.Identifier; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public record ModelOptionImpl(boolean useAmbientOcclusion, BlockModel.GuiLight guiLight, ResourceLocation particle, - ItemTransforms transforms) implements ModelOption { +public record ModelOptionImpl(boolean useAmbientOcclusion, UnbakedModel.GuiLight guiLight, Identifier particle, + ItemTransforms transforms) implements ModelOption { public static ModelOptionImpl parse(JsonObject modelJson) { ItemTransforms transform = ItemTransforms.NO_TRANSFORMS; @@ -21,15 +21,16 @@ public static ModelOptionImpl parse(JsonObject modelJson) { transform = BlockModelAccessor.getGson().fromJson(jo, ItemTransforms.class); } - BlockModel.GuiLight guiLight = null; + UnbakedModel.GuiLight guiLight = null; if (modelJson.has("gui_light")) - guiLight = BlockModel.GuiLight.getByName(GsonHelper.getAsString(modelJson, "gui_light")); + guiLight = UnbakedModel.GuiLight.getByName(GsonHelper.getAsString(modelJson, "gui_light")); - ResourceLocation particle = null; + Identifier particle = null; if (modelJson.has("particle")) - particle = ResourceLocation.parse(GsonHelper.getAsString(modelJson, "particle")); + particle = Identifier.parse(GsonHelper.getAsString(modelJson, "particle")); - return new ModelOptionImpl(GsonHelper.getAsBoolean(modelJson, "ambientocclusion", true), guiLight, particle, transform); + return new ModelOptionImpl(GsonHelper.getAsBoolean(modelJson, "ambientocclusion", true), guiLight, particle, + transform); } @Override @@ -38,12 +39,12 @@ public boolean isUseAmbientOcclusion() { } @Override - public @Nullable BlockModel.GuiLight getGuiLight() { + public @Nullable UnbakedModel.GuiLight getGuiLight() { return guiLight; } @Override - public @Nullable ResourceLocation getParticle() { + public @Nullable Identifier getParticle() { return particle; } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/NeoForgeCompat.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/NeoForgeCompat.java index d856def..6444ff2 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/NeoForgeCompat.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/NeoForgeCompat.java @@ -5,14 +5,14 @@ import dev.felnull.specialmodelloader.impl.SpecialModelLoader; import dev.felnull.specialmodelloader.impl.util.JsonUtils; import net.fabricmc.loader.api.FabricLoader; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import org.apache.commons.lang3.tuple.Pair; /** * Compatibility to load models in formats supported by NeoForge */ public final class NeoForgeCompat { - private static final ResourceLocation NEO_FORGE_OBJ = ResourceLocation.fromNamespaceAndPath("neoforge", "obj"); + private static final Identifier NEO_FORGE_OBJ = Identifier.fromNamespaceAndPath("neoforge", "obj"); public static void init() { if (FabricLoader.getInstance().isModLoaded("connector")) { @@ -22,24 +22,25 @@ public static void init() { } public static boolean isEnable() { - // If the Sinytra Connector is present, disable compatibility as it was launched in NeoForge + // If the Sinytra Connector is present, disable compatibility as it was launched + // in NeoForge // https://sinytra.org/docs/connector/developers return !FabricLoader.getInstance().isModLoaded("connector"); } - public static Pair getObjModelData(JsonObject modelJson) { + public static Pair getObjModelData(JsonObject modelJson) { if (modelJson == null) { return null; } // https://docs.neoforged.net/docs/resources/client/models/modelloaders/#obj-model - ResourceLocation loaderLoc = JsonUtils.getResourceLocation(modelJson, "loader"); + Identifier loaderLoc = JsonUtils.getResourceLocation(modelJson, "loader"); if (!NEO_FORGE_OBJ.equals(loaderLoc)) { return null; } - ResourceLocation model = JsonUtils.getResourceLocation(modelJson, "model"); + Identifier model = JsonUtils.getResourceLocation(modelJson, "model"); if (model == null) { return null; } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/SimpleMeshModel.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/SimpleMeshModel.java deleted file mode 100644 index ca90a26..0000000 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/SimpleMeshModel.java +++ /dev/null @@ -1,46 +0,0 @@ -package dev.felnull.specialmodelloader.impl.model; - -import com.google.common.base.Suppliers; -import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; -import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; -import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; -import net.minecraft.client.renderer.block.model.BakedQuad; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.BlockAndTintGetter; -import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.function.Predicate; -import java.util.function.Supplier; - -public class SimpleMeshModel extends SpecialBaseModel { - private final Mesh mesh; - private final Supplier[]> quadCache; - - public SimpleMeshModel(boolean useAmbientOcclusion, boolean usesBlockLight, TextureAtlasSprite particleIcon, ItemTransforms transforms, Mesh mesh) { - super(useAmbientOcclusion, usesBlockLight, particleIcon, transforms); - this.mesh = mesh; - this.quadCache = Suppliers.memoize(() -> ModelHelper.toQuadLists(mesh)); - } - - @Override - public void emitBlockQuads(QuadEmitter emitter, BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, Predicate<@Nullable Direction> cullTest) { - mesh.outputTo(emitter); - } - - @Override - public void emitItemQuads(QuadEmitter emitter, Supplier randomSupplier) { - mesh.outputTo(emitter); - } - - @Override - public @NotNull List getQuads(@Nullable BlockState blockState, @Nullable Direction direction, RandomSource randomSource) { - return this.quadCache.get()[ModelHelper.toFaceIndex(direction)]; - } -} diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseModel.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseModel.java deleted file mode 100644 index 66abe28..0000000 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseModel.java +++ /dev/null @@ -1,51 +0,0 @@ -package dev.felnull.specialmodelloader.impl.model; - -import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; -import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.resources.model.BakedModel; -import org.jetbrains.annotations.NotNull; - -public abstract class SpecialBaseModel implements BakedModel, FabricBakedModel { - private final boolean useAmbientOcclusion; - private final boolean usesBlockLight; - private final TextureAtlasSprite particleIcon; - private final ItemTransforms transforms; - - protected SpecialBaseModel(boolean useAmbientOcclusion, boolean usesBlockLight, TextureAtlasSprite particleIcon, ItemTransforms transforms) { - this.useAmbientOcclusion = useAmbientOcclusion; - this.usesBlockLight = usesBlockLight; - this.particleIcon = particleIcon; - this.transforms = transforms; - } - - @Override - public boolean isVanillaAdapter() { - return false; - } - - @Override - public boolean useAmbientOcclusion() { - return useAmbientOcclusion; - } - - @Override - public boolean isGui3d() { - return true; - } - - @Override - public boolean usesBlockLight() { - return usesBlockLight; - } - - @Override - public @NotNull TextureAtlasSprite getParticleIcon() { - return particleIcon; - } - - @Override - public @NotNull ItemTransforms getTransforms() { - return transforms; - } -} diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseUnbakedModel.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseUnbakedModel.java index cbfe2e0..7fb2e7b 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseUnbakedModel.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/SpecialBaseUnbakedModel.java @@ -1,14 +1,18 @@ package dev.felnull.specialmodelloader.impl.model; +import com.google.gson.JsonObject; import dev.felnull.specialmodelloader.api.model.ModelOption; -import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.block.model.TextureSlots; import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite; -import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.ModelManager; import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.Identifier; public abstract class SpecialBaseUnbakedModel implements UnbakedModel { - protected static final Material MISSING = new Material(TextureAtlas.LOCATION_BLOCKS, MissingTextureAtlasSprite.getLocation()); + protected static final Material MISSING = new Material(ModelManager.BLOCK_OR_ITEM, + MissingTextureAtlasSprite.getLocation()); private final ModelOption modelOption; protected SpecialBaseUnbakedModel(ModelOption modelOption) { @@ -21,13 +25,42 @@ public ModelOption getModelOption() { public Material getParticleLocation() { if (modelOption.getParticle() != null) - return new Material(TextureAtlas.LOCATION_BLOCKS, modelOption.getParticle()); + return new Material(ModelManager.BLOCK_OR_ITEM, modelOption.getParticle()); return MISSING; } - public BlockModel.GuiLight getGuiLight() { + public UnbakedModel.GuiLight getGuiLightValue() { if (modelOption.getGuiLight() == null) - return BlockModel.GuiLight.SIDE; + return UnbakedModel.GuiLight.SIDE; return modelOption.getGuiLight(); } + + @Override + public Boolean ambientOcclusion() { + return modelOption.isUseAmbientOcclusion(); + } + + @Override + public UnbakedModel.GuiLight guiLight() { + return modelOption.getGuiLight(); + } + + @Override + public ItemTransforms transforms() { + return modelOption.getTransforms(); + } + + @Override + public TextureSlots.Data textureSlots() { + JsonObject jo = new JsonObject(); + if (modelOption.getParticle() != null) { + jo.addProperty(UnbakedModel.PARTICLE_TEXTURE_REFERENCE, modelOption.getParticle().toString()); + } + return TextureSlots.parseTextureMap(jo); + } + + @Override + public Identifier parent() { + return null; + } } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoadedResource.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoadedResource.java index ba7630f..63636d2 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoadedResource.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoadedResource.java @@ -5,14 +5,14 @@ import dev.felnull.specialmodelloader.api.model.LoadedResource; import dev.felnull.specialmodelloader.api.model.ModelLoader; import dev.felnull.specialmodelloader.api.model.obj.ObjModelOption; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import java.util.Map; -record ObjModelLoadedResource(ResourceLocation location, - Obj obj, - Map mtl, - ObjModelOption option) implements LoadedResource { +record ObjModelLoadedResource(Identifier location, + Obj obj, + Map mtl, + ObjModelOption option) implements LoadedResource { @Override public ModelLoader getLoader() { return ObjModelLoaderImp.INSTANCE; diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoaderImp.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoaderImp.java index 076c7fe..7795cbc 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoaderImp.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelLoaderImp.java @@ -9,7 +9,7 @@ import dev.felnull.specialmodelloader.api.model.obj.ObjModelOption; import dev.felnull.specialmodelloader.impl.SpecialModelLoader; import net.minecraft.client.resources.model.UnbakedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import org.apache.commons.lang3.ArrayUtils; @@ -27,18 +27,21 @@ public class ObjModelLoaderImp implements ObjModelLoader { public static final ObjModelLoaderImp INSTANCE = new ObjModelLoaderImp(); @Override - public @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull JsonObject modelJson) { - if (!modelJson.has("model") || !modelJson.get("model").isJsonPrimitive() || !modelJson.getAsJsonPrimitive("model").isString()) { + public @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, + @NotNull JsonObject modelJson) { + if (!modelJson.has("model") || !modelJson.get("model").isJsonPrimitive() + || !modelJson.getAsJsonPrimitive("model").isString()) { return null; } - ResourceLocation modelLocation = ResourceLocation.parse(modelJson.get("model").getAsString()); + Identifier modelLocation = Identifier.parse(modelJson.get("model").getAsString()); return loadResource(resourceManager, modelLocation, ObjModelOption.parse(modelJson)); } @Override - public @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, @NotNull ResourceLocation modelLocation, @NotNull ObjModelOption option) { + public @Nullable LoadedResource loadResource(@NotNull ResourceManager resourceManager, + @NotNull Identifier modelLocation, @NotNull ObjModelOption option) { Optional res = resourceManager.getResource(modelLocation); if (res.isEmpty()) { @@ -48,20 +51,22 @@ public class ObjModelLoaderImp implements ObjModelLoader { try (var reader = res.get().openAsReader()) { Obj obj = ObjUtils.convertToRenderable(ObjReader.read(reader)); - ResourceLocation mtlDirLoc; + Identifier mtlDirLoc; List mtlFileNames; String mtlOverride; if ((mtlOverride = option.getMtlOverride()) != null) { String[] overrideSplit = mtlOverride.split("/"); - mtlDirLoc = ResourceLocation.parse(String.join("/", ArrayUtils.remove(overrideSplit, overrideSplit.length - 1))); + mtlDirLoc = Identifier + .parse(String.join("/", ArrayUtils.remove(overrideSplit, overrideSplit.length - 1))); mtlFileNames = ImmutableList.of(overrideSplit[overrideSplit.length - 1]); } else { String[] mtlDirPaths = modelLocation.getPath().split("/"); mtlDirPaths = ArrayUtils.remove(mtlDirPaths, mtlDirPaths.length - 1); - mtlDirLoc = ResourceLocation.fromNamespaceAndPath(modelLocation.getNamespace(), String.join("/", mtlDirPaths)); + mtlDirLoc = Identifier.fromNamespaceAndPath(modelLocation.getNamespace(), + String.join("/", mtlDirPaths)); mtlFileNames = obj.getMtlFileNames(); } @@ -77,18 +82,19 @@ public class ObjModelLoaderImp implements ObjModelLoader { if (loadedResource instanceof ObjModelLoadedResource objRes) { return new ObjUnbakedModelModel(objRes.location(), objRes.obj(), objRes.mtl(), objRes.option()); } else { - throw new IllegalArgumentException("A loaded resource that is not an OBJ model was received as an argument."); + throw new IllegalArgumentException( + "A loaded resource that is not an OBJ model was received as an argument."); } } - private Map loadMtl(ResourceManager resourceManager, ResourceLocation location, List mtlNames) { + private Map loadMtl(ResourceManager resourceManager, Identifier location, List mtlNames) { return mtlNames.stream() .flatMap(r -> loadMtl(resourceManager, location, r).stream()) .collect(Collectors.toMap(Mtl::getName, r -> r)); } - private List loadMtl(ResourceManager resourceManager, ResourceLocation location, String mtlName) { - var loc = ResourceLocation.fromNamespaceAndPath(location.getNamespace(), location.getPath() + "/" + mtlName); + private List loadMtl(ResourceManager resourceManager, Identifier location, String mtlName) { + var loc = Identifier.fromNamespaceAndPath(location.getNamespace(), location.getPath() + "/" + mtlName); return resourceManager.getResource(loc).map(res -> { try (var reader = res.openAsReader()) { return MtlReader.read(reader); diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelOptionImpl.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelOptionImpl.java index de6bc25..eb648b7 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelOptionImpl.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjModelOptionImpl.java @@ -5,9 +5,9 @@ import dev.felnull.specialmodelloader.api.model.ModelOption; import dev.felnull.specialmodelloader.api.model.obj.ObjModelOption; import dev.felnull.specialmodelloader.impl.util.JsonUtils; -import net.minecraft.client.renderer.block.model.BlockModel; import net.minecraft.client.renderer.block.model.ItemTransforms; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.client.resources.model.UnbakedModel; +import net.minecraft.resources.Identifier; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,17 +16,17 @@ import java.util.Map; public record ObjModelOptionImpl(ModelOption modelOption, boolean flipV, String mtlOverride, - Map textures) implements ObjModelOption { + Map textures) implements ObjModelOption { public static ObjModelOptionImpl parse(JsonObject modelJson) { boolean flipV = GsonHelper.getAsBoolean(modelJson, "flip_v", false); String mtlOverride = GsonHelper.getAsString(modelJson, "mtl_override", null); - ImmutableMap.Builder textures = ImmutableMap.builder(); + ImmutableMap.Builder textures = ImmutableMap.builder(); if (modelJson.has("textures") && modelJson.get("textures").isJsonObject()) { JsonObject texturesJo = modelJson.getAsJsonObject("textures"); texturesJo.keySet().forEach(key -> { - ResourceLocation tex = JsonUtils.getResourceLocation(texturesJo, key); + Identifier tex = JsonUtils.getResourceLocation(texturesJo, key); if (tex != null) { textures.put(key, tex); } @@ -48,7 +48,7 @@ public String getMtlOverride() { } @Override - public @Unmodifiable @NotNull Map getTextures() { + public @Unmodifiable @NotNull Map getTextures() { return textures; } @@ -58,12 +58,12 @@ public boolean isUseAmbientOcclusion() { } @Override - public @Nullable BlockModel.GuiLight getGuiLight() { + public @Nullable UnbakedModel.GuiLight getGuiLight() { return modelOption.getGuiLight(); } @Override - public @Nullable ResourceLocation getParticle() { + public @Nullable Identifier getParticle() { return modelOption.getParticle(); } diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjUnbakedModelModel.java b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjUnbakedModelModel.java index 395c4f1..e97bed9 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjUnbakedModelModel.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/model/obj/ObjUnbakedModelModel.java @@ -6,30 +6,29 @@ import de.javagl.obj.ObjSplitting; import dev.felnull.specialmodelloader.api.model.obj.ObjModelOption; import dev.felnull.specialmodelloader.impl.SpecialModelLoader; -import dev.felnull.specialmodelloader.impl.model.SimpleMeshModel; import dev.felnull.specialmodelloader.impl.model.SpecialBaseUnbakedModel; import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableMesh; import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.renderer.v1.model.MeshBakedGeometry; import net.fabricmc.fabric.impl.client.indigo.renderer.IndigoRenderer; -import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.block.model.TextureSlots; -import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.resources.model.*; -import net.minecraft.resources.ResourceLocation; -import org.jetbrains.annotations.NotNull; +import net.minecraft.resources.Identifier; import org.joml.Vector3f; +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class ObjUnbakedModelModel extends SpecialBaseUnbakedModel { - private final ResourceLocation location; + private final Identifier location; private final Obj obj; private final Map mtl; private final ObjModelOption option; - public ObjUnbakedModelModel(ResourceLocation location, Obj obj, Map mtl, ObjModelOption option) { + public ObjUnbakedModelModel(Identifier location, Obj obj, Map mtl, ObjModelOption option) { super(option); this.location = location; this.obj = obj; @@ -38,39 +37,72 @@ public ObjUnbakedModelModel(ResourceLocation location, Obj obj, Map } @Override - public void resolveDependencies(Resolver resolver) { - } + public TextureSlots.Data textureSlots() { + // Collect all texture identifiers referenced by MTL files and option textures + // so they are included in the texture atlas + Set textures = new HashSet<>(); + + // Add textures from MTL materials + for (Mtl material : mtl.values()) { + String tex = material.getMapKd(); + if (tex != null && !tex.startsWith("#")) { + textures.add(Identifier.parse(tex)); + } + } - @Override - public @NotNull BakedModel bake(TextureSlots textureSlots, ModelBaker baker, ModelState modelState, boolean hasAmbientOcclusion, boolean useBlockLight, ItemTransforms transforms) { - Renderer renderer = Renderer.get(); + // Add textures from option texture overrides + textures.addAll(option.getTextures().values()); - if (renderer == null) { - SpecialModelLoader.LOGGER.warn("IndigoRenderer is used since the Renderer cannot be obtained. ({})", location); - renderer = IndigoRenderer.INSTANCE; + // Add particle texture + if (getModelOption().getParticle() != null) { + textures.add(getModelOption().getParticle()); } - MutableMesh builder = renderer.mutableMesh(); - QuadEmitter emitter = builder.emitter(); - SpriteGetter spriteGetter = baker.sprites(); - Map materialGroups = ObjSplitting.splitByMaterialGroups(obj); + // Build TextureSlots.Data with all textures declared as named slots + com.google.gson.JsonObject jo = new com.google.gson.JsonObject(); + int idx = 0; + for (Identifier tex : textures) { + jo.addProperty("sml_tex_" + idx, tex.toString()); + idx++; + } + if (getModelOption().getParticle() != null) { + jo.addProperty(UnbakedModel.PARTICLE_TEXTURE_REFERENCE, getModelOption().getParticle().toString()); + } else if (!textures.isEmpty()) { + // Default particle to the first available texture + jo.addProperty(UnbakedModel.PARTICLE_TEXTURE_REFERENCE, textures.iterator().next().toString()); + } - materialGroups.forEach((name, model) -> { - for (int i = 0; i < model.getNumFaces(); i++) { - emitFace(emitter, modelState, spriteGetter, name, model, model.getFace(i)); + return TextureSlots.parseTextureMap(jo); + } + + @Override + public UnbakedGeometry geometry() { + return (textureSlots, baker, modelState, debugName) -> { + Renderer renderer = Renderer.get(); + + if (renderer == null) { + SpecialModelLoader.LOGGER.warn("IndigoRenderer is used since the Renderer cannot be obtained. ({})", + location); + renderer = IndigoRenderer.INSTANCE; } - }); - - return new SimpleMeshModel( - getModelOption().isUseAmbientOcclusion(), - getGuiLight().lightLikeBlock(), - spriteGetter.get(getParticleLocation()), - getModelOption().getTransforms(), - builder.immutableCopy() - ); + + MutableMesh builder = renderer.mutableMesh(); + QuadEmitter emitter = builder.emitter(); + SpriteGetter spriteGetter = baker.sprites(); + Map materialGroups = ObjSplitting.splitByMaterialGroups(obj); + + materialGroups.forEach((name, model) -> { + for (int i = 0; i < model.getNumFaces(); i++) { + emitFace(emitter, modelState, spriteGetter, debugName, name, model, model.getFace(i)); + } + }); + + return new MeshBakedGeometry(builder.immutableCopy()); + }; } - private void emitFace(QuadEmitter emitter, ModelState modelState, SpriteGetter spriteGetter, String materialName, Obj fObj, ObjFace face) { + private void emitFace(QuadEmitter emitter, ModelState modelState, SpriteGetter spriteGetter, + ModelDebugName debugName, String materialName, Obj fObj, ObjFace face) { for (int i = 0; i < face.getNumVertices(); i++) { emitVertex(i, i, emitter, modelState, fObj, face); } @@ -85,23 +117,20 @@ private void emitFace(QuadEmitter emitter, ModelState modelState, SpriteGetter s if (option.isFlipV()) flg |= MutableQuadView.BAKE_FLIP_V; - if (modelState.isUvLocked()) - flg |= MutableQuadView.BAKE_LOCK_UV; - - ResourceLocation texLoc = null; + Identifier texLoc = null; String tex; if (smtl != null && (tex = smtl.getMapKd()) != null) { if (tex.startsWith("#")) { texLoc = option.getTextures().get(tex.substring(1)); } else { - texLoc = ResourceLocation.parse(tex); + texLoc = Identifier.parse(tex); } } if (texLoc != null) { - emitter.spriteBake(spriteGetter.get(new Material(TextureAtlas.LOCATION_BLOCKS, texLoc)), flg); + emitter.spriteBake(spriteGetter.get(new Material(ModelManager.BLOCK_OR_ITEM, texLoc), debugName), flg); } else { - emitter.spriteBake(spriteGetter.get(MISSING), flg); + emitter.spriteBake(spriteGetter.get(MISSING, debugName), flg); } emitter.color(-1, -1, -1, -1); @@ -109,12 +138,13 @@ private void emitFace(QuadEmitter emitter, ModelState modelState, SpriteGetter s emitter.emit(); } - private void emitVertex(int index, int vertexNum, QuadEmitter emitter, ModelState modelState, Obj fObj, ObjFace face) { + private void emitVertex(int index, int vertexNum, QuadEmitter emitter, ModelState modelState, Obj fObj, + ObjFace face) { var vt = fObj.getVertex(face.getVertexIndex(vertexNum)); var vertex = new Vector3f(vt.getX(), vt.getY(), vt.getZ()); vertex.add(-0.5f, -0.5f, -0.5f); - vertex.rotate(modelState.getRotation().getLeftRotation()); + vertex.rotate(modelState.transformation().getLeftRotation()); vertex.add(0.5f, 0.5f, 0.5f); var normal = fObj.getNormal(face.getNormalIndex(vertexNum)); diff --git a/src/client/java/dev/felnull/specialmodelloader/impl/util/JsonUtils.java b/src/client/java/dev/felnull/specialmodelloader/impl/util/JsonUtils.java index c2cc21a..e39a56c 100644 --- a/src/client/java/dev/felnull/specialmodelloader/impl/util/JsonUtils.java +++ b/src/client/java/dev/felnull/specialmodelloader/impl/util/JsonUtils.java @@ -1,22 +1,23 @@ package dev.felnull.specialmodelloader.impl.util; import com.google.gson.JsonObject; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; import net.minecraft.util.GsonHelper; public class JsonUtils { - public static ResourceLocation getParentLocation(JsonObject modelJson) { + public static Identifier getParentLocation(JsonObject modelJson) { if (modelJson == null) return null; if (modelJson.has("parent")) - return ResourceLocation.parse(GsonHelper.getAsString(modelJson, "parent")); + return Identifier.parse(GsonHelper.getAsString(modelJson, "parent")); return null; } - public static ResourceLocation getResourceLocation(JsonObject jsonObject, String name) { - if (jsonObject.has(name) && jsonObject.get(name).isJsonPrimitive() && jsonObject.getAsJsonPrimitive(name).isString()) { - return ResourceLocation.parse(jsonObject.get(name).getAsString()); + public static Identifier getResourceLocation(JsonObject jsonObject, String name) { + if (jsonObject.has(name) && jsonObject.get(name).isJsonPrimitive() + && jsonObject.getAsJsonPrimitive(name).isString()) { + return Identifier.parse(jsonObject.get(name).getAsString()); } return null; } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 04a3b85..331db89 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -32,9 +32,10 @@ "environment": "client" } ], + "accessWidener": "special-model-loader.accesswidener", "depends": { - "fabricloader": ">=0.16.9", - "minecraft": ">=1.21.4", + "fabricloader": ">=0.18.4", + "minecraft": ">=1.21.11", "java": ">=21", "fabric-api": "*" }, diff --git a/src/main/resources/special-model-loader.accesswidener b/src/main/resources/special-model-loader.accesswidener new file mode 100644 index 0000000..a1318be --- /dev/null +++ b/src/main/resources/special-model-loader.accesswidener @@ -0,0 +1,3 @@ +accessWidener v2 named + +accessible field net/minecraft/client/renderer/special/SpecialModelRenderers ID_MAPPER Lnet/minecraft/util/ExtraCodecs$LateBoundIdMapper; diff --git a/src/test/java/dev/felnull/smltest/block/SMLTestBlocks.java b/src/test/java/dev/felnull/smltest/block/SMLTestBlocks.java index a02fcb1..ee4625b 100644 --- a/src/test/java/dev/felnull/smltest/block/SMLTestBlocks.java +++ b/src/test/java/dev/felnull/smltest/block/SMLTestBlocks.java @@ -3,8 +3,8 @@ import dev.felnull.smltest.SMLTest; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; @@ -16,10 +16,14 @@ import java.util.function.Function; public class SMLTestBlocks { - public static final Block NORMAL_MODEL_BLOCK = register("normal_model_block", Block::new, BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); - public static final Block OBJ_MODEL_BLOCK = register("obj_model_block", Block::new, BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); - public static final Block FACING_MODEL_BLOCK = register("facing_model_block", FacingBlock::new, BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); - public static final Block FACING_OBJ_MODEL_BLOCK = register("facing_obj_model_block", FacingBlock::new, BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); + public static final Block NORMAL_MODEL_BLOCK = register("normal_model_block", Block::new, + BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); + public static final Block OBJ_MODEL_BLOCK = register("obj_model_block", Block::new, + BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); + public static final Block FACING_MODEL_BLOCK = register("facing_model_block", FacingBlock::new, + BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); + public static final Block FACING_OBJ_MODEL_BLOCK = register("facing_obj_model_block", FacingBlock::new, + BlockBehaviour.Properties.of().sound(SoundType.AMETHYST).mapColor(MapColor.DEEPSLATE)); public static void init() { ItemGroupEvents.modifyEntriesEvent(CreativeModeTabs.BUILDING_BLOCKS).register(ct -> { @@ -30,8 +34,10 @@ public static void init() { }); } - public static Block register(String name, Function factory, BlockBehaviour.Properties properties) { - ResourceKey resKey = ResourceKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, name)); + public static Block register(String name, Function factory, + BlockBehaviour.Properties properties) { + ResourceKey resKey = ResourceKey.create(Registries.BLOCK, + Identifier.fromNamespaceAndPath(SMLTest.MODID, name)); Block block = Blocks.register(resKey, factory, properties); Items.registerBlock(block); return block; diff --git a/src/test/java/dev/felnull/smltest/client/DynamicObjModelItemSpecialRenderer.java b/src/test/java/dev/felnull/smltest/client/DynamicObjModelItemSpecialRenderer.java index f0aade8..6e40363 100644 --- a/src/test/java/dev/felnull/smltest/client/DynamicObjModelItemSpecialRenderer.java +++ b/src/test/java/dev/felnull/smltest/client/DynamicObjModelItemSpecialRenderer.java @@ -1,26 +1,33 @@ package dev.felnull.smltest.client; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; import com.mojang.serialization.MapCodec; +import net.fabricmc.fabric.api.client.model.loading.v1.FabricBakedModelManager; import net.minecraft.client.Minecraft; -import net.minecraft.client.model.geom.EntityModelSet; -import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.block.model.BlockStateModel; import net.minecraft.client.renderer.special.NoDataSpecialModelRenderer; import net.minecraft.client.renderer.special.SpecialModelRenderer; -import net.minecraft.client.resources.model.BakedModel; import net.minecraft.world.item.ItemDisplayContext; import org.jetbrains.annotations.NotNull; +import org.joml.Vector3f; +import org.joml.Vector3fc; -import java.util.Objects; import java.util.function.Consumer; public class DynamicObjModelItemSpecialRenderer implements NoDataSpecialModelRenderer { @Override - public void render(ItemDisplayContext displayContext, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, boolean hasFoilType) { + public void getExtents(Consumer consumer) { + consumer.accept(new Vector3f(0, 0, 0)); + consumer.accept(new Vector3f(1, 1, 1)); + } + + @Override + public void submit(ItemDisplayContext displayContext, PoseStack poseStack, SubmitNodeCollector collector, + int packedLight, int packedOverlay, boolean hasFoilType, int seed) { poseStack.pushPose(); poseCenterConsumer(poseStack, 0.5f, 0.5f, 0.5f, pose -> { @@ -29,25 +36,23 @@ public void render(ItemDisplayContext displayContext, PoseStack poseStack, Multi poseRotateZ(poseStack, 360f * (float) (System.currentTimeMillis() % 30000) / 30000f); }); - var model = Minecraft.getInstance().getModelManager().getModel(SMLTestClient.TEST_OBJ_MODEL); - var vc = bufferSource.getBuffer(Sheets.solidBlockSheet()); - renderModel(poseStack, vc, model, packedLight, packedOverlay); + var model = ((FabricBakedModelManager) Minecraft.getInstance().getModelManager()) + .getModel(SMLTestClient.TEST_OBJ_MODEL_KEY); + if (model != null) { + collector.submitBlockModel(poseStack, Sheets.solidBlockSheet(), model, 1.0f, 1.0f, 1.0f, packedLight, + packedOverlay, seed); + } poseStack.popPose(); } - public static void poseCenterConsumer(@NotNull PoseStack poseStack, float centerX, float centerY, float centerZ, @NotNull Consumer poseStackConsumer) { + public static void poseCenterConsumer(@NotNull PoseStack poseStack, float centerX, float centerY, float centerZ, + @NotNull Consumer poseStackConsumer) { poseStack.translate(centerX, centerY, centerZ); poseStackConsumer.accept(poseStack); poseStack.translate(-centerX, -centerY, -centerZ); } - public static void renderModel(PoseStack poseStack, VertexConsumer vertexConsumer, @NotNull BakedModel bakedModel, int combinedLight, int combinedOverlay) { - Objects.requireNonNull(bakedModel); - var bmr = Minecraft.getInstance().getBlockRenderer().getModelRenderer(); - bmr.renderModel(poseStack.last(), vertexConsumer, null, bakedModel, 1.0F, 1.0F, 1.0F, combinedLight, combinedOverlay); - } - public static void poseRotateX(@NotNull PoseStack poseStack, float angle) { poseStack.mulPose(Axis.XP.rotationDegrees(angle)); } @@ -64,7 +69,7 @@ public record Unbaked() implements SpecialModelRenderer.Unbaked { public static final MapCodec MAP_CODEC = MapCodec.unit(new Unbaked()); @Override - public @NotNull SpecialModelRenderer bake(EntityModelSet modelSet) { + public @NotNull SpecialModelRenderer bake(SpecialModelRenderer.BakingContext context) { return new DynamicObjModelItemSpecialRenderer(); } diff --git a/src/test/java/dev/felnull/smltest/client/SMLTestClient.java b/src/test/java/dev/felnull/smltest/client/SMLTestClient.java index f678075..08bb14b 100644 --- a/src/test/java/dev/felnull/smltest/client/SMLTestClient.java +++ b/src/test/java/dev/felnull/smltest/client/SMLTestClient.java @@ -4,20 +4,26 @@ import dev.felnull.specialmodelloader.api.event.SpecialModelLoaderEvents; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin; +import net.fabricmc.fabric.api.client.model.loading.v1.SimpleUnbakedExtraModel; +import net.fabricmc.fabric.api.client.model.loading.v1.ExtraModelKey; +import net.minecraft.client.renderer.block.model.BlockStateModel; import net.minecraft.client.renderer.special.SpecialModelRenderers; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.resources.Identifier; public class SMLTestClient implements ClientModInitializer { - public static final ResourceLocation TEST_OBJ_MODEL = ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, "item/obj_model_item_dynamic"); + public static final Identifier TEST_OBJ_MODEL = Identifier.fromNamespaceAndPath(SMLTest.MODID, + "item/obj_model_item_dynamic"); + public static final ExtraModelKey TEST_OBJ_MODEL_KEY = ExtraModelKey.create(); @Override public void onInitializeClient() { - SpecialModelLoaderEvents.LOAD_SCOPE.register(() -> (resManager, location) -> SMLTest.MODID.equals(location.getNamespace())); - ModelLoadingPlugin.register(pluginContext -> pluginContext.addModels(TEST_OBJ_MODEL)); + SpecialModelLoaderEvents.LOAD_SCOPE + .register(() -> (resManager, location) -> SMLTest.MODID.equals(location.getNamespace())); + ModelLoadingPlugin.register(pluginContext -> pluginContext.addModel(TEST_OBJ_MODEL_KEY, + SimpleUnbakedExtraModel.blockStateModel(TEST_OBJ_MODEL))); SpecialModelRenderers.ID_MAPPER.put( - ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, "dynamic_obj_model_item"), - DynamicObjModelItemSpecialRenderer.Unbaked.MAP_CODEC - ); + Identifier.fromNamespaceAndPath(SMLTest.MODID, "dynamic_obj_model_item"), + DynamicObjModelItemSpecialRenderer.Unbaked.MAP_CODEC); } } diff --git a/src/test/java/dev/felnull/smltest/data/SMLTestModelProvider.java b/src/test/java/dev/felnull/smltest/data/SMLTestModelProvider.java index 9d61bb7..1c69af6 100644 --- a/src/test/java/dev/felnull/smltest/data/SMLTestModelProvider.java +++ b/src/test/java/dev/felnull/smltest/data/SMLTestModelProvider.java @@ -9,61 +9,85 @@ import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; import net.minecraft.client.data.models.BlockModelGenerators; import net.minecraft.client.data.models.ItemModelGenerators; +import net.minecraft.client.data.models.MultiVariant; import net.minecraft.client.data.models.blockstates.MultiVariantGenerator; -import net.minecraft.client.data.models.blockstates.Variant; -import net.minecraft.client.data.models.blockstates.VariantProperties; +import net.minecraft.client.data.models.blockstates.PropertyDispatch; import net.minecraft.client.data.models.model.ItemModelUtils; import net.minecraft.client.data.models.model.ModelLocationUtils; import net.minecraft.client.data.models.model.ModelTemplates; import net.minecraft.client.data.models.model.TexturedModel; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.client.renderer.block.model.Variant; +import net.minecraft.client.renderer.block.model.VariantMutator; +import net.minecraft.core.Direction; +import net.minecraft.resources.Identifier; +import net.minecraft.util.random.WeightedList; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; public class SMLTestModelProvider extends FabricModelProvider { - public SMLTestModelProvider(FabricDataOutput output) { - super(output); - } + public SMLTestModelProvider(FabricDataOutput output) { + super(output); + } - @Override - public void generateBlockStateModels(BlockModelGenerators blockStateModelGenerator) { - blockStateModelGenerator.createTrivialCube(SMLTestBlocks.NORMAL_MODEL_BLOCK); + @Override + public void generateBlockStateModels(BlockModelGenerators blockStateModelGenerator) { + blockStateModelGenerator.createTrivialCube(SMLTestBlocks.NORMAL_MODEL_BLOCK); - createFacing(blockStateModelGenerator, SMLTestBlocks.FACING_MODEL_BLOCK); + createFacing(blockStateModelGenerator, SMLTestBlocks.FACING_MODEL_BLOCK); - blockStateModelGenerator.blockStateOutput.accept(MultiVariantGenerator.multiVariant(SMLTestBlocks.FACING_OBJ_MODEL_BLOCK, Variant.variant().with(VariantProperties.MODEL, ModelLocationUtils.getModelLocation(SMLTestBlocks.OBJ_MODEL_BLOCK, ""))) - .with(BlockModelGenerators.createHorizontalFacingDispatch())); - } + blockStateModelGenerator.blockStateOutput.accept(MultiVariantGenerator + .dispatch(SMLTestBlocks.FACING_OBJ_MODEL_BLOCK, + new MultiVariant(WeightedList.of(new Variant(ModelLocationUtils + .getModelLocation(SMLTestBlocks.OBJ_MODEL_BLOCK, ""))))) + .with(createHorizontalFacingDispatch())); + } - private void createFacing(BlockModelGenerators blockStateModelGenerator, Block block) { - var r = TexturedModel.ORIENTABLE_ONLY_TOP.create(SMLTestBlocks.FACING_MODEL_BLOCK, blockStateModelGenerator.modelOutput); + private void createFacing(BlockModelGenerators blockStateModelGenerator, Block block) { + var r = TexturedModel.ORIENTABLE_ONLY_TOP.create(SMLTestBlocks.FACING_MODEL_BLOCK, + blockStateModelGenerator.modelOutput); - blockStateModelGenerator.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block, Variant.variant().with(VariantProperties.MODEL, r)) - .with(BlockModelGenerators.createHorizontalFacingDispatch())); - } + blockStateModelGenerator.blockStateOutput.accept(MultiVariantGenerator.dispatch(block, + new MultiVariant(WeightedList.of(new Variant(r)))) + .with(createHorizontalFacingDispatch())); + } - @Override - public void generateItemModels(ItemModelGenerators itemModelGenerator) { - itemModelGenerator.generateFlatItem(SMLTestItems.NORMAL_MODEL_ITEM, ModelTemplates.FLAT_ITEM); + private static PropertyDispatch createHorizontalFacingDispatch() { + return PropertyDispatch.modify(BlockStateProperties.HORIZONTAL_FACING) + .select(Direction.EAST, BlockModelGenerators.Y_ROT_90) + .select(Direction.SOUTH, BlockModelGenerators.Y_ROT_180) + .select(Direction.WEST, BlockModelGenerators.Y_ROT_270) + .select(Direction.NORTH, BlockModelGenerators.NOP); + } - SpecialModelDataGenHelper.generateObjModel(SMLTestItems.OBJ_MODEL_ITEM, ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, "models/item/sea_cheken_pack/sea_chicken.obj"), - true, false, null, ImmutableMap.of(), - null, itemModelGenerator.modelOutput); - itemModelGenerator.itemModelOutput.accept(SMLTestItems.OBJ_MODEL_ITEM, - ItemModelUtils.plainModel(ModelLocationUtils.getModelLocation(SMLTestItems.OBJ_MODEL_ITEM))); + @Override + public void generateItemModels(ItemModelGenerators itemModelGenerator) { + itemModelGenerator.generateFlatItem(SMLTestItems.NORMAL_MODEL_ITEM, ModelTemplates.FLAT_ITEM); - SpecialModelDataGenHelper.generateObjModel(SMLTestItems.MTLOVERRIDE_OBJ_MODEL_ITEM, - ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, "models/item/ring/ring.obj"), - true, false, SMLTest.MODID + ":models/item/ring/ring_2.mtl", ImmutableMap.of(), - null, itemModelGenerator.modelOutput); - itemModelGenerator.itemModelOutput.accept(SMLTestItems.MTLOVERRIDE_OBJ_MODEL_ITEM, - ItemModelUtils.plainModel(ModelLocationUtils.getModelLocation(SMLTestItems.MTLOVERRIDE_OBJ_MODEL_ITEM))); + SpecialModelDataGenHelper.generateObjModel(SMLTestItems.OBJ_MODEL_ITEM, + Identifier.fromNamespaceAndPath(SMLTest.MODID, + "models/item/sea_cheken_pack/sea_chicken.obj"), + true, false, null, ImmutableMap.of(), + null, itemModelGenerator.modelOutput); + itemModelGenerator.itemModelOutput.accept(SMLTestItems.OBJ_MODEL_ITEM, + ItemModelUtils.plainModel( + ModelLocationUtils.getModelLocation(SMLTestItems.OBJ_MODEL_ITEM))); - SpecialModelDataGenHelper.generateObjModel(SMLTestItems.TEXTURES_OBJ_MODEL_ITEM, - ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, "models/item/ring/ring.obj"), - true, false, null, ImmutableMap.of("texture0", ResourceLocation.withDefaultNamespace("block/cobblestone")), - null, itemModelGenerator.modelOutput); - itemModelGenerator.itemModelOutput.accept(SMLTestItems.TEXTURES_OBJ_MODEL_ITEM, - ItemModelUtils.plainModel(ModelLocationUtils.getModelLocation(SMLTestItems.TEXTURES_OBJ_MODEL_ITEM))); - } + SpecialModelDataGenHelper.generateObjModel(SMLTestItems.MTLOVERRIDE_OBJ_MODEL_ITEM, + Identifier.fromNamespaceAndPath(SMLTest.MODID, "models/item/ring/ring.obj"), + true, false, SMLTest.MODID + ":models/item/ring/ring_2.mtl", ImmutableMap.of(), + null, itemModelGenerator.modelOutput); + itemModelGenerator.itemModelOutput.accept(SMLTestItems.MTLOVERRIDE_OBJ_MODEL_ITEM, + ItemModelUtils.plainModel(ModelLocationUtils + .getModelLocation(SMLTestItems.MTLOVERRIDE_OBJ_MODEL_ITEM))); + + SpecialModelDataGenHelper.generateObjModel(SMLTestItems.TEXTURES_OBJ_MODEL_ITEM, + Identifier.fromNamespaceAndPath(SMLTest.MODID, "models/item/ring/ring.obj"), + true, false, null, + ImmutableMap.of("texture0", Identifier.withDefaultNamespace("block/cobblestone")), + null, itemModelGenerator.modelOutput); + itemModelGenerator.itemModelOutput.accept(SMLTestItems.TEXTURES_OBJ_MODEL_ITEM, + ItemModelUtils.plainModel(ModelLocationUtils + .getModelLocation(SMLTestItems.TEXTURES_OBJ_MODEL_ITEM))); + } } diff --git a/src/test/java/dev/felnull/smltest/item/SMLTestItems.java b/src/test/java/dev/felnull/smltest/item/SMLTestItems.java index 5b70fce..ff70c2f 100644 --- a/src/test/java/dev/felnull/smltest/item/SMLTestItems.java +++ b/src/test/java/dev/felnull/smltest/item/SMLTestItems.java @@ -3,8 +3,8 @@ import dev.felnull.smltest.SMLTest; import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; import net.minecraft.core.registries.Registries; +import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; @@ -16,9 +16,12 @@ public class SMLTestItems { public static final Item OBJ_MODEL_ITEM = register("obj_model_item", Item::new, new Item.Properties()); public static final Item OBJ2_MODEL_ITEM = register("obj2_model_item", Item::new, new Item.Properties()); public static final Item FORGE_OBJ_MODEL_ITEM = register("forge_obj_model_item", Item::new, new Item.Properties()); - public static final Item DYNAMIC_OBJ_MODEL_ITEM = register("dynamic_obj_model_item", Item::new, new Item.Properties()); - public static final Item MTLOVERRIDE_OBJ_MODEL_ITEM = register("mtloverride_obj_model_item", Item::new, new Item.Properties()); - public static final Item TEXTURES_OBJ_MODEL_ITEM = register("textures_obj_model_item", Item::new, new Item.Properties()); + public static final Item DYNAMIC_OBJ_MODEL_ITEM = register("dynamic_obj_model_item", Item::new, + new Item.Properties()); + public static final Item MTLOVERRIDE_OBJ_MODEL_ITEM = register("mtloverride_obj_model_item", Item::new, + new Item.Properties()); + public static final Item TEXTURES_OBJ_MODEL_ITEM = register("textures_obj_model_item", Item::new, + new Item.Properties()); public static void init() { ItemGroupEvents.modifyEntriesEvent(CreativeModeTabs.BUILDING_BLOCKS).register(ct -> { @@ -33,7 +36,8 @@ public static void init() { } public static Item register(String name, Function factory, Item.Properties properties) { - ResourceKey resKey = ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(SMLTest.MODID, name)); + ResourceKey resKey = ResourceKey.create(Registries.ITEM, + Identifier.fromNamespaceAndPath(SMLTest.MODID, name)); return Items.registerItem(resKey, factory, properties); } } diff --git a/src/test/resources/fabric.mod.json b/src/test/resources/fabric.mod.json index cd6b914..16e8846 100644 --- a/src/test/resources/fabric.mod.json +++ b/src/test/resources/fabric.mod.json @@ -7,8 +7,7 @@ "authors": [ "MORIMORI0317" ], - "contact": { - }, + "contact": {}, "license": "IKISUGI", "environment": "*", "entrypoints": { @@ -23,8 +22,8 @@ ] }, "depends": { - "fabricloader": ">=0.16.9", + "fabricloader": ">=0.18.4", "java": ">=21", "fabric-api": "*" } -} +} \ No newline at end of file