diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
new file mode 100644
index 0000000..d7d8698
--- /dev/null
+++ b/DEVELOPMENT.md
@@ -0,0 +1,7 @@
+To see Minecraft source code: https://git.m724.eu/Minecon724/fabric-template-minimal-source
+
+To setup NMS:
+1. Download BuildTools, move it into an empty directory and open terminal
+2. ```
+ java -jar BuildTools.jar --rev 1.21.1 --remapped
+ ```
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index e18aee6..9136b71 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,6 +12,7 @@
21
21
UTF-8
+ 1.21.1-R0.1-SNAPSHOT
@@ -54,6 +55,39 @@
+
+ net.md-5
+ specialsource-maven-plugin
+ 2.0.3
+
+
+ package
+
+ remap
+
+ remap-obf
+
+ org.spigotmc:minecraft-server:${project.spigot.version}:txt:maps-mojang
+ true
+ org.spigotmc:spigot:${project.spigot.version}:jar:remapped-mojang
+ true
+ remapped-obf-temp-dont-use
+
+
+
+ package
+
+ remap
+
+ remap-spigot
+
+ ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf-temp-dont-use.jar
+ org.spigotmc:minecraft-server:${project.spigot.version}:csrg:maps-spigot
+ org.spigotmc:spigot:${project.spigot.version}:jar:remapped-obf
+
+
+
+
@@ -66,13 +100,37 @@
dmulloy2-repo
https://repo.dmulloy2.net/repository/public/
+
+
+ maxhenkel-repo
+ https://maven.maxhenkel.de/repository/public
+
org.spigotmc
spigot-api
- 1.21.1-R0.1-SNAPSHOT
+ ${project.spigot.version}
+ provided
+
+
+ org.spigotmc
+ spigot
+ ${project.spigot.version}
+ remapped-mojang
+ provided
+
+
+ com.comphenix.protocol
+ ProtocolLib
+ 5.3.0
+ provided
+
+
+ de.maxhenkel.voicechat
+ voicechat-api
+ 2.5.0
provided
@@ -81,11 +139,5 @@
24.1.0
compile
-
- com.comphenix.protocol
- ProtocolLib
- 5.3.0
- provided
-
\ No newline at end of file
diff --git a/src/main/java/eu/m724/tweaks/TweaksPlugin.java b/src/main/java/eu/m724/tweaks/TweaksPlugin.java
index 325c402..b268f52 100644
--- a/src/main/java/eu/m724/tweaks/TweaksPlugin.java
+++ b/src/main/java/eu/m724/tweaks/TweaksPlugin.java
@@ -3,11 +3,14 @@ package eu.m724.tweaks;
import eu.m724.tweaks.chat.ChatCommands;
import eu.m724.tweaks.chat.ChatManager;
import eu.m724.tweaks.door.DoorListener;
+import eu.m724.tweaks.motd.MotdListener;
import eu.m724.tweaks.ping.F3NameListener;
import eu.m724.tweaks.ping.PingChecker;
import eu.m724.tweaks.ping.PingCommands;
+import eu.m724.tweaks.player.MusicPlayer;
import org.bukkit.plugin.java.JavaPlugin;
+import java.io.IOException;
import java.util.Objects;
public class TweaksPlugin extends JavaPlugin {
@@ -26,5 +29,18 @@ public class TweaksPlugin extends JavaPlugin {
new PingChecker(this).init();
Objects.requireNonNull(getCommand("ping")).setExecutor(new PingCommands());
Objects.requireNonNull(getCommand("dkick")).setExecutor(new PingCommands());
+
+ if (getServer().getPluginManager().getPlugin("voicechat") != null) {
+ new MusicPlayer(this).init();
+ } else {
+ getLogger().warning("To use voice extensions, install \"Simple Voice Chat\"");
+ }
+
+ try {
+ new MotdListener("example").init(this);
+ } catch (IOException e) {
+ getLogger().severe("Failed to initialize MOTD extension");
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/src/main/java/eu/m724/tweaks/motd/MotdListener.java b/src/main/java/eu/m724/tweaks/motd/MotdListener.java
new file mode 100644
index 0000000..40f879d
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/motd/MotdListener.java
@@ -0,0 +1,87 @@
+package eu.m724.tweaks.motd;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.events.*;
+import com.comphenix.protocol.reflect.StructureModifier;
+import com.google.gson.JsonElement;
+import net.md_5.bungee.api.chat.TextComponent;
+import net.md_5.bungee.chat.ComponentSerializer;
+import net.minecraft.SharedConstants;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.status.ServerStatus;
+import org.bukkit.plugin.Plugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.concurrent.ThreadLocalRandom;
+
+public class MotdListener {
+ private final String motdSetName;
+
+ private Component[] motds;
+
+ public MotdListener(String motdSetName) {
+ this.motdSetName = motdSetName;
+ }
+
+ public void init(Plugin plugin) throws IOException {
+ File motdSetsFile = new File(plugin.getDataFolder() + "/motd sets/" + motdSetName + ".txt");
+
+ // if the directory didn't exist create example motd sets
+ if (motdSetsFile.getParentFile().mkdirs()) {
+ plugin.saveResource("motd sets/" + motdSetName + ".txt", true);
+ }
+
+ String fileContent = Files.readString(motdSetsFile.toPath());
+ // MOTDs are split with an empty line
+ motds = Arrays.stream(fileContent.split("\n\n"))
+ .map(s -> {
+ JsonElement json = ComponentSerializer.toJson(TextComponent.fromLegacy(s.strip()));
+ return Component.Serializer.fromJson(json, RegistryAccess.EMPTY);
+ })
+ .toArray(Component[]::new);
+
+ plugin.getLogger().info("Loaded %d MOTDs".formatted(motds.length));
+
+ registerListener(plugin);
+ }
+
+ private void registerListener(Plugin plugin) {
+ ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
+ plugin,
+ ListenerPriority.NORMAL,
+ PacketType.Status.Server.SERVER_INFO
+ ) {
+ @Override
+ public void onPacketSending(PacketEvent event) {
+ PacketContainer packet = event.getPacket();
+
+ Component motd = motds[ThreadLocalRandom.current().nextInt(motds.length)];
+
+ ServerStatus serverStatus = (ServerStatus) packet.getStructures().read(0).getHandle();
+
+ /* this:
+ * removes server mod prefix (Paper, Spigot, any brand)
+ * hides players
+ */
+ ServerStatus newStatus = new ServerStatus(
+ motd,
+ Optional.empty(),
+ Optional.of(new ServerStatus.Version(
+ SharedConstants.getCurrentVersion().getName(),
+ SharedConstants.getProtocolVersion()
+ )),
+ serverStatus.favicon(),
+ false
+ );
+
+ packet.getStructures().write(0, new InternalStructure(newStatus, new StructureModifier<>(ServerStatus.class)));
+ }
+ });
+ }
+}
diff --git a/src/main/java/eu/m724/tweaks/ping/F3NameListener.java b/src/main/java/eu/m724/tweaks/ping/F3NameListener.java
index ca16aa4..b53a0f9 100644
--- a/src/main/java/eu/m724/tweaks/ping/F3NameListener.java
+++ b/src/main/java/eu/m724/tweaks/ping/F3NameListener.java
@@ -4,26 +4,16 @@ import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.*;
import com.comphenix.protocol.reflect.StructureModifier;
+import net.minecraft.network.protocol.common.custom.BrandPayload;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-
public class F3NameListener {
private final Plugin plugin;
- private final Class> brandPayloadClass;
- private final Constructor> brandPayloadConstructor;
public F3NameListener(Plugin plugin) {
this.plugin = plugin;
- try {
- this.brandPayloadClass = Class.forName("net.minecraft.network.protocol.common.custom.BrandPayload");
- this.brandPayloadConstructor = brandPayloadClass.getConstructor(String.class);
- } catch (ClassNotFoundException | NoSuchMethodException e) {
- throw new BrandPayloadReflectionException(e);
- }
}
public void init() {
@@ -57,34 +47,27 @@ public class F3NameListener {
) {
@Override
public void onPacketSending(PacketEvent event) {
- try {
- PacketContainer packet = event.getPacket();
- Object brandPayload = brandPayloadConstructor.newInstance("wait");
- InternalStructure structure = new InternalStructure(brandPayload, new StructureModifier<>(brandPayloadClass));
- packet.getStructures().write(0, structure);
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new BrandPayloadReflectionException(e);
- }
+ PacketContainer packet = event.getPacket();
+
+ InternalStructure structure = new InternalStructure(
+ new BrandPayload("wait"),
+ new StructureModifier<>(BrandPayload.class)
+ );
+
+ packet.getStructures().write(0, structure);
}
});
}
private void changeBrand(Player player, String brand) {
PacketContainer packet = new PacketContainer(PacketType.Play.Server.CUSTOM_PAYLOAD);
- Object brandPayload;
- try {
- brandPayload = brandPayloadConstructor.newInstance(brand);
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
- throw new BrandPayloadReflectionException(e);
- }
- InternalStructure structure = new InternalStructure(brandPayload, new StructureModifier<>(brandPayloadClass));
+
+ InternalStructure structure = new InternalStructure(
+ new BrandPayload(brand),
+ new StructureModifier<>(BrandPayload.class)
+ );
+
packet.getStructures().write(0, structure);
ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet);
}
-
- public static class BrandPayloadReflectionException extends RuntimeException {
- public BrandPayloadReflectionException(Exception e) {
- super(e);
- }
- }
}
diff --git a/src/main/java/eu/m724/tweaks/player/MusicPlayer.java b/src/main/java/eu/m724/tweaks/player/MusicPlayer.java
new file mode 100644
index 0000000..6ce1d9f
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/player/MusicPlayer.java
@@ -0,0 +1,70 @@
+package eu.m724.tweaks.player;
+
+import de.maxhenkel.voicechat.api.BukkitVoicechatService;
+import de.maxhenkel.voicechat.api.VoicechatServerApi;
+import de.maxhenkel.voicechat.api.VolumeCategory;
+import de.maxhenkel.voicechat.api.audiochannel.AudioPlayer;
+import de.maxhenkel.voicechat.api.audiochannel.EntityAudioChannel;
+import de.maxhenkel.voicechat.api.opus.OpusEncoderMode;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.UnsupportedAudioFileException;
+import java.io.IOException;
+import java.util.UUID;
+
+public class MusicPlayer {
+ private static final String PLAYER_CATEGORY = "music_player";
+
+ private VoicechatServerApi voicechat = null;
+
+ private final Plugin plugin;
+
+ public MusicPlayer(Plugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public void init() {
+ BukkitVoicechatService service = plugin.getServer().getServicesManager().load(BukkitVoicechatService.class);
+ service.registerPlugin(new MyVoicechatPlugin(this));
+ }
+
+ void unlock(VoicechatServerApi voicechat) {
+ VolumeCategory category = voicechat.volumeCategoryBuilder()
+ .setId(PLAYER_CATEGORY)
+ .setName("Music players")
+ .build();
+
+ voicechat.registerVolumeCategory(category);
+
+ this.voicechat = voicechat;
+ }
+
+ public void create(Player player) {
+ UUID channelID = UUID.randomUUID();
+ EntityAudioChannel channel = voicechat.createEntityAudioChannel(channelID, voicechat.fromEntity(player));
+
+ channel.setCategory(PLAYER_CATEGORY);
+ channel.setDistance(10);
+
+ short[] arr;
+ try {
+ AudioInputStream audio = AudioSystem.getAudioInputStream(plugin.getResource("music.flac"));
+ int samples = (int) (audio.available() / audio.getFrameLength());
+ arr = new short[samples];
+ for (int i=0; i