Added subcontexting. Context#subcontexting.

This commit is contained in:
OLEGSHA 2021-08-06 10:49:40 +03:00
parent 80541eafc3
commit 15f741bc04
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
29 changed files with 978 additions and 110 deletions

View File

@ -17,9 +17,12 @@
*/ */
package ru.windcorp.progressia.common.world.context; 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.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextWO; 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; import ru.windcorp.progressia.common.world.tile.TileData;
public interface BlockDataContext public interface BlockDataContext
@ -27,6 +30,33 @@ public interface BlockDataContext
WorldDataContext, WorldDataContext,
BlockDataContextRO { 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);
}
} }

View File

@ -17,15 +17,45 @@
*/ */
package ru.windcorp.progressia.common.world.context; 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.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; 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; import ru.windcorp.progressia.common.world.tile.TileData;
public interface BlockDataContextRO public interface BlockDataContextRO
extends BlockGenericContextRO<BlockData, TileData, EntityData>, extends BlockGenericContextRO<BlockData, TileData, EntityData>,
WorldDataContextRO { 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);
}
} }

View File

@ -17,11 +17,15 @@
*/ */
package ru.windcorp.progressia.common.world.context; 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 cursor-like object for retrieving information about an in-game environment.
* A context object typically holds a reference to some sort of data structure * 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 * 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
* <em>relevant</em> and <em>implied</em> should be understood to refer to the
* aforementioned location.
* <p> * <p>
* Context objects are intended to be the primary way of interacting for in-game * Context objects are intended to be the primary way of interacting for in-game
* content. Wherever possible, context objects should be preferred over other * content. Wherever possible, context objects should be preferred over other
@ -41,37 +45,48 @@ package ru.windcorp.progressia.common.world.context;
* thread-safe</em> and are often pooled and reused. * thread-safe</em> and are often pooled and reused.
* <p> * <p>
* <h2 id="subcontexting">Subcontexting</h2> * <h2 id="subcontexting">Subcontexting</h2>
* <em>Subcontexting</em> is the invocation of user-provided code with a context * Context objects allow <em>subcontexting</em>. Subcontexting is the temporary
* object derived from an existing one. For example, block context provides a * modification of the context object. Contexts use a stack approach to
* convenience method for referencing the block's neighbor: * modification: all modifications must be reverted in the reversed order they
* were applied.
* <p>
* Modification methods are usually named <em>{@code pushXXX}</em>. 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.
* <p>
* Although various push methods declare differing result types, the same object
* is always returned:
* *
* <pre> * <pre>
* blockContextA.forNeighbor(RelFace.UP, blockContextB -&gt; { * someContext.pushXXX() == someContext
* foo(blockContextA); // undefined behavior!
* foo(blockContextB); // correct
* });
* </pre> * </pre>
* *
* In this example, {@code forNeighbor} is a subcontexting method, * Therefore invoking {@link #pop()} is valid using both the original reference
* {@code blockContextA} is the parent context, {@code blockContextB} is the * and the obtained reference.
* subcontext, and the lambda is the context consumer. * <h3>Subcontexting example</h3>
* <p> * Given a {@link ru.windcorp.progressia.common.world.context.BlockDataContext
* <em>Parent contexts are invalid while the subcontexting method is * BlockDataContext} {@code a} one can process the tile stack on the top of the
* running.</em> Referencing {@code blockContextA} from inside the lambda * relevant block by using
* creates undefined behavior.
* <p>
* 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:
* *
* <pre> * <pre>
* public void forNeighbor(BlockFace face, Consumer&lt;BlockContext&gt; action) { * TileStackDataContext b = a.push(RelFace.TOP);
* this.position.add(face); * processTileStack(b);
* action.accept(this); * b.pop();
* this.position.sub(face);
* }
* </pre> * </pre>
*
* One can improve readability by eliminating the temporary variable:
*
* <pre>
* processTileStack(a.push(RelFace.TOP));
* a.pop();
* </pre>
*
* Notice that {@code a.pop()} and {@code b.pop()} are interchangeable.
*
* @see AbstractContextRO
* @author javapony
*/ */
public interface Context { public interface Context {
@ -102,4 +117,23 @@ public interface Context {
*/ */
boolean isReal(); boolean isReal();
/**
* Reverts the more recent modification to this object that has not been
* reverted yet.
* <p>
* Context objects may be modified temporarily with various push methods
* (see <a href="#subcontexting">subcontexting</a>). 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.
* <p>
* This method may be invoked using either the original reference or the
* reference provided by push method.
* <p>
* This method fails with an {@link IllegalStateException} when there are no
* modifications to revert.
*/
void pop();
} }

View File

@ -27,6 +27,18 @@ public interface TileDataContext
TileStackDataContext, TileStackDataContext,
TileDataContextRO { TileDataContextRO {
// currently empty /*
* Subcontexting
*/
@Override
default TileDataContext pushCloser() {
return push(getLocation(), getFace(), getLayer() - 1);
}
@Override
default TileDataContext pushFarther() {
return push(getLocation(), getFace(), getLayer() + 1);
}
} }

View File

@ -26,6 +26,18 @@ public interface TileDataContextRO
extends TileGenericContextRO<BlockData, TileData, EntityData>, extends TileGenericContextRO<BlockData, TileData, EntityData>,
TileStackDataContextRO { TileStackDataContextRO {
// currently empty /*
* Subcontexting
*/
@Override
default TileDataContextRO pushCloser() {
return push(getLocation(), getFace(), getLayer() - 1);
}
@Override
default TileDataContextRO pushFarther() {
return push(getLocation(), getFace(), getLayer() + 1);
}
} }

View File

@ -27,6 +27,23 @@ public interface TileStackDataContext
BlockDataContext, BlockDataContext,
TileStackDataContextRO { 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());
}
} }

