Всем привет! Клиентские моды во многом отличаются от глобальных. Но чем?
Основное различие заключается в том, что клиентские моды работают только на стороне игрока и не требуют установки на сервер. Они изменяют визуальную часть, добавляют удобства в управлении или предоставляют вспомогательные функции (например, мини-карты, моды на интерфейс или оптимизацию).
В этом гайде мы разберём, как создать Forge-мод, который будет работать исключительно на клиенте.
(на примере буду работать на MCreator)
Откройте главный класс мода (у меня это "LemonadeMod"), после найдите инициализирующий класс, после напишите следующие -
// в public (название класса без class)
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); // может быть другое название за место modEventBus
modEventBus.addListener(this::setupClient);
// создаем класс setupClient
private void setupClient(final FMLClientSetupEvent event) {
event.enqueueWork(() -> {
if (FMLEnvironment.dist == Dist.CLIENT) {
new LemonadeModClient(); // наш класс
}
});
}
FMLJavaModLoadingContext.get()
- получает контекст загрузки мода..getModEventBus()
- возвращает шину событий (EventBus), специфичную для вашего мода.modEventBus
- это просто название переменной, вы можете назвать её как угодно (например,eventBus
).
addListener
- регистрирует метод (в данном случаеsetupClient
), который будет вызываться при наступлении определённого события.this::setupClient
- ссылка на методsetupClient
в текущем классе.
FMLClientSetupEvent
- событие, которое вызывается, когда Forge готов к настройке клиентской части мода.Этот метод вызывается только на клиенте (не на сервере).
enqueueWork
- добавляет задачу в очередь выполнения на основном потоке Minecraft.Используется, потому что некоторые операции (например, регистрация рендеров) должны выполняться в основном потоке игры.
FMLEnvironment.dist
- проверяет, в каком окружении работает код (CLIENT
илиDEDICATED_SERVER
).Dist.CLIENT
- гарантирует, что код внутри блока выполнится только на клиенте (избыточная проверка, так какFMLClientSetupEvent
и так вызывается только на клиенте).
LemonadeModClient()
- инициализирует клиентскую часть мода (например, регистрирует рендеры для сущностей, блоков и т. д.).
Создаем класс LemonadeModClient -
package net.genamistik.lemonade;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.api.distmarker.Dist;
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class LemonadeModClient {
public LemonadeModClient() {
}
@SubscribeEvent
public static void init(FMLCommonSetupEvent event) {
new LemonadeModClient();
}
@Mod.EventBusSubscriber
private static class ForgeBusEvents {
@SubscribeEvent
public static void serverLoad(ServerStartingEvent event) {
}
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void clientLoad(FMLClientSetupEvent event) {
}
}
}
@Mod.EventBusSubscriber
– указывает, что этот класс подписывается на события Forge.bus = Mod.EventBusSubscriber.Bus.MOD
– означает, что он слушает события Mod-шины (а не Forge-шины).
public LemonadeModClient()
– пустой конструктор. Обычно здесь инициализируются клиентские вещи (рендеры, текстуры и т. д.), но в данном случае он пуст.
@SubscribeEvent
– метод будет вызван при наступлении событияFMLCommonSetupEvent
.FMLCommonSetupEvent
– событие, которое вызывается на обеих сторонах (клиент и сервер) во время загрузки мода.new LemonadeModClient()
– создаёт экземпляр клиентского класса.
@Mod.EventBusSubscriber
private static class ForgeBusEvents {
@SubscribeEvent
public static void serverLoad(ServerStartingEvent event) {
}
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void clientLoad(FMLClientSetupEvent event) {
}
}
Данный кусок кода ForgeBusEvents
это подписка на Forge-шину (а не Mod-шину), поэтому он может слушать другие события.
@SubscribeEvent
public static void serverLoad(ServerStartingEvent event) {
}
ServerStartingEvent
– вызывается при старте сервера.
(Можно использовать для регистрации команд, инициализации данных и т. д.)
@OnlyIn(Dist.CLIENT)
@SubscribeEvent
public static void clientLoad(FMLClientSetupEvent event) {
}
@OnlyIn(Dist.CLIENT)
– гарантирует, что метод не вызовется на сервере (иначе будет краш).FMLClientSetupEvent
– вызывается только на клиенте, когда можно безопасно регистрировать рендеры, текстуры и т. д.
И все! Он стал клиентским модом!
Для проверки зайдем с MCreator на сервер 217.106.107.100:27481.
И вы увидите -

Давайте проверим добавив кнопку (на главное меню/стоп экран) и при нажатии майнкрафт будет закрыт (класс TestKnopkaOverlay) -
package net.genamistik.lemonade.client.screens;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.gui.screens.PauseScreen;
@Mod.EventBusSubscriber(Dist.CLIENT)
public class TestKnopkaOverlay {
@SubscribeEvent
public static void onScreenInit(ScreenEvent.Init event) {
if (event.getScreen() instanceof TitleScreen || event.getScreen() instanceof PauseScreen) {
int w = Minecraft.getInstance().getWindow().getGuiScaledWidth();
int h = Minecraft.getInstance().getWindow().getGuiScaledHeight();
// Координаты кнопки: w / 2 + -90, h / 2 + -4
int buttonX = w / 2 - 130; // X = центр экрана - 90
int buttonY = h / 2 - 8; // Y = центр экрана - 4
// Создаем кнопку с желтой "L" (или другим текстом)
Button button = Button.builder(
Component.literal("§eL"), // Желтая "L"
btn -> Minecraft.getInstance().stop()
)
.bounds(
buttonX, // Позиция X
buttonY, // Позиция Y
20, 20 // Размер кнопки (можно настроить)
)
.build();
event.addListener(button);
}
}
}
(его не надо регистрировать)
И на главном меню со стоп меню вы увидите кнопку "L" (желтый)\
Удачной разработки!