use of eelfloat.replcraft.Structure in project replcraft by LeeFlemingRepl.
the class StructureInteractions method onPlayerInteract.
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
Player player = event.getPlayer();
if (!player.isSneaking() || event.getAction() != Action.RIGHT_CLICK_BLOCK)
return;
Block block = event.getClickedBlock();
UUID uuid = player.getUniqueId();
if (block == null)
return;
ItemStack item = player.getInventory().getItemInMainHand();
if (item.getType() == Material.STICK) {
boolean tryPrint = false;
try {
Structure structure = StructureUtil.verifyStructure(block);
if (structure.location_equals(boundStructures.get(uuid))) {
tryPrint = true;
} else {
boundStructures.put(uuid, structure);
player.sendMessage(String.format("%s bound. Shift-right-click with stick again inside to print block info.", structure));
}
} catch (InvalidStructure ex) {
tryPrint = true;
}
if (tryPrint) {
Structure structure = boundStructures.get(uuid);
if (structure == null) {
player.sendMessage(String.format("%sNo structure bound%s. Shift-right-click with stick on a valid structure wall first.", ChatColor.RED, ChatColor.WHITE));
return;
}
player.sendMessage(String.format("%s===%s Structure %s===%s\n%sStructure:%s %s\n%sRelative coordinates:%s %d %d %d\n%sBlock string:%s \"%s%s%s\"", ChatColor.GRAY, ChatColor.WHITE, ChatColor.GRAY, ChatColor.WHITE, ChatColor.GRAY, ChatColor.WHITE, structure, ChatColor.GRAY, ChatColor.WHITE, block.getX() - structure.inner_min_x(), block.getY() - structure.inner_min_y(), block.getZ() - structure.inner_min_z(), ChatColor.GRAY, ChatColor.WHITE, ChatColor.GOLD, block.getBlockData().getAsString(), ChatColor.WHITE));
}
return;
}
if (!(block.getState() instanceof org.bukkit.block.Sign))
return;
try {
AtomicReference<String> checkedUsername = new AtomicReference<>();
AtomicReference<String> usedPermission = new AtomicReference<>();
boolean permAdmin = player.hasPermission("replcraft.auth.admin");
boolean permPublic = player.hasPermission("replcraft.auth.public");
boolean permSelf = player.hasPermission("replcraft.auth.self");
StructureUtil.verifySign(block, uuid, username -> {
checkedUsername.set(username);
if (username.equals("@ADMIN")) {
usedPermission.set("admin");
return permAdmin;
}
if (username.equals("@PUBLIC")) {
usedPermission.set("public");
return permPublic;
}
if (username.equals(player.getName())) {
usedPermission.set("player");
return permSelf;
}
if (username.matches("[A-Za-z0-9]+")) {
usedPermission.set("admin");
return permAdmin;
}
return false;
});
Claims claims = Jwts.claims();
claims.put("host", ReplCraft.plugin.public_address);
claims.put("world", block.getWorld().getName());
claims.put("x", block.getX());
claims.put("y", block.getY());
claims.put("z", block.getZ());
claims.put("uuid", uuid.toString());
claims.put("username", checkedUsername.get());
claims.put("permission", usedPermission.get());
String jws = Jwts.builder().setClaims(claims).signWith(ReplCraft.plugin.key).compact();
player.sendMessage("Your token (click to copy): " + jws);
player.sendMessage("Keep it secret! To revoke this token, break the sign.");
} catch (InvalidStructure ex) {
player.sendMessage(ex.getMessage());
}
}
use of eelfloat.replcraft.Structure in project replcraft by LeeFlemingRepl.
the class StructureUtil method verifySign.
/**
* Verifies a sign and the attached structure
* @param block the block containing the sign.
* @param usernameValidator A function that validates the username on the sign.
* @throws InvalidStructure if the sign or structure is invalid
* @return the validated structure
*/
public static Structure verifySign(Block block, UUID minecraft_uuid, Predicate<String> usernameValidator) throws InvalidStructure {
BlockState state = block.getState();
if (!(state instanceof org.bukkit.block.Sign)) {
throw new InvalidStructure("Block is not a sign.");
}
BlockData data = block.getBlockData();
if (!(data instanceof WallSign)) {
throw new InvalidStructure("Sign must be on a wall.");
}
String[] lines = ((org.bukkit.block.Sign) state).getLines();
assert lines.length == 4;
String repl = lines[0];
// Note: No way to actually enforce these at the moment, that's why we're using auth tokens instead
String replit_username = lines[1];
String repl_id = lines[2];
String minecraft_username = lines[3];
if (!repl.equals("REPL")) {
throw new InvalidStructure("Line 1 of sign is not \"REPL\"");
}
if (!usernameValidator.test(minecraft_username)) {
throw new InvalidStructure("Missing permissions for this sign. Does your username match line 4?");
}
Structure structure = verifyStructure(block.getRelative(((WallSign) data).getFacing().getOppositeFace()));
structure.sign = block;
structure.replit_username = replit_username;
structure.replit_repl_id = repl_id;
structure.minecraft_username = minecraft_username;
structure.minecraft_uuid = minecraft_uuid;
return structure;
}
use of eelfloat.replcraft.Structure in project replcraft by LeeFlemingRepl.
the class StructureUtil method verifyStructure.
/**
* Verifies the structure attached to a sign
* @param starting_block A block on the frame of the structure
* @throws InvalidStructure if the structure is invalid
* @return a partially validated structure, missing its sign field
*/
public static Structure verifyStructure(Block starting_block) throws InvalidStructure {
// A list of all seen frame blocks, attached chests, and signs.
HashSet<Location> seen = new HashSet<>();
Stack<Location> to_explore = new Stack<>();
int min_x = starting_block.getX();
int min_y = starting_block.getY();
int min_z = starting_block.getZ();
int max_x = starting_block.getX();
int max_y = starting_block.getY();
int max_z = starting_block.getZ();
List<Block> chests = new ArrayList<>();
to_explore.push(starting_block.getLocation());
StructureMaterial material = null;
int explored = 0;
while (!to_explore.isEmpty()) {
explored += 1;
if (material == null && explored > 100) {
throw new InvalidStructure("Too many connected blocks before finding any valid structure material.");
}
if (material != null && explored > material.max_size) {
throw new InvalidStructure(String.format("Too many connected %s blocks. The limit is %d for this material type.", material.name, material.max_size));
}
Block block = to_explore.pop().getBlock();
for (BlockFace face : BlockFace.values()) {
if (!face.isCartesian())
continue;
Block relative = block.getRelative(face);
Location location = relative.getLocation();
if (relative.getType() == Material.CHEST) {
seen.add(location);
chests.add(relative);
}
boolean isValidStructureMaterial = material == null ? ReplCraft.plugin.frame_materials.stream().flatMap(mats -> mats.validMaterials.stream()).anyMatch(mat -> relative.getType() == mat) : material.validMaterials.contains(relative.getType());
if (isValidStructureMaterial && !seen.contains(location)) {
if (material == null) {
material = ReplCraft.plugin.frame_materials.stream().filter(mats -> mats.validMaterials.contains(relative.getType())).findFirst().orElseThrow(() -> new RuntimeException("unreachable"));
ReplCraft.plugin.logger.info("Structure type determined to be " + material.name);
}
seen.add(location);
to_explore.push(location);
min_x = Math.min(min_x, location.getBlockX());
min_y = Math.min(min_y, location.getBlockY());
min_z = Math.min(min_z, location.getBlockZ());
max_x = Math.max(max_x, location.getBlockX());
max_y = Math.max(max_y, location.getBlockY());
max_z = Math.max(max_z, location.getBlockZ());
}
}
}
ReplCraft.plugin.logger.info(String.format("Structure min [%s %s %s] max [%s %s %s]", min_x, min_y, min_z, max_x, max_y, max_z));
if (material == null) {
throw new InvalidStructure("Structure must contain at least one valid structure block from any structure type.");
}
// Top edges
// 1
check_axis(material, new Location(starting_block.getWorld(), min_x, max_y, max_z), 1, 0, 0, max_x - min_x);
// 2
check_axis(material, new Location(starting_block.getWorld(), max_x, max_y, max_z), 0, 0, -1, max_z - min_z);
// 3
check_axis(material, new Location(starting_block.getWorld(), max_x, max_y, min_z), -1, 0, 0, max_x - min_x);
// 4
check_axis(material, new Location(starting_block.getWorld(), min_x, max_y, min_z), 0, 0, 1, max_z - min_z);
// Side edges
// 5
check_axis(material, new Location(starting_block.getWorld(), max_x, min_y, max_z), 0, 1, 0, max_y - min_y);
// 6
check_axis(material, new Location(starting_block.getWorld(), max_x, min_y, min_z), 0, 1, 0, max_y - min_y);
// 7
check_axis(material, new Location(starting_block.getWorld(), min_x, min_y, min_z), 0, 1, 0, max_y - min_y);
// 8
check_axis(material, new Location(starting_block.getWorld(), min_x, min_y, max_z), 0, 1, 0, max_y - min_y);
// Bottom edges
// 9
check_axis(material, new Location(starting_block.getWorld(), min_x, min_y, max_z), 1, 0, 0, max_x - min_x);
// 10
check_axis(material, new Location(starting_block.getWorld(), max_x, min_y, max_z), 0, 0, -1, max_z - min_z);
// 11
check_axis(material, new Location(starting_block.getWorld(), max_x, min_y, min_z), -1, 0, 0, max_x - min_x);
// 12
check_axis(material, new Location(starting_block.getWorld(), min_x, min_y, min_z), 0, 0, 1, max_z - min_z);
Structure structure = new Structure(material, null, null, null, null, null, seen, chests, min_x, min_y, min_z, max_x, max_y, max_z);
if (structure.inner_size_x() < 1 || structure.inner_size_y() < 1 || structure.inner_size_z() < 1) {
throw new InvalidStructure("Structure must have a nonzero interior size.");
}
return structure;
}
Aggregations