valueEntry : map.get(entryValues.getKey()).entrySet()) {
627 | valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
628 | allSkipped = false;
629 | }
630 | if (!allSkipped) {
631 | reallyAllSkipped = false;
632 | valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
633 | }
634 | }
635 | if (reallyAllSkipped) {
636 | // Null = skip the chart
637 | return null;
638 | }
639 | return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
640 | }
641 | }
642 |
643 | /**
644 | * An extremely simple JSON builder.
645 | *
646 | * While this class is neither feature-rich nor the most performant one, it's sufficient enough
647 | * for its use-case.
648 | */
649 | public static class JsonObjectBuilder {
650 |
651 | private StringBuilder builder = new StringBuilder();
652 |
653 | private boolean hasAtLeastOneField = false;
654 |
655 | public JsonObjectBuilder() {
656 | builder.append("{");
657 | }
658 |
659 | /**
660 | * Appends a null field to the JSON.
661 | *
662 | * @param key The key of the field.
663 | * @return A reference to this object.
664 | */
665 | public JsonObjectBuilder appendNull(String key) {
666 | appendFieldUnescaped(key, "null");
667 | return this;
668 | }
669 |
670 | /**
671 | * Appends a string field to the JSON.
672 | *
673 | * @param key The key of the field.
674 | * @param value The value of the field.
675 | * @return A reference to this object.
676 | */
677 | public JsonObjectBuilder appendField(String key, String value) {
678 | if (value == null) {
679 | throw new IllegalArgumentException("JSON value must not be null");
680 | }
681 | appendFieldUnescaped(key, "\"" + escape(value) + "\"");
682 | return this;
683 | }
684 |
685 | /**
686 | * Appends an integer field to the JSON.
687 | *
688 | * @param key The key of the field.
689 | * @param value The value of the field.
690 | * @return A reference to this object.
691 | */
692 | public JsonObjectBuilder appendField(String key, int value) {
693 | appendFieldUnescaped(key, String.valueOf(value));
694 | return this;
695 | }
696 |
697 | /**
698 | * Appends an object to the JSON.
699 | *
700 | * @param key The key of the field.
701 | * @param object The object.
702 | * @return A reference to this object.
703 | */
704 | public JsonObjectBuilder appendField(String key, JsonObject object) {
705 | if (object == null) {
706 | throw new IllegalArgumentException("JSON object must not be null");
707 | }
708 | appendFieldUnescaped(key, object.toString());
709 | return this;
710 | }
711 |
712 | /**
713 | * Appends a string array to the JSON.
714 | *
715 | * @param key The key of the field.
716 | * @param values The string array.
717 | * @return A reference to this object.
718 | */
719 | public JsonObjectBuilder appendField(String key, String[] values) {
720 | if (values == null) {
721 | throw new IllegalArgumentException("JSON values must not be null");
722 | }
723 | String escapedValues =
724 | Arrays.stream(values)
725 | .map(value -> "\"" + escape(value) + "\"")
726 | .collect(Collectors.joining(","));
727 | appendFieldUnescaped(key, "[" + escapedValues + "]");
728 | return this;
729 | }
730 |
731 | /**
732 | * Appends an integer array to the JSON.
733 | *
734 | * @param key The key of the field.
735 | * @param values The integer array.
736 | * @return A reference to this object.
737 | */
738 | public JsonObjectBuilder appendField(String key, int[] values) {
739 | if (values == null) {
740 | throw new IllegalArgumentException("JSON values must not be null");
741 | }
742 | String escapedValues =
743 | Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
744 | appendFieldUnescaped(key, "[" + escapedValues + "]");
745 | return this;
746 | }
747 |
748 | /**
749 | * Appends an object array to the JSON.
750 | *
751 | * @param key The key of the field.
752 | * @param values The integer array.
753 | * @return A reference to this object.
754 | */
755 | public JsonObjectBuilder appendField(String key, JsonObject[] values) {
756 | if (values == null) {
757 | throw new IllegalArgumentException("JSON values must not be null");
758 | }
759 | String escapedValues =
760 | Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
761 | appendFieldUnescaped(key, "[" + escapedValues + "]");
762 | return this;
763 | }
764 |
765 | /**
766 | * Appends a field to the object.
767 | *
768 | * @param key The key of the field.
769 | * @param escapedValue The escaped value of the field.
770 | */
771 | private void appendFieldUnescaped(String key, String escapedValue) {
772 | if (builder == null) {
773 | throw new IllegalStateException("JSON has already been built");
774 | }
775 | if (key == null) {
776 | throw new IllegalArgumentException("JSON key must not be null");
777 | }
778 | if (hasAtLeastOneField) {
779 | builder.append(",");
780 | }
781 | builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
782 | hasAtLeastOneField = true;
783 | }
784 |
785 | /**
786 | * Builds the JSON string and invalidates this builder.
787 | *
788 | * @return The built JSON string.
789 | */
790 | public JsonObject build() {
791 | if (builder == null) {
792 | throw new IllegalStateException("JSON has already been built");
793 | }
794 | JsonObject object = new JsonObject(builder.append("}").toString());
795 | builder = null;
796 | return object;
797 | }
798 |
799 | /**
800 | * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
801 | *
802 | *
This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
803 | * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
804 | *
805 | * @param value The value to escape.
806 | * @return The escaped value.
807 | */
808 | private static String escape(String value) {
809 | final StringBuilder builder = new StringBuilder();
810 | for (int i = 0; i < value.length(); i++) {
811 | char c = value.charAt(i);
812 | if (c == '"') {
813 | builder.append("\\\"");
814 | } else if (c == '\\') {
815 | builder.append("\\\\");
816 | } else if (c <= '\u000F') {
817 | builder.append("\\u000").append(Integer.toHexString(c));
818 | } else if (c <= '\u001F') {
819 | builder.append("\\u00").append(Integer.toHexString(c));
820 | } else {
821 | builder.append(c);
822 | }
823 | }
824 | return builder.toString();
825 | }
826 |
827 | /**
828 | * A super simple representation of a JSON object.
829 | *
830 | *
This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
831 | * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
832 | * JsonObject)}.
833 | */
834 | public static class JsonObject {
835 |
836 | private final String value;
837 |
838 | private JsonObject(String value) {
839 | this.value = value;
840 | }
841 |
842 | @Override
843 | public String toString() {
844 | return value;
845 | }
846 | }
847 | }
848 | }
--------------------------------------------------------------------------------
/src/main/java/de/rexlnico/realtimeplugin/util/NMSUtil.java:
--------------------------------------------------------------------------------
1 | package de.rexlnico.realtimeplugin.util;
2 |
3 | import org.bukkit.Bukkit;
4 | import org.bukkit.Location;
5 | import org.bukkit.Sound;
6 | import org.bukkit.entity.Player;
7 |
8 | import java.lang.reflect.Constructor;
9 |
10 | public class NMSUtil {
11 | public static final String VERSION = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
12 |
13 | public static Class> getNMSClass(String name) {
14 | try {
15 | return Class.forName(String.format("net.minecraft.server.%s.%s", VERSION, name));
16 | } catch (ClassNotFoundException ignored) {
17 | return null;
18 | }
19 | }
20 |
21 | public static void sendPacket(Player player, Object packet) {
22 | try {
23 | Object handle = player.getClass().getMethod("getHandle").invoke(player);
24 | Object playerConnection = handle.getClass().getField("playerConnection").get(handle);
25 | playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet"))
26 | .invoke(playerConnection, packet);
27 | } catch (Exception e) {
28 | e.printStackTrace();
29 | }
30 | }
31 |
32 | public static void sendLightning(Player player, Location l) {
33 | Class> light = getNMSClass("EntityLightning");
34 | try {
35 | Constructor> constu = light.getConstructor(getNMSClass("World"), double.class, double.class, double.class, boolean.class, boolean.class);
36 | Object wh = player.getWorld().getClass().getMethod("getHandle").invoke(player.getWorld());
37 | Object lighobj = constu.newInstance(wh, l.getX(), l.getY(), l.getZ(), false, false);
38 | Object obj = getNMSClass("PacketPlayOutSpawnEntityWeather").getConstructor(getNMSClass("Entity")).newInstance(lighobj);
39 | sendPacket(player, obj);
40 | player.playSound(player.getLocation(), Sound.AMBIENCE_THUNDER, 100, 1);
41 | } catch (Exception e) {
42 | e.printStackTrace();
43 | }
44 | }
45 |
46 | public static void sendGameState(Player player, int type, float state) throws InstantiationException, NoSuchFieldException {
47 | try {
48 | final Object entityPlayer = player.getClass().getMethod("getHandle", new Class[0]).invoke(player);
49 | final Object playerConnection = entityPlayer.getClass().getField("playerConnection").get(entityPlayer);
50 | final Object packet = getNMSClass("PacketPlayOutGameStateChange").getConstructor(Integer.TYPE, Float.TYPE).newInstance(type, state);
51 | playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(playerConnection, packet);
52 | } catch (Exception ignored) {
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/de/rexlnico/realtimeplugin/util/Utils.java:
--------------------------------------------------------------------------------
1 | package de.rexlnico.realtimeplugin.util;
2 |
3 | import de.rexlnico.realtimeplugin.main.Main;
4 | import org.bukkit.Location;
5 | import org.bukkit.entity.Player;
6 | import org.json.simple.JSONObject;
7 | import org.json.simple.JSONValue;
8 |
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.InputStream;
11 | import java.net.MalformedURLException;
12 | import java.net.URL;
13 | import java.net.URLConnection;
14 | import java.util.Random;
15 | import java.util.logging.Level;
16 |
17 | public class Utils {
18 | private static final Random RAND = new Random();
19 |
20 | public static int overflow(int value, int at) {
21 | while (value > at) {
22 | value -= at;
23 | }
24 | return value;
25 | }
26 |
27 | public static byte[] httpRequest(String url) {
28 | try {
29 | return httpRequest(new URL(url));
30 | } catch (MalformedURLException e) {
31 | //Main.getPlugin().getLogger().log(Level.SEVERE, String.format("HTTP request to %s failed", url), e);
32 | return null;
33 | }
34 | }
35 |
36 | public static byte[] httpRequest(URL url) {
37 | try {
38 | URLConnection conn = url.openConnection();
39 | InputStream in = conn.getInputStream();
40 | ByteArrayOutputStream bout = new ByteArrayOutputStream();
41 |
42 | byte[] buff = new byte[1024];
43 | int len;
44 | while ((len = in.read(buff)) != -1) {
45 | bout.write(buff, 0, len);
46 | }
47 |
48 | bout.close();
49 | in.close();
50 |
51 | return bout.toByteArray();
52 | } catch (Exception e) {
53 | //Main.getPlugin().getLogger().log(Level.SEVERE, String.format("HTTP request to %s failed", url), e);
54 | return null;
55 | }
56 | }
57 |
58 | public static Location getRandomLocation(Player player) {
59 | Location location;
60 | int x;
61 | int z;
62 | x = RAND.nextInt(player.getLocation().getBlockX() + 25) + 12;
63 | z = RAND.nextInt(player.getLocation().getBlockZ() + 25) + 12;
64 | if (RAND.nextBoolean()) {
65 | x *= -1;
66 | }
67 | if (RAND.nextBoolean()) {
68 | z *= -1;
69 | }
70 | location = new Location(player.getWorld(), player.getLocation().add(x, 0, z).getX(), player.getWorld().getHighestBlockYAt(x, z) + 1, player.getLocation().add(x, 0, z).getZ());
71 | return location;
72 | }
73 |
74 | public static JSONObject parseJSON(String json) {
75 | return (JSONObject) JSONValue.parse(json);
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | main: de.rexlnico.realtimeplugin.main.Main
2 | authors: [ rexlNico, fluse1367 ]
3 | version: 3.8
4 | api-version: 1.13
5 | name: RealTimePlugin
6 | website: https://rexlNico.de
7 |
8 | commands:
9 | realtime:
--------------------------------------------------------------------------------
/src/main/resources/template.json:
--------------------------------------------------------------------------------
1 | {
2 | "world": "example",
3 | "updateInterval": 20,
4 | "active": false,
5 | "time": {
6 | "active": false,
7 | "timezone": "Europe/Berlin"
8 | },
9 | "weather": {
10 | "active": false,
11 | "City": "Berlin",
12 | "Country": "Germany",
13 | "weatherKey": ""
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/resources/world.json:
--------------------------------------------------------------------------------
1 | {
2 | "world": "world",
3 | "updateInterval": 20,
4 | "active": true,
5 | "time": {
6 | "active": true,
7 | "timezone": "Europe/Berlin"
8 | },
9 | "weather": {
10 | "active": false,
11 | "City": "Berlin",
12 | "Country": "Germany",
13 | "weatherKey": ""
14 | }
15 | }
--------------------------------------------------------------------------------