View File

@ -24,8 +24,25 @@ import ru.windcorp.progressia.common.world.tile.TileData;
public interface TileStackDataContextRO public interface TileStackDataContextRO
extends TileStackGenericContextRO<BlockData, TileData, EntityData>, extends TileStackGenericContextRO<BlockData, TileData, EntityData>,
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());
}
} }

View File

@ -17,9 +17,11 @@
*/ */
package ru.windcorp.progressia.common.world.context; 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.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextWO; 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; import ru.windcorp.progressia.common.world.tile.TileData;
public interface WorldDataContext public interface WorldDataContext
@ -36,4 +38,17 @@ public interface WorldDataContext
*/ */
void advanceTime(float change); 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);
} }

View File

@ -18,10 +18,12 @@
package ru.windcorp.progressia.common.world.context; 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.GravityModel;
import ru.windcorp.progressia.common.world.block.BlockData; import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; 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; import ru.windcorp.progressia.common.world.tile.TileData;
public interface WorldDataContextRO extends WorldGenericContextRO<BlockData, TileData, EntityData> { public interface WorldDataContextRO extends WorldGenericContextRO<BlockData, TileData, EntityData> {
@ -44,4 +46,17 @@ public interface WorldDataContextRO extends WorldGenericContextRO<BlockData, Til
*/ */
GravityModel getGravityModel(); GravityModel getGravityModel();
/*
* Subcontexting
*/
@Override
BlockDataContextRO push(Vec3i location);
@Override
TileStackDataContextRO push(Vec3i location, RelFace face);
@Override
TileDataContextRO push(Vec3i location, RelFace face, int layer);
} }

View File

@ -0,0 +1,95 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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<B, T, E> {
//@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<Frame> 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<B, T, E> 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<B, T, E> 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<B, T, E> 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();
}
}

View File

@ -17,9 +17,12 @@
*/ */
package ru.windcorp.progressia.common.world.generic.context; 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.context.Context;
import ru.windcorp.progressia.common.world.generic.*; 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.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
/** /**
* A {@link Context} referencing a world with a block location specified. The * A {@link Context} referencing a world with a block location specified. The
@ -130,4 +133,33 @@ public interface BlockGenericContextRO<
return getTileCount(face); return getTileCount(face);
} }
/*
* Subcontexting
*/
@Override
default BlockGenericContextRO<B, T, E> pushRelative(int dx, int dy, int dz) {
return push(getLocation().add_(dx, dy, dz));
}
@Override
default BlockGenericContextRO<B, T, E> pushRelative(Vec3i direction) {
return push(getLocation().add_(direction));
}
@Override
default BlockGenericContextRO<B, T, E> pushRelative(AbsRelation direction) {
return push(direction.getVector());
}
@Override
default TileStackGenericContextRO<B, T, E> push(RelFace face) {
return push(getLocation(), face);
}
@Override
default TileGenericContextRO<B, T, E> push(RelFace face, int layer) {
return push(getLocation(), face, layer);
}
} }

View File

@ -17,9 +17,12 @@
*/ */
package ru.windcorp.progressia.common.world.generic.context; 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.context.Context;
import ru.windcorp.progressia.common.world.generic.*; 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.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
/** /**
* A writable {@link Context} referencing a world with a block location * A writable {@link Context} referencing a world with a block location
@ -73,4 +76,33 @@ public interface BlockGenericContextWO<
removeTile(getLocation(), face, tag); removeTile(getLocation(), face, tag);
} }
/*
* Subcontexting
*/
@Override
default BlockGenericContextWO<B, T, E> pushRelative(int dx, int dy, int dz) {
return push(getLocation().add_(dx, dy, dz));
}
@Override
default BlockGenericContextWO<B, T, E> pushRelative(Vec3i direction) {
return push(getLocation().add_(direction));
}
@Override
default BlockGenericContextWO<B, T, E> pushRelative(AbsRelation direction) {
return push(direction.getVector());
}
@Override
default TileStackGenericContextWO<B, T, E> push(RelFace face) {
return push(getLocation(), face);
}
@Override
default TileGenericContextWO<B, T, E> push(RelFace face, int layer) {
return push(getLocation(), face, layer);
}
} }

View File

@ -57,4 +57,18 @@ public interface TileGenericContextRO<
return getTile(getLocation(), getFace(), getLayer()); return getTile(getLocation(), getFace(), getLayer());
} }
/*
* Subcontexting
*/
@Override
default TileGenericContextRO<B, T, E> pushCloser() {
return push(getLocation(), getFace(), getLayer() - 1);
}
@Override
default TileGenericContextRO<B, T, E> pushFarther() {
return push(getLocation(), getFace(), getLayer() + 1);
}
} }

View File

@ -44,4 +44,18 @@ public interface TileGenericContextWO<
removeTile(getLocation(), getFace(), getTag()); removeTile(getLocation(), getFace(), getTag());
} }
/*
* Subcontexting
*/
@Override
default TileGenericContextWO<B, T, E> pushCloser() {
return push(getLocation(), getFace(), getLayer() - 1);
}
@Override
default TileGenericContextWO<B, T, E> pushFarther() {
return push(getLocation(), getFace(), getLayer() + 1);
}
} }

View File

@ -30,7 +30,7 @@ public interface TileStackGenericContextRO<
B extends BlockGeneric, B extends BlockGeneric,
T extends TileGeneric, T extends TileGeneric,
E extends EntityGeneric E extends EntityGeneric
> extends WorldContexts.BlockFace, BlockGenericContextRO<B, T, E> { > extends WorldContexts.TileStack, BlockGenericContextRO<B, T, E> {
//@formatter:on //@formatter:on
/** /**
@ -101,4 +101,23 @@ public interface TileStackGenericContextRO<
return getTileCount(getLocation(), getFace()); return getTileCount(getLocation(), getFace());
} }
/*
* Subcontexting
*/
@Override
default TileGenericContextRO<B, T, E> push(int layer) {
return push(getLocation(), getFace(), layer);
}
@Override
default TileStackGenericContextRO<B, T, E> pushCounter() {
return push(getFace().getCounter());
}
@Override
default TileStackGenericContextRO<B, T, E> pushOpposite() {
return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter());
}
} }

View File

@ -32,7 +32,7 @@ public interface TileStackGenericContextWO<
B extends BlockGeneric, B extends BlockGeneric,
T extends TileGeneric, T extends TileGeneric,
E extends EntityGeneric E extends EntityGeneric
> extends WorldContexts.BlockFace, BlockGenericContextWO<B, T, E> { > extends WorldContexts.TileStack, BlockGenericContextWO<B, T, E> {
//@formatter:on //@formatter:on
/** /**
@ -60,4 +60,23 @@ public interface TileStackGenericContextWO<
removeTile(getLocation(), getFace(), tag); removeTile(getLocation(), getFace(), tag);
} }
/*
* Subcontexting
*/
@Override
default TileGenericContextWO<B, T, E> push(int layer) {
return push(getLocation(), getFace(), layer);
}
@Override
default TileStackGenericContextWO<B, T, E> pushCounter() {
return push(getFace().getCounter());
}
@Override
default TileStackGenericContextWO<B, T, E> pushOpposite() {
return push(getLocation().add_(getFace().getRelVector()), getFace().getCounter());
}
} }

View File

@ -20,19 +20,20 @@ package ru.windcorp.progressia.common.world.generic.context;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.context.Context;
import ru.windcorp.progressia.common.world.rels.AbsRelation;
import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.rels.RelFace;
/** /**
* This class defines several {@link Context} subinterfaces that are further * This class defines several {@link Context} subinterfaces that are further
* extended by Generic contexts. These interfaces declare methods for * extended by Generic contexts. These interfaces declare methods for
* determining which location is "relevant" to the context. Since they are not * determining which location is "relevant" to the context and the basic
* Java generics they can safely be extended more than once. * subcontexting methods. Since they are not Java generics they can safely be
* extended more than once.
* <p> * <p>
* Do not reuse these interfaces outside the Generic contexts' package; consider * Do not reuse these interfaces outside the Generic contexts' package; consider
* them to be an implementation detail. * them to be an implementation detail.
* *
* @author javapony * @author javapony
*
*/ */
class WorldContexts { class WorldContexts {
@ -42,48 +43,149 @@ class WorldContexts {
* {@link WorldGenericContextWO}. * {@link WorldGenericContextWO}.
* *
* @author javapony * @author javapony
*
*/ */
public static interface World extends Context { 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 * should not be implemented directly; see {@link BlockGenericContextRO} or
* {@link BlockGenericContextWO}. * {@link BlockGenericContextWO}.
* *
* @author javapony * @author javapony
*
*/ */
public static interface Block extends World { public static interface Block extends World {
/** /**
* Returns the location of the block. * Returns the location of the block.
* <p> * <p>
* 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. * all methods of this context.
* <p> * <p>
* 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}. * while the context is {@linkplain valid}.
* *
* @return a vector describing the block's position * @return a vector describing the block's position
*/ */
Vec3i getLocation(); 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 <i>x</i> component
* @param dy the change of the <i>y</i> component
* @param dz the change of the <i>z</i> component
* @return this object
* @see #pop()
*/
default Block pushRelative(int dx, int dy, int dz) {
return push(getLocation().add_(dx, dy, dz));
} }
/** /**
* A {@link Context} with a world instance, a block location and a block face * 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
* (block side). This interface should not be implemented directly; see * (block side). This interface should not be implemented directly; see
* {@link TileStackGenericContextRO} or {@link TileStackGenericContextWO}. * {@link TileStackGenericContextRO} or {@link TileStackGenericContextWO}.
* *
* @author javapony * @author javapony
*
*/ */
public static interface BlockFace extends Block { public static interface TileStack extends Block {
/** /**
* Returns the face relevant to this context. * Returns the face relevant to this context.
@ -92,17 +194,57 @@ class WorldContexts {
*/ */
RelFace getFace(); 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 * 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 * (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 * @author javapony
*
*/ */
public static interface Tile extends BlockFace { public static interface Tile extends TileStack {
/** /**
* Returns the tile layer relevant to this context. * Returns the tile layer relevant to this context.
@ -114,11 +256,34 @@ class WorldContexts {
/** /**
* Gets the tag of the tile at the relevant position. * 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 * or the tile does not exist
*/ */
int getTag(); 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() { WorldContexts() {

View File

@ -25,6 +25,7 @@ import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.world.context.Context; import ru.windcorp.progressia.common.world.context.Context;
import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.generic.*;
import ru.windcorp.progressia.common.world.rels.BlockFace; import ru.windcorp.progressia.common.world.rels.BlockFace;
import ru.windcorp.progressia.common.world.rels.RelFace;
/** /**
* A {@link Context} with a world instance. * A {@link Context} with a world instance.
@ -188,4 +189,17 @@ public interface WorldGenericContextRO<
}); });
} }
/*
* Subcontexting
*/
@Override
BlockGenericContextRO<B, T, E> push(Vec3i location);
@Override
TileStackGenericContextRO<B, T, E> push(Vec3i location, RelFace face);
@Override
TileGenericContextRO<B, T, E> push(Vec3i location, RelFace face, int layer);
} }

View File

@ -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.context.Context;
import ru.windcorp.progressia.common.world.generic.*; import ru.windcorp.progressia.common.world.generic.*;
import ru.windcorp.progressia.common.world.rels.BlockFace; 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 * A writable {@link Context} with a world instance. This context provides
@ -150,4 +151,17 @@ public interface WorldGenericContextWO<
*/ */
<SE extends StatefulObject & EntityGeneric> void changeEntity(SE entity, StateChange<SE> change); <SE extends StatefulObject & EntityGeneric> void changeEntity(SE entity, StateChange<SE> change);
/*
* Subcontexting
*/
@Override
BlockGenericContextWO<B, T, E> push(Vec3i location);
@Override
TileStackGenericContextWO<B, T, E> push(Vec3i location, RelFace face);
@Override
TileGenericContextWO<B, T, E> push(Vec3i location, RelFace face, int layer);
} }

View File

@ -17,7 +17,10 @@
*/ */
package ru.windcorp.progressia.server.world.context; 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.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 { public interface ServerBlockContext extends BlockDataContext, ServerWorldContext, ServerBlockContextRO {
@ -26,9 +29,59 @@ public interface ServerBlockContext extends BlockDataContext, ServerWorldContext
@Override @Override
ServerBlockContext data(); 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 @Override
ServerBlockContext.Logic logic(); 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);
}
} }

View File

@ -17,9 +17,12 @@
*/ */
package ru.windcorp.progressia.server.world.context; 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.context.BlockDataContextRO;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.context.BlockGenericContextRO; 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.block.BlockLogic;
import ru.windcorp.progressia.server.world.tile.TileLogic; import ru.windcorp.progressia.server.world.tile.TileLogic;
@ -31,9 +34,59 @@ public interface ServerBlockContextRO extends ServerWorldContextRO, BlockDataCon
@Override @Override
ServerBlockContextRO data(); 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 @Override
ServerBlockContextRO.Logic logic(); 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);
}
} }

View File

@ -26,9 +26,29 @@ public interface ServerTileContext extends TileDataContext, ServerTileStackConte
@Override @Override
ServerTileContext data(); 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 @Override
ServerTileContext.Logic logic(); ServerTileContext.Logic logic();
@Override
default ServerTileContext pushCloser() {
return push(getLocation(), getFace(), getLayer() - 1);
}
@Override
default ServerTileContext pushFarther() {
return push(getLocation(), getFace(), getLayer() + 1);
}
} }

