diff --git a/common/src/main/java/dev/latvian/kubejs/BuiltinKubeJSPlugin.java b/common/src/main/java/dev/latvian/kubejs/BuiltinKubeJSPlugin.java index 821f92bb9..66dd089eb 100644 --- a/common/src/main/java/dev/latvian/kubejs/BuiltinKubeJSPlugin.java +++ b/common/src/main/java/dev/latvian/kubejs/BuiltinKubeJSPlugin.java @@ -14,6 +14,7 @@ import dev.latvian.kubejs.block.BlockStatePredicate; import dev.latvian.kubejs.client.painter.Painter; import dev.latvian.kubejs.client.painter.screen.*; +import dev.latvian.kubejs.client.toast.NotificationBuilder; import dev.latvian.kubejs.entity.EntityJS; import dev.latvian.kubejs.event.IEventHandler; import dev.latvian.kubejs.fluid.FluidBuilder; @@ -353,11 +354,10 @@ public void addBindings(BindingsEvent event) { //matrix event.add("Matrix3f", Matrix3f.class); event.add("Matrix4f", Matrix4f.class); - // - event.add("BlockPos", BlockPos.class); - //block + event.add("BlockPos", BlockPos.class); event.add("BlockProperties", BlockStateProperties.class); + event.add("Notification", NotificationBuilder.class); KubeJS.PROXY.clientBindings(event); } @@ -464,6 +464,8 @@ public void addTypeWrappers(ScriptType type, TypeWrappers typeWrappers) { typeWrappers.register(BlockTintFunction.class, BlockTintFunction::of); typeWrappers.register(ItemTintFunction.class, ItemTintFunction::of); + typeWrappers.register(NotificationBuilder.class, NotificationBuilder::of); + //registry for (val wrapperFactory : RegistryTypeWrapperFactory.getAll()) { try { diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/NotificationBuilder.java b/common/src/main/java/dev/latvian/kubejs/client/toast/NotificationBuilder.java new file mode 100644 index 000000000..804638433 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/NotificationBuilder.java @@ -0,0 +1,163 @@ +package dev.latvian.kubejs.client.toast; + +import dev.latvian.kubejs.bindings.TextWrapper; +import dev.latvian.kubejs.client.toast.icon.*; +import dev.latvian.kubejs.util.UtilsJS; +import dev.latvian.mods.rhino.BaseFunction; +import dev.latvian.mods.rhino.Context; +import dev.latvian.mods.rhino.NativeJavaObject; +import dev.latvian.mods.rhino.mod.util.color.Color; +import dev.latvian.mods.rhino.mod.util.color.SimpleColor; +import dev.latvian.mods.rhino.native_java.type.info.TypeInfo; +import dev.latvian.mods.rhino.util.HideFromJS; +import lombok.val; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; + +import java.time.Duration; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +public class NotificationBuilder { + public static final Component[] NO_TEXT = new Component[0]; + public static final Duration DEFAULT_DURATION = Duration.ofSeconds(5L); + public static final Color DEFAULT_BORDER_COLOR = new SimpleColor(0x472954); + public static final Color DEFAULT_BACKGROUND_COLOR = new SimpleColor(0x241335); + + private static final int FLAG_ICON = 1; + private static final int FLAG_TEXT_SHADOW = FLAG_ICON << 1; + private static final int FLAG_DURATION = FLAG_TEXT_SHADOW << 1; + + @HideFromJS + public static NotificationBuilder of(Context cx, Object object, TypeInfo target) { + if (object instanceof NotificationBuilder b) { + return b; + } else if (object instanceof Map map) { + return null; // FIXME + } else if (object instanceof BaseFunction func) { + val consumer = (Consumer) NativeJavaObject.createInterfaceAdapter(cx, Consumer.class, func); + return make(consumer); + } + return new NotificationBuilder(TextWrapper.componentOf(object)); + } + + public static NotificationBuilder ofText(Component title) { + return new NotificationBuilder(title); + } + + public static NotificationBuilder ofTitles(Component title, Component subTitle) { + return new NotificationBuilder(title.copy().append("\n").append(subTitle)); + } + + public static NotificationBuilder make(Consumer consumer) { + val b = new NotificationBuilder(); + consumer.accept(b); + return b; + } + + public Duration duration; + public Component text; + public ToastIcon icon; + public int iconSize; + public Color outlineColor; + public Color borderColor; + public Color backgroundColor; + public boolean textShadow; + + public NotificationBuilder(Component text) { + duration = DEFAULT_DURATION; + this.text = text; + iconSize = 16; + outlineColor = SimpleColor.BLACK; + borderColor = DEFAULT_BORDER_COLOR; + backgroundColor = DEFAULT_BACKGROUND_COLOR; + textShadow = true; + } + + public NotificationBuilder() { + this(new TextComponent("")); + } + + public NotificationBuilder(FriendlyByteBuf buf) { + int flags = buf.readVarInt(); + text = buf.readComponent(); + + duration = ((flags & FLAG_DURATION) != 0) + ? Duration.ofMillis(buf.readVarLong()) + : DEFAULT_DURATION; + + if ((flags & FLAG_ICON) != 0) { + icon = ToastIcon.read(buf); + iconSize = buf.readByte(); + } else { + icon = null; + iconSize = 16; + } + + outlineColor = UtilsJS.readColor(buf); + borderColor = UtilsJS.readColor(buf); + backgroundColor = UtilsJS.readColor(buf); + textShadow = (flags & FLAG_TEXT_SHADOW) != 0; + } + + public void write(FriendlyByteBuf buf) { + int flags = 0; + + if (icon != null) { + flags |= FLAG_ICON; + } + + if (textShadow) { + flags |= FLAG_TEXT_SHADOW; + } + + if (duration != DEFAULT_DURATION) { + flags |= FLAG_DURATION; + } + + buf.writeVarInt(flags); + buf.writeComponent(text); + + if (duration != DEFAULT_DURATION) { + buf.writeVarLong(duration.toMillis()); + } + + if (icon != null) { + icon.write(buf); + buf.writeByte(iconSize); + } + + UtilsJS.writeColor(buf, outlineColor); + UtilsJS.writeColor(buf, borderColor); + UtilsJS.writeColor(buf, backgroundColor); + } + + public void setTextureIcon(ResourceLocation textureLocation) { + this.icon = new TextureIcon(textureLocation); + } + + public void setItemIcon(ItemStack stack) { + icon = new ItemIcon(stack); + } + + public void setAtlasIcon(ResourceLocation atlas, ResourceLocation sprite) { + this.icon = new AtlasIcon(Optional.ofNullable(atlas), sprite); + } + + public void setAtlasIcon(ResourceLocation sprite) { + setAtlasIcon(null, sprite); + } + + @Environment(EnvType.CLIENT) + public void show() { + val mc = Minecraft.getInstance(); + mc.getToasts().addToast(new NotificationToast(mc, this)); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/NotificationToast.java b/common/src/main/java/dev/latvian/kubejs/client/toast/NotificationToast.java new file mode 100644 index 000000000..0bca758ae --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/NotificationToast.java @@ -0,0 +1,142 @@ +package dev.latvian.kubejs.client.toast; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import com.mojang.math.Matrix4f; +import dev.latvian.kubejs.bindings.TextWrapper; +import dev.latvian.kubejs.client.toast.icon.*; +import lombok.val; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.toasts.Toast; +import net.minecraft.client.gui.components.toasts.ToastComponent; +import net.minecraft.util.FastColor; +import net.minecraft.util.FormattedCharSequence; + +import java.util.ArrayList; +import java.util.List; + +public class NotificationToast implements Toast { + + private final NotificationBuilder notification; + + private final long duration; + private final ToastIcon icon; + private final List text; + private int width, height; + + private long lastChanged; + private boolean changed; + + public NotificationToast(Minecraft mc, NotificationBuilder notification) { + this.notification = notification; + this.duration = notification.duration.toMillis(); + + this.icon = notification.icon; + + this.text = new ArrayList<>(2); + this.width = 0; + this.height = 0; + + if (!TextWrapper.isEmpty(notification.text)) { + this.text.addAll(mc.font.split(notification.text, 240)); + } + + for (val l : this.text) { + this.width = Math.max(this.width, mc.font.width(l)); + } + + this.width += 12; + + if (this.icon != null) { + this.width += 24; + } + + this.height = Math.max(this.text.size() * 10 + 12, 28); + + if (this.text.isEmpty() && this.icon != null) { + this.width = 28; + this.height = 28; + } + + //this.width = Math.max(160, 30 + Math.max(mc.font.width(component), component2 == null ? 0 : mc.font.width(component2)); + } + + @Override + public int width() { + return this.width; + } + + @Override + public int height() { + return this.height; + } + + private void drawRectangle(Matrix4f m, int x0, int y0, int x1, int y1, int r, int g, int b) { + val tesselator = Tesselator.getInstance(); + val buf = tesselator.getBuilder(); + buf.begin(7, DefaultVertexFormat.POSITION_COLOR); + buf.vertex(m, x0, y1, 0F).color(r, g, b, 255).endVertex(); + buf.vertex(m, x1, y1, 0F).color(r, g, b, 255).endVertex(); + buf.vertex(m, x1, y0, 0F).color(r, g, b, 255).endVertex(); + buf.vertex(m, x0, y0, 0F).color(r, g, b, 255).endVertex(); + tesselator.end(); + } + + @Override + public Toast.Visibility render(PoseStack poseStack, ToastComponent toastComponent, long l) { + if (this.changed) { + this.lastChanged = l; + this.changed = false; + } + + val mc = toastComponent.getMinecraft(); + + poseStack.pushPose(); + poseStack.translate(-2D, 2D, 0D); + val m = poseStack.last().pose(); + val w = width(); + val h = height(); + + val oc = notification.outlineColor.getRgbKJS(); + val ocr = FastColor.ARGB32.red(oc); + val ocg = FastColor.ARGB32.green(oc); + val ocb = FastColor.ARGB32.blue(oc); + + val bc = notification.borderColor.getRgbKJS(); + val bcr = FastColor.ARGB32.red(bc); + val bcg = FastColor.ARGB32.green(bc); + val bcb = FastColor.ARGB32.blue(bc); + + val bgc = notification.backgroundColor.getRgbKJS(); + val bgcr = FastColor.ARGB32.red(bgc); + val bgcg = FastColor.ARGB32.green(bgc); + val bgcb = FastColor.ARGB32.blue(bgc); + + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + drawRectangle(m, 2, 0, w - 2, h, ocr, ocg, ocb); + drawRectangle(m, 0, 2, w, h - 2, ocr, ocg, ocb); + drawRectangle(m, 1, 1, w - 1, h - 1, ocr, ocg, ocb); + drawRectangle(m, 2, 1, w - 2, h - 1, bcr, bcg, bcb); + drawRectangle(m, 1, 2, w - 1, h - 2, bcr, bcg, bcb); + drawRectangle(m, 2, 2, w - 2, h - 2, bgcr, bgcg, bgcb); + + if (icon != null) { + icon.draw(mc, poseStack, 14, h / 2, notification.iconSize); + } + + val th = icon == null ? 6 : 26; + val tv = (h - text.size() * 10) / 2 + 1; + + for (var i = 0; i < text.size(); i++) { + if (notification.textShadow) { + mc.font.drawShadow(poseStack, text.get(i), th, tv + i * 10, 0xFFFFFF); + } else { + mc.font.draw(poseStack, text.get(i), th, tv + i * 10, 0xFFFFFF); + } + } + + poseStack.popPose(); + return l - this.lastChanged < duration ? Toast.Visibility.SHOW : Toast.Visibility.HIDE; + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/AtlasIcon.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/AtlasIcon.java new file mode 100644 index 000000000..350e4e1d9 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/AtlasIcon.java @@ -0,0 +1,55 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.val; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.InventoryMenu; + +import java.util.Optional; + +/** + * @author ZZZank + */ +public record AtlasIcon(Optional atlas, ResourceLocation sprite) implements ToastIcon { + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + ResourceLocation.CODEC.optionalFieldOf("altas").forGetter(AtlasIcon::atlas), + ResourceLocation.CODEC.fieldOf("sprite").forGetter(AtlasIcon::sprite) + ).apply(instance, AtlasIcon::new) + ); + + @Override + public void draw(Minecraft mc, PoseStack poseStack, int x, int y, int size) { + val m = poseStack.last().pose(); + val sprite = mc + .getTextureAtlas(this.atlas.orElse(InventoryMenu.BLOCK_ATLAS)) + .apply(this.sprite); + + val p0 = -size / 2; + val p1 = p0 + size; + + val u0 = sprite.getU0(); + val v0 = sprite.getV0(); + val u1 = sprite.getU1(); + val v1 = sprite.getV1(); + + val tesselator = Tesselator.getInstance(); + val buf = tesselator.getBuilder(); + buf.begin(7, DefaultVertexFormat.POSITION_TEX_COLOR); + buf.vertex(m, x + p0, y + p1, 0F).uv(u0, v1).color(255, 255, 255, 255).endVertex(); + buf.vertex(m, x + p1, y + p1, 0F).uv(u1, v1).color(255, 255, 255, 255).endVertex(); + buf.vertex(m, x + p1, y + p0, 0F).uv(u1, v0).color(255, 255, 255, 255).endVertex(); + buf.vertex(m, x + p0, y + p0, 0F).uv(u0, v0).color(255, 255, 255, 255).endVertex(); + tesselator.end(); + } + + @Override + public ToastIconType getType() { + return ToastIconRegistry.ATLAS; + } +} diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ItemIcon.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ItemIcon.java new file mode 100644 index 000000000..ef0182cdc --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ItemIcon.java @@ -0,0 +1,44 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.blaze3d.platform.Lighting; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.val; +import net.minecraft.client.Minecraft; +import net.minecraft.world.item.ItemStack; + +/** + * @author ZZZank + */ +public record ItemIcon(ItemStack stack) implements ToastIcon { + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + ItemStack.CODEC.fieldOf("stack").forGetter(ItemIcon::stack) + ).apply(instance, ItemIcon::new) + ); + + @Override + public void draw(Minecraft mc, PoseStack poseStack, int x, int y, int size) { + RenderSystem.pushMatrix(); + RenderSystem.multMatrix(poseStack.last().pose()); + RenderSystem.enableDepthTest(); + + RenderSystem.translated(x - 2D, y + 2D, 0D); + val s = size / 16F; + RenderSystem.scalef(s, s, s); + + Lighting.turnBackOn(); + mc.getItemRenderer().renderAndDecorateFakeItem(stack, -8, -8); + + RenderSystem.disableBlend(); + Lighting.turnOff(); + RenderSystem.popMatrix(); + } + + @Override + public ToastIconType getType() { + return ToastIconRegistry.ITEM; + } +} diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/NoIcon.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/NoIcon.java new file mode 100644 index 000000000..054098149 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/NoIcon.java @@ -0,0 +1,21 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.serialization.Codec; +import net.minecraft.client.Minecraft; + +/** + * @author ZZZank + */ +public class NoIcon implements ToastIcon { + public static final Codec CODEC = Codec.unit(null); + + @Override + public void draw(Minecraft mc, PoseStack graphics, int x, int y, int size) { + } + + @Override + public ToastIconType getType() { + return ToastIconRegistry.NONE; + } +} diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/TextureIcon.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/TextureIcon.java new file mode 100644 index 000000000..0e2dd4638 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/TextureIcon.java @@ -0,0 +1,42 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.val; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; + +/** + * @author ZZZank + */ +public record TextureIcon(ResourceLocation texture) implements ToastIcon { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + ResourceLocation.CODEC.fieldOf("texture").forGetter(TextureIcon::texture) + ).apply(instance, TextureIcon::new) + ); + + @Override + public void draw(Minecraft mc, PoseStack matrixStack, int x, int y, int size) { + mc.getTextureManager().bind(this.texture); + int p0 = -size / 2; + int p1 = p0 + size; + + val tessellator = Tesselator.getInstance(); + val buf = tessellator.getBuilder(); + val matrix4f = matrixStack.last().pose(); + buf.begin(7, DefaultVertexFormat.POSITION_TEX_COLOR); + buf.vertex(matrix4f, x + p0, y + p1, 0F).uv(0F, 1F).color(255, 255, 255, 255).endVertex(); + buf.vertex(matrix4f, x + p1, y + p1, 0F).uv(1F, 1F).color(255, 255, 255, 255).endVertex(); + buf.vertex(matrix4f, x + p1, y + p0, 0F).uv(1F, 0F).color(255, 255, 255, 255).endVertex(); + buf.vertex(matrix4f, x + p0, y + p0, 0F).uv(0F, 0F).color(255, 255, 255, 255).endVertex(); + tessellator.end(); + } + + @Override + public ToastIconType getType() { + return ToastIconRegistry.TEXTURE; + } +} diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIcon.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIcon.java new file mode 100644 index 000000000..e1d9d1710 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIcon.java @@ -0,0 +1,36 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.blaze3d.vertex.PoseStack; +import dev.latvian.kubejs.util.UtilsJS; +import lombok.val; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; + +import java.io.IOException; + +/** + * @author ZZZank + */ +public interface ToastIcon { + void draw(Minecraft mc, PoseStack graphics, int x, int y, int size); + + ToastIconType getType(); + + static ToastIcon read(FriendlyByteBuf buf) { + val index = buf.readVarInt(); + val type = ToastIconRegistry.getOrDefault(index, ToastIconRegistry.NONE); + try { + return buf.readWithCodec(type.codec()); + } catch (IOException e) { + return null; + } + } + + default void write(FriendlyByteBuf buf) { + buf.writeInt(this.getType().index()); + try { + buf.writeWithCodec(this.getType().codec(), UtilsJS.cast(this)); + } catch (IOException ignored) { + } + } +} diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIconRegistry.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIconRegistry.java new file mode 100644 index 000000000..6c3c2e8cc --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIconRegistry.java @@ -0,0 +1,43 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.serialization.Codec; +import lombok.val; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author ZZZank + */ +public record ToastIconRegistry(int index, Codec codec) implements ToastIconType { + + private static final List REGISTERED = new ArrayList<>(); + + public static final ToastIconType NONE = register(NoIcon.CODEC); + public static final ToastIconType TEXTURE = register(TextureIcon.CODEC); + public static final ToastIconType ITEM = register(ItemIcon.CODEC); + public static final ToastIconType ATLAS = register(AtlasIcon.CODEC); + + public static ToastIconType register(Codec codec) { + val entry = new ToastIconRegistry(REGISTERED.size(), codec); + REGISTERED.add(entry); + return entry; + } + + public static Collection getRegistered() { + return Collections.unmodifiableList(REGISTERED); + } + + public static ToastIconType get(int index) { + return index < 0 || index >= REGISTERED.size() + ? null + : REGISTERED.get(index); + } + + public static ToastIconType getOrDefault(int index, ToastIconType defaultValue) { + val got = get(index); + return got == null ? defaultValue : got; + } +} diff --git a/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIconType.java b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIconType.java new file mode 100644 index 000000000..0aa2cc329 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/client/toast/icon/ToastIconType.java @@ -0,0 +1,13 @@ +package dev.latvian.kubejs.client.toast.icon; + +import com.mojang.serialization.Codec; + +/** + * @author ZZZank + */ +public interface ToastIconType { + + int index(); + + Codec codec(); +} diff --git a/common/src/main/java/dev/latvian/kubejs/net/KubeJSNet.java b/common/src/main/java/dev/latvian/kubejs/net/KubeJSNet.java index 54189300b..383f5eaef 100644 --- a/common/src/main/java/dev/latvian/kubejs/net/KubeJSNet.java +++ b/common/src/main/java/dev/latvian/kubejs/net/KubeJSNet.java @@ -16,6 +16,7 @@ public interface KubeJSNet { MessageType ADD_STAGE = NET.registerS2C("add_stage", AddStageMessage::new); MessageType REMOVE_STAGE = NET.registerS2C("remove_stage", RemoveStageMessage::new); MessageType SYNC_STAGES = NET.registerS2C("sync_stages", SyncStagesMessage::new); + MessageType NOTIFICATION = NET.registerS2C("toast", NotificationMessage::new); static void init() { } diff --git a/common/src/main/java/dev/latvian/kubejs/net/NotificationMessage.java b/common/src/main/java/dev/latvian/kubejs/net/NotificationMessage.java new file mode 100644 index 000000000..3930a4244 --- /dev/null +++ b/common/src/main/java/dev/latvian/kubejs/net/NotificationMessage.java @@ -0,0 +1,41 @@ +package dev.latvian.kubejs.net; + +import dev.latvian.kubejs.KubeJS; +import dev.latvian.kubejs.bindings.UtilsWrapper; +import dev.latvian.kubejs.client.toast.NotificationBuilder; +import lombok.val; +import me.shedaniel.architectury.networking.NetworkManager.PacketContext; +import me.shedaniel.architectury.networking.simple.BaseS2CMessage; +import me.shedaniel.architectury.networking.simple.MessageType; +import net.minecraft.network.FriendlyByteBuf; + +public class NotificationMessage extends BaseS2CMessage { + private final NotificationBuilder notification; + + public NotificationMessage(NotificationBuilder notification) { + this.notification = notification; + } + + NotificationMessage(FriendlyByteBuf buf) { + notification = new NotificationBuilder(buf); + } + + @Override + public MessageType getType() { + return KubeJSNet.NOTIFICATION; + } + + @Override + public void write(FriendlyByteBuf buf) { + notification.write(buf); + } + + @Override + public void handle(PacketContext context) { + val player = UtilsWrapper.getClientWorld().getPlayer(KubeJS.PROXY.getClientPlayer()); + if (player == null) { + return; + } + player.notify(notification); + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/kubejs/player/ClientPlayerJS.java b/common/src/main/java/dev/latvian/kubejs/player/ClientPlayerJS.java index 9931faee6..80a560fb0 100644 --- a/common/src/main/java/dev/latvian/kubejs/player/ClientPlayerJS.java +++ b/common/src/main/java/dev/latvian/kubejs/player/ClientPlayerJS.java @@ -1,6 +1,7 @@ package dev.latvian.kubejs.player; import dev.latvian.kubejs.KubeJS; +import dev.latvian.kubejs.client.toast.NotificationBuilder; import dev.latvian.kubejs.entity.RayTraceResultJS; import dev.latvian.kubejs.net.SendDataFromClientMessage; import net.minecraft.client.Minecraft; @@ -56,4 +57,9 @@ public void sendData(String channel, @Nullable CompoundTag data) { public RayTraceResultJS rayTrace(double distance) { return isSelf ? new RayTraceResultJS(this, Minecraft.getInstance().hitResult, distance) : super.rayTrace(distance); } + + @Override + public void notify(NotificationBuilder notification) { + notification.show(); + } } \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/kubejs/player/PlayerJS.java b/common/src/main/java/dev/latvian/kubejs/player/PlayerJS.java index f920b9ca9..b074de733 100644 --- a/common/src/main/java/dev/latvian/kubejs/player/PlayerJS.java +++ b/common/src/main/java/dev/latvian/kubejs/player/PlayerJS.java @@ -1,6 +1,7 @@ package dev.latvian.kubejs.player; import com.mojang.authlib.GameProfile; +import dev.latvian.kubejs.client.toast.NotificationBuilder; import dev.latvian.kubejs.core.PlayerKJS; import dev.latvian.kubejs.entity.LivingEntityJS; import dev.latvian.kubejs.item.InventoryJS; @@ -219,4 +220,7 @@ public int getMaxAirSupply() { public Stages getStages() { return ((PlayerKJS) minecraftPlayer).kjs$getStages(); } + + public void notify(NotificationBuilder notification) { + } } \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/kubejs/player/ServerPlayerJS.java b/common/src/main/java/dev/latvian/kubejs/player/ServerPlayerJS.java index cdde08515..7f7c4999a 100644 --- a/common/src/main/java/dev/latvian/kubejs/player/ServerPlayerJS.java +++ b/common/src/main/java/dev/latvian/kubejs/player/ServerPlayerJS.java @@ -1,7 +1,9 @@ package dev.latvian.kubejs.player; +import dev.latvian.kubejs.client.toast.NotificationBuilder; import dev.latvian.kubejs.core.PlayerInteractionManagerKJS; import dev.latvian.kubejs.item.ItemStackJS; +import dev.latvian.kubejs.net.NotificationMessage; import dev.latvian.kubejs.net.PaintMessage; import dev.latvian.kubejs.net.SendDataFromServerMessage; import dev.latvian.kubejs.server.ServerJS; @@ -165,4 +167,9 @@ public BlockContainerJS getSpawnLocation() { public void setSpawnLocation(BlockContainerJS c) { minecraftPlayer.setRespawnPosition(c.minecraftLevel.dimension(), c.getPos(), 0F, true, false); } + + @Override + public void notify(NotificationBuilder notification) { + new NotificationMessage(notification).sendTo(this.minecraftPlayer); + } } \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/kubejs/util/UtilsJS.java b/common/src/main/java/dev/latvian/kubejs/util/UtilsJS.java index 46e64bfc0..078a34041 100644 --- a/common/src/main/java/dev/latvian/kubejs/util/UtilsJS.java +++ b/common/src/main/java/dev/latvian/kubejs/util/UtilsJS.java @@ -19,11 +19,14 @@ import dev.latvian.kubejs.world.WorldJS; import dev.latvian.mods.rhino.Wrapper; import dev.latvian.mods.rhino.mod.util.Copyable; +import dev.latvian.mods.rhino.mod.util.color.Color; +import dev.latvian.mods.rhino.mod.util.color.SimpleColorWithAlpha; import dev.latvian.mods.rhino.regexp.NativeRegExp; import lombok.val; import me.shedaniel.architectury.registry.ToolType; import net.minecraft.nbt.EndTag; import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; @@ -582,4 +585,12 @@ public static Collection getAllBlockStates() { ALL_STATE_CACHE = Collections.unmodifiableCollection(states); return ALL_STATE_CACHE; } + + public static void writeColor(FriendlyByteBuf buf, Color color) { + buf.writeInt(color.getArgbKJS()); + } + + public static Color readColor(FriendlyByteBuf buf) { + return new SimpleColorWithAlpha(buf.readInt()); + } } \ No newline at end of file diff --git a/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideCustomJEIEventJS.java b/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideCustomJEIEventJS.java index 26be4c1d8..bc70fbb3a 100644 --- a/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideCustomJEIEventJS.java +++ b/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideCustomJEIEventJS.java @@ -1,14 +1,12 @@ package dev.latvian.kubejs.integration.jei; +import com.google.common.base.Predicates; import dev.latvian.kubejs.event.EventJS; import dev.latvian.kubejs.util.ListJS; -import dev.latvian.kubejs.util.UtilsJS; import mezz.jei.api.ingredients.IIngredientType; import mezz.jei.api.runtime.IJeiRuntime; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; /** * @author LatvianModder @@ -22,19 +20,17 @@ public HideCustomJEIEventJS(IJeiRuntime r) { events = new HashMap<>(); } - @SuppressWarnings("all") - public HideJEIEventJS get(IIngredientType s) { - return events.computeIfAbsent(s, type -> { - return new HideJEIEventJS(runtime, type, o -> { - List list = new ArrayList(); - - for (Object o1 : ListJS.orSelf(o)) { - list.add(UtilsJS.cast(o1)); - } - - return list; - }, o -> true); - }); + @SuppressWarnings("unchecked") + public HideJEIEventJS get(IIngredientType ingredientType) { + return (HideJEIEventJS) events.computeIfAbsent( + ingredientType, + type -> new HideJEIEventJS<>( + runtime, + type, + o -> ListJS.orSelf(o)::contains, + Predicates.alwaysTrue() + ) + ); } @Override diff --git a/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideJEIEventJS.java b/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideJEIEventJS.java index 42775acf1..b311018d2 100644 --- a/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideJEIEventJS.java +++ b/forge/src/main/java/dev/latvian/kubejs/integration/jei/HideJEIEventJS.java @@ -24,12 +24,12 @@ public class HideJEIEventJS extends EventJS { public HideJEIEventJS( IJeiRuntime runtime, IIngredientType type, - Function> typeWrapper, + Function> toIngredient, Predicate filter ) { this.runtime = runtime; this.type = type; - function = typeWrapper; + function = toIngredient; hidden = new HashSet<>(); isValid = filter; allIngredients = this.runtime.getIngredientManager().getAllIngredients(this.type); diff --git a/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSRegistryEvents.java b/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSRegistryEvents.java index e07b09739..534e53663 100644 --- a/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSRegistryEvents.java +++ b/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSRegistryEvents.java @@ -83,7 +83,7 @@ public Set> provideJavaClass(ScriptDump scriptDump) { .stream() .map(r -> r.registryEventProvider) .map(Supplier::get) - .map(e -> e.getClass()) + .map(Object::getClass) .forEach(classes::add); RegistryInfos.MAP.values() .stream() diff --git a/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSTypeAssignments.java b/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSTypeAssignments.java index 4c97587a9..397da009c 100644 --- a/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSTypeAssignments.java +++ b/forge/src/main/java/dev/latvian/kubejs/integration/probejs/KessJSTypeAssignments.java @@ -1,9 +1,11 @@ package dev.latvian.kubejs.integration.probejs; import dev.latvian.kubejs.block.BlockTintFunction; +import dev.latvian.kubejs.client.toast.NotificationBuilder; import dev.latvian.kubejs.item.ItemTintFunction; import dev.latvian.mods.rhino.mod.util.color.Color; import lombok.val; +import net.minecraft.network.chat.Component; import zzzank.probejs.lang.typescript.ScriptDump; import zzzank.probejs.lang.typescript.code.type.Types; import zzzank.probejs.plugin.ProbeJSPlugin; @@ -26,5 +28,7 @@ public void assignType(ScriptDump scriptDump) { for (val s : new String[]{"block", "potion", "map", "display_color_nbt"}) { scriptDump.assignType(ItemTintFunction.class, Types.literal(s)); } + + scriptDump.assignType(NotificationBuilder.class, Types.type(Component.class)); } }