mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-26 06:57:02 +01:00
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!)
This commit is contained in:
parent
4af63c6fee
commit
69cf9e9b21
13 changed files with 348 additions and 38 deletions
16
README.md
16
README.md
|
@ -1,14 +1,20 @@
|
|||
# Flywheel
|
||||
A modern engine for modded Minecraft.
|
||||
|
||||
<div align="center">
|
||||
<img src="https://i.imgur.com/yVFgPpr.png" alt="Logo" width="250">
|
||||
<h1>Flywheel</h1>
|
||||
<h6>A modern engine for modded Minecraft.</h6>
|
||||
<a href="https://discord.gg/xjD59ThnXy"><img src="https://img.shields.io/discord/841464837406195712?color=844685&label=Discord&style=flat" alt="Discord"></a>
|
||||
<a href="https://www.curseforge.com/minecraft/mc-mods/flywheel"><img src="http://cf.way2muchnoise.eu/flywheel.svg" alt="Curseforge Downloads"></a>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
### 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.
|
||||
|
|
15
src/main/java/com/jozufozu/flywheel/Client.java
Normal file
15
src/main/java/com/jozufozu/flywheel/Client.java
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() { }
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<Consumer<BooleanDirective>> receiver;
|
||||
|
||||
BooleanConfig(Supplier<Consumer<BooleanDirective>> 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);
|
||||
}
|
||||
}
|
|
@ -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<CommandSource, ?> 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;
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
22
src/main/java/com/jozufozu/flywheel/config/FlwCommands.java
Normal file
22
src/main/java/com/jozufozu/flywheel/config/FlwCommands.java
Normal file
|
@ -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<CommandSource> 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()));
|
||||
}
|
||||
}
|
52
src/main/java/com/jozufozu/flywheel/config/FlwConfig.java
Normal file
52
src/main/java/com/jozufozu/flywheel/config/FlwConfig.java
Normal file
|
@ -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<ClientConfig, ForgeConfigSpec> 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);
|
||||
}
|
||||
}
|
||||
}
|
28
src/main/java/com/jozufozu/flywheel/config/FlwPackets.java
Normal file
28
src/main/java/com/jozufozu/flywheel/config/FlwPackets.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<NetworkEvent.Context> ctx) {
|
||||
target.receiver.get().accept(directive);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue