Skip to content

Instantly share code, notes, and snippets.

@boy0001
Created June 24, 2018 11:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boy0001/a57a813264c58db267109fbffe38c723 to your computer and use it in GitHub Desktop.
Save boy0001/a57a813264c58db267109fbffe38c723 to your computer and use it in GitHub Desktop.
package com.boydti.buildoff.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.plugin.Plugin;
public abstract class InSignsNano implements Listener {
// BUFFER = how many signs can be in the queue to auto-update at one time
// lower it if you want to save a couple kilobytes of ram
final int UPDATE_BUFFER = 4096;
// AMOUNT = how many signs (MAX) to update each tick
final int UPDATE_AMOUNT = 16;
public abstract String[] getValue(String[] lines, Player player, Sign sign);
public HashSet<Location> broken_signs = new HashSet<>();
private final boolean manual;
private final Plugin plugin;
private int counter = 0;
private volatile List<Sign> updateQueueSign = new ArrayList<Sign>();
private volatile List<Player> updateQueuePlayer = new ArrayList<Player>();
public InSignsNano(final Plugin plugin, final boolean autoupdating, final boolean manualUpdating) {
this.manual = manualUpdating;
Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
this.plugin = plugin;
if (autoupdating) {
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
@Override
public void run() {
int size = InSignsNano.this.updateQueuePlayer.size();
if (size > InSignsNano.this.UPDATE_BUFFER) {
InSignsNano.this.updateQueuePlayer.remove(size - 1);
InSignsNano.this.updateQueueSign.remove(size - 1);
size -= 1;
}
final ArrayList<Sign> toRemoveSign = new ArrayList<Sign>();
final ArrayList<Player> toRemovePlayer = new ArrayList<Player>();
for (int i = 0; i < Math.min(InSignsNano.this.UPDATE_AMOUNT, size); i++) {
if (InSignsNano.this.counter >= size) {
InSignsNano.this.counter = 0;
}
;
final Player player = InSignsNano.this.updateQueuePlayer.get(InSignsNano.this.counter);
final Sign sign = InSignsNano.this.updateQueueSign.get(InSignsNano.this.counter);
final boolean result = updateSign(player, sign);
if (!result) {
toRemovePlayer.add(player);
toRemoveSign.add(sign);
}
InSignsNano.this.counter++;
}
InSignsNano.this.updateQueuePlayer.removeAll(toRemovePlayer);
InSignsNano.this.updateQueueSign.removeAll(toRemoveSign);
}
}, 0L, 1L);
}
}
@EventHandler
public void onPlayerMove(final PlayerMoveEvent event) {
if (!event.getFrom().getChunk().equals(event.getTo().getChunk())) {
scheduleUpdate(event.getPlayer(), event.getTo());
}
}
@EventHandler
public void onPlayerTeleport(final PlayerTeleportEvent event) {
if (!event.getFrom().getChunk().equals(event.getTo().getChunk())) {
scheduleUpdate(event.getPlayer(), event.getTo());
}
}
@EventHandler
public void onSignChange(final SignChangeEvent event) {
final Location loc = event.getBlock().getLocation();
final World world = loc.getWorld();
final List<Chunk> chunks = Arrays.asList(new Chunk[] { loc.getChunk(), world.getChunkAt(loc.add(16.0D, 0.0D, 0.0D)), world.getChunkAt(loc.add(16.0D, 0.0D, 16.0D)), world.getChunkAt(loc.add(0.0D, 0.0D, 16.0D)), world.getChunkAt(loc.add(-16.0D, 0.0D, 0.0D)), world.getChunkAt(loc.add(-16.0D, 0.0D, -16.0D)), world.getChunkAt(loc.add(0.0D, 0.0D, -16.0D)), world.getChunkAt(loc.add(16.0D, 0.0D, -16.0D)), world.getChunkAt(loc.add(-16.0D, 0.0D, 16.0D)) });
final List<Player> myplayers = new ArrayList<Player>();
for (final Chunk chunk : chunks) {
for (final Entity entity : chunk.getEntities()) {
if (((entity instanceof Player)) && (!myplayers.contains(entity))) {
myplayers.add((Player) entity);
}
}
}
for (final Player user : myplayers) {
scheduleUpdate(user, loc);
}
return;
}
@EventHandler
public void onPlayerInteract(final PlayerInteractEvent event) {
if (!((event.getAction() == Action.RIGHT_CLICK_BLOCK) || (event.getAction() == Action.LEFT_CLICK_BLOCK))) {
return;
}
final Block block = event.getClickedBlock();
if ((block.getType() != Material.SIGN_POST) && (block.getType() != Material.WALL_SIGN)) {
return;
}
final Sign sign = (Sign) block.getState();
final Player player = event.getPlayer();
final String[] lines = sign.getLines();
if (onClick(player, lines)) {
scheduleUpdate(player, sign, 1);
}
}
public abstract boolean onClick(Player player, String[] lines);
@EventHandler
public void onPlayerJoin(final PlayerJoinEvent event) {
scheduleUpdate(event.getPlayer(), event.getPlayer().getLocation());
}
public void scheduleUpdate(final Player player, final Location location) {
if (this.manual) {
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin, new Runnable() {
@Override
public void run() {
if (player.isOnline()) {
updateAllSigns(player, location);
}
}
}, 40L);
}
}
public void scheduleUpdate(final Player player, final Sign sign, final long time) {
if (this.broken_signs.contains(sign.getLocation())) {
this.broken_signs = new HashSet<>();
return;
}
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(this.plugin, new Runnable() {
@Override
public void run() {
if (player.isOnline()) {
if ((sign.getBlock() != null) && (sign.getBlock().getState() instanceof Sign)) {
updateSign(player, (Sign) sign.getBlock().getState());
}
}
}
}, time);
}
public void addUpdateQueue(final Sign sign, final Player player) {
for (int i = 0; i < this.updateQueuePlayer.size(); i++) {
if (this.updateQueuePlayer.get(i).getName().equals(player.getName())) {
if (this.updateQueueSign.get(i).getLocation().equals(sign.getLocation())) {
return;
}
}
}
this.updateQueuePlayer.add(player);
this.updateQueueSign.add(sign);
}
public void updateAllSigns(final Player player, final Location location) {
List<BlockState> states = new ArrayList<BlockState>();
final World world = player.getWorld();
final List<Chunk> chunks = Arrays.asList(new Chunk[] { location.getChunk(), world.getChunkAt(location.add(16.0D, 0.0D, 0.0D)), world.getChunkAt(location.add(16.0D, 0.0D, 16.0D)), world.getChunkAt(location.add(0.0D, 0.0D, 16.0D)), world.getChunkAt(location.add(-16.0D, 0.0D, 0.0D)), world.getChunkAt(location.add(-16.0D, 0.0D, -16.0D)), world.getChunkAt(location.add(0.0D, 0.0D, -16.0D)), world.getChunkAt(location.add(16.0D, 0.0D, -16.0D)), world.getChunkAt(location.add(-16.0D, 0.0D, 16.0D)) });
for (final Chunk chunk : chunks) {
for (final BlockState state : chunk.getTileEntities()) {
states.add(state);
}
}
for (final BlockState current : states) {
if ((current instanceof Sign)) {
updateSign(player, (Sign) current);
}
}
states = null;
}
public boolean updateSign(final Player player, final Sign sign) {
final Location location = sign.getLocation();
final Block block = location.getBlock();
if (block == null) {
return false;
}
if (block.getState() == null) {
return false;
}
if (!(block.getState() instanceof Sign)) {
return false;
}
if ((player == null) || !player.isOnline()) {
return false;
}
if (!location.getWorld().equals(player.getWorld())) {
return false;
}
if (!location.getChunk().isLoaded()) {
return false;
}
final double distance = location.distanceSquared(player.getLocation());
if (distance > 1024) {
return false;
}
final String[] lines = getValue(sign.getLines(), player, sign);
if (lines == null) {
return false;
}
for (int i = 0; i < 4; i++) {
if (lines[i].contains("\n")) {
if ((i < 3)) {
if (lines[i + 1].isEmpty()) {
lines[i + 1] = ChatColor.getLastColors(lines[i].substring(0, 15)) + lines[i].substring(lines[i].indexOf("\n") + 1);
}
}
lines[i] = lines[i].substring(0, lines[i].indexOf("\n"));
}
if (lines[i].length() > 15) {
if ((i < 3)) {
if (lines[i + 1].isEmpty()) {
lines[i + 1] = ChatColor.getLastColors(lines[i].substring(0, 15)) + lines[i].substring(15);
}
}
lines[i] = lines[i].substring(0, 15);
}
}
player.sendSignChange(sign.getLocation(), lines);
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment