Skip to content

Commit

Permalink
More data components
Browse files Browse the repository at this point in the history
- moved component-related helper methods to their own class, DataComponentHelper
- ItemNBTHelper is now deprecated
  • Loading branch information
TheRealWormbo committed Feb 23, 2025
1 parent 528941e commit a956ecd
Show file tree
Hide file tree
Showing 33 changed files with 454 additions and 414 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
* such as generating flowers to mana collectors, or functional flowers to pools.
* Implements the bindability logic common to both types of flower.
*
* @param <T> Type of block entity this special flower cna bind to.
* @param <T> Type of block entity this special flower can bind to.
*/
public abstract class BindableSpecialFlowerBlockEntity<T> extends SpecialFlowerBlockEntity implements WandBindable {
/**
Expand Down Expand Up @@ -107,7 +107,7 @@ public void setBindingPos(@Nullable BlockPos bindingPos) {
}
}

public @Nullable T findBindCandidateAt(BlockPos pos) {
public @Nullable T findBindCandidateAt(@Nullable BlockPos pos) {
if (level == null || pos == null) {
return null;
}
Expand All @@ -132,6 +132,7 @@ public boolean isValidBinding() {
return wouldBeValidBinding(bindingPos);
}

@Nullable
@Override
public BlockPos getBinding() {
//Used for Wand of the Forest overlays; only return the binding if it's valid.
Expand Down Expand Up @@ -166,22 +167,7 @@ public void writeToPacketNBT(CompoundTag cmp, HolderLookup.Provider registries)
public void readFromPacketNBT(CompoundTag cmp, HolderLookup.Provider registries) {
super.readFromPacketNBT(cmp, registries);

if (cmp.contains(TAG_BINDING)) {
//todo bindingPos = NbtUtils.readBlockPos(cmp.getCompound(TAG_BINDING));
} else {
//In older versions of the mod (1.16, early 1.17), GeneratingFlowerBlockEntity and SpecialFlowerBlockEntity
//implemented their own copies of the binding logic. Read data from the old locations.
if (cmp.contains("collectorX")) {
bindingPos = new BlockPos(cmp.getInt("collectorX"), cmp.getInt("collectorY"), cmp.getInt("collectorZ"));
} else if (cmp.contains("poolX")) {
bindingPos = new BlockPos(cmp.getInt("poolX"), cmp.getInt("poolY"), cmp.getInt("poolZ"));
}
//These versions of the mod also sometimes used a binding with a Y of -1 to signify an unbound flower.
//Currently, `null` is always used for unbound flowers. Coerce these positions to `null`.
if (bindingPos != null && bindingPos.getY() == -1) {
bindingPos = null;
}
}
NbtUtils.readBlockPos(cmp, TAG_BINDING).ifPresent(this::setBindingPos);
}

public abstract int getMana();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,7 @@
import vazkii.botania.api.block_entity.FunctionalFlowerBlockEntity;
import vazkii.botania.api.block_entity.RadiusDescriptor;
import vazkii.botania.common.block.BotaniaFlowerBlocks;
import vazkii.botania.common.helper.DelayHelper;
import vazkii.botania.common.helper.EntityHelper;
import vazkii.botania.common.helper.InventoryHelper;
import vazkii.botania.common.helper.ItemNBTHelper;
import vazkii.botania.common.helper.*;
import vazkii.botania.common.internal_caps.ItemFlagsComponent;
import vazkii.botania.xplat.XplatAbstractions;

Expand Down Expand Up @@ -156,7 +153,7 @@ public static boolean canAcceptItem(ItemStack stack, List<ItemStack> filter, int
}
anyFilter = true;

if (ItemNBTHelper.matchTagAndManaFullness(stack, filterEntry)) {
if (DataComponentHelper.matchTagAndManaFullness(stack, filterEntry)) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,15 @@ public class BotaniaDataComponents {
public static final DataComponentType<GlobalPos> MANA_POOL_POS = make(LibComponentNames.MANA_POOL_POS,
builder -> builder.persistent(GlobalPos.CODEC).networkSynchronized(GlobalPos.STREAM_CODEC));

public static final DataComponentType<Integer> RANGE = make(LibComponentNames.RANGE,
builder -> builder.persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT));

// crafting halo data
public static final DataComponentType<Float> HALO_ROTATION_BASE = make(LibComponentNames.HALO_ROTATION_BASE,
builder -> builder.networkSynchronized(ByteBufCodecs.FLOAT));
public static final DataComponentType<ResourceLocation> LAST_RECIPE_ID = make(LibComponentNames.LAST_RECIPE_ID,
builder -> builder.persistent(ResourceLocation.CODEC).networkSynchronized(ResourceLocation.STREAM_CODEC)
);
public static final DataComponentType<HaloRecipeStorageComponent> STORED_RECIPES = make(LibComponentNames.STORED_RECIPES,
builder -> builder.persistent(HaloRecipeStorageComponent.CODEC)
.networkSynchronized(HaloRecipeStorageComponent.STREAM_CODEC).cacheEncoding());
public static final DataComponentType<StoredIds> STORED_RECIPES = make(LibComponentNames.STORED_RECIPES,
builder -> builder.persistent(StoredIds.CODEC).cacheEncoding()
.networkSynchronized(StoredIds.STREAM_CODEC));

public static final DataComponentType<Long> LAST_TRIGGER_TIME = make(LibComponentNames.LAST_TRIGGER_TIME,
builder -> builder.persistent(Codec.LONG).networkSynchronized(ByteBufCodecs.VAR_LONG));
Expand All @@ -132,7 +129,7 @@ public class BotaniaDataComponents {
*/
public static final DataComponentType<Unit> LENS_RAINBOW_TINT = makeUnit(LibComponentNames.LENS_RAINBOW_TINT);
public static final DataComponentType<ItemStack> ATTACHED_LENS = make(LibComponentNames.ATTACHED_LENS,
builder -> builder.persistent(ItemStack.CODEC).networkSynchronized(ItemStack.STREAM_CODEC).cacheEncoding());
builder -> builder.persistent(ItemStack.CODEC).cacheEncoding().networkSynchronized(ItemStack.STREAM_CODEC));

// brews and similar consumables
public static final DataComponentType<ResourceLocation> BREW = make(LibComponentNames.BREW,
Expand Down Expand Up @@ -166,6 +163,13 @@ public void encode(RegistryFriendlyByteBuf buffer, Long value) {
public static final DataComponentType<Integer> BLOCK_COUNT = make(LibComponentNames.BLOCK_COUNT,
builder -> builder.persistent(ExtraCodecs.NON_NEGATIVE_INT).networkSynchronized(ByteBufCodecs.VAR_INT));

public static final DataComponentType<Integer> RANGE = make(LibComponentNames.RANGE,
builder -> builder.persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT));
public static final DataComponentType<ResourceLocation> MOB_TYPE = make(LibComponentNames.MOB_TYPE,
builder -> builder.persistent(ResourceLocation.CODEC).networkSynchronized(ResourceLocation.STREAM_CODEC));
public static final DataComponentType<Integer> NOT_MY_NAME_STEP = make(LibComponentNames.NOT_MY_NAME_STEP,
builder -> builder.persistent(Codec.INT).networkSynchronized(ByteBufCodecs.VAR_INT));

public static void registerComponents(BiConsumer<DataComponentType<?>, ResourceLocation> biConsumer) {
for (Map.Entry<String, DataComponentType<?>> entry : ALL.entrySet()) {
biConsumer.accept(entry.getValue(), botaniaRL(entry.getKey()));
Expand Down

This file was deleted.

146 changes: 146 additions & 0 deletions Xplat/src/main/java/vazkii/botania/common/component/StoredIds.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/*
* This class is distributed as part of the Botania Mod.
* Get the Source Code in github:
* https://github.com/Vazkii/Botania
*
* Botania is Open Source and distributed under the
* Botania License: http://botaniamod.net/license.php
*
*/

package vazkii.botania.common.component;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;

import org.jetbrains.annotations.Nullable;

import java.util.*;

import io.netty.buffer.ByteBuf;

public class StoredIds {
public static final StoredIds EMPTY = new StoredIds(new ResourceLocation[0]);
public static final int MAX_SLOTS = 128; // happens to be a single byte if written as VAR_INT

public static final Codec<StoredIds> CODEC = Slot.CODEC.sizeLimitedListOf(MAX_SLOTS)
.xmap(StoredIds::fromSlots, StoredIds::getPopulatedSlots);
public static final StreamCodec<ByteBuf, StoredIds> STREAM_CODEC = Slot.STREAM_CODEC
.apply(ByteBufCodecs.list(MAX_SLOTS))
.map(StoredIds::fromSlots, StoredIds::getPopulatedSlots);

private static StoredIds fromSlots(List<Slot> slots) {
OptionalInt lastSlotIndex = slots.stream().mapToInt(Slot::index).max();
if (lastSlotIndex.isEmpty()) {
return EMPTY;
}

var ids = new ResourceLocation[lastSlotIndex.getAsInt() + 1];
for (Slot slot : slots) {
ids[slot.index] = slot.value;
}

return new StoredIds(ids);
}

private static List<Slot> getPopulatedSlots(StoredIds storedIds) {
var ids = storedIds.ids;
List<Slot> slots = new ArrayList<>(ids.length);
for (int i = 0; i < ids.length; i++) {
if (ids[i] != null) {
slots.add(new Slot(i, ids[i]));
}
}
return slots;
}

@Nullable
private final ResourceLocation[] ids;
private final int cachedHashCode;

private StoredIds(ResourceLocation[] idsToStore) {
ids = idsToStore;
cachedHashCode = Arrays.hashCode(idsToStore);
}

public StoredIds store(int slot, @Nullable ResourceLocation newId) {
if (slot < 0 || slot >= MAX_SLOTS) {
throw new IndexOutOfBoundsException("Slot index must be positive and less than " + MAX_SLOTS + ", but was " + slot);
}

if (slot < ids.length && Objects.equals(ids[slot], newId)) {
return this;
}

int newLength = getNewLength(slot, newId);

if (newLength == 0) {
return EMPTY;
}

var idsCopy = Arrays.copyOf(ids, newLength);
if (slot < newLength) {
idsCopy[slot] = newId;
}

return new StoredIds(idsCopy);
}

private int getNewLength(int slot, @Nullable ResourceLocation newId) {
if (newId != null) {
// setting a slot, array might need to grow
return Math.max(ids.length, slot + 1);

}

if (slot == ids.length - 1) {
// clearing last entry, trim array to have no empty slots at the end
int newLastSlot = slot;
//noinspection StatementWithEmptyBody
while (--newLastSlot >= 0 && ids[newLastSlot] == null) {}
return newLastSlot + 1;

}

// clearing a slot that is not the last one, array will keep its length
return ids.length;
}

@Nullable
public ResourceLocation getSlot(int slot) {
return slot >= 0 && slot < ids.length ? ids[slot] : null;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof StoredIds that)) {
return false;
}
return Arrays.equals(ids, that.ids);
}

@Override
public int hashCode() {
return cachedHashCode;
}

public record Slot(int index, ResourceLocation value) {
public static final Codec<Slot> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.intRange(0, MAX_SLOTS).fieldOf("index").forGetter(Slot::index),
ResourceLocation.CODEC.fieldOf("value").forGetter(Slot::value)
).apply(instance, Slot::new));

public static final StreamCodec<ByteBuf, Slot> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.VAR_INT, Slot::index,
ResourceLocation.STREAM_CODEC, Slot::value,
Slot::new
);
}
}
Loading

0 comments on commit a956ecd

Please sign in to comment.