/* * Copyright (C) 2024 Minecon724 * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file * in the project root for the full license text. */ package eu.m724.tweaks.redstone; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import eu.m724.tweaks.Language; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.block.data.AnaloguePowerable; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.Plugin; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; public class RedstoneRepeaters { private final Plugin plugin; private final NamespacedKey repeaterKey; private final BiMap repeatersById = HashBiMap.create(); private final Map repeatersByPower = new HashMap<>(); public RedstoneRepeaters(Plugin plugin) { this.plugin = plugin; this.repeaterKey = new NamespacedKey(plugin, "repeater"); } /* Item functions */ public ItemStack give() { var itemStack = new ItemStack(Material.DAYLIGHT_DETECTOR); var meta = itemStack.getItemMeta(); meta.setItemName(Language.getString("retstoneBlockItem")); meta.getPersistentDataContainer().set(repeaterKey, PersistentDataType.BOOLEAN, true); meta.setEnchantmentGlintOverride(true); itemStack.setItemMeta(meta); return itemStack; } public boolean isRepeater(ItemStack itemStack) { var meta = itemStack.getItemMeta(); if (meta == null) return false; var value = meta.getPersistentDataContainer().get(repeaterKey, PersistentDataType.BOOLEAN); return value != null; } /* Event */ int onPlace(Block block) { var repeaterId = ThreadLocalRandom.current().nextInt() & 0x7FFFFFF0; repeatersById.put(repeaterId, block.getLocation()); block.setMetadata("rid", new FixedMetadataValue(plugin, repeaterId)); Store.getInstance().saveRepeaterData(block.getLocation(), repeaterId, (byte) 0); return repeaterId; } void onBreak(int repeaterId) { delete(repeaterId); } void delete(int repeaterId) { var location = repeatersById.remove(repeaterId); if (location == null) return; repeatersByPower.remove(repeaterId); Store.getInstance().deleteSavedRepeaterData(location); } /* Get functions */ private boolean isValid(int repeaterId) { // check if there's a repeater with such ID stored // if not, we're not loading because it's loaded as the block is var loc = repeatersById.get(repeaterId); if (loc == null) { System.err.println("Delete because no loc"); delete(repeaterId); return false; } // check if chunk the block is in is loaded // you may think it could be simplified, but it can't without loading the chunk (to check if it's loaded) var isLoaded = loc.getWorld().isChunkLoaded(loc.getBlockX() / 16, loc.getBlockZ() / 16); if (!isLoaded) return false; // check if the block is correct type if (loc.getBlock().getType() != Material.DAYLIGHT_DETECTOR) { delete(repeaterId); return false; } // check if the block has the same ID bound var meta = loc.getBlock().getMetadata("rid"); if (meta.isEmpty() || meta.getFirst().asInt() != repeaterId) { System.err.println("Delete because no meta"); delete(repeaterId); return false; } return true; } public int getId(Block block) { if (block.hasMetadata("rid")) { var id = block.getMetadata("rid").getFirst().asInt(); return id; } var id = repeatersById.inverse().get(block.getLocation()); if (id == null) { // not in memory, check if repeater var d = Store.getInstance().getSavedRepeaterData(block.getLocation()); if (d == null) { block.setMetadata("rid", new FixedMetadataValue(plugin, Integer.MIN_VALUE)); return Integer.MIN_VALUE; } id = d.getKey(); block.setMetadata("rid", new FixedMetadataValue(plugin, id)); repeatersById.put(id, block.getLocation()); repeatersByPower.put(id, d.getValue()); } if (!isValid(id)) return Integer.MIN_VALUE; return id; } Block getBlock(int repeaterId) { var location = repeatersById.get(repeaterId); if (location == null) return null; if (!isValid(repeaterId)) return null; var storedId = location.getBlock().getMetadata("rid").getFirst().asInt(); if (storedId != repeaterId) { System.out.println("retrieved but not exitt"); delete(repeaterId); return null; } System.out.println("retrieved exist " + repeaterId); return location.getBlock(); } /* Control functions */ byte getInboundPower(int repeaterId) { var block = getBlock(repeaterId); if (block == null) return -1; block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3); System.out.println("Okay I got in power" + block.getBlockPower()); return (byte) block.getBlockPower(); } byte getOutboundPower(int repeaterId) { var block = getBlock(repeaterId); if (block == null) return -1; System.out.println("Okay I got out power" + repeatersByPower.get(repeaterId)); return repeatersByPower.getOrDefault(repeaterId, (byte) 0); } void setPower(int repeaterId, byte power) { System.out.println(power); if (power < 0 || power > 15) throw new IllegalArgumentException("Power should be 0-15, but is " + power); var block = getBlock(repeaterId); if (block == null) return; var data = (AnaloguePowerable) block.getBlockData(); repeatersByPower.put(repeaterId, power); data.setPower(power); block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3); System.out.println("Okay I set power"); } }