Skip to content

Commit

Permalink
Add Furnace Minecart Resupplying, add fuel cap to toggleable furnace …
Browse files Browse the repository at this point in the history
…minecarts; Close #717
  • Loading branch information
SFort committed May 19, 2024
1 parent 5975b68 commit f41197b
Show file tree
Hide file tree
Showing 10 changed files with 281 additions and 8 deletions.
7 changes: 7 additions & 0 deletions features.d/f_minor_mechanics.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,12 @@ minor_mechanics.gradual_block_breaking:
desc:
Snow layers and slabs will be mined a layer at a time.

minor_mechanics.furnace_minecart_resupplying:
name: Furnace Minecart Resupplying
since: 3.4.16
sides: server_only
desc:
Allows furnace minecarts to accept fuel from hoppers.

# kate: space-indent off
# vim: noai:noet
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ org.gradle.jvmargs=-Xmx1G
# Mod Properties
maven_group = com.unascribed
archives_base_name = fabrication
version = 3.4.15
version = 3.4.16
13 changes: 13 additions & 0 deletions src/main/java/com/unascribed/fabrication/FabRefl.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.unascribed.fabrication.support.FabReflField;
import com.unascribed.fabrication.support.injection.FabRefMap;
import net.minecraft.client.util.SelectionManager;
import net.minecraft.entity.vehicle.FurnaceMinecartEntity;
import net.minecraft.recipe.Ingredient;
import net.minecraft.server.command.GameModeCommand;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.GameMode;
Expand Down Expand Up @@ -251,6 +253,17 @@ public static int getPickupDelay(ItemEntity subject) {
throw rethrow(t);
}
}
@FabReflField
private static final String fme_acceptableFuel_field = "net/minecraft/entity/vehicle/FurnaceMinecartEntity;ACCEPTABLE_FUEL";
private static final MethodHandle fme_acceptableFuel = unreflectGetter("FurnaceMinecartEntity", () -> FurnaceMinecartEntity.class, fme_acceptableFuel_field)
.requiredBy("*.furnace_minecart_resupplying").get();
public static Ingredient getAcceltableFuel() {
try {
return (Ingredient)checkHandle(fme_acceptableFuel).invokeExact();
} catch (Throwable t) {
throw rethrow(t);
}
}

@FabReflField
private static final String gmc_execute_field = "Lnet/minecraft/server/command/GameModeCommand;execute(Lcom/mojang/brigadier/context/CommandContext;Ljava/util/Collection;Lnet/minecraft/world/GameMode;)I";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.unascribed.fabrication.interfaces;

import com.unascribed.fabrication.util.FurnaceResupplierFakeInventory;

