Listless no longer

- Visualizers return a list of visuals instead of just one
- Simple*Visualizer's builders still only allow one visual per object,
  I'm not sure how best to expose adding multiple in a way that allows
  other mods to extend existing visualizers
This commit is contained in:
Jozufozu 2024-06-29 13:57:41 -07:00
parent ee3958b140
commit 22383fd51e
11 changed files with 101 additions and 73 deletions

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.visual; package dev.engine_room.flywheel.api.visual;
import java.util.List;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
/** /**
@ -14,5 +16,5 @@ public interface Effect {
* @param ctx The visualization context. * @param ctx The visualization context.
* @return An arbitrary EffectVisual. * @return An arbitrary EffectVisual.
*/ */
EffectVisual<?> visualize(VisualizationContext ctx); List<EffectVisual<?>> visualize(VisualizationContext ctx);
} }

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.visualization; package dev.engine_room.flywheel.api.visualization;
import java.util.List;
import dev.engine_room.flywheel.api.visual.BlockEntityVisual; import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -16,7 +18,7 @@ public interface BlockEntityVisualizer<T extends BlockEntity> {
* @param blockEntity The block entity to construct a visual for. * @param blockEntity The block entity to construct a visual for.
* @return The visual. * @return The visual.
*/ */
BlockEntityVisual<? super T> createVisual(VisualizationContext ctx, T blockEntity); List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity);
/** /**
* Checks if the given block entity should not be rendered with the vanilla {@link BlockEntityRenderer}. * Checks if the given block entity should not be rendered with the vanilla {@link BlockEntityRenderer}.

View file

@ -1,5 +1,7 @@
package dev.engine_room.flywheel.api.visualization; package dev.engine_room.flywheel.api.visualization;
import java.util.List;
import dev.engine_room.flywheel.api.visual.EntityVisual; import dev.engine_room.flywheel.api.visual.EntityVisual;
import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
@ -16,7 +18,7 @@ public interface EntityVisualizer<T extends Entity> {
* @param entity The entity to construct a visual for. * @param entity The entity to construct a visual for.
* @return The visual. * @return The visual.
*/ */
EntityVisual<? super T> createVisual(VisualizationContext ctx, T entity); List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity);
/** /**
* Checks if the given entity should not render with the vanilla {@link EntityRenderer}. * Checks if the given entity should not render with the vanilla {@link EntityRenderer}.

View file

@ -1,5 +1,6 @@
package dev.engine_room.flywheel.lib.visual; package dev.engine_room.flywheel.lib.visual;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -23,8 +24,8 @@ public class SimpleBlockEntityVisualizer<T extends BlockEntity> implements Block
} }
@Override @Override
public BlockEntityVisual<? super T> createVisual(VisualizationContext ctx, T blockEntity) { public List<BlockEntityVisual<? super T>> createVisual(VisualizationContext ctx, T blockEntity) {
return visualFactory.create(ctx, blockEntity); return List.of(visualFactory.create(ctx, blockEntity));
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package dev.engine_room.flywheel.lib.visual; package dev.engine_room.flywheel.lib.visual;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -23,8 +24,8 @@ public class SimpleEntityVisualizer<T extends Entity> implements EntityVisualize
} }
@Override @Override
public EntityVisual<? super T> createVisual(VisualizationContext ctx, T entity) { public List<EntityVisual<? super T>> createVisual(VisualizationContext ctx, T entity) {
return visualFactory.create(ctx, entity); return List.of(visualFactory.create(ctx, entity));
} }
@Override @Override

View file

@ -17,6 +17,7 @@ import dev.engine_room.flywheel.api.event.RenderStage;
import dev.engine_room.flywheel.api.instance.Instance; import dev.engine_room.flywheel.api.instance.Instance;
import dev.engine_room.flywheel.api.task.Plan; import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.task.TaskExecutor; import dev.engine_room.flywheel.api.task.TaskExecutor;
import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
import dev.engine_room.flywheel.api.visual.DynamicVisual; import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visual.Effect; import dev.engine_room.flywheel.api.visual.Effect;
import dev.engine_room.flywheel.api.visual.TickableVisual; import dev.engine_room.flywheel.api.visual.TickableVisual;
@ -261,21 +262,23 @@ public class VisualizationManagerImpl implements VisualizationManager {
continue; continue;
} }
var visual = blockEntities.getStorage() var visualList = blockEntities.getStorage()
.visualAtPos(entry.getLongKey()); .visualAtPos(entry.getLongKey());
if (visual == null) { if (visualList == null || visualList.isEmpty()) {
// The block doesn't have a visual, this is probably the common case. // The block doesn't have a visual, this is probably the common case.
continue; continue;
} }
List<Instance> instances = new ArrayList<>(); List<Instance> instances = new ArrayList<>();
visual.collectCrumblingInstances(instance -> { for (BlockEntityVisual<?> visual : visualList) {
if (instance != null) { visual.collectCrumblingInstances(instance -> {
instances.add(instance); if (instance != null) {
} instances.add(instance);
}); }
});
}
if (instances.isEmpty()) { if (instances.isEmpty()) {
// The visual doesn't want to render anything crumbling. // The visual doesn't want to render anything crumbling.

View file

@ -1,11 +1,11 @@
package dev.engine_room.flywheel.impl.visualization.manager; package dev.engine_room.flywheel.impl.visualization.manager;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.visual.BlockEntityVisual; import dev.engine_room.flywheel.api.visual.BlockEntityVisual;
import dev.engine_room.flywheel.api.visual.Visual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.impl.visualization.storage.Storage; import dev.engine_room.flywheel.impl.visualization.storage.Storage;
import dev.engine_room.flywheel.lib.visual.VisualizationHelper; import dev.engine_room.flywheel.lib.visual.VisualizationHelper;
@ -17,14 +17,14 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; 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<List<? extends BlockEntityVisual<?>>> posLookup = new Long2ObjectOpenHashMap<>();
public BlockEntityStorage(Supplier<VisualizationContext> visualizationContextSupplier) { public BlockEntityStorage(Supplier<VisualizationContext> visualizationContextSupplier) {
super(visualizationContextSupplier); super(visualizationContextSupplier);
} }
@Nullable @Nullable
public BlockEntityVisual<?> visualAtPos(long pos) { public List<? extends BlockEntityVisual<?>> visualAtPos(long pos) {
return posLookup.get(pos); return posLookup.get(pos);
} }
@ -53,19 +53,18 @@ public class BlockEntityStorage extends Storage<BlockEntity> {
} }
@Override @Override
@Nullable protected List<? extends BlockEntityVisual<?>> createRaw(BlockEntity obj) {
protected Visual createRaw(BlockEntity obj) {
var visualizer = VisualizationHelper.getVisualizer(obj); var visualizer = VisualizationHelper.getVisualizer(obj);
if (visualizer == null) { if (visualizer == null) {
return null; return List.of();
} }
var visual = visualizer.createVisual(visualizationContextSupplier.get(), obj); var visualList = visualizer.createVisual(visualizationContextSupplier.get(), obj);
BlockPos blockPos = obj.getBlockPos(); BlockPos blockPos = obj.getBlockPos();
posLookup.put(blockPos.asLong(), visual); posLookup.put(blockPos.asLong(), visualList);
return visual; return visualList;
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package dev.engine_room.flywheel.impl.visualization.manager; package dev.engine_room.flywheel.impl.visualization.manager;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import dev.engine_room.flywheel.api.visual.Effect; import dev.engine_room.flywheel.api.visual.Effect;
@ -13,7 +14,7 @@ public class EffectStorage extends Storage<Effect> {
} }
@Override @Override
protected EffectVisual<?> createRaw(Effect obj) { protected List<? extends EffectVisual<?>> createRaw(Effect obj) {
return obj.visualize(visualizationContextSupplier.get()); return obj.visualize(visualizationContextSupplier.get());
} }

View file

@ -1,10 +1,9 @@
package dev.engine_room.flywheel.impl.visualization.manager; package dev.engine_room.flywheel.impl.visualization.manager;
import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.jetbrains.annotations.Nullable; import dev.engine_room.flywheel.api.visual.EntityVisual;
import dev.engine_room.flywheel.api.visual.Visual;
import dev.engine_room.flywheel.api.visualization.VisualizationContext; import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.impl.visualization.storage.Storage; import dev.engine_room.flywheel.impl.visualization.storage.Storage;
import dev.engine_room.flywheel.lib.visual.VisualizationHelper; import dev.engine_room.flywheel.lib.visual.VisualizationHelper;
@ -17,11 +16,10 @@ public class EntityStorage extends Storage<Entity> {
} }
@Override @Override
@Nullable protected List<? extends EntityVisual<?>> createRaw(Entity obj) {
protected Visual createRaw(Entity obj) {
var visualizer = VisualizationHelper.getVisualizer(obj); var visualizer = VisualizationHelper.getVisualizer(obj);
if (visualizer == null) { if (visualizer == null) {
return null; return List.of();
} }
return visualizer.createVisual(visualizationContextSupplier.get(), obj); return visualizer.createVisual(visualizationContextSupplier.get(), obj);

View file

@ -26,7 +26,7 @@ public class VisualManagerImpl<T, S extends Storage<T>> implements VisualManager
@Override @Override
public int getVisualCount() { public int getVisualCount() {
return getStorage().getAllVisuals().size(); return getStorage().visualCount();
} }
@Override @Override

View file

@ -1,13 +1,10 @@
package dev.engine_room.flywheel.impl.visualization.storage; package dev.engine_room.flywheel.impl.visualization.storage;
import java.util.ArrayList; import java.util.ArrayList;
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 java.util.function.Supplier;
import org.jetbrains.annotations.Nullable;
import dev.engine_room.flywheel.api.task.Plan; import dev.engine_room.flywheel.api.task.Plan;
import dev.engine_room.flywheel.api.visual.DynamicVisual; import dev.engine_room.flywheel.api.visual.DynamicVisual;
import dev.engine_room.flywheel.api.visual.LitVisual; import dev.engine_room.flywheel.api.visual.LitVisual;
@ -29,59 +26,50 @@ public abstract class Storage<T> {
protected final List<SimpleTickableVisual> simpleTickableVisuals = new ArrayList<>(); protected final List<SimpleTickableVisual> simpleTickableVisuals = new ArrayList<>();
protected final LitVisualStorage litVisuals = new LitVisualStorage(); protected final LitVisualStorage litVisuals = new LitVisualStorage();
private final Map<T, Visual> visuals = new Reference2ObjectOpenHashMap<>(); private final Map<T, List<? extends Visual>> visuals = new Reference2ObjectOpenHashMap<>();
public Storage(Supplier<VisualizationContext> visualizationContextSupplier) { public Storage(Supplier<VisualizationContext> visualizationContextSupplier) {
this.visualizationContextSupplier = visualizationContextSupplier; this.visualizationContextSupplier = visualizationContextSupplier;
} }
public Collection<Visual> getAllVisuals() { public int visualCount() {
return visuals.values(); int out = 0;
for (var visualList : visuals.values()) {
out += visualList.size();
}
return out;
} }
public void add(T obj, float partialTick) { public void add(T obj, float partialTick) {
Visual visual = visuals.get(obj); var visualList = this.visuals.get(obj);
if (visual == null) { if (visualList == null) {
create(obj, partialTick); create(obj, partialTick);
} }
} }
public void remove(T obj) { public void remove(T obj) {
Visual visual = visuals.remove(obj); var visualList = this.visuals.remove(obj);
if (visual == null) { if (visualList == null || visualList.isEmpty()) {
return; return;
} }
if (visual instanceof TickableVisual tickable) { for (Visual visual : visualList) {
if (visual instanceof SimpleTickableVisual simpleTickable) { remove(visual);
simpleTickableVisuals.remove(simpleTickable);
} else {
tickableVisuals.remove(tickable);
}
} }
if (visual instanceof DynamicVisual dynamic) {
if (visual instanceof SimpleDynamicVisual simpleDynamic) {
simpleDynamicVisuals.remove(simpleDynamic);
} else {
dynamicVisuals.remove(dynamic);
}
}
if (visual instanceof LitVisual lit) {
litVisuals.remove(lit);
}
visual.delete();
} }
public void update(T obj, float partialTick) { public void update(T obj, float partialTick) {
Visual visual = visuals.get(obj); var visualList = visuals.get(obj);
if (visual == null) { if (visualList == null || visualList.isEmpty()) {
return; return;
} }
visual.update(partialTick); for (Visual visual : visualList) {
visual.update(partialTick);
}
} }
public void recreateAll(float partialTick) { public void recreateAll(float partialTick) {
@ -90,13 +78,17 @@ public abstract class Storage<T> {
simpleTickableVisuals.clear(); simpleTickableVisuals.clear();
simpleDynamicVisuals.clear(); simpleDynamicVisuals.clear();
litVisuals.clear(); litVisuals.clear();
visuals.replaceAll((obj, visual) -> { visuals.replaceAll((obj, visuals) -> {
visual.delete(); visuals.forEach(Visual::delete);
Visual out = createRaw(obj); var out = createRaw(obj);
if (out != null) { if (out.isEmpty()) {
setup(out, partialTick); return null;
}
for (Visual visual : out) {
setup(visual, partialTick);
} }
return out; return out;
@ -107,22 +99,28 @@ public abstract class Storage<T> {
tickableVisuals.clear(); tickableVisuals.clear();
dynamicVisuals.clear(); dynamicVisuals.clear();
litVisuals.clear(); litVisuals.clear();
visuals.values() for (var visualList : visuals.values()) {
.forEach(Visual::delete); for (Visual visual : visualList) {
visual.delete();
}
}
visuals.clear(); visuals.clear();
} }
private void create(T obj, float partialTick) { private void create(T obj, float partialTick) {
Visual visual = createRaw(obj); var visuals = createRaw(obj);
if (visual != null) { if (visuals.isEmpty()) {
return;
}
this.visuals.put(obj, visuals);
for (Visual visual : visuals) {
setup(visual, partialTick); setup(visual, partialTick);
visuals.put(obj, visual);
} }
} }
@Nullable protected abstract List<? extends Visual> createRaw(T obj);
protected abstract Visual createRaw(T obj);
public Plan<DynamicVisual.Context> framePlan() { public Plan<DynamicVisual.Context> framePlan() {
return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame)); return NestedPlan.of(dynamicVisuals, litVisuals.plan(), ForEachPlan.of(() -> simpleDynamicVisuals, SimpleDynamicVisual::beginFrame));
@ -160,6 +158,27 @@ public abstract class Storage<T> {
} }
} }
private void remove(Visual visual) {
if (visual instanceof TickableVisual tickable) {
if (visual instanceof SimpleTickableVisual simpleTickable) {
simpleTickableVisuals.remove(simpleTickable);
} else {
tickableVisuals.remove(tickable);
}
}
if (visual instanceof DynamicVisual dynamic) {
if (visual instanceof SimpleDynamicVisual simpleDynamic) {
simpleDynamicVisuals.remove(simpleDynamic);
} else {
dynamicVisuals.remove(dynamic);
}
}
if (visual instanceof LitVisual lit) {
litVisuals.remove(lit);
}
visual.delete();
}
/** /**
* Is the given object currently capable of being added? * Is the given object currently capable of being added?
* *