diff --git a/src/main/java/me/ayunami2000/ayunEagVidMap/Main.java b/src/main/java/me/ayunami2000/ayunEagVidMap/Main.java index f75e47e..adc921e 100644 --- a/src/main/java/me/ayunami2000/ayunEagVidMap/Main.java +++ b/src/main/java/me/ayunami2000/ayunEagVidMap/Main.java @@ -1,9 +1,12 @@ package me.ayunami2000.ayunEagVidMap; +import net.minecraft.server.v1_5_R3.Packet; +import net.minecraft.server.v1_5_R3.Packet131ItemData; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.v1_5_R3.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -18,7 +21,7 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { public static Main plugin; - private VideoMapPacketCodecBukkit videoMapCodec = null; + private VideoMapPacketCodec videoMapCodec = null; private Vector audioLoc = new Vector(0, 100, 0); private String url = ""; private boolean urlChanged = true; @@ -27,6 +30,7 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { private int mapOffset = 0; private int interval = 10; private int syncTask = -1; + private boolean imageMode = false; @Override public void onLoad(){ @@ -43,7 +47,7 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { @Override public void onDisable(){ - sendToAllPlayers(videoMapCodec.disableVideoBukkit()); + if (videoMapCodec.mapIds != null) sendToAllPlayers(videoMapCodec.disableVideo()); } private void stopSyncTask() { @@ -67,20 +71,21 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { setSize(this.getConfig().getInt("size.width"), this.getConfig().getInt("size.height")); url = this.getConfig().getString("url"); interval = this.getConfig().getInt("interval"); + imageMode = this.getConfig().getBoolean("image"); stopSyncTask(); createSyncTask(); } private void syncToPlayer(Player player) { - videoMapCodec.syncPlaybackWithPlayersBukkit().send(player); + freePacketSender(player, videoMapCodec.syncPlaybackWithPlayers()); } private void syncToAllPlayers() { - videoMapCodec.syncPlaybackWithPlayersBukkit().send(this.getServer().getOnlinePlayers()); + sendToAllPlayers(videoMapCodec.syncPlaybackWithPlayers()); } - private void sendToAllPlayers(VideoMapPacketCodecBukkit.VideoMapPacket p) { - p.send(this.getServer().getOnlinePlayers()); + private void sendToAllPlayers(byte[] p) { + for (Player player : this.getServer().getOnlinePlayers()) freePacketSender(player, p); } private void setSize(int width, int height) { @@ -97,14 +102,14 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { mapIds[y][x] = offset++; } } - videoMapCodec = new VideoMapPacketCodecBukkit(mapIds, audioLoc.getX(), audioLoc.getY(), audioLoc.getZ(), 0.5f); + videoMapCodec = new VideoMapPacketCodec(mapIds, audioLoc.getX(), audioLoc.getY(), audioLoc.getZ(), 0.5f); } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { if (videoMapCodec != null && videoMapCodec.getURL() != null) { Player player = event.getPlayer(); - videoMapCodec.beginPlaybackBukkit(videoMapCodec.getURL(), videoMapCodec.isLoopEnable(), videoMapCodec.getDuration()).send(player); + freePacketSender(player, videoMapCodec.beginPlayback(videoMapCodec.getURL() == null ? "" : videoMapCodec.getURL(), videoMapCodec.isLoopEnable(), videoMapCodec.getDuration())); syncToPlayer(player); } } @@ -116,6 +121,15 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { return true; } switch (args[0].toLowerCase()) { + case "m": + case "mode": + sendToAllPlayers(videoMapCodec.disableVideo()); + imageMode = !imageMode; + sendToAllPlayers(videoMapCodec.beginPlayback(videoMapCodec.getURL() == null ? "" : videoMapCodec.getURL(), videoMapCodec.isLoopEnable(), videoMapCodec.getDuration())); + this.getConfig().set("image", imageMode); + this.saveConfig(); + MessageHandler.sendPrefixedMessage(sender, "mode", imageMode ? MessageHandler.getMessage("image") : MessageHandler.getMessage("video")); + break; case "rl": case "reload": this.reloadConfig(); @@ -174,8 +188,8 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { this.getConfig().set("audio.z", audioLoc.getZ()); this.saveConfig(); float ct = videoMapCodec.getPlaybackTime(); - sendToAllPlayers(videoMapCodec.moveAudioSourceBukkit(audioLoc.getX(), audioLoc.getY(), audioLoc.getZ(), 0.5f)); - sendToAllPlayers(videoMapCodec.setPlaybackTimeBukkit(ct)); + sendToAllPlayers(videoMapCodec.moveAudioSource(audioLoc.getX(), audioLoc.getY(), audioLoc.getZ(), 0.5f)); + sendToAllPlayers(videoMapCodec.setPlaybackTime(ct)); MessageHandler.sendPrefixedMessage(sender, "locSet", audioLoc); break; case "p": @@ -186,14 +200,14 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { if (urlChanged) { urlChanged = false; MessageHandler.sendPrefixedMessage(sender, "playing"); - sendToAllPlayers(videoMapCodec.beginPlaybackBukkit(url, true, Integer.MAX_VALUE / 1000.0f)); + sendToAllPlayers(videoMapCodec.beginPlayback(url, true, Integer.MAX_VALUE / 1000.0f)); } else { MessageHandler.sendPrefixedMessage(sender, "resuming"); } - sendToAllPlayers(videoMapCodec.setPausedBukkit(false)); + sendToAllPlayers(videoMapCodec.setPaused(false)); } else { MessageHandler.sendPrefixedMessage(sender, "pausing"); - sendToAllPlayers(videoMapCodec.setPausedBukkit(true)); + sendToAllPlayers(videoMapCodec.setPaused(true)); } break; case "s": @@ -213,7 +227,7 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { MessageHandler.sendPrefixedMessage(sender, "notANumber", args[offendingIndex], MessageHandler.getMessage("integer")); break; } - sendToAllPlayers(videoMapCodec.disableVideoBukkit()); + sendToAllPlayers(videoMapCodec.disableVideo()); setSize(width, height); syncToAllPlayers(); this.getConfig().set("size.width", mapSize[0]); @@ -242,4 +256,15 @@ public class Main extends JavaPlugin implements CommandExecutor, Listener { } return true; } + + private void freePacketSender(Player player, byte[] packet) { + nativeSendPacketToPlayer(player, new Packet131ItemData((short)(104 + (imageMode ? 1 : 0)), (short)0, packet)); + } + + private static void nativeSendPacketToPlayer(Player player, Object obj) { + if(obj == null) { + return; + } + ((CraftPlayer)player).getHandle().playerConnection.sendPacket((Packet)obj); + } } diff --git a/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodec.java b/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodec.java index 11798ba..055378e 100644 --- a/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodec.java +++ b/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodec.java @@ -40,7 +40,7 @@ public class VideoMapPacketCodec { this.requiresFullResetPacket = true; this.isDisabled = true; } - + /** * @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x]) * @param posX audio playback X coord @@ -48,7 +48,14 @@ public class VideoMapPacketCodec { * @param posZ audio playback Z coord */ public VideoMapPacketCodec(int[][] mapIds, double posX, double posY, double posZ) { - this(mapIds, posX, posY, posZ, 1.0f); + this(mapIds, posX, posY, posZ, 0.5f); + } + + /** + * @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x]) + */ + public VideoMapPacketCodec(int[][] mapIds) { + this(mapIds, 0, 100, 0, 0.5f); } /** @@ -119,7 +126,7 @@ public class VideoMapPacketCodec { } str.write(frameRate); str.writeInt(duration); - str.writeUTF(url); + str.writeUTF(url == null ? "" : url); } if(requiresFullResetPacket || requiresPositionPacket) { @@ -163,7 +170,7 @@ public class VideoMapPacketCodec { } return t; } - + /** * @param url URL to an MP4 or other HTML5 supported video file * @param loop If the video file should loop @@ -180,6 +187,40 @@ public class VideoMapPacketCodec { this.isDisabled = false; return syncPlaybackWithPlayers(); } + + /** + * @param url URL to an MP4 or other HTML5 supported video file + * @return packet to send to players + */ + public byte[] beginPlayback(String url) { + this.url = url; + this.loop = false; + this.duration = 0; + this.pauseTimestamp = 0l; + this.timestamp = 0l; + this.requiresFullResetPacket = true; + this.isDisabled = false; + return syncPlaybackWithPlayers(); + } + + /** + * Tells the browser to pre-load a URL to a video to be played in the future + * @param url the URL of the video + * @param ttl the amount of time the video should stay loaded + * @return packet to send to players + */ + public static byte[] bufferVideo(String url, int ttl) { + try { + ByteArrayOutputStream bao = new ByteArrayOutputStream(); + DataOutputStream str = new DataOutputStream(bao); + str.write(8); + str.writeInt(ttl); + str.writeUTF(url); + return bao.toByteArray(); + }catch(IOException e) { + throw new RuntimeException("serialization error", e); + } + } /** * @return the duration of the current clip @@ -254,4 +295,11 @@ public class VideoMapPacketCodec { return pauseTimestamp > 0l; } + /** + * @return current server-side volume + */ + public float getVolume() { + return volume; + } + } diff --git a/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodecBukkit.java b/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodecBukkit.java deleted file mode 100644 index 14bd6c9..0000000 --- a/src/main/java/me/ayunami2000/ayunEagVidMap/VideoMapPacketCodecBukkit.java +++ /dev/null @@ -1,122 +0,0 @@ -package me.ayunami2000.ayunEagVidMap; - -import java.util.List; - -import org.bukkit.craftbukkit.v1_5_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import net.minecraft.server.v1_5_R3.Packet; -import net.minecraft.server.v1_5_R3.Packet131ItemData; - -public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec { - - /** - * @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x]) - * @param posX audio playback X coord - * @param posY audio playback Y coord - * @param posZ audio playback Z coord - * @param volume the volume of the clip - */ - public VideoMapPacketCodecBukkit(int[][] mapIds, double posX, double posY, double posZ, float volume) { - super(mapIds, posX, posY, posZ, volume); - } - - /** - * @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x]) - * @param posX audio playback X coord - * @param posY audio playback Y coord - * @param posZ audio playback Z coord - */ - public VideoMapPacketCodecBukkit(int[][] mapIds, double posX, double posY, double posZ) { - super(mapIds, posX, posY, posZ, 1.0f); - } - - public class VideoMapPacket { - protected final Object packet; - protected VideoMapPacket(byte[] packet) { - this.packet = new Packet131ItemData((short)104, (short)0, packet); - } - public Object getNativePacket() { - return packet; - } - public void send(Player p) { - nativeSendPacketToPlayer(p, packet); - } - public void send(Player... p) { - for(Player pp : p) { - nativeSendPacketToPlayer(pp, packet); - } - } - public void send(List p) { - for(Player pp : p) { - nativeSendPacketToPlayer(pp, packet); - } - } - } - - /** - * @param posX audio playback X coord - * @param posY audio playback Y coord - * @param posZ audio playback Z coord - * @param volume the volume of the clip - * @return packet to send to players - */ - public VideoMapPacket moveAudioSourceBukkit(double posX, double posY, double posZ, float volume) { - return new VideoMapPacket(moveAudioSource(posX, posY, posZ, volume)); - } - - /** - * unloads video and resets all map object to vanilla renderer - * @return packet to send to players - */ - public VideoMapPacket disableVideoBukkit() { - return new VideoMapPacket(disableVideo()); - } - - /** - * syncs the server side video timestamp with players - * @return packet to send to players - */ - public VideoMapPacket syncPlaybackWithPlayersBukkit() { - return new VideoMapPacket(syncPlaybackWithPlayers()); - } - - /** - * @param url URL to an MP4 or other HTML5 supported video file - * @param loop If the video file should loop - * @param duration duration of the video in seconds - * @return packet to send to players - */ - public VideoMapPacket beginPlaybackBukkit(String url, boolean loop, float duration) { - return new VideoMapPacket(beginPlayback(url, loop, duration)); - } - - /** - * @param time time in seconds to seek the video to - */ - public VideoMapPacket setPlaybackTimeBukkit(float time) { - return new VideoMapPacket(setPlaybackTime(time)); - } - - /** - * @param loop video should loop - */ - public VideoMapPacket setLoopEnableBukkit(boolean loop) { - return new VideoMapPacket(setLoopEnable(loop)); - } - - /** - * @param pause set if video should pause - * @return packet to send to players - */ - public VideoMapPacket setPausedBukkit(boolean pause) { - return new VideoMapPacket(setPaused(pause)); - } - - public static void nativeSendPacketToPlayer(Player player, Object obj) { - if(obj == null) { - return; - } - ((CraftPlayer)player).getHandle().playerConnection.sendPacket((Packet)obj); - } -} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6e325b8..4a769ac 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -14,4 +14,8 @@ interval: 10 audio: x: 0 y: 100 - z: 0 \ No newline at end of file + z: 0 +# image mode +image: false +# autoplay +autoplay: false \ No newline at end of file diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index b6e217d..a55d63c 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -8,6 +8,7 @@ usage: - "&7&o/ayunvid [ ] &3- Sets or gets the size of video, in maps. E.g., a width of 2 and a height of 3 would result in a video using 6 maps." - "&7&o/ayunvid &3- Reloads the configuration file." - "&7&o/ayunvid &3- Set the sync interval, in seconds, or 0 to disable." + - "&7&o/ayunvid &3- Switch between image mode and video mode." currentUrl: "&3Current URL: {0}" setUrl: "&3Successfully set URL." locFromConsole: "&cError: You must specify the coordinates when running this command from the console!" @@ -24,4 +25,7 @@ setSize: "&3Set size to {0} maps wide by {1} maps tall ({2} maps total)" invalidUsage: "&cError: That is not a valid subcommand! Try &n/ayunvid&c help for usage." reloaded: "&3Successfully reloaded configuration!" currentInterval: "&3Current sync interval: {0} seconds" -setInterval: "&3Successfully set or disabled sync interval." \ No newline at end of file +setInterval: "&3Successfully set or disabled sync interval." +mode: "&3Now using {0}." +image: "an image" +video: "video" \ No newline at end of file diff --git a/target/ayunEagVidMap-1.0-SNAPSHOT.jar b/target/ayunEagVidMap-1.0-SNAPSHOT.jar index acb122a..2a0421f 100644 Binary files a/target/ayunEagVidMap-1.0-SNAPSHOT.jar and b/target/ayunEagVidMap-1.0-SNAPSHOT.jar differ