Skip to content

Commit b562093

Browse files
committed
feat: add helper classes for item-backed storages
1 parent 74289c7 commit b562093

6 files changed

+416
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright (c) 2021-2024 Team Galacticraft
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package dev.galacticraft.machinelib.api.component;
24+
25+
import com.mojang.serialization.Codec;
26+
import dev.galacticraft.machinelib.impl.Constant;
27+
import io.netty.buffer.ByteBuf;
28+
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
29+
import net.minecraft.core.Registry;
30+
import net.minecraft.core.component.DataComponentType;
31+
import net.minecraft.core.registries.BuiltInRegistries;
32+
import net.minecraft.network.codec.StreamCodec;
33+
34+
import java.util.function.UnaryOperator;
35+
36+
public class MLDataComponents {
37+
private static final StreamCodec<ByteBuf, Long> LONG_STREAM_CODEC = StreamCodec.of(ByteBuf::writeLong, ByteBuf::readLong);
38+
39+
public static final DataComponentType<Long> AMOUNT = register("amount", b -> b
40+
.persistent(Codec.LONG)
41+
.networkSynchronized(LONG_STREAM_CODEC)
42+
);
43+
44+
public static final DataComponentType<Long> CAPACITY = register("capacity", b -> b
45+
.persistent(Codec.LONG)
46+
.networkSynchronized(LONG_STREAM_CODEC)
47+
);
48+
49+
public static final DataComponentType<Long> MAX_INPUT = register("max_input", b -> b
50+
.persistent(Codec.LONG)
51+
.networkSynchronized(LONG_STREAM_CODEC)
52+
);
53+
54+
public static final DataComponentType<Long> MAX_OUTPUT = register("max_output", b -> b
55+
.persistent(Codec.LONG)
56+
.networkSynchronized(LONG_STREAM_CODEC)
57+
);
58+
59+
public static final DataComponentType<FluidVariant> FLUID = register("fluid", b -> b
60+
.persistent(FluidVariant.CODEC)
61+
.networkSynchronized(FluidVariant.PACKET_CODEC)
62+
);
63+
64+
private static <T> DataComponentType<T> register(String id, UnaryOperator<DataComponentType.Builder<T>> op) {
65+
return Registry.register(BuiltInRegistries.DATA_COMPONENT_TYPE, Constant.id(id), op.apply(DataComponentType.builder()).build());
66+
}
67+
68+
public static void init() {}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2021-2024 Team Galacticraft
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package dev.galacticraft.machinelib.api.item;
24+
25+
import dev.galacticraft.machinelib.api.filter.ResourceFilter;
26+
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
27+
import net.minecraft.world.item.ItemStack;
28+
import net.minecraft.world.level.material.Fluid;
29+
30+
public class FixedItemBackedFluidStorage extends ItemBackedFluidStorage {
31+
private final long maxIn;
32+
private final long maxOut;
33+
private final long capacity;
34+
35+
public FixedItemBackedFluidStorage(ItemStack stack, ContainerItemContext context, ResourceFilter<Fluid> filter, long maxIn, long maxOut, long capacity) {
36+
super(stack, context, filter);
37+
this.maxIn = maxIn;
38+
this.maxOut = maxOut;
39+
this.capacity = capacity;
40+
}
41+
42+
@Override
43+
protected long getRawMaxInput() {
44+
return this.maxIn;
45+
}
46+
47+
@Override
48+
protected long getRawMaxOutput() {
49+
return this.maxOut;
50+
}
51+
52+
@Override
53+
protected long getRawCapacity() {
54+
return this.capacity;
55+
}
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) 2021-2024 Team Galacticraft
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package dev.galacticraft.machinelib.api.item;
24+
25+
import com.google.common.collect.Iterators;
26+
import dev.galacticraft.machinelib.api.filter.ResourceFilter;
27+
import dev.galacticraft.machinelib.api.filter.ResourceFilters;
28+
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
29+
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
30+
import net.fabricmc.fabric.api.transfer.v1.storage.Storage;
31+
import net.fabricmc.fabric.api.transfer.v1.storage.StorageView;
32+
import net.fabricmc.fabric.api.transfer.v1.storage.TransferVariant;
33+
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
34+
import net.minecraft.world.item.ItemStack;
35+
import org.jetbrains.annotations.NotNull;
36+
37+
import java.util.Collections;
38+
import java.util.Iterator;
39+
40+
public abstract class GenericItemBackedStorage<T, V extends TransferVariant<T>> implements Storage<V>, StorageView<V> {
41+
protected final ItemVariant item;
42+
protected final ContainerItemContext context;
43+
protected final ResourceFilter<T> filter;
44+
45+
protected GenericItemBackedStorage(ItemStack stack, ContainerItemContext context, ResourceFilter<T> filter) {
46+
this.item = ItemVariant.of(stack);
47+
this.context = context;
48+
this.filter = filter;
49+
}
50+
51+
protected GenericItemBackedStorage(ItemStack stack, ContainerItemContext context) {
52+
this(stack, context, ResourceFilters.any());
53+
}
54+
55+
protected abstract long getRawMaxInput();
56+
protected abstract long getRawMaxOutput();
57+
protected abstract long getRawCapacity();
58+
protected abstract long getRawAmount();
59+
protected abstract boolean setRawContents(V variant, long amount, TransactionContext transaction);
60+
61+
@Override
62+
public long insert(V resource, long maxAmount, TransactionContext transaction) {
63+
if (!this.item.equals(this.context.getItemVariant())) return 0;
64+
if (this.filter.test(resource.getObject(), resource.getComponents()) && (this.getResource().isBlank() || this.getResource().equals(resource))) {
65+
long stored = this.getRawAmount();
66+
maxAmount = Math.min(this.getRawCapacity() - stored, maxAmount / this.context.getAmount());
67+
maxAmount = Math.min(maxAmount, this.getRawMaxInput());
68+
if (this.setRawContents(resource, stored + maxAmount, transaction)) {
69+
return maxAmount * this.context.getAmount();
70+
}
71+
}
72+
return 0;
73+
}
74+
75+
@Override
76+
public long extract(V resource, long maxAmount, TransactionContext transaction) {
77+
assert !resource.isBlank();
78+
if (!this.item.equals(this.context.getItemVariant())) return 0;
79+
if (this.getResource().equals(resource)) {
80+
long stored = this.getRawAmount();
81+
maxAmount = Math.min(stored, maxAmount / this.context.getAmount());
82+
maxAmount = Math.min(maxAmount, this.getRawMaxOutput());
83+
if (this.setRawContents(resource, stored - maxAmount, transaction)) {
84+
return maxAmount * this.context.getAmount();
85+
}
86+
}
87+
return 0;
88+
}
89+
90+
@Override
91+
public boolean isResourceBlank() {
92+
return this.getResource().isBlank();
93+
}
94+
95+
@Override
96+
public long getAmount() {
97+
if (!this.item.equals(this.context.getItemVariant())) return 0;
98+
return this.getRawAmount() * this.context.getAmount();
99+
}
100+
101+
@Override
102+
public long getCapacity() {
103+
if (!this.item.equals(this.context.getItemVariant())) return 0;
104+
return this.getRawCapacity() * this.context.getAmount();
105+
}
106+
107+
@Override
108+
public @NotNull Iterator<StorageView<V>> iterator() {
109+
if (!this.item.equals(this.context.getItemVariant())) return Collections.emptyIterator();
110+
return Iterators.singletonIterator(this);
111+
}
112+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright (c) 2021-2024 Team Galacticraft
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in all
12+
* copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
23+
package dev.galacticraft.machinelib.api.item;
24+
25+
import dev.galacticraft.machinelib.api.component.MLDataComponents;
26+
import dev.galacticraft.machinelib.api.filter.ResourceFilter;
27+
import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext;
28+
import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant;
29+
import net.fabricmc.fabric.api.transfer.v1.item.ItemVariant;
30+
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
31+
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
32+
import net.minecraft.core.component.DataComponentPatch;
33+
import net.minecraft.core.component.DataComponentType;
34+
import net.minecraft.world.item.ItemStack;
35+
import net.minecraft.world.level.material.Fluid;
36+
37+
import java.util.Optional;
38+
39+
public class ItemBackedFluidStorage extends GenericItemBackedStorage<Fluid, FluidVariant> {
40+
public ItemBackedFluidStorage(ItemStack stack, ContainerItemContext context, ResourceFilter<Fluid> filter) {
41+
super(stack, context, filter);
42+
}
43+
44+
protected ItemBackedFluidStorage(ItemStack stack, ContainerItemContext context) {
45+
super(stack, context);
46+
}
47+
48+
@Override
49+
protected long getRawMaxInput() {
50+
return this.getComponent(MLDataComponents.MAX_INPUT);
51+
}
52+
53+
@Override
54+
protected long getRawMaxOutput() {
55+
return this.getComponent(MLDataComponents.MAX_OUTPUT);
56+
}
57+
58+
@Override
59+
protected long getRawCapacity() {
60+
return this.getComponent(MLDataComponents.CAPACITY);
61+
}
62+
63+
@Override
64+
protected long getRawAmount() {
65+
return this.getComponent(MLDataComponents.AMOUNT);
66+
}
67+
68+
@Override
69+
protected boolean setRawContents(FluidVariant variant, long amount, TransactionContext transaction) {
70+
ItemStack stack = this.context.getItemVariant().toStack();
71+
if (amount == 0) {
72+
assert variant.isBlank();
73+
stack.remove(MLDataComponents.FLUID);
74+
stack.remove(MLDataComponents.AMOUNT);
75+
} else {
76+
assert !variant.isBlank();
77+
stack.set(MLDataComponents.FLUID, variant);
78+
stack.set(MLDataComponents.AMOUNT, amount);
79+
}
80+
81+
long itemCount = this.context.getAmount();
82+
try (Transaction nested = transaction.openNested()) {
83+
if (this.context.extract(this.context.getItemVariant(), itemCount, nested) == itemCount && this.context.insert(ItemVariant.of(stack), itemCount, nested) == itemCount) {
84+
nested.commit();
85+
return true;
86+
}
87+
}
88+
return false;
89+
}
90+
91+
@Override
92+
public FluidVariant getResource() {
93+
DataComponentPatch components = this.context.getItemVariant().getComponents();
94+
if (components != null) {
95+
Optional<? extends FluidVariant> optional = components.get(MLDataComponents.FLUID);
96+
return optional != null && optional.isPresent() ? optional.get() : FluidVariant.blank();
97+
}
98+
return FluidVariant.blank();
99+
}
100+
101+
private long getComponent(DataComponentType<Long> type) {
102+
DataComponentPatch components = this.context.getItemVariant().getComponents();
103+
if (components != null) {
104+
Optional<? extends Long> optional = components.get(type);
105+
return optional != null && optional.isPresent() ? optional.get() : 0L;
106+
}
107+
return 0L;
108+
}
109+
}

0 commit comments

Comments
 (0)