1818import com .sk89q .worldedit .bukkit .BukkitAdapter ;
1919import com .sk89q .worldedit .util .formatting .text .TextComponent ;
2020import com .sk89q .worldedit .world .block .BlockType ;
21+ import net .kyori .adventure .text .Component ;
2122import net .kyori .adventure .text .serializer .plain .PlainTextComponentSerializer ;
2223import org .bukkit .Material ;
2324import org .bukkit .NamespacedKey ;
@@ -55,6 +56,7 @@ public abstract class StoredBlockMechanic extends AbstractCraftBookMechanic impl
5556
5657 private final NamespacedKey storedBlockTypeKey = new NamespacedKey ("craftbook" , "toggle_block_type" );
5758 private final NamespacedKey storedBlockQuantityKey = new NamespacedKey ("craftbook" , "toggle_block_quantity" );
59+ protected final static int INFINITE_SENTINEL = Integer .MIN_VALUE ;
5860
5961 public StoredBlockMechanic (MechanicType <? extends CraftBookMechanic > mechanicType ) {
6062 super (mechanicType );
@@ -165,10 +167,10 @@ public void onPipeSuck(PipeSuckEvent event) {
165167 List <ItemStack > items = event .getItems ();
166168 try {
167169 Material base = getOrSetStoredType (event .getSuckedBlock ());
168- int blocks = getStoredBlockCount (sign );
170+ int blocks = getStoredBlockCounts (sign );
169171 if (blocks > 0 ) {
170172 items .add (new ItemStack (base , blocks ));
171- setStoredBlockCount ( sign , 0 );
173+ takeFromStoredBlockCounts ( blocks , sign );
172174 }
173175 event .setItems (items );
174176 } catch (InvalidMechanismException e ) {
@@ -194,9 +196,10 @@ public void onBlockBreak(BlockBreakEvent event) {
194196 }
195197
196198 CraftBookPlayer player = CraftBookPlugin .inst ().wrapPlayer (event .getPlayer ());
197- int amount = getStoredBlockCounts (sign );
199+ int amount = getStoredBlockCount (sign );
198200
199- if (amount > 0 ) {
201+ //noinspection ConstantValue
202+ if (amount > 0 && amount != INFINITE_SENTINEL ) {
200203 try {
201204 Material base = getOrSetStoredType (event .getBlock ());
202205 while (amount > 0 ) {
@@ -248,6 +251,9 @@ public boolean takeFromStoredBlockCounts(int amount, @Nullable Sign... signs) {
248251 continue ;
249252 }
250253 int stored = getStoredBlockCount (sign );
254+ if (stored == INFINITE_SENTINEL ) {
255+ return true ;
256+ }
251257 if (stored >= amount ) {
252258 return setStoredBlockCount (sign , stored - amount );
253259 } else {
@@ -278,6 +284,11 @@ public boolean addToStoredBlockCount(Sign sign, int amount) {
278284 * If `enforce-type` is set, it will only return the amount of blocks of the type stored in the first sign.
279285 * </p>
280286 *
287+ * <p>
288+ * Only use this when getting actual physical blocks, it will not count infinite signs.
289+ * Use {@link #hasRequiredBlockCounts(int, Sign...)} for quantity checks.
290+ * </p>
291+ *
281292 * @param signs The list of signs
282293 * @return The stored block count
283294 */
@@ -292,38 +303,111 @@ public int getStoredBlockCounts(@Nullable Sign... signs) {
292303 int sum = 0 ;
293304 for (Sign sign : signs ) {
294305 if (sign != null && getStoredType (sign ) == type ) {
295- sum += getStoredBlockCount (sign );
306+ int stored = getStoredBlockCount (sign );
307+ if (stored == INFINITE_SENTINEL ) {
308+ // Skip infinite signs in this data.
309+ continue ;
310+ }
311+ sum += stored ;
296312 }
297313 }
298314
299315 return sum ;
300316 }
301317
318+ /**
319+ * Checks whether the given signs contain enough blocks to meet the given count.
320+ *
321+ * @param count The count to check for
322+ * @param signs The list of signs
323+ * @return Whether the signs contain more or equal to count
324+ */
325+ public boolean hasRequiredBlockCounts (int count , @ Nullable Sign ... signs ) {
326+ if (count <= 0 ) {
327+ // Short-circuit if something asks for no blocks for whatever reason.
328+ return true ;
329+ }
330+ if (signs .length == 0 || signs [0 ] == null ) {
331+ return false ;
332+ }
333+
334+ Material type = getStoredType (signs [0 ]);
335+
336+ int sum = 0 ;
337+ for (Sign sign : signs ) {
338+ if (sign != null && getStoredType (sign ) == type ) {
339+ int stored = getStoredBlockCount (sign );
340+ if (stored == INFINITE_SENTINEL ) {
341+ // Infinite means this is always true.
342+ return true ;
343+ }
344+ sum += stored ;
345+ }
346+ }
347+
348+ return count >= sum ;
349+ }
350+
302351 /**
303352 * Gets the number of stored blocks within this sign.
304353 *
354+ * <p>
355+ * This gets the raw data, use {@link #getStoredBlockCounts(Sign...)} instead.
356+ * </p>
357+ *
305358 * @param sign The sign
306359 * @return The stored block count
307360 */
308- public int getStoredBlockCount (Sign sign ) {
361+ private int getStoredBlockCount (Sign sign ) {
309362 if (sign .getPersistentDataContainer ().has (storedBlockQuantityKey , PersistentDataType .INTEGER )) {
310363 //noinspection DataFlowIssue
311364 return sign .getPersistentDataContainer ().get (storedBlockQuantityKey , PersistentDataType .INTEGER );
312365 }
366+ for (Side side : Side .values ()) {
367+ String signLine0 = PlainTextComponentSerializer .plainText ().serialize (sign .getSide (side ).line (0 ));
368+ if (signLine0 .equals ("infinite" )) {
369+ // Persist infinite data to internal data.
370+ sign .getSide (side ).line (0 , Component .text ("" ));
371+ sign .getPersistentDataContainer ().set (storedBlockQuantityKey , PersistentDataType .INTEGER , INFINITE_SENTINEL );
372+ sign .update (false , false );
373+ return INFINITE_SENTINEL ;
374+ }
375+ }
313376 return 0 ;
314377 }
315378
379+ /**
380+ * Gets whether this sign contains infinite blocks.
381+ *
382+ * @param sign The sign to check
383+ * @return Whether it contains infinite blocks
384+ */
385+ private boolean hasInfiniteBlockCount (Sign sign ) {
386+ int count = getStoredBlockCount (sign );
387+ return count == INFINITE_SENTINEL ;
388+ }
389+
316390 /**
317391 * Sets the stored block count within this sign.
318392 *
393+ * <p>
394+ * This sets the raw data, use {@link #takeFromStoredBlockCounts(int, Sign...)} instead.
395+ * </p>
396+ *
319397 * @param sign The sign
320398 * @param count The count
321399 * @return If the count was set
322400 */
323- public boolean setStoredBlockCount (Sign sign , int count ) {
401+ private boolean setStoredBlockCount (Sign sign , int count ) {
324402 if (count < 0 ) {
325403 return false ;
326404 }
405+
406+ if (hasInfiniteBlockCount (sign )) {
407+ // Don't modify the count if it's infinite, to avoid accidentally making it finite.
408+ return true ;
409+ }
410+
327411 sign .getPersistentDataContainer ().set (storedBlockQuantityKey , PersistentDataType .INTEGER , count );
328412 return true ;
329413 }
0 commit comments