package fr.hugo4715.crackedskywars.scoreboard;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import fr.hugo4715.crackedskywars.util.PacketUtil;
import fr.hugo4715.crackedskywars.util.Reflection;
/**
* @author zyuiop
* @author Seveningful
* @author Hugo4715
*/
public class ScoreboardSign {
private Class<?> classPacketPlayOutScoreboardScore = Reflection.getClass("{nms}.PacketPlayOutScoreboardScore");
private Constructor<?> constructorPacketPlayOutScoreboardScore;
private Class<?> classPacketPlayOutScoreboardScoreEnumScoreboardAction = Reflection.getClass("{nms}.PacketPlayOutScoreboardScore").getClasses()[0];
private Class<?> classPacketPlayOutScoreboardTeam = Reflection.getClass("{nms}.PacketPlayOutScoreboardTeam");
private Constructor<?> constructorPacketPlayOutScoreboardTeam;
private boolean created = false;
private String[] lines = new String[16];
private Object[] teams = new Object[16];//acketPlayOutScoreboardTeam
private final Player player;
private String objectiveName;
public ScoreboardSign(Player player, String objectiveName) {
this.player = player;
this.objectiveName = objectiveName;
init();
}
private void init() {
try {
constructorPacketPlayOutScoreboardScore = classPacketPlayOutScoreboardScore.getConstructor(String.class);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
try {
constructorPacketPlayOutScoreboardTeam = classPacketPlayOutScoreboardTeam.getDeclaredConstructor();
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
}
public ScoreboardSign(Player player, String objectiveName, String[] lines) {
this.player = player;
this.objectiveName = objectiveName;
this.lines = lines;
init();
}
public void create() {
if (created) return;
PacketUtil.getInstance().sendPacket(player,createObjectivePacket(0, objectiveName));
PacketUtil.getInstance().sendPacket(player, setObjectiveSlot());
int i = 0;
while (i < lines.length)
{
sendLine(i++);
}
created = true;
}
public void destroy() {
if (!created)
return;
PacketUtil.getInstance().sendPacket(player, createObjectivePacket(1, null));
created = false;
}
private Object sendLine(int line) {
if (line > 15)
return null;
if (line < 0)
return null;
if (!created)
return null;
Object teamPacket = apply(line);
int score = 15-line;
PacketUtil.getInstance().sendPacket(player, teamPacket);
return sendScore(ChatColor.values()[line].toString() + ChatColor.RESET , score);
}
public void setObjectiveName(String name) {
this.objectiveName = name;
if (created)
PacketUtil.getInstance().sendPacket(player, createObjectivePacket(2, name));
}
public void setLine(int line, String value) {
lines[line] = value;
PacketUtil.getInstance().sendPacket(player, sendLine(line));
}
public void removeLine(int line) {
String oldLine = getLine(line);
if (oldLine != null && created)
PacketUtil.getInstance().sendPacket(player, removeLine(oldLine));
lines[line] = null;
}
public String getLine(int line) {
if (line > 15)
return null;
if (line < 0)
return null;
return lines[line];
}
/*
Factories
*/
/**
*
* @param mode
* @param displayName
* @return PacketPlayOutScoreboardObjective as object
*/
private Object createObjectivePacket(int mode, String displayName) {
Class<?> classPacketPlayOutScoreboardObjective = Reflection.getClass("{nms}.PacketPlayOutScoreboardObjective");
Object packet = null;
try {
packet = classPacketPlayOutScoreboardObjective.newInstance();
} catch (InstantiationException e1) {
e1.printStackTrace();
return null;
} catch (IllegalAccessException e1) {
e1.printStackTrace();
return null;
}
//PacketPlayOutScoreboardObjective packet = new PacketPlayOutScoreboardObjective();
try {
// Nom de l'objectif
Field name = packet.getClass().getDeclaredField("a");
name.setAccessible(true);
name.set(packet, player.getName());
// Mode
// 0 : créer
// 1 : Supprimer
// 2 : Mettre à jour
Field modeField = packet.getClass().getDeclaredField("d");
modeField.setAccessible(true);
modeField.set(packet, mode);
if (mode == 0 || mode == 2) {
Field displayNameField = packet.getClass().getDeclaredField("b");
displayNameField.setAccessible(true);
displayNameField.set(packet, displayName);
Field display = packet.getClass().getDeclaredField("c");
display.setAccessible(true);
Class<?> iScoreboardCriteria = Reflection.getClass("{nms}.IScoreboardCriteria").getDeclaredClasses()[0];
Object i = iScoreboardCriteria.getEnumConstants()[0];
display.set(packet, i);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
return packet;
}
/**
* @return PacketPlayOutScoreboardDisplayObjective as object
*/
private Object setObjectiveSlot() {
Object packet;
try {
packet = Reflection.getClass("{nms}.PacketPlayOutScoreboardDisplayObjective").newInstance();
} catch (InstantiationException e1) {
e1.printStackTrace();
return null;
} catch (IllegalAccessException e1) {
e1.printStackTrace();
return null;
}
//PacketPlayOutScoreboardDisplayObjective packet = new PacketPlayOutScoreboardDisplayObjective();
try {
// Slot de l'objectif
Field position = packet.getClass().getDeclaredField("a");
position.setAccessible(true);
position.set(packet, 1); // SideBar
Field name = packet.getClass().getDeclaredField("b");
name.setAccessible(true);
name.set(packet, player.getName());
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
return packet;
}
/**
*
* @param line
* @param score
* @return PacketPlayOutScoreboardScore as object
*/
private Object sendScore(String line, int score) {
Object packet;
try {
packet = constructorPacketPlayOutScoreboardScore.newInstance(line);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
e1.printStackTrace();
return null;
}
//PacketPlayOutScoreboardScore packet = new PacketPlayOutScoreboardScore(line);
try {
Field name = packet.getClass().getDeclaredField("b");
name.setAccessible(true);
name.set(packet, player.getName());
Field scoreField = packet.getClass().getDeclaredField("c");
scoreField.setAccessible(true);
scoreField.set(packet, score); // SideBar
Field action = packet.getClass().getDeclaredField("d");
action.setAccessible(true);
action.set(packet, classPacketPlayOutScoreboardScoreEnumScoreboardAction.getEnumConstants()[0]);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
return packet;
}
/**
* @param line
* @return PacketPlayOutScoreboardScore as Object
*/
private Object removeLine(String line) {
try {
return constructorPacketPlayOutScoreboardScore.newInstance(line);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public Player getBukkitPlayer() {
return player;
}
public String getDisplayName() {
return objectiveName;
}
public String[] getLines() {
return lines;
}
private String[] splitString(String string)
{
Validate.isTrue(string.length() <= 32, "String can't have more than 32 characters " );
if (string.isEmpty()) {
return new String[] { " ", "" };
}
StringBuilder prefix = new StringBuilder(string.substring(0, string.length() >= 16 ? 16 : string.length()));
StringBuilder suffix = new StringBuilder(string.length() > 16 ? string.substring(16) : "");
if (prefix.charAt(prefix.length() - 1) == '§')
{
prefix.deleteCharAt(prefix.length() - 1);
suffix.insert(0, '§');
}
if(!suffix.toString().isEmpty())
suffix.insert(0, ChatColor.getLastColors(prefix.toString()));
return new String[] { prefix.toString().length() > 16 ? prefix.toString().substring(0, 16) : prefix.toString(), suffix.toString().length() > 16 ? suffix.toString().substring(0, 16) : suffix.toString() };
}
/**
*
* @param line
* @return PacketPlayOutScoreboardTeam as Object
*/
private Object apply(int line){
if(teams[line] != null)
{
setField(getTeamLine(line),"i", 2);
setField(getTeamLine(line), "c", splitString(getLine(line))[0]);
setField(getTeamLine(line), "d", splitString(getLine(line))[1]);
}
return getTeamLine(line);
}
/**
*
* @param line
* @return PacketPlayOutScoreboardTeam as Object
*/
private Object getTeamLine(int line) {
if(teams[line] == null)
{
//PacketPlayOutScoreboardTeam team = new PacketPlayOutScoreboardTeam();
Object team = null;;
try {
team = constructorPacketPlayOutScoreboardTeam.newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
return null;
}
setField(team, "a", line + "");
setField(team, "b", line + "");
setField(team, "c", splitString(getLine(line))[0]);
setField(team, "d", splitString(getLine(line))[1]);
addEntry(team, ChatColor.values()[line].toString() + ChatColor.RESET);
teams[line] = team;
}
return teams[line];
}
private static void setField(Object packet, String field, Object value) {
try {
Field f = packet.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(packet, value);
f.setAccessible(false);
} catch (Exception ex) {ex.printStackTrace();}
}
/**
* @param packet PacketPlayOutScoreboardTeam as Object
*/
private void addEntry(Object packet, String entry) {
Field f = null;
try {
f = packet.getClass().getDeclaredField("h");//g in 1.8
f.setAccessible(true);
System.out.println(f.get(packet).getClass().getName());
((Collection) f.get(packet)).add(entry);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}