This commit is contained in:
2026-01-09 21:48:48 +01:00
parent c89433c8dd
commit a711ba501d
28 changed files with 1343 additions and 123 deletions

View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.fabricmc.fabric.api.client.screen.v1;
import java.util.Objects;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.impl.client.screen.ScreenExtensions;
import net.minecraft.class_310;
import net.minecraft.class_332;
import net.minecraft.class_437;
/**
* Holds events related to {@link class_437}s.
*
* <p>Some events require a screen instance in order to obtain an event instance.
* The events that require a screen instance can be identified by the use of a method passing a screen instance.
* All events in {@link ScreenKeyboardEvents} and {@link ScreenMouseEvents} require a screen instance.
* This registration model is used since a screen being (re)initialized will reset the screen to its default state, therefore reverting all changes a mod developer may have applied to a screen.
* Furthermore, this design was chosen to reduce the amount of wasted iterations of events as a mod developer would only need to register screen events for rendering, ticking, keyboards and mice if needed on a per-instance basis.
*
* <p>The primary entrypoint into a screen is when it is being opened, this is signified by an event {@link ScreenEvents#BEFORE_INIT before} and {@link ScreenEvents#AFTER_INIT after} initialization of the screen.
*
* @see Screens
* @see ScreenKeyboardEvents
* @see ScreenMouseEvents
*/
public final class ScreenEvents {
/**
* An event that is called before {@link class_437#method_25423(class_310, int, int) a screen is initialized} to its default state.
* It should be noted some methods in {@link Screens} such as a screen's {@link class_437#method_64506 text renderer} may not be initialized yet, and as such their use is discouraged.
*
* <!--<p>Typically this event is used to register screen events such as listening to when child elements are added to the screen. ------ Uncomment when child add/remove event is added for elements-->
* You can still use {@link ScreenEvents#AFTER_INIT} to register events such as keyboard and mouse events.
*
* <p>The {@link ScreenExtensions} provided by the {@code info} parameter may be used to register tick, render events, keyboard, mouse, additional and removal of child elements (including buttons).
* For example, to register an event on inventory like screens after render, the following code could be used:
* <pre>{@code
* &#64;Override
* public void onInitializeClient() {
* ScreenEvents.BEFORE_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
* if (screen instanceof AbstractInventoryScreen) {
* ScreenEvents.afterRender(screen).register((screen1, matrices, mouseX, mouseY, tickDelta) -> {
* ...
* });
* }
* });
* }
* }</pre>
*
* <p>This event indicates a screen has been resized, and therefore is being re-initialized.
* This event can also indicate that the previous screen has been changed.
* @see ScreenEvents#AFTER_INIT
*/
public static final Event<BeforeInit> BEFORE_INIT = EventFactory.createArrayBacked(BeforeInit.class, callbacks -> (client, screen, scaledWidth, scaledHeight) -> {
for (BeforeInit callback : callbacks) {
callback.beforeInit(client, screen, scaledWidth, scaledHeight);
}
});
/**
* An event that is called after {@link class_437#method_25423(class_310, int, int) a screen is initialized} to its default state.
*
* <p>Typically this event is used to modify a screen after the screen has been initialized.
* Modifications such as changing sizes of buttons, removing buttons and adding/removing child elements to the screen can be done safely using this event.
*
* <p>For example, to add a button to the title screen, the following code could be used:
* <pre>{@code
* ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> {
* if (screen instanceof TitleScreen) {
* Screens.getButtons(screen).add(new ButtonWidget(...));
* }
* });
* }</pre>
*
* <p>Note that by adding an element to a screen, the element is not automatically {@link net.minecraft.class_4068 drawn}.
* Unless the element is button, you need to call the specific {@link net.minecraft.class_4068#method_25394(class_332, int, int, float) render} methods in the corresponding screen events.
*
* <p>This event can also indicate that the previous screen has been closed.
* @see ScreenEvents#BEFORE_INIT
*/
public static final Event<AfterInit> AFTER_INIT = EventFactory.createArrayBacked(AfterInit.class, callbacks -> (client, screen, scaledWidth, scaledHeight) -> {
for (AfterInit callback : callbacks) {
callback.afterInit(client, screen, scaledWidth, scaledHeight);
}
});
/**
* An event that is called after {@link class_437#method_25432()} is called.
* This event signifies that the screen is now closed.
*
* <p>This event is typically used to undo any screen specific state changes or to terminate threads spawned by a screen.
* This event may precede initialization events {@link ScreenEvents#BEFORE_INIT} but there is no guarantee that event will be called immediately afterwards.
*/
public static Event<Remove> remove(class_437 screen) {
Objects.requireNonNull(screen, "Screen cannot be null");
return ScreenExtensions.getExtensions(screen).fabric_getRemoveEvent();
}
/**
* An event that is called before a screen is rendered.
*
* @return the event
*/
public static Event<BeforeRender> beforeRender(class_437 screen) {
Objects.requireNonNull(screen, "Screen cannot be null");
return ScreenExtensions.getExtensions(screen).fabric_getBeforeRenderEvent();
}
/**
* An event that is called after a screen is rendered.
*
* @return the event
*/
public static Event<AfterRender> afterRender(class_437 screen) {
Objects.requireNonNull(screen, "Screen cannot be null");
return ScreenExtensions.getExtensions(screen).fabric_getAfterRenderEvent();
}
/**
* An event that is called before a screen is ticked.
*
* @return the event
*/
public static Event<BeforeTick> beforeTick(class_437 screen) {
Objects.requireNonNull(screen, "Screen cannot be null");
return ScreenExtensions.getExtensions(screen).fabric_getBeforeTickEvent();
}
/**
* An event that is called after a screen is ticked.
*
* @return the event
*/
public static Event<AfterTick> afterTick(class_437 screen) {
Objects.requireNonNull(screen, "Screen cannot be null");
return ScreenExtensions.getExtensions(screen).fabric_getAfterTickEvent();
}
@FunctionalInterface
public interface BeforeInit {
void beforeInit(class_310 client, class_437 screen, int scaledWidth, int scaledHeight);
}
@FunctionalInterface
public interface AfterInit {
void afterInit(class_310 client, class_437 screen, int scaledWidth, int scaledHeight);
}
@FunctionalInterface
public interface Remove {
void onRemove(class_437 screen);
}
@FunctionalInterface
public interface BeforeRender {
void beforeRender(class_437 screen, class_332 drawContext, int mouseX, int mouseY, float tickDelta);
}
@FunctionalInterface
public interface AfterRender {
void afterRender(class_437 screen, class_332 drawContext, int mouseX, int mouseY, float tickDelta);
}
@FunctionalInterface
public interface BeforeTick {
void beforeTick(class_437 screen);
}
@FunctionalInterface
public interface AfterTick {
void afterTick(class_437 screen);
}
private ScreenEvents() {
}
}