Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-add model override functionality #228

Open
wants to merge 6 commits into
base: 1.18/dev
Choose a base branch
from
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
21 changes: 20 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ buildscript {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
}
maven { url = 'https://repo.spongepowered.org/maven' }
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+'
classpath 'org.parchmentmc:librarian:1.+'
classpath 'org.ajoberstar:gradle-git:0.10.1'
classpath "org.spongepowered:mixingradle:0.7-SNAPSHOT"
}
}
plugins {
Expand All @@ -24,6 +26,7 @@ plugins {
apply plugin: 'eclipse'
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'org.parchmentmc.librarian.forgegradle'
apply plugin: 'org.spongepowered.mixin'
apply plugin: 'maven-publish'

import org.ajoberstar.grgit.Grgit
Expand Down Expand Up @@ -55,6 +58,7 @@ minecraft {

// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
arg '-mixin.config=ctm.mixins.json'

mods {
ctm {
Expand All @@ -70,6 +74,7 @@ minecraft {

// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
arg '-mixin.config=ctm.mixins.json'

mods {
ctm {
Expand All @@ -92,16 +97,26 @@ jar {
"Implementation-Title": project.name,
"Implementation-Version": "${version}",
"Implementation-Vendor" :"chisel-team",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")],)
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
"MixinConfigs": "ctm.mixins.json"],)
}
}

repositories {
mavenLocal()
maven {
name = 'sponge'
url = 'https://repo.spongepowered.org/repository/maven-public/'
content {
includeGroup "org.spongepowered"
}
}
}

dependencies {
minecraft 'net.minecraftforge:forge:' + minecraft_version + '-' + forge_version

annotationProcessor 'org.spongepowered:mixin:0.8.5-SNAPSHOT:processor'
}

lombok {
Expand All @@ -116,6 +131,10 @@ task apiJar(type: Jar) {
classifier = 'api'
}

mixin {
add sourceSets.main, "ctm.refmap.json"
}

publishing {
tasks.publish.dependsOn 'build'
publications {
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod_version=1.1.5
mod_version=1.1.6
minecraft_version=1.18.2
forge_version=40.0.36

Expand Down
2 changes: 2 additions & 0 deletions src/main/java/team/chisel/ctm/api/texture/ICTMTexture.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public interface ICTMTexture<T extends ITextureType> {
List<BakedQuad> transformQuad(BakedQuad quad, @Nullable ITextureContext context, int quadGoal);

Collection<ResourceLocation> getTextures();

public void addSprite(TextureAtlasSprite sprite);

/**
* Gets the block render type of this texture
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/team/chisel/ctm/client/BlockModelExtension.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package team.chisel.ctm.client;

import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import team.chisel.ctm.client.texture.IMetadataSectionCTM;

public interface BlockModelExtension {
Int2ObjectMap<IMetadataSectionCTM> getMetaOverrides();

void setMetaOverrides(Int2ObjectMap<IMetadataSectionCTM> overrides);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package team.chisel.ctm.client.mixin;

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.renderer.block.model.BlockModel;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import team.chisel.ctm.client.BlockModelExtension;
import team.chisel.ctm.client.texture.IMetadataSectionCTM;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;

@Mixin(BlockModel.Deserializer.class)
public abstract class BlockModelDeserializerMixin implements JsonDeserializer<BlockModel> {

private static final Gson GSON = new Gson();

@Inject(at = @At("TAIL"), method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/renderer/block/model/BlockModel;")
private void addCTMData(JsonElement pJson, Type pType, JsonDeserializationContext pContext, CallbackInfoReturnable<BlockModel> cir) {
Map<String, JsonElement> parsed = GSON.fromJson(pJson.getAsJsonObject().getAsJsonObject("ctm_overrides"), new TypeToken<Map<String, JsonElement>>(){}.getType());
if (parsed == null) {
parsed = Collections.emptyMap();
}
Int2ObjectMap<IMetadataSectionCTM> overrides = new Int2ObjectArrayMap<>(parsed.size());
for (Map.Entry<String, JsonElement> e : parsed.entrySet()) {
try {
int index = Integer.parseInt(e.getKey());
if (!e.getValue().getAsJsonObject().has("ctm_version")) {
// This model can only be version 1, TODO improve this
e.getValue().getAsJsonObject().add("ctm_version", new JsonPrimitive(1));
}
overrides.put(index, new IMetadataSectionCTM.Serializer().fromJson(e.getValue().getAsJsonObject()));
} catch (NumberFormatException ex) {}
}

((BlockModelExtension) cir.getReturnValue()).setMetaOverrides(overrides);

}

}
88 changes: 88 additions & 0 deletions src/main/java/team/chisel/ctm/client/mixin/BlockModelMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package team.chisel.ctm.client.mixin;

import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.renderer.block.model.BlockModel;
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.*;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import team.chisel.ctm.client.BlockModelExtension;
import team.chisel.ctm.client.model.ModelBakedCTM;
import team.chisel.ctm.client.model.ModelCTM;
import team.chisel.ctm.client.texture.IMetadataSectionCTM;

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

@Mixin(BlockModel.class)
public abstract class BlockModelMixin implements UnbakedModel, BlockModelExtension {

@Shadow public abstract BakedModel bake(ModelBakery pBakery, BlockModel pModel, Function<Material, TextureAtlasSprite> pSpriteGetter, ModelState pTransform, ResourceLocation pLocation, boolean pGuiLight3d);

@Shadow public abstract Material getMaterial(String pName);

@Shadow public abstract String toString();

@Unique
protected Int2ObjectMap<IMetadataSectionCTM> metaOverrides = new Int2ObjectArrayMap<>();

@Inject(at = @At("TAIL"), method = "bake(Lnet/minecraft/client/resources/model/ModelBakery;Lnet/minecraft/client/renderer/block/model/BlockModel;Ljava/util/function/Function;Lnet/minecraft/client/resources/model/ModelState;Lnet/minecraft/resources/ResourceLocation;Z)Lnet/minecraft/client/resources/model/BakedModel;",
cancellable = true)
private void ctm$bake(ModelBakery pBakery, BlockModel pModel, Function<Material, TextureAtlasSprite> pSpriteGetter, ModelState pTransform, ResourceLocation pLocation, boolean pGuiLight3d, CallbackInfoReturnable<BakedModel> cir) {
if (pModel instanceof BlockModelExtension extension && !extension.getMetaOverrides().isEmpty()) {
ModelCTM model = new ModelCTM(pModel);
model.initializeTextures(pBakery, pSpriteGetter);
ModelBakedCTM bakedCTM = new ModelBakedCTM(model, cir.getReturnValue());
cir.setReturnValue(bakedCTM);
}
}

@Inject(at = @At("RETURN"), method = "getMaterials")
private void ctm$materials(Function<ResourceLocation, UnbakedModel> pModelGetter, Set<Pair<String, String>> pMissingTextureErrors, CallbackInfoReturnable<Collection<Material>> cir) {
for (IMetadataSectionCTM meta : getMetaOverrides().values()) {
for (String s : meta.getAdditionalTextures()) {
Material material = this.getMaterial(s);

if (Objects.equals(material.texture(), MissingTextureAtlasSprite.getLocation())) {
pMissingTextureErrors.add(Pair.of(s, this.toString()));
}

cir.getReturnValue().add(material);
}
}
}

private Int2ObjectMap<IMetadataSectionCTM> ctm$merge(Int2ObjectMap<IMetadataSectionCTM> other) {
Int2ObjectMap<IMetadataSectionCTM> copy = new Int2ObjectArrayMap<>(this.metaOverrides).clone();
for (int i: other.keySet()) {
if (!metaOverrides.containsKey(i)) {
copy.put(i, other.get(i));
} else {
copy.get(i).merge(other.get(i));
}
}
return copy;
}

public Int2ObjectMap<IMetadataSectionCTM> getMetaOverrides() {
if (((BlockModel) (Object) this).parent != null ) {
return ctm$merge(((BlockModelMixin) (Object) ((BlockModel) (Object) this).parent).getMetaOverrides());
}
return metaOverrides;
}

@Override
public void setMetaOverrides(Int2ObjectMap<IMetadataSectionCTM> overrides) {
this.metaOverrides = overrides;
}
}
40 changes: 27 additions & 13 deletions src/main/java/team/chisel/ctm/client/model/ModelCTM.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
Expand All @@ -31,6 +30,7 @@
import team.chisel.ctm.api.model.IModelCTM;
import team.chisel.ctm.api.texture.ICTMTexture;
import team.chisel.ctm.api.util.TextureInfo;
import team.chisel.ctm.client.BlockModelExtension;
import team.chisel.ctm.client.texture.IMetadataSectionCTM;
import team.chisel.ctm.client.texture.render.TextureNormal;
import team.chisel.ctm.client.texture.type.TextureTypeNormal;
Expand All @@ -45,23 +45,33 @@ public class ModelCTM implements IModelCTM {

// Populated from overrides data during construction
private final Int2ObjectMap<JsonElement> overrides;
protected final Int2ObjectMap<IMetadataSectionCTM> metaOverrides = new Int2ObjectArrayMap<>();
protected Int2ObjectMap<IMetadataSectionCTM> metaOverrides = new Int2ObjectArrayMap<>();

// Populated during bake with real texture data
protected Int2ObjectMap<TextureAtlasSprite> spriteOverrides;
protected Map<Pair<Integer, ResourceLocation>, ICTMTexture<?>> textureOverrides;

private final Collection<ResourceLocation> textureDependencies;
private final Collection<String> textureDependencies;

private transient byte layers;

private Map<ResourceLocation, ICTMTexture<?>> textures = new HashMap<>();

public ModelCTM(UnbakedModel modelinfo) {
this.vanillamodel = modelinfo;
this.modelinfo = null;
this.overrides = new Int2ObjectOpenHashMap<>();
this.textureDependencies = new HashSet<>();
BlockModel temp = null;

if (modelinfo instanceof BlockModel blockmodel && blockmodel instanceof BlockModelExtension extension) {
temp = blockmodel;
metaOverrides = extension.getMetaOverrides();
for (IMetadataSectionCTM meta: metaOverrides.values()) {
textureDependencies.addAll(Arrays.asList(meta.getAdditionalTextures()));
}
this.textureDependencies.removeIf(rl -> rl.contains("#"));
}
this.modelinfo = temp;
}

public ModelCTM(BlockModel modelinfo, Int2ObjectMap<JsonElement> overrides) throws IOException {
Expand All @@ -71,10 +81,10 @@ public ModelCTM(BlockModel modelinfo, Int2ObjectMap<JsonElement> overrides) thro
this.textureDependencies = new HashSet<>();
for (Int2ObjectMap.Entry<JsonElement> e : this.overrides.int2ObjectEntrySet()) {
IMetadataSectionCTM meta = null;
if (e.getValue().isJsonPrimitive() && e.getValue().getAsJsonPrimitive().isString()) {
if (e.getValue().isJsonPrimitive() && e.getValue().getAsJsonPrimitive().isString()) { //TODO is this still a thing?
ResourceLocation rl = new ResourceLocation(e.getValue().getAsString());
meta = ResourceUtil.getMetadata(ResourceUtil.spriteToAbsolute(rl));
textureDependencies.add(rl);
textureDependencies.add(rl.toString());
} else if (e.getValue().isJsonObject()) {
JsonObject obj = e.getValue().getAsJsonObject();
if (!obj.has("ctm_version")) {
Expand All @@ -89,15 +99,15 @@ public ModelCTM(BlockModel modelinfo, Int2ObjectMap<JsonElement> overrides) thro
}
}

this.textureDependencies.removeIf(rl -> rl.getPath().startsWith("#"));
this.textureDependencies.removeIf(rl -> rl.contains("#"));
}

@Override
public Collection<Material> getTextures(IModelConfiguration owner, Function<ResourceLocation, UnbakedModel> modelGetter, Set<Pair<String, String>> missingTextureErrors) {
List<Material> ret = textureDependencies.stream()
.map(rl -> new Material(TextureAtlas.LOCATION_BLOCKS, rl))
.map(rl -> new Material(TextureAtlas.LOCATION_BLOCKS, new ResourceLocation(rl)))
.collect(Collectors.toList());
ret.addAll(vanillamodel.getMaterials(modelGetter, missingTextureErrors));
ret.addAll(vanillamodel.getMaterials(modelGetter, missingTextureErrors));
// Validate all texture metadata
for (Material tex : ret) {
IMetadataSectionCTM meta;
Expand All @@ -117,7 +127,7 @@ public Collection<Material> getTextures(IModelConfiguration owner, Function<Reso

@Override
public BakedModel bake(IModelConfiguration owner, ModelBakery bakery, Function<Material, TextureAtlasSprite> spriteGetter, ModelState modelTransform, ItemOverrides itemOverrides, ResourceLocation modelLocation) {
return bake(bakery, spriteGetter, modelTransform, modelLocation);
return bake(bakery, spriteGetter, modelTransform, modelLocation);
}

private static final ItemModelGenerator ITEM_MODEL_GENERATOR = new ItemModelGenerator();
Expand Down Expand Up @@ -152,7 +162,7 @@ public void initializeTextures(ModelBakery bakery, Function<Material, TextureAtl
return tex;
});
}
if (spriteOverrides == null) {
if (spriteOverrides == null) { //TODO is this a thing?
spriteOverrides = new Int2ObjectArrayMap<>();
// Convert all primitive values into sprites
for (Int2ObjectMap.Entry<JsonElement> e : overrides.int2ObjectEntrySet()) {
Expand All @@ -168,15 +178,19 @@ public void initializeTextures(ModelBakery bakery, Function<Material, TextureAtl
List<BlockElementFace> matches = modelinfo.getElements().stream().flatMap(b -> b.faces.values().stream()).filter(b -> b.tintIndex == e.getIntKey()).toList();
Multimap<Material, BlockElementFace> bySprite = HashMultimap.create();
// TODO 1.15 this isn't right
matches.forEach(part -> bySprite.put(modelinfo.textureMap.getOrDefault(part.texture.substring(1), Either.right(part.texture)).left().get(), part));
matches.forEach(part -> bySprite.put(modelinfo.getMaterial(part.texture), part));
for (var e2 : bySprite.asMap().entrySet()) {
ResourceLocation texLoc = e2.getKey().sprite().getName();
ResourceLocation texLoc = e2.getKey().texture();
TextureAtlasSprite sprite = getOverrideSprite(e.getIntKey());
if (sprite == null) {
sprite = spriteGetter.apply(new Material(TextureAtlas.LOCATION_BLOCKS, texLoc));
}
ICTMTexture<?> tex = e.getValue().makeTexture(sprite, spriteGetter);
layers |= 1 << (tex.getLayer() == null ? 7 : tex.getLayer().ordinal());
for (String s: e.getValue().getAdditionalTextures()) {
TextureAtlasSprite atlasSprite = spriteGetter.apply(modelinfo.getMaterial(s));
tex.addSprite(atlasSprite);
}
textureOverrides.put(Pair.of(e.getIntKey(), texLoc), tex);
}
}
Expand Down
Loading