View File

@ -31,9 +31,29 @@ public interface ServerTileContextRO extends ServerTileStackContextRO, TileDataC
@Override @Override
ServerTileContextRO data(); 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 @Override
ServerTileContextRO.Logic logic(); ServerTileContextRO.Logic logic();
@Override
default ServerTileContextRO pushCloser() {
return push(getLocation(), getFace(), getLayer() - 1);
}
@Override
default ServerTileContextRO pushFarther() {
return push(getLocation(), getFace(), getLayer() + 1);
}
} }

View File

@ -26,9 +26,39 @@ public interface ServerTileStackContext extends TileStackDataContext, ServerBloc
@Override @Override
ServerTileStackContext data(); 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 @Override
ServerTileStackContext.Logic logic(); 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());
}
} }

View File

@ -31,9 +31,39 @@ public interface ServerTileStackContextRO extends ServerBlockContextRO, TileStac
@Override @Override
ServerTileStackContextRO data(); 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 @Override
ServerTileStackContextRO.Logic logic(); 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());
}
} }

View File

@ -17,7 +17,9 @@
*/ */
package ru.windcorp.progressia.server.world.context; 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.context.WorldDataContext;
import ru.windcorp.progressia.common.world.rels.RelFace;
public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO { public interface ServerWorldContext extends WorldDataContext, ServerWorldContextRO {
@ -26,9 +28,27 @@ public interface ServerWorldContext extends WorldDataContext, ServerWorldContext
@Override @Override
ServerWorldContext data(); 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 @Override
ServerWorldContext.Logic logic(); ServerWorldContext.Logic logic();
@Override
ServerBlockContext push(Vec3i location);
@Override
ServerTileStackContext push(Vec3i location, RelFace face);
@Override
ServerTileContext push(Vec3i location, RelFace face, int layer);
} }

