From 05069aa62b09f02a8cd6e526ec58a30347a56500 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Wed, 27 Jul 2022 23:25:27 +0800 Subject: WIP Module --- .../impl/client/entry/type/EntryRegistryImpl.java | 276 +++++++++++++++++++++ .../impl/client/entry/type/EntryRegistryList.java | 62 +++++ .../client/entry/type/EntryRegistryListener.java | 47 ++++ .../client/entry/type/EntryTypeRegistryImpl.java | 102 ++++++++ .../client/entry/type/NormalEntryRegistryList.java | 117 +++++++++ .../entry/type/ReloadingEntryRegistryList.java | 109 ++++++++ .../collapsed/CollapsibleEntryRegistryImpl.java | 149 +++++++++++ ...iel.rei.api.client.registry.entry.EntryRegistry | 1 + 8 files changed, 863 insertions(+) create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java create mode 100644 runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java create mode 100644 runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry (limited to 'runtime-engine/entries/src') diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java new file mode 100644 index 000000000..be1ed5225 --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryImpl.java @@ -0,0 +1,276 @@ +/* + * 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.client.entry.type; + +import com.google.common.collect.Lists; +import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.longs.LongList; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; +import me.shedaniel.rei.api.client.REIRuntime; +import me.shedaniel.rei.api.client.overlay.ScreenOverlay; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext; +import me.shedaniel.rei.api.common.entry.type.EntryDefinition; +import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.Internals; +import me.shedaniel.rei.impl.common.InternalLogger; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.LongPredicate; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@ApiStatus.Internal +@Environment(EnvType.CLIENT) +public class EntryRegistryImpl implements EntryRegistry { + private final List listeners = Lists.newCopyOnWriteArrayList(); + private EntryRegistryList registryList; + private LongSet entriesHash; + private boolean reloading; + + public EntryRegistryImpl() { + registryList = new NormalEntryRegistryList(); + entriesHash = new LongOpenHashSet(); + listeners.addAll(Internals.resolveServices(EntryRegistryListener.class)); + } + + @Override + public void acceptPlugin(REIClientPlugin plugin) { + plugin.registerEntries(this); + } + + @Override + public ReloadStage getStage() { + return ReloadStage.START; + } + + @Override + public void startReload() { + registryList = new ReloadingEntryRegistryList(); + entriesHash = new LongOpenHashSet(); + reloading = true; + } + + @Override + public void endReload() { + reloading = false; + if (!(registryList instanceof ReloadingEntryRegistryList)) { + throw new IllegalStateException("Expected ReloadingEntryRegistryList, got " + registryList.getClass().getName()); + } + registryList = new NormalEntryRegistryList(registryList.stream().filter(((Predicate>) EntryStack::isEmpty).negate())); + refilter(); + REIRuntime.getInstance().getOverlay().ifPresent(ScreenOverlay::queueReloadOverlay); + InternalLogger.getInstance().debug("Reloaded entry registry with %d entries and %d filtered entries", size(), getPreFilteredList().size()); + } + + @Override + public boolean isReloading() { + return reloading; + } + + @Override + public int size() { + return registryList.size(); + } + + @Override + public Stream> getEntryStacks() { + return registryList.stream(); + } + + @Override + public void refilter() { + List> stacks = registryList.collect(); + + for (EntryRegistryListener listener : listeners) { + listener.onReFilter(stacks); + } + } + + private static final Comparator STACK_COMPARATOR = (a, b) -> ItemStack.matches(a, b) ? 0 : 1; + + @Override + public List appendStacksForItem(Item item) { + NonNullList list = NonNullList.create(); + LongSet set = new LongOpenHashSet(); + EntryDefinition itemDefinition = VanillaEntryTypes.ITEM.getDefinition(); + for (CreativeModeTab tab : CreativeModeTab.TABS) { + if (tab != CreativeModeTab.TAB_HOTBAR && tab != CreativeModeTab.TAB_INVENTORY) { + NonNullList tabList = NonNullList.create(); + item.fillItemCategory(tab, tabList); + for (ItemStack stack : tabList) { + if (set.add(itemDefinition.hash(null, stack, ComparisonContext.EXACT))) { + list.add(stack); + } + } + } + } + if (list.isEmpty()) { + return Collections.singletonList(item.getDefaultInstance()); + } + if (list.size() > 1) { + list.sort(STACK_COMPARATOR); + } + return list; + } + + @Override + public boolean alreadyContain(EntryStack stack) { + return entriesHash.contains(EntryStacks.hashExact(stack)); + } + + @Override + public void addEntryAfter(@Nullable EntryStack afterEntry, EntryStack stack) { + long hashExact = EntryStacks.hashExact(stack); + if (this.entriesHash.add(hashExact)) { + if (afterEntry != null) { + int index = registryList.lastIndexOf(afterEntry); + registryList.add(index, stack, hashExact); + } else registryList.add(stack, hashExact); + + for (EntryRegistryListener listener : listeners) { + listener.addEntryAfter(afterEntry, stack, hashExact); + } + } + } + + @Override + public void addEntriesAfter(@Nullable EntryStack afterEntry, Collection> stacks) { + List> filtered; + LongList hashes = registryList.needsHash() ? new LongArrayList(stacks.size()) : null; + + if (registryList.needsHash()) { + filtered = new ArrayList<>(stacks.size()); + for (EntryStack stack : stacks) { + long hashExact = EntryStacks.hashExact(stack); + if (entriesHash.add(hashExact)) { + filtered.add(stack); + hashes.add(hashExact); + } + } + } else { + filtered = CollectionUtils.filterToList((List>) stacks, entry -> entriesHash.add(EntryStacks.hashExact(entry))); + } + + if (afterEntry != null) { + int index = registryList.lastIndexOf(afterEntry); + registryList.addAll(index, filtered, hashes); + } else registryList.addAll(filtered, hashes); + + for (EntryRegistryListener listener : listeners) { + listener.addEntriesAfter(afterEntry, filtered, hashes); + } + } + + @Override + public boolean removeEntry(EntryStack stack) { + long hashExact = EntryStacks.hashExact(stack); + registryList.remove(stack, hashExact); + boolean removed = entriesHash.remove(hashExact); + + if (removed) { + for (EntryRegistryListener listener : listeners) { + listener.removeEntry(stack, hashExact); + } + } + + return removed; + } + + @Override + public boolean removeEntryIf(Predicate> predicate) { + List> removedStacks = new ArrayList<>(); + LongList hashes = registryList.needsHash() ? new LongArrayList() : null; + + boolean removed = registryList.removeIf(stack -> { + if (((Predicate>) predicate).test(stack)) { + long hashExact = EntryStacks.hashExact(stack); + entriesHash.remove(hashExact); + removedStacks.add(stack); + if (hashes != null) hashes.add(hashExact); + return true; + } + + return false; + }); + + if (removed) { + for (EntryRegistryListener listener : listeners) { + listener.removeEntries(removedStacks, hashes); + } + } + + return removed; + } + + @Override + public boolean removeEntryExactHashIf(LongPredicate predicate) { + LongPredicate entryStackPredicate = hash -> { + if (predicate.test(hash)) { + entriesHash.remove(hash); + return true; + } + + return false; + }; + + for (EntryRegistryListener listener : listeners) { + listener.removeEntriesIf(stack -> predicate.test(EntryStacks.hashExact(stack))); + } + + return registryList.removeExactIf(entryStackPredicate); + } + + @Override + public boolean removeEntryFuzzyHashIf(LongPredicate predicate) { + Predicate> entryStackPredicate = stack -> { + if (predicate.test(EntryStacks.hashFuzzy(stack))) { + entriesHash.remove(EntryStacks.hashExact(stack)); + return true; + } + + return false; + }; + + for (EntryRegistryListener listener : listeners) { + listener.removeEntriesIf(entryStackPredicate); + } + + return registryList.removeIf(entryStackPredicate); + } +} diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java new file mode 100644 index 000000000..401bf61a9 --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryList.java @@ -0,0 +1,62 @@ +/* + * 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.client.entry.type; + +import it.unimi.dsi.fastutil.longs.LongList; +import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.ApiStatus; + +import java.util.List; +import java.util.function.LongPredicate; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@ApiStatus.Internal +public interface EntryRegistryList { + int size(); + + Stream> stream(); + + List> collect(); + + int indexOf(EntryStack stack); + + int lastIndexOf(EntryStack stack); + + void add(EntryStack stack, long hashExact); + + void add(int index, EntryStack stack, long hashExact); + + void addAll(List> stacks, LongList hashes); + + void addAll(int index, List> stacks, LongList hashes); + + void remove(EntryStack stack, long hashExact); + + boolean removeIf(Predicate> predicate); + + boolean removeExactIf(LongPredicate predicate); + + boolean needsHash(); +} diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java new file mode 100644 index 000000000..b1c59e0e7 --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryRegistryListener.java @@ -0,0 +1,47 @@ +/* + * 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.client.entry.type; + +import it.unimi.dsi.fastutil.longs.LongList; +import me.shedaniel.rei.api.common.entry.EntryStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.function.Predicate; + +@ApiStatus.Internal +public interface EntryRegistryListener { + default void addEntryAfter(@Nullable EntryStack afterEntry, EntryStack stack, long stackHashExact) {} + + default void addEntriesAfter(@Nullable EntryStack afterEntry, List> stacks, @Nullable LongList hashes) {} + + default void removeEntry(EntryStack stack, long hashExact) {} + + default void removeEntries(List> stacks, @Nullable LongList hashes) {} + + default void removeEntriesIf(Predicate> predicate) {} + + default void onReFilter(List> stacks) {} +} diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java new file mode 100644 index 000000000..ad5a6261d --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/EntryTypeRegistryImpl.java @@ -0,0 +1,102 @@ +/* + * 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.client.entry.type; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.Table; +import me.shedaniel.rei.api.common.entry.type.EntryDefinition; +import me.shedaniel.rei.api.common.entry.type.EntryType; +import me.shedaniel.rei.api.common.entry.type.EntryTypeBridge; +import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry; +import me.shedaniel.rei.api.common.plugins.REIPlugin; +import me.shedaniel.rei.api.common.registry.ReloadStage; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +@ApiStatus.Internal +public class EntryTypeRegistryImpl implements EntryTypeRegistry { + private final BiMap> entryTypes = HashBiMap.create(); + private final Table>> typeBridges = HashBasedTable.create(); + + @Override + public ReloadStage getStage() { + return ReloadStage.START; + } + + @Override + public void acceptPlugin(REIPlugin plugin) { + plugin.registerEntryTypes(this); + } + + @Override + public void register(ResourceLocation id, EntryDefinition definition) { + this.entryTypes.put(id, definition); + } + + @Override + public void registerBridge(EntryType original, EntryType destination, EntryTypeBridge bridge) { + List> list = this.typeBridges.get(original.getId(), destination.getId()); + if (list == null) { + this.typeBridges.put(original.getId(), destination.getId(), list = new ArrayList<>()); + } + list.add(bridge); + } + + @Override + public EntryDefinition get(ResourceLocation id) { + return this.entryTypes.get(id); + } + + @Override + public Set keySet() { + return this.entryTypes.keySet(); + } + + @Override + public Set> values() { + return this.entryTypes.values(); + } + + @Override + public Iterable> getBridgesFor(EntryType original, EntryType destination) { + List> list = this.typeBridges.get(original.getId(), destination.getId()); + if (list == null) { + return Collections.emptyList(); + } + return (Iterable>) list; + } + + @Override + public void startReload() { + entryTypes.clear(); + typeBridges.clear(); + } +} diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java new file mode 100644 index 000000000..73f378c0f --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/NormalEntryRegistryList.java @@ -0,0 +1,117 @@ +/* + * 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.client.entry.type; + +import it.unimi.dsi.fastutil.longs.LongList; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.LongPredicate; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@ApiStatus.Internal +public class NormalEntryRegistryList implements EntryRegistryList { + private List> list = new ArrayList<>(); + + public NormalEntryRegistryList() { + } + + public NormalEntryRegistryList(Stream> list) { + list.collect(Collectors.toCollection(() -> this.list)); + } + + @Override + public int size() { + return list.size(); + } + + @Override + public Stream> stream() { + return list.stream(); + } + + @Override + public List> collect() { + return list; + } + + @Override + public int indexOf(EntryStack stack) { + return list.indexOf(stack); + } + + @Override + public int lastIndexOf(EntryStack stack) { + return list.lastIndexOf(stack); + } + + @Override + public void add(EntryStack stack, long hashExact) { + list.add(stack); + } + + @Override + public void add(int index, EntryStack stack, long hashExact) { + list.add(index, stack); + } + + @Override + public void addAll(List> stacks, LongList hashes) { + list.addAll(stacks); + } + + @Override + public void addAll(int index, List> stacks, LongList hashes) { + list.addAll(index, stacks); + } + + @Override + public void remove(EntryStack stack, long hashExact) { + list.remove(stack); + } + + @Override + public boolean removeIf(Predicate> predicate) { + return list.removeIf((Predicate>) predicate); + } + + @Override + public boolean removeExactIf(LongPredicate predicate) { + return list.removeIf(stack -> predicate.test(EntryStacks.hashExact(stack))); + } + + @Override + public boolean needsHash() { + return false; + } + + public List> getList() { + return list; + } +} diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java new file mode 100644 index 000000000..53f21406b --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/ReloadingEntryRegistryList.java @@ -0,0 +1,109 @@ +/* + * 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.client.entry.type; + +import it.unimi.dsi.fastutil.longs.LongList; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.CollectionUtils; +import me.shedaniel.rei.impl.common.util.HashedEntryStackWrapper; +import net.minecraft.core.Registry; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.LongPredicate; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@ApiStatus.Internal +public class ReloadingEntryRegistryList implements EntryRegistryList { + private List list = new ArrayList<>(Registry.ITEM.keySet().size() + 100); + + @Override + public int size() { + return list.size(); + } + + @Override + public Stream> stream() { + return list.stream().map(HashedEntryStackWrapper::unwrap); + } + + @Override + public List> collect() { + return CollectionUtils.map(list, HashedEntryStackWrapper::unwrap); + } + + @Override + public int indexOf(EntryStack stack) { + return list.indexOf(new HashedEntryStackWrapper(stack)); + } + + @Override + public int lastIndexOf(EntryStack stack) { + return list.lastIndexOf(new HashedEntryStackWrapper(stack)); + } + + @Override + public void add(EntryStack stack, long hashExact) { + list.add(new HashedEntryStackWrapper(stack, hashExact)); + } + + @Override + public void add(int index, EntryStack stack, long hashExact) { + list.add(index, new HashedEntryStackWrapper(stack, hashExact)); + } + + @Override + public void addAll(List> stacks, LongList hashes) { + List wrappers = CollectionUtils.mapIndexed(stacks, (i, stack) -> new HashedEntryStackWrapper(stack, hashes.getLong(i))); + list.addAll(wrappers); + } + + @Override + public void addAll(int index, List> stacks, LongList hashes) { + List wrappers = CollectionUtils.mapIndexed(stacks, (i, stack) -> new HashedEntryStackWrapper(stack, hashes.getLong(i))); + list.addAll(index, wrappers); + } + + @Override + public void remove(EntryStack stack, long hashExact) { + list.remove(new HashedEntryStackWrapper(stack, hashExact)); + } + + @Override + public boolean removeIf(Predicate> predicate) { + return list.removeIf(wrapper -> ((Predicate>) predicate).test(wrapper.unwrap())); + } + + @Override + public boolean removeExactIf(LongPredicate predicate) { + return list.removeIf(wrapper -> predicate.test(wrapper.hashExact())); + } + + @Override + public boolean needsHash() { + return true; + } +} diff --git a/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java new file mode 100644 index 000000000..f5222f864 --- /dev/null +++ b/runtime-engine/entries/src/main/java/me/shedaniel/rei/impl/client/entry/type/collapsed/CollapsibleEntryRegistryImpl.java @@ -0,0 +1,149 @@ +/* + * 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.client.entry.type.collapsed; + +import com.google.common.collect.ForwardingList; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntry; +import me.shedaniel.rei.api.client.registry.entry.CollapsibleEntryRegistry; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import me.shedaniel.rei.impl.common.InternalLogger; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import org.jetbrains.annotations.ApiStatus; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +@ApiStatus.Internal +public class CollapsibleEntryRegistryImpl extends ForwardingList implements CollapsibleEntryRegistry { + private final List entries = new ArrayList<>(); + + @Override + public void group(ResourceLocation id, Component name, List> stacks) { + Objects.requireNonNull(stacks, "stacks"); + this.entries.add(new Entry(id, name, new ListMatcher(stacks))); + InternalLogger.getInstance().debug("Added collapsible entry group [%s] %s with %d entries", id, name.getString(), stacks.size()); + } + + @Override + public void group(ResourceLocation id, Component name, Predicate> predicate) { + Objects.requireNonNull(predicate, "predicate"); + this.entries.add(new Entry(id, name, (stack, hashExact) -> ((Predicate>) predicate).test(stack))); + InternalLogger.getInstance().debug("Added collapsible entry group [%s] %s with dynamic predicate", id, name.getString()); + } + + @Override + public void startReload() { + this.entries.clear(); + } + + @Override + public void endReload() { + InternalLogger.getInstance().debug("Registered %d collapsible entry groups: ", entries.size(), + entries.stream().map(entry -> entry.getName().getString()).collect(Collectors.joining(", "))); + } + + @Override + public void acceptPlugin(REIClientPlugin plugin) { + plugin.registerCollapsibleEntries(this); + } + + @Override + protected List delegate() { + return (List) (List) Collections.unmodifiableList(this.entries); + } + + public static class Entry implements CollapsibleEntry { + private final ResourceLocation id; + private final Component name; + private final Matcher matcher; + private boolean expanded; + + public Entry(ResourceLocation id, Component name, Matcher matcher) { + this.id = id; + this.name = name; + this.matcher = matcher; + } + + @Override + public ResourceLocation getId() { + return id; + } + + @Override + public Component getName() { + return name; + } + + @Override + public boolean matches(EntryStack stack, long hashExact) { + return matcher.matches(stack, hashExact); + } + + @Override + public boolean isExpanded() { + return expanded; + } + + @Override + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } + } + + + @FunctionalInterface + public interface Matcher { + boolean matches(EntryStack stack, long hashExact); + } + + private static class ListMatcher implements Matcher { + private final Long2ObjectMap> stacks; + + public ListMatcher(List> stacks) { + this.stacks = new Long2ObjectOpenHashMap<>(stacks.size() + 1); + for (EntryStack stack : stacks) { + this.stacks.put(EntryStacks.hashExact(stack), stack); + } + } + + @Override + public boolean matches(EntryStack stack, long hashExact) { + EntryStack entryStack = stacks.get(hashExact); + + if (entryStack == null) + return false; + + return EntryStacks.equalsExact(entryStack, stack); + } + } +} diff --git a/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry new file mode 100644 index 000000000..e199e1429 --- /dev/null +++ b/runtime-engine/entries/src/main/resources/META-INF/services/me.shedaniel.rei.api.client.registry.entry.EntryRegistry @@ -0,0 +1 @@ +me.shedaniel.rei.impl.client.entry.type.EntryRegistryImpl \ No newline at end of file -- cgit