Skip to content

Commit

Permalink
Improved fluids a lot, added BlockEvents.randomTick, ID icon, fixed m…
Browse files Browse the repository at this point in the history
…ixin issue (again)
  • Loading branch information
LatvianModder committed Jun 17, 2024
1 parent a32e2a7 commit 2328e65
Show file tree
Hide file tree
Showing 33 changed files with 532 additions and 257 deletions.
10 changes: 9 additions & 1 deletion src/main/java/dev/latvian/mods/kubejs/BuiltinKubeJSPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import dev.latvian.mods.kubejs.fluid.FluidBuilder;
import dev.latvian.mods.kubejs.fluid.FluidTypeBuilder;
import dev.latvian.mods.kubejs.fluid.FluidWrapper;
import dev.latvian.mods.kubejs.fluid.ThickFluidBuilder;
import dev.latvian.mods.kubejs.fluid.ThinFluidBuilder;
import dev.latvian.mods.kubejs.helpers.IngredientHelper;
import dev.latvian.mods.kubejs.item.ArmorMaterialBuilder;
import dev.latvian.mods.kubejs.item.ChancedItem;
Expand Down Expand Up @@ -266,8 +268,14 @@ public void registerBuilderTypes(BuilderTypeRegistry registry) {
reg.add("smithing_template", SmithingTemplateItemBuilder.class, SmithingTemplateItemBuilder::new);
});

registry.addDefault(NeoForgeRegistries.Keys.FLUID_TYPES, FluidTypeBuilder.class, FluidTypeBuilder::new);
registry.addDefault(Registries.FLUID, FluidBuilder.class, FluidBuilder::new);

registry.of(Registries.FLUID, reg -> {
reg.add("thin", ThinFluidBuilder.class, ThinFluidBuilder::new);
reg.add("thick", ThickFluidBuilder.class, ThickFluidBuilder::new);
});

