added Cypher's CastingEnvironmentComponent system, with some extensions.
This commit is contained in:
parent
4c9e380ea8
commit
9904e3adb4
8 changed files with 171 additions and 14 deletions
|
@ -16,15 +16,21 @@ import net.minecraft.server.level.ServerLevel;
|
|||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
import static at.petrak.hexcasting.api.casting.eval.CastingEnvironmentComponent.*;
|
||||
|
||||
/**
|
||||
* Environment within which hexes are cast.
|
||||
|
@ -32,8 +38,37 @@ import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
|||
* Stuff like "the player with a staff," "the player with a trinket," "spell circles,"
|
||||
*/
|
||||
public abstract class CastingEnvironment {
|
||||
/**
|
||||
* Stores all listeners that should be notified whenever a CastingEnvironment is initialised.
|
||||
*/
|
||||
private static final List<Consumer<CastingEnvironment>> createEventListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add a listener that will be called whenever a new CastingEnvironment is created.
|
||||
*/
|
||||
public static void addCreateEventListener(Consumer<CastingEnvironment> listener) {
|
||||
createEventListeners.add(listener);
|
||||
}
|
||||
|
||||
private boolean createEventTriggered = false;
|
||||
|
||||
public final void triggerCreateEvent() {
|
||||
if (!createEventTriggered) {
|
||||
for (var listener : createEventListeners)
|
||||
listener.accept(this);
|
||||
createEventTriggered = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected final ServerLevel world;
|
||||
|
||||
protected Map<CastingEnvironmentComponent.Key<?>, @NotNull CastingEnvironmentComponent> componentMap = new HashMap<>();
|
||||
private final List<PostExecutionComponent> postExecutionComponents = new ArrayList<>();
|
||||
private final List<ExtractMediaComponent> extractMediaComponents = new ArrayList<>();
|
||||
private final List<IsVecInRangeComponent> isVecInRangeComponents = new ArrayList<>();
|
||||
private final List<HasEditPermissionsAtComponent> hasEditPermissionsAtComponents = new ArrayList<>();
|
||||
|
||||
protected CastingEnvironment(ServerLevel world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
@ -56,6 +91,39 @@ public abstract class CastingEnvironment {
|
|||
*/
|
||||
public abstract MishapEnvironment getMishapEnvironment();
|
||||
|
||||
public <T extends CastingEnvironmentComponent> void addExtension(@NotNull T extension) {
|
||||
componentMap.put(extension.getKey(), extension);
|
||||
if (extension instanceof PostExecutionComponent postExecutionComponent)
|
||||
postExecutionComponents.add(postExecutionComponent);
|
||||
if (extension instanceof ExtractMediaComponent extractMediaComponent)
|
||||
extractMediaComponents.add(extractMediaComponent);
|
||||
if (extension instanceof IsVecInRangeComponent isVecInRangeComponent)
|
||||
isVecInRangeComponents.add(isVecInRangeComponent);
|
||||
if (extension instanceof HasEditPermissionsAtComponent hasEditPermissionsAtComponent)
|
||||
hasEditPermissionsAtComponents.add(hasEditPermissionsAtComponent);
|
||||
}
|
||||
|
||||
public void removeExtension(@NotNull CastingEnvironmentComponent.Key<?> key) {
|
||||
var extension = componentMap.remove(key);
|
||||
if (extension == null)
|
||||
return;
|
||||
|
||||
if (extension instanceof PostExecutionComponent postExecutionComponent)
|
||||
postExecutionComponents.remove(postExecutionComponent);
|
||||
if (extension instanceof ExtractMediaComponent extractMediaComponent)
|
||||
extractMediaComponents.remove(extractMediaComponent);
|
||||
if (extension instanceof IsVecInRangeComponent isVecInRangeComponent)
|
||||
isVecInRangeComponents.remove(isVecInRangeComponent);
|
||||
if (extension instanceof HasEditPermissionsAtComponent hasEditPermissionsAtComponent)
|
||||
hasEditPermissionsAtComponents.remove(hasEditPermissionsAtComponent);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends CastingEnvironmentComponent> T getExtension(@NotNull CastingEnvironmentComponent.Key<T> key) {
|
||||
return (T) componentMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* If something about this ARE itself is invalid, mishap.
|
||||
* <p>
|
||||
|
@ -89,7 +157,10 @@ public abstract class CastingEnvironment {
|
|||
/**
|
||||
* Do whatever you like after a pattern is executed.
|
||||
*/
|
||||
public abstract void postExecution(CastResult result);
|
||||
public void postExecution(CastResult result) {
|
||||
for (var postExecutionComponent : postExecutionComponents)
|
||||
postExecutionComponent.onPostExecution(result);
|
||||
}
|
||||
|
||||
public abstract Vec3 mishapSprayPos();
|
||||
|
||||
|
@ -114,19 +185,53 @@ public abstract class CastingEnvironment {
|
|||
* If there was enough media found, it will return less or equal to zero; if there wasn't, it will be
|
||||
* positive.
|
||||
*/
|
||||
public abstract long extractMedia(long cost);
|
||||
public long extractMedia(long cost) {
|
||||
for (var extractMediaComponent : extractMediaComponents)
|
||||
cost = extractMediaComponent.onExtractMedia(cost);
|
||||
return extractMediaEnvironment(cost);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to extract the given amount of media. Returns the amount of media left in the cost.
|
||||
* <p>
|
||||
* If there was enough media found, it will return less or equal to zero; if there wasn't, it will be
|
||||
* positive.
|
||||
*/
|
||||
protected abstract long extractMediaEnvironment(long cost);
|
||||
|
||||
/**
|
||||
* Get if the vec is close enough, to the player or sentinel ...
|
||||
* <p>
|
||||
* Doesn't take into account being out of the <em>world</em>.
|
||||
*/
|
||||
public abstract boolean isVecInRange(Vec3 vec);
|
||||
public boolean isVecInRange(Vec3 vec) {
|
||||
boolean isInRange = isVecInRangeEnvironment(vec);
|
||||
for (var isVecInRangeComponent : isVecInRangeComponents)
|
||||
isInRange = isVecInRangeComponent.onIsVecInRange(vec, isInRange);
|
||||
return isInRange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get if the vec is close enough, to the player or sentinel ...
|
||||
* <p>
|
||||
* Doesn't take into account being out of the <em>world</em>.
|
||||
*/
|
||||
protected abstract boolean isVecInRangeEnvironment(Vec3 vec);
|
||||
|
||||
/**
|
||||
* Return whether the caster can edit blocks at the given permission (i.e. not adventure mode, etc.)
|
||||
*/
|
||||
public abstract boolean hasEditPermissionsAt(BlockPos vec);
|
||||
public boolean hasEditPermissionsAt(BlockPos pos) {
|
||||
boolean hasEditPermissionsAt = hasEditPermissionsAtEnvironment(pos);
|
||||
for (var hasEditPermissionsAtComponent : hasEditPermissionsAtComponents)
|
||||
hasEditPermissionsAt = hasEditPermissionsAtComponent.onHasEditPermissionsAt(pos, hasEditPermissionsAt);
|
||||
return hasEditPermissionsAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the caster can edit blocks at the given permission (i.e. not adventure mode, etc.)
|
||||
*/
|
||||
protected abstract boolean hasEditPermissionsAtEnvironment(BlockPos pos);
|
||||
|
||||
public final boolean isVecInWorld(Vec3 vec) {
|
||||
return this.world.isInWorldBounds(BlockPos.containing(vec))
|
||||
|
@ -138,7 +243,7 @@ public abstract class CastingEnvironment {
|
|||
}
|
||||
|
||||
public final boolean isEntityInRange(Entity e) {
|
||||
return this.isVecInRange(e.position());
|
||||
return e instanceof Player || this.isVecInRange(e.position());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package at.petrak.hexcasting.api.casting.eval;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface CastingEnvironmentComponent {
|
||||
Key<?> getKey();
|
||||
|
||||
interface Key<C extends CastingEnvironmentComponent> {}
|
||||
|
||||
interface PostExecutionComponent extends CastingEnvironmentComponent {
|
||||
/**
|
||||
* Do whatever you like after a pattern is executed.
|
||||
*/
|
||||
void onPostExecution(CastResult result);
|
||||
}
|
||||
|
||||
interface ExtractMediaComponent extends CastingEnvironmentComponent {
|
||||
/**
|
||||
* Receives the cost that is being extracted, should return the
|
||||
* remaining cost after deducting whatever cost source this component
|
||||
* is responsible for (should be >= 0). All Components are executed
|
||||
* before the CastingEnvironment's extractMedia is executed.
|
||||
*/
|
||||
long onExtractMedia(long cost);
|
||||
}
|
||||
|
||||
interface IsVecInRangeComponent extends CastingEnvironmentComponent {
|
||||
/**
|
||||
* Receives the vec, and the current return value, and returns the new return value.
|
||||
*/
|
||||
boolean onIsVecInRange(Vec3 vec, boolean current);
|
||||
}
|
||||
|
||||
interface HasEditPermissionsAtComponent extends CastingEnvironmentComponent {
|
||||
/**
|
||||
* Receives the vec, and the current return value, and returns the new return value.
|
||||
*/
|
||||
boolean onHasEditPermissionsAt(BlockPos pos, boolean current);
|
||||
}
|
||||
}
|
|
@ -73,6 +73,8 @@ public class CircleCastEnv extends CastingEnvironment {
|
|||
|
||||
@Override
|
||||
public void postExecution(CastResult result) {
|
||||
super.postExecution(result);
|
||||
|
||||
// we always want to play this sound one at a time
|
||||
var sound = result.getSound().sound();
|
||||
if (sound != null) {
|
||||
|
@ -103,7 +105,7 @@ public class CircleCastEnv extends CastingEnvironment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long extractMedia(long cost) {
|
||||
public long extractMediaEnvironment(long cost) {
|
||||
var entity = this.getImpetus();
|
||||
if (entity == null)
|
||||
return cost;
|
||||
|
@ -120,7 +122,7 @@ public class CircleCastEnv extends CastingEnvironment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isVecInRange(Vec3 vec) {
|
||||
public boolean isVecInRangeEnvironment(Vec3 vec) {
|
||||
var caster = this.execState.getCaster(this.world);
|
||||
if (caster != null) {
|
||||
var sentinel = HexAPI.instance().getSentinel(caster);
|
||||
|
@ -137,7 +139,7 @@ public class CircleCastEnv extends CastingEnvironment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEditPermissionsAt(BlockPos vec) {
|
||||
public boolean hasEditPermissionsAtEnvironment(BlockPos pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,12 +37,14 @@ public class PackagedItemCastEnv extends PlayerBasedCastEnv {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long extractMedia(long costLeft) {
|
||||
public long extractMediaEnvironment(long costLeft) {
|
||||
if (this.caster.isCreative())
|
||||
return 0;
|
||||
|
||||
var casterStack = this.caster.getItemInHand(this.castingHand);
|
||||
var casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack);
|
||||
if (casterHexHolder == null)
|
||||
return costLeft;
|
||||
var canCastFromInv = casterHexHolder.canDrawMediaFromInventory();
|
||||
|
||||
var casterMediaHolder = IXplatAbstractions.INSTANCE.findMediaHolder(casterStack);
|
||||
|
@ -69,6 +71,8 @@ public class PackagedItemCastEnv extends PlayerBasedCastEnv {
|
|||
public FrozenPigment getPigment() {
|
||||
var casterStack = this.caster.getItemInHand(this.castingHand);
|
||||
var casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack);
|
||||
if (casterHexHolder == null)
|
||||
return IXplatAbstractions.INSTANCE.getPigment(this.caster);
|
||||
var hexHolderPigment = casterHexHolder.getPigment();
|
||||
if (hexHolderPigment != null)
|
||||
return hexHolderPigment;
|
||||
|
|
|
@ -53,6 +53,8 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
|
||||
@Override
|
||||
public void postExecution(CastResult result) {
|
||||
super.postExecution(result);
|
||||
|
||||
for (var sideEffect : result.getSideEffects()) {
|
||||
if (sideEffect instanceof OperatorSideEffect.DoMishap doMishap) {
|
||||
this.sendMishapMsgToPlayer(doMishap);
|
||||
|
@ -165,7 +167,7 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isVecInRange(Vec3 vec) {
|
||||
public boolean isVecInRangeEnvironment(Vec3 vec) {
|
||||
var sentinel = HexAPI.instance().getSentinel(this.caster);
|
||||
if (sentinel != null
|
||||
&& sentinel.extendsRange()
|
||||
|
@ -179,8 +181,8 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasEditPermissionsAt(BlockPos vec) {
|
||||
return this.caster.gameMode.getGameModeForPlayer() != GameType.ADVENTURE && this.world.mayInteract(this.caster, vec);
|
||||
public boolean hasEditPermissionsAtEnvironment(BlockPos pos) {
|
||||
return this.caster.gameMode.getGameModeForPlayer() != GameType.ADVENTURE && this.world.mayInteract(this.caster, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -52,7 +52,7 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long extractMedia(long cost) {
|
||||
public long extractMediaEnvironment(long cost) {
|
||||
if (this.caster.isCreative())
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package at.petrak.hexcasting.api.casting.eval.sideeffects
|
|||
|
||||
import at.petrak.hexcasting.api.casting.ParticleSpray
|
||||
import at.petrak.hexcasting.api.casting.RenderedSpell
|
||||
import at.petrak.hexcasting.api.casting.eval.env.PlayerBasedCastEnv
|
||||
import at.petrak.hexcasting.api.casting.eval.vm.CastingVM
|
||||
import at.petrak.hexcasting.api.casting.mishaps.Mishap
|
||||
import at.petrak.hexcasting.api.mod.HexStatistics
|
||||
|
|
|
@ -23,6 +23,10 @@ import net.minecraft.server.level.ServerLevel
|
|||
* [CastingEnvironment] to affect the world.
|
||||
*/
|
||||
class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
|
||||
init {
|
||||
env.triggerCreateEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a single iota.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue