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`)
|
`/emergencyalerts` (`tweaks724.emergencyalerts`)
|
||||||
|
|
||||||
|
### Remote redstone
|
||||||
|
Control redstone remotely
|
||||||
|
|
||||||
### Utility commands
|
### Utility commands
|
||||||
|
|
||||||
- `/ping` - displays player ping \
|
- `/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 authEnabled,
|
||||||
boolean authForce,
|
boolean authForce,
|
||||||
String authDomain
|
String authDomain,
|
||||||
|
|
||||||
|
boolean redstoneEnabled,
|
||||||
|
String redstoneListen
|
||||||
) {
|
) {
|
||||||
public static final int CONFIG_VERSION = 1;
|
public static final int CONFIG_VERSION = 1;
|
||||||
private static TweaksConfig config;
|
private static TweaksConfig config;
|
||||||
|
@ -113,6 +116,9 @@ public record TweaksConfig(
|
||||||
boolean authForce = config.getBoolean("auth.force");
|
boolean authForce = config.getBoolean("auth.force");
|
||||||
String authHostname = config.getString("auth.domain");
|
String authHostname = config.getString("auth.domain");
|
||||||
|
|
||||||
|
boolean redstoneEnabled = config.getBoolean("retstone.enabled");
|
||||||
|
String redstoneListen = config.getString("retstone.listen");
|
||||||
|
|
||||||
TweaksConfig.config = new TweaksConfig(
|
TweaksConfig.config = new TweaksConfig(
|
||||||
metrics,
|
metrics,
|
||||||
worldborderExpand, worldborderHide,
|
worldborderExpand, worldborderHide,
|
||||||
|
@ -125,7 +131,8 @@ public record TweaksConfig(
|
||||||
updaterEnabled,
|
updaterEnabled,
|
||||||
hardcoreEnabled, hardcoreChance,
|
hardcoreEnabled, hardcoreChance,
|
||||||
sleepEnabled, sleepInstant,
|
sleepEnabled, sleepInstant,
|
||||||
authEnabled, authForce, authHostname
|
authEnabled, authForce, authHostname,
|
||||||
|
redstoneEnabled, redstoneListen
|
||||||
);
|
);
|
||||||
|
|
||||||
return TweaksConfig.config;
|
return TweaksConfig.config;
|
||||||
|
|
|
@ -20,6 +20,7 @@ import eu.m724.tweaks.ping.PingChecker;
|
||||||
import eu.m724.tweaks.ping.PingCommands;
|
import eu.m724.tweaks.ping.PingCommands;
|
||||||
import eu.m724.tweaks.pomodoro.PomodoroCommands;
|
import eu.m724.tweaks.pomodoro.PomodoroCommands;
|
||||||
import eu.m724.tweaks.pomodoro.PomodoroManager;
|
import eu.m724.tweaks.pomodoro.PomodoroManager;
|
||||||
|
import eu.m724.tweaks.redstone.RedstoneManager;
|
||||||
import eu.m724.tweaks.sleep.SleepManager;
|
import eu.m724.tweaks.sleep.SleepManager;
|
||||||
import eu.m724.tweaks.updater.UpdaterCommands;
|
import eu.m724.tweaks.updater.UpdaterCommands;
|
||||||
import eu.m724.tweaks.updater.UpdaterManager;
|
import eu.m724.tweaks.updater.UpdaterManager;
|
||||||
|
@ -112,6 +113,10 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
|
|
||||||
this.getServer().getPluginManager().registerEvents(new FullListener(), this);
|
this.getServer().getPluginManager().registerEvents(new FullListener(), this);
|
||||||
|
|
||||||
|
if (config.redstoneEnabled()) {
|
||||||
|
new RedstoneManager(this).init(getCommand("retstone"));
|
||||||
|
}
|
||||||
|
|
||||||
if (config.metrics())
|
if (config.metrics())
|
||||||
mStats(1);
|
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
|
# The domain of the server. Doesn't do anything other than showing in /tauth new
|
||||||
domain: "replace.me"
|
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!
|
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
|
||||||
|
|
||||||
# Don't modify unless told to
|
# Don't modify unless told to
|
||||||
|
|
|
@ -34,6 +34,7 @@ commands:
|
||||||
emergencyalert:
|
emergencyalert:
|
||||||
description: Send emergency alert
|
description: Send emergency alert
|
||||||
permission: tweaks724.emergencyalert
|
permission: tweaks724.emergencyalert
|
||||||
|
retstone:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
tweaks724:
|
tweaks724:
|
||||||
|
|
|
@ -24,3 +24,5 @@ chatAlreadyHere = You're already in this room
|
||||||
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
|
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
|
# 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…
Reference in a new issue