Rename to gateway, add crafting, some other changes
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				/ build (push) Has been cancelled
				
			
		
		
	
	
		
	
		
			Some checks failed
		
		
	
	/ build (push) Has been cancelled
				
			This commit is contained in:
		
					parent
					
						
							
								225adf0354
							
						
					
				
			
			
				commit
				
					
						c0b85870e0
					
				
			
		
					 12 changed files with 152 additions and 95 deletions
				
			
		| 
						 | 
				
			
			@ -82,7 +82,11 @@ Issue messages that the player needs to read to keep playing, and that make an a
 | 
			
		|||
`/emergencyalerts` (`tweaks724.emergencyalerts`)
 | 
			
		||||
 | 
			
		||||
### Remote redstone
 | 
			
		||||
Control redstone remotely
 | 
			
		||||
Adds a "gateway" item that are controlled over internet. \
 | 
			
		||||
[RETSTONE.md for more info](/Minecon724/tweaks724/src/branch/master/RETSTONE.md)
 | 
			
		||||
 | 
			
		||||
### Knockback
 | 
			
		||||
Control knockback dealt by entities
 | 
			
		||||
 | 
			
		||||
### Utility commands
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										17
									
								
								RETSTONE.md
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								RETSTONE.md
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -3,8 +3,21 @@
 | 
			
		|||
See [retstone.py](retstone.py) for usage example
 | 
			
		||||
 | 
			
		||||
### Glossary
 | 
			
		||||
repeaters - the blocks which allow to interact with redstone over internet \
 | 
			
		||||
packet - a bunch of bytes sent over the internet, that do something with a single repeater
 | 
			
		||||
gateways - the blocks (daylight detector) that read or emit redstone with a specified power, controlled with UDP packets \
 | 
			
		||||
packet - a bunch of bytes sent over the internet, that do something with a specified gateway
 | 
			
		||||
 | 
			
		||||
### Crafting
 | 
			
		||||
 | 
			
		||||
To craft a gateway, combine:
 | 
			
		||||
- nether star
 | 
			
		||||
- ender chest
 | 
			
		||||
- chorus flower
 | 
			
		||||
- daylight detector
 | 
			
		||||
 | 
			
		||||
### Usage
 | 
			
		||||
Each gateway has an ID assigned. To view it, shift right-click a gateway.
 | 
			
		||||
 | 
			
		||||
To destroy a gateway, use silk touch.
 | 
			
		||||
 | 
			
		||||
### How it works
 | 
			
		||||
A packet is int / 4 bytes / 32 bits
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								src/main/java/eu/m724/tweaks/redstone/GatewayItem.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/main/java/eu/m724/tweaks/redstone/GatewayItem.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 eu.m724.tweaks.Language;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.NamespacedKey;
 | 
			
		||||
import org.bukkit.inventory.ItemStack;
 | 
			
		||||
import org.bukkit.inventory.ShapelessRecipe;
 | 
			
		||||
import org.bukkit.persistence.PersistentDataType;
 | 
			
		||||
import org.bukkit.plugin.Plugin;
 | 
			
		||||
 | 
			
		||||
public class GatewayItem {
 | 
			
		||||
    private final NamespacedKey gatewayKey;
 | 
			
		||||
 | 
			