View File

@ -1,8 +1,10 @@
package ru.windcorp.progressia.server.world.context; 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.context.WorldDataContextRO;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.generic.context.WorldGenericContextRO; 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.block.BlockLogic;
import ru.windcorp.progressia.server.world.tile.TileLogic; import ru.windcorp.progressia.server.world.tile.TileLogic;
@ -19,6 +21,15 @@ public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext
*/ */
ServerWorldContextRO data(); 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);
} }
/** /**
@ -30,4 +41,13 @@ public interface ServerWorldContextRO extends WorldDataContextRO, ServerContext
*/ */
ServerWorldContextRO.Logic logic(); ServerWorldContextRO.Logic logic();
@Override
ServerBlockContextRO push(Vec3i location);
@Override
ServerTileStackContextRO push(Vec3i location, RelFace face);
@Override
ServerTileContextRO push(Vec3i location, RelFace face, int layer);
} }

View File

@ -17,7 +17,13 @@
*/ */
package ru.windcorp.progressia.server.world.context.impl; 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.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.WorldLogic;
import ru.windcorp.progressia.server.world.WorldLogicRO; import ru.windcorp.progressia.server.world.WorldLogicRO;
import ru.windcorp.progressia.server.world.context.*; import ru.windcorp.progressia.server.world.context.*;
@ -45,7 +51,8 @@ import ru.windcorp.progressia.server.world.context.*;
* *
* @author javapony * @author javapony
*/ */
public abstract class ReusableServerContext implements ServerTileContext { public abstract class ReusableServerContext extends AbstractContextRO<BlockData, TileData, EntityData>
implements ServerTileContext {
/** /**
* An RSC can conform to a variety of different {@link Context} interfaces. * 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 * @return a {@link ReusableServerContextBuilders.Empty} instance that may
* be used to reinitialize this object * be used to reinitialize this object
* @throws IllegalStateException if active subcontexting is detected. * @throws IllegalStateException if active subcontexting is detected
* Detection is done on a best-effort basis;
* do not rely this exception
*/ */
public abstract ReusableServerContextBuilders.Empty reuse() throws IllegalStateException; public abstract ReusableServerContextBuilders.Empty reuse() throws IllegalStateException;
@ -116,4 +121,22 @@ public abstract class ReusableServerContext implements ServerTileContext {
return new ReusableServerContextImpl(); 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;
}
} }

View File

