diff --git a/build-logic/src/main/groovy/qsl.module.gradle b/build-logic/src/main/groovy/qsl.module.gradle index 95257f7479..d173c117b3 100644 --- a/build-logic/src/main/groovy/qsl.module.gradle +++ b/build-logic/src/main/groovy/qsl.module.gradle @@ -193,6 +193,7 @@ javadoc { license { rule rootProject.file("codeformat/COLONEL_MODIFIED_HEADER") rule rootProject.file("codeformat/FABRIC_MODIFIED_HEADER") + rule rootProject.file("codeformat/FOUNDATIONGAMES_MODIFIED_HEADER") rule rootProject.file("codeformat/HEADER") include "**/*.java" diff --git a/codeformat/FOUNDATIONGAMES_MODIFIED_HEADER b/codeformat/FOUNDATIONGAMES_MODIFIED_HEADER new file mode 100644 index 0000000000..000623e5d4 --- /dev/null +++ b/codeformat/FOUNDATIONGAMES_MODIFIED_HEADER @@ -0,0 +1,26 @@ +Copyright 2021 FoundationGames + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Copyright ${YEAR} QuiltMC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +;;match_from: \/\*\r?\n \* Copyright 2021 FoundationGames +;;match_from: \/\/\/ F[Oo][Uu][Nn][Dd][Aa][Tt][Ii][Oo][Nn] +;;year_display: lenient_range \ No newline at end of file diff --git a/library/rendering/entity_models/build.gradle b/library/rendering/entity_models/build.gradle new file mode 100644 index 0000000000..7c9b60de9a --- /dev/null +++ b/library/rendering/entity_models/build.gradle @@ -0,0 +1,29 @@ +plugins { + id("qsl.module") +} + +qslModule { + name = "Quilt Entity Model API" + moduleName = "entity_models" + id = "quilt_entity_models" + description = "Adds data driven entity models and animations." + moduleDependencies { + core { + api("qsl_base") + impl("resource_loader") + } + } + injectedInterface("net/minecraft/class_898") { + values = ["org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManagerContainer"] + } + injectedInterface("net/minecraft/class_5617\$class_5618") { + values = ["org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManagerContainer"] + } + injectedInterface("net/minecraft/class_7184"){ + values = ["org/quiltmc/qsl/rendering/entity_models/api/animation/TypedAnimation"] + } + injectedInterface("net/minecraft/class_5607"){ + values = ["org/quiltmc/qsl/rendering/entity_models/api/model/TypedModel"] + } + clientOnly() +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/Codecs.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/Codecs.java new file mode 100644 index 0000000000..817bf5f1d2 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/Codecs.java @@ -0,0 +1,39 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api; + +import java.util.List; + +import com.mojang.serialization.Codec; +import org.joml.Vector3f; + +import net.minecraft.util.Util; + +public class Codecs { + public static final Codec VECTOR_3F_CODEC = Codec.list(Codec.FLOAT).comapFlatMap( + list -> Util.fixedSizeList(list, 3).map(listx -> new Vector3f(listx.get(0), listx.get(1), listx.get(2))), + vec3d -> List.of(vec3d.x(), vec3d.y(), vec3d.z())); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationCodecs.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationCodecs.java new file mode 100644 index 0000000000..d3394d7c0b --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationCodecs.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import java.util.Arrays; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.minecraft.client.render.animation.Animation; +import net.minecraft.client.render.animation.AnimationKeyframe; +import net.minecraft.client.render.animation.PartAnimation; + +import org.quiltmc.qsl.rendering.entity_models.api.Codecs; + +/** + * Codecs for animation loading. + */ +public final class AnimationCodecs { + public static final Codec KEYFRAME = RecordCodecBuilder.create(instance -> + instance.group( + Codec.floatRange(0, Float.MAX_VALUE).fieldOf("timestamp").forGetter(AnimationKeyframe::timestamp), + Codecs.VECTOR_3F_CODEC.fieldOf("transformation").forGetter(AnimationKeyframe::transformation), + AnimationInterpolations.CODEC.fieldOf("interpolator").forGetter(AnimationKeyframe::interpolator) + ).apply(instance, AnimationKeyframe::new) + ); + + public static final Codec PART_ANIMATION = RecordCodecBuilder.create(instance -> + instance.group( + AnimationTransformations.CODEC.fieldOf("transformation").forGetter(PartAnimation::transformation), + Codec.list(KEYFRAME).xmap(list -> list.toArray(AnimationKeyframe[]::new), Arrays::asList).fieldOf("keyframes").forGetter(PartAnimation::keyframes) + ).apply(instance, PartAnimation::new) + ); + + public static final Codec ANIMATION = RecordCodecBuilder.create(instance -> + instance.group( + Codec.floatRange(0, Float.MAX_VALUE).fieldOf("length").forGetter(Animation::length), + Codec.BOOL.fieldOf("looping").forGetter(Animation::looping), + Codec.unboundedMap(Codec.STRING, Codec.list(PART_ANIMATION)).fieldOf("animations").forGetter(Animation::animations) + ).apply(instance, Animation::new) + ); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationInterpolations.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationInterpolations.java new file mode 100644 index 0000000000..383f329887 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationInterpolations.java @@ -0,0 +1,59 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; + +import net.minecraft.client.render.animation.PartAnimation; +import net.minecraft.util.Identifier; + +/** + * A class for registering different {@link net.minecraft.client.render.animation.PartAnimation.Interpolator}s. + */ +public class AnimationInterpolations { + private static final BiMap INTERPOLATORS = HashBiMap.create(); + + public static final Codec CODEC = Identifier.CODEC.flatXmap(identifier -> { + PartAnimation.Interpolator type = INTERPOLATORS.get(identifier); + return type != null ? DataResult.success(type) : DataResult.error(() -> "Unknown interpolator: " + identifier); + }, type -> { + Identifier id = INTERPOLATORS.inverse().get(type); + return id != null ? DataResult.success(id) : DataResult.error(() -> "Unknown interpolator."); + }); + + static { + register("linear", PartAnimation.Interpolators.LINEAR); + register("spline", PartAnimation.Interpolators.SPLINE); + } + + public static void register(String name, PartAnimation.Interpolator interpolator) { + register(new Identifier(name), interpolator); + } + + public static void register(Identifier id, PartAnimation.Interpolator interpolator) { + if (INTERPOLATORS.containsKey(id)) { + throw new IllegalArgumentException(id + " already used as name"); + } else if (INTERPOLATORS.containsValue(interpolator)) { + throw new IllegalArgumentException("Interpolator already assigned to " + INTERPOLATORS.inverse().get(interpolator)); + } + + INTERPOLATORS.put(id, interpolator); + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManager.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManager.java new file mode 100644 index 0000000000..713001f795 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManager.java @@ -0,0 +1,126 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.JsonOps; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.client.render.animation.Animation; +import net.minecraft.client.render.entity.model.EntityModelLayer; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.profiler.Profiler; + +import org.quiltmc.qsl.resource.loader.api.reloader.SimpleResourceReloader; + +/** + * A class that loads and holds {@link Animation}s. + * See {@link net.minecraft.client.render.entity.model.EntityModelLoader#getModelPart(EntityModelLayer)} for a similar usage. + */ +public class AnimationManager implements SimpleResourceReloader { + private static final Logger LOGGER = LoggerFactory.getLogger("Quilt Animation Manager"); + private Map animations; + + /** + * + * @param id The animation ID + * @return An animation if found, or null otherwise + */ + public @Nullable Animation getAnimation(Identifier id) { + return this.animations.get(id); + } + + @Override + public CompletableFuture load(ResourceManager manager, Profiler profiler, Executor executor) { + return CompletableFuture.supplyAsync(() -> new AnimationLoader(manager, profiler), executor); + } + + @Override + public CompletableFuture apply(AnimationLoader prepared, ResourceManager manager, Profiler profiler, Executor executor) { + this.animations = prepared.getAnimations(); + return CompletableFuture.runAsync(() -> { + }); + } + + @Override + public @NotNull Identifier getQuiltId() { + return new Identifier("quilt_entity_models", "animation_reloader"); + } + + public static class AnimationLoader { + private final ResourceManager manager; + private final Profiler profiler; + private final Map animations = new HashMap<>(); + + public AnimationLoader(ResourceManager manager, Profiler profiler) { + this.manager = manager; + this.profiler = profiler; + this.loadAnimations(); + } + + private void loadAnimations() { + this.profiler.push("Load Animations"); + Map resources = this.manager.findResources("animations", id -> id.getPath().endsWith(".json")); + for (Map.Entry entry : resources.entrySet()) { + this.addAnimation(entry.getKey(), entry.getValue()); + } + + this.profiler.pop(); + } + + private void addAnimation(Identifier id, Resource resource) { + BufferedReader reader; + try { + reader = resource.openBufferedReader(); + } catch (IOException e) { + LOGGER.error(String.format("Unable to open BufferedReader for id %s", id), e); + return; + } + + JsonObject json = JsonHelper.deserialize(reader); + DataResult> result = AnimationTypes.CODEC.decode(JsonOps.INSTANCE, json); + + if (result.error().isPresent()) { + LOGGER.error(String.format("Unable to parse animation file %s.\nReason: %s", id, result.error().get().message())); + return; + } + + Identifier animationId = new Identifier(id.getNamespace(), id.getPath().substring("animations/".length())); + this.animations.put(animationId, result.result().get().getFirst()); + } + + public Map getAnimations() { + return this.animations; + } + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManagerContainer.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManagerContainer.java new file mode 100644 index 0000000000..6734cc410d --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationManagerContainer.java @@ -0,0 +1,38 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import org.jetbrains.annotations.NotNull; + +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.EntityRendererFactory; + +import org.quiltmc.qsl.base.api.util.InjectedInterface; + +/** + * An injected interface for classes that have an {@link AnimationManager}. + */ +@InjectedInterface(value = { + EntityRenderDispatcher.class, + EntityRendererFactory.Context.class +}) +public interface AnimationManagerContainer { + /** + * @return The {@link AnimationManager animation manager} for this instance + */ + @NotNull AnimationManager getAnimationManager(); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationTransformations.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationTransformations.java new file mode 100644 index 0000000000..3255cbdbbd --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationTransformations.java @@ -0,0 +1,60 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; + +import net.minecraft.client.render.animation.PartAnimation; +import net.minecraft.util.Identifier; + +/** + * A for registering different {@link net.minecraft.client.render.animation.PartAnimation.Transformation}s to. + */ +public class AnimationTransformations { + private static final BiMap TRANSFORMATIONS = HashBiMap.create(); + + public static final Codec CODEC = Identifier.CODEC.flatXmap(identifier -> { + PartAnimation.Transformation type = TRANSFORMATIONS.get(identifier); + return type != null ? DataResult.success(type) : DataResult.error(() -> "Unknown transformation: " + identifier); + }, type -> { + Identifier id = TRANSFORMATIONS.inverse().get(type); + return id != null ? DataResult.success(id) : DataResult.error(() -> "Unknown transformation."); + }); + + static { + register("translate", PartAnimation.AnimationTargets.TRANSLATE); + register("rotate", PartAnimation.AnimationTargets.ROTATE); + register("scale", PartAnimation.AnimationTargets.SCALE); + } + + public static void register(String name, PartAnimation.Transformation transformation) { + register(new Identifier(name), transformation); + } + + public static void register(Identifier id, PartAnimation.Transformation transformation) { + if (TRANSFORMATIONS.containsKey(id)) { + throw new IllegalArgumentException(id + " already used as name"); + } else if (TRANSFORMATIONS.containsValue(transformation)) { + throw new IllegalArgumentException("Transformation already assigned to " + TRANSFORMATIONS.inverse().get(transformation)); + } + + TRANSFORMATIONS.put(id, transformation); + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationType.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationType.java new file mode 100644 index 0000000000..c252a29af1 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationType.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import com.mojang.serialization.Codec; + +import net.minecraft.client.render.animation.Animation; + +/** + * A type parameter that allows animations to be loaded in different ways. + * + * @param codec The codec to load an animation + */ +public record AnimationType(Codec codec) { +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationTypes.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationTypes.java new file mode 100644 index 0000000000..0dd827ea4d --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/AnimationTypes.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; + +import net.minecraft.client.render.animation.Animation; +import net.minecraft.util.Identifier; + +public class AnimationTypes { + private static final BiMap TYPES = HashBiMap.create(); + + public static final AnimationType QUILT_ANIMATION = register("quilt:animation", AnimationCodecs.ANIMATION); + + public static final Codec TYPE_CODEC = Identifier.CODEC.flatXmap(identifier -> { + AnimationType type = TYPES.get(identifier); + return type != null ? DataResult.success(type) : DataResult.error(() -> "Unknown animation type: " + identifier); + }, animationType -> { + Identifier id = TYPES.inverse().get(animationType); + return id != null ? DataResult.success(id) : DataResult.error(() -> "Unknown animation type."); + }); + public static Codec CODEC = TYPE_CODEC.dispatch(animation -> ((TypedAnimation) (Object) animation).getType(), AnimationType::codec); + + public static AnimationType register(String name, Codec codec) { + return register(new Identifier(name), codec); + } + + public static AnimationType register(Identifier id, Codec codec) { + AnimationType type = new AnimationType(codec); + AnimationType old = TYPES.putIfAbsent(id, type); + if (old != null) { + throw new IllegalStateException("Duplicate registration for " + id); + } + + return type; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/TypedAnimation.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/TypedAnimation.java new file mode 100644 index 0000000000..3993d212e8 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/animation/TypedAnimation.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.animation; + +import net.minecraft.client.render.animation.Animation; + +import org.quiltmc.qsl.base.api.util.InjectedInterface; + +/** + * An injected interface on {@link net.minecraft.client.render.animation.Animation} to specify its type. + * Defaults to {@link org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationTypes#QUILT_ANIMATION}. + */ +@InjectedInterface(Animation.class) +public interface TypedAnimation { + AnimationType getType(); + void setType(AnimationType type); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelCodecs.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelCodecs.java new file mode 100644 index 0000000000..b25e92c6cd --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelCodecs.java @@ -0,0 +1,128 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.model; + +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.google.common.collect.ImmutableList; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import org.joml.Vector3f; + +import net.minecraft.client.model.Dilation; +import net.minecraft.client.model.ModelCuboidData; +import net.minecraft.client.model.ModelData; +import net.minecraft.client.model.ModelPartData; +import net.minecraft.client.model.ModelTransform; +import net.minecraft.client.model.TextureDimensions; +import net.minecraft.client.model.TexturedModelData; +import net.minecraft.client.util.math.Vector2f; +import net.minecraft.util.Util; +import net.minecraft.util.math.Direction; + +import org.quiltmc.qsl.rendering.entity_models.api.Codecs; +import org.quiltmc.qsl.rendering.entity_models.impl.LazyTypeUnboundedMapCodec; +import org.quiltmc.qsl.rendering.entity_models.mixin.DilationAccessor; +import org.quiltmc.qsl.rendering.entity_models.mixin.ModelCuboidDataAccessor; +import org.quiltmc.qsl.rendering.entity_models.mixin.ModelPartDataAccessor; +import org.quiltmc.qsl.rendering.entity_models.mixin.TextureDimensionsAccessor; +import org.quiltmc.qsl.rendering.entity_models.mixin.TexturedModelDataAccessor; + +/** + * Codecs for model loading. + */ +public final class ModelCodecs { + public static final Codec TEXTURE_DIMENSIONS = RecordCodecBuilder.create(instance -> + instance.group( + Codec.INT.fieldOf("width").forGetter(obj -> ((TextureDimensionsAccessor) obj).width()), + Codec.INT.fieldOf("height").forGetter(obj -> ((TextureDimensionsAccessor) obj).height()) + ).apply(instance, TextureDimensions::new) + ); + + public static final Codec MODEL_TRANSFORM = RecordCodecBuilder.create(instance -> + instance.group( + Codecs.VECTOR_3F_CODEC.optionalFieldOf("origin", new Vector3f()).forGetter(obj -> new Vector3f(obj.pivotX, obj.pivotY, obj.pivotZ)), + Codecs.VECTOR_3F_CODEC.optionalFieldOf("rotation", new Vector3f()).forGetter(obj -> new Vector3f(obj.pitch, obj.yaw, obj.roll)) + ).apply(instance, (origin, rot) -> ModelTransform.of(origin.x(), origin.y(), origin.z(), rot.x(), rot.y(), rot.z())) + ); + + public static final Codec DILATION = Codecs.VECTOR_3F_CODEC.xmap( + vec -> new Dilation(vec.x(), vec.y(), vec.z()), + dil -> new Vector3f( + ((DilationAccessor) dil).radiusX(), + ((DilationAccessor) dil).radiusY(), + ((DilationAccessor) dil).radiusZ()) + ); + + public static final Codec VECTOR2F = Codec.FLOAT.listOf().comapFlatMap(vec -> + Util.fixedSizeList(vec, 2).map((arr) -> new Vector2f(arr.get(0), arr.get(1))), + vec -> ImmutableList.of(vec.getX(), vec.getY()) + ); + + private static ModelCuboidData createCuboidData(Optional name, Vector3f offset, Vector3f dimensions, Dilation dilation, boolean mirror, Vector2f uv, Vector2f uvSize, List directions) { + return ModelCuboidDataAccessor.create( + name.orElse(null), + uv.getX(), uv.getY(), + offset.x(), offset.y(), offset.z(), + dimensions.x(), dimensions.y(), dimensions.z(), + dilation, + mirror, + uvSize.getX(), uvSize.getY(), + Set.copyOf(directions)); + } + + private static final Vector2f DEFAULT_UV_SCALE = new Vector2f(1.0f, 1.0f); + + public static final Codec MODEL_CUBOID_DATA = RecordCodecBuilder.create(instance -> + instance.group( + Codec.STRING.optionalFieldOf("name").forGetter(obj -> Optional.ofNullable(((ModelCuboidDataAccessor) (Object) obj).name())), + Codecs.VECTOR_3F_CODEC.fieldOf("offset").forGetter(obj -> ((ModelCuboidDataAccessor) (Object) obj).offset()), + Codecs.VECTOR_3F_CODEC.fieldOf("dimensions").forGetter(obj -> ((ModelCuboidDataAccessor) (Object) obj).dimensions()), + DILATION.optionalFieldOf("dilation", Dilation.NONE).forGetter(obj -> ((ModelCuboidDataAccessor) (Object) obj).dilation()), + Codec.BOOL.optionalFieldOf("mirror", false).forGetter(obj -> ((ModelCuboidDataAccessor) (Object) obj).mirror()), + VECTOR2F.fieldOf("uv").forGetter(obj -> ((ModelCuboidDataAccessor) (Object) obj).uv()), + VECTOR2F.optionalFieldOf("uv_scale", DEFAULT_UV_SCALE).forGetter(obj -> ((ModelCuboidDataAccessor) (Object) obj).uvScale()), + Direction.CODEC.listOf().optionalFieldOf("directions", List.of(Direction.values())).forGetter(obj -> List.copyOf(((ModelCuboidDataAccessor) (Object) obj).directions())) + ).apply(instance, ModelCodecs::createCuboidData) + ); + + public static final Codec MODEL_PART_DATA = RecordCodecBuilder.create(instance -> + instance.group( + MODEL_TRANSFORM.optionalFieldOf("transform", ModelTransform.NONE).forGetter(obj -> ((ModelPartDataAccessor) obj).transform()), + Codec.list(MODEL_CUBOID_DATA).fieldOf("cuboids").forGetter(obj -> ((ModelPartDataAccessor) obj).cuboids()), + LazyTypeUnboundedMapCodec.of(Codec.STRING, () -> ModelCodecs.MODEL_PART_DATA).optionalFieldOf("children", new HashMap<>()).forGetter(obj -> ((ModelPartDataAccessor) obj).children()) + ).apply(instance, (transform, cuboids, children) -> { + var data = ModelPartDataAccessor.create(cuboids, transform); + ((ModelPartDataAccessor) data).children().putAll(children); + return data; + }) + ); + + public static final Codec TEXTURED_MODEL_DATA = RecordCodecBuilder.create(instance -> + instance.group( + TEXTURE_DIMENSIONS.fieldOf("texture").forGetter(obj -> ((TexturedModelDataAccessor) obj).texture()), + Codec.unboundedMap(Codec.STRING, MODEL_PART_DATA).fieldOf("bones").forGetter(obj -> ((ModelPartDataAccessor) ((TexturedModelDataAccessor) obj).root().getRoot()).children()) + ).apply(instance, (texture, bones) -> { + var data = new ModelData(); + ((ModelPartDataAccessor) data.getRoot()).children().putAll(bones); + return TexturedModelDataAccessor.create(data, texture); + }) + ); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelType.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelType.java new file mode 100644 index 0000000000..bee3cb9a5b --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelType.java @@ -0,0 +1,29 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.model; + +import com.mojang.serialization.Codec; + +import net.minecraft.client.model.TexturedModelData; + +/** + * A type parameter that allows models to be loaded in different ways. + * + * @param codec The codec to load a model + */ +public record ModelType(Codec codec) { +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelTypes.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelTypes.java new file mode 100644 index 0000000000..4b6592dc82 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/ModelTypes.java @@ -0,0 +1,54 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.model; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; + +import net.minecraft.client.model.TexturedModelData; +import net.minecraft.util.Identifier; + +public class ModelTypes { + private static final BiMap TYPES = HashBiMap.create(); + + public static final ModelType QUILT_MODEL = register("quilt:model", ModelCodecs.TEXTURED_MODEL_DATA); + + public static final Codec TYPE_CODEC = Identifier.CODEC.flatXmap(identifier -> { + ModelType type = TYPES.get(identifier); + return type != null ? DataResult.success(type) : DataResult.error(() -> "Unknown model type: " + identifier); + }, model -> { + Identifier id = TYPES.inverse().get(model); + return id != null ? DataResult.success(id) : DataResult.error(() -> "Unknown model type."); + }); + public static Codec CODEC = TYPE_CODEC.dispatch(model -> ((TypedModel) (Object) model).getType(), ModelType::codec); + + public static ModelType register(String name, Codec codec) { + return register(new Identifier(name), codec); + } + + public static ModelType register(Identifier id, Codec codec) { + ModelType type = new ModelType(codec); + ModelType old = TYPES.putIfAbsent(id, type); + if (old != null) { + throw new IllegalStateException("Duplicate registration for " + id); + } + + return type; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/TypedModel.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/TypedModel.java new file mode 100644 index 0000000000..67c6114e51 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/model/TypedModel.java @@ -0,0 +1,31 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.api.model; + +import net.minecraft.client.model.TexturedModelData; + +import org.quiltmc.qsl.base.api.util.InjectedInterface; + +/** + * An injected interface on {@link net.minecraft.client.model.TexturedModelData} to specify its type. + * Defaults to {@link ModelTypes#QUILT_MODEL}. + */ +@InjectedInterface(TexturedModelData.class) +public interface TypedModel { + ModelType getType(); + void setType(ModelType type); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/package-info.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/package-info.java new file mode 100644 index 0000000000..3d4cd8deb8 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/api/package-info.java @@ -0,0 +1,11 @@ +/** + * This API is responsible for loading {@link net.minecraft.client.render.animation.Animation Animations} and {@link net.minecraft.client.model.TexturedModelData Models} from assets. + * + *

+ * Animations are expected to be at {@code assets/[namespace]/animations/[path].json}, and are retrievable from an {@link org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationManager AnimationManager} with an identifier. + * + *

+ * Models are loaded from {@code assets/[namespace]/models/entity/[path]/[layer_name].json}. Models can be automatically retrieved from the {@link net.minecraft.client.render.entity.model.EntityModelLoader EntityModelLoader} with the proper {@link net.minecraft.client.render.entity.model.EntityModelLayer EntityModelLayer}. + */ + +package org.quiltmc.qsl.rendering.entity_models.api; diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/impl/DynamicEntityModelLoader.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/impl/DynamicEntityModelLoader.java new file mode 100644 index 0000000000..8250f62cb6 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/impl/DynamicEntityModelLoader.java @@ -0,0 +1,128 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.impl; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.JsonOps; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.minecraft.client.model.TexturedModelData; +import net.minecraft.client.render.entity.model.EntityModelLayer; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.profiler.Profiler; + +import org.quiltmc.qsl.rendering.entity_models.api.model.ModelTypes; +import org.quiltmc.qsl.resource.loader.api.reloader.SimpleResourceReloader; + +public class DynamicEntityModelLoader implements SimpleResourceReloader { + private static final Logger LOGGER = LoggerFactory.getLogger("Quilt Entity Model Manager"); + private Map modelData; + + public TexturedModelData getModelData(EntityModelLayer layer) { + return this.modelData.get(layer); + } + + @Override + public CompletableFuture load(ResourceManager manager, Profiler profiler, Executor executor) { + return CompletableFuture.supplyAsync(() -> new ModelLoader(manager, profiler), executor); + } + + @Override + public CompletableFuture apply(ModelLoader prepared, ResourceManager manager, Profiler profiler, Executor executor) { + this.modelData = prepared.getModelData(); + return CompletableFuture.runAsync(() -> {}); + } + + @Override + public Identifier getQuiltId() { + return new Identifier("quilt_entity_models", "entity_model_reloader"); + } + + public static class ModelLoader { + private static final Pattern PATH_AND_NAME_PATTERN = Pattern.compile("models/entity/([\\w/]*)/(\\w*)\\.json"); + + private final ResourceManager manager; + private final Profiler profiler; + private final Map modelData = new HashMap<>(); + + public ModelLoader(ResourceManager manager, Profiler profiler) { + this.manager = manager; + this.profiler = profiler; + this.loadModels(); + } + + private void loadModels() { + this.profiler.push("Load Entity Models"); + Map resources = this.manager.findResources("models/entity", id -> id.getPath().endsWith(".json")); + for (Map.Entry entry : resources.entrySet()) { + this.addModel(entry.getKey(), entry.getValue()); + } + + this.profiler.pop(); + } + + private void addModel(Identifier id, Resource resource) { + BufferedReader reader; + try { + reader = resource.openBufferedReader(); + } catch (IOException e) { + LOGGER.error(String.format("Unable to open BufferedReader for id %s", id), e); + return; + } + + JsonObject json = JsonHelper.deserialize(reader); + DataResult> result = ModelTypes.CODEC.decode(JsonOps.INSTANCE, json); + + if (result.error().isPresent()) { + LOGGER.error(String.format("Unable to parse entity model file %s.\nReason: %s", id, result.error().get().message())); + return; + } + + Matcher matcher = PATH_AND_NAME_PATTERN.matcher(id.getPath()); + if (!matcher.find()) { + LOGGER.error(String.format("Unable create model layer for entity model file %s.", id)); + return; + } + + String path = matcher.group(1); + String name = matcher.group(2); + + Identifier modelID = new Identifier(id.getNamespace(), path); + this.modelData.put(new EntityModelLayer(modelID, name), result.result().get().getFirst()); + } + + public Map getModelData() { + return this.modelData; + } + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/impl/LazyTypeUnboundedMapCodec.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/impl/LazyTypeUnboundedMapCodec.java new file mode 100644 index 0000000000..1eda52c49e --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/impl/LazyTypeUnboundedMapCodec.java @@ -0,0 +1,76 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.impl; + +import java.util.Map; +import java.util.function.Supplier; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.Lifecycle; +import com.mojang.serialization.codecs.BaseMapCodec; + +public class LazyTypeUnboundedMapCodec implements BaseMapCodec, Codec> { + private final Codec keyCodec; + private final Supplier> elementCodecProvider; + + private Codec elementCodec; + + public LazyTypeUnboundedMapCodec(Codec keyCodec, Supplier> elementCodecProvider) { + this.keyCodec = keyCodec; + this.elementCodecProvider = elementCodecProvider; + } + + public static LazyTypeUnboundedMapCodec of(Codec keyCodec, Supplier> elementCodecProvider) { + return new LazyTypeUnboundedMapCodec<>(keyCodec, elementCodecProvider); + } + + @Override + public DataResult, T>> decode(DynamicOps ops, T input) { + return ops.getMap(input).setLifecycle(Lifecycle.stable()).flatMap(map -> this.decode(ops, map)).map(r -> Pair.of(r, input)); + } + + @Override + public DataResult encode(Map input, DynamicOps ops, T prefix) { + return this.encode(input, ops, ops.mapBuilder()).build(prefix); + } + + @Override + public Codec keyCodec() { + return this.keyCodec; + } + + @Override + public Codec elementCodec() { + if (this.elementCodec == null) { + this.elementCodec = this.elementCodecProvider.get(); + } + + return this.elementCodec; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/AnimationMixin.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/AnimationMixin.java new file mode 100644 index 0000000000..ffd5ade4bf --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/AnimationMixin.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.client.render.animation.Animation; + +import org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationType; +import org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationTypes; +import org.quiltmc.qsl.rendering.entity_models.api.animation.TypedAnimation; + +@Mixin(Animation.class) +public class AnimationMixin implements TypedAnimation { + @Unique + private AnimationType quilt$animationType = AnimationTypes.QUILT_ANIMATION; + + @Override + public AnimationType getType() { + return this.quilt$animationType; + } + + @Override + public void setType(AnimationType type) { + this.quilt$animationType = type; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/DilationAccessor.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/DilationAccessor.java new file mode 100644 index 0000000000..0b32098d99 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/DilationAccessor.java @@ -0,0 +1,43 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.model.Dilation; + +@Mixin(Dilation.class) +public interface DilationAccessor { + @Accessor("radiusX") + float radiusX(); + + @Accessor("radiusY") + float radiusY(); + + @Accessor("radiusZ") + float radiusZ(); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityModelLoaderMixin.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityModelLoaderMixin.java new file mode 100644 index 0000000000..a4fff2a375 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityModelLoaderMixin.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.model.TexturedModelData; +import net.minecraft.client.render.entity.model.EntityModelLayer; +import net.minecraft.client.render.entity.model.EntityModelLoader; +import net.minecraft.resource.ResourceType; + +import org.quiltmc.qsl.rendering.entity_models.impl.DynamicEntityModelLoader; +import org.quiltmc.qsl.resource.loader.api.ResourceLoader; +import org.quiltmc.qsl.resource.loader.api.reloader.ResourceReloaderKeys; + +@Mixin(EntityModelLoader.class) +public class EntityModelLoaderMixin { + @Unique + private DynamicEntityModelLoader quilt$dynamicEntityModelLoader; + + @Inject(method = "", at = @At("TAIL")) + private void createAnimationManager(CallbackInfo ci) { + this.quilt$dynamicEntityModelLoader = new DynamicEntityModelLoader(); + ResourceLoader resourceLoader = ResourceLoader.get(ResourceType.CLIENT_RESOURCES); + resourceLoader.registerReloader(this.quilt$dynamicEntityModelLoader); + resourceLoader.addReloaderOrdering(this.quilt$dynamicEntityModelLoader.getQuiltId(), ResourceReloaderKeys.Client.ENTITY_MODELS); + } + + @Inject(method = "getModelPart", at = @At("HEAD"), cancellable = true) + public void returnDynamicModel(EntityModelLayer layer, CallbackInfoReturnable cir) { + TexturedModelData modelData = this.quilt$dynamicEntityModelLoader.getModelData(layer); + if (modelData != null) { + cir.setReturnValue(modelData.createModel()); + } + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityRenderDispatcherMixin.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityRenderDispatcherMixin.java new file mode 100644 index 0000000000..e0c6fdac5d --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityRenderDispatcherMixin.java @@ -0,0 +1,56 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.option.GameOptions; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.model.EntityModelLoader; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.texture.TextureManager; +import net.minecraft.resource.ResourceType; + +import org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationManager; +import org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationManagerContainer; +import org.quiltmc.qsl.resource.loader.api.ResourceLoader; + +@Mixin(EntityRenderDispatcher.class) +public class EntityRenderDispatcherMixin implements AnimationManagerContainer { + @Unique + private AnimationManager quilt$animationManager; + + @Inject(method = "", at = @At("TAIL")) + private void createAnimationManager(MinecraftClient minecraftClient, TextureManager textureManager, ItemRenderer itemRenderer, BlockRenderManager blockRenderManager, TextRenderer textRenderer, GameOptions gameOptions, EntityModelLoader entityModelLoader, CallbackInfo ci) { + this.quilt$animationManager = new AnimationManager(); + ResourceLoader.get(ResourceType.CLIENT_RESOURCES).registerReloader(this.quilt$animationManager); + } + + @Override + @NotNull + public AnimationManager getAnimationManager() { + return this.quilt$animationManager; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityRendererFactoryContextMixin.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityRendererFactoryContextMixin.java new file mode 100644 index 0000000000..61208d8c24 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/EntityRendererFactoryContextMixin.java @@ -0,0 +1,53 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.render.entity.EntityRendererFactory; +import net.minecraft.client.render.entity.model.EntityModelLoader; +import net.minecraft.client.render.item.HeldItemRenderer; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.resource.ResourceManager; + +import org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationManager; +import org.quiltmc.qsl.rendering.entity_models.api.animation.AnimationManagerContainer; + +@Mixin(EntityRendererFactory.Context.class) +public class EntityRendererFactoryContextMixin implements AnimationManagerContainer { + @Unique + private AnimationManager quilt$animationManager; + + @Inject(method = "", at = @At("TAIL")) + private void createAnimationManager(EntityRenderDispatcher entityRenderDispatcher, ItemRenderer itemRenderer, BlockRenderManager blockRenderManager, HeldItemRenderer heldItemRenderer, ResourceManager resourceManager, EntityModelLoader entityModelLoader, TextRenderer textRenderer, CallbackInfo ci) { + this.quilt$animationManager = ((AnimationManagerContainer) entityRenderDispatcher).getAnimationManager(); + } + + @NotNull + @Override + public AnimationManager getAnimationManager() { + return this.quilt$animationManager; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/ModelCuboidDataAccessor.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/ModelCuboidDataAccessor.java new file mode 100644 index 0000000000..c62f07686e --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/ModelCuboidDataAccessor.java @@ -0,0 +1,71 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import java.util.Set; + +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3f; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.client.model.Dilation; +import net.minecraft.client.model.ModelCuboidData; +import net.minecraft.client.util.math.Vector2f; +import net.minecraft.util.math.Direction; + +@Mixin(ModelCuboidData.class) +public interface ModelCuboidDataAccessor { + @Accessor("name") + String name(); + + @Accessor("offset") + Vector3f offset(); + + @Accessor("dimensions") + Vector3f dimensions(); + + @Accessor("extraSize") + Dilation dilation(); + + @Accessor("mirror") + boolean mirror(); + + @Accessor("textureUV") + Vector2f uv(); + + @Accessor("textureScale") + Vector2f uvScale(); + + @Accessor("directions") + Set directions(); + + @Invoker("") + static ModelCuboidData create(@Nullable String string, float f, float g, float h, float i, float j, float k, float l, float m, Dilation dilation, boolean bl, float n, float o, Set directions) { + throw new AssertionError("Mixin injection failed."); + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/ModelPartDataAccessor.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/ModelPartDataAccessor.java new file mode 100644 index 0000000000..2ddee409ff --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/ModelPartDataAccessor.java @@ -0,0 +1,54 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import java.util.List; +import java.util.Map; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.client.model.ModelCuboidData; +import net.minecraft.client.model.ModelPartData; +import net.minecraft.client.model.ModelTransform; + +@Mixin(ModelPartData.class) +public interface ModelPartDataAccessor { + @Accessor("cuboidData") + List cuboids(); + + @Accessor("rotationData") + ModelTransform transform(); + + @Accessor("children") + Map children(); + + @Invoker("") + static ModelPartData create(List cuboids, ModelTransform rotation) { + throw new AssertionError("Mixin injection failed."); + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TextureDimensionsAccessor.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TextureDimensionsAccessor.java new file mode 100644 index 0000000000..fc276643ec --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TextureDimensionsAccessor.java @@ -0,0 +1,40 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.model.TextureDimensions; + +@Mixin(TextureDimensions.class) +public interface TextureDimensionsAccessor { + @Accessor("width") + int width(); + + @Accessor("height") + int height(); +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TexturedModelDataAccessor.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TexturedModelDataAccessor.java new file mode 100644 index 0000000000..8c6c2aa460 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TexturedModelDataAccessor.java @@ -0,0 +1,48 @@ +/* + * Copyright 2021 FoundationGames + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.client.model.ModelData; +import net.minecraft.client.model.TextureDimensions; +import net.minecraft.client.model.TexturedModelData; + +@Mixin(TexturedModelData.class) +public interface TexturedModelDataAccessor { + @Accessor("data") + ModelData root(); + + @Accessor("dimensions") + TextureDimensions texture(); + + @Invoker("") + static TexturedModelData create(ModelData data, TextureDimensions dimensions) { + throw new AssertionError("Mixin injection failed."); + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TexturedModelDataMixin.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TexturedModelDataMixin.java new file mode 100644 index 0000000000..da40398ac4 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/TexturedModelDataMixin.java @@ -0,0 +1,42 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +import net.minecraft.client.model.TexturedModelData; + +import org.quiltmc.qsl.rendering.entity_models.api.model.TypedModel; +import org.quiltmc.qsl.rendering.entity_models.api.model.ModelType; +import org.quiltmc.qsl.rendering.entity_models.api.model.ModelTypes; + +@Mixin(TexturedModelData.class) +public class TexturedModelDataMixin implements TypedModel { + @Unique + private ModelType quilt$modelType = ModelTypes.QUILT_MODEL; + + @Override + public ModelType getType() { + return this.quilt$modelType; + } + + @Override + public void setType(ModelType type) { + this.quilt$modelType = type; + } +} diff --git a/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/Vector2fMixin.java b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/Vector2fMixin.java new file mode 100644 index 0000000000..e9f688a4b9 --- /dev/null +++ b/library/rendering/entity_models/src/main/java/org/quiltmc/qsl/rendering/entity_models/mixin/Vector2fMixin.java @@ -0,0 +1,40 @@ +/* + * Copyright 2023 QuiltMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.quiltmc.qsl.rendering.entity_models.mixin; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.util.math.Vector2f; + +@Mixin(Vector2f.class) +public abstract class Vector2fMixin { + @Shadow + public abstract float getX(); + + @Shadow + public abstract float getY(); + + @Override + public boolean equals(Object o) { + if (o instanceof Vector2f vec) { + return this.getX() == vec.getX() && this.getY() == vec.getY(); + } + + return super.equals(o); + } +} diff --git a/library/rendering/entity_models/src/main/resources/assets/quilt_entity_models/icon.png b/library/rendering/entity_models/src/main/resources/assets/quilt_entity_models/icon.png new file mode 100644 index 0000000000..8d54ad0021 Binary files /dev/null and b/library/rendering/entity_models/src/main/resources/assets/quilt_entity_models/icon.png differ diff --git a/library/rendering/entity_models/src/main/resources/quilt_entity_models.mixins.json b/library/rendering/entity_models/src/main/resources/quilt_entity_models.mixins.json new file mode 100644 index 0000000000..046c264214 --- /dev/null +++ b/library/rendering/entity_models/src/main/resources/quilt_entity_models.mixins.json @@ -0,0 +1,21 @@ +{ + "required": true, + "package": "org.quiltmc.qsl.rendering.entity_models.mixin", + "compatibilityLevel": "JAVA_17", + "client": [ + "AnimationMixin", + "DilationAccessor", + "EntityModelLoaderMixin", + "EntityRenderDispatcherMixin", + "EntityRendererFactoryContextMixin", + "ModelCuboidDataAccessor", + "ModelPartDataAccessor", + "TextureDimensionsAccessor", + "TexturedModelDataAccessor", + "TexturedModelDataMixin", + "Vector2fMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/library/rendering/entity_models/src/testmod/resources/assets/minecraft/models/entity/elytra/main.json b/library/rendering/entity_models/src/testmod/resources/assets/minecraft/models/entity/elytra/main.json new file mode 100644 index 0000000000..0567c9303a --- /dev/null +++ b/library/rendering/entity_models/src/testmod/resources/assets/minecraft/models/entity/elytra/main.json @@ -0,0 +1,54 @@ +{ + "type": "quilt:model", + "texture": { + "width": 64, + "height": 32 + }, + "bones": { + "right_wing": { + "transform": { + "origin": [-5.0, 0.0, 0.0], + "rotation": [0.2617994, 0.0, 0.2617994] + }, + "cuboids": [ + { + "dilation": [1.0, 1.0, 1.0], + "mirror": true, + "uv": [22.0, 0.0], + "offset": [0.0, 0.0, 0.0], + "dimensions": [10.0, 20.0, 2.0] + } + ] + }, + "left_wing": { + "transform": { + "origin": [5.0, 0.0, 0.0], + "rotation": [0.2617994, 0.0, -0.2617994] + }, + "cuboids": [ + { + "dilation": [1.0, 1.0, 1.0], + "uv": [22.0, 0.0], + "offset": [-10.0, 0.0, 0.0], + "dimensions": [10.0, 20.0, 2.0] + } + ], + "children" : { + "extra_cube" : { + "transform": { + "origin": [6.0, 1.0, 1.0], + "rotation": [0.2617994, 0.0, -0.2617994] + }, + "cuboids" : [ + { + "dilation": [1.0, 1.0, 1.0], + "uv": [22.0, 0.0], + "offset": [-10.0, 0.0, 0.0], + "dimensions": [10.0, 20.0, 2.0] + } + ] + } + } + } + } +} diff --git a/library/rendering/entity_models/src/testmod/resources/quilt.mod.json b/library/rendering/entity_models/src/testmod/resources/quilt.mod.json new file mode 100644 index 0000000000..29bcd23f69 --- /dev/null +++ b/library/rendering/entity_models/src/testmod/resources/quilt.mod.json @@ -0,0 +1,18 @@ +{ + "schema_version": 1, + "quilt_loader": { + "group": "org.quiltmc.qsl.rendering", + "id": "quilt_entity_models_testmod", + "version": "1.0.0", + "metadata": { + "name": "Quilt Entity Models Test Mod", + "license": "Apache-2.0" + }, + "intermediate_mappings": "net.fabricmc:intermediary", + "load_type": "always", + "depends": [ + "quilt_loader", + "quilt_entity_models" + ] + } +} diff --git a/settings.gradle b/settings.gradle index 766607e392..ed7ae61fe0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -34,6 +34,7 @@ library("rendering") library("gui") library("item") library("management") +library("rendering") library("worldgen") library("misc")