001/* 002 * This file is part of Baritone. 003 * 004 * Baritone is free software: you can redistribute it and/or modify 005 * it under the terms of the GNU Lesser General Public License as published by 006 * the Free Software Foundation, either version 3 of the License, or 007 * (at your option) any later version. 008 * 009 * Baritone is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License 015 * along with Baritone. If not, see <https://www.gnu.org/licenses/>. 016 */ 017 018package baritone.api.command.registry; 019 020import java.util.*; 021import java.util.function.Consumer; 022import java.util.stream.Stream; 023import java.util.stream.StreamSupport; 024 025/** 026 * This registry class allows for registration and unregistration of a certain type. This is mainly designed for use by 027 * event handlers where newly registered ones are encountered first during iteration and can therefore override older 028 * ones. In Baritone, this is used for commands and argument parsers so that mods and addons can extend Baritone's 029 * functionality without resorting to hacks, wrappers, or mixins. 030 * 031 * @param <V> The entry type that will be stored in this registry. This can be anything, really - preferably anything 032 * that works as a HashMap key, as that's what's used to keep track of which entries are registered or not. 033 */ 034public class Registry<V> { 035 036 /** 037 * An internal linked list of all the entries that are currently registered. This is a linked list so that entries 038 * can be inserted at the beginning, which means that newer entries are encountered first during iteration. This is 039 * an important property of the registry that makes it more useful than a simple list, and also the reason it does 040 * not just use a map. 041 */ 042 private final Deque<V> _entries = new LinkedList<>(); 043 /** 044 * A HashSet containing every entry currently registered. Entries are added to this set when something is registered 045 * and removed from the set when they are unregistered. An entry being present in this set indicates that it is 046 * currently registered, can be removed, and should not be reregistered until it is removed. 047 */ 048 private final Set<V> registered = new HashSet<>(); 049 /** 050 * The collection of entries that are currently in this registry. This is a collection (and not a list) because, 051 * internally, entries are stored in a linked list, which is not the same as a normal list. 052 */ 053 public final Collection<V> entries = Collections.unmodifiableCollection(_entries); 054 055 /** 056 * @param entry The entry to check. 057 * @return If this entry is currently registered in this registry. 058 */ 059 public boolean registered(V entry) { 060 return registered.contains(entry); 061 } 062 063 /** 064 * Ensures that the entry {@code entry} is registered. 065 * 066 * @param entry The entry to register. 067 * @return A boolean indicating whether or not this is a new registration. No matter the value of this boolean, the 068 * entry is always guaranteed to now be in this registry. This boolean simply indicates if the entry was <i>not</i> 069 * in the map prior to this method call. 070 */ 071 public boolean register(V entry) { 072 if (!registered(entry)) { 073 _entries.addFirst(entry); 074 registered.add(entry); 075 return true; 076 } 077 return false; 078 } 079 080 /** 081 * Unregisters this entry from this registry. After this method call, the entry is guaranteed to be removed from the 082 * registry, since each entry only ever appears once. 083 * 084 * @param entry The entry to unregister. 085 */ 086 public void unregister(V entry) { 087 if (registered(entry)) { 088 return; 089 } 090 _entries.remove(entry); 091 registered.remove(entry); 092 } 093 094 /** 095 * Returns an iterator that iterates over each entry in this registry, with the newest elements iterated over first. 096 * Internally, as new elements are prepended to the registry rather than appended to the end, this order is the best 097 * way to search through the registry if you want to discover newer items first. 098 */ 099 public Iterator<V> iterator() { 100 return _entries.iterator(); 101 } 102 103 /** 104 * Returns an iterator that iterates over each entry in this registry, in the order they were added. Internally, 105 * this iterates through the registry backwards, as new elements are prepended to the registry rather than appended 106 * to the end. You should only do this when you need to, for example, list elements in order - it is almost always 107 * fine to simply use {@link Iterable#forEach(Consumer) forEach} on the {@link #entries} collection instead. 108 */ 109 public Iterator<V> descendingIterator() { 110 return _entries.descendingIterator(); 111 } 112 113 /** 114 * Returns a stream that contains each entry in this registry, with the newest elements ordered first. Internally, 115 * as new elements are prepended to the registry rather than appended to the end, this order is the best way to 116 * search through the registry if you want to discover newer items first. 117 */ 118 public Stream<V> stream() { 119 return _entries.stream(); 120 } 121 122 /** 123 * Returns a stream that returns each entry in this registry, in the order they were added. Internally, this orders 124 * the registry backwards, as new elements are prepended to the registry rather than appended to the end. You should 125 * only use this when you need to, for example, list elements in order - it is almost always fine to simply use the 126 * regular {@link #stream()} method instead. 127 */ 128 public Stream<V> descendingStream() { 129 return StreamSupport.stream(Spliterators.spliterator( 130 descendingIterator(), 131 _entries.size(), 132 Spliterator.SIZED | Spliterator.SUBSIZED 133 ), false); 134 } 135}