redstone WIP 2
All checks were successful
/ build (push) Successful in 1m1s

This commit is contained in:
Minecon724 2024-12-30 21:07:47 +01:00
parent dde8700248
commit 916f44da47
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
7 changed files with 231 additions and 52 deletions

View file

@ -19,10 +19,10 @@ action bits 2-28 of repeater id
- payload: power level if writing - payload: power level if writing
If writing, no response \ If writing, no response \
If reading, response is the power level, or -1 if no repeater with that id (subject to change) If reading, response is the power level, or 0 if not powered or no repeater with that ID
Reading powers the block down of course \ 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 BUT you should power it down (or read), wait some, and then read again
### Retstone ### Retstone

View file

@ -22,11 +22,23 @@ def set_power(repeater_id: int, power: int):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(message.to_bytes(4), ENDPOINT) sock.sendto(message.to_bytes(4), ENDPOINT)
repeater_id = 235459920
print("Reading from repeater") if __name__ == "__main__":
power = get_power(repeater_id) from argparse import ArgumentParser
print("Read power:", power)
print("Powering repeater with power 10") parser = ArgumentParser()
set_power(repeater_id, 10) parser.add_argument("repeater_id", help="The repeater ID", type=int)
parser.add_argument("-p", "--power", help="Power the repeater with specified power. Leave to read.", type=int)
parser.add_argument("-c", "--copy", help="Copy input of one repeater to another. If combined with power, power is added.", type=int)
args = parser.parse_args()
if args.copy is None:
if args.power is None:
power = get_power(args.repeater_id)
print(power)
else:
set_power(args.repeater_id, args.power)
else:
while True:
power = get_power(args.repeater_id)
set_power(args.copy, power)

View file

@ -51,4 +51,17 @@ public class RedstoneListener implements Listener {
event.getPlayer().sendMessage("Repeater ID: " + id); event.getPlayer().sendMessage("Repeater ID: " + id);
} }
@EventHandler
public void b(BlockRedstoneEvent event) {
var block = event.getBlock();
System.out.println(block);
var id = redstoneRepeaters.getId(block);
if (id == Integer.MIN_VALUE) return;
System.out.println("yes it isi");
event.setNewCurrent(redstoneRepeaters.getOutboundPower(id));
}
} }

View file

