Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Commit

Permalink
Functional (albeit messy) proof of concept
Browse files Browse the repository at this point in the history
  • Loading branch information
cocona20xx committed Oct 9, 2022
1 parent 09666bf commit 8a1cc78
Show file tree
Hide file tree
Showing 14 changed files with 256 additions and 147 deletions.
1 change: 0 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@ quilted_fabric_api_version = 4.0.0-beta.13+0.62.0
version = 0.1.0+1.19.2
maven_group = io.github.cocona20xx
archives_base_name = retribution

12 changes: 9 additions & 3 deletions src/main/java/cocona20xx/retribution/RetributionModClient.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package cocona20xx.retribution;

import cocona20xx.retribution.impl.EmissiveDataReloader;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.resource.ResourceType;
import org.quiltmc.loader.api.ModContainer;
import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer;
import org.quiltmc.qsl.resource.loader.api.ResourceLoader;
import org.quiltmc.qsl.resource.loader.api.reloader.ResourceReloaderKeys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RetributionModClient implements ClientModInitializer {
public static final String MOD_ID = "retribution";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);

public static final int MODIFIER = 0;
@Override
public void onInitializeClient(ModContainer mod) {
LOGGER.info("It's retributing time!!!");
LOGGER.info("Retribution is loading...");
ResourceLoader.get(ResourceType.CLIENT_RESOURCES).registerReloader(new EmissiveDataReloader());
ResourceLoader.get(ResourceType.CLIENT_RESOURCES).addReloaderOrdering(EmissiveDataReloader.RELOADER_ID, ResourceReloaderKeys.BEFORE_VANILLA);
}
}
114 changes: 114 additions & 0 deletions src/main/java/cocona20xx/retribution/impl/EmissiveDataReloader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package cocona20xx.retribution.impl;

import cocona20xx.retribution.RetributionModClient;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.quiltmc.qsl.resource.loader.api.reloader.SimpleSynchronousResourceReloader;

import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Objects;
import java.util.regex.Pattern;

public class EmissiveDataReloader implements SimpleSynchronousResourceReloader {
private static final Object2ObjectMap<String, ParsedItemFlagData> EMISSIVE_MAP = new Object2ObjectArrayMap<>();
private static final Gson GSON = new Gson();
private static final String[] PARENT_BLACKLIST = {"template_banner", "template_bed", "template_shulker_box", "template_skull", "template_spawn_egg", "trident_in_hand", "spyglass_in_hand", "block"};
private static final ArrayList<String> BLACKLIST_LIST = Lists.newArrayList(PARENT_BLACKLIST);
public static final Identifier RELOADER_ID = new Identifier("retribution", "emissive");
private static final String[] flags = {"layer0", "layer1", "layer2", "layer3", "layer4"};

@Override
public void reload(ResourceManager manager) {
RetributionModClient.LOGGER.info("Starting Emissive Load...");
EMISSIVE_MAP.clear();
for(Identifier id : manager.findResources("models/item", path -> path.toString().endsWith(".json")).keySet()){
try {
for(Resource r : manager.getAllResources(id)){
try (BufferedReader reader = r.openBufferedReader()){
JsonObject mainObject = GSON.fromJson(reader, JsonObject.class);
if(mainObject.has("emissive_flags")){
if(!BLACKLIST_LIST.contains(mainObject.get("parent").getAsString())){
JsonObject flagObject = mainObject.getAsJsonObject("emissive_flags");
JsonObject textureObject = mainObject.getAsJsonObject("textures");
for (int i = 0; i < 4; i++) {
if (flagObject.has(flags[i])) {
JsonPrimitive flagPrim = flagObject.getAsJsonPrimitive(flags[i]);
if (flagPrim.isBoolean()) {
if (flagPrim.getAsBoolean()) {
if (!textureObject.has(flags[i])) {
throw new JsonParseException("Flag set for layer but layer is not present");
} else {
String texSimple = simplifyFromIdString(textureObject.get(flags[i]).getAsString());
ParsedItemFlagData data = new ParsedItemFlagData();
data.setFlag(i, texSimple);
EMISSIVE_MAP.put(texSimple, data);
}
}
} else throw new JsonParseException("Flag set to non-boolean value");
}
}
}
}
} catch (Exception e){
RetributionModClient.LOGGER.warn("Error occurred when trying to parse emissive data: " + e);
}
}
} catch (Exception e){
RetributionModClient.LOGGER.warn("IO Error when trying to parse emissive data: " + e);
}
}
}

@Override
public @NotNull Identifier getQuiltId() {
return RELOADER_ID;
}

private static void add(String simplifiedId, ParsedItemFlagData data){
if(EMISSIVE_MAP.containsKey(simplifiedId)) RetributionModClient.LOGGER.warn("Emissive map key overlap detected: "+ simplifiedId);
EMISSIVE_MAP.put(simplifiedId, data);
}
public static ParsedItemFlagData getData(String simplifiedId){
return EMISSIVE_MAP.get(simplifiedId);
}
public static boolean hasDataForSimple(String simplifiedId){
return EMISSIVE_MAP.containsKey(simplifiedId);
}
public static String simplifyFromId(Identifier id){
String buildSimple = "";
buildSimple = buildSimple.concat(id.getNamespace()).concat("#");
String[] slashSeparatedPath = id.getPath().split(Pattern.quote("/"));
int s = slashSeparatedPath.length - 1;
return buildSimple.concat(slashSeparatedPath[s]);
}
private static String simplifyFromIdString(String idAsString){
if(idAsString.contains(":")) {
//string contains a namespace, we can parse it like an Identifier object
String buildSimple = idAsString.split(Pattern.quote(":"))[0].concat("#");
String[] slashSeparatedPath = idAsString.split(Pattern.quote(":"))[1].split("/");
int s = slashSeparatedPath.length - 1;
return buildSimple.concat(slashSeparatedPath[s]);
} else {
//no namespace means implicit minecraft namespace
String buildSimple = idAsString.replaceFirst(Pattern.quote("item/"),"");
buildSimple = "minecraft#" + buildSimple;
return buildSimple;
}
}
public static int flagStringToInt(String flag){
for(int i = 0; i < 4; i++){
if(Objects.equals(flag, flags[i])) return i;
}
return -1;
}
}

