Skip to content

Commit 4f5f067

Browse files
committed
forge energy salepoint implementation
1 parent 2aaf4ac commit 4f5f067

File tree

4 files changed

+239
-2
lines changed

4 files changed

+239
-2
lines changed

common/src/main/java/dev/ithundxr/createnumismatics/content/salepoint/types/SimpleEnergyBuffer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import net.minecraft.nbt.CompoundTag;
2222
import org.jetbrains.annotations.Nullable;
2323

24-
public class SimpleEnergyBuffer implements EnergyBuffer{
24+
public class SimpleEnergyBuffer implements EnergyBuffer {
2525

2626
private final long capacity;
2727
private long amount;

fabric/src/main/java/dev/ithundxr/createnumismatics/fabric/mixin/compat/PortableEnergyInterfaceBlockEntityMixin.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ private void keepControl(InterfaceEnergyHandler instance, EnergyStorage wrapped,
8080
if (!(existingWrapped instanceof InvalidatableWrappingEnergyBufferStorage)) {
8181
original.call(instance, wrapped);
8282
}
83-
railway$contraptionStorage = ((InterfaceEnergyHandlerAccessor) wrapped).getWrapped();
83+
railway$contraptionStorage = wrapped;
8484
}
8585

8686
@WrapOperation(
@@ -222,6 +222,7 @@ public void write(@NotNull CompoundTag nbt, boolean clientPacket) {
222222
behaviours.add(railway$salepointBehaviour);
223223
}
224224

225+
@ConditionalMixin(mods = Mods.CREATEADDITION)
225226
@Mixin(InterfaceEnergyHandler.class)
226227
private interface InterfaceEnergyHandlerAccessor {
227228
@Accessor("wrapped")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
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.forge.mixin.compat;
20+
21+
import com.llamalad7.mixinextras.sugar.Local;
22+
import com.mrh0.createaddition.blocks.portable_energy_interface.PortableEnergyInterfaceBlockEntity;
23+
import com.mrh0.createaddition.blocks.portable_energy_interface.PortableEnergyInterfaceBlockEntity.InterfaceEnergyHandler;
24+
import com.mrh0.createaddition.blocks.portable_energy_interface.PortableEnergyManager;
25+
import com.simibubi.create.content.contraptions.Contraption;
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.EnergySalepointTargetBehaviour;
32+
import dev.ithundxr.createnumismatics.content.salepoint.containers.forge.InvalidatableWrappingEnergyBufferStorage;
33+
import dev.ithundxr.createnumismatics.content.salepoint.states.ISalepointState;
34+
import dev.ithundxr.createnumismatics.content.salepoint.types.Energy;
35+
import net.minecraft.core.BlockPos;
36+
import net.minecraft.nbt.CompoundTag;
37+
import net.minecraft.world.level.block.entity.BlockEntityType;
38+
import net.minecraft.world.level.block.state.BlockState;
39+
import net.minecraftforge.common.util.LazyOptional;
40+
import net.minecraftforge.energy.EnergyStorage;
41+
import net.minecraftforge.energy.IEnergyStorage;
42+
import org.jetbrains.annotations.NotNull;
43+
import org.jetbrains.annotations.Nullable;
44+
import org.spongepowered.asm.mixin.*;
45+
import org.spongepowered.asm.mixin.gen.Accessor;
46+
import org.spongepowered.asm.mixin.injection.At;
47+
import org.spongepowered.asm.mixin.injection.Inject;
48+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
49+
50+
import java.util.List;
51+
import java.util.Objects;
52+
53+
@ConditionalMixin(mods = Mods.CREATEADDITION)
54+
@Mixin(PortableEnergyInterfaceBlockEntity.class)
55+
public abstract class PortableEnergyInterfaceBlockEntityMixin extends PortableStorageInterfaceBlockEntity {
56+
57+
@Shadow protected LazyOptional<IEnergyStorage> capability;
58+
59+
@Unique
60+
private EnergySalepointTargetBehaviour railway$salepointBehaviour;
61+
62+
@Unique
63+
@Nullable
64+
private IEnergyStorage railway$contraptionStorage;
65+
66+
private PortableEnergyInterfaceBlockEntityMixin(BlockEntityType<?> type, BlockPos pos, BlockState state) {
67+
super(type, pos, state);
68+
}
69+
70+
@Inject(
71+
method = "startTransferringTo",
72+
at = @At(
73+
value = "INVOKE",
74+
target = "Lnet/minecraftforge/common/util/LazyOptional;invalidate()V"
75+
),
76+
remap = false
77+
)
78+
private void keepControl(Contraption contraption, float distance, CallbackInfo ci, @Local(name = "oldcap") LazyOptional<IEnergyStorage> oldcap) {
79+
railway$contraptionStorage = PortableEnergyManager.get(contraption);
80+
81+
oldcap.ifPresent(energyHandler -> {
82+
IEnergyStorage existingWrapped = ((InterfaceEnergyHandlerAccessor) energyHandler).getWrapped();
83+
if (existingWrapped instanceof InvalidatableWrappingEnergyBufferStorage) {
84+
capability.ifPresent(newEnergyHandler -> {
85+
((InterfaceEnergyHandlerAccessor) newEnergyHandler).setWrapped(existingWrapped);
86+
});
87+
}
88+
});
89+
}
90+
91+
@Inject(
92+
method = "stopTransferring",
93+
at = @At(
94+
value = "INVOKE",
95+
target = "Lnet/minecraftforge/common/util/LazyOptional;invalidate()V"
96+
),
97+
remap = false
98+
)
99+
private void keepControl2(CallbackInfo ci, @Local(name = "oldcap") LazyOptional<IEnergyStorage> oldcap) {
100+
railway$contraptionStorage = null;
101+
102+
oldcap.ifPresent(energyHandler -> {
103+
IEnergyStorage existingWrapped = ((InterfaceEnergyHandlerAccessor) energyHandler).getWrapped();
104+
if (existingWrapped instanceof InvalidatableWrappingEnergyBufferStorage) {
105+
capability.ifPresent(newEnergyHandler -> {
106+
((InterfaceEnergyHandlerAccessor) newEnergyHandler).setWrapped(existingWrapped);
107+
});
108+
}
109+
});
110+
}
111+
112+
@Override
113+
public boolean canTransfer() {
114+
return super.canTransfer() || railway$salepointBehaviour.isControlledBySalepoint();
115+
}
116+
117+
@Override
118+
public void addBehaviours(List<BlockEntityBehaviour> behaviours) {
119+
super.addBehaviours(behaviours);
120+
railway$salepointBehaviour = new EnergySalepointTargetBehaviour(this) {
121+
private boolean underControl;
122+
123+
@Override
124+
protected boolean isUnderControlInternal(@NotNull ISalepointState<Energy> state) {
125+
return underControl; // id checks done by super
126+
}
127+
128+
@Override
129+
protected void ensureUnderControlInternal(@NotNull ISalepointState<Energy> state) {
130+
capability.ifPresent(energyHandler -> {
131+
((InterfaceEnergyHandlerAccessor) energyHandler).setWrapped((InvalidatableWrappingEnergyBufferStorage) state.getBuffer());
132+
});
133+
134+
if (!underControl) {
135+
underControl = true;
136+
notifyUpdate();
137+
}
138+
}
139+
140+
@Override
141+
protected void relinquishControlInternal(@NotNull ISalepointState<Energy> state) {
142+
capability.ifPresent(energyHandler -> {
143+
((InterfaceEnergyHandlerAccessor) energyHandler).setWrapped(Objects.requireNonNullElseGet(
144+
railway$contraptionStorage,
145+
() -> new EnergyStorage(0)
146+
));
147+
});
148+
149+
if (underControl) {
150+
underControl = false;
151+
notifyUpdate();
152+
}
153+
}
154+
155+
@Override
156+
public boolean hasSpaceFor(@NotNull Energy object) {
157+
if (railway$contraptionStorage == null)
158+
return false;
159+
160+
if (!railway$contraptionStorage.canReceive())
161+
return false;
162+
163+
if (railway$contraptionStorage.receiveEnergy((int) object.getAmount(), true) == 0)
164+
return false;
165+
166+
int remainingCapacity = railway$contraptionStorage.getMaxEnergyStored() - railway$contraptionStorage.getEnergyStored();
167+
return remainingCapacity >= object.getAmount();
168+
}
169+
170+
@Override
171+
public boolean doPurchase(@NotNull Energy object, @NotNull PurchaseProvider<Energy> purchaseProvider) {
172+
if (railway$contraptionStorage == null)
173+
return false;
174+
175+
if (!hasSpaceFor(object))
176+
return false;
177+
178+
List<Energy> extracted = purchaseProvider.extract();
179+
for (Energy energy : extracted) {
180+
long totalInserted = 0;
181+
while (totalInserted < energy.getAmount()) {
182+
long inserted = railway$contraptionStorage.receiveEnergy((int) (energy.getAmount() - totalInserted), false);
183+
if (inserted == 0)
184+
break;
185+
totalInserted += inserted;
186+
}
187+
if (totalInserted != energy.getAmount()) {
188+
Numismatics.LOGGER.error("Failed to insert energy into contraption storage, despite having space.");
189+
return false;
190+
}
191+
}
192+
193+
return true;
194+
}
195+
196+
@Override
197+
public void read(@NotNull CompoundTag nbt, boolean clientPacket) {
198+
super.read(nbt, clientPacket);
199+
200+
underControl = nbt.getBoolean("SalepointUnderControl");
201+
}
202+
203+
@Override
204+
public void write(@NotNull CompoundTag nbt, boolean clientPacket) {
205+
super.write(nbt, clientPacket);
206+
207+
nbt.putBoolean("SalepointUnderControl", underControl);
208+
}
209+
};
210+
211+
behaviours.add(railway$salepointBehaviour);
212+
}
213+
214+
@ConditionalMixin(mods = Mods.CREATEADDITION)
215+
@Mixin(InterfaceEnergyHandler.class)
216+
private interface InterfaceEnergyHandlerAccessor {
217+
@Accessor("wrapped")
218+
IEnergyStorage getWrapped();
219+
220+
@Accessor("wrapped")
221+
void setWrapped(IEnergyStorage wrapped);
222+
}
223+
224+
@ConditionalMixin(mods = Mods.CREATEADDITION)
225+
@Mixin(InterfaceEnergyHandler.class)
226+
private static class InterfaceEnergyHandlerMixin {
227+
@Shadow
228+
@Final
229+
@Mutable
230+
@SuppressWarnings("unused") // Used to make mutable for the accessor above
231+
private IEnergyStorage wrapped;
232+
}
233+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
"PortableFluidInterfaceBlockEntityMixin$InterfaceFluidHandlerMixin",
1616
"PortableItemInterfaceBlockEntityMixin",
1717
"ServerGamePacketListenerImplMixin",
18+
"compat.PortableEnergyInterfaceBlockEntityMixin",
19+
"compat.PortableEnergyInterfaceBlockEntityMixin$InterfaceEnergyHandlerAccessor",
20+
"compat.PortableEnergyInterfaceBlockEntityMixin$InterfaceEnergyHandlerMixin",
1821
"self.BrassDepositorBlockEntityCapabilities",
1922
"self.ComputerBehaviourCapabilities",
2023
"self.VendorBlockEntityCapabilities"

0 commit comments

Comments
 (0)