@ -28,6 +28,8 @@ public class RedstoneManager {
} }
public void init(PluginCommand command) { public void init(PluginCommand command) {
Store.init(plugin);
plugin.getServer().getPluginManager().registerEvents(new RedstoneListener(redstoneRepeaters), plugin); plugin.getServer().getPluginManager().registerEvents(new RedstoneListener(redstoneRepeaters), plugin);
command.setExecutor(new RedstoneCommands(redstoneRepeaters)); command.setExecutor(new RedstoneCommands(redstoneRepeaters));
@ -66,17 +68,17 @@ public class RedstoneManager {
} }
boolean write = (buf[0] >> 7 & 1) == 1; boolean write = (buf[0] >> 7 & 1) == 1;
byte state = (byte) (buf[3] & 0xF); byte data = (byte) (buf[3] & 0xF);
int repeaterId = ((buf[0] & 0x7F) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | (buf[3] & 0xF0); int repeaterId = ((buf[0] & 0x7F) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | (buf[3] & 0xF0);
if (write) { if (write) {
enqueueUpdate(repeaterId, state); enqueueUpdate(repeaterId, data);
} else { } else {
var newPacket = new DatagramPacket(new byte[1], 1, packet.getSocketAddress()); var newPacket = new DatagramPacket(new byte[1], 1, packet.getSocketAddress());
enqueueRetrieve(repeaterId, value -> { enqueueRetrieve(repeaterId, value -> {
System.out.println("retieved state " + value); System.out.println("retieved state " + value);
newPacket.setData(new byte[] { value }); newPacket.setData(new byte[] { (byte) Math.max(value, 0) });
try { try {
socket.send(newPacket); socket.send(newPacket);
@ -89,9 +91,9 @@ public class RedstoneManager {
}); });
} }
private void enqueueUpdate(int repeaterId, byte state) { private void enqueueUpdate(int repeaterId, byte power) {
System.out.println("Update enqueud " + repeaterId + " " + state); System.out.println("Update enqueud " + repeaterId + " " + power);
runnable.enqueueUpdate(repeaterId, state); runnable.enqueueUpdate(repeaterId, power);
} }
private void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) { private void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) {

View file

@ -6,49 +6,40 @@
package eu.m724.tweaks.redstone; package eu.m724.tweaks.redstone;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import eu.m724.tweaks.Language; import eu.m724.tweaks.Language;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.data.AnaloguePowerable;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.persistence.PersistentDataType; import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import java.util.*; import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
public class RedstoneRepeaters { public class RedstoneRepeaters {
private final Plugin plugin; private final Plugin plugin;
private final NamespacedKey repeaterKey; private final NamespacedKey repeaterKey;
private final Map<Integer, Location> repeatersById = new HashMap<>(); private final BiMap<Integer, Location> repeatersById = HashBiMap.create();
private final Map<Location, Integer> repeatersByLocation = new HashMap<>(); private final Map<Integer, Byte> repeatersByPower = new HashMap<>();
public RedstoneRepeaters(Plugin plugin) { public RedstoneRepeaters(Plugin plugin) {
this.plugin = plugin; this.plugin = plugin;
this.repeaterKey = new NamespacedKey(plugin, "repeater"); this.repeaterKey = new NamespacedKey(plugin, "repeater");
} }
// /* Item functions */
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() { public ItemStack give() {
var itemStack = new ItemStack(Material.RED_STAINED_GLASS); var itemStack = new ItemStack(Material.DAYLIGHT_DETECTOR);
var meta = itemStack.getItemMeta(); var meta = itemStack.getItemMeta();
meta.setItemName(Language.getString("retstoneBlockItem")); meta.setItemName(Language.getString("retstoneBlockItem"));
@ -59,15 +50,23 @@ public class RedstoneRepeaters {
return itemStack; return itemStack;
} }
// TODO save in those 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) { int onPlace(Block block) {
var repeaterId = ThreadLocalRandom.current().nextInt() & 0x7FFFFFF0; var repeaterId = ThreadLocalRandom.current().nextInt() & 0x7FFFFFF0;
repeatersById.put(repeaterId, block.getLocation()); repeatersById.put(repeaterId, block.getLocation());
repeatersByLocation.put(block.getLocation(), repeaterId);
block.setMetadata("rid", new FixedMetadataValue(plugin, repeaterId)); block.setMetadata("rid", new FixedMetadataValue(plugin, repeaterId));
Store.getInstance().saveRepeaterData(block.getLocation(), repeaterId, (byte) 0);
return repeaterId; return repeaterId;
} }
@ -75,12 +74,83 @@ public class RedstoneRepeaters {
delete(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) { Block getBlock(int repeaterId) {
var location = repeatersById.get(repeaterId); var location = repeatersById.get(repeaterId);
if (location == null) return null; if (location == null) return null;
if (!isValid(repeaterId)) return null;
var storedId = location.getBlock().getMetadata("rid").getFirst().asInt(); var storedId = location.getBlock().getMetadata("rid").getFirst().asInt();
if (storedId != repeaterId) { if (storedId != repeaterId) {
System.out.println("retrieved but not exitt"); System.out.println("retrieved but not exitt");
@ -92,35 +162,41 @@ public class RedstoneRepeaters {
return location.getBlock(); return location.getBlock();
} }
void delete(int repeaterId) { /* Control functions */
var l = repeatersById.remove(repeaterId);
if (l == null) return;
repeatersByLocation.remove(l);
}
// byte getInboundPower(int repeaterId) {
byte getPower(int repeaterId) {
var block = getBlock(repeaterId); var block = getBlock(repeaterId);
if (block == null) return -1; 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); 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(); 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) { 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); var block = getBlock(repeaterId);
if (block == null) return; if (block == null) return;
if (power == 0) var data = (AnaloguePowerable) block.getBlockData();
block.setType(Material.RED_STAINED_GLASS);
else repeatersByPower.put(repeaterId, power);
block.setType(Material.REDSTONE_BLOCK); data.setPower(power);
block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3); block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3);
}
} System.out.println("Okay I set power");
}
}

View file

@ -39,6 +39,6 @@ public class RedstoneStateUpdateRunnable extends BukkitRunnable {
this.retrieveQueue = new HashMap<>(); this.retrieveQueue = new HashMap<>();
updateQueue.forEach((key, value) -> redstoneRepeaters.setPower(key, value)); updateQueue.forEach((key, value) -> redstoneRepeaters.setPower(key, value));
retrieveQueue.forEach((key, value) -> value.accept(redstoneRepeaters.getPower(key))); retrieveQueue.forEach((key, value) -> value.accept(redstoneRepeaters.getInboundPower(key)));
} }
} }

View file

@ -0,0 +1,76 @@
/*
* 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.primitives.Ints;
import org.apache.commons.lang3.tuple.Pair;
import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
public class Store {
private static Store INSTANCE;
private final Plugin plugin;
private final File directory;
private Store(Plugin plugin) {
this.plugin = plugin;
this.directory = new File(plugin.getDataFolder(), "storage/redstone");
directory.mkdirs();
}
static void init(Plugin plugin) {
INSTANCE = new Store(plugin);
}
static Store getInstance() {
return INSTANCE;
}
Pair<Integer, Byte> getSavedRepeaterData(Location location) {
var file = getFile(location);
if (!file.exists()) return null;
byte[] bytes;
try {
// TODO read just 4 bytes
bytes = Files.readAllBytes(file.toPath());
} catch (IOException e) {
throw new RuntimeException("Loading saved repeater data", e);
}
var repeaterId = Ints.fromByteArray(bytes) & ~0xF;
var powerLevel = (byte) (bytes[3] & 0xF);
return Pair.of(repeaterId, powerLevel);
}
void saveRepeaterData(Location location, int repeaterId, byte powerLevel) {
var file = getFile(location);
System.out.println(file);
byte[] bytes = Ints.toByteArray((repeaterId & ~0xF) | (powerLevel & 0xF));
try {
Files.write(file.toPath(), bytes);
} catch (IOException e) {
throw new RuntimeException("Saving repeater data", e);
}
}
void deleteSavedRepeaterData(Location location) {
getFile(location).delete();
}
private File getFile(Location location) {
return new File(directory, location.getWorld().getName() + " " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
}
}