Files
StructureLib/src/main/java/com/gtnewhorizon/structurelib/structure/AutoPlaceEnvironment.java
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

231 lines
8.2 KiB
Java
Raw Normal View History

2022-09-11 02:54:11 +08:00
package com.gtnewhorizon.structurelib.structure;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
2022-09-11 02:54:11 +08:00
import javax.annotation.Nonnull;
2022-09-11 02:54:11 +08:00
import net.minecraft.entity.player.EntityPlayer;
2022-09-15 18:16:28 +08:00
import net.minecraft.entity.player.EntityPlayerMP;
2022-09-11 02:54:11 +08:00
import net.minecraft.item.ItemStack;
import net.minecraft.util.IChatComponent;
import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing;
2022-09-11 02:54:11 +08:00
/**
* Represent the environment in which autoplace of a single element took place.
*/
public class AutoPlaceEnvironment {
2022-09-11 02:54:11 +08:00
private IItemSource source;
private final EntityPlayer actor;
private final Consumer<IChatComponent> chatter;
private final IStructureDefinition<?> definition;
private final String piece;
private final ExtendedFacing facing;
final int[] offsetABC;
private final int[] baseOffsetABC;
public static AutoPlaceEnvironment fromLegacy(IItemSource source, EntityPlayer actor,
2022-09-15 18:02:53 +08:00
Consumer<IChatComponent> chatter) {
2022-09-11 02:54:11 +08:00
if (source instanceof WrappedIItemSource) {
AutoPlaceEnvironment original = ((WrappedIItemSource) source).container;
// feels like this is extremely likely to cause issues, but this does allow us to recover lost info.
// TODO probably should remove this once all addons migrate over
if (actor != original.actor || chatter != original.chatter) {
AutoPlaceEnvironment newEnv = original;
if (actor != original.actor) newEnv = newEnv.withActor(actor);
if (chatter != original.chatter) newEnv = newEnv.withChatter(chatter);
return newEnv;
}
return original;
}
return new AutoPlaceEnvironment(source, actor, chatter, null, null, null, null, null);
}
AutoPlaceEnvironment(EntityPlayer actor, Consumer<IChatComponent> chatter, IStructureDefinition<?> definition,
String piece, ExtendedFacing facing, int[] baseOffsetABC) {
this.source = null;
this.actor = actor;
this.chatter = chatter;
this.definition = definition;
this.piece = piece;
this.facing = facing;
this.offsetABC = new int[3];
this.baseOffsetABC = baseOffsetABC;
}
AutoPlaceEnvironment(IItemSource source, EntityPlayer actor, Consumer<IChatComponent> chatter,
IStructureDefinition<?> definition, String piece, ExtendedFacing facing, int[] offsetABC,
int[] baseOffsetABC) {
this.source = definition != null && !(source instanceof WrappedIItemSource)
? new WrappedIItemSource(this, source)
: source;
this.actor = actor;
this.chatter = chatter;
this.definition = definition;
this.piece = piece;
this.facing = facing;
this.offsetABC = offsetABC;
this.baseOffsetABC = baseOffsetABC;
}
protected AutoPlaceEnvironment(AutoPlaceEnvironment parent) {
this(
parent.getSource(),
parent.getActor(),
parent.getChatter(),
parent.definition,
parent.piece,
parent.facing,
parent.offsetABC,
parent.baseOffsetABC);
}
void setSource(IItemSource source) {
this.source = definition != null && !(source instanceof WrappedIItemSource)
? new WrappedIItemSource(this, source)
: source;
}
public APILevel getAPILevel() {
2022-09-15 18:16:28 +08:00
return definition == null ? actor instanceof EntityPlayerMP ? APILevel.Legacy : APILevel.LegacyRelaxed
: APILevel.V2;
2022-09-11 02:54:11 +08:00
}
/**
* From where survival autoplace will drain resources.
*/
public IItemSource getSource() {
return source;
}
/**
* The initiator of actions. for very critical errors you can also just send the error messages here, bypassing any
* filter that {@link #getChatter()} might have. You might want to use
* {@link com.gtnewhorizon.structurelib.StructureLibAPI#addThrottledChat(Object, EntityPlayer, IChatComponent, short)}
* to help reduce spam.
*/
public EntityPlayer getActor() {
return actor;
}
/**
* send error messages here. Caller will choose an appropriate way to forward it to player if the other fallbacks
* also fails.
*/
public Consumer<IChatComponent> getChatter() {
return chatter;
}
/**
* Test if given location is contained within the current piece.
2022-09-15 18:16:28 +08:00
*
2022-09-11 02:54:11 +08:00
* @param offsetA offset in A direction <b>relative to current element</b>
* @param offsetB offset in B direction <b>relative to current element</b>
* @param offsetC offset in C direction <b>relative to current element</b>
* @return true if contained, false otherwise.
*/
public boolean isContainedInPiece(int offsetA, int offsetB, int offsetC) {
if (definition == null) return false;
return definition.isContainedInStructure(
piece,
offsetABC[0] + offsetA + baseOffsetABC[0],
offsetABC[1] + offsetB + baseOffsetABC[1],
offsetABC[2] + offsetC + baseOffsetABC[2]);
}
public ExtendedFacing getFacing() {
return facing;
}
/**
* Return a new instance with source modified to given value.
*
* @param source new source
* @return new instance
*/
public AutoPlaceEnvironment withSource(IItemSource source) {
return new AutoPlaceEnvironment(source, actor, chatter, definition, piece, facing, offsetABC, baseOffsetABC);
}
/**
* Return a new instance with actor modified to given value.
*
* @param actor new actor
* @return new instance
*/
2022-09-15 18:02:53 +08:00
public AutoPlaceEnvironment withActor(EntityPlayer actor) {
2022-09-11 02:54:11 +08:00
return new AutoPlaceEnvironment(source, actor, chatter, definition, piece, facing, offsetABC, baseOffsetABC);
}
/**
* Return a new instance with chatter modified to given value.
*
* @param chatter new chatter
* @return new instance
*/
public AutoPlaceEnvironment withChatter(Consumer<IChatComponent> chatter) {
return new AutoPlaceEnvironment(source, actor, chatter, definition, piece, facing, offsetABC, baseOffsetABC);
}
private static class WrappedIItemSource implements IItemSource {
2022-09-11 02:54:11 +08:00
final AutoPlaceEnvironment container;
final IItemSource delegate;
public WrappedIItemSource(AutoPlaceEnvironment container, IItemSource delegate) {
this.container = container;
this.delegate = delegate;
}
@Override
@Nonnull
public Map<ItemStack, Integer> take(Predicate<ItemStack> predicate, boolean simulate, int count) {
return delegate.take(predicate, simulate, count);
}
@Override
public ItemStack takeOne(Predicate<ItemStack> predicate, boolean simulate) {
return delegate.takeOne(predicate, simulate);
}
@Override
public boolean takeAll(Predicate<ItemStack> predicate, boolean simulate, int count) {
return delegate.takeAll(predicate, simulate, count);
}
@Override
public boolean takeOne(ItemStack stack, boolean simulate) {
return delegate.takeOne(stack, simulate);
}
@Override
public boolean takeAll(ItemStack stack, boolean simulate) {
return delegate.takeAll(stack, simulate);
}
}
2022-09-15 18:16:28 +08:00
/**
* Defines the various API level an {@link AutoPlaceEnvironment} has implemented.
* <p>
* Enum constants are defined in chronological order.
*/
2022-09-11 02:54:11 +08:00
public enum APILevel {
2022-09-15 18:16:28 +08:00
/**
* Implements {@link #getChatter()}, {@link #getActor()} and {@link #getSource()}. {@link #getActor()} is
* guaranteed to be an {@link net.minecraft.entity.player.EntityPlayerMP}
*/
2022-09-11 02:54:11 +08:00
Legacy,
2022-09-15 18:16:28 +08:00
/**
* Implements {@link #getChatter()}, {@link #getActor()} and {@link #getSource()}. {@link #getActor()} is
* <b>NOT</b> guaranteed to be an {@link net.minecraft.entity.player.EntityPlayerMP}
*/
LegacyRelaxed,
/**
* Implements everything so far we have defined.
*/
2022-09-11 02:54:11 +08:00
V2,
}
}