Skip to content

Commit fd92620

Browse files
committed
fabric and forge fuel salepoint implementation
1 parent 40e9f05 commit fd92620

File tree

10 files changed

+531
-6
lines changed

10 files changed

+531
-6
lines changed

common/src/main/java/dev/ithundxr/createnumismatics/compat/Mods.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public enum Mods {
3535
EMI("emi"),
3636
JEI("jei"),
3737
CREATEADDITION("createaddition"),
38-
;
38+
RAILWAYS("railways");
3939

4040
public final boolean isLoaded;
4141
public final boolean requiredForDataGen;

common/src/main/java/dev/ithundxr/createnumismatics/content/salepoint/behaviours/FluidSalepointTargetBehaviour.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.jetbrains.annotations.NotNull;
2626
import org.jetbrains.annotations.Nullable;
2727

28-
public abstract class FluidSalepointTargetBehaviour extends SalepointTargetBehaviour<MultiloaderFluidStack> {
28+
public abstract class FluidSalepointTargetBehaviour extends SalepointTargetBehaviour<MultiloaderFluidStack> implements IFilteringSalepointBehaviour {
2929
public FluidSalepointTargetBehaviour(SmartBlockEntity be) {
3030
super(be);
3131
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Numismatics
3+
* Copyright (c) 2024 The Railways Team
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
package dev.ithundxr.createnumismatics.content.salepoint.behaviours;
20+
21+
public interface IFilteringSalepointBehaviour {
22+
default boolean canSetFilter(Object filter) {
23+
return true;
24+
}
25+
}

common/src/main/java/dev/ithundxr/createnumismatics/content/salepoint/states/FluidSalepointState.java

+14
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import dev.architectury.injectables.annotations.ExpectPlatform;
2424
import dev.ithundxr.createnumismatics.compat.computercraft.ComputerCraftProxy;
2525
import dev.ithundxr.createnumismatics.content.backend.ReasonHolder;
26+
import dev.ithundxr.createnumismatics.content.salepoint.SalepointBlockEntity;
27+
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.IFilteringSalepointBehaviour;
2628
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.SalepointTargetBehaviour;
2729
import dev.ithundxr.createnumismatics.content.salepoint.widgets.SalepointFluidConfigWidget;
2830
import dev.ithundxr.createnumismatics.content.salepoint.widgets.SalepointFluidDisplayWidget;
@@ -86,6 +88,18 @@ public final boolean setFilter(MultiloaderFluidStack filter, Level salepointLeve
8688
if (!canChangeFilterTo(filter))
8789
return false;
8890

91+
if (!filter.isEmpty() && salepointLevel.getBlockEntity(salepointPos) instanceof SalepointBlockEntity salepointBE) {
92+
BlockPos targetedPos = salepointBE.getTargetedPos();
93+
if (targetedPos != null) {
94+
var behaviour = getBehaviour(salepointLevel, targetedPos);
95+
if (behaviour instanceof IFilteringSalepointBehaviour filteringSalepointBehaviour) {
96+
if (!filteringSalepointBehaviour.canSetFilter(filter)) {
97+
return false;
98+
}
99+
}
100+
}
101+
}
102+
89103
setFilterInternal(filter, salepointLevel, salepointPos, player);
90104
this.filter = filter.copy();
91105

common/src/main/java/dev/ithundxr/createnumismatics/registry/NumismaticsBlocks.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
import dev.ithundxr.createnumismatics.content.vendor.VendorBlock;
3535
import dev.ithundxr.createnumismatics.multiloader.CommonTags;
3636
import net.minecraft.client.renderer.RenderType;
37+
import net.minecraft.core.BlockPos;
3738
import net.minecraft.world.item.Rarity;
38-
import net.minecraft.world.level.block.Blocks;
39+
import net.minecraft.world.level.BlockGetter;
3940
import net.minecraft.world.level.block.SoundType;
4041
import net.minecraft.world.level.block.state.BlockBehaviour.Properties;
42+
import net.minecraft.world.level.block.state.BlockState;
4143
import net.minecraft.world.level.material.MapColor;
4244
import net.minecraft.world.level.storage.loot.LootPool;
4345
import net.minecraft.world.level.storage.loot.entries.LootItem;
@@ -142,7 +144,7 @@ public class NumismaticsBlocks {
142144
.initialProperties(SharedProperties::softMetal)
143145
.properties(p -> p.strength(1.0F, 3600000.0F)) // Unexplodable
144146
.properties(Properties::requiresCorrectToolForDrops)
145-
.properties(p -> p.isRedstoneConductor(Blocks::never))
147+
.properties(p -> p.isRedstoneConductor(NumismaticsBlocks::never))
146148
.transform(pickaxeOnly())
147149
.lang("Salepoint")
148150
.transform(BuilderTransformers.salepoint())
@@ -154,4 +156,8 @@ public static void register() {
154156
// load the class and register everything
155157
Numismatics.LOGGER.info("Registering blocks for " + Numismatics.NAME);
156158
}
159+
160+
private static boolean never(BlockState state, BlockGetter blockGetter, BlockPos pos) {
161+
return false;
162+
}
157163
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* Numismatics
3+
* Copyright (c) 2024 The Railways Team
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Lesser General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Lesser General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Lesser General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
package dev.ithundxr.createnumismatics.fabric.mixin.compat;
20+
21+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
22+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
23+
import com.railwayteam.railways.content.fuel.LiquidFuelTrainHandler;
24+
import com.railwayteam.railways.content.fuel.psi.PortableFuelInterfaceBlockEntity;
25+
import com.railwayteam.railways.content.fuel.psi.PortableFuelInterfaceBlockEntity.InterfaceFluidHandler;
26+
import com.simibubi.create.content.contraptions.actors.psi.PortableStorageInterfaceBlockEntity;
27+
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
28+
import dev.ithundxr.createnumismatics.Numismatics;
29+
import dev.ithundxr.createnumismatics.annotation.mixin.ConditionalMixin;
30+
import dev.ithundxr.createnumismatics.compat.Mods;
31+
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.FluidSalepointTargetBehaviour;
32+
import dev.ithundxr.createnumismatics.content.salepoint.behaviours.SalepointTargetBehaviour;
33+
import dev.ithundxr.createnumismatics.content.salepoint.containers.fabric.InvalidatableWrappingFluidBufferTank;
34+
import dev.ithundxr.createnumismatics.content.salepoint.states.ISalepointState;
35+
import dev.ithundxr.createnumismatics.fabric.mixin.WrappedStorageAccessor;
36+
import dev.ithundxr.createnumismatics.multiloader.fluid.MultiloaderFluidStack;
37+
import dev.ithundxr.createnumismatics.multiloader.fluid.fabric.MultiloaderFluidStackImpl;
38+
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
39+
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
40+
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
41+
import net.minecraft.core.BlockPos;
42+
import net.minecraft.nbt.CompoundTag;
43+
import net.minecraft.world.level.block.entity.BlockEntityType;
44+
import net.minecraft.world.level.block.state.BlockState;
45+
import org.jetbrains.annotations.NotNull;
46+
import org.jetbrains.annotations.Nullable;
47+
import org.spongepowered.asm.mixin.Mixin;
48+
import org.spongepowered.asm.mixin.Shadow;
49+
import org.spongepowered.asm.mixin.Unique;
50+
import org.spongepowered.asm.mixin.injection.At;
51+
52+
import java.util.List;
53+
54+
@ConditionalMixin(mods = Mods.RAILWAYS)
55+
@Mixin(PortableFuelInterfaceBlockEntity.class)
56+
@SuppressWarnings("UnstableApiUsage")
57+
public abstract class PortableFuelInterfaceBlockEntityMixin extends PortableStorageInterfaceBlockEntity {
58+
59+
@Shadow(remap = false) protected InterfaceFluidHandler capability;
60+
@Unique
61+
private FluidSalepointTargetBehaviour railway$salepointBehaviour;
62+
63+
@Unique
64+
@Nullable
65+
private Storage<FluidVariant> railway$contraptionStorage;
66+
67+
private PortableFuelInterfaceBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
68+
super(type, pos, state);
69+
}
70+
71+
@WrapOperation(
72+
method = "startTransferringTo",
73+
at = @At(
74+
value = "INVOKE",
75+
target = "Lcom/railwayteam/railways/content/fuel/psi/PortableFuelInterfaceBlockEntity$InterfaceFluidHandler;setWrapped(Lnet/fabricmc/fabric/api/transfer/v1/storage/Storage;)V"
76+
),
77+
remap = false
78+
)
79+
@SuppressWarnings("unchecked")
80+
private void keepControl(InterfaceFluidHandler instance, Storage<FluidVariant> wrapped, Operation<Void> original) {
81+
Storage<FluidVariant> existingWrapped = ((WrappedStorageAccessor<FluidVariant>) capability).getWrapped();
82+
if (!(existingWrapped instanceof InvalidatableWrappingFluidBufferTank)) {
83+
original.call(instance, wrapped);
84+
}
85+
railway$contraptionStorage = wrapped;
86+
}
87+
88+
@WrapOperation(
89+
method = "stopTransferring",
90+
at = @At(
91+
value = "INVOKE",
92+
target = "Lcom/railwayteam/railways/content/fuel/psi/PortableFuelInterfaceBlockEntity$InterfaceFluidHandler;setWrapped(Lnet/fabricmc/fabric/api/transfer/v1/storage/Storage;)V"
93+
),
94+
remap = false
95+
)
96+
@SuppressWarnings("unchecked")
97+
private void keepControl2(InterfaceFluidHandler instance, Storage<FluidVariant> wrapped, Operation<Void> original) {
98+
Storage<FluidVariant> existingWrapped = ((WrappedStorageAccessor<FluidVariant>) capability).getWrapped();
99+
if (!(existingWrapped instanceof InvalidatableWrappingFluidBufferTank)) {
100+
original.call(instance, wrapped);
101+
}
102+
railway$contraptionStorage = null;
103+
}
104+
105+
@Override
106+
public boolean canTransfer() {
107+
return super.canTransfer() || railway$salepointBehaviour.isControlledBySalepoint();
108+
}
109+
110+
@Override
111+
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
112+
super.addBehaviours(behaviours);
113+
railway$salepointBehaviour = new FluidSalepointTargetBehaviour(this) {
114+
private boolean underControl = false;
115+
116+
@Override
117+
protected boolean isUnderControlInternal(@NotNull ISalepointState<MultiloaderFluidStack> state) {
118+
return underControl; // id checks done by super
119+
}
120+
121+
@Override
122+
@SuppressWarnings("unchecked")
123+
protected void ensureUnderControlInternal(@NotNull ISalepointState<MultiloaderFluidStack> state) {
124+
((WrappedStorageAccessor<FluidVariant>) capability).setWrapped((InvalidatableWrappingFluidBufferTank) state.getBuffer());
125+
126+
if (!underControl) {
127+
underControl = true;
128+
notifyUpdate();
129+
}
130+
}
131+
132+
@Override
133+
@SuppressWarnings("unchecked")
134+
protected void relinquishControlInternal(@NotNull ISalepointState<MultiloaderFluidStack> state) {
135+
if (railway$contraptionStorage != null) {
136+
((WrappedStorageAccessor<FluidVariant>) capability).setWrapped(railway$contraptionStorage);
137+
} else {
138+
((WrappedStorageAccessor<FluidVariant>) capability).setWrapped(Storage.empty());
139+
}
140+
141+
if (underControl) {
142+
underControl = false;
143+
notifyUpdate();
144+
}
145+
}
146+
147+
@Override
148+
public boolean hasSpaceFor(@NotNull MultiloaderFluidStack object) {
149+
if (railway$contraptionStorage == null)
150+
return false;
151+
152+
if (!railway$contraptionStorage.supportsInsertion())
153+
return false;
154+
155+
try (Transaction transaction = Transaction.openOuter()) {
156+
if (railway$contraptionStorage.insert(((MultiloaderFluidStackImpl) object).getType(), object.getAmount(), transaction) != object.getAmount()) {
157+
return false;
158+
}
159+
}
160+
161+
return true;
162+
}
163+
164+
@Override
165+
public boolean doPurchase(@NotNull MultiloaderFluidStack object, @NotNull PurchaseProvider<MultiloaderFluidStack> purchaseProvider) {
166+
if (railway$contraptionStorage == null)
167+
return false;
168+
169+
if (!hasSpaceFor(object))
170+
return false;
171+
172+
List<MultiloaderFluidStack> extracted = purchaseProvider.extract();
173+
try (Transaction transaction = Transaction.openOuter()) {
174+
for (MultiloaderFluidStack stack : extracted) {
175+
if (railway$contraptionStorage.insert(((MultiloaderFluidStackImpl) stack).getType(), stack.getAmount(), transaction) != stack.getAmount()) {
176+
Numismatics.LOGGER.error("Failed to insert fluid into contraption storage, despite having space.");
177+
return false;
178+
}
179+
}
180+
transaction.commit();
181+
}
182+
183+
return true;
184+
}
185+
186+
@Override
187+
public void read(@NotNull CompoundTag nbt, boolean clientPacket) {
188+
super.read(nbt, clientPacket);
189+
190+
underControl = nbt.getBoolean("SalepointUnderControl");
191+
}
192+
193+
@Override
194+
public void write(@NotNull CompoundTag nbt, boolean clientPacket) {
195+
super.write(nbt, clientPacket);
196+
197+
nbt.putBoolean("SalepointUnderControl", underControl);
198+
}
199+
200+
@Override
201+
public boolean canSetFilter(Object filter) {
202+
if (!super.canSetFilter(filter))
203+
return false;
204+
205+
if (!(filter instanceof MultiloaderFluidStackImpl fs))
206+
return false;
207+
208+
return LiquidFuelTrainHandler.isFuel(fs.getFluid());
209+
}
210+
};
211+
212+
behaviours.add(railway$salepointBehaviour);
213+
}
214+
215+
@Mixin(InterfaceFluidHandler.class)
216+
private static class InterfaceFluidHandlerMixin {
217+
@WrapOperation(
218+
method = "insert(Lnet/fabricmc/fabric/api/transfer/v1/fluid/FluidVariant;JLnet/fabricmc/fabric/api/transfer/v1/transaction/TransactionContext;)J",
219+
at = @At(
220+
value = "INVOKE",
221+
target = "Lcom/railwayteam/railways/content/fuel/psi/PortableFuelInterfaceBlockEntity;isConnected()Z"
222+
)
223+
)
224+
private boolean fakeConnect(PortableFuelInterfaceBlockEntity instance, Operation<Boolean> original) {
225+
return original.call(instance) || instance.getBehaviour(SalepointTargetBehaviour.TYPE).isControlledBySalepoint();
226+
}
227+
}
228+
}

fabric/src/main/resources/numismatics.mixins.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
"WrappedStorageAccessor",
1717
"compat.PortableEnergyInterfaceBlockEntityMixin",
1818
"compat.PortableEnergyInterfaceBlockEntityMixin$InterfaceEnergyHandlerAccessor",
19-
"compat.PortableEnergyInterfaceMovementMixin"
19+
"compat.PortableEnergyInterfaceMovementMixin",
20+
"compat.PortableFuelInterfaceBlockEntityMixin",
21+
"compat.PortableFuelInterfaceBlockEntityMixin$InterfaceFluidHandlerMixin"
2022
],
2123
"injectors": {
2224
"defaultRequire": 1

0 commit comments

Comments
 (0)