Created
June 24, 2018 11:24
-
-
Save boy0001/a57a813264c58db267109fbffe38c723 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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