diff options
Diffstat (limited to 'runtime-engine/entry-stacks/src/main/java')
6 files changed, 976 insertions, 0 deletions
diff --git a/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java new file mode 100644 index 000000000..4da98dd58 --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/EntryIngredientImpl.java @@ -0,0 +1,476 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.common.entry; + +import com.google.common.collect.Iterators; +import me.shedaniel.rei.api.common.entry.EntryIngredient; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.impl.common.provider.EntryIngredientProvider; +import net.minecraft.nbt.ListTag; +import org.jetbrains.annotations.ApiStatus; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.StreamSupport; + +@ApiStatus.Internal +public class EntryIngredientImpl implements EntryIngredientProvider { + @Override + public EntryIngredient empty() { + return EmptyEntryIngredient.EMPTY; + } + + @Override + public EntryIngredient of(EntryStack<?> stack) { + return new SingletonEntryIngredient(stack); + } + + @Override + public EntryIngredient of(EntryStack<?>... stacks) { + if (stacks.length == 0) return empty(); + if (stacks.length == 1) return of(stacks[0]); + return _of(stacks); + } + + @Override + public EntryIngredient of(Iterable<EntryStack<?>> stacks) { + if (stacks instanceof EntryIngredient) return (EntryIngredient) stacks; + if (stacks instanceof Collection<EntryStack<?>> collection) { + int size = collection.size(); + if (size == 0) return empty(); + if (size == 1) return of(stacks.iterator().next()); + return _of(collection.toArray(new EntryStack[0])); + } + return _of(StreamSupport.stream(stacks.spliterator(), false).toArray(EntryStack[]::new)); + } + + private EntryIngredient _of(EntryStack<?>... stacks) { + return new ArrayIngredient(stacks); + } + + @Override + public EntryIngredient.Builder builder() { + return new EntryIngredientBuilder(0); + } + + @Override + public EntryIngredient.Builder builder(int initialCapacity) { + return new EntryIngredientBuilder(initialCapacity); + } + + private static class EntryIngredientBuilder implements EntryIngredient.Builder { + private EntryStack<?>[] contents; + private int size = 0; + + public EntryIngredientBuilder(int initialCapacity) { + this.contents = new EntryStack[initialCapacity]; + } + + private void ensureCapacity(int minCapacity) { + if (contents.length < minCapacity) { + this.contents = Arrays.copyOf(this.contents, expandedCapacity(contents.length, minCapacity)); + } + } + + static int expandedCapacity(int oldCapacity, int minCapacity) { + int newCapacity = oldCapacity + (oldCapacity >> 1) + 1; + if (newCapacity < minCapacity) { + newCapacity = Integer.highestOneBit(minCapacity - 1) << 1; + } + if (newCapacity < 0) { + newCapacity = Integer.MAX_VALUE; + } + return newCapacity; + } + + @Override + public EntryIngredient.Builder add(EntryStack<?> stack) { + ensureCapacity(size + 1); + contents[size++] = stack; + return this; + } + + @Override + public EntryIngredient.Builder add(EntryStack<?>... stacks) { + ensureCapacity(size + stacks.length); + System.arraycopy(stacks, 0, contents, size, stacks.length); + size += stacks.length; + return this; + } + + @Override + public EntryIngredient.Builder addAll(Iterable<? extends EntryStack<?>> stacks) { + if (stacks instanceof Collection<?> collection) { + ensureCapacity(size + collection.size()); + } + for (EntryStack<?> stack : stacks) { + add(stack); + } + return this; + } + + @Override + public EntryIngredient build() { + if (contents.length > size) { + return EntryIngredient.of((EntryStack<Object>[]) Arrays.copyOf(contents, size)); + } + return EntryIngredient.of((EntryStack<Object>[]) contents); + } + } + + private static class EmptyEntryIngredient extends AbstractList<EntryStack<?>> implements EntryIngredient, RandomAccess { + private static final EmptyEntryIngredient EMPTY = new EmptyEntryIngredient(); + + @Override + public Iterator<EntryStack<?>> iterator() { + return Collections.emptyIterator(); + } + + @Override + public ListIterator<EntryStack<?>> listIterator() { + return Collections.emptyListIterator(); + } + + @Override + public int size() { + return 0; + } + + @Override + public boolean isEmpty() { + return true; + } + + @Override + public boolean contains(Object obj) { + return false; + } + + @Override + public boolean containsAll(Collection<?> c) { + return c.isEmpty(); + } + + @Override + public Object[] toArray() { + return new Object[0]; + } + + @Override + public <T> T[] toArray(T[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + @Override + public EntryStack<?> get(int index) { + throw new IndexOutOfBoundsException("Index: " + index); + } + + @Override + public boolean equals(Object o) { + return (o instanceof List) && ((List<?>) o).isEmpty(); + } + + @Override + public int hashCode() { + return 1; + } + + @Override + public boolean removeIf(Predicate<? super EntryStack<?>> filter) { + Objects.requireNonNull(filter); + return false; + } + + @Override + public void replaceAll(UnaryOperator<EntryStack<?>> operator) { + Objects.requireNonNull(operator); + } + + @Override + public void sort(Comparator<? super EntryStack<?>> c) { + } + + @Override + public void forEach(Consumer<? super EntryStack<?>> action) { + Objects.requireNonNull(action); + } + + @Override + public Spliterator<EntryStack<?>> spliterator() { + return Spliterators.emptySpliterator(); + } + + @Override + public ListTag save() { + return new ListTag(); + } + + @Override + public EntryIngredient filter(Predicate<EntryStack<?>> filter) { + return this; + } + + @Override + public EntryIngredient map(UnaryOperator<EntryStack<?>> transformer) { + return this; + } + } + + private static class SingletonEntryIngredient extends AbstractList<EntryStack<?>> implements EntryIngredient, RandomAccess { + private EntryStack<?> stack; + + public SingletonEntryIngredient(EntryStack<?> stack) { + this.stack = stack; + } + + @Override + public Iterator<EntryStack<?>> iterator() { + return Iterators.singletonIterator(stack); + } + + @Override + public int size() { + return 1; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean contains(Object obj) { + return Objects.equals(obj, stack); + } + + @Override + public Object[] toArray() { + return new Object[]{stack}; + } + + @Override + public EntryStack<?> get(int index) { + if (index != 0) + throw new IndexOutOfBoundsException("Index: " + index + ", Size: 1"); + return stack; + } + + @Override + public boolean removeIf(Predicate<? super EntryStack<?>> filter) { + throw new UnsupportedOperationException(); + } + + @Override + public void replaceAll(UnaryOperator<EntryStack<?>> operator) { + throw new UnsupportedOperationException(); + } + + @Override + public void sort(Comparator<? super EntryStack<?>> c) { + } + + @Override + public void forEach(Consumer<? super EntryStack<?>> action) { + action.accept(stack); + } + + @Override + public Spliterator<EntryStack<?>> spliterator() { + return singletonSpliterator(stack); + } + + static <T> Spliterator<T> singletonSpliterator(final T element) { + return new Spliterator<T>() { + long est = 1; + + @Override + public Spliterator<T> trySplit() { + return null; + } + + @Override + public boolean tryAdvance(Consumer<? super T> consumer) { + Objects.requireNonNull(consumer); + if (est > 0) { + est--; + consumer.accept(element); + return true; + } + return false; + } + + @Override + public void forEachRemaining(Consumer<? super T> consumer) { + tryAdvance(consumer); + } + + @Override + public long estimateSize() { + return est; + } + + @Override + public int characteristics() { + int value = (element != null) ? Spliterator.NONNULL : 0; + + return value | Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.IMMUTABLE | + Spliterator.DISTINCT | Spliterator.ORDERED; + } + }; + } + + @Override + public ListTag save() { + ListTag listTag = new ListTag(); + listTag.add(stack.saveStack()); + return listTag; + } + + @Override + public EntryIngredient filter(Predicate<EntryStack<?>> filter) { + if (filter.test(stack)) { + return this; + } + return EmptyEntryIngredient.EMPTY; + } + + @Override + public EntryIngredient map(UnaryOperator<EntryStack<?>> transformer) { + return new SingletonEntryIngredient(transformer.apply(stack)); + } + } + + private static class ArrayIngredient extends AbstractList<EntryStack<?>> implements EntryIngredient, RandomAccess { + private static final long serialVersionUID = -2764017481108945198L; + private final EntryStack<?>[] array; + + ArrayIngredient(EntryStack<?>[] array) { + this.array = Objects.requireNonNull(array); + } + + @Override + public int size() { + return array.length; + } + + @Override + public Object[] toArray() { + return toArray(new Object[0]); + } + + @Override + public <T> T[] toArray(T[] a) { + int size = size(); + if (a.length < size) { + return Arrays.copyOf(this.array, size, (Class<? extends T[]>) a.getClass()); + } + System.arraycopy(this.array, 0, a, 0, size); + if (a.length > size) { + a[size] = null; + } + return a; + } + + @Override + public EntryStack<?> get(int index) { + return array[index]; + } + + @Override + public EntryStack<?> set(int index, EntryStack<?> element) { + throw new UnsupportedOperationException(); + } + + @Override + public int indexOf(Object o) { + EntryStack<?>[] a = this.array; + if (o == null) { + for (int i = 0; i < a.length; i++) + if (a[i] == null) + return i; + } else { + for (int i = 0; i < a.length; i++) + if (o.equals(a[i])) + return i; + } + return -1; + } + + @Override + public boolean contains(Object o) { + return indexOf(o) != -1; + } + + @Override + public Spliterator<EntryStack<?>> spliterator() { + return Spliterators.spliterator(array, Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + @Override + public void forEach(Consumer<? super EntryStack<?>> action) { + Objects.requireNonNull(action); + for (EntryStack<?> stack : array) { + action.accept(stack); + } + } + + @Override + public void replaceAll(UnaryOperator<EntryStack<?>> operator) { + throw new UnsupportedOperationException(); + } + + @Override + public void sort(Comparator<? super EntryStack<?>> c) { + throw new UnsupportedOperationException(); + } + + @Override + public ListTag save() { + ListTag listTag = new ListTag(); + for (EntryStack<?> stack : array) { + listTag.add(stack.saveStack()); + } + return listTag; + } + + @Override + public EntryIngredient filter(Predicate<EntryStack<?>> filter) { + return EntryIngredient.of(stream().filter(filter).toArray(EntryStack[]::new)); + } + + @Override + public EntryIngredient map(UnaryOperator<EntryStack<?>> transformer) { + EntryStack<?>[] out = new EntryStack[array.length]; + for (int i = 0; i < array.length; i++) { + out[i] = transformer.apply(array[i]); + } + return new ArrayIngredient(out); + } + } +} diff --git a/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java new file mode 100644 index 000000000..9380f4b0b --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/settings/EntrySettingsAdapterRegistryImpl.java @@ -0,0 +1,71 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.common.entry.settings; + +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapter; +import me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry; +import me.shedaniel.rei.api.common.entry.type.EntryType; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class EntrySettingsAdapterRegistryImpl implements EntrySettingsAdapterRegistry { + private final Map<EntryStack.Settings<?>, Multimap<EntryType<?>, EntrySettingsAdapter<?, ?>>> providers = new HashMap<>(); + + @Override + public <T,S> void register(EntryType<T> type, EntryStack.Settings<S> settings, EntrySettingsAdapter<T,S> provider) { + Multimap<EntryType<?>, EntrySettingsAdapter<?, ?>> multimap = this.providers.computeIfAbsent(settings, $ -> Multimaps.newMultimap(new Reference2ObjectOpenHashMap<>(), ArrayList::new)); + multimap.put(type, provider); + } + + @Override + @Nullable + public <T,S> S adapt(EntryStack<T> stack, EntryStack.Settings<S> settings, @Nullable S value) { + Multimap<EntryType<?>, EntrySettingsAdapter<?, ?>> multimap = providers.get(settings); + if (multimap != null) { + for (EntrySettingsAdapter<T, S> adapter : (Collection<EntrySettingsAdapter<T, S>>) (Collection<? extends EntrySettingsAdapter<?, ?>>) multimap.get(stack.getType())) { + value = adapter.provide(stack, settings, value); + } + } + return value; + } + + @Override + public void startReload() { + providers.clear(); + } + + @Override + public void acceptPlugin(REIPlugin<?> plugin) { + plugin.registerEntrySettingsAdapters(this); + } +} diff --git a/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/AbstractEntryStack.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/AbstractEntryStack.java new file mode 100644 index 000000000..9bfe7bfb5 --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/AbstractEntryStack.java @@ -0,0 +1,281 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.common.entry.stack; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; +import it.unimi.dsi.fastutil.shorts.Short2ObjectMaps; +import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.client.ClientHelper; +import me.shedaniel.rei.api.client.gui.Renderer; +import me.shedaniel.rei.api.client.gui.widgets.Tooltip; +import me.shedaniel.rei.api.client.gui.widgets.TooltipContext; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.settings.EntrySettingsAdapterRegistry; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.api.common.util.FormattingUtils; +import me.shedaniel.rei.impl.client.util.CrashReportUtils; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.CrashReport; +import net.minecraft.CrashReportCategory; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.ItemStack; +import org.apache.commons.lang3.mutable.Mutable; +import org.apache.commons.lang3.mutable.MutableObject; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.Iterator; +import java.util.stream.Stream; + +@ApiStatus.Internal +abstract class AbstractEntryStack<A> implements EntryStack<A>, Renderer { + private static final Short2ObjectMap<Object> EMPTY_SETTINGS = Short2ObjectMaps.emptyMap(); + private Short2ObjectMap<Object> settings = null; + @Environment(EnvType.CLIENT) + private int blitOffset; + + @Override + @Environment(EnvType.CLIENT) + public int getZ() { + return blitOffset; + } + + @Override + @Environment(EnvType.CLIENT) + public void setZ(int z) { + this.blitOffset = z; + } + + @Override + public <T> EntryStack<A> setting(Settings<T> settings, T value) { + short settingsId = settings.getId(); + if (this.settings == null) + this.settings = Short2ObjectMaps.singleton(settingsId, value); + else { + if (this.settings.size() == 1) { + if (this.settings.containsKey(settingsId)) { + this.settings = Short2ObjectMaps.singleton(settingsId, value); + return this; + } else { + Short2ObjectMap<Object> singletonSettings = this.settings; + this.settings = new Short2ObjectOpenHashMap<>(2); + this.settings.putAll(singletonSettings); + } + } + this.settings.put(settingsId, value); + } + return this; + } + + @Override + public <T> EntryStack<A> removeSetting(Settings<T> settings) { + if (this.settings != null) { + short settingsId = settings.getId(); + if (this.settings.size() == 1) { + if (this.settings.containsKey(settingsId)) { + this.settings = null; + } + } else if (this.settings.remove(settingsId) != null && this.settings.isEmpty()) { + this.settings = null; + } + } + return this; + } + + @Override + public EntryStack<A> clearSettings() { + this.settings = null; + return this; + } + + protected Short2ObjectMap<Object> getSettings() { + return this.settings == null ? EMPTY_SETTINGS : this.settings; + } + + @Override + @Nullable + public ResourceLocation getIdentifier() { + return getDefinition().getIdentifier(this, getValue()); + } + + @Override + @Nullable + public String getContainingNamespace() { + return get(Settings.CONTAINING_NS).apply(this, getDefinition().getContainingNamespace(this, getValue())); + } + + @Override + public boolean isEmpty() { + return getDefinition().isEmpty(this, getValue()); + } + + @Override + public EntryStack<A> copy() { + return wrap(getDefinition().copy(this, getValue()), true); + } + + @Override + public EntryStack<A> rewrap() { + return wrap(getValue(), true); + } + + @Override + public EntryStack<A> normalize() { + return wrap(getDefinition().normalize(this, getValue()), false); + } + + @Override + public EntryStack<A> wildcard() { + return wrap(getDefinition().wildcard(this, getValue()), false); + } + + @Override + public EntryStack<ItemStack> cheatsAs() { + ItemStack stack = getDefinition().cheatsAs(this, getValue()); + + if (stack == null) { + return EntryStacks.of(ItemStack.EMPTY); + } + + return EntryStacks.of(stack); + } + + protected EntryStack<A> wrap(A value, boolean copySettings) { + TypedEntryStack<A> stack = new TypedEntryStack<>(getDefinition(), value); + if (copySettings) { + for (Short2ObjectMap.Entry<Object> entry : getSettings().short2ObjectEntrySet()) { + stack.setting(EntryStack.Settings.getById(entry.getShortKey()), entry.getValue()); + } + } + return stack; + } + + @Override + public <T> T get(Settings<T> settings) { + T o = getNullable(settings); + if (o == null) { + o = settings.getDefaultValue(); + } + return o; + } + + @Override + @Nullable + public <T> T getNullable(Settings<T> settings) { + T o = this.settings == null ? null : (T) this.settings.get(settings.getId()); + o = EntrySettingsAdapterRegistry.getInstance().adapt(this, settings, o); + return o; + } + + @Override + public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) { + try { + this.getRenderer().render(this, matrices, bounds, mouseX, mouseY, delta); + } catch (Throwable throwable) { + CrashReport report = CrashReportUtils.essential(throwable, "Rendering entry"); + CrashReportUtils.renderer(report, this); + throw CrashReportUtils.throwReport(report); + } + } + + @Override + @Nullable + public Tooltip getTooltip(TooltipContext context, boolean appendModName) { + try { + Mutable<Tooltip> tooltip = new MutableObject<>(getRenderer().<A>cast().getTooltip(this, context)); + if (tooltip.getValue() == null) return null; + tooltip.getValue().withContextStack(this); + tooltip.getValue().addAllTexts(get(Settings.TOOLTIP_APPEND_EXTRA).apply(this)); + tooltip.setValue(get(Settings.TOOLTIP_PROCESSOR).apply(this, tooltip.getValue())); + if (tooltip.getValue() == null) return null; + String containingNs = getContainingNamespace(); + if (appendModName) { + if (containingNs != null) { + ClientHelper.getInstance().appendModIdToTooltips(tooltip.getValue(), containingNs); + } + } else if (containingNs != null) { + final String modName = ClientHelper.getInstance().getModFromModId(containingNs); + Iterator<Tooltip.Entry> iterator = tooltip.getValue().entries().iterator(); + while (iterator.hasNext()) { + Tooltip.Entry s = iterator.next(); + if (s.isText() && FormattingUtils.stripFormatting(s.getAsText().getString()).equalsIgnoreCase(modName)) { + iterator.remove(); + } + } + } + return tooltip.getValue(); + } catch (Throwable throwable) { + CrashReport report = CrashReportUtils.essential(throwable, "Getting tooltips"); + CrashReportUtils.renderer(report, this); + throw CrashReportUtils.throwReport(report); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof AbstractEntryStack<?> that)) return false; + return EntryStacks.equalsExact(this, that); + } + + @Override + public int hashCode() { + return Long.hashCode(EntryStacks.hashExact(this)); + } + + @Override + public Stream<TagKey<?>> getTagsFor() { + return (Stream<TagKey<?>>) getDefinition().getTagsFor(this, getValue()); + } + + @Override + public Component asFormattedText() { + return getDefinition().asFormattedText(this, getValue(), TooltipContext.of()); + } + + @Override + public Component asFormattedText(TooltipContext context) { + return getDefinition().asFormattedText(this, getValue(), context); + } + + @Override + public void fillCrashReport(CrashReport report, CrashReportCategory category) { + EntryStack.super.fillCrashReport(report, category); + category.setDetail("Entry type", () -> String.valueOf(getType().getId())); + category.setDetail("Is empty", () -> String.valueOf(isEmpty())); + category.setDetail("Entry identifier", () -> String.valueOf(getIdentifier())); + + CrashReportCategory rendererCategory = report.addCategory("Entry Renderer"); + try { + getDefinition().fillCrashReport(report, rendererCategory, this); + } catch (Throwable throwable) { + rendererCategory.setDetailError("Filling Report", throwable); + } + } +} diff --git a/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EmptyEntryStack.java b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EmptyEntryStack.java new file mode 100644 index 000000000..43030eb92 --- /dev/null +++ b/runtime-engine/entry-stacks/src/main/java/me/shedaniel/rei/impl/common/entry/stack/EmptyEntryStack.java @@ -0,0 +1,45 @@ +/* + * This file is licensed under the MIT License, part of Roughly Enough Items. + * Copyright (c) 2018, 2019, 2020, 2021, 2022 shedaniel + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.shedaniel.rei.impl.common.entry.stack; + +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.type.BuiltinEntryTypes; +import me.shedaniel.rei.api.common.entry.type.EntryDefinition; +import net.minecraft.util.Unit; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.Internal +class EmptyEntryStack extends AbstractEntryStack<Unit> { + static final EntryStack<Unit> EMPT |
