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
4 changes: 4 additions & 0 deletions worldeditcui-fabric/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ loom {
}
}

mixin {
defaultRefmapName.set("worldeditcui-refmap.json")
}

accessWidenerPath.set(project.file("src/main/resources/worldeditcui.accesswidener"))
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2011-2024 WorldEditCUI team and contributors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.enginehub.worldeditcui.callback;

import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.state.BlockOutlineRenderState;

public interface BlockOutlineRenderCallback {
record Context(
Minecraft client,
Camera camera,
PoseStack poseStack,
GpuBufferSlice projectionMatrixBuffer,
VertexConsumer vertexConsumer,
double camX, double camY, double camZ,
BlockOutlineRenderState state
) {}

/**
* Return true to cancel vanilla outline (replace it), false to let vanilla draw after you.
*/
boolean render(Context ctx);

Event<BlockOutlineRenderCallback> EVENT =
EventFactory.createArrayBacked(BlockOutlineRenderCallback.class, cbs -> ctx -> {
boolean cancel = false;
for (var cb : cbs) cancel |= cb.render(ctx);
return cancel;
});
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2011-2024 WorldEditCUI team and contributors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.enginehub.worldeditcui.callback;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import org.enginehub.worldeditcui.render.WecuiRenderContext;

/**
* A re-implementation of the old world render events for Fabric.
* Temporary until Fabric finishes their new rendering API.
*/
public interface WorldRenderCallback {
void render(WecuiRenderContext ctx);

/**
* Fires at the end of world rendering, after all other rendering is complete.
*/
Event<WorldRenderCallback> LAST = EventFactory.createArrayBacked(WorldRenderCallback.class, cbs -> ctx -> {
for (var cb : cbs) cb.render(ctx);
});

/**
* Fires immediately after the translucent rendering pass.
*/
Event<WorldRenderCallback> AFTER_TRANSLUCENT = EventFactory.createArrayBacked(WorldRenderCallback.class, cbs -> ctx -> {
for (var cb : cbs) cb.render(ctx);
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,21 @@
*/
package org.enginehub.worldeditcui.fabric;

import com.mojang.blaze3d.platform.InputConstants;
import com.mojang.blaze3d.systems.RenderSystem;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import org.enginehub.worldeditcui.WorldEditCUI;
import org.enginehub.worldeditcui.callback.WorldRenderCallback;
import org.enginehub.worldeditcui.config.CUIConfiguration;
import org.enginehub.worldeditcui.event.listeners.CUIListenerChannel;
import org.enginehub.worldeditcui.event.listeners.CUIListenerWorldRender;
Expand All @@ -33,6 +32,7 @@
import org.enginehub.worldeditcui.render.OptifinePipelineProvider;
import org.enginehub.worldeditcui.render.PipelineProvider;
import org.enginehub.worldeditcui.render.VanillaPipelineProvider;
import org.enginehub.worldeditcui.render.WecuiRenderContext;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.MixinEnvironment;

Expand All @@ -49,10 +49,12 @@ public final class FabricModWorldEditCUI implements ModInitializer {
public static final String MOD_ID = "worldeditcui";
private static FabricModWorldEditCUI instance;

private static final String KEYBIND_CATEGORY_WECUI = "key.categories.worldeditcui";
private final KeyMapping keyBindToggleUI = key("toggle", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN);
private final KeyMapping keyBindClearSel = key("clear", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN);
private final KeyMapping keyBindChunkBorder = key("chunk", InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN);
private static final KeyMapping.Category KEYBIND_CATEGORY_WECUI
= new KeyMapping.Category(ResourceLocation.fromNamespaceAndPath(MOD_ID, "general"));

private final KeyMapping keyBindToggleUI = key("toggle", GLFW.GLFW_KEY_UNKNOWN);
private final KeyMapping keyBindClearSel = key("clear", GLFW.GLFW_KEY_UNKNOWN);
private final KeyMapping keyBindChunkBorder = key("chunk", GLFW.GLFW_KEY_UNKNOWN);

private static final List<PipelineProvider> RENDER_PIPELINES = List.of(
new OptifinePipelineProvider(),
Expand All @@ -73,12 +75,12 @@ public final class FabricModWorldEditCUI implements ModInitializer {
* Register a key binding
*
* @param name id, will be used as a localization key under {@code key.worldeditcui.<name>}
* @param type type
* @param code default value
* @return new, registered keybinding in the mod category
*/
private static KeyMapping key(final String name, final InputConstants.Type type, final int code) {
return KeyBindingHelper.registerKeyBinding(new KeyMapping("key." + MOD_ID + '.' + name, type, code, KEYBIND_CATEGORY_WECUI));
private static KeyMapping key(final String name, final int code) {
return KeyBindingHelper.registerKeyBinding(
new KeyMapping("key." + MOD_ID + '.' + name, code, KEYBIND_CATEGORY_WECUI));
}

@Override
Expand All @@ -94,11 +96,11 @@ public void onInitialize() {
ClientLifecycleEvents.CLIENT_STARTED.register(this::onGameInitDone);
CUINetworking.subscribeToCuiPacket(this::onPluginMessage);
ClientPlayConnectionEvents.JOIN.register(this::onJoinGame);
WorldRenderEvents.AFTER_TRANSLUCENT.register(ctx -> {
WorldRenderCallback.AFTER_TRANSLUCENT.register(ctx -> {
if (ctx.advancedTranslucency()) {
try {
RenderSystem.getModelViewStack().pushMatrix();
RenderSystem.getModelViewStack().mul(ctx.matrixStack().last().pose());
RenderSystem.getModelViewStack().mul(ctx.poseStack().last().pose());
// RenderSystem.applyModelViewMatrix();
//ctx.worldRenderer().getTranslucentTarget().bindWrite(false);
this.onPostRenderEntities(ctx);
Expand All @@ -108,11 +110,11 @@ public void onInitialize() {
}
}
});
WorldRenderEvents.LAST.register(ctx -> {
WorldRenderCallback.LAST.register(ctx -> {
if (!ctx.advancedTranslucency()) {
try {
RenderSystem.getModelViewStack().pushMatrix();
RenderSystem.getModelViewStack().mul(ctx.matrixStack().last().pose());
RenderSystem.getModelViewStack().mul(ctx.poseStack().last().pose());
// RenderSystem.applyModelViewMatrix();
this.onPostRenderEntities(ctx);
} finally {
Expand Down Expand Up @@ -192,9 +194,9 @@ public void onJoinGame(final ClientPacketListener handler, final PacketSender se
this.helo(handler);
}

public void onPostRenderEntities(final WorldRenderContext ctx) {
public void onPostRenderEntities(final WecuiRenderContext ctx) {
if (this.visible) {
this.worldRenderListener.onRender(ctx.tickCounter().getRealtimeDeltaTicks());
this.worldRenderListener.onRender(ctx.delta().getRealtimeDeltaTicks());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@
import net.minecraft.util.FormattedCharSequence;
import org.enginehub.worldeditcui.config.CUIConfiguration;
import org.enginehub.worldeditcui.config.Colour;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;

import java.util.List;
import java.util.Objects;

public class CUIConfigList extends ContainerObjectSelectionList<CUIConfigList.ConfigEntry> {
private static final Logger LOGGER = LogUtils.getLogger();
Expand Down Expand Up @@ -87,28 +89,28 @@ public OnOffEntry(String tag) {
}

@Override
public void render(GuiGraphics gfx, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTick) {
super.render(gfx, index, top, left, width, height, mouseX, mouseY, isMouseOver, partialTick);

this.toggleBotton.setX(left + 105);
this.toggleBotton.setY(top);
this.toggleBotton.render(gfx, mouseX, mouseY, partialTick);
}

@Override
public List<? extends GuiEventListener> children() {
public @NotNull List<? extends GuiEventListener> children() {
return ImmutableList.of(this.resetButton, this.toggleBotton);
}

@Override
public List<? extends NarratableEntry> narratables() {
public @NotNull List<? extends NarratableEntry> narratables() {
return ImmutableList.of(this.resetButton, this.toggleBotton);
}

@Override
protected void updateFromConfig() {
this.toggleBotton.setValue((Boolean)configuration.getConfigArray().get(tag));
}

@Override
public void renderContent(GuiGraphics gfx, int mouseX, int mouseY, boolean isMouseOver, float partialTick) {
super.renderContent(gfx, mouseX, mouseY, isMouseOver, partialTick);

this.toggleBotton.setX(getRowLeft() + 105);
this.toggleBotton.setY(getY());
this.toggleBotton.render(gfx, mouseX, mouseY, partialTick);
}
}

public class ColorConfigEntry extends ConfigEntry {
Expand All @@ -127,7 +129,7 @@ public ColorConfigEntry(String tag) {
configuration.changeValue(tag, tested);
}
});
textField.setFormatter((string, integer) -> {
textField.addFormatter((string, integer) -> {
final String colorSource = textField.getValue();
if (colorSource.length() != 9) {
return FormattedCharSequence.forward(string, invalidFormat);
Expand Down Expand Up @@ -155,27 +157,27 @@ public ColorConfigEntry(String tag) {
}

@Override
public void render(GuiGraphics gfx, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTick) {
super.render(gfx, index, top, left, width, height, mouseX, mouseY, isMouseOver, partialTick);
this.textField.setX(left + 105);
this.textField.setY(top);
this.textField.render(gfx, mouseX, mouseY, partialTick);
}

@Override
public List<? extends GuiEventListener> children() {
public @NotNull List<? extends GuiEventListener> children() {
return ImmutableList.of(this.resetButton, this.textField);
}

@Override
public List<? extends NarratableEntry> narratables() {
public @NotNull List<? extends NarratableEntry> narratables() {
return ImmutableList.of(this.resetButton, this.textField);
}

@Override
protected void updateFromConfig() {
this.textField.setValue(((Colour)configuration.getConfigArray().get(tag)).hexString());
}

@Override
public void renderContent(GuiGraphics gfx, int mouseX, int mouseY, boolean isMouseOver, float partialTick) {
super.renderContent(gfx, mouseX, mouseY, isMouseOver, partialTick);
this.textField.setX(getRowLeft() + 105);
this.textField.setY(getY());
this.textField.render(gfx, mouseX, mouseY, partialTick);
}
}

public abstract class ConfigEntry extends ContainerObjectSelectionList.Entry<ConfigEntry> {
Expand All @@ -186,21 +188,26 @@ public abstract class ConfigEntry extends ContainerObjectSelectionList.Entry<Con
public ConfigEntry(String tag) {
this.tag = tag;

this.resetButton = Button.builder(Component.translatable("controls.reset"), (button) -> {
this.resetButton = Button.builder(Component.translatable("controls.reset"), button -> {
configuration.changeValue(tag, configuration.getDefaultValue(tag));
updateFromConfig();
}).bounds(0, 0, 50, BUTTON_HEIGHT).build();

textField = new StringWidget(configuration.getDescription(tag), minecraft.font);
textField.alignLeft();

textField = new StringWidget(Objects.requireNonNull(configuration.getDescription(tag)), minecraft.font);
//textField.alignLeft();
Component tooltip = configuration.getTooltip(tag);
if (tooltip != null) {
textField.setTooltip(Tooltip.create(tooltip));
}
}

@Override
public void render(GuiGraphics gfx, int index, int top, int left, int width, int height, int mouseX, int mouseY, boolean isMouseOver, float partialTick) {
public void renderContent(GuiGraphics gfx, int mouseX, int mouseY, boolean hovered, float partialTick) {
// new API handles entry position internally
int left = this.getX();
int top = this.getY(); // or getRowTop()

int textLeft = left + 90 - maxNameWidth;

this.textField.setX(textLeft);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2011-2024 WorldEditCUI team and contributors
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.enginehub.worldeditcui.mixin;

import com.mojang.blaze3d.buffers.GpuBufferSlice;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.Camera;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LevelRenderer;
import org.enginehub.worldeditcui.callback.WorldRenderCallback;
import org.enginehub.worldeditcui.render.WecuiRenderContext;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

/**
* Mixin to LevelRenderer to inject our world render callbacks.
* Temporary until Fabric finishes their new rendering API.
*/
@Mixin(LevelRenderer.class)
public abstract class LevelRendererMixin {
@Shadow @Final private Minecraft minecraft;

// LAST (old LAST)
@Inject(method = "renderLevel", at = @At("TAIL"))
private void wecui$last(
GraphicsResourceAllocator gfx, DeltaTracker delta, boolean renderBlockOutline,
Camera camera, Matrix4f modelView, Matrix4f projection, Matrix4f inverseProjection,
GpuBufferSlice slice, Vector4f clearColor, boolean renderSky, CallbackInfo ci
) {
PoseStack pose = new PoseStack();
pose.last().pose().set(modelView);
WorldRenderCallback.LAST.invoker()
.render(new WecuiRenderContext(this.minecraft, camera, delta, pose, projection));
}

// AFTER_TRANSLUCENT — fires immediately after translucent pass queued/executed
@Inject(
method = "renderLevel",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/LevelRenderer;addParticlesPass(Lcom/mojang/blaze3d/framegraph/FrameGraphBuilder;Lcom/mojang/blaze3d/buffers/GpuBufferSlice;)V"
)
)
private void wecui$afterTranslucent(
GraphicsResourceAllocator gfx, DeltaTracker delta, boolean renderBlockOutline,
Camera camera, Matrix4f modelView, Matrix4f projection, Matrix4f inverseProjection,
GpuBufferSlice slice, Vector4f clearColor, boolean renderSky,
CallbackInfo ci
) {
var pose = new PoseStack();
pose.last().pose().set(modelView);
WorldRenderCallback.AFTER_TRANSLUCENT.invoker()
.render(new WecuiRenderContext(this.minecraft, camera, delta, pose, projection));
}
}
Loading
Loading