hugo4715
6/26/2016 - 9:37 AM

ScoreboardSign2.java

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();
        }

    }
}