Everything but models

- Trying to get xplat forge working, fabric can wait until the common
  project compiles
- Move backend manager event handling to separate class
- Move commands into forge for now
- Make FlwConfig an interface and move concrete impl into forge
- Remove event parameters from handlers than don't actually use them
- Add platform specific blockstate light emission for uniforms
- Remove example effect
- Add accessor for LevelRenderer#ticks
This commit is contained in:
Jozufozu 2024-04-18 19:32:05 -07:00
parent ec685ebdc0
commit ff0a928479
20 changed files with 216 additions and 435 deletions

View File

@ -6,6 +6,7 @@ import org.joml.Vector3f;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.backend.mixin.LevelRendererAccessor;
import com.jozufozu.flywheel.config.DebugMode;
import com.jozufozu.flywheel.lib.math.MatrixMath;
@ -147,8 +148,7 @@ public final class FrameUniforms extends UniformWriter {
}
private static long writeTime(long ptr, RenderContext context) {
int ticks = context.renderer()
.getTicks();
int ticks = ((LevelRendererAccessor) context.renderer()).flywheel$ticks();
float partialTick = context.partialTick();
float renderTicks = ticks + partialTick;
float renderSeconds = renderTicks / 20f;

View File

@ -4,6 +4,7 @@ import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.backend.mixin.AbstractClientPlayerAccessor;
import com.jozufozu.flywheel.platform.ClientPlatform;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
@ -93,7 +94,8 @@ public final class PlayerUniforms extends UniformWriter {
Item handItem = player.getItemInHand(hand).getItem();
if (handItem instanceof BlockItem bitem) {
Block block = bitem.getBlock();
int blockLight = block.defaultBlockState().getLightEmission(player.clientLevel, player.blockPosition());
int blockLight = ClientPlatform.getInstance()
.getLightEmission(block.defaultBlockState(), player.clientLevel, player.blockPosition());
if (heldLight < blockLight) {
heldLight = blockLight;
}

View File

@ -1,6 +1,5 @@
package com.jozufozu.flywheel.backend.engine.uniform;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.event.RenderContext;
public final class Uniforms {
@ -33,7 +32,7 @@ public final class Uniforms {
}
}
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
public static void onReloadLevelRenderer() {
deleteAll();
}
}

View File

@ -0,0 +1,12 @@
package com.jozufozu.flywheel.backend.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.renderer.LevelRenderer;
@Mixin(LevelRenderer.class)
public interface LevelRendererAccessor {
@Accessor("ticks")
int flywheel$ticks();
}

View File

@ -1,94 +1,17 @@
package com.jozufozu.flywheel.config;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.api.backend.BackendManager;
import com.mojang.logging.LogUtils;
import com.jozufozu.flywheel.platform.ClientPlatform;
import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.common.ForgeConfigSpec.BooleanValue;
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
public class FlwConfig {
private static final Logger LOGGER = LogUtils.getLogger();
private static final FlwConfig INSTANCE = new FlwConfig();
public final ClientConfig client;
private final ForgeConfigSpec clientSpec;
private FlwConfig() {
Pair<ClientConfig, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = clientPair.getLeft();
clientSpec = clientPair.getRight();
}
public static FlwConfig get() {
public interface FlwConfig {
FlwConfig INSTANCE = ClientPlatform.getInstance().getConfigInstance();
static FlwConfig get() {
return INSTANCE;
}
public Backend getBackend() {
Backend backend = parseBackend(client.backend.get());
if (backend == null) {
backend = BackendManager.getDefaultBackend();
client.backend.set(Backend.REGISTRY.getIdOrThrow(backend).toString());
}
Backend getBackend();
return backend;
}
boolean limitUpdates();
@Nullable
private static Backend parseBackend(String idStr) {
ResourceLocation backendId;
try {
backendId = new ResourceLocation(idStr);
} catch (ResourceLocationException e) {
LOGGER.warn("Config contains invalid backend ID '" + idStr + "'!");
return null;
}
Backend backend = Backend.REGISTRY.get(backendId);
if (backend == null) {
LOGGER.warn("Config contains non-existent backend with ID '" + backendId + "'!");
return null;
}
return backend;
}
public boolean limitUpdates() {
return client.limitUpdates.get();
}
public int workerThreads() {
return client.workerThreads.get();
}
public void registerSpecs(ModLoadingContext context) {
context.registerConfig(ModConfig.Type.CLIENT, clientSpec);
}
public static class ClientConfig {
public final ConfigValue<String> backend;
public final BooleanValue limitUpdates;
public final ForgeConfigSpec.IntValue workerThreads;
private ClientConfig(ForgeConfigSpec.Builder builder) {
backend = builder.comment("Select the backend to use.")
.define("backend", Backend.REGISTRY.getIdOrThrow(BackendManager.getDefaultBackend()).toString());
limitUpdates = builder.comment("Enable or disable instance update limiting with distance.")
.define("limitUpdates", true);
workerThreads = builder.comment("The number of worker threads to use. Set to -1 to let Flywheel decide. Set to 0 to disable parallelism. Requires a game restart to take effect.")
.defineInRange("workerThreads", -1, -1, Runtime.getRuntime()
.availableProcessors());
}
}
int workerThreads();
}

View File

@ -4,8 +4,6 @@ import org.slf4j.Logger;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.backend.Backends;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl;
@ -14,7 +12,6 @@ import com.mojang.logging.LogUtils;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.fml.CrashReportCallables;
public final class BackendManagerImpl {
private static final Logger LOGGER = LogUtils.getLogger();
@ -47,7 +44,7 @@ public final class BackendManagerImpl {
return Backends.INDIRECT;
}
private static void chooseBackend() {
public static void chooseBackend() {
var preferred = FlwConfig.get().getBackend();
var actual = preferred.findFallback();
@ -67,25 +64,5 @@ public final class BackendManagerImpl {
}
public static void init() {
CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString);
}
public static void onEndClientResourceReload(EndClientResourceReloadEvent event) {
if (event.error()
.isPresent()) {
return;
}
chooseBackend();
VisualizationManagerImpl.resetAll();
}
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
chooseBackend();
ClientLevel level = event.level();
if (level != null) {
VisualizationManagerImpl.reset(level);
}
}
}

View File

@ -8,7 +8,6 @@ import java.util.function.Function;
import org.jetbrains.annotations.ApiStatus;
import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent;
import com.jozufozu.flywheel.api.model.Model;
public class ModelCache<T> {
@ -31,7 +30,7 @@ public class ModelCache<T> {
}
@ApiStatus.Internal
public static void onEndClientResourceReload(EndClientResourceReloadEvent event) {
public static void onEndClientResourceReload() {
for (ModelCache<?> cache : ALL) {
cache.clear();
}

View File

@ -7,7 +7,6 @@ import java.util.function.Supplier;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent;
import com.jozufozu.flywheel.api.model.Model;
public class ModelHolder {
@ -51,7 +50,7 @@ public class ModelHolder {
}
@ApiStatus.Internal
public static void onEndClientResourceReload(EndClientResourceReloadEvent event) {
public static void onEndClientResourceReload() {
for (ModelHolder holder : ALL) {
holder.clear();
}

View File

@ -12,7 +12,7 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
class MeshEmitter implements VertexConsumer {
private final BufferBuilder bufferBuilder;
protected final BufferBuilder bufferBuilder;
private final RenderType renderType;
private boolean lastQuadWasShaded;
private boolean seenFirstQuad;
@ -51,7 +51,7 @@ class MeshEmitter implements VertexConsumer {
}
}
private void observeQuadAndEmitIfNecessary(BakedQuad quad) {
protected void observeQuadAndEmitIfNecessary(BakedQuad quad) {
if (seenFirstQuad && lastQuadWasShaded != quad.isShade()) {
emit();
begin();
@ -68,13 +68,6 @@ class MeshEmitter implements VertexConsumer {
bufferBuilder.putBulkData(poseEntry, quad, colorMuls, red, green, blue, combinedLights, combinedOverlay, mulColor);
}
@Override
public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad quad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) {
observeQuadAndEmitIfNecessary(quad);
bufferBuilder.putBulkData(matrixEntry, quad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor);
}
@Override
public VertexConsumer vertex(double x, double y, double z) {
throw new UnsupportedOperationException("ShadeSeparatingVertexConsumer only supports putBulkData!");

View File

@ -14,7 +14,6 @@ import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraft.world.level.LevelAccessor;
import net.minecraftforge.event.level.LevelEvent;
public final class LevelAttached<T> {
private static final ConcurrentLinkedDeque<WeakReference<LevelAttached<?>>> ALL = new ConcurrentLinkedDeque<>();
@ -42,11 +41,6 @@ public final class LevelAttached<T> {
this(factory, t -> {});
}
@ApiStatus.Internal
public static void onUnloadLevel(LevelEvent.Unload event) {
invalidateLevel(event.getLevel());
}
public static void invalidateLevel(LevelAccessor level) {
Iterator<WeakReference<LevelAttached<?>>> iterator = ALL.iterator();
while (iterator.hasNext()) {

View File

@ -6,9 +6,12 @@ import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
public abstract class ClientPlatform {
private static final ClientPlatform INSTANCE;
@ -38,4 +41,8 @@ public abstract class ClientPlatform {
@Nullable
public abstract ShadersModHandler.InternalHandler createIrisOculusHandlerIfPresent();
public abstract int getLightEmission(BlockState state, ClientLevel level, BlockPos pos);
public abstract FlwConfig getConfigInstance();
}

View File

@ -1,292 +0,0 @@
package com.jozufozu.flywheel.vanilla.effect;
import java.util.ArrayList;
import java.util.List;
import org.joml.Vector3f;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.Effect;
import com.jozufozu.flywheel.api.visual.EffectVisual;
import com.jozufozu.flywheel.api.visual.TickableVisual;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
import com.jozufozu.flywheel.lib.instance.TransformedInstance;
import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.task.ForEachPlan;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.core.Vec3i;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.event.TickEvent;
// http://www.kfish.org/boids/pseudocode.html
public class ExampleEffect implements Effect {
private static final List<ExampleEffect> ALL_EFFECTS = new ArrayList<>();
private static final int VISUAL_COUNT = 500;
private static final float SPAWN_RADIUS = 8.0f;
private static final float LIMIT_RANGE = 10.0f;
private static final float SPEED_LIMIT = 0.1f;
private static final float RENDER_SCALE = 2 / 16f;
private static final float SIGHT_RANGE = 5;
private static final float COHERENCE = 1f / 60f;
private static final float SEPARATION = 0.05f;
private static final float ALIGNMENT = 1 / 20f;
private static final float TENDENCY = 1 / 1000f;
private static final float AVERSION = 1;
private static final float GNAT_JITTER = 0.05f;
private final Level level;
private final Vector3f targetPoint;
public ExampleEffect(Level level, Vector3f targetPoint) {
this.level = level;
this.targetPoint = targetPoint;
}
public static void tick(TickEvent.ClientTickEvent event) {
if (event.phase != TickEvent.Phase.START || Minecraft.getInstance().isPaused()) {
return;
}
trySpawnNewEffect();
}
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
ALL_EFFECTS.clear();
}
private static void trySpawnNewEffect() {
Level level = Minecraft.getInstance().level;
Player player = Minecraft.getInstance().player;
if (player == null || level == null) {
return;
}
VisualizationManager manager = VisualizationManager.get(level);
if (manager == null) {
return;
}
if (!ALL_EFFECTS.isEmpty() && level.random.nextFloat() > 0.005f) {
return;
}
Vec3 playerPos = player.position();
var x = (float) (playerPos.x + Mth.nextFloat(level.random, -20, 20));
var y = (float) (playerPos.y + Mth.nextFloat(level.random, 0, 5));
var z = (float) (playerPos.z + Mth.nextFloat(level.random, -20, 20));
ExampleEffect effect = new ExampleEffect(level, new Vector3f(x, y, z));
ALL_EFFECTS.add(effect);
manager.getEffects().queueAdd(effect);
}
@Override
public EffectVisual<?> visualize(VisualizationContext ctx) {
return new ExampleVisual(ctx);
}
public class ExampleVisual implements EffectVisual<ExampleEffect>, TickableVisual, DynamicVisual {
private final List<BoidVisual> effects;
private final List<Boid> boids;
public ExampleVisual(VisualizationContext ctx) {
this.effects = new ArrayList<>(VISUAL_COUNT);
this.boids = new ArrayList<>(VISUAL_COUNT);
for (int i = 0; i < VISUAL_COUNT; i++) {
var x = targetPoint.x + Mth.nextFloat(level.random, -SPAWN_RADIUS, SPAWN_RADIUS);
var y = targetPoint.y + Mth.nextFloat(level.random, -SPAWN_RADIUS, SPAWN_RADIUS);
var z = targetPoint.z + Mth.nextFloat(level.random, -SPAWN_RADIUS, SPAWN_RADIUS);
Boid boid = new Boid(x, y, z);
boids.add(boid);
effects.add(new BoidVisual(ctx, boid));
}
}
@Override
public Plan<TickableVisual.Context> planTick() {
Plan<TickableVisual.Context> beginTick = ForEachPlan.of(() -> boids, Boid::beginTick);
return beginTick.then(ForEachPlan.of(() -> effects, boid -> boid.self.tick(boids)));
}
@Override
public Plan<DynamicVisual.Context> planFrame() {
return ForEachPlan.of(() -> effects, BoidVisual::beginFrame);
}
@Override
public void init(float partialTick) {
}
@Override
public void update(float partialTick) {
}
@Override
public void delete() {
effects.forEach(BoidVisual::_delete);
}
}
public static class Boid {
final Vector3f lastPosition;
final Vector3f position;
final Vector3f lastVelocity = new Vector3f(0);
final Vector3f velocity = new Vector3f(0);
final Vector3f scratch = new Vector3f(0);
final Vector3f coherence = new Vector3f(0);
final Vector3f alignment = new Vector3f(0);
public Boid(float x, float y, float z) {
lastPosition = new Vector3f(x, y, z);
position = new Vector3f(x, y, z);
}
private void beginTick() {
lastVelocity.set(velocity);
lastPosition.set(position);
}
public void tick(List<Boid> swarm) {
int seen = 0;
coherence.set(0);
alignment.set(0);
for (Boid boid : swarm) {
if (boid == this) {
continue;
}
float distance = boid.lastPosition.distance(lastPosition);
if (distance > SIGHT_RANGE) {
continue;
}
seen++;
coherence(boid);
separation(boid);
alignment(boid);
}
if (seen > 0) {
coherencePost(seen);
alignmentPost(seen);
}
//tend(ExampleEffect.this.targetPoint);
avoidPlayer();
position.add(capSpeed(velocity));
}
private void avoidPlayer() {
var player = Minecraft.getInstance().player.position();
scratch.set(player.x, player.y, player.z);
float dsq = lastPosition.distanceSquared(scratch);
if (dsq > SIGHT_RANGE * SIGHT_RANGE) {
return;
}
lastPosition.sub(scratch, scratch)
.mul(AVERSION / dsq);
velocity.add(capSpeed(scratch));
}
private void coherence(Boid other) {
this.coherence.add(other.lastPosition);
}
private void separation(Boid other) {
float dsq = lastPosition.distanceSquared(other.lastPosition);
var push = other.lastPosition.sub(lastPosition, this.scratch)
.mul(SEPARATION / dsq);
this.velocity.sub(push);
}
private void alignment(Boid boid) {
this.alignment.add(boid.lastVelocity);
}
private void coherencePost(int seen) {
this.coherence.div(seen)
.sub(lastPosition)
.mul(COHERENCE);
this.velocity.add(capSpeed(this.coherence));
}
private void alignmentPost(int seen) {
this.alignment.div(seen)
.sub(lastVelocity)
.mul(ALIGNMENT);
this.velocity.add(this.alignment);
}
private void tend(Vector3f target) {
this.scratch.set(target)
.sub(lastPosition)
.mul(TENDENCY);
this.velocity.add(capSpeed(this.scratch));
}
private static Vector3f capSpeed(Vector3f vec) {
return vec.normalize(SPEED_LIMIT);
}
}
public static class BoidVisual {
private final Boid self;
private final Vec3i renderOrigin;
private final TransformedInstance instance;
public BoidVisual(VisualizationContext ctx, Boid self) {
renderOrigin = ctx.renderOrigin();
this.self = self;
instance = ctx.instancerProvider()
.instancer(InstanceTypes.TRANSFORMED, Models.block(Blocks.SHROOMLIGHT.defaultBlockState()))
.createInstance();
instance.light(LightTexture.FULL_BRIGHT);
}
public void _delete() {
instance.delete();
}
public void beginFrame(DynamicVisual.Context context) {
float partialTick = context.partialTick();
var x = Mth.lerp(partialTick, self.lastPosition.x, self.position.x);
var y = Mth.lerp(partialTick, self.lastPosition.y, self.position.y);
var z = Mth.lerp(partialTick, self.lastPosition.z, self.position.z);
instance.loadIdentity()
.translateBack(renderOrigin)
.translate(x, y, z)
.scale(RENDER_SCALE);
}
}
}

View File

@ -8,6 +8,7 @@
"AbstractClientPlayerAccessor",
"GameRendererAccessor",
"GlStateManagerMixin",
"LevelRendererAccessor",
"LightTextureAccessor",
"OptionsMixin",
"OverlayTextureAccessor",

View File

@ -7,11 +7,14 @@ import com.jozufozu.flywheel.api.event.ReloadLevelRendererCallback;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.event.RenderStageCallback;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
import net.fabricmc.loader.api.FabricLoader;
import net.irisshaders.iris.api.v0.IrisApi;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
public class ClientPlatformImpl extends ClientPlatform {
@Override
@ -56,4 +59,15 @@ public class ClientPlatformImpl extends ClientPlatform {
return null;
}
}
@Override
public int getLightEmission(BlockState state, ClientLevel level, BlockPos pos) {
return state.getLightEmission();
}
@Override
public FlwConfig getConfigInstance() {
// TODO: fabric config
return null;
}
}

View File

@ -5,12 +5,15 @@ import java.util.ArrayList;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
import com.jozufozu.flywheel.config.BackendArgument;
import com.jozufozu.flywheel.config.FlwCommands;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.config.FlwForgeConfig;
import com.jozufozu.flywheel.impl.BackendEventHandler;
import com.jozufozu.flywheel.impl.BackendManagerImpl;
import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler;
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
@ -29,6 +32,7 @@ import net.minecraftforge.client.event.RegisterClientReloadListenersEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.level.LevelEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.CrashReportCallables;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.IExtensionPoint;
import net.minecraftforge.fml.ModLoadingContext;
@ -58,7 +62,7 @@ public class FlywheelForge {
modEventBus.addListener(FlywheelForge::onCommonSetup);
modEventBus.addListener(FlywheelForge::onRegister);
FlwConfig.get().registerSpecs(modLoadingContext);
FlwForgeConfig.INSTANCE.registerSpecs(modLoadingContext);
modLoadingContext.registerExtensionPoint(IExtensionPoint.DisplayTest.class, () -> new IExtensionPoint.DisplayTest(
() -> "any",
@ -71,7 +75,7 @@ public class FlywheelForge {
private static void clientInit(IEventBus forgeEventBus, IEventBus modEventBus) {
forgeEventBus.addListener(FlywheelForge::addDebugInfo);
forgeEventBus.addListener(BackendManagerImpl::onReloadLevelRenderer);
forgeEventBus.addListener(BackendEventHandler::onReloadLevelRenderer);
forgeEventBus.addListener(VisualizationEventHandler::onClientTick);
forgeEventBus.addListener(VisualizationEventHandler::onBeginFrame);
@ -81,26 +85,24 @@ public class FlywheelForge {
forgeEventBus.addListener(FlwCommands::registerClientCommands);
forgeEventBus.addListener(Uniforms::onReloadLevelRenderer);
forgeEventBus.<ReloadLevelRendererEvent>addListener($ -> Uniforms.onReloadLevelRenderer());
forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.onUnloadLevel(e));
// forgeEventBus.addListener(ExampleEffect::tick);
// forgeEventBus.addListener(ExampleEffect::onReload);
forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.invalidateLevel(e.getLevel()));
modEventBus.addListener(FlywheelForge::registerClientReloadListeners);
modEventBus.addListener(FlywheelForge::onClientSetup);
modEventBus.addListener(FlywheelForge::onLoadComplete);
modEventBus.addListener(BackendManagerImpl::onEndClientResourceReload);
modEventBus.addListener(BackendEventHandler::onEndClientResourceReload);
modEventBus.addListener((EndClientResourceReloadEvent e) -> ModelCache.onEndClientResourceReload(e));
modEventBus.addListener(ModelHolder::onEndClientResourceReload);
modEventBus.<EndClientResourceReloadEvent>addListener($ -> ModelCache.onEndClientResourceReload());
modEventBus.<EndClientResourceReloadEvent>addListener($ -> ModelHolder.onEndClientResourceReload());
modEventBus.addListener(PartialModel::onModelRegistry);
modEventBus.addListener(PartialModel::onModelBake);
Flywheel.earlyInit();
CrashReportCallables.registerCrashCallable("Flywheel Backend", BackendManagerImpl::getBackendString);
}
private static void registerClientReloadListeners(RegisterClientReloadListenersEvent event) {

View File

@ -25,7 +25,7 @@ public final class FlwCommands {
}
public static void registerClientCommands(RegisterClientCommandsEvent event) {
FlwConfig config = FlwConfig.get();
var config = FlwForgeConfig.INSTANCE;
LiteralArgumentBuilder<CommandSourceStack> command = Commands.literal("flywheel");

View File

@ -0,0 +1,88 @@
package com.jozufozu.flywheel.config;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import com.jozufozu.flywheel.api.backend.Backend;
import com.jozufozu.flywheel.api.backend.BackendManager;
import com.mojang.logging.LogUtils;
import net.minecraft.ResourceLocationException;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
public class FlwForgeConfig implements FlwConfig {
private static final Logger LOGGER = LogUtils.getLogger();
public static final FlwForgeConfig INSTANCE = new FlwForgeConfig();
public final ClientConfig client;
private final ForgeConfigSpec clientSpec;
private FlwForgeConfig() {
Pair<ClientConfig, ForgeConfigSpec> clientPair = new ForgeConfigSpec.Builder().configure(ClientConfig::new);
this.client = clientPair.getLeft();
clientSpec = clientPair.getRight();
}
public Backend getBackend() {
Backend backend = parseBackend(client.backend.get());
if (backend == null) {
backend = BackendManager.getDefaultBackend();
client.backend.set(Backend.REGISTRY.getIdOrThrow(backend).toString());
}
return backend;
}
@Nullable
private static Backend parseBackend(String idStr) {
ResourceLocation backendId;
try {
backendId = new ResourceLocation(idStr);
} catch (ResourceLocationException e) {
LOGGER.warn("Config contains invalid backend ID '" + idStr + "'!");
return null;
}
Backend backend = Backend.REGISTRY.get(backendId);
if (backend == null) {
LOGGER.warn("Config contains non-existent backend with ID '" + backendId + "'!");
return null;
}
return backend;
}
public boolean limitUpdates() {
return client.limitUpdates.get();
}
public int workerThreads() {
return client.workerThreads.get();
}
public void registerSpecs(ModLoadingContext context) {
context.registerConfig(ModConfig.Type.CLIENT, clientSpec);
}
public static class ClientConfig {
public final ForgeConfigSpec.ConfigValue<String> backend;
public final ForgeConfigSpec.BooleanValue limitUpdates;
public final ForgeConfigSpec.IntValue workerThreads;
private ClientConfig(ForgeConfigSpec.Builder builder) {
backend = builder.comment("Select the backend to use.")
.define("backend", Backend.REGISTRY.getIdOrThrow(BackendManager.getDefaultBackend()).toString());
limitUpdates = builder.comment("Enable or disable instance update limiting with distance.")
.define("limitUpdates", true);
workerThreads = builder.comment("The number of worker threads to use. Set to -1 to let Flywheel decide. Set to 0 to disable parallelism. Requires a game restart to take effect.")
.defineInRange("workerThreads", -1, -1, Runtime.getRuntime()
.availableProcessors());
}
}
}

View File

@ -0,0 +1,28 @@
package com.jozufozu.flywheel.impl;
import com.jozufozu.flywheel.api.event.EndClientResourceReloadEvent;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl;
import net.minecraft.client.multiplayer.ClientLevel;
public class BackendEventHandler {
public static void onEndClientResourceReload(EndClientResourceReloadEvent event) {
if (event.error()
.isPresent()) {
return;
}
BackendManagerImpl.chooseBackend();
VisualizationManagerImpl.resetAll();
}
public static void onReloadLevelRenderer(ReloadLevelRendererEvent event) {
BackendManagerImpl.chooseBackend();
ClientLevel level = event.level();
if (level != null) {
VisualizationManagerImpl.reset(level);
}
}
}

View File

@ -0,0 +1,21 @@
package com.jozufozu.flywheel.lib.model.baked;
import com.mojang.blaze3d.vertex.BufferBuilder;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
class ForgeMeshEmitter extends MeshEmitter {
ForgeMeshEmitter(BufferBuilder bufferBuilder, RenderType renderType) {
super(bufferBuilder, renderType);
}
// Forge has another putBulkData that we need to override
@Override
public void putBulkData(PoseStack.Pose matrixEntry, BakedQuad quad, float[] baseBrightness, float red, float green, float blue, float alpha, int[] lightmapCoords, int overlayCoords, boolean readExistingColor) {
observeQuadAndEmitIfNecessary(quad);
bufferBuilder.putBulkData(matrixEntry, quad, baseBrightness, red, green, blue, alpha, lightmapCoords, overlayCoords, readExistingColor);
}
}

View File

@ -7,10 +7,14 @@ import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.event.RenderStageEvent;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.config.FlwForgeConfig;
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
import net.irisshaders.iris.api.v0.IrisApi;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.ModList;
@ -57,4 +61,14 @@ public class ClientPlatformImpl extends ClientPlatform {
return null;
}
}
@Override
public int getLightEmission(BlockState state, ClientLevel level, BlockPos pos) {
return state.getLightEmission(level, pos);
}
@Override
public FlwConfig getConfigInstance() {
return FlwForgeConfig.INSTANCE;
}
}