mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-24 20:07:54 +01:00
Tasteful stateful handles
- Use state machine interface in InstanceHandleImpl - 3 states: deleted, visible, hidden - Visible is directly implemented by AbstractInstancer - Hidden stores the instancer supplier to recreate an instancer
This commit is contained in:
parent
6a6d98c0a7
commit
c5d9abab5f
3 changed files with 132 additions and 38 deletions
|
@ -11,10 +11,10 @@ import dev.engine_room.flywheel.api.instance.Instancer;
|
||||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||||
import dev.engine_room.flywheel.backend.util.AtomicBitSet;
|
import dev.engine_room.flywheel.backend.util.AtomicBitSet;
|
||||||
|
|
||||||
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I>, InstanceHandleImpl.State<I> {
|
||||||
public final InstanceType<I> type;
|
public final InstanceType<I> type;
|
||||||
public final Environment environment;
|
public final Environment environment;
|
||||||
private final Supplier<AbstractInstancer<I>> recreate;
|
private final InstanceHandleImpl.Hidden<I> hidden;
|
||||||
|
|
||||||
// Lock for all instances, only needs to be used in methods that may run on the TaskExecutor.
|
// Lock for all instances, only needs to be used in methods that may run on the TaskExecutor.
|
||||||
protected final Object lock = new Object();
|
protected final Object lock = new Object();
|
||||||
|
@ -27,20 +27,45 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||||
protected AbstractInstancer(InstancerKey<I> key, Supplier<AbstractInstancer<I>> recreate) {
|
protected AbstractInstancer(InstancerKey<I> key, Supplier<AbstractInstancer<I>> recreate) {
|
||||||
this.type = key.type();
|
this.type = key.type();
|
||||||
this.environment = key.environment();
|
this.environment = key.environment();
|
||||||
this.recreate = recreate;
|
this.hidden = new InstanceHandleImpl.Hidden<>(recreate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceHandleImpl.State<I> setChanged(int index) {
|
||||||
|
notifyDirty(index);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceHandleImpl.State<I> setDeleted(int index) {
|
||||||
|
notifyRemoval(index);
|
||||||
|
return InstanceHandleImpl.Deleted.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceHandleImpl.State<I> setVisible(int index, I instance, boolean visible) {
|
||||||
|
if (visible) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyRemoval(index);
|
||||||
|
|
||||||
|
return hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InstanceHandleImpl.Status status() {
|
||||||
|
return InstanceHandleImpl.Status.VISIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public I createInstance() {
|
public I createInstance() {
|
||||||
synchronized (lock) {
|
var handle = new InstanceHandleImpl<>(this);
|
||||||
var i = instances.size();
|
I instance = type.create(handle);
|
||||||
var handle = new InstanceHandleImpl<I>();
|
handle.instance = instance;
|
||||||
handle.instancer = this;
|
|
||||||
handle.recreate = recreate;
|
|
||||||
handle.index = i;
|
|
||||||
I instance = type.create(handle);
|
|
||||||
handle.instance = instance;
|
|
||||||
|
|
||||||
|
synchronized (lock) {
|
||||||
|
handle.index = instances.size();
|
||||||
addLocked(instance, handle);
|
addLocked(instance, handle);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +87,8 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||||
// Should InstanceType have an isInstance method?
|
// Should InstanceType have an isInstance method?
|
||||||
var handle = (InstanceHandleImpl<I>) instanceHandle;
|
var handle = (InstanceHandleImpl<I>) instanceHandle;
|
||||||
|
|
||||||
if (handle.instancer == this && handle.visible) {
|
// Should you be allowed to steal deleted instances?
|
||||||
|
if (handle.state == this || handle.state.status() == InstanceHandleImpl.Status.DELETED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,15 +102,18 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||||
handle.setDeleted();
|
handle.setDeleted();
|
||||||
|
|
||||||
// Add the instance to this instancer.
|
// Add the instance to this instancer.
|
||||||
handle.instancer = this;
|
switch (handle.state.status()) {
|
||||||
handle.recreate = recreate;
|
case VISIBLE:
|
||||||
|
handle.state = this;
|
||||||
if (handle.visible) {
|
|
||||||
// Only lock now that we'll be mutating our state.
|
// Only lock now that we'll be mutating our state.
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
handle.index = instances.size();
|
handle.index = instances.size();
|
||||||
addLocked(instance, handle);
|
addLocked(instance, handle);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case HIDDEN:
|
||||||
|
handle.state = hidden;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,8 +216,9 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||||
// clearing it here would cause significant visual artifacts and instance leaks.
|
// clearing it here would cause significant visual artifacts and instance leaks.
|
||||||
// At the same time, we need to clear handles we own to prevent
|
// At the same time, we need to clear handles we own to prevent
|
||||||
// instances from changing/deleting positions in this instancer that no longer exist.
|
// instances from changing/deleting positions in this instancer that no longer exist.
|
||||||
if (handle.instancer == this) {
|
if (handle.state == this || handle.state == hidden) {
|
||||||
handle.clear();
|
handle.clear();
|
||||||
|
handle.state = InstanceHandleImpl.Deleted.instance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instances.clear();
|
instances.clear();
|
||||||
|
|
|
@ -115,8 +115,11 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractInstancer<?> abstractInstancer = impl.instancer;
|
InstanceHandleImpl.State<?> abstractInstancer = impl.state;
|
||||||
|
// AbstractInstancer directly implement HandleState, so this check is valid.
|
||||||
if (!clazz.isInstance(abstractInstancer)) {
|
if (!clazz.isInstance(abstractInstancer)) {
|
||||||
|
// This rejects instances that were created by a different engine,
|
||||||
|
// and also instances that are hidden or deleted.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,49 +8,110 @@ import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
import dev.engine_room.flywheel.api.instance.InstanceHandle;
|
||||||
|
|
||||||
public class InstanceHandleImpl<I extends Instance> implements InstanceHandle {
|
public class InstanceHandleImpl<I extends Instance> implements InstanceHandle {
|
||||||
@UnknownNullability
|
public State<I> state;
|
||||||
public AbstractInstancer<I> instancer;
|
|
||||||
@UnknownNullability
|
@UnknownNullability
|
||||||
public I instance;
|
public I instance;
|
||||||
@UnknownNullability
|
|
||||||
public Supplier<AbstractInstancer<I>> recreate;
|
|
||||||
public boolean visible = true;
|
|
||||||
public int index;
|
public int index;
|
||||||
|
|
||||||
|
public InstanceHandleImpl(State<I> state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setChanged() {
|
public void setChanged() {
|
||||||
instancer.notifyDirty(index);
|
state = state.setChanged(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDeleted() {
|
public void setDeleted() {
|
||||||
instancer.notifyRemoval(index);
|
state = state.setDeleted(index);
|
||||||
// invalidate ourselves
|
// invalidate ourselves
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setVisible(boolean visible) {
|
public void setVisible(boolean visible) {
|
||||||
if (this.visible == visible) {
|
state = state.setVisible(index, instance, visible);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.visible = visible;
|
|
||||||
|
|
||||||
if (visible) {
|
|
||||||
recreate.get().stealInstance(instance);
|
|
||||||
} else {
|
|
||||||
instancer.notifyRemoval(index);
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return visible;
|
return state.status() == Status.VISIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
index = -1;
|
index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Status {
|
||||||
|
HIDDEN,
|
||||||
|
DELETED,
|
||||||
|
VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface State<I extends Instance> {
|
||||||
|
State<I> setChanged(int index);
|
||||||
|
|
||||||
|
State<I> setDeleted(int index);
|
||||||
|
|
||||||
|
State<I> setVisible(int index, I instance, boolean visible);
|
||||||
|
|
||||||
|
Status status();
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Hidden<I extends Instance>(Supplier<AbstractInstancer<I>> supplier) implements State<I> {
|
||||||
|
@Override
|
||||||
|
public State<I> setChanged(int index) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State<I> setDeleted(int index) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State<I> setVisible(int index, I instance, boolean visible) {
|
||||||
|
if (!visible) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
var instancer = supplier.get();
|
||||||
|
instancer.stealInstance(instance);
|
||||||
|
return instancer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status status() {
|
||||||
|
return Status.HIDDEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Deleted<I extends Instance>() implements State<I> {
|
||||||
|
private static final Deleted<?> INSTANCE = new Deleted<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <I extends Instance> Deleted<I> instance() {
|
||||||
|
return (Deleted<I>) INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State<I> setChanged(int index) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State<I> setDeleted(int index) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public State<I> setVisible(int index, I instance, boolean visible) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status status() {
|
||||||
|
return Status.DELETED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue