diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java index 3462048..9667eac 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContext.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContext @@ -27,6 +30,33 @@ public interface BlockDataContext WorldDataContext, BlockDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default BlockDataContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockDataContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockDataContext pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackDataContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileDataContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java index 70ad8f4..7d35ec3 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/BlockDataContextRO.java @@ -17,15 +17,45 @@ */ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface BlockDataContextRO extends BlockGenericContextRO, WorldDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default BlockDataContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockDataContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockDataContextRO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackDataContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileDataContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java index bfbd164..73644ea 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/Context.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/Context.java @@ -17,11 +17,15 @@ */ package ru.windcorp.progressia.common.world.context; +import ru.windcorp.progressia.common.world.generic.context.AbstractContextRO; + /** * A cursor-like object for retrieving information about an in-game environment. * A context object typically holds a reference to some sort of data structure * and a cursor pointing to a location in that data structure. The exact meaning - * of "environment" and "location" is defined by extending interfaces. + * of "environment" and "location" is defined by extending interfaces. The terms + * relevant and implied should be understood to refer to the + * aforementioned location. *

* Context objects are intended to be the primary way of interacting for in-game * content. Wherever possible, context objects should be preferred over other @@ -41,37 +45,48 @@ package ru.windcorp.progressia.common.world.context; * thread-safe and are often pooled and reused. *

*

Subcontexting

- * Subcontexting is the invocation of user-provided code with a context - * object derived from an existing one. For example, block context provides a - * convenience method for referencing the block's neighbor: + * Context objects allow subcontexting. Subcontexting is the temporary + * modification of the context object. Contexts use a stack approach to + * modification: all modifications must be reverted in the reversed order they + * were applied. + *

+ * Modification methods are usually named {@code pushXXX}. To revert + * the most recent non-reverted modification, use {@link #pop()}. As a general + * rule, a method that is given a context must always {@link #pop()} every + * change it has pushed. Failure to abide by this contract results in bugs that + * is difficult to trace. + *

+ * Although various push methods declare differing result types, the same object + * is always returned: * *

- * blockContextA.forNeighbor(RelFace.UP, blockContextB -> {
- * 	foo(blockContextA); // undefined behavior!
- * 	foo(blockContextB); // correct
- * });
+ * someContext.pushXXX() == someContext
  * 
* - * In this example, {@code forNeighbor} is a subcontexting method, - * {@code blockContextA} is the parent context, {@code blockContextB} is the - * subcontext, and the lambda is the context consumer. - *

- * Parent contexts are invalid while the subcontexting method is - * running. Referencing {@code blockContextA} from inside the lambda - * creates undefined behavior. - *

- * This restriction exists because some implementations of contexts may - * implement subcontexting by simply modifying the parent context for the - * duration of the call and presenting the temporarily modified parent context - * as the subcontext: + * Therefore invoking {@link #pop()} is valid using both the original reference + * and the obtained reference. + *

Subcontexting example

+ * Given a {@link ru.windcorp.progressia.common.world.context.BlockDataContext + * BlockDataContext} {@code a} one can process the tile stack on the top of the + * relevant block by using * *
- * public void forNeighbor(BlockFace face, Consumer<BlockContext> action) {
- * 	this.position.add(face);
- * 	action.accept(this);
- * 	this.position.sub(face);
- * }
+ * TileStackDataContext b = a.push(RelFace.TOP);
+ * processTileStack(b);
+ * b.pop();
  * 
+ * + * One can improve readability by eliminating the temporary variable: + * + *
+ * processTileStack(a.push(RelFace.TOP));
+ * a.pop();
+ * 
+ * + * Notice that {@code a.pop()} and {@code b.pop()} are interchangeable. + * + * @see AbstractContextRO + * @author javapony */ public interface Context { @@ -102,4 +117,23 @@ public interface Context { */ boolean isReal(); + /** + * Reverts the more recent modification to this object that has not been + * reverted yet. + *

+ * Context objects may be modified temporarily with various push methods + * (see subcontexting). To revert the most + * recent non-reverted modification, use {@link #pop()}. As a general rule, + * a method that is given a context must always {@link #pop()} every change + * it has pushed. Failure to abide by this contract results in bugs that is + * difficult to trace. + *

+ * This method may be invoked using either the original reference or the + * reference provided by push method. + *

+ * This method fails with an {@link IllegalStateException} when there are no + * modifications to revert. + */ + void pop(); + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java index 78538c4..b424b2f 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContext.java @@ -27,6 +27,18 @@ public interface TileDataContext TileStackDataContext, TileDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default TileDataContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileDataContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java index e9f2d41..f6979e2 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileDataContextRO.java @@ -26,6 +26,18 @@ public interface TileDataContextRO extends TileGenericContextRO, TileStackDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default TileDataContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileDataContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java index 12ded3c..1751a50 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContext.java @@ -26,7 +26,24 @@ public interface TileStackDataContext extends TileStackGenericContextWO, BlockDataContext, TileStackDataContextRO { - - // currently empty + + /* + * Subcontexting + */ + + @Override + default TileDataContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackDataContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackDataContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java index 1e3a46d..bcdb948 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/TileStackDataContextRO.java @@ -24,8 +24,25 @@ import ru.windcorp.progressia.common.world.tile.TileData; public interface TileStackDataContextRO extends TileStackGenericContextRO, - BlockDataContext { + BlockDataContextRO { - // currently empty + /* + * Subcontexting + */ + + @Override + default TileDataContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackDataContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackDataContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java index 68965b5..9dcb0ae 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContext.java @@ -17,9 +17,11 @@ */ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextWO; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface WorldDataContext @@ -35,5 +37,18 @@ public interface WorldDataContext * @see #getTime() */ void advanceTime(float change); + + /* + * Subcontexting + */ + + @Override + BlockDataContext push(Vec3i location); + + @Override + TileStackDataContext push(Vec3i location, RelFace face); + + @Override + TileDataContext push(Vec3i location, RelFace face, int layer); } diff --git a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java index 8201738..be037bf 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/context/WorldDataContextRO.java @@ -18,10 +18,12 @@ package ru.windcorp.progressia.common.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.GravityModel; import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.tile.TileData; public interface WorldDataContextRO extends WorldGenericContextRO { @@ -43,5 +45,18 @@ public interface WorldDataContextRO extends WorldGenericContextRO. + */ +package ru.windcorp.progressia.common.world.generic.context; + +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.util.StashingStack; +import ru.windcorp.progressia.common.world.generic.BlockGeneric; +import ru.windcorp.progressia.common.world.generic.EntityGeneric; +import ru.windcorp.progressia.common.world.generic.TileGeneric; +import ru.windcorp.progressia.common.world.rels.RelFace; + +//@formatter:off +public abstract class AbstractContextRO< + B extends BlockGeneric, + T extends TileGeneric, + E extends EntityGeneric +> implements TileGenericContextRO { +//@formatter:on + + public static final int MAX_SUBCONTEXTS = 64; + + protected class Frame { + + public final Vec3i location = new Vec3i(); + public RelFace face; + public int layer; + + } + + protected Frame frame = null; + + private final StashingStack frameStack = new StashingStack<>(MAX_SUBCONTEXTS, Frame::new); + + @Override + public void pop() { + if (!isSubcontexting()) { + throw new IllegalStateException("Cannot pop(): already top frame"); + } + + frame = frameStack.pop(); + } + + @Override + public BlockGenericContextRO push(Vec3i location) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = null; + frame.layer = -1; + + return this; + } + + @Override + public TileStackGenericContextRO push(Vec3i location, RelFace face) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = face; + frame.layer = -1; + + return this; + } + + @Override + public TileGenericContextRO push(Vec3i location, RelFace face, int layer) { + frame = frameStack.push(); + + frame.location.set(location.x, location.y, location.z); + frame.face = face; + frame.layer = layer; + + return this; + } + + public boolean isSubcontexting() { + return frameStack.isEmpty(); + } + +} diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java index 239a02e..842fd0a 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextRO.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.common.world.generic.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A {@link Context} referencing a world with a block location specified. The @@ -129,5 +132,34 @@ public interface BlockGenericContextRO< default int getTileCount(BlockFace face) { return getTileCount(face); } + + /* + * Subcontexting + */ + + @Override + default BlockGenericContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockGenericContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockGenericContextRO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackGenericContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileGenericContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java index ffdb969..97ec62d 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/BlockGenericContextWO.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.common.world.generic.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A writable {@link Context} referencing a world with a block location @@ -72,5 +75,34 @@ public interface BlockGenericContextWO< default void removeTile(BlockFace face, int tag) { removeTile(getLocation(), face, tag); } + + /* + * Subcontexting + */ + + @Override + default BlockGenericContextWO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default BlockGenericContextWO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default BlockGenericContextWO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default TileStackGenericContextWO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default TileGenericContextWO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java index bdc5b69..1088a16 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextRO.java @@ -56,5 +56,19 @@ public interface TileGenericContextRO< default T getTile() { return getTile(getLocation(), getFace(), getLayer()); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileGenericContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java index ae8a2ff..1193f51 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileGenericContextWO.java @@ -43,5 +43,19 @@ public interface TileGenericContextWO< default void removeTile() { removeTile(getLocation(), getFace(), getTag()); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextWO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default TileGenericContextWO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java index 082788b..2a5cd3c 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextRO.java @@ -30,7 +30,7 @@ public interface TileStackGenericContextRO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric -> extends WorldContexts.BlockFace, BlockGenericContextRO { +> extends WorldContexts.TileStack, BlockGenericContextRO { //@formatter:on /** @@ -100,5 +100,24 @@ public interface TileStackGenericContextRO< default int getTileCount() { return getTileCount(getLocation(), getFace()); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackGenericContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackGenericContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java index 28c87ee..7a618b9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/TileStackGenericContextWO.java @@ -32,7 +32,7 @@ public interface TileStackGenericContextWO< B extends BlockGeneric, T extends TileGeneric, E extends EntityGeneric -> extends WorldContexts.BlockFace, BlockGenericContextWO { +> extends WorldContexts.TileStack, BlockGenericContextWO { //@formatter:on /** @@ -59,5 +59,24 @@ public interface TileStackGenericContextWO< default void removeTile(int tag) { removeTile(getLocation(), getFace(), tag); } + + /* + * Subcontexting + */ + + @Override + default TileGenericContextWO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default TileStackGenericContextWO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default TileStackGenericContextWO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java index 4dd8c19..bfc85bb 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldContexts.java @@ -20,19 +20,20 @@ package ru.windcorp.progressia.common.world.generic.context; import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.rels.AbsRelation; import ru.windcorp.progressia.common.world.rels.RelFace; /** * This class defines several {@link Context} subinterfaces that are further * extended by Generic contexts. These interfaces declare methods for - * determining which location is "relevant" to the context. Since they are not - * Java generics they can safely be extended more than once. + * determining which location is "relevant" to the context and the basic + * subcontexting methods. Since they are not Java generics they can safely be + * extended more than once. *

* Do not reuse these interfaces outside the Generic contexts' package; consider * them to be an implementation detail. * * @author javapony - * */ class WorldContexts { @@ -42,48 +43,149 @@ class WorldContexts { * {@link WorldGenericContextWO}. * * @author javapony - * */ public static interface World extends Context { - // currently empty + /** + * Assigns the specified location to this context. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @return this object + * @see #pop() + */ + Block push(Vec3i location); + + /** + * Assigns the specified location and block face to this context. Tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @param face the new block face to use + * @return this object + * @see #pop() + */ + TileStack push(Vec3i location, RelFace face); + + /** + * Assigns the specified position to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param location the new location to use + * @param face the new block face to use + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + Tile push(Vec3i location, RelFace face, int layer); } /** - * A {@link Context} with a world instance and a block location. This interface + * A {@link Context} with a world instance and a block location. This + * interface * should not be implemented directly; see {@link BlockGenericContextRO} or * {@link BlockGenericContextWO}. * * @author javapony - * */ public static interface Block extends World { /** * Returns the location of the block. *

- * The coordinate system in use is not specified, but it is consistent across + * The coordinate system in use is not specified, but it is consistent + * across * all methods of this context. *

- * The object returned by this method must not be modified. It is only valid + * The object returned by this method must not be modified. It is only + * valid * while the context is {@linkplain valid}. * * @return a vector describing the block's position */ Vec3i getLocation(); + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param dx the change of the x component + * @param dy the change of the y component + * @param dz the change of the z component + * @return this object + * @see #pop() + */ + default Block pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param direction the change added to the current location + * @return this object + * @see #pop() + */ + default Block pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + /** + * Shifts the location in the specified direction. Block face and tile + * layer information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param direction the change added to the current location + * @return this object + * @see #pop() + */ + default Block pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + /** + * Assigns the specified block face to this context. Tile layer + * information is discarded if it was present. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param face the new block face to use + * @return this object + * @see #pop() + */ + default TileStack push(RelFace face) { + return push(getLocation(), face); + } + + /** + * Assigns the specified block face and tile layer to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param face the new block face to use + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + default Tile push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } + } /** - * A {@link Context} with a world instance, a block location and a block face + * A {@link Context} with a world instance, a block location and a block + * face * (block side). This interface should not be implemented directly; see * {@link TileStackGenericContextRO} or {@link TileStackGenericContextWO}. * * @author javapony - * */ - public static interface BlockFace extends Block { + public static interface TileStack extends Block { /** * Returns the face relevant to this context. @@ -92,17 +194,57 @@ class WorldContexts { */ RelFace getFace(); + /** + * Assigns the specified tile layer to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @param layer the new tile layer to use + * @return this object + * @see #pop() + */ + default Tile push(int layer) { + return push(getLocation(), getFace(), layer); + } + + /** + * Assigns the counter face (the face on the opposite side of this + * block) to this context. Tile layer information is discarded if it was + * present. See {@linkplain Context#subcontexting subcontexting} for + * more details. + * + * @return this object + * @see #pop() + */ + default TileStack pushCounter() { + return push(getFace().getCounter()); + } + + /** + * Assigns the face opposite to the current face to this context. The + * current face and its opposite are the only two tile stacks occupying + * the gap between the two respective blocks. Tile layer information is + * discarded if it was present. See {@linkplain Context#subcontexting + * subcontexting} for + * more details. + * + * @return this object + * @see #pop() + */ + default TileStack pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } + } /** * A {@link Context} with a world instance, a block location, a block face * (block side) and a tile layer. This interface should not be implemented - * directly; see {@link TileGenericContextRO} or {@link TileGenericContextWO}. + * directly; see {@link TileGenericContextRO} or + * {@link TileGenericContextWO}. * * @author javapony - * */ - public static interface Tile extends BlockFace { + public static interface Tile extends TileStack { /** * Returns the tile layer relevant to this context. @@ -114,11 +256,34 @@ class WorldContexts { /** * Gets the tag of the tile at the relevant position. * - * @return the tag of the tile or {@code -1} if the location is not loaded + * @return the tag of the tile or {@code -1} if the location is not + * loaded * or the tile does not exist */ int getTag(); + /** + * Assigns the tile layer closer to the host block to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @return this object + * @see #pop() + */ + default Tile pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + /** + * Assigns the tile layer farther to the host block to this context. See + * {@linkplain Context#subcontexting subcontexting} for more details. + * + * @return this object + * @see #pop() + */ + default Tile pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } + } WorldContexts() { diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java index d604d62..59707e9 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextRO.java @@ -25,6 +25,7 @@ import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A {@link Context} with a world instance. @@ -188,4 +189,17 @@ public interface WorldGenericContextRO< }); } + /* + * Subcontexting + */ + + @Override + BlockGenericContextRO push(Vec3i location); + + @Override + TileStackGenericContextRO push(Vec3i location, RelFace face); + + @Override + TileGenericContextRO push(Vec3i location, RelFace face, int layer); + } diff --git a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java index ad1291e..0a465a0 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java +++ b/src/main/java/ru/windcorp/progressia/common/world/generic/context/WorldGenericContextWO.java @@ -23,6 +23,7 @@ import ru.windcorp.progressia.common.state.StatefulObject; import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.rels.BlockFace; +import ru.windcorp.progressia.common.world.rels.RelFace; /** * A writable {@link Context} with a world instance. This context provides @@ -149,5 +150,18 @@ public interface WorldGenericContextWO< * @param change the change to apply */ void changeEntity(SE entity, StateChange change); + + /* + * Subcontexting + */ + + @Override + BlockGenericContextWO push(Vec3i location); + + @Override + TileStackGenericContextWO push(Vec3i location, RelFace face); + + @Override + TileGenericContextWO push(Vec3i location, RelFace face, int layer); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java index 4130b50..c8bdf0b 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContext.java @@ -17,7 +17,10 @@ */ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.BlockDataContext; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO { @@ -25,10 +28,60 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext @Override ServerBlockContext data(); + + @Override + default ServerBlockContext.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContext.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContext.Logic pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContext.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContext.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } @Override ServerBlockContext.Logic logic(); + + @Override + default ServerBlockContext pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContext pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContext pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContext push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContext push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java index ca2e09f..eefa195 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerBlockContextRO.java @@ -17,9 +17,12 @@ */ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.BlockDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; +import ru.windcorp.progressia.common.world.rels.AbsRelation; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; @@ -30,10 +33,60 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon @Override ServerBlockContextRO data(); + + @Override + default ServerBlockContextRO.Logic pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContextRO.Logic pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContextRO.Logic pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContextRO.Logic push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContextRO.Logic push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } @Override ServerBlockContextRO.Logic logic(); + + @Override + default ServerBlockContextRO pushRelative(int dx, int dy, int dz) { + return push(getLocation().add_(dx, dy, dz)); + } + + @Override + default ServerBlockContextRO pushRelative(Vec3i direction) { + return push(getLocation().add_(direction)); + } + + @Override + default ServerBlockContextRO pushRelative(AbsRelation direction) { + return push(direction.getVector()); + } + + @Override + default ServerTileStackContextRO push(RelFace face) { + return push(getLocation(), face); + } + + @Override + default ServerTileContextRO push(RelFace face, int layer) { + return push(getLocation(), face, layer); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java index bc5fe6c..6850f43 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContext.java @@ -25,10 +25,30 @@ public interface ServerTileContext extends TileDataContext, ServerTileStackConte @Override ServerTileContext data(); + + @Override + default ServerTileContext.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContext.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } @Override ServerTileContext.Logic logic(); + + @Override + default ServerTileContext pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContext pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java index 87faf0c..18382bd 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileContextRO.java @@ -30,10 +30,30 @@ public interface ServerTileContextRO extends ServerTileStackContextRO, TileDataC @Override ServerTileContextRO data(); + + @Override + default ServerTileContextRO.Logic pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContextRO.Logic pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } @Override ServerTileContextRO.Logic logic(); + + @Override + default ServerTileContextRO pushCloser() { + return push(getLocation(), getFace(), getLayer() - 1); + } + + @Override + default ServerTileContextRO pushFarther() { + return push(getLocation(), getFace(), getLayer() + 1); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java index 938271b..7454f26 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContext.java @@ -25,10 +25,40 @@ public interface ServerTileStackContext extends TileStackDataContext, ServerBloc @Override ServerTileStackContext data(); + + @Override + default ServerTileContext.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContext.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContext.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } @Override ServerTileStackContext.Logic logic(); + + @Override + default ServerTileContext push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContext pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContext pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java index 0b33933..ef2d476 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerTileStackContextRO.java @@ -30,10 +30,40 @@ public interface ServerTileStackContextRO extends ServerBlockContextRO, TileStac @Override ServerTileStackContextRO data(); + + @Override + default ServerTileContextRO.Logic push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContextRO.Logic pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContextRO.Logic pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } @Override ServerTileStackContextRO.Logic logic(); + + @Override + default ServerTileContextRO push(int layer) { + return push(getLocation(), getFace(), layer); + } + + @Override + default ServerTileStackContextRO pushCounter() { + return push(getFace().getCounter()); + } + + @Override + default ServerTileStackContextRO pushOpposite() { + return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter()); + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java index b8504c4..3de8038 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContext.java @@ -17,7 +17,9 @@ */ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.WorldDataContext; +import ru.windcorp.progressia.common.world.rels.RelFace; public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO { @@ -25,10 +27,28 @@ public interface ServerWorldContext extends WorldDataContext, ServerWorldContext @Override ServerWorldContext data(); + + @Override + ServerBlockContext.Logic push(Vec3i location); + + @Override + ServerTileStackContext.Logic push(Vec3i location, RelFace face); + + @Override + ServerTileContext.Logic push(Vec3i location, RelFace face, int layer); } @Override ServerWorldContext.Logic logic(); + + @Override + ServerBlockContext push(Vec3i location); + + @Override + ServerTileStackContext push(Vec3i location, RelFace face); + + @Override + ServerTileContext push(Vec3i location, RelFace face, int layer); } \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java index 0202024..ff849c1 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/ServerWorldContextRO.java @@ -1,8 +1,10 @@ package ru.windcorp.progressia.server.world.context; +import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.context.WorldDataContextRO; import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.server.world.block.BlockLogic; import ru.windcorp.progressia.server.world.tile.TileLogic; @@ -18,6 +20,15 @@ public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext * @return a view of this context that returns data objects */ ServerWorldContextRO data(); + + @Override + ServerBlockContextRO.Logic push(Vec3i location); + + @Override + ServerTileStackContextRO.Logic push(Vec3i location, RelFace face); + + @Override + ServerTileContextRO.Logic push(Vec3i location, RelFace face, int layer); } @@ -29,5 +40,14 @@ public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext * @return a view of this context that returns appropriate logic objects */ ServerWorldContextRO.Logic logic(); + + @Override + ServerBlockContextRO push(Vec3i location); + + @Override + ServerTileStackContextRO push(Vec3i location, RelFace face); + + @Override + ServerTileContextRO push(Vec3i location, RelFace face, int layer); } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java index 345ff37..d32974c 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContext.java @@ -17,7 +17,13 @@ */ package ru.windcorp.progressia.server.world.context.impl; +import glm.vec._3.i.Vec3i; +import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.context.Context; +import ru.windcorp.progressia.common.world.entity.EntityData; +import ru.windcorp.progressia.common.world.generic.context.AbstractContextRO; +import ru.windcorp.progressia.common.world.rels.RelFace; +import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.server.world.WorldLogic; import ru.windcorp.progressia.server.world.WorldLogicRO; import ru.windcorp.progressia.server.world.context.*; @@ -45,7 +51,8 @@ import ru.windcorp.progressia.server.world.context.*; * * @author javapony */ -public abstract class ReusableServerContext implements ServerTileContext { +public abstract class ReusableServerContext extends AbstractContextRO + implements ServerTileContext { /** * An RSC can conform to a variety of different {@link Context} interfaces. @@ -92,9 +99,7 @@ public abstract class ReusableServerContext implements ServerTileContext { * * @return a {@link ReusableServerContextBuilders.Empty} instance that may * be used to reinitialize this object - * @throws IllegalStateException if active subcontexting is detected. - * Detection is done on a best-effort basis; - * do not rely this exception + * @throws IllegalStateException if active subcontexting is detected */ public abstract ReusableServerContextBuilders.Empty reuse() throws IllegalStateException; @@ -115,5 +120,23 @@ public abstract class ReusableServerContext implements ServerTileContext { public static ReusableServerContextBuilders.Empty empty() { return new ReusableServerContextImpl(); } + + @Override + public ReusableServerContext push(Vec3i location) { + super.push(location); + return this; + } + + @Override + public ReusableServerContext push(Vec3i location, RelFace face) { + super.push(location, face); + return this; + } + + @Override + public ReusableServerContext push(Vec3i location, RelFace face, int layer) { + super.push(location, face, layer); + return this; + } } diff --git a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java index 7e4545d..2994205 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java +++ b/src/main/java/ru/windcorp/progressia/server/world/context/impl/ReusableServerContextImpl.java @@ -69,30 +69,6 @@ class ReusableServerContextImpl extends ReusableServerContext */ protected WorldData worldData; - /** - * The relevant location. If this is {@code null}, the role is - * {@link Role#WORLD} or {@link Role#NONE}. - */ - protected Vec3i location; - - /** - * A {@code final} reference to the {@link Vec3i} instance used by - * {@link #location}. - */ - protected final Vec3i locationVectorContainer = new Vec3i(); - - /** - * The relevant {@link RelFace}. If the role is {@link Role#TILE_STACK} or - * {@link Role#TILE}, this is not {@code null}. - */ - protected RelFace blockFace; - - /** - * The index of the relevant tile. This value is {@code -1} unless the role - * is {@link Role#TILE}. - */ - protected int layer; - /** * The {@link Random} instance exposed with {@link #getRandom()}. */ @@ -124,11 +100,11 @@ class ReusableServerContextImpl extends ReusableServerContext public Role getRole() { if (server == null) return Role.NONE; - if (location == null) + if (frame == null) return Role.WORLD; - if (blockFace == null) + if (frame.face == null) return Role.LOCATION; - if (layer == -1) + if (frame.layer == -1) return Role.TILE_STACK; return Role.TILE; } @@ -186,19 +162,19 @@ class ReusableServerContextImpl extends ReusableServerContext case TILE: result = String.format( "ServerTileContext[x=%d, y=%d, z=%d, %s, index=%d]", - location.x, - location.y, - location.z, - blockFace, - layer + frame.location.x, + frame.location.y, + frame.location.z, + frame.face, + frame.layer ); break; case TILE_STACK: result = String - .format("ServerBlockFaceContext[x=%d, y=%d, z=%d, %s]", location.x, location.y, location.z, blockFace); + .format("ServerBlockFaceContext[x=%d, y=%d, z=%d, %s]", frame.location.x, frame.location.y, frame.location.z, frame.face); break; case LOCATION: - result = String.format("ServerBlockContext[x=%d, y=%d, z=%d]", location.x, location.y, location.z); + result = String.format("ServerBlockContext[x=%d, y=%d, z=%d]", frame.location.x, frame.location.y, frame.location.z); break; case WORLD: result = String.format("ServerWorldContext"); @@ -222,16 +198,13 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Empty reuse() { - if (subcontextDepth != 0) { - throw new IllegalStateException("Resetting is not allowed when subcontexting"); - } - server = null; worldLogic = null; worldData = null; - location = null; - blockFace = null; - layer = -1; + + while (isSubcontexting()) { + pop(); + } isBuilder = true; @@ -270,8 +243,7 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public WithLocation at(Vec3i location) { requireBuilderRole(Role.WORLD); - this.location = this.locationVectorContainer; - this.location.set(location.x, location.y, location.z); + push(location); return this; } @@ -282,14 +254,14 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public WithTileStack on(RelFace side) { requireBuilderRole(Role.LOCATION); - this.blockFace = side; + frame.face = side; return this; } @Override public WithTileStack on(BlockFace side) { requireBuilderRole(Role.LOCATION); - this.blockFace = side.relativize(worldLogic.getData().getUp(location)); + frame.face = side.relativize(worldLogic.getData().getUp(frame.location)); return this; } @@ -300,7 +272,7 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public ReusableServerContext index(int index) { requireBuilderRole(Role.TILE_STACK); - this.layer = index; + frame.layer = index; return build(); } @@ -317,19 +289,19 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Vec3i getLocation() { assert requireContextRole(Role.LOCATION); - return location; + return frame.location; } @Override public RelFace getFace() { assert requireContextRole(Role.TILE_STACK); - return blockFace; + return frame.face; } @Override public int getLayer() { assert requireContextRole(Role.TILE); - return layer; + return frame.layer; } /* @@ -402,16 +374,16 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public int getTag() { assert requireContextRole(Role.TILE); - TileDataStack stack = worldData.getTilesOrNull(location, blockFace); + TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face); if (stack == null) return -1; - return stack.getTagByIndex(layer); + return stack.getTagByIndex(frame.layer); } @Override public int getTileCount(Vec3i location, BlockFace face) { assert requireContextRole(Role.TILE_STACK); - TileDataStack stack = worldData.getTilesOrNull(location, blockFace); + TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face); if (stack == null) return 0; return stack.size(); @@ -516,17 +488,17 @@ class ReusableServerContextImpl extends ReusableServerContext @Override public Vec3i getLocation() { - return location; + return frame.location; } @Override public RelFace getFace() { - return blockFace; + return frame.face; } @Override public int getLayer() { - return layer; + return frame.layer; } /* @@ -614,6 +586,33 @@ class ReusableServerContextImpl extends ReusableServerContext return worldLogic.getEntity(entityId); } + /* + * Subcontexting + */ + + @Override + public Logic push(Vec3i location) { + ReusableServerContextImpl.this.push(location); + return this; + } + + @Override + public Logic push(Vec3i location, RelFace face) { + ReusableServerContextImpl.this.push(location, face); + return this; + } + + @Override + public Logic push(Vec3i location, RelFace face, int layer) { + ReusableServerContextImpl.this.push(location, face, layer); + return this; + } + + @Override + public void pop() { + ReusableServerContextImpl.this.pop(); + } + /* * MISC */