@ -69,30 +69,6 @@ class ReusableServerContextImpl extends ReusableServerContext
*/ */
protected WorldData worldData; 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()}. * The {@link Random} instance exposed with {@link #getRandom()}.
*/ */
@ -124,11 +100,11 @@ class ReusableServerContextImpl extends ReusableServerContext
public Role getRole() { public Role getRole() {
if (server == null) if (server == null)
return Role.NONE; return Role.NONE;
if (location == null) if (frame == null)
return Role.WORLD; return Role.WORLD;
if (blockFace == null) if (frame.face == null)
return Role.LOCATION; return Role.LOCATION;
if (layer == -1) if (frame.layer == -1)
return Role.TILE_STACK; return Role.TILE_STACK;
return Role.TILE; return Role.TILE;
} }
@ -186,19 +162,19 @@ class ReusableServerContextImpl extends ReusableServerContext
case TILE: case TILE:
result = String.format( result = String.format(
"ServerTileContext[x=%d, y=%d, z=%d, %s, index=%d]", "ServerTileContext[x=%d, y=%d, z=%d, %s, index=%d]",
location.x, frame.location.x,
location.y, frame.location.y,
location.z, frame.location.z,
blockFace, frame.face,
layer frame.layer
); );
break; break;
case TILE_STACK: case TILE_STACK:
result = String 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; break;
case LOCATION: 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; break;
case WORLD: case WORLD:
result = String.format("ServerWorldContext"); result = String.format("ServerWorldContext");
@ -222,16 +198,13 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public Empty reuse() { public Empty reuse() {
if (subcontextDepth != 0) {
throw new IllegalStateException("Resetting is not allowed when subcontexting");
}
server = null; server = null;
worldLogic = null; worldLogic = null;
worldData = null; worldData = null;
location = null;
blockFace = null; while (isSubcontexting()) {
layer = -1; pop();
}
isBuilder = true; isBuilder = true;
@ -270,8 +243,7 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public WithLocation at(Vec3i location) { public WithLocation at(Vec3i location) {
requireBuilderRole(Role.WORLD); requireBuilderRole(Role.WORLD);
this.location = this.locationVectorContainer; push(location);
this.location.set(location.x, location.y, location.z);
return this; return this;
} }
@ -282,14 +254,14 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public WithTileStack on(RelFace side) { public WithTileStack on(RelFace side) {
requireBuilderRole(Role.LOCATION); requireBuilderRole(Role.LOCATION);
this.blockFace = side; frame.face = side;
return this; return this;
} }
@Override @Override
public WithTileStack on(BlockFace side) { public WithTileStack on(BlockFace side) {
requireBuilderRole(Role.LOCATION); requireBuilderRole(Role.LOCATION);
this.blockFace = side.relativize(worldLogic.getData().getUp(location)); frame.face = side.relativize(worldLogic.getData().getUp(frame.location));
return this; return this;
} }
@ -300,7 +272,7 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public ReusableServerContext index(int index) { public ReusableServerContext index(int index) {
requireBuilderRole(Role.TILE_STACK); requireBuilderRole(Role.TILE_STACK);
this.layer = index; frame.layer = index;
return build(); return build();
} }
@ -317,19 +289,19 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public Vec3i getLocation() { public Vec3i getLocation() {
assert requireContextRole(Role.LOCATION); assert requireContextRole(Role.LOCATION);
return location; return frame.location;
} }
@Override @Override
public RelFace getFace() { public RelFace getFace() {
assert requireContextRole(Role.TILE_STACK); assert requireContextRole(Role.TILE_STACK);
return blockFace; return frame.face;
} }
@Override @Override
public int getLayer() { public int getLayer() {
assert requireContextRole(Role.TILE); assert requireContextRole(Role.TILE);
return layer; return frame.layer;
} }
/* /*
@ -402,16 +374,16 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public int getTag() { public int getTag() {
assert requireContextRole(Role.TILE); assert requireContextRole(Role.TILE);
TileDataStack stack = worldData.getTilesOrNull(location, blockFace); TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face);
if (stack == null) if (stack == null)
return -1; return -1;
return stack.getTagByIndex(layer); return stack.getTagByIndex(frame.layer);
} }
@Override @Override
public int getTileCount(Vec3i location, BlockFace face) { public int getTileCount(Vec3i location, BlockFace face) {
assert requireContextRole(Role.TILE_STACK); assert requireContextRole(Role.TILE_STACK);
TileDataStack stack = worldData.getTilesOrNull(location, blockFace); TileDataStack stack = worldData.getTilesOrNull(frame.location, frame.face);
if (stack == null) if (stack == null)
return 0; return 0;
return stack.size(); return stack.size();
@ -516,17 +488,17 @@ class ReusableServerContextImpl extends ReusableServerContext
@Override @Override
public Vec3i getLocation() { public Vec3i getLocation() {
return location; return frame.location;
} }
@Override @Override
public RelFace getFace() { public RelFace getFace() {
return blockFace; return frame.face;
} }
@Override @Override
public int getLayer() { public int getLayer() {
return layer; return frame.layer;
} }
/* /*
@ -614,6 +586,33 @@ class ReusableServerContextImpl extends ReusableServerContext
return worldLogic.getEntity(entityId); 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 * MISC
*/ */