From 69cf9e9b2167ca5b80224e4e8f1c35acbe6c971b Mon Sep 17 00:00:00 2001 From: JozsefA Date: Fri, 18 Jun 2021 22:52:33 -0700 Subject: [PATCH] Commands, config, and a logo - Added /flywheel backend command to replace /create experimentalRendering - Added /flywheel normalOverlay command - Need to think more about a good way to do this in a client only way - Added basic config - Logo in README.md (thanks, dani!) --- README.md | 16 ++-- .../java/com/jozufozu/flywheel/Client.java | 15 ++++ .../java/com/jozufozu/flywheel/Flywheel.java | 45 ++++------- .../jozufozu/flywheel/backend/Backend.java | 11 ++- .../instancing/InstancedRenderDispatcher.java | 11 ++- .../flywheel/config/BooleanConfig.java | 77 +++++++++++++++++++ .../flywheel/config/BooleanConfigCommand.java | 49 ++++++++++++ .../flywheel/config/BooleanDirective.java | 22 ++++++ .../jozufozu/flywheel/config/FlwCommands.java | 22 ++++++ .../jozufozu/flywheel/config/FlwConfig.java | 52 +++++++++++++ .../jozufozu/flywheel/config/FlwPackets.java | 28 +++++++ .../config/SConfigureBooleanPacket.java | 35 +++++++++ .../gamestate/NormalDebugStateProvider.java | 3 +- 13 files changed, 348 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/jozufozu/flywheel/Client.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/FlwCommands.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/FlwConfig.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/FlwPackets.java create mode 100644 src/main/java/com/jozufozu/flywheel/config/SConfigureBooleanPacket.java diff --git a/README.md b/README.md index e7016a414..5f407c882 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,20 @@ -# Flywheel -A modern engine for modded Minecraft. - +
+Logo +

Flywheel

