This commit is contained in:
		
					parent
					
						
							
								3318863cf8
							
						
					
				
			
			
				commit
				
					
						dde8700248
					
				
			
		
					 13 changed files with 468 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -81,6 +81,9 @@ Issue messages that the player needs to read to keep playing, and that make an a
 | 
			
		|||
 | 
			
		||||
`/emergencyalerts` (`tweaks724.emergencyalerts`)
 | 
			
		||||
 | 
			
		||||
### Remote redstone
 | 
			
		||||
Control redstone remotely
 | 
			
		||||
 | 
			
		||||
### Utility commands
 | 
			
		||||
 | 
			
		||||
- `/ping` - displays player ping \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										32
									
								
								RETSTONE.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								RETSTONE.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
## Remote redstone
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
### How it works
 | 
			
		||||
A packet is int / 4 bytes / 32 bits
 | 
			
		||||
 | 
			
		||||
Packet format:
 | 
			
		||||
```
 | 
			
		||||
[ 01 ] [ 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ] [ 29 30 31 32 ]
 | 
			
		||||
action                          bits 2-28 of repeater id                                        payload
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- action: `1` to write, `0` to read
 | 
			
		||||
- payload: power level if writing
 | 
			
		||||
 | 
			
		||||
If writing, no response \
 | 
			
		||||
If reading, response is the power level, or -1 if no repeater with that id (subject to change)
 | 
			
		||||
 | 
			
		||||
Reading powers the block down of course \
 | 
			
		||||
If the block was powered, you should power it down (or read), wait some, and then read again
 | 
			
		||||
 | 
			
		||||
### Retstone
 | 
			
		||||
 | 
			
		||||
**Network** translates to **reto** in Esperanto \
 | 
			
		||||
So retsomething means networked something (posto - mail, retposto - email, ejo - place (site), retejo - website, etc.) \
 | 
			
		||||
And sometimes we use network instead of internet, same is in that language \
 | 
			
		||||
Hence retstone
 | 
			
		||||
							
								
								
									
										32
									
								
								retstone.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								retstone.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
#  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.
 | 
			
		||||
 | 
			
		||||
import socket, struct
 | 
			
		||||
 | 
			
		||||
ENDPOINT = ("127.0.0.1", 57931)
 | 
			
		||||
 | 
			
		||||
def get_power(repeater_id: int) -> int | None:
 | 
			
		||||
    message = repeater_id & 0x7FFFFFF0
 | 
			
		||||
 | 
			
		||||
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
			
		||||
    sock.sendto(message.to_bytes(4), ENDPOINT)
 | 
			
		||||
 | 
			
		||||
    return struct.unpack(">b", sock.recvfrom(1)[0])[0]
 | 
			
		||||
 | 
			
		||||
def set_power(repeater_id: int, power: int):
 | 
			
		||||
    message = repeater_id & 0x7FFFFFF0
 | 
			
		||||
    message |= 0x80000000
 | 
			
		||||
    message |= power & 0xF
 | 
			
		||||
 | 
			
		||||
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 | 
			
		||||
    sock.sendto(message.to_bytes(4), ENDPOINT)
 | 
			
		||||
 | 
			
		||||
repeater_id = 235459920
 | 
			
		||||
 | 
			
		||||
print("Reading from repeater")
 | 
			
		||||
power = get_power(repeater_id)
 | 
			
		||||
print("Read power:", power)
 | 
			
		||||
 | 
			
		||||
print("Powering repeater with power 10")
 | 
			
		||||
set_power(repeater_id, 10)
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +49,10 @@ public record TweaksConfig(
 | 
			
		|||
 | 
			
		||||
        boolean authEnabled,
 | 
			
		||||
        boolean authForce,
 | 
			
		||||
        String authDomain
 | 
			
		||||
        String authDomain,
 | 
			
		||||
 | 
			
		||||
        boolean redstoneEnabled,
 | 
			
		||||
        String redstoneListen
 | 
			
		||||
) {
 | 
			
		||||
    public static final int CONFIG_VERSION = 1;
 | 
			
		||||
    private static TweaksConfig config;
 | 
			
		||||
| 
						 | 
				
			
			@ -113,6 +116,9 @@ public record TweaksConfig(
 | 
			
		|||
        boolean authForce = config.getBoolean("auth.force");
 | 
			
		||||
        String authHostname = config.getString("auth.domain");
 | 
			
		||||
 | 
			
		||||
        boolean redstoneEnabled = config.getBoolean("retstone.enabled");
 | 
			
		||||
        String redstoneListen = config.getString("retstone.listen");
 | 
			
		||||
 | 
			
		||||
        TweaksConfig.config = new TweaksConfig(
 | 
			
		||||
                metrics,
 | 
			
		||||
                worldborderExpand, worldborderHide,
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +131,8 @@ public record TweaksConfig(
 | 
			
		|||
                updaterEnabled,
 | 
			
		||||
                hardcoreEnabled, hardcoreChance,
 | 
			
		||||
                sleepEnabled, sleepInstant,
 | 
			
		||||
                authEnabled, authForce, authHostname
 | 
			
		||||
                authEnabled, authForce, authHostname,
 | 
			
		||||
                redstoneEnabled, redstoneListen
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        return TweaksConfig.config;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ import eu.m724.tweaks.ping.PingChecker;
 | 
			
		|||
import eu.m724.tweaks.ping.PingCommands;
 | 
			
		||||
import eu.m724.tweaks.pomodoro.PomodoroCommands;
 | 
			
		||||
import eu.m724.tweaks.pomodoro.PomodoroManager;
 | 
			
		||||
import eu.m724.tweaks.redstone.RedstoneManager;
 | 
			
		||||
import eu.m724.tweaks.sleep.SleepManager;
 | 
			
		||||
import eu.m724.tweaks.updater.UpdaterCommands;
 | 
			
		||||
import eu.m724.tweaks.updater.UpdaterManager;
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +113,10 @@ public class TweaksPlugin extends MStatsPlugin {
 | 
			
		|||
 | 
			
		||||
        this.getServer().getPluginManager().registerEvents(new FullListener(), this);
 | 
			
		||||
 | 
			
		||||
        if (config.redstoneEnabled()) {
 | 
			
		||||
            new RedstoneManager(this).init(getCommand("retstone"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (config.metrics())
 | 
			
		||||
            mStats(1);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										52
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneCommands.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneCommands.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.command.Command;
 | 
			
		||||
import org.bukkit.command.CommandExecutor;
 | 
			
		||||
import org.bukkit.command.CommandSender;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
 | 
			
		||||
public class RedstoneCommands implements CommandExecutor {
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
 | 
			
		||||
    public RedstoneCommands(RedstoneRepeaters redstoneRepeaters) {
 | 
			
		||||
        this.redstoneRepeaters = redstoneRepeaters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
 | 
			
		||||
        if (args.length > 0) {
 | 
			
		||||
            if (args[0].equals("give")) {
 | 
			
		||||
                Player player = null;
 | 
			
		||||
 | 
			
		||||
                if (args.length > 1) {
 | 
			
		||||
                    player = Bukkit.getPlayerExact(args[1]);
 | 
			
		||||
                    if (player == null) {
 | 
			
		||||
                        sender.sendMessage("No player named " + args[1]);
 | 
			
		||||
                        return true;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (sender instanceof Player) {
 | 
			
		||||
                        player = (Player) sender;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        sender.sendMessage("Specify a player to give to, or be a player");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var itemStack = redstoneRepeaters.give();
 | 
			
		||||
                player.getInventory().addItem(itemStack);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            sender.sendMessage("Argument needed");
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneListener.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneListener.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 org.bukkit.event.EventHandler;
 | 
			
		||||
import org.bukkit.event.Listener;
 | 
			
		||||
import org.bukkit.event.block.Action;
 | 
			
		||||
import org.bukkit.event.block.BlockBreakEvent;
 | 
			
		||||
import org.bukkit.event.block.BlockPlaceEvent;
 | 
			
		||||
import org.bukkit.event.block.BlockRedstoneEvent;
 | 
			
		||||
import org.bukkit.event.player.PlayerInteractEvent;
 | 
			
		||||
 | 
			
		||||
public class RedstoneListener implements Listener {
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
 | 
			
		||||
    public RedstoneListener(RedstoneRepeaters redstoneRepeaters) {
 | 
			
		||||
        this.redstoneRepeaters = redstoneRepeaters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onPlace(BlockPlaceEvent event) {
 | 
			
		||||
        if (!redstoneRepeaters.isRepeater(event.getItemInHand())) return;
 | 
			
		||||
 | 
			
		||||
        var block = event.getBlockPlaced();
 | 
			
		||||
        var id = redstoneRepeaters.onPlace(block);
 | 
			
		||||
 | 
			
		||||
        System.out.println("repeate place " + id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void onBreak(BlockBreakEvent event) {
 | 
			
		||||
        var id = redstoneRepeaters.getId(event.getBlock());
 | 
			
		||||
        if (id == Integer.MIN_VALUE) return;
 | 
			
		||||
 | 
			
		||||
        redstoneRepeaters.onBreak(id);
 | 
			
		||||
 | 
			
		||||
        System.out.println("repeate brek " + id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @EventHandler
 | 
			
		||||
    public void a(PlayerInteractEvent event) {
 | 
			
		||||
        if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
 | 
			
		||||
        if (event.getClickedBlock() == null) return;
 | 
			
		||||
 | 
			
		||||
        var id = redstoneRepeaters.getId(event.getClickedBlock());
 | 
			
		||||
        if (id == Integer.MIN_VALUE) return;
 | 
			
		||||
 | 
			
		||||
        event.getPlayer().sendMessage("Repeater ID: " + id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneManager.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneManager.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,101 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.TweaksConfig;
 | 
			
		||||
import org.bukkit.command.PluginCommand;
 | 
			
		||||
import org.bukkit.plugin.Plugin;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.net.*;
 | 
			
		||||
import java.util.concurrent.Executors;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
public class RedstoneManager {
 | 
			
		||||
    private final Plugin plugin;
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
 | 
			
		||||
    private DatagramSocket socket;
 | 
			
		||||
    private RedstoneStateUpdateRunnable runnable;
 | 
			
		||||
 | 
			
		||||
    public RedstoneManager(Plugin plugin) {
 | 
			
		||||
        this.plugin = plugin;
 | 
			
		||||
        this.redstoneRepeaters = new RedstoneRepeaters(plugin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void init(PluginCommand command) {
 | 
			
		||||
        plugin.getServer().getPluginManager().registerEvents(new RedstoneListener(redstoneRepeaters), plugin);
 | 
			
		||||
        command.setExecutor(new RedstoneCommands(redstoneRepeaters));
 | 
			
		||||
 | 
			
		||||
        this.runnable = new RedstoneStateUpdateRunnable(redstoneRepeaters);
 | 
			
		||||
        this.runnable.runTaskTimer(plugin, 0, 20); // TODO configurable
 | 
			
		||||
 | 
			
		||||
        var listenAddress = TweaksConfig.getConfig().redstoneListen().split(":");
 | 
			
		||||
        InetSocketAddress bindAddress;
 | 
			
		||||
        if (listenAddress.length == 1) {
 | 
			
		||||
            bindAddress = new InetSocketAddress(Integer.parseInt(listenAddress[0]));
 | 
			
		||||
        } else {
 | 
			
		||||
            bindAddress = new InetSocketAddress(listenAddress[0], Integer.parseInt(listenAddress[1]));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            initSocket(bindAddress);
 | 
			
		||||
        } catch (SocketException e) {
 | 
			
		||||
            throw new RuntimeException("Starting socket", e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initSocket(SocketAddress bindAddress) throws SocketException {
 | 
			
		||||
        socket = new DatagramSocket(bindAddress);
 | 
			
		||||
 | 
			
		||||
        Executors.newSingleThreadExecutor().execute(() -> {
 | 
			
		||||
            byte[] buf = new byte[4];
 | 
			
		||||
 | 
			
		||||
            while (!socket.isClosed()) {
 | 
			
		||||
                DatagramPacket packet
 | 
			
		||||
                        = new DatagramPacket(buf, buf.length);
 | 
			
		||||
                try {
 | 
			
		||||
                    socket.receive(packet);
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    System.err.println("Error reading packet: " + e.getMessage());
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                boolean write = (buf[0] >> 7 & 1) == 1;
 | 
			
		||||
                byte state = (byte) (buf[3] & 0xF);
 | 
			
		||||
                int repeaterId = ((buf[0] & 0x7F) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | (buf[3] & 0xF0);
 | 
			
		||||
 | 
			
		||||
                if (write) {
 | 
			
		||||
                    enqueueUpdate(repeaterId, state);
 | 
			
		||||
                } else {
 | 
			
		||||
                    var newPacket = new DatagramPacket(new byte[1], 1, packet.getSocketAddress());
 | 
			
		||||
 | 
			
		||||
                    enqueueRetrieve(repeaterId, value -> {
 | 
			
		||||
                        System.out.println("retieved state " + value);
 | 
			
		||||
                        newPacket.setData(new byte[] { value });
 | 
			
		||||
 | 
			
		||||
                        try {
 | 
			
		||||
                            socket.send(newPacket);
 | 
			
		||||
                        } catch (IOException e) {
 | 
			
		||||
                            throw new RuntimeException("Sending response to get repeater value", e);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void enqueueUpdate(int repeaterId, byte state) {
 | 
			
		||||
        System.out.println("Update enqueud " + repeaterId + " " + state);
 | 
			
		||||
        runnable.enqueueUpdate(repeaterId, state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) {
 | 
			
		||||
        System.out.println("retieve enqueud " + repeaterId);
 | 
			
		||||
        runnable.enqueueRetrieve(repeaterId, consumer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneRepeaters.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/main/java/eu/m724/tweaks/redstone/RedstoneRepeaters.java
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,126 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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.Location;
 | 
			
		||||
import org.bukkit.Material;
 | 
			
		||||
import org.bukkit.NamespacedKey;
 | 
			
		||||
import org.bukkit.Particle;
 | 
			
		||||
import org.bukkit.block.Block;
 | 
			
		||||
import org.bukkit.inventory.ItemStack;
 | 
			
		||||
import org.bukkit.metadata.FixedMetadataValue;
 | 
			
		||||
import org.bukkit.persistence.PersistentDataType;
 | 
			
		||||
import org.bukkit.plugin.Plugin;
 | 
			
		||||
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.ThreadLocalRandom;
 | 
			
		||||
 | 
			
		||||
public class RedstoneRepeaters {
 | 
			
		||||
    private final Plugin plugin;
 | 
			
		||||
    private final NamespacedKey repeaterKey;
 | 
			
		||||
 | 
			
		||||
    private final Map<Integer, Location> repeatersById = new HashMap<>();
 | 
			
		||||
    private final Map<Location, Integer> repeatersByLocation = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    public RedstoneRepeaters(Plugin plugin) {
 | 
			
		||||
        this.plugin = plugin;
 | 
			
		||||
        this.repeaterKey = new NamespacedKey(plugin, "repeater");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getId(Block block) {
 | 
			
		||||
        return repeatersByLocation.getOrDefault(block.getLocation(), Integer.MIN_VALUE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    public ItemStack give() {
 | 
			
		||||
        var itemStack = new ItemStack(Material.RED_STAINED_GLASS);
 | 
			
		||||
        var meta = itemStack.getItemMeta();
 | 
			
		||||
 | 
			
		||||
        meta.setItemName(Language.getString("retstoneBlockItem"));
 | 
			
		||||
        meta.getPersistentDataContainer().set(repeaterKey, PersistentDataType.BOOLEAN, true);
 | 
			
		||||
        meta.setEnchantmentGlintOverride(true);
 | 
			
		||||
 | 
			
		||||
        itemStack.setItemMeta(meta);
 | 
			
		||||
        return itemStack;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO save in those
 | 
			
		||||
 | 
			
		||||
    int onPlace(Block block) {
 | 
			
		||||
        var repeaterId = ThreadLocalRandom.current().nextInt() & 0x7FFFFFF0;
 | 
			
		||||
 | 
			
		||||
        repeatersById.put(repeaterId, block.getLocation());
 | 
			
		||||
        repeatersByLocation.put(block.getLocation(), repeaterId);
 | 
			
		||||
        block.setMetadata("rid", new FixedMetadataValue(plugin, repeaterId));
 | 
			
		||||
 | 
			
		||||
        return repeaterId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onBreak(int repeaterId) {
 | 
			
		||||
        delete(repeaterId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    Block getBlock(int repeaterId) {
 | 
			
		||||
        var location = repeatersById.get(repeaterId);
 | 
			
		||||
        if (location == null) 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();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void delete(int repeaterId) {
 | 
			
		||||
        var l = repeatersById.remove(repeaterId);
 | 
			
		||||
        if (l == null) return;
 | 
			
		||||
        repeatersByLocation.remove(l);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    byte getPower(int repeaterId) {
 | 
			
		||||
        var block = getBlock(repeaterId);
 | 
			
		||||
        if (block == null) return -1;
 | 
			
		||||
 | 
			
		||||
        block.setType(Material.RED_STAINED_GLASS);
 | 
			
		||||
 | 
			
		||||
        block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3);
 | 
			
		||||
 | 
			
		||||
        return (byte) block.getBlockPower();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setPower(int repeaterId, byte power) {
 | 
			
		||||
        var block = getBlock(repeaterId);
 | 
			
		||||
        if (block == null) return;
 | 
			
		||||
 | 
			
		||||
        if (power == 0)
 | 
			
		||||
            block.setType(Material.RED_STAINED_GLASS);
 | 
			
		||||
        else
 | 
			
		||||
            block.setType(Material.REDSTONE_BLOCK);
 | 
			
		||||
 | 
			
		||||
        block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 org.bukkit.scheduler.BukkitRunnable;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
public class RedstoneStateUpdateRunnable extends BukkitRunnable {
 | 
			
		||||
    private Map<Integer, Byte> updateQueue = new HashMap<>();
 | 
			
		||||
    private Map<Integer, Consumer<Byte>> retrieveQueue = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    private final RedstoneRepeaters redstoneRepeaters;
 | 
			
		||||
 | 
			
		||||
    RedstoneStateUpdateRunnable(RedstoneRepeaters redstoneRepeaters) {
 | 
			
		||||
        this.redstoneRepeaters = redstoneRepeaters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void enqueueUpdate(int repeaterId, byte power) {
 | 
			
		||||
        updateQueue.put(repeaterId, power);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) {
 | 
			
		||||
        retrieveQueue.put(repeaterId, consumer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void run() {
 | 
			
		||||
        var updateQueue = this.updateQueue;
 | 
			
		||||
        this.updateQueue = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        var retrieveQueue = this.retrieveQueue;
 | 
			
		||||
        this.retrieveQueue = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        updateQueue.forEach((key, value) -> redstoneRepeaters.setPower(key, value));
 | 
			
		||||
        retrieveQueue.forEach((key, value) -> value.accept(redstoneRepeaters.getPower(key)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +103,12 @@ 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
 | 
			
		||||
retstone:
 | 
			
		||||
  enabled: true
 | 
			
		||||
  # This takes host:port, listens on UDP
 | 
			
		||||
  listen: 127.0.0.1:57931
 | 
			
		||||
 | 
			
		||||
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
 | 
			
		||||
 | 
			
		||||
# Don't modify unless told to
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ commands:
 | 
			
		|||
  emergencyalert:
 | 
			
		||||
    description: Send emergency alert
 | 
			
		||||
    permission: tweaks724.emergencyalert
 | 
			
		||||
  retstone:
 | 
			
		||||
 | 
			
		||||
permissions:
 | 
			
		||||
  tweaks724:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,4 +23,6 @@ chatAlreadyHere = You're already in this room
 | 
			
		|||
# Used when a player joins using the wrong key or no key
 | 
			
		||||
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
 | 
			
		||||
# 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!
 | 
			
		||||
authKickUnregistered = You are not whitelisted on this server!
 | 
			
		||||
 | 
			
		||||
retstoneBlockItem = Online redstone block
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue