Plans all the way down

- Remove PlannedVisual
- Dynamic/Tickable visuals create plans
- Add Simple*Visual to lib to replace the old api interfaces
- Better dynamic plan storage, no need to optimize on every change
- Special case the Simple*Visuals in Storage as to not lose performance
- Needs better documentation
- Add RunnablePlan
This commit is contained in:
Jozufozu 2024-02-16 21:17:17 -08:00
parent 464deff42e
commit dcecc9672d
21 changed files with 240 additions and 152 deletions

View file

@ -1,7 +1,6 @@
package com.jozufozu.flywheel.api.visual;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.task.Plan;
/**
* An interface giving {@link Visual}s a hook to have a function called at
@ -13,15 +12,5 @@ import com.jozufozu.flywheel.api.instance.Instancer;
* to parameterize the instances, you're encouraged to implement this for prototyping.
*/
public interface DynamicVisual extends Visual {
/**
* Called every frame.
* <br>
* The implementation is free to parallelize calls to this method.
* You must ensure proper synchronization if you need to mutate anything outside this visual.
* <br>
* This method and {@link TickableVisual#tick} will never be called simultaneously.
* <br>
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/
void beginFrame(VisualFrameContext ctx);
Plan<VisualFrameContext> planFrame();
}

View file

@ -1,17 +0,0 @@
package com.jozufozu.flywheel.api.visual;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.lib.task.UnitPlan;
/**
* An interface giving {@link Visual}s a way to define complex, parallelized update plans.
*/
public interface PlannedVisual extends Visual {
default Plan<VisualFrameContext> planFrame() {
return UnitPlan.of();
}
default Plan<VisualTickContext> planTick() {
return UnitPlan.of();
}
}

View file

@ -1,7 +1,6 @@
package com.jozufozu.flywheel.api.visual;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.task.Plan;
/**
* An interface giving {@link Visual}s a hook to have a function called at
@ -20,15 +19,5 @@ import com.jozufozu.flywheel.api.instance.Instancer;
* </ul>
*/
public interface TickableVisual extends Visual {
/**
* Called every tick.
* <br>
* The implementation is free to parallelize calls to this method.
* You must ensure proper synchronization if you need to mutate anything outside this visual.
* <br>
* This method and {@link DynamicVisual#beginFrame} will never be called simultaneously.
* <br>
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/
void tick(VisualTickContext ctx);
Plan<VisualTickContext> planTick();
}

View file

@ -5,7 +5,6 @@ package com.jozufozu.flywheel.api.visual;
*
* @see DynamicVisual
* @see TickableVisual
* @see PlannedVisual
* @see LitVisual
*/
public interface Visual {

View file

@ -66,11 +66,11 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
public Plan<VisualFrameContext> framePlan() {
return SimplePlan.<VisualFrameContext>of(context -> processQueue(context.partialTick()))
.then(storage.getFramePlan());
.then(storage.framePlan());
}
public Plan<VisualTickContext> tickPlan() {
return SimplePlan.<VisualTickContext>of(context -> processQueue(0))
.then(storage.getTickPlan());
.then(storage.tickPlan());
}
}

View file

@ -0,0 +1,35 @@
package com.jozufozu.flywheel.impl.visualization.storage;
import java.util.ArrayList;
import java.util.List;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.PlanUtil;
import com.jozufozu.flywheel.lib.task.SimplyComposedPlan;
import com.jozufozu.flywheel.lib.task.functional.ConsumerWithContext;
public class FastPlanStorage<T, C> implements SimplyComposedPlan<C> {
private final List<T> objects = new ArrayList<>();
private final ConsumerWithContext<T, C> consumer;
public FastPlanStorage(ConsumerWithContext<T, C> consumer) {
this.consumer = consumer;
}
public void add(T object) {
objects.add(object);
}
public void remove(T object) {
objects.remove(object);
}
public void clear() {
objects.clear();
}
@Override
public void execute(TaskExecutor taskExecutor, C context, Runnable onCompletion) {
PlanUtil.distribute(taskExecutor, context, onCompletion, objects, consumer);
}
}

View file

@ -0,0 +1,72 @@
package com.jozufozu.flywheel.impl.visualization.storage;
import java.util.ArrayList;
import java.util.List;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.PlanUtil;
import com.jozufozu.flywheel.lib.task.SimplyComposedPlan;
import com.jozufozu.flywheel.lib.task.Synchronizer;
public class PlanStorage<T, C> implements SimplyComposedPlan<C> {
private final List<T> objects = new ArrayList<>();
private final List<Plan<C>> plans = new ArrayList<>();
public void add(T object, Plan<C> plan) {
objects.add(object);
plans.add(plan);
}
public void remove(T object) {
int index = objects.indexOf(object);
if (index != -1) {
objects.remove(index);
plans.remove(index);
}
}
public void clear() {
objects.clear();
plans.clear();
}
@Override
public void execute(TaskExecutor taskExecutor, C context, Runnable onCompletion) {
final int size = plans.size();
if (size == 0) {
onCompletion.run();
return;
}
var synchronizer = new Synchronizer(size, onCompletion);
final int sliceSize = PlanUtil.sliceSize(taskExecutor, size, 8);
if (size <= sliceSize) {
for (var t : plans) {
t.execute(taskExecutor, context, synchronizer);
}
} else if (sliceSize == 1) {
for (var t : plans) {
taskExecutor.execute(() -> t.execute(taskExecutor, context, synchronizer));
}
} else {
int remaining = size;
while (remaining > 0) {
int end = remaining;
remaining -= sliceSize;
int start = Math.max(remaining, 0);
var subList = plans.subList(start, end);
taskExecutor.execute(() -> {
for (var t : subList) {
t.execute(taskExecutor, context, synchronizer);
}
});
}
}
}
}

View file

@ -1,8 +1,6 @@
package com.jozufozu.flywheel.impl.visualization.storage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
@ -11,29 +9,25 @@ import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.LitVisual;
import com.jozufozu.flywheel.api.visual.PlannedVisual;
import com.jozufozu.flywheel.api.visual.TickableVisual;
import com.jozufozu.flywheel.api.visual.Visual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
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.NestedPlan;
import com.jozufozu.flywheel.lib.visual.SimpleDynamicVisual;
import com.jozufozu.flywheel.lib.visual.SimpleTickableVisual;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
public abstract class Storage<T> {
protected final Supplier<VisualizationContext> visualizationContextSupplier;
protected final List<TickableVisual> tickableVisuals = new ArrayList<>();
protected final List<DynamicVisual> dynamicVisuals = new ArrayList<>();
protected final List<PlannedVisual> plannedVisuals = new ArrayList<>();
protected final PlanStorage<DynamicVisual, VisualFrameContext> dynamicVisuals = new PlanStorage<>();
protected final FastPlanStorage<SimpleDynamicVisual, VisualFrameContext> fastDynamicVisuals = new FastPlanStorage<>(SimpleDynamicVisual::beginFrame);
protected final PlanStorage<TickableVisual, VisualTickContext> tickableVisuals = new PlanStorage<>();
protected final FastPlanStorage<SimpleTickableVisual, VisualTickContext> fastTickableVisuals = new FastPlanStorage<>(SimpleTickableVisual::tick);
protected final LitVisualStorage litVisuals = new LitVisualStorage();
protected final VisualUpdatePlan<VisualFrameContext> framePlan = new VisualUpdatePlan<>(() -> plannedVisuals.stream()
.map(PlannedVisual::planFrame)
.toList());
protected final VisualUpdatePlan<VisualTickContext> tickPlan = new VisualUpdatePlan<>(() -> plannedVisuals.stream()
.map(PlannedVisual::planTick)
.toList());
private final Map<T, Visual> visuals = new Reference2ObjectOpenHashMap<>();
@ -61,15 +55,17 @@ public abstract class Storage<T> {
}
if (visual instanceof TickableVisual tickable) {
tickableVisuals.remove(tickable);
if (visual instanceof SimpleTickableVisual simpleTickable) {
fastTickableVisuals.remove(simpleTickable);
} else {
tickableVisuals.remove(tickable);
}
}
if (visual instanceof DynamicVisual dynamic) {
dynamicVisuals.remove(dynamic);
}
if (visual instanceof PlannedVisual planned) {
if (plannedVisuals.remove(planned)) {
framePlan.triggerReInitialize();
tickPlan.triggerReInitialize();
if (visual instanceof SimpleDynamicVisual simpleDynamic) {
fastDynamicVisuals.remove(simpleDynamic);
} else {
dynamicVisuals.remove(dynamic);
}
}
if (visual instanceof LitVisual lit) {
@ -98,8 +94,9 @@ public abstract class Storage<T> {
public void recreateAll(float partialTick) {
tickableVisuals.clear();
fastTickableVisuals.clear();
dynamicVisuals.clear();
plannedVisuals.clear();
fastDynamicVisuals.clear();
litVisuals.clear();
visuals.replaceAll((obj, visual) -> {
visual.delete();
@ -117,10 +114,7 @@ public abstract class Storage<T> {
public void invalidate() {
tickableVisuals.clear();
dynamicVisuals.clear();
plannedVisuals.clear();
litVisuals.clear();
framePlan.triggerReInitialize();
tickPlan.triggerReInitialize();
visuals.values()
.forEach(Visual::delete);
visuals.clear();
@ -138,13 +132,12 @@ public abstract class Storage<T> {
@Nullable
protected abstract Visual createRaw(T obj);
public Plan<VisualFrameContext> getFramePlan() {
return framePlan.and(ForEachPlan.of(() -> dynamicVisuals, DynamicVisual::beginFrame))
.and(litVisuals.plan());
public Plan<VisualFrameContext> framePlan() {
return NestedPlan.of(dynamicVisuals, fastDynamicVisuals, litVisuals.plan());
}
public Plan<VisualTickContext> getTickPlan() {
return tickPlan.and(ForEachPlan.of(() -> tickableVisuals, TickableVisual::tick));
public Plan<VisualTickContext> tickPlan() {
return NestedPlan.of(tickableVisuals, fastTickableVisuals);
}
public void enqueueLightUpdateSections(LongSet sections) {
@ -155,17 +148,19 @@ public abstract class Storage<T> {
visual.init(partialTick);
if (visual instanceof TickableVisual tickable) {
tickableVisuals.add(tickable);
if (visual instanceof SimpleTickableVisual simpleTickable) {
fastTickableVisuals.add(simpleTickable);
} else {
tickableVisuals.add(tickable, tickable.planTick());
}
}
if (visual instanceof DynamicVisual dynamic) {
dynamicVisuals.add(dynamic);
}
if (visual instanceof PlannedVisual planned) {
plannedVisuals.add(planned);
framePlan.add(planned.planFrame());
tickPlan.add(planned.planTick());
if (visual instanceof SimpleDynamicVisual simpleDynamic) {
fastDynamicVisuals.add(simpleDynamic);
} else {
dynamicVisuals.add(dynamic, dynamic.planFrame());
}
}
if (visual instanceof LitVisual lit) {

View file

@ -1,51 +0,0 @@
package com.jozufozu.flywheel.impl.visualization.storage;
import java.util.List;
import java.util.function.Supplier;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.NestedPlan;
import com.jozufozu.flywheel.lib.task.SimplyComposedPlan;
import com.jozufozu.flywheel.lib.task.UnitPlan;
public class VisualUpdatePlan<C> implements SimplyComposedPlan<C> {
private final Supplier<List<Plan<C>>> initializer;
private Plan<C> plan = UnitPlan.of();
private boolean initialized = false;
private boolean needsSimplify = true;
public VisualUpdatePlan(Supplier<List<Plan<C>>> initializer) {
this.initializer = initializer;
}
@Override
public void execute(TaskExecutor taskExecutor, C context, Runnable onCompletion) {
updatePlans().execute(taskExecutor, context, onCompletion);
}
public void add(Plan<C> plan) {
this.plan = this.plan.and(plan);
needsSimplify = true;
}
private Plan<C> updatePlans() {
if (!initialized) {
Plan<C> mainPlan = new NestedPlan<>(initializer.get());
plan = mainPlan.and(plan);
plan = plan.simplify();
initialized = true;
} else if (needsSimplify) {
plan = plan.simplify();
}
needsSimplify = false;
return plan;
}
public void triggerReInitialize() {
plan = UnitPlan.of();
initialized = false;
}
}

View file

@ -91,7 +91,11 @@ public final class PlanUtil {
}
public static int sliceSize(TaskExecutor taskExecutor, int totalSize) {
return MoreMath.ceilingDiv(totalSize, taskExecutor.getThreadCount() * 32);
return sliceSize(taskExecutor, totalSize, 32);
}
public static int sliceSize(TaskExecutor taskExecutor, int totalSize, int denominator) {
return MoreMath.ceilingDiv(totalSize, taskExecutor.getThreadCount() * denominator);
}
private PlanUtil() {

View file

@ -0,0 +1,20 @@
package com.jozufozu.flywheel.lib.task;
import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.lib.task.functional.RunnableWithContext;
public record RunnablePlan<C>(RunnableWithContext<C> runnable) implements SimplyComposedPlan<C> {
public static <C> RunnablePlan<C> of(RunnableWithContext<C> runnable) {
return new RunnablePlan<>(runnable);
}
public static <C> RunnablePlan<C> of(RunnableWithContext.Ignored<C> runnable) {
return new RunnablePlan<>(runnable);
}
@Override
public void execute(TaskExecutor taskExecutor, C context, Runnable onCompletion) {
runnable.accept(context);
onCompletion.run();
}
}

View file

@ -8,7 +8,6 @@ import org.joml.FrustumIntersection;
import com.jozufozu.flywheel.api.visual.BlockEntityVisual;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.LitVisual;
import com.jozufozu.flywheel.api.visual.PlannedVisual;
import com.jozufozu.flywheel.api.visual.TickableVisual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualManager;
@ -27,7 +26,6 @@ import net.minecraft.world.level.block.state.BlockState;
* <ul>
* <li>{@link DynamicVisual}</li>
* <li>{@link TickableVisual}</li>
* <li>{@link PlannedVisual}</li>
* </ul>
* See the interfaces' documentation for more information about each one.
*

View file

@ -5,7 +5,6 @@ import org.joml.Vector3f;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.EntityVisual;
import com.jozufozu.flywheel.api.visual.PlannedVisual;
import com.jozufozu.flywheel.api.visual.TickableVisual;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.api.visualization.VisualizationManager;
@ -21,7 +20,6 @@ import net.minecraft.world.phys.Vec3;
* <ul>
* <li>{@link DynamicVisual}</li>
* <li>{@link TickableVisual}</li>
* <li>{@link PlannedVisual}</li>
* </ul>
* See the interfaces' documentation for more information about each one.
*

View file

@ -0,0 +1,28 @@
package com.jozufozu.flywheel.lib.visual;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.TickableVisual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.lib.task.RunnablePlan;
public interface SimpleDynamicVisual extends DynamicVisual {
/**
* Called every frame.
* <br>
* The implementation is free to parallelize calls to this method.
* You must ensure proper synchronization if you need to mutate anything outside this visual.
* <br>
* This method and {@link TickableVisual#tick} will never be called simultaneously.
* <br>
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/
void beginFrame(VisualFrameContext ctx);
@Override
default Plan<VisualFrameContext> planFrame() {
return RunnablePlan.of(this::beginFrame);
}
}

View file

@ -3,13 +3,12 @@ package com.jozufozu.flywheel.lib.visual;
import java.util.ArrayList;
import java.util.List;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import net.minecraft.world.entity.Entity;
public class SimpleEntityVisual<T extends Entity> extends AbstractEntityVisual<T> implements DynamicVisual {
public class SimpleEntityVisual<T extends Entity> extends AbstractEntityVisual<T> implements SimpleDynamicVisual {
protected final List<EntityComponent> components = new ArrayList<>();
public SimpleEntityVisual(VisualizationContext ctx, T entity) {

View file

@ -0,0 +1,29 @@
package com.jozufozu.flywheel.lib.visual;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.instance.Instancer;
import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.TickableVisual;
import com.jozufozu.flywheel.api.visual.VisualTickContext;
import com.jozufozu.flywheel.lib.task.RunnablePlan;
public interface SimpleTickableVisual extends TickableVisual {
/**
* Called every tick.
* <br>
* The implementation is free to parallelize calls to this method.
* You must ensure proper synchronization if you need to mutate anything outside this visual.
* <br>
* This method and {@link DynamicVisual#beginFrame} will never be called simultaneously.
* <br>
* {@link Instancer}/{@link Instance} creation/acquisition is safe here.
*/
void tick(VisualTickContext ctx);
@Override
default Plan<VisualTickContext> planTick() {
return RunnablePlan.of(this::tick);
}
}

View file

@ -7,7 +7,6 @@ import org.joml.Quaternionf;
import org.joml.Vector3f;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
@ -17,13 +16,14 @@ import com.jozufozu.flywheel.lib.model.ModelHolder;
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual;
import com.jozufozu.flywheel.lib.visual.SimpleDynamicVisual;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.renderer.blockentity.BellRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.entity.BellBlockEntity;
public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> implements DynamicVisual {
public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> implements SimpleDynamicVisual {
private static final ModelHolder BELL_MODEL = new ModelHolder(() -> {
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), Materials.BELL);
});

View file

@ -8,7 +8,6 @@ import java.util.function.Consumer;
import org.joml.Quaternionf;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
@ -20,6 +19,7 @@ import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.util.Pair;
import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual;
import com.jozufozu.flywheel.lib.visual.SimpleDynamicVisual;
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
import net.minecraft.client.model.geom.ModelLayerLocation;
@ -35,7 +35,7 @@ import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.entity.LidBlockEntity;
import net.minecraft.world.level.block.state.properties.ChestType;
public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends AbstractBlockEntityVisual<T> implements DynamicVisual {
public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends AbstractBlockEntityVisual<T> implements SimpleDynamicVisual {
private static final Map<ChestType, ModelLayerLocation> LAYER_LOCATIONS = new EnumMap<>(ChestType.class);
static {
LAYER_LOCATIONS.put(ChestType.SINGLE, ModelLayers.CHEST);

View file

@ -2,8 +2,6 @@ package com.jozufozu.flywheel.vanilla;
import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
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.VisualizationContext;
@ -14,7 +12,9 @@ import com.jozufozu.flywheel.lib.model.ModelHolder;
import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.visual.SimpleDynamicVisual;
import com.jozufozu.flywheel.lib.visual.SimpleEntityVisual;
import com.jozufozu.flywheel.lib.visual.SimpleTickableVisual;
import com.jozufozu.flywheel.lib.visual.components.FireComponent;
import com.jozufozu.flywheel.lib.visual.components.HitboxComponent;
import com.jozufozu.flywheel.lib.visual.components.ShadowComponent;
@ -29,7 +29,7 @@ import net.minecraft.world.level.block.RenderShape;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisual<T> implements TickableVisual, DynamicVisual {
public class MinecartVisual<T extends AbstractMinecart> extends SimpleEntityVisual<T> implements SimpleTickableVisual, SimpleDynamicVisual {
public static final ModelHolder CHEST_BODY_MODEL = createBodyModelHolder(ModelLayers.CHEST_MINECART);
public static final ModelHolder COMMAND_BLOCK_BODY_MODEL = createBodyModelHolder(ModelLayers.COMMAND_BLOCK_MINECART);
public static final ModelHolder FURNACE_BODY_MODEL = createBodyModelHolder(ModelLayers.FURNACE_MINECART);

View file

@ -5,7 +5,6 @@ import java.util.function.Consumer;
import org.joml.Quaternionf;
import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.visual.DynamicVisual;
import com.jozufozu.flywheel.api.visual.VisualFrameContext;
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
@ -16,6 +15,7 @@ import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.transform.TransformStack;
import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual;
import com.jozufozu.flywheel.lib.visual.SimpleDynamicVisual;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
@ -27,7 +27,7 @@ import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements DynamicVisual {
public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements SimpleDynamicVisual {
private static final ModelCache<Material> BASE_MODELS = new ModelCache<>(texture -> {
return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "base"), Materials.SHULKER);
});

View file

@ -7,9 +7,10 @@ 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.PlannedVisual;
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.VisualizationContext;
@ -101,7 +102,7 @@ public class ExampleEffect implements Effect {
return new ExampleVisual(ctx);
}
public class ExampleVisual implements EffectVisual<ExampleEffect>, PlannedVisual {
public class ExampleVisual implements EffectVisual<ExampleEffect>, TickableVisual, DynamicVisual {
private final List<BoidVisual> effects;
private final List<Boid> boids;