Skip to content
Merged
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
7 changes: 6 additions & 1 deletion src/main/java/com/ruling_0/materiallib/CommandMatInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
/// MaterialLib shape.
public class CommandMatInfo extends CommandBase {

/// The properties printed as AARRGGBB hex.
private static final Set<Property<?>> TINT_PROPERTIES = Set.of(StandardProperties.TINT,
StandardProperties.FLUID_TINT, StandardProperties.BLOCK_TINT, StandardProperties.BLOCK_OVERLAY_TINT,
StandardProperties.CELL_TINT);

@Override
public String getCommandName() { return "matinfo"; }

Expand Down Expand Up @@ -111,7 +116,7 @@ private static void report(ICommandSender sender, Shape shape, String variant, M

private static String formatValue(Material material, Property<?> property) {
Object value = material.getProperty(property);
if (property == StandardProperties.TINT) {
if (TINT_PROPERTIES.contains(property)) {
return String.format("0x%08X", value);
}
return String.valueOf(value);
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/ruling_0/materiallib/api/MaterialTints.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.ruling_0.materiallib.api;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.gtnewhorizon.gtnhlib.color.ColorResource;
import com.ruling_0.materiallib.MaterialLib;

/// Reads the standard ARGB tint properties through [ColorResource], so a resource pack retints one material with a
/// lang entry; see [StandardProperties] for the pack-facing key and value format.
///
/// One [ColorResource] per unified material and property is cached here for the life of the game. GTNHLib tracks its
/// instances weakly and refreshes only the reachable ones when resource packs reload. Angelica meshes chunks on
/// several threads at once (see [ShapeBlockRenderingHandler]), so the cache is concurrent. A dedicated server carries
/// no lang files, so every read there returns the value the material declares.
final class MaterialTints {

private static final Map<Property<Integer>, Map<Material, ColorResource>> RESOURCES = new ConcurrentHashMap<>();

private MaterialTints() {}

/// The ARGB tint `material` resolves for `property`, taken from a resource pack's lang entry where one exists.
/// The property must resolve non-null for the material.
static int color(Material material, Property<Integer> property) {
return resourceFor(material, property).getColor();
}

/// The [ColorResource] backing `property` for `material`, created on first read and shared by every declaration
/// unified onto the same material.
static ColorResource resourceFor(Material material, Property<Integer> property) {
Map<Material, ColorResource> byMaterial = RESOURCES.computeIfAbsent(property,
ignored -> new ConcurrentHashMap<>());
return byMaterial.computeIfAbsent(material.canonical(),
canonical -> new ColorResource(MaterialLib.MODID, canonical.getName() + "." + property.getName(),
String.format("0x%08X", canonical.getProperty(property)), true));
}
}
8 changes: 4 additions & 4 deletions src/main/java/com/ruling_0/materiallib/api/ShapeBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,10 @@ int tintFor(int meta) {
if (icons.isOverride(meta)) return 0xFFFFFF;
Material material = MaterialRegistry.instance().getMaterialByIndex(meta);
if (material == null) return 0xFFFFFF;
Integer override = material.getProperty(
baseTexture != null ? StandardProperties.BLOCK_OVERLAY_TINT : StandardProperties.BLOCK_TINT);
if (override != null) return override & 0xFFFFFF;
return material.getProperty(StandardProperties.TINT) & 0xFFFFFF;
Property<Integer> specific = baseTexture != null ? StandardProperties.BLOCK_OVERLAY_TINT :
StandardProperties.BLOCK_TINT;
Property<Integer> tint = material.getProperty(specific) != null ? specific : StandardProperties.TINT;
return MaterialTints.color(material, tint) & 0xFFFFFF;
}

@Override
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/ruling_0/materiallib/api/ShapeFluid.java
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ public int getColor() {
/// The ARGB fill tint for `material`'s fluid: [StandardProperties#FLUID_TINT] when set, or
/// [StandardProperties#TINT] otherwise.
static int tintOf(Material material) {
Integer fluidTint = material.getProperty(StandardProperties.FLUID_TINT);
return fluidTint != null ? fluidTint : material.getProperty(StandardProperties.TINT);
Property<Integer> tint = material.getProperty(StandardProperties.FLUID_TINT) != null ?
StandardProperties.FLUID_TINT : StandardProperties.TINT;
return MaterialTints.color(material, tint);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public int getColorFromItemStack(ItemStack stack, int renderPass) {
if (renderPass == 0) return 0xFFFFFFFF;
Material material = ShapeText.materialFor(stack);
if (material == null || hasOverrideIcon(material)) return 0xFFFFFFFF;
Integer cellTint = material.getProperty(StandardProperties.CELL_TINT);
return cellTint != null ? cellTint : ShapeFluid.tintOf(material);
if (material.getProperty(StandardProperties.CELL_TINT) == null) return ShapeFluid.tintOf(material);
return MaterialTints.color(material, StandardProperties.CELL_TINT);
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/ruling_0/materiallib/api/ShapeItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,6 @@ public int getColorFromItemStack(ItemStack stack, int renderPass) {
if (renderPass != 0) return 0xFFFFFFFF;
Material material = ShapeText.materialFor(stack);
if (material == null || hasOverrideIcon(material)) return 0xFFFFFFFF;
return material.getProperty(StandardProperties.TINT);
return MaterialTints.color(material, StandardProperties.TINT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@

/// The properties this mod defines and uses itself. Other mods define their own [Property] constants for values
/// their shape and recipe generation consumes (melting point, tool durability, etc.).
///
/// A resource pack retints one material through a lang entry at
/// `color.resource.materiallib.<MaterialName>.<propertyName>`, where `<MaterialName>` is the material's registry
/// name in its exact case and `<propertyName>` is one of `tint`, `fluidTint`, `blockTint`, `blockOverlayTint`, or
/// `cellTint`. The value is AARRGGBB hex. An entry changes what renders, not what [Material#getProperty] returns.
/// Every material reads `tint`; the other four keys are read only for a material that sets the matching property.
public final class StandardProperties {

private StandardProperties() {}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/ruling_0/materiallib/api/TextureSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/// `assets/materiallib/textures/<items|blocks>/mloverrides/<materialName>/<shape>[_OVERLAY].png`. `<materialName>` is
/// the material's registry name in its exact case, and `<shape>` is the name the art is filed under inside a texture
/// set. The winning file supplies its own `_OVERLAY` layer or none. Override art carries its own colors, so it draws
/// untinted.
/// untinted. A pack recolors art it does not replace through the tint lang keys instead; see [StandardProperties].
public final class TextureSet {

private final String modid;
Expand Down
37 changes: 37 additions & 0 deletions src/test/java/com/ruling_0/materiallib/api/MaterialTintsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.ruling_0.materiallib.api;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;

import org.junit.jupiter.api.Test;

/// Pins the pack-facing lang key the standard tint properties read, and the coded value a read falls back to with
/// no lang entry present.
class MaterialTintsTest {

private final MaterialRegistry registry = new MaterialRegistry();
private final TextureSet texture = TextureSet.of("testmod", "shiny");

@Test
void aTintReadsTheLangKeyNamedAfterItsMaterialAndProperty() {
Material material = registry.newMaterial("testmod", "TestIron", texture).setTint(0xFFFFCC00).build();
registry.resolve();

assertEquals("color.resource.materiallib.TestIron.tint",
MaterialTints.resourceFor(material, StandardProperties.TINT).getLangKey());
assertEquals(0xFFFFCC00, MaterialTints.color(material, StandardProperties.TINT));
}

@Test
void aUnifiedAlternativeReadsTheCanonicalMaterialsKey() {
Material owner = registry.newMaterial("amod", "TestSteel", texture)
.setProperty(StandardProperties.CELL_TINT, 0x80FF0000).build();
Material alternative = registry.newMaterial("bmod", "TestSteel", texture).build();
registry.resolve();

assertEquals("color.resource.materiallib.TestSteel.cellTint",
MaterialTints.resourceFor(alternative, StandardProperties.CELL_TINT).getLangKey());
assertSame(MaterialTints.resourceFor(owner, StandardProperties.CELL_TINT),
MaterialTints.resourceFor(alternative, StandardProperties.CELL_TINT));
}
}