Skip to content

Commit

Permalink
fabric and forge fuel salepoint implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
techno-sam committed Aug 13, 2024
1 parent 40e9f05 commit fd92620
Show file tree
Hide file tree
Showing 10 changed files with 531 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public enum Mods {
EMI("emi"),
JEI("jei"),
CREATEADDITION("createaddition"),
;
RAILWAYS("railways");

public final boolean isLoaded;
public final boolean requiredForDataGen;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public abstract class FluidSalepointTargetBehaviour extends SalepointTargetBehaviour<MultiloaderFluidStack> {
public abstract class FluidSalepointTargetBehaviour extends SalepointTargetBehaviour<MultiloaderFluidStack> implements IFilteringSalepointBehaviour {
public FluidSalepointTargetBehaviour(SmartBlockEntity be) {
super(be);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Numismatics
* Copyright (c) 2024 The Railways Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package dev.ithundxr.createnumismatics.content.salepoint.behaviours;

public interface IFilteringSalepointBehaviour {
default boolean canSetFilter(Object filter) {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import dev.architectury.injectables.annotations.ExpectPlatform;
import dev.ithundxr.createnumismatics.compat.computercraft.ComputerCraftProxy;
import dev.ithundxr.createnumismatics.content.backend.ReasonHolder;
import dev.ithundxr.createnumismatics.content.salepoint.SalepointBlockEntity;
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.IFilteringSalepointBehaviour;
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.SalepointTargetBehaviour;
import dev.ithundxr.createnumismatics.content.salepoint.widgets.SalepointFluidConfigWidget;
import dev.ithundxr.createnumismatics.content.salepoint.widgets.SalepointFluidDisplayWidget;
Expand Down Expand Up @@ -86,6 +88,18 @@ public final boolean setFilter(MultiloaderFluidStack filter, Level salepointLeve
if (!canChangeFilterTo(filter))
return false;

if (!filter.isEmpty() && salepointLevel.getBlockEntity(salepointPos) instanceof SalepointBlockEntity salepointBE) {
BlockPos targetedPos = salepointBE.getTargetedPos();
if (targetedPos != null) {
var behaviour = getBehaviour(salepointLevel, targetedPos);
if (behaviour instanceof IFilteringSalepointBehaviour filteringSalepointBehaviour) {
if (!filteringSalepointBehaviour.canSetFilter(filter)) {
return false;
}
}
}
}

setFilterInternal(filter, salepointLevel, salepointPos, player);
this.filter = filter.copy();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,12 @@
import dev.ithundxr.createnumismatics.content.vendor.VendorBlock;
import dev.ithundxr.createnumismatics.multiloader.CommonTags;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.MapColor;
import net.minecraft.world.level.storage.loot.LootPool;
import net.minecraft.world.level.storage.loot.entries.LootItem;
Expand Down Expand Up @@ -142,7 +144,7 @@ public class NumismaticsBlocks {
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.strength(1.0F, 3600000.0F)) // Unexplodable
.properties(Properties::requiresCorrectToolForDrops)
.properties(p -> p.isRedstoneConductor(Blocks::never))
.properties(p -> p.isRedstoneConductor(NumismaticsBlocks::never))
.transform(pickaxeOnly())
.lang("Salepoint")
.transform(BuilderTransformers.salepoint())
Expand All @@ -154,4 +156,8 @@ public static void register() {
// load the class and register everything
Numismatics.LOGGER.info("Registering blocks for " + Numismatics.NAME);
}

private static boolean never(BlockState state, BlockGetter blockGetter, BlockPos pos) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
/*
* Numismatics
* Copyright (c) 2024 The Railways Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package dev.ithundxr.createnumismatics.fabric.mixin.compat;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.railwayteam.railways.content.fuel.LiquidFuelTrainHandler;
import com.railwayteam.railways.content.fuel.psi.PortableFuelInterfaceBlockEntity;
import com.railwayteam.railways.content.fuel.psi.PortableFuelInterfaceBlockEntity.InterfaceFluidHandler;
import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import dev.ithundxr.createnumismatics.Numismatics;
import dev.ithundxr.createnumismatics.annotation.mixin.ConditionalMixin;
import dev.ithundxr.createnumismatics.compat.Mods;
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.FluidSalepointTargetBehaviour;
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.SalepointTargetBehaviour;
import dev.ithundxr.createnumismatics.content.salepoint.containers.fabric.InvalidatableWrappingFluidBufferTank;
import dev.ithundxr.createnumismatics.content.salepoint.states.ISalepointState;
import dev.ithundxr.createnumismatics.fabric.mixin.WrappedStorageAccessor;
import dev.ithundxr.createnumismatics.multiloader.fluid.MultiloaderFluidStack;
import dev.ithundxr.createnumismatics.multiloader.fluid.fabric.MultiloaderFluidStackImpl;
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;

import java.util.List;

@ConditionalMixin(mods = Mods.RAILWAYS)
@Mixin(PortableFuelInterfaceBlockEntity.class)
@SuppressWarnings("UnstableApiUsage")
public abstract class PortableFuelInterfaceBlockEntityMixin extends PortableStorageInterfaceBlockEntity {

@Shadow(remap = false) protected InterfaceFluidHandler capability;
@Unique
private FluidSalepointTargetBehaviour railway$salepointBehaviour;

@Unique
@Nullable
private Storage<FluidVariant> railway$contraptionStorage;

private PortableFuelInterfaceBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}

@WrapOperation(
method = "startTransferringTo",
at = @At(
value = "INVOKE",
target = "Lcom/railwayteam/railways/content/fuel/psi/PortableFuelInterfaceBlockEntity$InterfaceFluidHandler;setWrapped(Lnet/fabricmc/fabric/api/transfer/v1/storage/Storage;)V"
),
remap = false
)
@SuppressWarnings("unchecked")
private void keepControl(InterfaceFluidHandler instance, Storage<FluidVariant> wrapped, Operation<Void> original) {
Storage<FluidVariant> existingWrapped = ((WrappedStorageAccessor<FluidVariant>) capability).getWrapped();
if (!(existingWrapped instanceof InvalidatableWrappingFluidBufferTank)) {
original.call(instance, wrapped);
}
railway$contraptionStorage = wrapped;
}

@WrapOperation(
method = "stopTransferring",
at = @At(
value = "INVOKE",
target = "Lcom/railwayteam/railways/content/fuel/psi/PortableFuelInterfaceBlockEntity$InterfaceFluidHandler;setWrapped(Lnet/fabricmc/fabric/api/transfer/v1/storage/Storage;)V"
),
remap = false
)
@SuppressWarnings("unchecked")
private void keepControl2(InterfaceFluidHandler instance, Storage<FluidVariant> wrapped, Operation<Void> original) {
Storage<FluidVariant> existingWrapped = ((WrappedStorageAccessor<FluidVariant>) capability).getWrapped();
if (!(existingWrapped instanceof InvalidatableWrappingFluidBufferTank)) {
original.call(instance, wrapped);
}
railway$contraptionStorage = null;
}

@Override
public boolean canTransfer() {
return super.canTransfer() || railway$salepointBehaviour.isControlledBySalepoint();
}

@Override
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
railway$salepointBehaviour = new FluidSalepointTargetBehaviour(this) {
private boolean underControl = false;

@Override
protected boolean isUnderControlInternal(@NotNull ISalepointState<MultiloaderFluidStack> state) {
return underControl; // id checks done by super
}

@Override
@SuppressWarnings("unchecked")
protected void ensureUnderControlInternal(@NotNull ISalepointState<MultiloaderFluidStack> state) {
((WrappedStorageAccessor<FluidVariant>) capability).setWrapped((InvalidatableWrappingFluidBufferTank) state.getBuffer());

if (!underControl) {
underControl = true;
notifyUpdate();
}
}

@Override
@SuppressWarnings("unchecked")
protected void relinquishControlInternal(@NotNull ISalepointState<MultiloaderFluidStack> state) {
if (railway$contraptionStorage != null) {
((WrappedStorageAccessor<FluidVariant>) capability).setWrapped(railway$contraptionStorage);
} else {
((WrappedStorageAccessor<FluidVariant>) capability).setWrapped(Storage.empty());
}

if (underControl) {
underControl = false;
notifyUpdate();
}
}

@Override
public boolean hasSpaceFor(@NotNull MultiloaderFluidStack object) {
if (railway$contraptionStorage == null)
return false;

if (!railway$contraptionStorage.supportsInsertion())
return false;

try (Transaction transaction = Transaction.openOuter()) {
if (railway$contraptionStorage.insert(((MultiloaderFluidStackImpl) object).getType(), object.getAmount(), transaction) != object.getAmount()) {
return false;
}
}

return true;
}

@Override
public boolean doPurchase(@NotNull MultiloaderFluidStack object, @NotNull PurchaseProvider<MultiloaderFluidStack> purchaseProvider) {
if (railway$contraptionStorage == null)
return false;

if (!hasSpaceFor(object))
return false;

List<MultiloaderFluidStack> extracted = purchaseProvider.extract();
try (Transaction transaction = Transaction.openOuter()) {
for (MultiloaderFluidStack stack : extracted) {
if (railway$contraptionStorage.insert(((MultiloaderFluidStackImpl) stack).getType(), stack.getAmount(), transaction) != stack.getAmount()) {
Numismatics.LOGGER.error("Failed to insert fluid into contraption storage, despite having space.");
return false;
}
}
transaction.commit();
}

return true;
}

@Override
public void read(@NotNull CompoundTag nbt, boolean clientPacket) {
super.read(nbt, clientPacket);

underControl = nbt.getBoolean("SalepointUnderControl");
}

@Override
public void write(@NotNull CompoundTag nbt, boolean clientPacket) {
super.write(nbt, clientPacket);

nbt.putBoolean("SalepointUnderControl", underControl);
}

@Override
public boolean canSetFilter(Object filter) {
if (!super.canSetFilter(filter))
return false;

if (!(filter instanceof MultiloaderFluidStackImpl fs))
return false;

return LiquidFuelTrainHandler.isFuel(fs.getFluid());
}
};

behaviours.add(railway$salepointBehaviour);
}

@Mixin(InterfaceFluidHandler.class)
private static class InterfaceFluidHandlerMixin {
@WrapOperation(
method = "insert(Lnet/fabricmc/fabric/api/transfer/v1/fluid/FluidVariant;JLnet/fabricmc/fabric/api/transfer/v1/transaction/TransactionContext;)J",
at = @At(
value = "INVOKE",
target = "Lcom/railwayteam/railways/content/fuel/psi/PortableFuelInterfaceBlockEntity;isConnected()Z"
)
)
private boolean fakeConnect(PortableFuelInterfaceBlockEntity instance, Operation<Boolean> original) {
return original.call(instance) || instance.getBehaviour(SalepointTargetBehaviour.TYPE).isControlledBySalepoint();
}
}
}
4 changes: 3 additions & 1 deletion fabric/src/main/resources/numismatics.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"WrappedStorageAccessor",
"compat.PortableEnergyInterfaceBlockEntityMixin",
"compat.PortableEnergyInterfaceBlockEntityMixin$InterfaceEnergyHandlerAccessor",
"compat.PortableEnergyInterfaceMovementMixin"
"compat.PortableEnergyInterfaceMovementMixin",
"compat.PortableFuelInterfaceBlockEntityMixin",
"compat.PortableFuelInterfaceBlockEntityMixin$InterfaceFluidHandlerMixin"
],
"injectors": {
"defaultRequire": 1
Expand Down
Loading

0 comments on commit fd92620

Please sign in to comment.