Skip to content

Commit

Permalink
[ui] store Hud addition/removal tasks in order and process the queue …
Browse files Browse the repository at this point in the history
…at the beginning of every frame while in a world (#213)
  • Loading branch information
gliscowo committed Feb 17, 2024
1 parent 37f42ca commit 2fc8914
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.wispforest.owo.mixin.ui;

import io.wispforest.owo.ui.event.ClientRenderCallback;
import io.wispforest.owo.ui.event.WindowResizeCallback;
import io.wispforest.owo.ui.util.DisposableScreen;
import net.minecraft.client.MinecraftClient;
Expand Down Expand Up @@ -38,6 +39,16 @@ private void captureResize(CallbackInfo ci) {
WindowResizeCallback.EVENT.invoker().onResized((MinecraftClient) (Object) this, this.window);
}

@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/Window;setPhase(Ljava/lang/String;)V", ordinal = 1))
private void beforeRender(boolean tick, CallbackInfo ci) {
ClientRenderCallback.BEFORE.invoker().onRender((MinecraftClient) (Object) this);
}

@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/Window;swapBuffers()V", shift = At.Shift.AFTER))
private void afterRender(boolean tick, CallbackInfo ci) {
ClientRenderCallback.AFTER.invoker().onRender((MinecraftClient) (Object) this);
}

@Inject(method = "setScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;removed()V"))
private void captureSetScreen(Screen screen, CallbackInfo ci) {
if (screen != null && this.currentScreen instanceof DisposableScreen disposable) {
Expand All @@ -64,5 +75,4 @@ private void captureSetScreen(Screen screen, CallbackInfo ci) {
this.screensToDispose.clear();
}
}

}
30 changes: 30 additions & 0 deletions src/main/java/io/wispforest/owo/ui/event/ClientRenderCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.wispforest.owo.ui.event;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.client.MinecraftClient;

public interface ClientRenderCallback {

/**
* Invoked just before the client's window enters the 'Render' phase, after the client
* has ticked and cleared the render task queue
*/
Event<ClientRenderCallback> BEFORE = EventFactory.createArrayBacked(ClientRenderCallback.class, callbacks -> (client) -> {
for (var callback : callbacks) {
callback.onRender(client);
}
});

/**
* Called just after the client has finished rendering and drawing the
* current frame and swapped buffers
*/
Event<ClientRenderCallback> AFTER = EventFactory.createArrayBacked(ClientRenderCallback.class, callbacks -> (client) -> {
for (var callback : callbacks) {
callback.onRender(client);
}
});

void onRender(MinecraftClient client);
}
57 changes: 26 additions & 31 deletions src/main/java/io/wispforest/owo/ui/hud/Hud.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.core.Component;
import io.wispforest.owo.ui.core.OwoUIAdapter;
import io.wispforest.owo.ui.event.ClientRenderCallback;
import io.wispforest.owo.ui.event.WindowResizeCallback;
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
Expand All @@ -25,8 +25,7 @@ public class Hud {
static boolean suppress = false;

private static final Map<Identifier, Component> activeComponents = new HashMap<>();
private static final Map<Identifier, Supplier<Component>> pendingComponents = new HashMap<>();
private static final Set<Identifier> pendingRemovals = new HashSet<>();
private static final List<Consumer<FlowLayout>> pendingActions = new ArrayList<>();

/**
* Add a new component to be rendered on the in-game HUD.
Expand All @@ -40,7 +39,12 @@ public class Hud {
* when the HUD is first rendered
*/
public static void add(Identifier id, Supplier<Component> component) {
pendingComponents.put(id, component);
pendingActions.add(flowLayout -> {
var instance = component.get();

flowLayout.child(instance);
activeComponents.put(id, instance);
});
}

/**
Expand All @@ -49,7 +53,13 @@ public static void add(Identifier id, Supplier<Component> component) {
* @param id The ID of the HUD component to remove
*/
public static void remove(Identifier id) {
pendingRemovals.add(id);
pendingActions.add(flowLayout -> {
var component = activeComponents.get(id);
if (component == null) return;

flowLayout.removeChild(component);
activeComponents.remove(id);
});
}

/**
Expand Down Expand Up @@ -84,33 +94,18 @@ private static void initializeAdapter() {
adapter.moveAndResize(0, 0, window.getScaledWidth(), window.getScaledHeight());
});

HudRenderCallback.EVENT.register((context, tickDelta) -> {
if (suppress) return;

if (!pendingRemovals.isEmpty() && adapter != null) {
pendingRemovals.forEach(identifier -> {
var component = activeComponents.get(identifier);
if (component == null) return;

adapter.rootComponent.removeChild(component);
activeComponents.remove(identifier);
});
pendingRemovals.clear();
}

if (!pendingComponents.isEmpty()) {
ClientRenderCallback.BEFORE.register(client -> {
if (client.world == null) return;
if (!pendingActions.isEmpty()) {
if (adapter == null) initializeAdapter();

pendingComponents.forEach((identifier, componentSupplier) -> {
var component = componentSupplier.get();

adapter.rootComponent.child(component);
activeComponents.put(identifier, component);
});
pendingComponents.clear();
pendingActions.forEach(action -> action.accept(adapter.rootComponent));
pendingActions.clear();
}
});

if (adapter == null) return;
HudRenderCallback.EVENT.register((context, tickDelta) -> {
if (adapter == null || suppress) return;

context.push().translate(0, 0, 100);
adapter.render(context, -69, -69, tickDelta);
Expand Down

0 comments on commit 2fc8914

Please sign in to comment.