Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions src/main/java/dev/amble/lib/boat/ABoatItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package dev.amble.lib.boat;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.entity.vehicle.ChestBoatEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.stat.Stats;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RaycastContext;
import net.minecraft.world.World;
import net.minecraft.world.event.GameEvent;

import java.util.List;
import java.util.function.Predicate;

public class ABoatItem extends Item {

private static final Predicate<Entity> RIDERS = EntityPredicates.EXCEPT_SPECTATOR.and(Entity::canHit);
private final ABoatType type;
private final boolean chest;

public ABoatItem(boolean chest, ABoatType type, Item.Settings settings) {
super(settings);
this.chest = chest;
this.type = type;
}

public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
ItemStack itemStack = user.getStackInHand(hand);
HitResult hitResult = raycast(world, user, RaycastContext.FluidHandling.ANY);

if (hitResult.getType() == HitResult.Type.MISS)
return TypedActionResult.pass(itemStack);

Vec3d vec3d = user.getRotationVec(1.0F);

List<Entity> list = world.getOtherEntities(user, user.getBoundingBox().stretch(vec3d.multiply(5.0F)).expand(1.0F), RIDERS);

if (!list.isEmpty()) {
Vec3d vec3d2 = user.getEyePos();

for(Entity entity : list) {
Box box = entity.getBoundingBox().expand(entity.getTargetingMargin());
if (box.contains(vec3d2)) {
return TypedActionResult.pass(itemStack);
}
}
}

if (hitResult.getType() != HitResult.Type.BLOCK)
return TypedActionResult.pass(itemStack);

BoatEntity boatEntity = this.createEntity(world, hitResult);
boatEntity.setVariant(this.type.get());
boatEntity.setYaw(user.getYaw());

if (!world.isSpaceEmpty(boatEntity, boatEntity.getBoundingBox())) {
return TypedActionResult.fail(itemStack);
} else {
if (!world.isClient()) {
world.spawnEntity(boatEntity);
world.emitGameEvent(user, GameEvent.ENTITY_PLACE, hitResult.getPos());

if (!user.getAbilities().creativeMode)
itemStack.decrement(1);
}

user.incrementStat(Stats.USED.getOrCreateStat(this));
return TypedActionResult.success(itemStack, world.isClient());
}
}

private BoatEntity createEntity(World world, HitResult hitResult) {
return this.chest ? new ChestBoatEntity(world, hitResult.getPos().x, hitResult.getPos().y, hitResult.getPos().z) : new BoatEntity(world, hitResult.getPos().x, hitResult.getPos().y, hitResult.getPos().z);
}
}
7 changes: 7 additions & 0 deletions src/main/java/dev/amble/lib/boat/ABoatType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package dev.amble.lib.boat;

import net.minecraft.entity.vehicle.BoatEntity;

public interface ABoatType {
BoatEntity.Type get();
}
71 changes: 71 additions & 0 deletions src/main/java/dev/amble/lib/boat/BoatTypeContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package dev.amble.lib.boat;

import dev.amble.lib.container.RegistryContainer;
import net.minecraft.block.Block;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.Item;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Field;

public abstract class BoatTypeContainer implements RegistryContainer<BoatTypeContainer.Holder> {
@Override
public @Nullable Registry<Holder> getRegistry() {
return null;
}

protected static ABoatType register(Item item, Item chest, Block block) {
return new Holder(new Pending(item, chest, block));
}

protected static ABoatType registerNormal(Item item, Block block) {
return register(item, null, block);
}

protected static ABoatType registerChest(Item item, Block block) {
return register(null, item, block);
}

record Pending(Item item, Item chest, Block block) implements ABoatType {

@Override
public BoatEntity.Type get() {
throw new IllegalStateException("This boat type was not registered yet!");
}

public ABoatType register(Identifier id) {
return BoatTypeRegistry.register(id, this.item, this.chest, this.block);
}
}

public static final class Holder implements ABoatType {

ABoatType child;

Holder(ABoatType child) {
this.child = child;
}

@Override
public BoatEntity.Type get() {
return child.get();
}
}

public Class<Holder> getTargetClass() {
return Holder.class;
}

@Override
public void postProcessField(Identifier identifier, Holder value, Field field) {
// Promotion
value.child = ((Pending) value.child).register(identifier);
}

@Override
public void finish() {
BoatTypeRegistry.apply();
}
}
80 changes: 80 additions & 0 deletions src/main/java/dev/amble/lib/boat/BoatTypeRegistry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@

package dev.amble.lib.boat;

import dev.amble.lib.util.LazyObject;
import net.minecraft.block.Block;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.Item;
import net.minecraft.util.Identifier;

import java.util.ArrayList;
import java.util.List;

