More rune types

This commit is contained in:
shylie 2024-08-04 16:19:04 -04:00
parent a2ef7e870c
commit 2cb6007d16
21 changed files with 312 additions and 21 deletions

View File

@ -8,7 +8,8 @@ import info.shylie.ashes.entity.AshenGolemEntity;
import info.shylie.ashes.item.RuneItem; import info.shylie.ashes.item.RuneItem;
import info.shylie.ashes.rune.param.BlockPosRune; import info.shylie.ashes.rune.param.BlockPosRune;
import info.shylie.ashes.rune.param.ItemRune; import info.shylie.ashes.rune.param.ItemRune;
import info.shylie.ashes.rune.task.*; import info.shylie.ashes.rune.task.composite.*;
import info.shylie.ashes.rune.task.leaf.*;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
@ -49,8 +50,14 @@ public class AshesRegistry {
public static final RegistryObject<RuneType<SelectorRune>> SELECTOR_RUNE; public static final RegistryObject<RuneType<SelectorRune>> SELECTOR_RUNE;
public static final RegistryObject<RuneType<StepSequenceRune>> STEP_SEQUENCE_RUNE; public static final RegistryObject<RuneType<StepSequenceRune>> STEP_SEQUENCE_RUNE;
public static final RegistryObject<RuneType<StepSelectorRune>> STEP_SELECTOR_RUNE; public static final RegistryObject<RuneType<StepSelectorRune>> STEP_SELECTOR_RUNE;
public static final RegistryObject<RuneType<InverterRune>> INVERTER_RUNE;
public static final RegistryObject<RuneType<MoveRune>> MOVE_RUNE; public static final RegistryObject<RuneType<MoveRune>> MOVE_RUNE;
public static final RegistryObject<RuneType<TakeItemRune>> TAKE_ITEM_RUNE;
public static final RegistryObject<RuneType<PutItemRune>> PUT_ITEM_RUNE;
public static final RegistryObject<RuneType<InteractRune>> INTERACT_RUNE;
public static final RegistryObject<RuneType<HasItemRune>> HAS_ITEM_RUNE;
static { static {
HEATED_ASHY_INGOT = ITEMS.register( HEATED_ASHY_INGOT = ITEMS.register(
@ -89,8 +96,13 @@ public class AshesRegistry {
SELECTOR_RUNE = RUNES.register("selector", RuneType.Builder.of(SelectorRune::new)::build); SELECTOR_RUNE = RUNES.register("selector", RuneType.Builder.of(SelectorRune::new)::build);
STEP_SEQUENCE_RUNE = RUNES.register("step_sequence", RuneType.Builder.of(StepSequenceRune::new)::build); STEP_SEQUENCE_RUNE = RUNES.register("step_sequence", RuneType.Builder.of(StepSequenceRune::new)::build);
STEP_SELECTOR_RUNE = RUNES.register("step_selector", RuneType.Builder.of(StepSelectorRune::new)::build); STEP_SELECTOR_RUNE = RUNES.register("step_selector", RuneType.Builder.of(StepSelectorRune::new)::build);
INVERTER_RUNE = RUNES.register("inverter", RuneType.Builder.of(InverterRune::new)::build);
MOVE_RUNE = RUNES.register("move", RuneType.Builder.of(MoveRune::new)::build); MOVE_RUNE = RUNES.register("move", RuneType.Builder.of(MoveRune::new)::build);
TAKE_ITEM_RUNE = RUNES.register("take_item", RuneType.Builder.of(TakeItemRune::new)::build);
PUT_ITEM_RUNE = RUNES.register("put_item", RuneType.Builder.of(PutItemRune::new)::build);
INTERACT_RUNE = RUNES.register("interact", RuneType.Builder.of(InteractRune::new)::build);
HAS_ITEM_RUNE = RUNES.register("has_item", RuneType.Builder.of(HasItemRune::new)::build);
} }
public static RegistryObject<ForgeSpawnEggItem> registerSpawnEgg(RegistryObject<? extends EntityType<? extends Mob>> type, int bg, int fg) { public static RegistryObject<ForgeSpawnEggItem> registerSpawnEgg(RegistryObject<? extends EntityType<? extends Mob>> type, int bg, int fg) {

View File

@ -0,0 +1,14 @@
package info.shylie.ashes;
import java.lang.reflect.Array;
public class Utils {
public static <T> T[] concat(T[] b, T... a) {
@SuppressWarnings("unchecked")
T[] c = (T[])Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
}

View File

@ -1,10 +1,16 @@
package info.shylie.ashes.api.golem; package info.shylie.ashes.api.golem;
import com.mojang.authlib.GameProfile;
import info.shylie.ashes.api.rune.TaskRune; import info.shylie.ashes.api.rune.TaskRune;
import net.minecraft.nbt.CompoundTag; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.animal.AbstractGolem; import net.minecraft.world.entity.animal.AbstractGolem;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.FakePlayerFactory;
public interface IGolem { public interface IGolem {
float MAX_INTERACT_DISTANCE = 2;
AbstractGolem asEntity(); AbstractGolem asEntity();
TaskRune getTask(); TaskRune getTask();
@ -16,4 +22,15 @@ public interface IGolem {
task.update(this); task.update(this);
} }
} }
default FakePlayer getFakePlayer() {
return FakePlayerFactory.get((ServerLevel)asEntity().level(), new GameProfile(
asEntity().getUUID(),
asEntity().getDisplayName().getString()
));
}
default boolean canInteract(BlockPos pos) {
return pos != null && asEntity().distanceToSqr(pos.getX(), pos.getY(), pos.getZ()) <= 3;
}
} }

View File

@ -19,7 +19,7 @@ public abstract class CompositeTaskRune extends TaskRune {
} }
public void add(TaskRune rune) { public void add(TaskRune rune) {
if (rune == null) { return; } if (rune == null || children.size() >= maxChildren()) { return; }
children.add(rune); children.add(rune);
} }
@ -74,7 +74,12 @@ public abstract class CompositeTaskRune extends TaskRune {
} }
} }
protected abstract Status updateImpl2(IGolem golem); protected int maxChildren() {
return 9;
}
protected void saveImpl2(CompoundTag tag) { } protected void saveImpl2(CompoundTag tag) { }
protected void loadImpl2(CompoundTag tag) { } protected void loadImpl2(CompoundTag tag) { }
protected abstract Status updateImpl2(IGolem golem);
} }

