mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Light updated
- Promote LightUpdater to the API. - Include LightUpdater in VisualizationContext. - Explicitly launch a plan to run light updates. - Misc tweaks: - The tick/frame limiters are now shared between visual managers. - The VisualizationManager assembles the frame/tick plans itself to avoid duplicate context mapping and to allow for reorganization in later commits.
This commit is contained in:
parent
f9e5d33296
commit
91738e38a8
18 changed files with 209 additions and 227 deletions
|
@ -21,7 +21,6 @@ import com.jozufozu.flywheel.impl.RegistryImpl;
|
||||||
import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler;
|
import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler;
|
||||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||||
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
|
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
|
||||||
import com.jozufozu.flywheel.lib.light.LightUpdater;
|
|
||||||
import com.jozufozu.flywheel.lib.material.CutoutShaders;
|
import com.jozufozu.flywheel.lib.material.CutoutShaders;
|
||||||
import com.jozufozu.flywheel.lib.material.FogShaders;
|
import com.jozufozu.flywheel.lib.material.FogShaders;
|
||||||
import com.jozufozu.flywheel.lib.material.StandardMaterialShaders;
|
import com.jozufozu.flywheel.lib.material.StandardMaterialShaders;
|
||||||
|
@ -97,7 +96,6 @@ public class Flywheel {
|
||||||
|
|
||||||
forgeEventBus.addListener(Uniforms::onReloadLevelRenderer);
|
forgeEventBus.addListener(Uniforms::onReloadLevelRenderer);
|
||||||
|
|
||||||
forgeEventBus.addListener(LightUpdater::onClientTick);
|
|
||||||
forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.onUnloadLevel(e));
|
forgeEventBus.addListener((LevelEvent.Unload e) -> LevelAttached.onUnloadLevel(e));
|
||||||
|
|
||||||
// forgeEventBus.addListener(ExampleEffect::tick);
|
// forgeEventBus.addListener(ExampleEffect::tick);
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package com.jozufozu.flywheel.api.visualization;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.lib.light.LightListener;
|
||||||
|
|
||||||
|
public interface LightUpdater {
|
||||||
|
void addListener(LightListener listener);
|
||||||
|
|
||||||
|
void removeListener(LightListener listener);
|
||||||
|
}
|
|
@ -11,5 +11,5 @@ import net.minecraft.core.Vec3i;
|
||||||
* @param renderOrigin The origin of the renderer as a world position.
|
* @param renderOrigin The origin of the renderer as a world position.
|
||||||
* All models render as if this position is (0, 0, 0).
|
* All models render as if this position is (0, 0, 0).
|
||||||
*/
|
*/
|
||||||
public record VisualizationContext(InstancerProvider instancerProvider, Vec3i renderOrigin) {
|
public record VisualizationContext(InstancerProvider instancerProvider, LightUpdater lightUpdater, Vec3i renderOrigin) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.impl.visualization;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@ -16,20 +17,30 @@ import com.jozufozu.flywheel.api.task.TaskExecutor;
|
||||||
import com.jozufozu.flywheel.api.visual.DynamicVisual;
|
import com.jozufozu.flywheel.api.visual.DynamicVisual;
|
||||||
import com.jozufozu.flywheel.api.visual.Effect;
|
import com.jozufozu.flywheel.api.visual.Effect;
|
||||||
import com.jozufozu.flywheel.api.visual.TickableVisual;
|
import com.jozufozu.flywheel.api.visual.TickableVisual;
|
||||||
|
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
||||||
|
import com.jozufozu.flywheel.api.visual.VisualTickContext;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualManager;
|
import com.jozufozu.flywheel.api.visualization.VisualManager;
|
||||||
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationLevel;
|
import com.jozufozu.flywheel.api.visualization.VisualizationLevel;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
|
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
|
||||||
|
import com.jozufozu.flywheel.config.FlwConfig;
|
||||||
import com.jozufozu.flywheel.extension.LevelExtension;
|
import com.jozufozu.flywheel.extension.LevelExtension;
|
||||||
import com.jozufozu.flywheel.impl.task.FlwTaskExecutor;
|
import com.jozufozu.flywheel.impl.task.FlwTaskExecutor;
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityStorage;
|
import com.jozufozu.flywheel.impl.visualization.manager.BlockEntityStorage;
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.EffectStorage;
|
import com.jozufozu.flywheel.impl.visualization.manager.EffectStorage;
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.EntityStorage;
|
import com.jozufozu.flywheel.impl.visualization.manager.EntityStorage;
|
||||||
import com.jozufozu.flywheel.impl.visualization.manager.VisualManagerImpl;
|
import com.jozufozu.flywheel.impl.visualization.manager.VisualManagerImpl;
|
||||||
|
import com.jozufozu.flywheel.impl.visualization.ratelimit.BandedPrimeLimiter;
|
||||||
|
import com.jozufozu.flywheel.impl.visualization.ratelimit.DistanceUpdateLimiterImpl;
|
||||||
|
import com.jozufozu.flywheel.impl.visualization.ratelimit.NonLimiter;
|
||||||
|
import com.jozufozu.flywheel.lib.light.LightUpdaterImpl;
|
||||||
import com.jozufozu.flywheel.lib.task.Flag;
|
import com.jozufozu.flywheel.lib.task.Flag;
|
||||||
import com.jozufozu.flywheel.lib.task.IfElsePlan;
|
import com.jozufozu.flywheel.lib.task.IfElsePlan;
|
||||||
import com.jozufozu.flywheel.lib.task.MapContextPlan;
|
import com.jozufozu.flywheel.lib.task.MapContextPlan;
|
||||||
import com.jozufozu.flywheel.lib.task.NamedFlag;
|
import com.jozufozu.flywheel.lib.task.NamedFlag;
|
||||||
|
import com.jozufozu.flywheel.lib.task.NestedPlan;
|
||||||
import com.jozufozu.flywheel.lib.task.RaisePlan;
|
import com.jozufozu.flywheel.lib.task.RaisePlan;
|
||||||
|
import com.jozufozu.flywheel.lib.task.SimplePlan;
|
||||||
import com.jozufozu.flywheel.lib.util.LevelAttached;
|
import com.jozufozu.flywheel.lib.util.LevelAttached;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
@ -44,11 +55,12 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
/**
|
/**
|
||||||
* A manager class for a single world where visualization is supported.
|
* A manager class for a single world where visualization is supported.
|
||||||
*/
|
*/
|
||||||
public class VisualizationManagerImpl implements VisualizationManager {
|
public class VisualizationManagerImpl implements VisualizationManager, Supplier<VisualizationContext> {
|
||||||
private static final LevelAttached<VisualizationManagerImpl> MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete);
|
private static final LevelAttached<VisualizationManagerImpl> MANAGERS = new LevelAttached<>(VisualizationManagerImpl::new, VisualizationManagerImpl::delete);
|
||||||
|
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final TaskExecutor taskExecutor;
|
private final TaskExecutor taskExecutor;
|
||||||
|
private final LightUpdaterImpl lightUpdater;
|
||||||
|
|
||||||
private final VisualManagerImpl<BlockEntity, BlockEntityStorage> blockEntities;
|
private final VisualManagerImpl<BlockEntity, BlockEntityStorage> blockEntities;
|
||||||
private final VisualManagerImpl<Entity, EntityStorage> entities;
|
private final VisualManagerImpl<Entity, EntityStorage> entities;
|
||||||
|
@ -61,18 +73,30 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
private final Flag frameVisualsFlag = new NamedFlag("frameVisualUpdates");
|
private final Flag frameVisualsFlag = new NamedFlag("frameVisualUpdates");
|
||||||
private final Flag frameFlag = new NamedFlag("frameComplete");
|
private final Flag frameFlag = new NamedFlag("frameComplete");
|
||||||
|
|
||||||
|
protected DistanceUpdateLimiterImpl tickLimiter;
|
||||||
|
protected DistanceUpdateLimiterImpl frameLimiter;
|
||||||
|
|
||||||
private VisualizationManagerImpl(LevelAccessor level) {
|
private VisualizationManagerImpl(LevelAccessor level) {
|
||||||
|
tickLimiter = createUpdateLimiter();
|
||||||
|
frameLimiter = createUpdateLimiter();
|
||||||
|
|
||||||
engine = BackendManager.getBackend()
|
engine = BackendManager.getBackend()
|
||||||
.createEngine(level);
|
.createEngine(level);
|
||||||
taskExecutor = FlwTaskExecutor.get();
|
taskExecutor = FlwTaskExecutor.get();
|
||||||
|
lightUpdater = new LightUpdaterImpl();
|
||||||
|
|
||||||
blockEntities = new VisualManagerImpl<>(new BlockEntityStorage(engine));
|
blockEntities = new VisualManagerImpl<>(new BlockEntityStorage(this));
|
||||||
entities = new VisualManagerImpl<>(new EntityStorage(engine));
|
entities = new VisualManagerImpl<>(new EntityStorage(this));
|
||||||
effects = new VisualManagerImpl<>(new EffectStorage(engine));
|
effects = new VisualManagerImpl<>(new EffectStorage(this));
|
||||||
|
|
||||||
tickPlan = blockEntities.createTickPlan()
|
tickPlan = MapContextPlan.map(this::createVisualTickContext)
|
||||||
.and(entities.createTickPlan())
|
.to(NestedPlan.of(SimplePlan.<VisualTickContext>of(context -> blockEntities.processQueue(0))
|
||||||
.and(effects.createTickPlan())
|
.then(blockEntities.getStorage()
|
||||||
|
.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> entities.processQueue(0))
|
||||||
|
.then(entities.getStorage()
|
||||||
|
.getTickPlan()), SimplePlan.<VisualTickContext>of(context -> effects.processQueue(0))
|
||||||
|
.then(effects.getStorage()
|
||||||
|
.getTickPlan())))
|
||||||
.then(RaisePlan.raise(tickFlag))
|
.then(RaisePlan.raise(tickFlag))
|
||||||
.simplify();
|
.simplify();
|
||||||
|
|
||||||
|
@ -81,11 +105,16 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
.to(blockEntities.createRecreationPlan()
|
.to(blockEntities.createRecreationPlan()
|
||||||
.and(entities.createRecreationPlan())
|
.and(entities.createRecreationPlan())
|
||||||
.and(effects.createRecreationPlan())))
|
.and(effects.createRecreationPlan())))
|
||||||
.ifFalse(MapContextPlan.map((RenderContext ctx) -> FrameContext.create(ctx, engine.renderOrigin()))
|
.ifFalse(MapContextPlan.map((RenderContext ctx) -> createVisualContext(FrameContext.create(ctx, engine.renderOrigin())))
|
||||||
.to(blockEntities.createFramePlan()
|
.to(NestedPlan.of(SimplePlan.<VisualFrameContext>of(context -> blockEntities.processQueue(context.partialTick()))
|
||||||
.and(entities.createFramePlan())
|
.then(blockEntities.getStorage()
|
||||||
.and(effects.createFramePlan())))
|
.getFramePlan()), SimplePlan.<VisualFrameContext>of(context -> entities.processQueue(context.partialTick()))
|
||||||
|
.then(entities.getStorage()
|
||||||
|
.getFramePlan()), SimplePlan.<VisualFrameContext>of(context -> effects.processQueue(context.partialTick()))
|
||||||
|
.then(effects.getStorage()
|
||||||
|
.getFramePlan()))))
|
||||||
.plan()
|
.plan()
|
||||||
|
.then(lightUpdater.plan())
|
||||||
.then(RaisePlan.raise(frameVisualsFlag))
|
.then(RaisePlan.raise(frameVisualsFlag))
|
||||||
.then(engine.createFramePlan())
|
.then(engine.createFramePlan())
|
||||||
.then(RaisePlan.raise(frameFlag))
|
.then(RaisePlan.raise(frameFlag))
|
||||||
|
@ -97,6 +126,23 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private VisualFrameContext createVisualContext(FrameContext ctx) {
|
||||||
|
return new VisualFrameContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), ctx.frustum(), ctx.partialTick(), frameLimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VisualTickContext createVisualTickContext(TickContext ctx) {
|
||||||
|
return new VisualTickContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), frameLimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DistanceUpdateLimiterImpl createUpdateLimiter() {
|
||||||
|
if (FlwConfig.get()
|
||||||
|
.limitUpdates()) {
|
||||||
|
return new BandedPrimeLimiter();
|
||||||
|
} else {
|
||||||
|
return new NonLimiter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean supportsVisualization(@Nullable LevelAccessor level) {
|
public static boolean supportsVisualization(@Nullable LevelAccessor level) {
|
||||||
if (!BackendManager.isOn()) {
|
if (!BackendManager.isOn()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -136,14 +182,19 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
|
|
||||||
// TODO: Consider making these reset actions reuse the existing game objects instead of re-adding them
|
// TODO: Consider making these reset actions reuse the existing game objects instead of re-adding them
|
||||||
// potentially by keeping the same VisualizationManagerImpl and deleting the engine and visuals but not the game objects
|
// potentially by keeping the same VisualizationManagerImpl and deleting the engine and visuals but not the game objects
|
||||||
|
|
||||||
public static void reset(LevelAccessor level) {
|
public static void reset(LevelAccessor level) {
|
||||||
MANAGERS.remove(level);
|
MANAGERS.remove(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void resetAll() {
|
public static void resetAll() {
|
||||||
MANAGERS.reset();
|
MANAGERS.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VisualizationContext get() {
|
||||||
|
return new VisualizationContext(engine, lightUpdater, engine.renderOrigin());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vec3i getRenderOrigin() {
|
public Vec3i getRenderOrigin() {
|
||||||
return engine.renderOrigin();
|
return engine.renderOrigin();
|
||||||
|
@ -164,6 +215,10 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
return effects;
|
return effects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LightUpdaterImpl getLightUpdater() {
|
||||||
|
return lightUpdater;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tick the visuals after the game has ticked:
|
* Tick the visuals after the game has ticked:
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -178,6 +233,10 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
taskExecutor.syncUntil(tickFlag::isRaised);
|
taskExecutor.syncUntil(tickFlag::isRaised);
|
||||||
tickFlag.lower();
|
tickFlag.lower();
|
||||||
|
|
||||||
|
tickLimiter.tick();
|
||||||
|
|
||||||
|
lightUpdater.tick();
|
||||||
|
|
||||||
tickPlan.execute(taskExecutor, new TickContext(cameraX, cameraY, cameraZ));
|
tickPlan.execute(taskExecutor, new TickContext(cameraX, cameraY, cameraZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +255,8 @@ public class VisualizationManagerImpl implements VisualizationManager {
|
||||||
|
|
||||||
frameVisualsFlag.lower();
|
frameVisualsFlag.lower();
|
||||||
frameFlag.lower();
|
frameFlag.lower();
|
||||||
|
|
||||||
|
frameLimiter.tick();
|
||||||
framePlan.execute(taskExecutor, context);
|
framePlan.execute(taskExecutor, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.jozufozu.flywheel.impl.visualization.manager;
|
package com.jozufozu.flywheel.impl.visualization.manager;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.backend.Engine;
|
|
||||||
import com.jozufozu.flywheel.api.visual.BlockEntityVisual;
|
import com.jozufozu.flywheel.api.visual.BlockEntityVisual;
|
||||||
import com.jozufozu.flywheel.api.visual.Visual;
|
import com.jozufozu.flywheel.api.visual.Visual;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
|
@ -19,8 +20,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
public class BlockEntityStorage extends Storage<BlockEntity> {
|
public class BlockEntityStorage extends Storage<BlockEntity> {
|
||||||
private final Long2ObjectMap<BlockEntityVisual<?>> posLookup = new Long2ObjectOpenHashMap<>();
|
private final Long2ObjectMap<BlockEntityVisual<?>> posLookup = new Long2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
public BlockEntityStorage(Engine engine) {
|
public BlockEntityStorage(Supplier<VisualizationContext> visualizationContextSupplier) {
|
||||||
super(engine);
|
super(visualizationContextSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BlockEntityVisual<?> visualAtPos(long pos) {
|
public BlockEntityVisual<?> visualAtPos(long pos) {
|
||||||
|
@ -59,7 +60,7 @@ public class BlockEntityStorage extends Storage<BlockEntity> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var visual = visualizer.createVisual(new VisualizationContext(engine, engine.renderOrigin()), obj);
|
var visual = visualizer.createVisual(visualizationContextSupplier.get(), obj);
|
||||||
|
|
||||||
BlockPos blockPos = obj.getBlockPos();
|
BlockPos blockPos = obj.getBlockPos();
|
||||||
posLookup.put(blockPos.asLong(), visual);
|
posLookup.put(blockPos.asLong(), visual);
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
package com.jozufozu.flywheel.impl.visualization.manager;
|
package com.jozufozu.flywheel.impl.visualization.manager;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.backend.Engine;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.visual.Effect;
|
import com.jozufozu.flywheel.api.visual.Effect;
|
||||||
import com.jozufozu.flywheel.api.visual.EffectVisual;
|
import com.jozufozu.flywheel.api.visual.EffectVisual;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
import com.jozufozu.flywheel.impl.visualization.storage.Storage;
|
import com.jozufozu.flywheel.impl.visualization.storage.Storage;
|
||||||
|
|
||||||
public class EffectStorage extends Storage<Effect> {
|
public class EffectStorage extends Storage<Effect> {
|
||||||
public EffectStorage(Engine engine) {
|
public EffectStorage(Supplier<VisualizationContext> visualizationContextSupplier) {
|
||||||
super(engine);
|
super(visualizationContextSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected EffectVisual<?> createRaw(Effect obj) {
|
protected EffectVisual<?> createRaw(Effect obj) {
|
||||||
return obj.visualize(new VisualizationContext(engine, engine.renderOrigin()));
|
return obj.visualize(visualizationContextSupplier.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package com.jozufozu.flywheel.impl.visualization.manager;
|
package com.jozufozu.flywheel.impl.visualization.manager;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.backend.Engine;
|
|
||||||
import com.jozufozu.flywheel.api.visual.Visual;
|
import com.jozufozu.flywheel.api.visual.Visual;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
import com.jozufozu.flywheel.impl.visualization.VisualizationHelper;
|
import com.jozufozu.flywheel.impl.visualization.VisualizationHelper;
|
||||||
|
@ -12,8 +13,8 @@ import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
public class EntityStorage extends Storage<Entity> {
|
public class EntityStorage extends Storage<Entity> {
|
||||||
public EntityStorage(Engine engine) {
|
public EntityStorage(Supplier<VisualizationContext> visualizationContextSupplier) {
|
||||||
super(engine);
|
super(visualizationContextSupplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,7 +25,7 @@ public class EntityStorage extends Storage<Entity> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return visualizer.createVisual(new VisualizationContext(engine, engine.renderOrigin()), obj);
|
return visualizer.createVisual(visualizationContextSupplier.get(), obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,31 +4,17 @@ import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.task.Plan;
|
import com.jozufozu.flywheel.api.task.Plan;
|
||||||
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
|
||||||
import com.jozufozu.flywheel.api.visual.VisualTickContext;
|
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualManager;
|
import com.jozufozu.flywheel.api.visualization.VisualManager;
|
||||||
import com.jozufozu.flywheel.config.FlwConfig;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.FrameContext;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.TickContext;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.ratelimit.BandedPrimeLimiter;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.ratelimit.DistanceUpdateLimiterImpl;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.ratelimit.NonLimiter;
|
|
||||||
import com.jozufozu.flywheel.impl.visualization.storage.Storage;
|
import com.jozufozu.flywheel.impl.visualization.storage.Storage;
|
||||||
import com.jozufozu.flywheel.impl.visualization.storage.Transaction;
|
import com.jozufozu.flywheel.impl.visualization.storage.Transaction;
|
||||||
import com.jozufozu.flywheel.lib.task.MapContextPlan;
|
|
||||||
import com.jozufozu.flywheel.lib.task.SimplePlan;
|
import com.jozufozu.flywheel.lib.task.SimplePlan;
|
||||||
|
|
||||||
public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager<T> {
|
public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager<T> {
|
||||||
private final Queue<Transaction<T>> queue = new ConcurrentLinkedQueue<>();
|
private final Queue<Transaction<T>> queue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
protected DistanceUpdateLimiterImpl tickLimiter;
|
|
||||||
protected DistanceUpdateLimiterImpl frameLimiter;
|
|
||||||
|
|
||||||
protected final S storage;
|
protected final S storage;
|
||||||
|
|
||||||
public VisualManagerImpl(S storage) {
|
public VisualManagerImpl(S storage) {
|
||||||
tickLimiter = createUpdateLimiter();
|
|
||||||
frameLimiter = createUpdateLimiter();
|
|
||||||
this.storage = storage;
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,15 +22,6 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DistanceUpdateLimiterImpl createUpdateLimiter() {
|
|
||||||
if (FlwConfig.get()
|
|
||||||
.limitUpdates()) {
|
|
||||||
return new BandedPrimeLimiter();
|
|
||||||
} else {
|
|
||||||
return new NonLimiter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getVisualCount() {
|
public int getVisualCount() {
|
||||||
return getStorage().getAllVisuals().size();
|
return getStorage().getAllVisuals().size();
|
||||||
|
@ -81,7 +58,7 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
|
||||||
getStorage().invalidate();
|
getStorage().invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processQueue(float partialTick) {
|
public void processQueue(float partialTick) {
|
||||||
var storage = getStorage();
|
var storage = getStorage();
|
||||||
Transaction<T> transaction;
|
Transaction<T> transaction;
|
||||||
while ((transaction = queue.poll()) != null) {
|
while ((transaction = queue.poll()) != null) {
|
||||||
|
@ -89,29 +66,4 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Plan<TickContext> createTickPlan() {
|
|
||||||
return SimplePlan.<TickContext>of(() -> {
|
|
||||||
tickLimiter.tick();
|
|
||||||
processQueue(0);
|
|
||||||
})
|
|
||||||
.then(MapContextPlan.map(this::createVisualTickContext)
|
|
||||||
.to(getStorage().getTickPlan()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Plan<FrameContext> createFramePlan() {
|
|
||||||
return SimplePlan.<FrameContext>of(context -> {
|
|
||||||
frameLimiter.tick();
|
|
||||||
processQueue(context.partialTick());
|
|
||||||
})
|
|
||||||
.then(MapContextPlan.map(this::createVisualContext)
|
|
||||||
.to(getStorage().getFramePlan()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private VisualFrameContext createVisualContext(FrameContext ctx) {
|
|
||||||
return new VisualFrameContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), ctx.frustum(), ctx.partialTick(), frameLimiter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private VisualTickContext createVisualTickContext(TickContext ctx) {
|
|
||||||
return new VisualTickContext(ctx.cameraX(), ctx.cameraY(), ctx.cameraZ(), frameLimiter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.backend.Engine;
|
|
||||||
import com.jozufozu.flywheel.api.task.Plan;
|
import com.jozufozu.flywheel.api.task.Plan;
|
||||||
import com.jozufozu.flywheel.api.visual.DynamicVisual;
|
import com.jozufozu.flywheel.api.visual.DynamicVisual;
|
||||||
import com.jozufozu.flywheel.api.visual.PlannedVisual;
|
import com.jozufozu.flywheel.api.visual.PlannedVisual;
|
||||||
|
@ -15,12 +15,13 @@ import com.jozufozu.flywheel.api.visual.TickableVisual;
|
||||||
import com.jozufozu.flywheel.api.visual.Visual;
|
import com.jozufozu.flywheel.api.visual.Visual;
|
||||||
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
|
||||||
import com.jozufozu.flywheel.api.visual.VisualTickContext;
|
import com.jozufozu.flywheel.api.visual.VisualTickContext;
|
||||||
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
import com.jozufozu.flywheel.lib.task.ForEachPlan;
|
import com.jozufozu.flywheel.lib.task.ForEachPlan;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||||
|
|
||||||
public abstract class Storage<T> {
|
public abstract class Storage<T> {
|
||||||
protected final Engine engine;
|
protected final Supplier<VisualizationContext> visualizationContextSupplier;
|
||||||
protected final List<TickableVisual> tickableVisuals = new ArrayList<>();
|
protected final List<TickableVisual> tickableVisuals = new ArrayList<>();
|
||||||
protected final List<DynamicVisual> dynamicVisuals = new ArrayList<>();
|
protected final List<DynamicVisual> dynamicVisuals = new ArrayList<>();
|
||||||
protected final List<PlannedVisual> plannedVisuals = new ArrayList<>();
|
protected final List<PlannedVisual> plannedVisuals = new ArrayList<>();
|
||||||
|
@ -33,8 +34,8 @@ public abstract class Storage<T> {
|
||||||
|
|
||||||
private final Map<T, Visual> visuals = new Reference2ObjectOpenHashMap<>();
|
private final Map<T, Visual> visuals = new Reference2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
public Storage(Engine engine) {
|
public Storage(Supplier<VisualizationContext> visualizationContextSupplier) {
|
||||||
this.engine = engine;
|
this.visualizationContextSupplier = visualizationContextSupplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Visual> getAllVisuals() {
|
public Collection<Visual> getAllVisuals() {
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
package com.jozufozu.flywheel.lib.light;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.lib.box.Box;
|
|
||||||
|
|
||||||
import net.minecraft.core.SectionPos;
|
|
||||||
import net.minecraft.world.level.LightLayer;
|
|
||||||
|
|
||||||
public final class DummyLightUpdater extends LightUpdater {
|
|
||||||
public static final DummyLightUpdater INSTANCE = new DummyLightUpdater();
|
|
||||||
|
|
||||||
private DummyLightUpdater() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick() {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addListener(LightListener listener) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeListener(LightListener listener) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLightUpdate(LightLayer type, SectionPos pos) {
|
|
||||||
// noop
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<Box> getAllBoxes() {
|
|
||||||
return Stream.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,7 @@ import net.minecraft.world.level.LightLayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementors of this interface may choose to subscribe to light updates by calling
|
* Implementors of this interface may choose to subscribe to light updates by calling
|
||||||
* {@link LightUpdater#addListener(LightListener)}.<p>
|
* {@link LightUpdaterImpl#addListener(LightListener)}.<p>
|
||||||
*
|
*
|
||||||
* It is the responsibility of the implementor to keep a reference to the level an object is contained in.
|
* It is the responsibility of the implementor to keep a reference to the level an object is contained in.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
package com.jozufozu.flywheel.lib.light;
|
package com.jozufozu.flywheel.lib.light;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||||
|
import com.jozufozu.flywheel.api.task.Plan;
|
||||||
|
import com.jozufozu.flywheel.api.visualization.LightUpdater;
|
||||||
import com.jozufozu.flywheel.lib.box.Box;
|
import com.jozufozu.flywheel.lib.box.Box;
|
||||||
|
import com.jozufozu.flywheel.lib.task.ForEachPlan;
|
||||||
|
import com.jozufozu.flywheel.lib.task.IfElsePlan;
|
||||||
|
import com.jozufozu.flywheel.lib.task.SimplePlan;
|
||||||
import com.jozufozu.flywheel.lib.util.FlwUtil;
|
import com.jozufozu.flywheel.lib.util.FlwUtil;
|
||||||
import com.jozufozu.flywheel.lib.util.LevelAttached;
|
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraftforge.event.TickEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of what chunks/sections each listener is in, so we can update exactly what needs to be updated.
|
* Keeps track of what chunks/sections each listener is in, so we can update exactly what needs to be updated.
|
||||||
|
@ -24,35 +28,12 @@ import net.minecraftforge.event.TickEvent;
|
||||||
* @apiNote Custom/fake levels (that are {@code != Minecraft.getInstance.level}) need to implement
|
* @apiNote Custom/fake levels (that are {@code != Minecraft.getInstance.level}) need to implement
|
||||||
* {@link LightUpdatedLevel} for LightUpdater to work with them.
|
* {@link LightUpdatedLevel} for LightUpdater to work with them.
|
||||||
*/
|
*/
|
||||||
public class LightUpdater {
|
public class LightUpdaterImpl implements LightUpdater {
|
||||||
private static final LevelAttached<LightUpdater> UPDATERS = new LevelAttached<>(level -> new LightUpdater());
|
private final WeakHashMap<LightListener, LongSet> listenersAndTheirSections = new WeakHashMap<>();
|
||||||
|
|
||||||
private final WeakContainmentMultiMap<LightListener> listenersBySection = new WeakContainmentMultiMap<>();
|
|
||||||
private final Set<TickingLightListener> tickingListeners = FlwUtil.createWeakHashSet();
|
private final Set<TickingLightListener> tickingListeners = FlwUtil.createWeakHashSet();
|
||||||
|
|
||||||
private final Queue<LightListener> additionQueue = new ConcurrentLinkedQueue<>();
|
private final Queue<LightListener> additionQueue = new ConcurrentLinkedQueue<>();
|
||||||
|
private final LongSet sectionsQueue = new LongOpenHashSet();
|
||||||
public static boolean supports(LevelAccessor level) {
|
|
||||||
// The client level is guaranteed to receive updates.
|
|
||||||
if (Minecraft.getInstance().level == level) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Custom/fake levels need to indicate that LightUpdater has meaning.
|
|
||||||
if (level instanceof LightUpdatedLevel c) {
|
|
||||||
return c.receivesLightUpdates();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LightUpdater get(LevelAccessor level) {
|
|
||||||
if (supports(level)) {
|
|
||||||
// The level is valid, so add it to the map.
|
|
||||||
return UPDATERS.get(level);
|
|
||||||
} else {
|
|
||||||
// Fake light updater for a fake level.
|
|
||||||
return DummyLightUpdater.INSTANCE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a listener.
|
* Add a listener.
|
||||||
|
@ -64,48 +45,47 @@ public class LightUpdater {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeListener(LightListener listener) {
|
public void removeListener(LightListener listener) {
|
||||||
listenersBySection.remove(listener);
|
listenersAndTheirSections.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Plan<RenderContext> plan() {
|
||||||
* Dispatch light updates to all registered {@link LightListener}s.
|
// Assume we'll have more listeners than sections updated
|
||||||
*
|
// TODO: this is slow, maybe launch a task for each changed section and distribute from there?
|
||||||
* @param type The type of light that changed.
|
return SimplePlan.<RenderContext>of(this::processQueue)
|
||||||
* @param pos The section position where light changed.
|
.then(IfElsePlan.<RenderContext>on(() -> !sectionsQueue.isEmpty())
|
||||||
*/
|
.ifTrue(ForEachPlan.of(() -> listenersAndTheirSections.entrySet()
|
||||||
public void onLightUpdate(LightLayer type, SectionPos pos) {
|
.stream()
|
||||||
processQueue();
|
.toList(), this::updateOneEntry))
|
||||||
|
.plan())
|
||||||
|
.then(SimplePlan.of(() -> sectionsQueue.clear()));
|
||||||
|
}
|
||||||
|
|
||||||
Set<LightListener> listeners = listenersBySection.get(pos.asLong());
|
private void updateOneEntry(Map.Entry<LightListener, LongSet> entry) {
|
||||||
|
|
||||||
if (listeners == null || listeners.isEmpty()) {
|
updateOne(entry.getKey(), entry.getValue());
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
listeners.removeIf(LightListener::isInvalid);
|
}
|
||||||
|
|
||||||
for (LightListener listener : listeners) {
|
private void updateOne(LightListener listener, LongSet containedSections) {
|
||||||
listener.onLightUpdate(type, pos);
|
for (long l : containedSections.toLongArray()) {
|
||||||
|
if (sectionsQueue.contains(l)) {
|
||||||
|
listener.onLightUpdate(LightLayer.BLOCK, SectionPos.of(l));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream<Box> getAllBoxes() {
|
public Stream<Box> getAllBoxes() {
|
||||||
return listenersBySection.stream().map(LightListener::getVolume);
|
return listenersAndTheirSections.keySet()
|
||||||
|
.stream()
|
||||||
|
.map(LightListener::getVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return listenersBySection.isEmpty();
|
return listenersAndTheirSections.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiStatus.Internal
|
public void tick() {
|
||||||
public static void onClientTick(TickEvent.ClientTickEvent event) {
|
|
||||||
if (event.phase == TickEvent.Phase.END && FlwUtil.isGameActive()) {
|
|
||||||
get(Minecraft.getInstance().level)
|
|
||||||
.tick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tick() {
|
|
||||||
processQueue();
|
processQueue();
|
||||||
|
|
||||||
for (TickingLightListener tickingListener : tickingListeners) {
|
for (TickingLightListener tickingListener : tickingListeners) {
|
||||||
|
@ -129,7 +109,7 @@ public class LightUpdater {
|
||||||
|
|
||||||
Box box = listener.getVolume();
|
Box box = listener.getVolume();
|
||||||
|
|
||||||
LongSet sections = listenersBySection.getAndResetContainment(listener);
|
LongSet sections = new LongArraySet();
|
||||||
|
|
||||||
int minX = SectionPos.blockToSectionCoord(box.getMinX());
|
int minX = SectionPos.blockToSectionCoord(box.getMinX());
|
||||||
int minY = SectionPos.blockToSectionCoord(box.getMinY());
|
int minY = SectionPos.blockToSectionCoord(box.getMinY());
|
||||||
|
@ -141,11 +121,15 @@ public class LightUpdater {
|
||||||
for (int x = minX; x <= maxX; x++) {
|
for (int x = minX; x <= maxX; x++) {
|
||||||
for (int y = minY; y <= maxY; y++) {
|
for (int y = minY; y <= maxY; y++) {
|
||||||
for (int z = minZ; z <= maxZ; z++) {
|
for (int z = minZ; z <= maxZ; z++) {
|
||||||
long sectionPos = SectionPos.asLong(x, y, z);
|
sections.add(SectionPos.asLong(x, y, z));
|
||||||
listenersBySection.put(sectionPos, listener);
|
|
||||||
sections.add(sectionPos);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listenersAndTheirSections.put(listener, sections);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifySectionUpdates(LongSet sections) {
|
||||||
|
sectionsQueue.addAll(sections);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,7 +39,9 @@ class WeakContainmentMultiMap<T> extends AbstractCollection<T> {
|
||||||
containmentSet.forEach((LongConsumer) l -> {
|
containmentSet.forEach((LongConsumer) l -> {
|
||||||
Set<T> listeners = forward.get(l);
|
Set<T> listeners = forward.get(l);
|
||||||
|
|
||||||
if (listeners != null) listeners.remove(listener);
|
if (listeners != null) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
containmentSet.clear();
|
containmentSet.clear();
|
||||||
|
@ -63,7 +65,9 @@ class WeakContainmentMultiMap<T> extends AbstractCollection<T> {
|
||||||
containmentSet.forEach((LongConsumer) l -> {
|
containmentSet.forEach((LongConsumer) l -> {
|
||||||
Set<T> listeners = forward.get(l);
|
Set<T> listeners = forward.get(l);
|
||||||
|
|
||||||
if (listeners != null) listeners.remove(o);
|
if (listeners != null) {
|
||||||
|
listeners.remove(o);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
containmentSet.clear();
|
containmentSet.clear();
|
||||||
|
|
|
@ -7,7 +7,6 @@ import com.jozufozu.flywheel.api.visual.Visual;
|
||||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||||
import com.jozufozu.flywheel.lib.instance.FlatLit;
|
import com.jozufozu.flywheel.lib.instance.FlatLit;
|
||||||
import com.jozufozu.flywheel.lib.light.LightListener;
|
import com.jozufozu.flywheel.lib.light.LightListener;
|
||||||
import com.jozufozu.flywheel.lib.light.LightUpdater;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
|
@ -37,7 +36,8 @@ public abstract class AbstractVisual implements Visual, LightListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(float partialTick) {
|
public void init(float partialTick) {
|
||||||
LightUpdater.get(level).addListener(this);
|
visualizationContext.lightUpdater()
|
||||||
|
.addListener(this);
|
||||||
updateLight();
|
updateLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,8 @@ public abstract class AbstractVisual implements Visual, LightListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
_delete();
|
_delete();
|
||||||
|
visualizationContext.lightUpdater()
|
||||||
|
.removeListener(this);
|
||||||
deleted = true;
|
deleted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.jozufozu.flywheel.mixin;
|
||||||
|
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.impl.visualization.VisualizationManagerImpl;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||||
|
import net.minecraft.world.level.lighting.LayerLightSectionStorage;
|
||||||
|
|
||||||
|
@Mixin(LayerLightSectionStorage.class)
|
||||||
|
public abstract class LayerLightSectionStorageMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected LongSet sectionsAffectedByLightUpdates;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected LightChunkGetter chunkSource;
|
||||||
|
|
||||||
|
@Inject(at = @At("HEAD"), method = "swapSectionMap")
|
||||||
|
private void flywheel$listenForChangedSections(CallbackInfo ci) {
|
||||||
|
if (this.sectionsAffectedByLightUpdates.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var manager = VisualizationManagerImpl.get((LevelAccessor) this.chunkSource.getLevel());
|
||||||
|
|
||||||
|
if (manager != null) {
|
||||||
|
manager.getLightUpdater()
|
||||||
|
.notifySectionUpdates(this.sectionsAffectedByLightUpdates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,6 +49,11 @@ abstract class LevelRendererMixin {
|
||||||
|
|
||||||
@Inject(method = "renderLevel", at = @At("HEAD"))
|
@Inject(method = "renderLevel", at = @At("HEAD"))
|
||||||
private void flywheel$beginRender(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
|
private void flywheel$beginRender(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
|
||||||
|
// TODO: divide some work to here, light updates may take a while
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "renderLevel", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;runLightUpdates()I"))
|
||||||
|
private void flywheel$processLightUpdates(PoseStack poseStack, float partialTick, long finishNanoTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f projectionMatrix, CallbackInfo ci) {
|
||||||
flywheel$renderContext = RenderContext.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera, partialTick);
|
flywheel$renderContext = RenderContext.create((LevelRenderer) (Object) this, level, renderBuffers, poseStack, projectionMatrix, camera, partialTick);
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(flywheel$renderContext));
|
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(flywheel$renderContext));
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
package com.jozufozu.flywheel.mixin;
|
|
||||||
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import com.jozufozu.flywheel.lib.light.LightUpdater;
|
|
||||||
|
|
||||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
|
||||||
import net.minecraft.core.SectionPos;
|
|
||||||
import net.minecraft.world.level.LightLayer;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkSource;
|
|
||||||
|
|
||||||
@Mixin(ClientChunkCache.class)
|
|
||||||
abstract class LightUpdateMixin extends ChunkSource {
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
ClientLevel level;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JUSTIFICATION: This method is called after lighting updates are finished processing
|
|
||||||
* per section where a lighting change occurred that frame. On the client, Minecraft
|
|
||||||
* uses this method to inform the rendering system that it needs to redraw a chunk.
|
|
||||||
*/
|
|
||||||
@Inject(method = "onLightUpdate(Lnet/minecraft/world/level/LightLayer;Lnet/minecraft/core/SectionPos;)V", at = @At("HEAD"))
|
|
||||||
private void flywheel$onLightUpdate(LightLayer type, SectionPos pos, CallbackInfo ci) {
|
|
||||||
LightUpdater.get(level).onLightUpdate(type, pos);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -10,9 +10,9 @@
|
||||||
"EntityTypeMixin",
|
"EntityTypeMixin",
|
||||||
"FogUpdateMixin",
|
"FogUpdateMixin",
|
||||||
"GlStateManagerMixin",
|
"GlStateManagerMixin",
|
||||||
|
"LayerLightSectionStorageMixin",
|
||||||
"LevelMixin",
|
"LevelMixin",
|
||||||
"LevelRendererMixin",
|
"LevelRendererMixin",
|
||||||
"LightUpdateMixin",
|
|
||||||
"MinecraftMixin",
|
"MinecraftMixin",
|
||||||
"PoseStackMixin",
|
"PoseStackMixin",
|
||||||
"VertexFormatMixin",
|
"VertexFormatMixin",
|
||||||
|
|
Loading…
Reference in a new issue