Skip to content

Commit

Permalink
Rewrite color manager in Java
Browse files Browse the repository at this point in the history
The rewrite is more crash-proof and uses JSON instead of
JSON5.
  • Loading branch information
Juuxel committed Aug 2, 2024
1 parent 2d1811c commit 0f8d94b
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ private ColorManager.ColorPair getPalette() {

@Override
protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) {
var bg = getPalette().getBg();
var bg = getPalette().bg();
RenderSystem.setShaderColor(Colors.redOf(bg), Colors.greenOf(bg), Colors.blueOf(bg), 1.0f);
context.drawTexture(getBackgroundTexture(), x, y, 0, 0, backgroundWidth, backgroundHeight);
RenderSystem.setShaderColor(1f, 1f, 1f, 1f);
}

@Override
protected void drawForeground(DrawContext context, int mouseX, int mouseY) {
var fg = getPalette().getFg();
var fg = getPalette().fg();
context.drawText(textRenderer, title, titleX, titleY, fg, false);
context.drawText(textRenderer, playerInventoryTitle, playerInventoryTitleX, playerInventoryTitleY, fg, false);
}
Expand Down
119 changes: 119 additions & 0 deletions common/src/main/java/juuxel/adorn/client/resources/ColorManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package juuxel.adorn.client.resources;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import juuxel.adorn.AdornCommon;
import juuxel.adorn.util.Colors;
import juuxel.adorn.util.ColorsKt;
import juuxel.adorn.util.Logging;
import net.minecraft.resource.ResourceFinder;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.SinglePreparationResourceReloader;
import net.minecraft.util.Identifier;
import net.minecraft.util.dynamic.Codecs;
import net.minecraft.util.profiler.Profiler;
import org.slf4j.Logger;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HexFormat;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;

public class ColorManager extends SinglePreparationResourceReloader<Map<Identifier, List<JsonObject>>> {
private static final Logger LOGGER = Logging.logger();
private static final Identifier FALLBACK = AdornCommon.id("fallback");
private static final String PREFIX = "adorn/color_palettes";
private static final Pattern COLOR_REGEX = Pattern.compile("^#(?:[0-9A-Fa-f]{2})?[0-9A-Fa-f]{6}$");
private static final Codec<Map<Identifier, ColorPair>> PALETTE_CODEC = Codec.unboundedMap(Identifier.CODEC, ColorPair.CODEC);

private final Map<Identifier, ColorPalette> palettes = new HashMap<>();

@Override
protected Map<Identifier, List<JsonObject>> prepare(ResourceManager manager, Profiler profiler) {
var gson = new Gson();
var resourceFinder = ResourceFinder.json(PREFIX);
Map<Identifier, List<JsonObject>> result = new HashMap<>();

for (var entry : resourceFinder.findAllResources(manager).entrySet()) {
var id = resourceFinder.toResourceId(entry.getKey());
List<JsonObject> jsons = new ArrayList<>();
result.put(id, jsons);

for (var resource : entry.getValue()) {
try (var in = resource.getReader()) {
jsons.add(gson.fromJson(in, JsonObject.class));
} catch (IOException | JsonParseException e) {
LOGGER.error("[Adorn] Could not load color palette resource {} from {}", entry.getKey(), resource.getResourcePackName(), e);
}
}
}

return result;
}

@Override
protected void apply(Map<Identifier, List<JsonObject>> prepared, ResourceManager manager, Profiler profiler) {
palettes.clear();
prepared.forEach((id, jsons) -> {
var palette = new HashMap<Identifier, ColorPair>();

for (var json : jsons) {
var partialPalette = PALETTE_CODEC.parse(JsonOps.INSTANCE, json).get()
.map(Function.identity(), partial -> {
LOGGER.error("[Adorn] Could not parse color palette {}", id);
return null;
});
if (partialPalette == null) continue;
palette.putAll(partialPalette);
}

palettes.put(id, new ColorPalette(palette));
});
}

public ColorPalette getColors(Identifier id) {
var pair = palettes.get(id);
if (pair == null) {
pair = palettes.get(FALLBACK);
if (pair == null) {
throw new IllegalStateException("Could not find fallback palette!");
}
}
return pair;
}

private static DataResult<Integer> parseHexColor(String str) {
if (!COLOR_REGEX.matcher(str).matches()) {
return DataResult.error(() -> "Color must be a hex color beginning with '#' - found " + str);
}

var colorStr = str.substring(1);
return DataResult.success(switch (colorStr.length()) {
case 6 -> ColorsKt.color(Integer.parseInt(colorStr, 16));
case 8 -> Integer.parseInt(colorStr, 16);
default -> throw new MatchException("Mismatching color length: " + colorStr.length(), null);
});
}

public record ColorPair(int bg, int fg) {
private static final int DEFAULT_FG = Colors.SCREEN_TEXT;

public static final Codec<ColorPair> CODEC = Codecs.alternatively(
RecordCodecBuilder.create(instance -> instance.group(
Codec.INT.fieldOf("bg").forGetter(ColorPair::bg),
Codec.INT.optionalFieldOf("fg", DEFAULT_FG).forGetter(ColorPair::bg)
).apply(instance, ColorPair::new)),
Codec.STRING.comapFlatMap(ColorManager::parseHexColor, color -> HexFormat.of().withUpperCase().toHexDigits(color))
.xmap(bg -> new ColorPair(bg, DEFAULT_FG), ColorPair::bg)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package juuxel.adorn.client.resources;

import juuxel.adorn.AdornCommon;
import net.minecraft.util.Identifier;

import java.util.Map;

public final class ColorPalette {
private static final Identifier DEFAULT_COLOR_ID = AdornCommon.id("default");
private final Map<Identifier, ColorManager.ColorPair> map;

public ColorPalette(Map<Identifier, ColorManager.ColorPair> map) {
this.map = Map.copyOf(map);
}

public ColorManager.ColorPair get(Identifier key) {
var pair = map.get(key);
if (pair == null) {
pair = map.get(DEFAULT_COLOR_ID);
if (pair == null) throw new IllegalStateException("Couldn't read default value from palette map");
}
return pair;
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@

"adorn:traverse/fir_drawer": { "bg": "#8E5E3D" },

// The default color is the oak color
"adorn:default": "#BE9A60"
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,5 @@

"adorn:traverse/fir_kitchen_cupboard": { "bg": "#8E5E3D" },

// The default color is the oak color
"adorn:default": "#BE9A60"
}

0 comments on commit 0f8d94b

Please sign in to comment.