View File

@ -14,6 +14,11 @@ public abstract class ParameterRune<T> extends Rune {
super(type); super(type);
} }
public ParameterRune(RuneType<? extends ParameterRune<?>> type, T data) {
this(type);
this.data = data;
}
public record UseContext(Level level, Player player, InteractionHand hand) { public record UseContext(Level level, Player player, InteractionHand hand) {
} }

View File

@ -16,8 +16,8 @@ public abstract class Rune {
this.type = type; this.type = type;
} }
public String getTypeID() { public ResourceLocation getTypeID() {
return type.toString(); return AshesRegistry.RUNE_REGISTRY.get().getKey(type);
} }
public Component getTooltip() { public Component getTooltip() {

View File

@ -0,0 +1,31 @@
package info.shylie.ashes.api.rune.leaf;
import info.shylie.ashes.Utils;
import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.LeafTaskRune;
import info.shylie.ashes.api.rune.RuneType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntity;
public abstract class BEInteractRune extends LeafTaskRune {
protected BEInteractRune(RuneType<? extends BEInteractRune> type, Class<?>... extra) {
super(type, Utils.concat(extra, BlockPos.class));
}
@Override
protected boolean startImpl(IGolem golem) {
return golem.canInteract(getValue(0));
}
@Override
protected Status updateImpl(IGolem golem) {
BlockEntity be = golem.asEntity().level().getBlockEntity(getValue(0));
if (be != null) {
return interact(golem, be);
}
return Status.SUCCESS;
}
protected abstract Status interact(IGolem golem, BlockEntity be);
}

View File

@ -64,11 +64,13 @@ public class AshenGolemEntity extends AbstractGolem implements IGolem {
@Override @Override
public void addAdditionalSaveData(CompoundTag tag) { public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
if (task != null) { task.save(tag); } if (task != null) { task.save(tag); }
} }
@Override @Override
public void readAdditionalSaveData(CompoundTag tag) { public void readAdditionalSaveData(CompoundTag tag) {
super.readAdditionalSaveData(tag);
task = Rune.of(tag, TaskRune.class); task = Rune.of(tag, TaskRune.class);
} }

View File

@ -2,6 +2,7 @@ package info.shylie.ashes.item;
import info.shylie.ashes.api.golem.IGolem; import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.*; import info.shylie.ashes.api.rune.*;
import net.minecraft.Util;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult;
@ -102,6 +103,15 @@ public class RuneItem extends Item {
components.add(component); components.add(component);
} }
@Override
public String getDescriptionId(ItemStack stack) {
Rune rune = Rune.of(stack.getTag());
if (rune == null) {
return super.getDescriptionId(stack);
}
return Util.makeDescriptionId("rune", rune.getTypeID());
}
private boolean setParameter(UseOnContext context) { private boolean setParameter(UseOnContext context) {
ParameterRune<?> rune = Rune.of(context.getItemInHand().getTag(), ParameterRune.class); ParameterRune<?> rune = Rune.of(context.getItemInHand().getTag(), ParameterRune.class);
if (rune == null) { return false; } if (rune == null) { return false; }

View File

@ -7,19 +7,20 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.tooltip.TooltipComponent; import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
public class ItemRune extends ParameterRune<Item> { public class ItemRune extends ParameterRune<Item> {
private static final String ITEM_TAG = "item"; private static final String ITEM_TAG = "item";
public ItemRune(RuneType<? extends ItemRune> type) { public ItemRune(RuneType<? extends ItemRune> type) {
super(type); super(type, Items.AIR);
} }
@Override @Override
public TooltipComponent getTooltipImage() { public TooltipComponent getTooltipImage() {
Item item = getValue(); Item item = getValue();
if (item == null) { return null; } if (item == Items.AIR) { return null; }
return new SingleItemTooltip(item); return new SingleItemTooltip(item);
} }

View File

@ -0,0 +1,22 @@
package info.shylie.ashes.rune.task.composite;
import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.CompositeTaskRune;
import info.shylie.ashes.api.rune.RuneType;
public class InverterRune extends CompositeTaskRune {
public InverterRune(RuneType<? extends InverterRune> type) {
super(type);
}
@Override
protected Status updateImpl2(IGolem golem) {
Status status = children.get(0).update(golem);
return switch (status) {
case SUCCESS -> Status.FAILURE;
case FAILURE -> Status.SUCCESS;
default -> Status.ONGOING;
};
}
}

View File

@ -1,4 +1,4 @@
package info.shylie.ashes.rune.task; package info.shylie.ashes.rune.task.composite;
import info.shylie.ashes.api.golem.IGolem; import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.CompositeTaskRune; import info.shylie.ashes.api.rune.CompositeTaskRune;

View File

@ -1,4 +1,4 @@
package info.shylie.ashes.rune.task; package info.shylie.ashes.rune.task.composite;
import info.shylie.ashes.api.golem.IGolem; import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.RuneType; import info.shylie.ashes.api.rune.RuneType;

View File

@ -1,4 +1,4 @@
package info.shylie.ashes.rune.task; package info.shylie.ashes.rune.task.composite;
import info.shylie.ashes.api.golem.IGolem; import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.CompositeTaskRune; import info.shylie.ashes.api.rune.CompositeTaskRune;

View File

@ -1,4 +1,4 @@
package info.shylie.ashes.rune.task; package info.shylie.ashes.rune.task.composite;
import info.shylie.ashes.api.golem.IGolem; import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.CompositeTaskRune; import info.shylie.ashes.api.rune.CompositeTaskRune;

View File

@ -0,0 +1,17 @@
package info.shylie.ashes.rune.task.leaf;
import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.LeafTaskRune;
import info.shylie.ashes.api.rune.RuneType;
import net.minecraft.world.item.Item;
public class HasItemRune extends LeafTaskRune {
public HasItemRune(RuneType<? extends HasItemRune> type) {
super(type, Item.class);
}
@Override
protected Status updateImpl(IGolem golem) {
return golem.asEntity().getMainHandItem().getItem() == getValue(0) ? Status.SUCCESS : Status.FAILURE;
}
}

View File

@ -0,0 +1,42 @@
package info.shylie.ashes.rune.task.leaf;
import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.LeafTaskRune;
import info.shylie.ashes.api.rune.RuneType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.util.FakePlayer;
public class InteractRune extends LeafTaskRune {
public InteractRune(RuneType<? extends InteractRune> type) {
super(type, BlockPos.class);
}
@Override
protected Status updateImpl(IGolem golem) {
BlockPos pos = getValue(0);
if (golem.canInteract(pos)) {
FakePlayer player = golem.getFakePlayer();
player.setItemInHand(InteractionHand.MAIN_HAND, golem.asEntity().getMainHandItem());
golem.asEntity().level().getBlockState(pos).use(
golem.asEntity().level(),
player,
InteractionHand.MAIN_HAND,
new BlockHitResult(
Vec3.atCenterOf(pos),
Direction.UP,
pos,
false
)
);
golem.asEntity().setItemInHand(InteractionHand.MAIN_HAND, player.getMainHandItem());
return Status.SUCCESS;
}
return Status.FAILURE;
}
}

View File

@ -1,4 +1,4 @@
package info.shylie.ashes.rune.task; package info.shylie.ashes.rune.task.leaf;
import info.shylie.ashes.api.golem.IGolem; import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.LeafTaskRune; import info.shylie.ashes.api.rune.LeafTaskRune;
@ -36,22 +36,22 @@ public class MoveRune extends LeafTaskRune {
e.move(MoverType.SELF, e.getDeltaMovement()); e.move(MoverType.SELF, e.getDeltaMovement());
if (e.getNavigation().isDone()) { if (e.getNavigation().isDone()) {
BlockPos pos = getValue(0); return golem.canInteract(getValue(0)) ? Status.SUCCESS : Status.FAILURE;
if (e.position().distanceToSqr(new Vec3(pos.getX(), pos.getY() + 1, pos.getZ())) < 1) {
return Status.SUCCESS;
}
return Status.FAILURE;
} }
return Status.ONGOING; return Status.ONGOING;
} }
@Override
protected void stopImpl(IGolem golem) {
golem.asEntity().getNavigation().stop();
}
private boolean path(IGolem golem) { private boolean path(IGolem golem) {
BlockPos pos = getValue(0); BlockPos pos = getValue(0);
return pos != null && golem.asEntity().getNavigation().moveTo( return pos != null && golem.asEntity().getNavigation().moveTo(
pos.getX(), pos.getX(),
pos.getY(), pos.getY() + 1,
pos.getZ(), pos.getZ(),
1.0 1.0
); );

View File

@ -0,0 +1,43 @@
package info.shylie.ashes.rune.task.leaf;
import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.RuneType;
import info.shylie.ashes.api.rune.leaf.BEInteractRune;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
public class PutItemRune extends BEInteractRune {
public PutItemRune(RuneType<? extends PutItemRune> type) {
super(type);
}
@Override
protected Status interact(IGolem golem, BlockEntity be) {
ItemStack handItem = golem.asEntity().getMainHandItem().copy();
if (handItem.isEmpty()) {
return Status.FAILURE;
}
final Status[] status = { Status.FAILURE };
be.getCapability(ForgeCapabilities.ITEM_HANDLER).ifPresent(handler -> {
for (int i = 0; i < handler.getSlots() && !handItem.isEmpty(); i++) {
int putCount = handItem.getCount() - handler.insertItem(i, handItem, true).getCount();
if (putCount > 0) {
handler.insertItem(i, handItem.copy(), false);
handItem.shrink(putCount);
status[0] = Status.SUCCESS;
}
}
});
if (status[0] == Status.SUCCESS) {
golem.asEntity().setItemInHand(InteractionHand.MAIN_HAND, handItem);
}
return status[0];
}
}

View File

@ -0,0 +1,57 @@
package info.shylie.ashes.rune.task.leaf;
import info.shylie.ashes.api.golem.IGolem;
import info.shylie.ashes.api.rune.RuneType;
import info.shylie.ashes.api.rune.leaf.BEInteractRune;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.items.ItemHandlerHelper;
public class TakeItemRune extends BEInteractRune {
public TakeItemRune(RuneType<? extends TakeItemRune> type) {
super(type, Item.class);
}
@Override
protected Status interact(IGolem golem, BlockEntity be) {
final Status[] status = { Status.FAILURE };
be.getCapability(ForgeCapabilities.ITEM_HANDLER).ifPresent(handler -> {
Item type = getValue(1);
ItemStack totalExtracted = golem.asEntity().getMainHandItem().copy();
for (int i = 0; i < handler.getSlots(); i++) {
ItemStack stack = handler.getStackInSlot(i);
if (!totalExtracted.isEmpty() && !ItemHandlerHelper.canItemStacksStack(totalExtracted, stack)) {
continue;
}
if (type == null || stack.getItem() == type) {
int count = Math.min(stack.getCount(), stack.getMaxStackSize());
if (!totalExtracted.isEmpty()) {
count = Math.min(totalExtracted.getMaxStackSize() - totalExtracted.getCount(), count);
}
ItemStack extracted = handler.extractItem(i, count, false);
if (!extracted.isEmpty()) {
if (totalExtracted.isEmpty()) {
totalExtracted = extracted;
}
else {
totalExtracted.grow(extracted.getCount());
}
status[0] = Status.SUCCESS;
}
}
}
if (status[0] == Status.SUCCESS) {
golem.asEntity().setItemInHand(InteractionHand.MAIN_HAND, totalExtracted);
}
});
return status[0];
}
}

View File

@ -1,7 +1,20 @@
{ {
"rune.ashes.blockpos": "Position Rune",
"rune.ashes.item": "Item Rune",
"rune.ashes.sequence": "Sequence Rune",
"rune.ashes.selector": "Selector Rune",
"rune.ashes.step_sequence": "Step Sequence Rune",
"rune.ashes.step_selector": "Step Selector Rune",
"rune.ashes.inverter":"Inverter Rune",
"rune.ashes.move": "Move Rune",
"rune.ashes.take_item": "Take Item Rune",
"rune.ashes.put_item": "Put Item Rune",
"rune.ashes.interact": "Interact Rune",
"rune.ashes.has_item": "Has Item Rune",
"rune.ashes.blockpos.default": "No position set", "rune.ashes.blockpos.default": "No position set",
"item.ashes.rune": "Rune", "item.ashes.rune": "Invalid Rune",
"itemgroup.ashes": "Ashes" "itemgroup.ashes": "Ashes"
} }