+
A modern engine for modded Minecraft.
+Discord +Curseforge Downloads +
+
+### About The goal of this project is to provide tools for mod developers so they no longer have to worry about performance, or limitations of Minecraft's archaic rendering engine. That said, this is primarily an outlet for me to have fun with graphics programming. -## Instancing +### Instancing So far, Flywheel provides an alternate, unified path for entity and tile entity rendering that takes advantage of GPU instancing. In doing so, Flywheel gives the developer the flexibility to define their own vertex and instance formats, and write custom shaders to ingest that data. -### Shader Abstraction +### Shaders To accomodate the developer and leave more in the hands of the engine, Flywheel provides a custom shader loading and templating system to hide the details of the CPU/GPU interface. This system is a work in progress. There will be breaking changes, and I make no guarantees of backwards compatibility. diff --git a/src/main/java/com/jozufozu/flywheel/Client.java b/src/main/java/com/jozufozu/flywheel/Client.java new file mode 100644 index 000000000..13166acc6 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/Client.java @@ -0,0 +1,15 @@ +package com.jozufozu.flywheel; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.core.AtlasStitcher; + +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; + +public class Client { + + public static void clientInit() { + + Backend.init(); + FMLJavaModLoadingContext.get().getModEventBus().addListener(AtlasStitcher.getInstance()::onTextureStitch); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/Flywheel.java b/src/main/java/com/jozufozu/flywheel/Flywheel.java index 02a9d02a6..3832e458f 100644 --- a/src/main/java/com/jozufozu/flywheel/Flywheel.java +++ b/src/main/java/com/jozufozu/flywheel/Flywheel.java @@ -1,13 +1,16 @@ package com.jozufozu.flywheel; +import com.jozufozu.flywheel.config.FlwConfig; +import com.jozufozu.flywheel.config.FlwCommands; + +import com.jozufozu.flywheel.config.FlwPackets; + +import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent; -import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -19,32 +22,16 @@ public class Flywheel { private static final Logger LOGGER = LogManager.getLogger(); public Flywheel() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup); - MinecraftForge.EVENT_BUS.register(this); - } + MinecraftForge.EVENT_BUS.addListener(FlwCommands::onServerStarting); - private void setup(final FMLCommonSetupEvent event) { + FlwConfig.init(); - } + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> Client::clientInit); + } - private void doClientStuff(final FMLClientSetupEvent event) { - - } - - private void enqueueIMC(final InterModEnqueueEvent event) { - - } - - private void processIMC(final InterModProcessEvent event) { - - } - - @SubscribeEvent - public void onServerStarting(FMLServerStartingEvent event) { - - } + private void setup(final FMLCommonSetupEvent event) { + FlwPackets.registerPackets(); + } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/Backend.java b/src/main/java/com/jozufozu/flywheel/backend/Backend.java index 4c541eef4..ca06060b5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/Backend.java +++ b/src/main/java/com/jozufozu/flywheel/backend/Backend.java @@ -6,6 +6,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import com.jozufozu.flywheel.config.FlwConfig; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.opengl.GL; @@ -143,8 +145,7 @@ public class Backend { compat.drawInstancedSupported() && compat.instancedArraysSupported(); - // TODO: Config - enabled = !OptifineHandler.usingShaders(); + enabled = FlwConfig.get().enabled() && !OptifineHandler.usingShaders(); } public boolean canUseInstancing(World world) { @@ -178,7 +179,13 @@ public class Backend { return (world instanceof IFlywheelWorld && ((IFlywheelWorld) world).supportsFlywheel()) || world == Minecraft.getInstance().world; } + public static boolean isGameActive() { + return !(Minecraft.getInstance().world == null || Minecraft.getInstance().player == null); + } + public static void reloadWorldRenderers() { RenderWork.enqueue(Minecraft.getInstance().worldRenderer::loadRenderers); } + + public static void init() { } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java index d07779765..1a59be843 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderDispatcher.java @@ -20,6 +20,7 @@ import com.jozufozu.flywheel.core.CrumblingInstanceManager; import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.RenderLayerEvent; +import com.jozufozu.flywheel.util.AnimationTickHolder; import com.jozufozu.flywheel.util.WorldAttached; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; @@ -39,7 +40,9 @@ import net.minecraft.util.LazyValue; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.world.IWorld; +import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -67,9 +70,15 @@ public class InstancedRenderDispatcher { return entityInstanceManager.get(world); } - public static void tick() { + @SubscribeEvent + public static void tick(TickEvent.ClientTickEvent event) { + + if (!Backend.isGameActive() || event.phase == TickEvent.Phase.START) { + return; + } Minecraft mc = Minecraft.getInstance(); ClientWorld world = mc.world; + AnimationTickHolder.tick(); Entity renderViewEntity = mc.renderViewEntity != null ? mc.renderViewEntity : mc.player; diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java new file mode 100644 index 000000000..d8046053d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/BooleanConfig.java @@ -0,0 +1,77 @@ +package com.jozufozu.flywheel.config; + +import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.OptifineHandler; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.util.text.IFormattableTextComponent; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +public enum BooleanConfig { + ENGINE(() -> BooleanConfig::enabled), + NORMAL_OVERLAY(() -> BooleanConfig::normalOverlay), + ; + + final Supplier> receiver; + + BooleanConfig(Supplier> receiver) { + this.receiver = receiver; + } + + public SConfigureBooleanPacket packet(BooleanDirective directive) { + return new SConfigureBooleanPacket(this, directive); + } + + @OnlyIn(Dist.CLIENT) + private static void enabled(BooleanDirective state) { + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || state == null) return; + + if (state == BooleanDirective.DISPLAY) { + ITextComponent text = new StringTextComponent("Flywheel Renderer is currently: ").append(boolToText(FlwConfig.get().client.enabled.get())); + player.sendStatusMessage(text, false); + return; + } + + boolean enabled = state.get(); + boolean cannotUseER = OptifineHandler.usingShaders() && enabled; + + FlwConfig.get().client.enabled.set(enabled); + + ITextComponent text = boolToText(FlwConfig.get().client.enabled.get()).append(new StringTextComponent(" Flywheel Renderer").formatted(TextFormatting.WHITE)); + ITextComponent error = new StringTextComponent("Flywheel Renderer does not support Optifine Shaders").formatted(TextFormatting.RED); + + player.sendStatusMessage(cannotUseER ? error : text, false); + Backend.reloadWorldRenderers(); + } + + @OnlyIn(Dist.CLIENT) + private static void normalOverlay(BooleanDirective state) { + ClientPlayerEntity player = Minecraft.getInstance().player; + if (player == null || state == null) return; + + if (state == BooleanDirective.DISPLAY) { + ITextComponent text = new StringTextComponent("Normal overlay is currently: ").append(boolToText(FlwConfig.get().client.normalDebug.get())); + player.sendStatusMessage(text, false); + return; + } + + FlwConfig.get().client.normalDebug.set(state.get()); + + ITextComponent text = boolToText(FlwConfig.get().client.normalDebug.get()).append(new StringTextComponent(" Normal Overlay").formatted(TextFormatting.WHITE)); + + player.sendStatusMessage(text, false); + } + + private static IFormattableTextComponent boolToText(boolean b) { + return b ? new StringTextComponent("enabled").formatted(TextFormatting.DARK_GREEN) : new StringTextComponent("disabled").formatted(TextFormatting.RED); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java b/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java new file mode 100644 index 000000000..d3037735f --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/BooleanConfigCommand.java @@ -0,0 +1,49 @@ +package com.jozufozu.flywheel.config; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.builder.ArgumentBuilder; + +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraftforge.fml.network.PacketDistributor; + +public class BooleanConfigCommand { + + private final String name; + + private final BooleanConfig value; + + public BooleanConfigCommand(String name, BooleanConfig value) { + this.name = name; + this.value = value; + } + + public ArgumentBuilder register() { + return Commands.literal(name) + .executes(context -> { + ServerPlayerEntity player = context.getSource().asPlayer(); + FlwPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureBooleanPacket(value, BooleanDirective.DISPLAY) + ); + return Command.SINGLE_SUCCESS; + }) + .then(Commands.literal("on").executes(context -> { + ServerPlayerEntity player = context.getSource().asPlayer(); + FlwPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureBooleanPacket(value, BooleanDirective.TRUE) + ); + return Command.SINGLE_SUCCESS; + })) + .then(Commands.literal("off").executes(context -> { + ServerPlayerEntity player = context.getSource().asPlayer(); + FlwPackets.channel.send( + PacketDistributor.PLAYER.with(() -> player), + new SConfigureBooleanPacket(value, BooleanDirective.FALSE) + ); + return Command.SINGLE_SUCCESS; + })); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java b/src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java new file mode 100644 index 000000000..d0ff5e62d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/BooleanDirective.java @@ -0,0 +1,22 @@ +package com.jozufozu.flywheel.config; + +public enum BooleanDirective { + TRUE(true), + FALSE(false), + /** + * Don't change anything, just display what the value currently is. + */ + DISPLAY(true), + ; + + private final boolean b; + + BooleanDirective(boolean b) { + this.b = b; + } + + public boolean get() { + if (this == DISPLAY) throw new IllegalStateException("Cannot get value from DISPLAY directive"); + return b; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java new file mode 100644 index 000000000..180831def --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/FlwCommands.java @@ -0,0 +1,22 @@ +package com.jozufozu.flywheel.config; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; + +import net.minecraft.command.CommandSource; +import net.minecraft.command.Commands; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.event.server.FMLServerStartingEvent; +import net.minecraftforge.fml.network.PacketDistributor; + +public class FlwCommands { + @SubscribeEvent + public static void onServerStarting(FMLServerStartingEvent event) { + CommandDispatcher dispatcher = event.getServer().getCommandManager().getDispatcher(); + + dispatcher.register(Commands.literal("flywheel") + .then(new BooleanConfigCommand("backend", BooleanConfig.ENGINE).register()) + .then(new BooleanConfigCommand("normalOverlay", BooleanConfig.NORMAL_OVERLAY).register())); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java new file mode 100644 index 000000000..c7e845a0a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/FlwConfig.java @@ -0,0 +1,52 @@ +package com.jozufozu.flywheel.config; + +import net.minecraftforge.common.ForgeConfigSpec; +import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; +import net.minecraftforge.fml.ModLoadingContext; + +import net.minecraftforge.fml.config.ModConfig; + +import org.apache.commons.lang3.tuple.Pair; + +public class FlwConfig { + + private static final FlwConfig INSTANCE = new FlwConfig(); + + public final ClientConfig client; + + public FlwConfig() { + Pair client = new ForgeConfigSpec.Builder().configure(ClientConfig::new); + + this.client = client.getLeft(); + + ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, client.getRight()); + } + + public static FlwConfig get() { + return INSTANCE; + } + + public boolean enabled() { + return client.enabled.get(); + } + + public boolean normalOverlayEnabled() { + return client.normalDebug.get(); + } + + public static void init() { } + + public static class ClientConfig { + public final BooleanValue enabled; + public final BooleanValue normalDebug; + + public ClientConfig(ForgeConfigSpec.Builder builder) { + + enabled = builder.comment("Enable or disable the entire engine") + .define("enabled", true); + + normalDebug = builder.comment("Enable or disable a debug overlay that colors pixels by their normal") + .define("normalDebug", false); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/FlwPackets.java b/src/main/java/com/jozufozu/flywheel/config/FlwPackets.java new file mode 100644 index 000000000..6b49a5eb0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/FlwPackets.java @@ -0,0 +1,28 @@ +package com.jozufozu.flywheel.config; + +import com.jozufozu.flywheel.Flywheel; + +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.network.NetworkDirection; +import net.minecraftforge.fml.network.NetworkRegistry; +import net.minecraftforge.fml.network.simple.SimpleChannel; + +public class FlwPackets { + public static final ResourceLocation CHANNEL_NAME = new ResourceLocation(Flywheel.ID, "network"); + public static final String NETWORK_VERSION = new ResourceLocation(Flywheel.ID, "1").toString(); + public static SimpleChannel channel; + + public static void registerPackets() { + channel = NetworkRegistry.ChannelBuilder.named(CHANNEL_NAME) + .serverAcceptedVersions(NETWORK_VERSION::equals) + .clientAcceptedVersions(NETWORK_VERSION::equals) + .networkProtocolVersion(() -> NETWORK_VERSION) + .simpleChannel(); + + channel.messageBuilder(SConfigureBooleanPacket.class, 0, NetworkDirection.PLAY_TO_CLIENT) + .decoder(SConfigureBooleanPacket::new) + .encoder(SConfigureBooleanPacket::encode) + .consumer(SConfigureBooleanPacket::execute) + .add(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/config/SConfigureBooleanPacket.java b/src/main/java/com/jozufozu/flywheel/config/SConfigureBooleanPacket.java new file mode 100644 index 000000000..84439c08d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/config/SConfigureBooleanPacket.java @@ -0,0 +1,35 @@ +package com.jozufozu.flywheel.config; + +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +/** + * Thanks, @zelophed + */ +public class SConfigureBooleanPacket { + + private final BooleanConfig target; + private final BooleanDirective directive; + + public SConfigureBooleanPacket(BooleanConfig target, BooleanDirective directive) { + this.target = target; + this.directive = directive; + } + + public SConfigureBooleanPacket(PacketBuffer buffer) { + target = BooleanConfig.values()[buffer.readByte()]; + directive = BooleanDirective.values()[buffer.readByte()]; + } + + public void encode(PacketBuffer buffer) { + buffer.writeByte(target.ordinal()); + buffer.writeByte(directive.ordinal()); + } + + public void execute(Supplier ctx) { + target.receiver.get().accept(directive); + } + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java b/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java index e05890003..a0717db8f 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/gamestate/NormalDebugStateProvider.java @@ -1,6 +1,7 @@ package com.jozufozu.flywheel.core.shader.gamestate; import com.jozufozu.flywheel.Flywheel; +import com.jozufozu.flywheel.config.FlwConfig; import com.jozufozu.flywheel.core.shader.spec.IBooleanStateProvider; import net.minecraft.util.ResourceLocation; @@ -16,7 +17,7 @@ public class NormalDebugStateProvider implements IBooleanStateProvider { @Override public boolean isTrue() { - return false; + return FlwConfig.get().normalOverlayEnabled(); } @Override