Skip to content

Commit

Permalink
Added new color functions for items and blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
LatvianModder committed Oct 19, 2023
1 parent 7dc2613 commit 4a07741
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dev.latvian.mods.kubejs.block;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import dev.latvian.mods.kubejs.block.callbacks.AfterEntityFallenOnBlockCallbackJS;
import dev.latvian.mods.kubejs.block.callbacks.BlockExplodedCallbackJS;
Expand All @@ -24,9 +23,7 @@
import dev.latvian.mods.kubejs.typings.Info;
import dev.latvian.mods.kubejs.util.ConsoleJS;
import dev.latvian.mods.kubejs.util.UtilsJS;
import dev.latvian.mods.rhino.mod.util.color.Color;
import dev.latvian.mods.rhino.util.HideFromJS;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.core.Direction;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
Expand All @@ -45,10 +42,8 @@
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
Expand All @@ -71,7 +66,7 @@ public abstract class BlockBuilder extends BuilderBase<Block> {
public transient boolean fullBlock;
public transient boolean requiresTool;
public transient String renderType;
public transient Int2IntOpenHashMap color;
public transient BlockTintFunction tint;
public transient final JsonObject textures;
public transient String model;
public transient BlockItemBuilder itemBuilder;
Expand Down Expand Up @@ -115,8 +110,6 @@ public BlockBuilder(ResourceLocation i) {
fullBlock = false;
requiresTool = false;
renderType = "solid";
color = new Int2IntOpenHashMap();
color.defaultReturnValue(0xFFFFFFFF);
textures = new JsonObject();
textureAll(id.getNamespace() + ":block/" + id.getPath());
model = "";
Expand Down Expand Up @@ -243,7 +236,7 @@ protected void generateBlockModelJsons(AssetJsonGenerator generator) {
mg.textures(textures);
}

if (!color.isEmpty() || !customShape.isEmpty()) {
if (tint != null || !customShape.isEmpty()) {
List<AABB> boxes = new ArrayList<>(customShape);

if (boxes.isEmpty()) {
Expand All @@ -259,7 +252,7 @@ protected void generateBlockModelJsons(AssetJsonGenerator generator) {
face.tex("#" + direction.getSerializedName());
face.cull();

if (!color.isEmpty()) {
if (tint != null) {
face.tintindex(0);
}
});
Expand All @@ -274,61 +267,6 @@ protected void generateBlockStateJson(VariantBlockStateGenerator bs) {
bs.simpleVariant("", model.isEmpty() ? (id.getNamespace() + ":block/" + id.getPath()) : model);
}

public Map<ResourceLocation, JsonObject> generateBlockModels(BlockBuilder builder) {
Map<ResourceLocation, JsonObject> map = new HashMap<>();

if (builder.modelJson != null) {
map.put(builder.newID("models/block/", ""), builder.modelJson);
} else {
var modelJson = new JsonObject();

var particle = builder.textures.get("particle").getAsString();

if (areAllTexturesEqual(builder.textures, particle)) {
modelJson.addProperty("parent", "block/cube_all");
var textures = new JsonObject();
textures.addProperty("all", particle);
modelJson.add("textures", textures);
} else {
modelJson.addProperty("parent", "block/cube");
modelJson.add("textures", builder.textures);
}

if (!builder.color.isEmpty()) {
var cube = new JsonObject();
var from = new JsonArray();
from.add(0);
from.add(0);
from.add(0);
cube.add("from", from);
var to = new JsonArray();
to.add(16);
to.add(16);
to.add(16);
cube.add("to", to);
var faces = new JsonObject();

for (var direction : Direction.values()) {
var f = new JsonObject();
f.addProperty("texture", "#" + direction.getSerializedName());
f.addProperty("cullface", direction.getSerializedName());
f.addProperty("tintindex", 0);
faces.add(direction.getSerializedName(), f);
}

cube.add("faces", faces);

var elements = new JsonArray();
elements.add(cube);
modelJson.add("elements", elements);
}

map.put(builder.newID("models/block/", ""), modelJson);
}

return map;
}

protected boolean areAllTexturesEqual(JsonObject tex, String t) {
for (var direction : Direction.values()) {
if (!tex.get(direction.getSerializedName()).getAsString().equals(t)) {
Expand Down Expand Up @@ -466,8 +404,20 @@ public BlockBuilder renderType(String l) {
@Info("""
Set the color of a specific layer of the block.
""")
public BlockBuilder color(int index, Color c) {
color.put(index, c.getArgbJS());
public BlockBuilder color(int index, BlockTintFunction color) {
if (!(tint instanceof BlockTintFunction.Mapped)) {
tint = new BlockTintFunction.Mapped();
}

((BlockTintFunction.Mapped) tint).map.put(index, color);
return this;
}

@Info("""
Set the color of a specific layer of the block.
""")
public BlockBuilder color(BlockTintFunction color) {
tint = color;
return this;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package dev.latvian.mods.kubejs.block;

import dev.latvian.mods.rhino.BaseFunction;
import dev.latvian.mods.rhino.Context;
import dev.latvian.mods.rhino.NativeJavaObject;
import dev.latvian.mods.rhino.Undefined;
import dev.latvian.mods.rhino.mod.util.color.Color;
import dev.latvian.mods.rhino.mod.util.color.SimpleColor;
import dev.latvian.mods.rhino.mod.util.color.SimpleColorWithAlpha;
import dev.latvian.mods.rhino.mod.wrapper.ColorWrapper;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.client.renderer.BiomeColors;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.FoliageColor;
import net.minecraft.world.level.GrassColor;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import org.jetbrains.annotations.Nullable;

import java.util.List;

@FunctionalInterface
public interface BlockTintFunction {
Color getColor(BlockState state, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos, int index);

record Fixed(Color color) implements BlockTintFunction {
@Override
public Color getColor(BlockState state, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos, int index) {
return color;
}
}

class Mapped implements BlockTintFunction {
public final Int2ObjectMap<BlockTintFunction> map = new Int2ObjectArrayMap<>(1);

@Override
public Color getColor(BlockState state, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos, int index) {
var f = map.get(index);
return f == null ? null : f.getColor(state, level, pos, index);
}
}

BlockTintFunction GRASS = (s, l, p, i) -> new SimpleColor(l == null || p == null ? GrassColor.get(0.5, 1.0) : BiomeColors.getAverageGrassColor(l, p));
Color DEFAULT_FOLIAGE_COLOR = new SimpleColor(FoliageColor.getDefaultColor());
BlockTintFunction FOLIAGE = (s, l, p, i) -> l == null || p == null ? DEFAULT_FOLIAGE_COLOR : new SimpleColor(BiomeColors.getAverageFoliageColor(l, p));
Fixed EVERGREEN_FOLIAGE = new Fixed(new SimpleColor(FoliageColor.getEvergreenColor()));
Fixed BIRCH_FOLIAGE = new Fixed(new SimpleColor(FoliageColor.getBirchColor()));
Fixed MANGROVE_FOLIAGE = new Fixed(new SimpleColor(FoliageColor.getMangroveColor()));
BlockTintFunction WATER = (s, l, p, i) -> l == null || p == null ? null : new SimpleColorWithAlpha(BiomeColors.getAverageWaterColor(l, p));
Color[] REDSTONE_COLORS = new Color[16];
BlockTintFunction REDSTONE = (state, level, pos, index) -> {
if (REDSTONE_COLORS[0] == null) {
for (int i = 0; i < REDSTONE_COLORS.length; i++) {
REDSTONE_COLORS[i] = new SimpleColor(RedStoneWireBlock.getColorForPower(i));
}
}

return REDSTONE_COLORS[state.getValue(BlockStateProperties.POWER)];
};

@Nullable
static BlockTintFunction of(Context cx, Object o) {
if (o == null || Undefined.isUndefined(o)) {
return null;
} else if (o instanceof BlockTintFunction f) {
return f;
} else if (o instanceof List<?> list) {
var map = new Mapped();

for (int i = 0; i < list.size(); i++) {
var f = of(cx, list.get(i));

if (f != null) {
map.map.put(i, f);
}
}

return map;
} else if (o instanceof CharSequence) {
var f = switch (o.toString()) {
case "grass" -> GRASS;
case "foliage" -> FOLIAGE;
case "evergreen_foliage" -> EVERGREEN_FOLIAGE;
case "birch_foliage" -> BIRCH_FOLIAGE;
case "mangrove_foliage" -> MANGROVE_FOLIAGE;
case "water" -> WATER;
case "redstone" -> REDSTONE;
default -> null;
};

if (f != null) {
return f;
}
} else if (o instanceof BaseFunction function) {
return (BlockTintFunction) NativeJavaObject.createInterfaceAdapter(cx, BlockTintFunction.class, function);
}

return new Fixed(ColorWrapper.of(o));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package dev.latvian.mods.kubejs.client;

import dev.latvian.mods.kubejs.block.BlockTintFunction;
import net.minecraft.client.color.block.BlockColor;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;

public record BlockTintFunctionWrapper(BlockTintFunction function) implements BlockColor {
@Override
public int getColor(BlockState state, @Nullable BlockAndTintGetter level, @Nullable BlockPos pos, int index) {
var c = function.getColor(state, level, pos, index);
return c == null ? 0xFFFFFFFF : c.getArgbJS();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package dev.latvian.mods.kubejs.client;

import dev.latvian.mods.kubejs.item.ItemTintFunction;
import net.minecraft.client.color.item.ItemColor;
import net.minecraft.world.item.ItemStack;

public record ItemTintFunctionWrapper(ItemTintFunction function) implements ItemColor {
@Override
public int getColor(ItemStack stack, int index) {
var c = function.getColor(stack, index);
return c == null ? 0xFFFFFFFF : c.getArgbJS();
}
}
45 changes: 9 additions & 36 deletions common/src/main/java/dev/latvian/mods/kubejs/item/ItemBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
import dev.latvian.mods.kubejs.typings.Param;
import dev.latvian.mods.kubejs.util.ConsoleJS;
import dev.latvian.mods.rhino.mod.util.color.Color;
import dev.latvian.mods.rhino.mod.wrapper.ColorWrapper;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.Util;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionHand;
Expand Down Expand Up @@ -101,7 +98,7 @@ public static Tier toToolTier(Object o) {
public transient boolean glow;
public transient final List<Component> tooltip;
@Nullable
public transient ItemColorJS colorCallback;
public transient ItemTintFunction tint;
public transient FoodBuilder foodBuilder;
public transient Function<ItemStack, Color> barColor;
public transient ToIntFunction<ItemStack> barWidth;
Expand Down Expand Up @@ -174,6 +171,7 @@ public void generateAssetJsons(AssetJsonGenerator generator) {
if (textureJson.size() == 0) {
texture(newID("item/", "").toString());
}

m.textures(textureJson);
});
}
Expand Down Expand Up @@ -242,21 +240,18 @@ public ItemBuilder group(@Nullable String g) {
}

@Info("Colorizes item's texture of the given index. Index is used when you have multiple layers, e.g. a crushed ore (of rock + ore).")
public ItemBuilder color(int index, Color c) {
if (!(colorCallback instanceof IndexedItemColor indexed)) {
if (colorCallback != null) {
ConsoleJS.STARTUP.warnf("Overwriting existing dynamic item color for {} with an indexed color", id);
}
color(Util.make(new IndexedItemColor(), col -> col.add(index, c)));
} else {
indexed.add(index, c);
public ItemBuilder color(int index, ItemTintFunction color) {
if (!(tint instanceof ItemTintFunction.Mapped)) {
tint = new ItemTintFunction.Mapped();
}

((ItemTintFunction.Mapped) tint).map.put(index, color);
return this;
}

@Info("Colorizes item's texture of the given index. Useful for coloring items, like GT ores ore dusts.")
public ItemBuilder color(ItemColorJS callback) {
colorCallback = callback;
public ItemBuilder color(ItemTintFunction callback) {
tint = callback;
return this;
}

Expand Down Expand Up @@ -432,28 +427,6 @@ public ItemBuilder releaseUsing(ReleaseUsingCallback releaseUsing) {
return this;
}

public static class IndexedItemColor implements ItemColorJS {
Int2IntOpenHashMap colors = new Int2IntOpenHashMap();

public IndexedItemColor() {
colors.defaultReturnValue(0xFFFFFFFF);
}

@Override
public Color getColor(ItemStack stack, int tintIndex) {
return ColorWrapper.of(colors.get(tintIndex));
}

public void add(int tintIndex, Color color) {
colors.put(tintIndex, color.getRgbJS());
}
}

@FunctionalInterface
public interface ItemColorJS {
Color getColor(ItemStack stack, int tintIndex);
}

@FunctionalInterface
public interface UseCallback {
boolean use(Level level, Player player, InteractionHand interactionHand);
Expand Down
Loading

0 comments on commit 4a07741

Please sign in to comment.