This file was deleted.

26 changes: 13 additions & 13 deletions src/main/java/cocona20xx/retribution/impl/ParsedItemFlagData.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,6 @@ public class ParsedItemFlagData {
private String layer3 = null;
private String layer4 = null;

public boolean hasFlag(int id){
return switch (id){
case 0 -> !Objects.isNull(layer0);
case 1 -> !Objects.isNull(layer1);
case 2 -> !Objects.isNull(layer2);
case 3 -> !Objects.isNull(layer3);
case 4 -> !Objects.isNull(layer4);
default -> false;
};
}
public boolean hasAny(){
return hasFlag(0) || hasFlag(1) || hasFlag(2) || hasFlag(3) ||hasFlag(4);
}
public void setFlag(int id, String val){
switch (id){
case 0 -> layer0 = val;
Expand All @@ -42,4 +29,17 @@ public String getId(int id){
default -> null;
};
}
public boolean hasAny(){
return Objects.nonNull(layer0) || Objects.nonNull(layer1) || Objects.nonNull(layer2) || Objects.nonNull(layer3) || Objects.nonNull(layer4);
}
public boolean hasId(int id){
return switch (id){
case 0 -> Objects.nonNull(layer0);
case 1 -> Objects.nonNull(layer1);
case 2 -> Objects.nonNull(layer2);
case 3 -> Objects.nonNull(layer3);
case 4 -> Objects.nonNull(layer4);
default -> false;
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package cocona20xx.retribution.internal;

import net.minecraft.client.render.model.json.ModelElement;

public interface ModelElementEmissiveAccessor {
boolean isEmissive();
void setEmissive(boolean set);

ModelElement getActual();

void storeActual(ModelElement actual);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public interface UnbakedModelAccessor {
void setData(ParsedItemFlagData data);
void storeActual(JsonUnbakedModel model);
JsonUnbakedModel getActual();

ParsedItemFlagData getData();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package cocona20xx.retribution.mixins;

import cocona20xx.retribution.RetributionModClient;
import cocona20xx.retribution.impl.EmissiveDataReloader;
import cocona20xx.retribution.impl.ParsedItemFlagData;
import cocona20xx.retribution.internal.ModelElementEmissiveAccessor;
import com.mojang.datafixers.util.Either;
import net.minecraft.client.render.model.json.ItemModelGenerator;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.render.model.json.ModelElement;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;

import java.util.List;
import java.util.Map;
import java.util.function.Function;

@Mixin(ItemModelGenerator.class)
public class ItemModelGeneratorMixin {
@Inject(method = "create", at = @At(value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/client/render/model/json/ItemModelGenerator;addLayerElements(ILjava/lang/String;Lnet/minecraft/client/texture/Sprite;)Ljava/util/List;", shift = At.Shift.BY, by = 1),
locals = LocalCapture.CAPTURE_FAILHARD)
public void createInjector(Function<SpriteIdentifier, Sprite> textureGetter, JsonUnbakedModel blockModel, CallbackInfoReturnable<JsonUnbakedModel> cir, Map<String, Either<SpriteIdentifier, String>> map, List<ModelElement> list, int i, String string, SpriteIdentifier spriteIdentifier, Sprite sprite){
int size = list.size();
Identifier id = spriteIdentifier.getTextureId();
String simple = EmissiveDataReloader.simplifyFromId(id);
if(EmissiveDataReloader.hasDataForSimple(simple)){
RetributionModClient.LOGGER.info(simple);
int flagInt = EmissiveDataReloader.flagStringToInt(string);
ParsedItemFlagData data = EmissiveDataReloader.getData(simple);
if(data.hasId(flagInt)){
for (int j = 0; j < size; j++) {
ModelElement current = list.get(j);
ModelElementEmissiveAccessor elementAccessor = (ModelElementEmissiveAccessor)current;
elementAccessor.setEmissive(true);
elementAccessor.storeActual(current);
list.set(j, elementAccessor.getActual());
}
}
}
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cocona20xx.retribution.mixins;

import cocona20xx.retribution.RetributionModClient;
import cocona20xx.retribution.impl.EmissiveDataReloader;
import cocona20xx.retribution.internal.BakedQuadLightingModifierAccessor;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.item.ItemRenderer;
Expand All @@ -14,7 +16,9 @@ public class ItemRenderMixin {
@ModifyArg(method = "renderBakedItemQuads", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/VertexConsumer;bakedQuad(Lnet/minecraft/client/util/math/MatrixStack$Entry;Lnet/minecraft/client/render/model/BakedQuad;FFFII)V"), index = 5)
public int modifyLighting(MatrixStack.Entry matrixEntry, BakedQuad quad, float red, float green, float blue, int light, int overlay){
BakedQuadLightingModifierAccessor wrap = (BakedQuadLightingModifierAccessor)quad;
if(wrap.getModifier() != 0 && light < 240) {
String sanitySimpleId = EmissiveDataReloader.simplifyFromId(quad.getSprite().getId());
boolean sanity = EmissiveDataReloader.hasDataForSimple(sanitySimpleId);
if((wrap.getModifier() != 0 && light < 240) && sanity) {
int mod = light + wrap.getModifier();
return Math.min(mod, 240);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package cocona20xx.retribution.mixins;

import cocona20xx.retribution.RetributionModClient;
import cocona20xx.retribution.impl.ParsedItemFlagData;
import cocona20xx.retribution.internal.BakedQuadLightingModifierAccessor;
import cocona20xx.retribution.internal.ModelElementEmissiveAccessor;
import cocona20xx.retribution.internal.UnbakedModelAccessor;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.UnbakedModel;
import net.minecraft.client.render.model.*;
import net.minecraft.client.render.model.json.JsonUnbakedModel;
import net.minecraft.client.render.model.json.ModelElement;
import net.minecraft.client.render.model.json.ModelElementFace;
Expand All @@ -16,6 +16,7 @@
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.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import java.util.Objects;
Expand All @@ -25,17 +26,19 @@ public abstract class JsonUnbakedModelMixin implements UnbakedModel, UnbakedMode

@Unique private ParsedItemFlagData data = new ParsedItemFlagData();
@Unique private JsonUnbakedModel actual;
@Unique
private static final int EMISSIVE_MODIFIER = 150;

@Inject(method = "createQuad", at = @At("RETURN"), cancellable = true)
private static void bakeQuadInjector(ModelElement element, ModelElementFace elementFace, Sprite sprite, Direction side, ModelBakeSettings settings, Identifier id, CallbackInfoReturnable<BakedQuad> cir){
for (int i = 0; i < 4; i++) {
if(JsonUnbakedModelMixin.matchFaceWithDataValue(elementFace, i, this.data))
private static void createQuadInjector(ModelElement element, ModelElementFace elementFace, Sprite sprite, Direction side, ModelBakeSettings settings, Identifier id, CallbackInfoReturnable<BakedQuad> cir){
ModelElementEmissiveAccessor accessor = (ModelElementEmissiveAccessor)element;
if(accessor.isEmissive()) {
BakedQuad initialReturn = cir.getReturnValue();
BakedQuadLightingModifierAccessor wrapped = ((BakedQuadLightingModifierAccessor) initialReturn);
wrapped.storeActual(initialReturn);
wrapped.setModifier(EMISSIVE_MODIFIER);
cir.setReturnValue(wrapped.getActual());
}
BakedQuad initialReturn = cir.getReturnValue();
BakedQuadLightingModifierAccessor wrapped = ((BakedQuadLightingModifierAccessor)initialReturn);
wrapped.storeActual(initialReturn);
wrapped.setModifier(150);
cir.setReturnValue(wrapped.getActual());
}

@Override
Expand All @@ -53,11 +56,8 @@ public JsonUnbakedModel getActual() {
return actual;
}

private static boolean matchFaceWithDataValue(ModelElementFace face, int id, ParsedItemFlagData data){
String keyStr = data.getId(id);
if(Objects.isNull(keyStr)) return false;
else {
return Objects.equals(face.textureId, keyStr);
}
@Override
public ParsedItemFlagData getData() {
return this.data;
}
}
Loading

0 comments on commit 8a1cc78

Please sign in to comment.