registry.addDefault(NeoForgeRegistries.Keys.FLUID_TYPES, FluidTypeBuilder.class, FluidTypeBuilder::new);
// FIXME registry.addDefault(Registries.ENCHANTMENT, EnchantmentBuilder.class, EnchantmentBuilder::new);
registry.addDefault(Registries.MOB_EFFECT, BasicMobEffect.Builder.class, BasicMobEffect.Builder::new);
registry.addDefault(Registries.POTION, PotionBuilder.class, PotionBuilder::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,8 @@ static MutableComponent fluidTagIcon() {
static MutableComponent entityTypeTagIcon() {
return icon(Component.literal("E"));
}

static MutableComponent idIcon() {
return icon(Component.literal("D"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import dev.latvian.mods.kubejs.block.BlockRightClickedKubeEvent;
import dev.latvian.mods.kubejs.block.DetectorBlockKubeEvent;
import dev.latvian.mods.kubejs.block.FarmlandTrampledKubeEvent;
import dev.latvian.mods.kubejs.block.RandomTickKubeEvent;
import dev.latvian.mods.kubejs.event.EventGroup;
import dev.latvian.mods.kubejs.event.EventHandler;
import dev.latvian.mods.kubejs.event.Extra;
Expand All @@ -30,4 +31,5 @@ public interface BlockEvents {
SpecializedEventHandler<String> DETECTOR_POWERED = GROUP.common("detectorPowered", Extra.STRING, () -> DetectorBlockKubeEvent.class);
SpecializedEventHandler<String> DETECTOR_UNPOWERED = GROUP.common("detectorUnpowered", Extra.STRING, () -> DetectorBlockKubeEvent.class);
SpecializedEventHandler<ResourceKey<Block>> FARMLAND_TRAMPLED = GROUP.common("farmlandTrampled", SUPPORTS_BLOCK, () -> FarmlandTrampledKubeEvent.class).hasResult();
SpecializedEventHandler<ResourceKey<Block>> RANDOM_TICK = GROUP.server("randomTick", SUPPORTS_BLOCK, () -> RandomTickKubeEvent.class).hasResult().required();
}
10 changes: 5 additions & 5 deletions src/main/java/dev/latvian/mods/kubejs/block/BlockBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public abstract class BlockBuilder extends BuilderBase<Block> {
public transient boolean opaque;
public transient boolean fullBlock;
public transient boolean requiresTool;
public transient String renderType;
public transient BlockRenderType renderType;
public transient BlockTintFunction tint;
public transient final JsonObject textures;
public transient String model;
Expand Down Expand Up @@ -119,7 +119,7 @@ public BlockBuilder(ResourceLocation i) {
opaque = true;
fullBlock = false;
requiresTool = false;
renderType = "solid";
renderType = BlockRenderType.SOLID;
textures = new JsonObject();
textureAll(id.getNamespace() + ":block/" + id.getPath());
model = "";
Expand Down Expand Up @@ -430,7 +430,7 @@ public BlockBuilder requiresTool() {
@Info("""
Sets the render type of the block. Can be `cutout`, `cutout_mipped`, `translucent`, or `basic`.
""")
public BlockBuilder renderType(String l) {
public BlockBuilder renderType(BlockRenderType l) {
renderType = l;
return this;
}
Expand Down Expand Up @@ -670,12 +670,12 @@ public BlockBuilder transparent(boolean b) {

@Info("Helper method for setting the render type of the block to `cutout` correctly.")
public BlockBuilder defaultCutout() {
return renderType("cutout").notSolid().noValidSpawns(true).suffocating(false).viewBlocking(false).redstoneConductor(false).transparent(true);
return renderType(BlockRenderType.CUTOUT).notSolid().noValidSpawns(true).suffocating(false).viewBlocking(false).redstoneConductor(false).transparent(true);
}

@Info("Helper method for setting the render type of the block to `translucent` correctly.")
public BlockBuilder defaultTranslucent() {
return defaultCutout().renderType("translucent");
return defaultCutout().renderType(BlockRenderType.TRANSLUCENT);
}

@Info("Note block instrument.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package dev.latvian.mods.kubejs.block;

public enum BlockRenderType {
SOLID,
CUTOUT,
CUTOUT_MIPPED,
TRANSLUCENT
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,46 +15,56 @@ public class KubeJSBlockEventHandler {
@SubscribeEvent
public static void rightClick(PlayerInteractEvent.RightClickBlock event) {
var state = event.getLevel().getBlockState(event.getPos());
var key = state.getBlock().kjs$getRegistryKey();

if (event.getLevel() instanceof Level level && BlockEvents.RIGHT_CLICKED.hasListeners(state.kjs$getRegistryKey()) && !event.getEntity().getCooldowns().isOnCooldown(event.getEntity().getItemInHand(event.getHand()).getItem())) {
BlockEvents.RIGHT_CLICKED.post(level, state.kjs$getRegistryKey(), new BlockRightClickedKubeEvent(null, event.getEntity(), event.getHand(), event.getPos(), event.getFace(), event.getHitVec())).applyCancel(event);
if (event.getLevel() instanceof Level level && BlockEvents.RIGHT_CLICKED.hasListeners(key) && !event.getEntity().getCooldowns().isOnCooldown(event.getEntity().getItemInHand(event.getHand()).getItem())) {
BlockEvents.RIGHT_CLICKED.post(level, key, new BlockRightClickedKubeEvent(null, event.getEntity(), event.getHand(), event.getPos(), event.getFace(), event.getHitVec())).applyCancel(event);
}
}

@SubscribeEvent
public static void leftClick(PlayerInteractEvent.LeftClickBlock event) {
var state = event.getLevel().getBlockState(event.getPos());
var key = state.getBlock().kjs$getRegistryKey();

if (event.getLevel() instanceof Level level && BlockEvents.LEFT_CLICKED.hasListeners(state.kjs$getRegistryKey())) {
BlockEvents.LEFT_CLICKED.post(level, state.kjs$getRegistryKey(), new BlockLeftClickedKubeEvent(event)).applyCancel(event);
if (event.getLevel() instanceof Level level && BlockEvents.LEFT_CLICKED.hasListeners(key)) {
BlockEvents.LEFT_CLICKED.post(level, key, new BlockLeftClickedKubeEvent(event)).applyCancel(event);
}
}

@SubscribeEvent
public static void blockBreak(BlockEvent.BreakEvent event) {
if (event.getLevel() instanceof Level level && BlockEvents.BROKEN.hasListeners(event.getState().kjs$getRegistryKey())) {
BlockEvents.BROKEN.post(level, event.getState().kjs$getRegistryKey(), new BlockBrokenKubeEvent(event)).applyCancel(event);
var key = event.getState().getBlock().kjs$getRegistryKey();

if (event.getLevel() instanceof Level level && BlockEvents.BROKEN.hasListeners(key)) {
BlockEvents.BROKEN.post(level, key, new BlockBrokenKubeEvent(event)).applyCancel(event);
}
}

@SubscribeEvent
public static void drops(BlockDropsEvent event) {
if (event.getLevel() instanceof ServerLevel level && BlockEvents.DROPS.hasListeners(event.getState().kjs$getRegistryKey())) {
BlockEvents.DROPS.post(level, event.getState().kjs$getRegistryKey(), new BlockDropsKubeEvent(event)).applyCancel(event);
var key = event.getState().getBlock().kjs$getRegistryKey();

if (event.getLevel() instanceof ServerLevel level && BlockEvents.DROPS.hasListeners(key)) {
BlockEvents.DROPS.post(level, key, new BlockDropsKubeEvent(event)).applyCancel(event);
}
}

@SubscribeEvent
public static void blockPlace(BlockEvent.EntityPlaceEvent event) {
if (event.getLevel() instanceof Level level && BlockEvents.PLACED.hasListeners(event.getPlacedBlock().kjs$getRegistryKey())) {
BlockEvents.PLACED.post(level, event.getPlacedBlock().kjs$getRegistryKey(), new BlockPlacedKubeEvent(event)).applyCancel(event);
var key = event.getPlacedBlock().getBlock().kjs$getRegistryKey();

if (event.getLevel() instanceof Level level && BlockEvents.PLACED.hasListeners(key)) {
BlockEvents.PLACED.post(level, key, new BlockPlacedKubeEvent(event)).applyCancel(event);
}
}

@SubscribeEvent
public static void farmlandTrample(BlockEvent.FarmlandTrampleEvent event) {
if (event.getLevel() instanceof Level level && BlockEvents.FARMLAND_TRAMPLED.hasListeners(event.getState().kjs$getRegistryKey())) {
BlockEvents.FARMLAND_TRAMPLED.post(level, event.getState().kjs$getRegistryKey(), new FarmlandTrampledKubeEvent(event)).applyCancel(event);
var key = event.getState().getBlock().kjs$getRegistryKey();

if (event.getLevel() instanceof Level level && BlockEvents.FARMLAND_TRAMPLED.hasListeners(key)) {
BlockEvents.FARMLAND_TRAMPLED.post(level, key, new FarmlandTrampledKubeEvent(event)).applyCancel(event);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package dev.latvian.mods.kubejs.block;

import dev.latvian.mods.kubejs.level.BlockContainerJS;
import dev.latvian.mods.kubejs.level.KubeLevelEvent;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.block.state.BlockState;

public class RandomTickKubeEvent implements KubeLevelEvent {
private final ServerLevel level;
private final BlockPos pos;
private final BlockState state;
public final RandomSource random;
private BlockContainerJS block;

public RandomTickKubeEvent(ServerLevel level, BlockPos pos, BlockState state, RandomSource random) {
this.level = level;
this.pos = pos;
this.state = state;
this.random = random;
}

@Override
public ServerLevel getLevel() {
return level;
}

public BlockContainerJS getBlock() {
if (block == null) {
block = new BlockContainerJS(level, pos);
block.cachedState = state;
}

return block;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.mojang.datafixers.util.Pair;
import dev.latvian.mods.kubejs.KubeJS;
import dev.latvian.mods.kubejs.block.BlockBuilder;
import dev.latvian.mods.kubejs.block.BlockRenderType;
import dev.latvian.mods.kubejs.block.RandomTickCallbackJS;
import dev.latvian.mods.kubejs.block.SeedItemBuilder;
import dev.latvian.mods.kubejs.client.VariantBlockStateGenerator;
Expand Down Expand Up @@ -88,7 +89,7 @@ public CropBlockBuilder(ResourceLocation i) {
growSpeedCallback = null;
fertilizerCallback = null;
surviveCallback = null;
renderType = "cutout";
renderType = BlockRenderType.CUTOUT;
noCollision = true;
itemBuilder = new SeedItemBuilder(newID("", "_seed"));
itemBuilder.blockBuilder = this;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package dev.latvian.mods.kubejs.client;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.latvian.mods.kubejs.color.Color;
import dev.latvian.mods.kubejs.event.KubeEvent;
import dev.latvian.mods.kubejs.generator.AssetJsonGenerator;
import dev.latvian.mods.kubejs.util.ConsoleJS;
import net.minecraft.Util;
import net.minecraft.resources.ResourceLocation;

import java.io.IOException;
import java.util.Map;
import java.util.function.Consumer;

public class GenerateClientAssetsKubeEvent implements KubeEvent {
Expand Down Expand Up @@ -41,8 +42,8 @@ public void addMultipartBlockState(ResourceLocation id, Consumer<MultipartBlockS
add(ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "blockstates/" + id.getPath()), gen.toJson());
}

public void stencil(ResourceLocation target, String stencil, JsonObject colors) throws IOException {
generator.stencil(target, stencil, colors);
public void stencil(ResourceLocation target, ResourceLocation stencil, Map<Color, Color> remap) throws IOException {
generator.stencil(target, stencil, remap);
}

public void defaultItemModel(ResourceLocation id) {
Expand Down
128 changes: 128 additions & 0 deletions src/main/java/dev/latvian/mods/kubejs/client/LoadedTexture.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package dev.latvian.mods.kubejs.client;

import dev.latvian.mods.kubejs.KubeJS;
import dev.latvian.mods.kubejs.KubeJSPaths;
import dev.latvian.mods.kubejs.color.Color;
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;

import javax.imageio.ImageIO;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Map;

public class LoadedTexture {
public static final LoadedTexture EMPTY = new LoadedTexture(0, 0, new int[0], null);

public static LoadedTexture load(ResourceLocation id) {
try {
var path = KubeJSPaths.ASSETS.resolve(id.getNamespace() + "/textures/" + id.getPath() + ".png");

if (Files.exists(path)) {
try (var in = new BufferedInputStream(Files.newInputStream(path))) {
var metaPath = KubeJSPaths.ASSETS.resolve(id.getNamespace() + "/textures/" + id.getPath() + ".png.mcmeta");
return new LoadedTexture(ImageIO.read(in), Files.exists(metaPath) ? Files.readAllBytes(metaPath) : null);
}
} else if (id.getNamespace().equals(KubeJS.MOD_ID)) {
var path1 = KubeJS.thisMod.getModInfo().getOwningFile().getFile().findResource("assets", "kubejs", "textures", id.getPath() + ".png");

if (Files.exists(path1)) {
try (var in = new BufferedInputStream(Files.newInputStream(path1))) {
var metaPath = KubeJS.thisMod.getModInfo().getOwningFile().getFile().findResource("assets", "kubejs", "textures", id.getPath() + ".png.mcmeta");
return new LoadedTexture(ImageIO.read(in), Files.exists(metaPath) ? Files.readAllBytes(metaPath) : null);
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}

return EMPTY;
}

public final int width;
public final int height;
public final int[] pixels;
public final byte[] mcmeta;

public LoadedTexture(int width, int height, int[] pixels, @Nullable byte[] mcmeta) {
this.width = width;
this.height = height;
this.pixels = pixels;
this.mcmeta = mcmeta;
}

public LoadedTexture(BufferedImage img, @Nullable byte[] mcmeta) {
this.width = img.getWidth();
this.height = img.getHeight();
this.pixels = new int[width * height];
img.getRGB(0, 0, width, height, pixels, 0, width);
this.mcmeta = mcmeta;
}

public byte[] toBytes() {
var img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, width, height, pixels, 0, width);

var out = new ByteArrayOutputStream();

try {
ImageIO.write(img, "png", out);
} catch (Exception ex) {
throw new RuntimeException(ex);
}

return out.toByteArray();
}

public LoadedTexture copy() {
return new LoadedTexture(width, height, pixels.clone(), mcmeta);
}

public LoadedTexture remap(Map<Color, Color> remap) {
if (remap.isEmpty()) {
return this;
}

var colorMap = new Int2IntArrayMap(remap.size());

for (var entry : remap.entrySet()) {
var k = entry.getKey();
var v = entry.getValue();
colorMap.put(k.getArgbJS(), v.getArgbJS());
}

int[] result = new int[pixels.length];

for (int i = 0; i < pixels.length; i++) {
result[i] = ((pixels[i] & 0xFF000000) == 0) ? 0 : colorMap.getOrDefault(pixels[i], pixels[i]);
}

return new LoadedTexture(width, height, result, mcmeta);
}

public LoadedTexture resize(int newWidth, int newHeight) {
if (width == newWidth && height == newHeight) {
return this;
}

var source = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
source.setRGB(0, 0, width, height, pixels, 0, width);

BufferedImage dst = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D bg = dst.createGraphics();
bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
float sx = (float) newWidth / (float) width;
float sy = (float) newHeight / (float) height;
bg.scale(sx, sy);
bg.drawImage(source, 0, 0, null);
bg.dispose();
return new LoadedTexture(dst, mcmeta);
}
}
Loading

0 comments on commit 2328e65

Please sign in to comment.