public class BoatTypeRegistry {

private static Item[] TYPE2ITEM;
private static Item[] CTYPE2ITEM;

private static final BoatItemConsumer CONSUMER = new BoatItemConsumer() {

@Override
public void init(int size) {
TYPE2ITEM = new Item[size];
CTYPE2ITEM = new Item[size];
}

@Override
public void accept(BoatEntity.Type type, Item normal, Item chest) {
TYPE2ITEM[type.ordinal()] = normal;
CTYPE2ITEM[type.ordinal()] = chest;
}
};

private static final List<Entry> entries = new ArrayList<>();

public static LazyBoatType register(Identifier id, Item item, Item chest, Block block) {
Entry entry = new Entry(id, item, chest, block);
entries.add(entry);

return entry.lazyGetter();
}

public static Item getItem(BoatEntity.Type type, boolean chest) {
return (chest ? CTYPE2ITEM : TYPE2ITEM)[type.ordinal()];
}

public static void apply() {
((CustomBoatTypes) (Object) BoatEntity.Type.OAK).amble$recalc(entries, CONSUMER);
}

public interface BoatItemConsumer {
void init(int size);
void accept(BoatEntity.Type type, Item normal, Item chest);
}

public interface CustomBoatTypes {
void amble$recalc(List<Entry> entries, BoatItemConsumer consumer);
}

public record Entry(Identifier id, Item item, Item chest, Block block) {

public String getPath() {
return id.getNamespace() + "/" + id.getPath();
}

public String getEnumName() {
return id.getNamespace().toUpperCase() + "_" + id.getPath().replace('/', '_').toUpperCase();
}

public LazyBoatType lazyGetter() {
return new LazyBoatType(this);
}
}

public static class LazyBoatType extends LazyObject<BoatEntity.Type> implements ABoatType {

public LazyBoatType(Entry entry) {
super(() -> BoatEntity.Type.getType(entry.getPath()), BoatEntity.Type.OAK);
}
}
}
18 changes: 14 additions & 4 deletions src/main/java/dev/amble/lib/container/RegistryContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import net.minecraft.util.Identifier;

import dev.amble.lib.AmbleKit;
import org.jetbrains.annotations.Nullable;

public interface RegistryContainer<T> {

Expand All @@ -16,6 +17,7 @@ public interface RegistryContainer<T> {
/**
* @return The registry the fields of this class should be registered into
*/
@Nullable
Registry<T> getRegistry();

/**
Expand All @@ -28,12 +30,16 @@ public interface RegistryContainer<T> {
*/
default void postProcessField(Identifier identifier, T value, Field field) {}

static <T> void register(Class<? extends RegistryContainer<T>> clazz, String namespace) {
default boolean preProcessField(Field field) {
return true;
}

static <T> void register(Class<? extends RegistryContainer<T>> clazz, String namespace) {
try {
RegistryContainer<T> container = clazz.getDeclaredConstructor().newInstance();
Field[] fields = clazz.getDeclaredFields();

container.start(fields.length);
if (!container.start(fields.length)) return;

for (Field field : fields) {
if (!Modifier.isStatic(field.getModifiers()))
Expand All @@ -42,6 +48,8 @@ static <T> void register(Class<? extends RegistryContainer<T>> clazz, String nam
if (!container.getTargetClass().isAssignableFrom(field.getType()))
continue;

if (!container.preProcessField(field)) return;

// trust me bro
T v = (T) field.get(null);

Expand All @@ -55,7 +63,9 @@ static <T> void register(Class<? extends RegistryContainer<T>> clazz, String nam

Identifier id = new Identifier(namespace, name);

Registry.register(container.getRegistry(), id, v);
if (container.getRegistry() != null) {
Registry.register(container.getRegistry(), id, v);
}
container.postProcessField(id, v, field);
}

Expand All @@ -70,7 +80,7 @@ static <T> Class<T> conform(Class<?> input) {
return (Class<T>) input;
}

default void start(int fields) { }
default boolean start(int fields) { return true; }

default void finish() { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ public abstract class BlockContainer implements RegistryContainer<Block> {
private List<Item> items;

@Override
public void start(int fields) {
public boolean start(int fields) {
this.items = new ArrayList<>(fields);
return true;
}

@Override
Expand Down
25 changes: 25 additions & 0 deletions src/main/java/dev/amble/lib/mixin/BoatEntityMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dev.amble.lib.mixin;

import dev.amble.lib.boat.BoatTypeRegistry;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.Item;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(value = BoatEntity.class, priority = 999)
public abstract class BoatEntityMixin {

@Shadow
public abstract BoatEntity.Type getVariant();

@Inject(method = "asItem", at = @At("HEAD"), cancellable = true)
public void asItem(CallbackInfoReturnable<Item> cir) {
Item item = BoatTypeRegistry.getItem(this.getVariant(), false);

if (item != null)
cir.setReturnValue(item);
}
}
Loading
Loading