public interface ResupplyingFurnaceCart {
FurnaceResupplierFakeInventory fabrication$getResupplyingFurnaceCart();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.unascribed.fabrication.interfaces;

public interface ToggleableFurnaceCart {
int fabrication$tgfc$getPauseFuel();
void fabrication$tgfc$setFuel(int fuel);
static int get(Object o) {
return o instanceof ToggleableFurnaceCart ? ((ToggleableFurnaceCart) o).fabrication$tgfc$getPauseFuel() : 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.unascribed.fabrication.mixin.a_fixes.furnace_minecart_pushing;

import com.unascribed.fabrication.FabConf;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
Expand All @@ -17,7 +16,6 @@
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.FurnaceMinecartEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Ingredient;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.world.World;
Expand All @@ -29,9 +27,6 @@ public abstract class MixinFurnaceMinecartEntity extends AbstractMinecartEntity
protected MixinFurnaceMinecartEntity(EntityType<?> entityType, World world) {
super(entityType, world);
}

@Shadow @Final
private static Ingredient ACCEPTABLE_FUEL;
@Shadow
private int fuel;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.unascribed.fabrication.mixin.d_minor_mechanics.furnace_minecart_resupplying;

import com.unascribed.fabrication.FabConf;
import com.unascribed.fabrication.interfaces.ResupplyingFurnaceCart;
import com.unascribed.fabrication.interfaces.ToggleableFurnaceCart;
import com.unascribed.fabrication.support.EligibleIf;
import com.unascribed.fabrication.support.injection.FabInject;
import com.unascribed.fabrication.util.FurnaceResupplierFakeInventory;
import net.minecraft.block.entity.FurnaceBlockEntity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.FurnaceMinecartEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
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.callback.CallbackInfo;

//TODO should just implement inventory if fabrication ever got a good way to create methods in classes
@Mixin(FurnaceMinecartEntity.class)
@EligibleIf(configAvailable="*.furnace_minecart_resupplying")
public abstract class MixinFurnaceMinecartEntity extends AbstractMinecartEntity implements ResupplyingFurnaceCart {
@Shadow
public double pushX;
@Shadow
public double pushZ;
@Shadow
private int fuel;
public FurnaceResupplierFakeInventory fabrication$hopperFuel = null;

protected MixinFurnaceMinecartEntity(EntityType<?> entityType, World world) {
super(entityType, world);
}

@FabInject(at=@At("HEAD"), method="tick()V")
protected void tick(CallbackInfo ci) {
if (!FabConf.isEnabled("*.furnace_minecart_resupplying")) return;
if (fabrication$hopperFuel == null || fabrication$hopperFuel.isEmpty()) return;
ItemStack fuelStack = fabrication$hopperFuel.stack;
int fuel;
int value = (FabConf.isEnabled("*.furnace_minecart_any_fuel") ? FurnaceBlockEntity.createFuelTimeMap().get(fuelStack.getItem())*2 : 3600) + ((fuel = ToggleableFurnaceCart.get(this)) == 0 ? this.fuel : fuel);
if (value <= 32000) {
fuelStack.decrement(1);
if (this instanceof ToggleableFurnaceCart) ((ToggleableFurnaceCart) this).fabrication$tgfc$setFuel(value);
else this.fuel = value;
}
if (ToggleableFurnaceCart.get(this) == 0 && this.fuel > 0) {
Direction dir = this.getMovementDirection();
pushX = dir.getOffsetX();
pushZ = dir.getOffsetZ();
}
}

@Override
public FurnaceResupplierFakeInventory fabrication$getResupplyingFurnaceCart() {
if (fabrication$hopperFuel == null) return fabrication$hopperFuel = new FurnaceResupplierFakeInventory(this.world);
return fabrication$hopperFuel;
}

/* I guess it's possible that someone inserts fuel and it doesn't turn into fuel before the cart gets unloaded, i think that's fine
@FabInject(at=@At("TAIL"), method="writeCustomDataToNbt(Lnet/minecraft/nbt/NbtCompound;)V")
protected void writeCustomDataToTag(NbtCompound nbt, CallbackInfo ci) {
}
@FabInject(at=@At("TAIL"), method="readCustomDataFromNbt(Lnet/minecraft/nbt/NbtCompound;)V")
protected void readCustomDataFromTag(NbtCompound nbt, CallbackInfo ci) {
}
*/

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.unascribed.fabrication.mixin.d_minor_mechanics.furnace_minecart_resupplying;

import com.unascribed.fabrication.FabConf;
import com.unascribed.fabrication.interfaces.ResupplyingFurnaceCart;
import com.unascribed.fabrication.support.EligibleIf;
import com.unascribed.fabrication.support.injection.FabModifyArg;
import com.unascribed.fabrication.support.injection.ModifyReturn;
import net.minecraft.block.entity.HopperBlockEntity;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

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

@Mixin(HopperBlockEntity.class)
@EligibleIf(configAvailable="*.furnace_minecart_resupplying")
public class MixinHopperBlockEntity {

@FabModifyArg(method="getInventoryAt(Lnet/minecraft/world/World;DDD)Lnet/minecraft/inventory/Inventory;", at=@At(value="INVOKE", target="Lnet/minecraft/world/World;getOtherEntities(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Box;Ljava/util/function/Predicate;)Ljava/util/List;"))
private static <T extends Entity> Predicate<T> addFurnaceCarts(Predicate<T> predicate) {
if (!FabConf.isEnabled("*.furnace_minecart_resupplying")) return predicate;
return predicate.or(new Predicate<>() {
@Override
public boolean test(T entity) {
return entity instanceof ResupplyingFurnaceCart;
}
});
}
@ModifyReturn(method="getInventoryAt(Lnet/minecraft/world/World;DDD)Lnet/minecraft/inventory/Inventory;", target="Lnet/minecraft/world/World;getOtherEntities(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/math/Box;Ljava/util/function/Predicate;)Ljava/util/List;")
private static List<Entity> fabrication$changeFurnaceCarts(List<Entity> list) {
for (int i=0, l=list.size(); i<l; i++) {
Entity entity = list.get(i);
if (entity instanceof ResupplyingFurnaceCart) {
list.set(i, ((ResupplyingFurnaceCart) entity).fabrication$getResupplyingFurnaceCart());
}
}
return list;
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package com.unascribed.fabrication.mixin.e_mechanics.toggleable_furnace_carts;

import com.unascribed.fabrication.FabConf;
import com.unascribed.fabrication.interfaces.ToggleableFurnaceCart;
import com.unascribed.fabrication.support.EligibleIf;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.PoweredRailBlock;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.entity.vehicle.FurnaceMinecartEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
Expand All @@ -17,10 +21,11 @@
import org.spongepowered.asm.mixin.injection.At;
import com.unascribed.fabrication.support.injection.FabInject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(FurnaceMinecartEntity.class)
@Mixin(value=FurnaceMinecartEntity.class, priority=990)
@EligibleIf(configAvailable="*.toggleable_furnace_carts")
public abstract class MixinFurnaceMinecartEntity extends AbstractMinecartEntity {
public abstract class MixinFurnaceMinecartEntity extends AbstractMinecartEntity implements ToggleableFurnaceCart {

@Shadow
private int fuel;
Expand All @@ -35,6 +40,11 @@ public MixinFurnaceMinecartEntity(EntityType<?> type, World world) {
super(type, world);
}

@FabInject(method="interact(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;", at=@At("HEAD"))
public void interact(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
if (fabrication$pauseFuel > 32000) cir.setReturnValue(ActionResult.success(this.world.isClient));
}

@FabInject(at=@At("HEAD"), method="moveOnRail(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V")
protected void toggleOnUnpoweredPoweredRail(BlockPos pos, BlockState state, CallbackInfo ci) {
if (!FabConf.isEnabled("*.toggleable_furnace_carts")) return;
Expand Down Expand Up @@ -65,4 +75,12 @@ protected void readCustomDataFromTag(NbtCompound nbt, CallbackInfo ci) {
fabrication$pauseFuel = nbt.getInt("fabrication:PauseFuel");
}

public int fabrication$tgfc$getPauseFuel() {
return this.fabrication$pauseFuel;
}
public void fabrication$tgfc$setFuel(int fuel) {
if (this.fabrication$pauseFuel == 0) this.fuel = fuel;
else this.fabrication$pauseFuel = fuel;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.unascribed.fabrication.util;

import com.unascribed.fabrication.FabConf;
import com.unascribed.fabrication.FabRefl;
import net.minecraft.block.entity.FurnaceBlockEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.FurnaceMinecartEntity;
import net.minecraft.inventory.SidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.Packet;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;

public class FurnaceResupplierFakeInventory extends Entity implements SidedInventory {
public ItemStack stack = ItemStack.EMPTY;
public FurnaceResupplierFakeInventory(World world) {
super(EntityType.EGG, world);
}

@Override
protected void initDataTracker() {
}

@Override
protected void readCustomDataFromNbt(NbtCompound nbt) {
}

@Override
protected void writeCustomDataToNbt(NbtCompound nbt) {
}

@Override
public Packet<?> createSpawnPacket() {
return null;
}

@Override
public int size() {
return 1;
}

@Override
public boolean isEmpty() {
return this.stack.isEmpty();
}

@Override
public ItemStack getStack(int slot) {
if (slot != 0) return ItemStack.EMPTY;
return this.stack;
}

@Override
public ItemStack removeStack(int slot, int amount) {
if (slot != 0) return ItemStack.EMPTY;
return this.stack.split(amount);
}

@Override
public ItemStack removeStack(int slot) {
if (slot != 0) return ItemStack.EMPTY;
ItemStack ret = this.stack;
this.stack = ItemStack.EMPTY;
return ret;
}

@Override
public void setStack(int slot, ItemStack stack) {
if (slot != 0) return;
this.stack = stack;
}

@Override
public void markDirty() {
}

@Override
public boolean canPlayerUse(PlayerEntity player) {
return false;
}

@Override
public void clear() {
this.stack = ItemStack.EMPTY;
}
public int getMaxCountPerStack() {
return 1;
}

public static int[] SLOTS = new int[]{0};
@Override
public int[] getAvailableSlots(Direction side) {
return SLOTS;
}

@Override
public boolean canInsert(int slot, ItemStack stack, Direction dir) {
if (!FabConf.isEnabled("*.furnace_minecart_resupplying")) return false;
if (slot != 0 || !this.stack.isEmpty()) return false;
if (FabConf.isEnabled("*.furnace_minecart_any_fuel")) return FurnaceBlockEntity.canUseAsFuel(stack);
return FabRefl.getAcceltableFuel().test(stack);
}

@Override
public boolean canExtract(int slot, ItemStack stack, Direction dir) {
return false;
}
}

0 comments on commit f41197b

Please sign in to comment.