		||||
    public GatewayItem(Plugin plugin) {
 | 
			
		||||
        this.gatewayKey = new NamespacedKey(plugin, "gateway");
 | 
			
		||||
 | 
			
		||||
        var recipe = new ShapelessRecipe(gatewayKey, itemStack());
 | 
			
		||||
        recipe.addIngredient(Material.NETHER_STAR);
 | 
			
		||||
        recipe.addIngredient(Material.ENDER_CHEST);
 | 
			
		||||
        recipe.addIngredient(Material.CHORUS_FLOWER);
 | 
			
		||||
        recipe.addIngredient(Material.DAYLIGHT_DETECTOR);
 | 
			
		||||
        plugin.getServer().addRecipe(recipe);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ItemStack itemStack() {
 | 
			
		||||
        var itemStack = new ItemStack(Material.DAYLIGHT_DETECTOR);
 | 
			
		||||
        var meta = itemStack.getItemMeta();
 | 
			
		||||
 | 
			
		||||
        meta.setItemName(Language.getString("redstoneGatewayItem"));
 | 
			
		||||
        meta.getPersistentDataContainer().set(gatewayKey, PersistentDataType.BOOLEAN, true);
 | 
			
		||||
        meta.setEnchantmentGlintOverride(true);
 | 
			
		||||
 | 
			
		||||
        itemStack.setItemMeta(meta);
 | 
			
		||||
        return itemStack;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isGateway(ItemStack itemStack) {
 | 
			
		||||
        var meta = itemStack.getItemMeta();
 | 
			
		||||
        if (meta == null) return false;
 | 
			
		||||
        var value = meta.getPersistentDataContainer().get(gatewayKey, PersistentDataType.BOOLEAN);
 | 
			
		||||
 | 
			
		||||
        return value != null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -14,10 +14,10 @@ import org.bukkit.entity.Player;
 | 
			
		|||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
public class RedstoneCommands implements CommandExecutor {
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
    private final GatewayItem gatewayItem;
 | 
			
		||||
 | 
			
		||||
    public RedstoneCommands(RedstoneRepeaters redstoneRepeaters) {
 | 
			
		||||
        this.redstoneRepeaters = redstoneRepeaters;
 | 
			
		||||
    public RedstoneCommands(GatewayItem gatewayItem) {
 | 
			
		||||
        this.gatewayItem = gatewayItem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -41,8 +41,9 @@ public class RedstoneCommands implements CommandExecutor {
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var itemStack = redstoneRepeaters.give();
 | 
			
		||||
                var itemStack = gatewayItem.itemStack();
 | 
			
		||||
                player.getInventory().addItem(itemStack);
 | 
			
		||||
                sender.sendMessage("Given to " + player.getName());
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            sender.sendMessage("Argument needed");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,53 +9,26 @@ package eu.m724.tweaks.redstone;
 | 
			
		|||
import com.google.common.collect.BiMap;
 | 
			
		||||
import com.google.common.collect.HashBiMap;
 | 
			
		||||
import eu.m724.tweaks.DebugLogger;
 | 
			
		||||
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 {
 | 
			
		||||
public class RedstoneGateways {
 | 
			
		||||
    private final Plugin plugin;
 | 
			
		||||
    private final NamespacedKey repeaterKey;
 | 
			
		||||
 | 
			
		||||
    private final BiMap<Integer, Location> repeatersById = HashBiMap.create();
 | 
			
		||||
    private final Map<Integer, Byte> repeatersByPower = new HashMap<>();
 | 
			
		||||
    private final BiMap<Integer, Location> gatewaysById = HashBiMap.create();
 | 
			
		||||
    private final Map<Integer, Byte> gatewaysByPower = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    public RedstoneRepeaters(Plugin plugin) {
 | 
			
		||||
    public RedstoneGateways(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 */
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +36,7 @@ public class RedstoneRepeaters {
 | 
			
		|||
    int onPlace(Block block) {
 | 
			
		||||
        var repeaterId = ThreadLocalRandom.current().nextInt() & 0x7FFFFFF0;
 | 
			
		||||
 | 
			
		||||
        repeatersById.put(repeaterId, block.getLocation());
 | 
			
		||||
        gatewaysById.put(repeaterId, block.getLocation());
 | 
			
		||||
        block.setMetadata("rid", new FixedMetadataValue(plugin, repeaterId));
 | 
			
		||||
 | 
			
		||||
        RedstoneStore.getInstance().saveRepeaterData(block.getLocation(), repeaterId, (byte) 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -76,9 +49,9 @@ public class RedstoneRepeaters {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void delete(int repeaterId) {
 | 
			
		||||
        var location = repeatersById.remove(repeaterId);
 | 
			
		||||
        var location = gatewaysById.remove(repeaterId);
 | 
			
		||||
        if (location == null) return;
 | 
			
		||||
        repeatersByPower.remove(repeaterId);
 | 
			
		||||
        gatewaysByPower.remove(repeaterId);
 | 
			
		||||
 | 
			
		||||
        RedstoneStore.getInstance().deleteSavedRepeaterData(location);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +61,7 @@ public class RedstoneRepeaters {
 | 
			
		|||
    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);
 | 
			
		||||
        var loc = gatewaysById.get(repeaterId);
 | 
			
		||||
        if (loc == null) {
 | 
			
		||||
            DebugLogger.fine("isValid: Delete because no loc");
 | 
			
		||||
            delete(repeaterId);
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +97,7 @@ public class RedstoneRepeaters {
 | 
			
		|||
            return id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var id = repeatersById.inverse().get(block.getLocation());
 | 
			
		||||
        var id = gatewaysById.inverse().get(block.getLocation());
 | 
			
		||||
 | 
			
		||||
        if (id == null) {
 | 
			
		||||
            // not in memory, check if repeater
 | 
			
		||||
| 
						 | 
				
			
			@ -138,8 +111,8 @@ public class RedstoneRepeaters {
 | 
			
		|||
            id = d.getKey();
 | 
			
		||||
            block.setMetadata("rid", new FixedMetadataValue(plugin, id));
 | 
			
		||||
 | 
			
		||||
            repeatersById.put(id, block.getLocation());
 | 
			
		||||
            repeatersByPower.put(id, d.getValue());
 | 
			
		||||
            gatewaysById.put(id, block.getLocation());
 | 
			
		||||
            gatewaysByPower.put(id, d.getValue());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!isValid(id)) return Integer.MIN_VALUE;
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +121,7 @@ public class RedstoneRepeaters {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    Block getBlock(int repeaterId) {
 | 
			
		||||
        var location = repeatersById.get(repeaterId);
 | 
			
		||||
        var location = gatewaysById.get(repeaterId);
 | 
			
		||||
        if (location == null) return null;
 | 
			
		||||
 | 
			
		||||
        if (!isValid(repeaterId)) return null;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,7 +155,7 @@ public class RedstoneRepeaters {
 | 
			
		|||
        var block = getBlock(repeaterId);
 | 
			
		||||
        if (block == null) return -1;
 | 
			
		||||
 | 
			
		||||
        var power = repeatersByPower.getOrDefault(repeaterId, (byte) 0);
 | 
			
		||||
        var power = gatewaysByPower.getOrDefault(repeaterId, (byte) 0);
 | 
			
		||||
        DebugLogger.fine("Got " + repeaterId + " outputs " + power);
 | 
			
		||||
        return power;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +169,7 @@ public class RedstoneRepeaters {
 | 
			
		|||
 | 
			
		||||
        var data = (AnaloguePowerable) block.getBlockData();
 | 
			
		||||
 | 
			
		||||
        repeatersByPower.put(repeaterId, power);
 | 
			
		||||
        gatewaysByPower.put(repeaterId, power);
 | 
			
		||||
        data.setPower(power);
 | 
			
		||||
 | 
			
		||||
        block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3);
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ import net.md_5.bungee.api.chat.ClickEvent;
 | 
			
		|||
import net.md_5.bungee.api.chat.ComponentBuilder;
 | 
			
		||||
import net.md_5.bungee.api.chat.HoverEvent;
 | 
			
		||||
import net.md_5.bungee.api.chat.hover.content.Text;
 | 
			
		||||
import org.bukkit.enchantments.Enchantment;
 | 
			
		||||
import org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.block.Action;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,30 +23,37 @@ import org.bukkit.event.block.BlockRedstoneEvent;
 | 
			
		|||
import org.bukkit.event.player.PlayerInteractEvent;
 | 
			
		||||
 | 
			
		||||
public class RedstoneListener implements Listener {
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
    private final RedstoneGateways redstoneGateways;
 | 
			
		||||
    private final GatewayItem gatewayItem;
 | 
			
		||||
 | 
			
		||||
    public RedstoneListener(RedstoneRepeaters redstoneRepeaters) {
 | 
			
		||||
        this.redstoneRepeaters = redstoneRepeaters;
 | 
			
		||||
    public RedstoneListener(RedstoneGateways redstoneGateways, GatewayItem gatewayItem) {
 | 
			
		||||
        this.redstoneGateways = redstoneGateways;
 | 
			
		||||
        this.gatewayItem = gatewayItem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBlockPlace(BlockPlaceEvent event) {
 | 
			
		||||
        if (!redstoneRepeaters.isRepeater(event.getItemInHand())) return;
 | 
			
		||||
        if (!gatewayItem.isGateway(event.getItemInHand())) return;
 | 
			
		||||
 | 
			
		||||
        var block = event.getBlockPlaced();
 | 
			
		||||
        var id = redstoneRepeaters.onPlace(block);
 | 
			
		||||
        var id = redstoneGateways.onPlace(block);
 | 
			
		||||
 | 
			
		||||
        DebugLogger.fine("Repeater placed: " + id);
 | 
			
		||||
        DebugLogger.fine("Gateway placed: " + id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBlockBreak(BlockBreakEvent event) {
 | 
			
		||||
        var id = redstoneRepeaters.getId(event.getBlock());
 | 
			
		||||
        var id = redstoneGateways.getId(event.getBlock());
 | 
			
		||||
        if (id == Integer.MIN_VALUE) return;
 | 
			
		||||
 | 
			
		||||
        redstoneRepeaters.onBreak(id);
 | 
			
		||||
        redstoneGateways.onBreak(id);
 | 
			
		||||
 | 
			
		||||
        DebugLogger.fine("Repeater broken: " + id);
 | 
			
		||||
        if (event.getPlayer().getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH)) {
 | 
			
		||||
            event.setDropItems(false);
 | 
			
		||||
            event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), gatewayItem.itemStack());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DebugLogger.fine("Gateway broken: " + id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
| 
						 | 
				
			
			@ -53,28 +61,31 @@ public class RedstoneListener implements Listener {
 | 
			
		|||
        if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
 | 
			
		||||
        if (!event.getPlayer().isSneaking()) return;
 | 
			
		||||
 | 
			
		||||
        var id = redstoneRepeaters.getId(event.getClickedBlock());
 | 
			
		||||
        var id = redstoneGateways.getId(event.getClickedBlock());
 | 
			
		||||
        if (id == Integer.MIN_VALUE) return;
 | 
			
		||||
 | 
			
		||||
        // TODO find a less lame way of showing ID
 | 
			
		||||
        var component = new ComponentBuilder("Repeater ID: ").color(ChatColor.GOLD)
 | 
			
		||||
        var component = new ComponentBuilder("Gateway ID: ").color(ChatColor.GOLD)
 | 
			
		||||
                .append(String.valueOf(id)).color(ChatColor.AQUA)
 | 
			
		||||
                .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Language.getString("clickToCopy"))))
 | 
			
		||||
                .event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, String.valueOf(id)))
 | 
			
		||||
                .build();
 | 
			
		||||
 | 
			
		||||
        event.getPlayer().spigot().sendMessage(component);
 | 
			
		||||
 | 
			
		||||
        // cancel block place
 | 
			
		||||
        event.setCancelled(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBlockRedstone(BlockRedstoneEvent event) {
 | 
			
		||||
        var block = event.getBlock();
 | 
			
		||||
 | 
			
		||||
        var id = redstoneRepeaters.getId(block);
 | 
			
		||||
        var id = redstoneGateways.getId(block);
 | 
			
		||||
        if (id == Integer.MIN_VALUE) return;
 | 
			
		||||
 | 
			
		||||
        event.setNewCurrent(redstoneRepeaters.getOutboundPower(id));
 | 
			
		||||
        event.setNewCurrent(redstoneGateways.getOutboundPower(id));
 | 
			
		||||
 | 
			
		||||
        DebugLogger.fine("Repeater redstone event: " + id);
 | 
			
		||||
        DebugLogger.fine("Gateway redstone event: " + id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,23 +18,25 @@ import java.util.function.Consumer;
 | 
			
		|||
 | 
			
		||||
public class RedstoneManager {
 | 
			
		||||
    private final Plugin plugin;
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
    private final RedstoneGateways redstoneGateways;
 | 
			
		||||
 | 
			
		||||
    private DatagramSocket socket;
 | 
			
		||||
    private RedstoneStateUpdateRunnable runnable;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public RedstoneManager(Plugin plugin) {
 | 
			
		||||
        this.plugin = plugin;
 | 
			
		||||
        this.redstoneRepeaters = new RedstoneRepeaters(plugin);
 | 
			
		||||
        this.redstoneGateways = new RedstoneGateways(plugin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void init(PluginCommand command) {
 | 
			
		||||
        RedstoneStore.init(plugin);
 | 
			
		||||
        var gatewayItem = new GatewayItem(plugin);
 | 
			
		||||
 | 
			
		||||
        plugin.getServer().getPluginManager().registerEvents(new RedstoneListener(redstoneRepeaters), plugin);
 | 
			
		||||
        command.setExecutor(new RedstoneCommands(redstoneRepeaters));
 | 
			
		||||
        plugin.getServer().getPluginManager().registerEvents(new RedstoneListener(redstoneGateways, gatewayItem), plugin);
 | 
			
		||||
        command.setExecutor(new RedstoneCommands(gatewayItem));
 | 
			
		||||
 | 
			
		||||
        this.runnable = new RedstoneStateUpdateRunnable(redstoneRepeaters);
 | 
			
		||||
        this.runnable = new RedstoneStateUpdateRunnable(redstoneGateways);
 | 
			
		||||
        this.runnable.runTaskTimer(plugin, 0, 20); // TODO configurable
 | 
			
		||||
 | 
			
		||||
        var listenAddress = TweaksConfig.getConfig().redstoneListen().split(":");
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +52,7 @@ public class RedstoneManager {
 | 
			
		|||
        } catch (SocketException e) {
 | 
			
		||||
            throw new RuntimeException("Starting socket", e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initSocket(SocketAddress bindAddress) throws SocketException {
 | 
			
		||||
| 
						 | 
				
			
			@ -70,15 +73,15 @@ public class RedstoneManager {
 | 
			
		|||
 | 
			
		||||
                boolean write = (buf[0] >> 7 & 1) == 1;
 | 
			
		||||
                byte data = (byte) (buf[3] & 0xF);
 | 
			
		||||
                int repeaterId = ((buf[0] & 0x7F) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | (buf[3] & 0xF0);
 | 
			
		||||
                int gatewayId = ((buf[0] & 0x7F) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | (buf[3] & 0xF0);
 | 
			
		||||
 | 
			
		||||
                if (write) {
 | 
			
		||||
                    enqueueUpdate(repeaterId, data);
 | 
			
		||||
                    enqueueUpdate(gatewayId, data);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var newPacket = new DatagramPacket(new byte[1], 1, packet.getSocketAddress());
 | 
			
		||||
 | 
			
		||||
                    enqueueRetrieve(repeaterId, value -> {
 | 
			
		||||
                        DebugLogger.fine("Retrieved for " + repeaterId + " power " + value);
 | 
			
		||||
                    enqueueRetrieve(gatewayId, value -> {
 | 
			
		||||
                        DebugLogger.fine("Retrieved for " + gatewayId + " power " + value);
 | 
			
		||||
                        newPacket.setData(new byte[] { (byte) Math.max(value, 0) });
 | 
			
		||||
 | 
			
		||||
                        try {
 | 
			
		||||
| 
						 | 
				
			
			@ -92,13 +95,13 @@ public class RedstoneManager {
 | 
			
		|||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void enqueueUpdate(int repeaterId, byte power) {
 | 
			
		||||
        DebugLogger.fine("Update enqueued " + repeaterId + " " + power);
 | 
			
		||||
        runnable.enqueueUpdate(repeaterId, power);
 | 
			
		||||
    private void enqueueUpdate(int gatewayId, byte power) {
 | 
			
		||||
        DebugLogger.fine("Update enqueued " + gatewayId + " " + power);
 | 
			
		||||
        runnable.enqueueUpdate(gatewayId, power);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) {
 | 
			
		||||
        DebugLogger.fine("Retrieve enqueued " + repeaterId);
 | 
			
		||||
        runnable.enqueueRetrieve(repeaterId, consumer);
 | 
			
		||||
    private void enqueueRetrieve(int gatewayId, Consumer<Byte> consumer) {
 | 
			
		||||
        DebugLogger.fine("Retrieve enqueued " + gatewayId);
 | 
			
		||||
        runnable.enqueueRetrieve(gatewayId, consumer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,14 +16,14 @@ public class RedstoneStateUpdateRunnable extends BukkitRunnable {
 | 
			
		|||
    private Map<Integer, Byte> updateQueue = new HashMap<>();
 | 
			
		||||
    private Map<Integer, Consumer<Byte>> retrieveQueue = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
    private final RedstoneGateways redstoneGateways;
 | 
			
		||||
 | 
			
		||||
    RedstoneStateUpdateRunnable(RedstoneRepeaters redstoneRepeaters) {
 | 
			
		||||
        this.redstoneRepeaters = redstoneRepeaters;
 | 
			
		||||
    RedstoneStateUpdateRunnable(RedstoneGateways redstoneGateways) {
 | 
			
		||||
        this.redstoneGateways = redstoneGateways;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void enqueueUpdate(int repeaterId, byte power) {
 | 
			
		||||
        updateQueue.put(repeaterId, power);
 | 
			
		||||
    void enqueueUpdate(int gatewayId, byte power) {
 | 
			
		||||
        updateQueue.put(gatewayId, power);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) {
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ public class RedstoneStateUpdateRunnable extends BukkitRunnable {
 | 
			
		|||
        var retrieveQueue = this.retrieveQueue;
 | 
			
		||||
        this.retrieveQueue = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        updateQueue.forEach((key, value) -> redstoneRepeaters.setPower(key, value));
 | 
			
		||||
        retrieveQueue.forEach((key, value) -> value.accept(redstoneRepeaters.getInboundPower(key)));
 | 
			
		||||
        updateQueue.forEach((key, value) -> redstoneGateways.setPower(key, value));
 | 
			
		||||
        retrieveQueue.forEach((key, value) -> value.accept(redstoneGateways.getInboundPower(key)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,11 +19,9 @@ import java.nio.file.Files;
 | 
			
		|||
public class RedstoneStore {
 | 
			
		||||
    private static RedstoneStore INSTANCE;
 | 
			
		||||
 | 
			
		||||
    private final Plugin plugin;
 | 
			
		||||
    private final File directory;
 | 
			
		||||
 | 
			
		||||
    private RedstoneStore(Plugin plugin) {
 | 
			
		||||
        this.plugin = plugin;
 | 
			
		||||
        this.directory = new File(plugin.getDataFolder(), "storage/redstone");
 | 
			
		||||
        directory.mkdirs();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -46,20 +44,20 @@ public class RedstoneStore {
 | 
			
		|||
            // TODO read just 4 bytes
 | 
			
		||||
            bytes = Files.readAllBytes(file.toPath());
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw new RuntimeException("Loading saved repeater data", e);
 | 
			
		||||
            throw new RuntimeException("Loading saved gateway data", e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var repeaterId = Ints.fromByteArray(bytes) & ~0xF;
 | 
			
		||||
        var gatewayId = Ints.fromByteArray(bytes) & ~0xF;
 | 
			
		||||
        var powerLevel = (byte) (bytes[3] & 0xF);
 | 
			
		||||
 | 
			
		||||
        DebugLogger.fine("load " + location + " " + repeaterId + " " + powerLevel);
 | 
			
		||||
        DebugLogger.fine("load " + location + " " + gatewayId + " " + powerLevel);
 | 
			
		||||
 | 
			
		||||
        return Pair.of(repeaterId, powerLevel);
 | 
			
		||||
        return Pair.of(gatewayId, powerLevel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void saveRepeaterData(Location location, int repeaterId, byte powerLevel) {
 | 
			
		||||
    void saveRepeaterData(Location location, int gatewayId, byte powerLevel) {
 | 
			
		||||
        var file = getFile(location);
 | 
			
		||||
        byte[] bytes = Ints.toByteArray((repeaterId & ~0xF) | (powerLevel & 0xF));
 | 
			
		||||
        byte[] bytes = Ints.toByteArray((gatewayId & ~0xF) | (powerLevel & 0xF));
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            Files.write(file.toPath(), bytes);
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +65,7 @@ public class RedstoneStore {
 | 
			
		|||
            throw new RuntimeException("Saving repeater data", e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        DebugLogger.fine("save " + location + " " + repeaterId + " " + powerLevel);
 | 
			
		||||
        DebugLogger.fine("save " + location + " " + gatewayId + " " + powerLevel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void deleteSavedRepeaterData(Location location) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -103,7 +103,7 @@ auth:
 | 
			
		|||
  # The domain of the server. Doesn't do anything other than showing in /tauth new
 | 
			
		||||
  domain: "replace.me"
 | 
			
		||||
 | 
			
		||||
# Adds blocks which allow to interact with redstone over internet
 | 
			
		||||
# Adds gateways emitting redstone, controlled over internet
 | 
			
		||||
retstone:
 | 
			
		||||
  enabled: true
 | 
			
		||||
  # This takes host:port, listens on UDP
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,6 +35,8 @@ commands:
 | 
			
		|||
    description: Send emergency alert
 | 
			
		||||
    permission: tweaks724.emergencyalert
 | 
			
		||||
  retstone:
 | 
			
		||||
    description: Retstone commands
 | 
			
		||||
    permission: tweaks724.retstone
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  tweaks724:
 | 
			
		||||
| 
						 | 
				
			
			@ -50,4 +52,6 @@ permissions:
 | 
			
		|||
      default: op
 | 
			
		||||
    emergencyalert:
 | 
			
		||||
      default: op
 | 
			
		||||
    retstone:
 | 
			
		||||
      default: op
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,6 @@ authKickWrongKey = You're connecting to the wrong server address. You must conne
 | 
			
		|||
# If force is enabled and player is not registered. Changing this reveals you're using this plugin
 | 
			
		||||
authKickUnregistered = You are not whitelisted on this server!
 | 
			
		||||
 | 
			
		||||
retstoneBlockItem = Online redstone block
 | 
			
		||||
redstoneGatewayItem = Redstone gateway
 | 
			
		||||
 | 
			
		||||
clickToCopy = Click to copy to clipboard
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue