Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -29,6 +29,7 @@ fabricApi {

loom {
splitEnvironmentSourceSets()
accessWidenerPath = file("src/main/resources/special-model-loader.accesswidener")

mods {
"special-model-loader" {
Expand Down Expand Up @@ -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}"

Expand All @@ -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 {
Expand All @@ -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()

Expand Down
12 changes: 7 additions & 5 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Empty file modified gradlew
100644 → 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -26,29 +26,35 @@ static SpecialModelLoaderAPI getInstance() {
* @return ModelLoader list
*/
@Unmodifiable
@NotNull List<ModelLoader> getLoaders();
@NotNull
List<ModelLoader> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<String, ResourceLocation> textures,
@Nullable ResourceLocation particle, @NotNull BiConsumer<ResourceLocation, ModelInstance> output) {
public static void generateObjModel(@NotNull Identifier location, @NotNull Identifier objLocation,
boolean flipV, boolean useAmbientOcclusion, @Nullable String mtlOverride,
@Unmodifiable @NotNull Map<String, Identifier> textures,
@Nullable Identifier particle, @NotNull BiConsumer<Identifier, ModelInstance> output) {

output.accept(location, () -> {
var jo = new JsonObject();
Expand Down Expand Up @@ -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<String, ResourceLocation> textures,
@Nullable ResourceLocation particle, @NotNull BiConsumer<ResourceLocation, ModelInstance> 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<String, Identifier> textures,
@Nullable Identifier particle, @NotNull BiConsumer<Identifier, ModelInstance> 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<String, ResourceLocation> textures,
@Nullable ResourceLocation particle, @NotNull BiConsumer<ResourceLocation, ModelInstance> 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<String, Identifier> textures,
@Nullable Identifier particle, @NotNull BiConsumer<Identifier, ModelInstance> output) {
generateObjModel(ModelLocationUtils.getModelLocation(block), objLocation, flipV, useAmbientOcclusion,
mtlOverride, textures, particle, output);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,41 +14,47 @@
public final class SpecialModelLoaderEvents {

public static final Event<LoadScope> LOAD_SCOPE = EventFactory.createArrayBacked(LoadScope.class, loadScopes -> {
BiPredicate<ResourceManager, ResourceLocation> predicate = Arrays.stream(loadScopes)
BiPredicate<ResourceManager, Identifier> predicate = Arrays.stream(loadScopes)
.map(LoadScope::provideLoadScopePredicate)
.reduce(BiPredicate::or)
.orElseGet(() -> (res, loc) -> false);
return () -> predicate;
});

public static final Event<AsyncLoadScope> LOAD_SCOPE_ASYNC = EventFactory.createArrayBacked(AsyncLoadScope.class, loadScopes -> (resourceManager, executor) ->
Arrays.stream(loadScopes)
public static final Event<AsyncLoadScope> 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<Identifier>) loc -> false)));

public interface LoadScope {

/**
* It must return a Predicate to check if the given resource location is Load Scope.<br/>
* 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.<br/>
* 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<ResourceManager, ResourceLocation> provideLoadScopePredicate();
BiPredicate<ResourceManager, Identifier> provideLoadScopePredicate();

}

public interface AsyncLoadScope {

/**
* Must return a CompletableFuture that obtains a Predicate to check if the given resource location is Load Scope.<br/>
* 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.<br/>
* 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<Predicate<ResourceLocation>> provideAsyncLoadScopePredicate(ResourceManager resourceManager, Executor executor);
CompletableFuture<Predicate<Identifier>> provideAsyncLoadScopePredicate(ResourceManager resourceManager,
Executor executor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,32 @@
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;

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.
*
* @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.
Expand All @@ -49,15 +52,16 @@ public interface ModelLoader {
*
* @return ID
*/
@Nullable String getId();
@Nullable
String getId();

/**
* Whether the model uses this model loader or not.
*
* @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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,7 +15,7 @@ public interface ObjModelOption extends ModelOption {

@NotNull
static ObjModelOption of(@NotNull ModelOption modelOption, boolean flipV,
String mtlOverride, Map<String, ResourceLocation> textures) {
String mtlOverride, Map<String, Identifier> textures) {
return new ObjModelOptionImpl(modelOption, flipV, mtlOverride, ImmutableMap.copyOf(textures));
}

Expand All @@ -31,5 +31,5 @@ static ObjModelOption parse(@NotNull JsonObject modelJson) {

@Unmodifiable
@NotNull
Map<String, ResourceLocation> getTextures();
Map<String, Identifier> getTextures();
}
Loading