mirror of
https://github.com/ayunami2000/ayunEagVidMap.git
synced 2024-10-03 05:56:01 -07:00
Initial commit
This commit is contained in:
commit
959f6da907
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
.idea/
|
||||
lib/
|
||||
target/classes/
|
||||
target/generated-sources/
|
||||
target/maven-archiver/
|
||||
target/maven-status/
|
||||
ayunEagVidMap.iml
|
||||
run/
|
25
pom.xml
Normal file
25
pom.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.ayunami2000</groupId>
|
||||
<artifactId>ayunEagVidMap</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>dont.care</groupId>
|
||||
<artifactId>didnt-ask</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/lib/craftbukkit-1.5.2-R1.0.jar</systemPath>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
111
src/main/java/me/ayunami2000/ayunEagVidMap/Main.java
Normal file
111
src/main/java/me/ayunami2000/ayunEagVidMap/Main.java
Normal file
|
@ -0,0 +1,111 @@
|
|||
package me.ayunami2000.ayunEagVidMap;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class Main extends JavaPlugin implements CommandExecutor, Listener {
|
||||
private boolean playing = false;
|
||||
private VideoMapPacketCodecBukkit videoMapCodec = null;
|
||||
private int[][] mapIds;
|
||||
private Location audioLoc;
|
||||
private String url;
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
this.saveDefaultConfig();
|
||||
this.getCommand("ayunvid").setExecutor(this);
|
||||
int width = this.getConfig().getInt("width");
|
||||
int height = this.getConfig().getInt("width");
|
||||
mapIds = new int[height][width];
|
||||
int offset = this.getConfig().getInt("offset");
|
||||
for (int y = 0; y < mapIds.length; y++) {
|
||||
for (int x = 0; x < mapIds[y].length; x++) {
|
||||
mapIds[y][x] = offset++;
|
||||
}
|
||||
}
|
||||
audioLoc.setX(this.getConfig().getDouble("audio.x"));
|
||||
audioLoc.setY(this.getConfig().getDouble("audio.y"));
|
||||
audioLoc.setZ(this.getConfig().getDouble("audio.z"));
|
||||
videoMapCodec = new VideoMapPacketCodecBukkit(mapIds, audioLoc.getX(), audioLoc.getY(), audioLoc.getZ(), 0.5f);
|
||||
url = this.getConfig().getString("url");
|
||||
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
|
||||
for (Player player : this.getServer().getOnlinePlayers()) {
|
||||
VideoMapPacketCodecBukkit.nativeSendPacketToPlayer(player, videoMapCodec.syncPlaybackWithPlayersBukkit());
|
||||
}
|
||||
}, 10000, 10000); // sync every 10 seconds
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable(){
|
||||
videoMapCodec.disableVideoBukkit();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
if (playing) {
|
||||
VideoMapPacketCodecBukkit.nativeSendPacketToPlayer(event.getPlayer(), videoMapCodec.);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length == 0){
|
||||
sender.sendMessage("usage");
|
||||
return true;
|
||||
}
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "u":
|
||||
case "url":
|
||||
if (args.length < 2) {
|
||||
sender.sendMessage("no url specified!");
|
||||
break;
|
||||
}
|
||||
this.getConfig().set("url", args[1]);
|
||||
this.saveConfig();
|
||||
sender.sendMessage("seturl");
|
||||
break;
|
||||
case "l":
|
||||
case "loc":
|
||||
case "location":
|
||||
sender.sendMessage("set location of audio");
|
||||
break;
|
||||
case "p":
|
||||
case "play":
|
||||
case "pause":
|
||||
sender.sendMessage("resuming & loading if needed, or pausing");
|
||||
|
||||
new VideoMapPacketCodecBukkit()
|
||||
break;
|
||||
case "s":
|
||||
case "size":
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage("must specify width & height to set! current vals are...");
|
||||
break;
|
||||
}
|
||||
int width;
|
||||
int height;
|
||||
try {
|
||||
width = Math.max(1, Integer.parseInt(args[1]));
|
||||
height = Math.max(1, Integer.parseInt(args[2]));
|
||||
} catch(NumberFormatException e) {
|
||||
sender.sendMessage("");
|
||||
break;
|
||||
}
|
||||
this.getConfig().set("width", width);
|
||||
this.getConfig().set("height", height);
|
||||
this.saveConfig();
|
||||
sender.sendMessage("set width & height");
|
||||
break;
|
||||
default:
|
||||
sender.sendMessage("invalid");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
package me.ayunami2000.ayunEagVidMap;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class VideoMapPacketCodec {
|
||||
|
||||
public final int[][] mapIds;
|
||||
private boolean loop;
|
||||
private String url;
|
||||
private int duration;
|
||||
private long timestamp;
|
||||
private long pauseTimestamp;
|
||||
private double posX;
|
||||
private double posY;
|
||||
private double posZ;
|
||||
private float volume;
|
||||
private int frameRate;
|
||||
private boolean requiresFullResetPacket;
|
||||
private boolean requiresPositionPacket;
|
||||
private boolean isDisabled;
|
||||
|
||||
/**
|
||||
* @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 VideoMapPacketCodec(int[][] mapIds, double posX, double posY, double posZ, float volume) {
|
||||
this.mapIds = mapIds;
|
||||
this.url = null;
|
||||
this.posX = posX;
|
||||
this.posY = posY;
|
||||
this.posZ = posZ;
|
||||
this.volume = 1.0f;
|
||||
this.frameRate = 60;
|
||||
this.requiresPositionPacket = true;
|
||||
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
|
||||
* @param posY audio playback Y coord
|
||||
* @param posZ audio playback Z coord
|
||||
*/
|
||||
public VideoMapPacketCodec(int[][] mapIds, double posX, double posY, double posZ) {
|
||||
this(mapIds, posX, posY, posZ, 1.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 byte[] moveAudioSource(double posX, double posY, double posZ, float volume) {
|
||||
this.posX = posX;
|
||||
this.posY = posY;
|
||||
this.posZ = posZ;
|
||||
this.volume = volume;
|
||||
this.requiresPositionPacket = true;
|
||||
return syncPlaybackWithPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* unloads video and resets all map object to vanilla renderer
|
||||
* @return packet to send to players
|
||||
*/
|
||||
public byte[] disableVideo() {
|
||||
isDisabled = true;
|
||||
return syncPlaybackWithPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* syncs the server side video timestamp with players
|
||||
* @return packet to send to players
|
||||
*/
|
||||
public byte[] syncPlaybackWithPlayers() {
|
||||
try {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
DataOutputStream str = new DataOutputStream(bao);
|
||||
|
||||
if(isDisabled) {
|
||||
str.write(0);
|
||||
int x = mapIds[0].length;
|
||||
int y = mapIds.length;
|
||||
str.write((x << 4) | y);
|
||||
for(int yy = 0; yy < y; ++yy) {
|
||||
for(int xx = 0; xx < x; ++xx) {
|
||||
str.writeShort(mapIds[yy][xx]);
|
||||
}
|
||||
}
|
||||
return bao.toByteArray();
|
||||
}
|
||||
|
||||
int packetType = 1;
|
||||
if(requiresFullResetPacket) {
|
||||
packetType = packetType | 2;
|
||||
}
|
||||
if(requiresFullResetPacket || requiresPositionPacket) {
|
||||
packetType = packetType | 4;
|
||||
}
|
||||
|
||||
str.write(packetType);
|
||||
|
||||
if(requiresFullResetPacket) {
|
||||
int x = mapIds[0].length;
|
||||
int y = mapIds.length;
|
||||
str.write((x << 4) | y);
|
||||
for(int yy = 0; yy < y; ++yy) {
|
||||
for(int xx = 0; xx < x; ++xx) {
|
||||
str.writeShort(mapIds[yy][xx]);
|
||||
}
|
||||
}
|
||||
str.write(frameRate);
|
||||
str.writeInt(duration);
|
||||
str.writeUTF(url);
|
||||
}
|
||||
|
||||
if(requiresFullResetPacket || requiresPositionPacket) {
|
||||
str.writeFloat(volume);
|
||||
str.writeDouble(posX);
|
||||
str.writeDouble(posY);
|
||||
str.writeDouble(posZ);
|
||||
}
|
||||
|
||||
str.writeInt(getElapsedMillis());
|
||||
str.writeBoolean(loop);
|
||||
str.writeBoolean(pauseTimestamp > 0l);
|
||||
|
||||
requiresFullResetPacket = false;
|
||||
requiresPositionPacket = false;
|
||||
|
||||
return bao.toByteArray();
|
||||
}catch(IOException e) {
|
||||
throw new RuntimeException("serialization error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this is dual purpose, it calculates elapsed time but also loops or pauses the video if it is finished playing
|
||||
*/
|
||||
private int getElapsedMillis() {
|
||||
if(pauseTimestamp > 0l) {
|
||||
return (int)(pauseTimestamp - timestamp);
|
||||
}
|
||||
int t = (int)(System.currentTimeMillis() - timestamp);
|
||||
if(loop) {
|
||||
while(t > duration) {
|
||||
t -= duration;
|
||||
timestamp += duration;
|
||||
}
|
||||
}else {
|
||||
if(t > duration) {
|
||||
timestamp = (int)(System.currentTimeMillis() - duration);
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 byte[] beginPlayback(String url, boolean loop, float duration) {
|
||||
this.url = url;
|
||||
this.loop = loop;
|
||||
this.duration = (int)(duration * 1000.0f);
|
||||
this.pauseTimestamp = 0l;
|
||||
this.timestamp = 0l;
|
||||
this.requiresFullResetPacket = true;
|
||||
this.isDisabled = false;
|
||||
return syncPlaybackWithPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the duration of the current clip
|
||||
*/
|
||||
public float getDuration() {
|
||||
return duration * 0.001f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the URL of the current clip
|
||||
*/
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the server's current timestamp
|
||||
*/
|
||||
public float getPlaybackTime() {
|
||||
return getElapsedMillis() * 0.001f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param time time in seconds to seek the video to
|
||||
*/
|
||||
public byte[] setPlaybackTime(float time) {
|
||||
timestamp = System.currentTimeMillis() - (int)(time * 1000.0f);
|
||||
return syncPlaybackWithPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if playback is complete (false if loop)
|
||||
*/
|
||||
public boolean isPlaybackFinished() {
|
||||
return !loop && getElapsedMillis() == duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param loop video should loop
|
||||
*/
|
||||
public byte[] setLoopEnable(boolean loop) {
|
||||
this.loop = loop;
|
||||
return syncPlaybackWithPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if loop is enabled
|
||||
*/
|
||||
public boolean isLoopEnable() {
|
||||
return loop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pause set if video should pause
|
||||
* @return packet to send to players
|
||||
*/
|
||||
public byte[] setPaused(boolean pause) {
|
||||
getElapsedMillis();
|
||||
if(pause && pauseTimestamp <= 0l) {
|
||||
pauseTimestamp = System.currentTimeMillis();
|
||||
}else if(!pause && pauseTimestamp > 0l) {
|
||||
timestamp = System.currentTimeMillis() - (pauseTimestamp - timestamp);
|
||||
pauseTimestamp = 0l;
|
||||
}
|
||||
return syncPlaybackWithPlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if video is currently paused
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return pauseTimestamp > 0l;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
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<Player> 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);
|
||||
}
|
||||
}
|
12
src/main/resources/config.yml
Normal file
12
src/main/resources/config.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
# URL of video to play
|
||||
url: ""
|
||||
# screen size
|
||||
width: 3
|
||||
height: 2
|
||||
# map ID offset
|
||||
offset: 0
|
||||
# audio location
|
||||
audio:
|
||||
x: 0
|
||||
y: 100
|
||||
z: 0
|
9
src/main/resources/plugin.yml
Normal file
9
src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,9 @@
|
|||
name: ayunEagVidMap
|
||||
version: 1.0
|
||||
main: me.ayunami2000.ayunEagVidMap.Main
|
||||
commands:
|
||||
ayunvid:
|
||||
description: Control ayunEagVidMap
|
||||
usage: /<command>
|
||||
permission: ayuneagvidmap.control
|
||||
#todo: separate play, pause, and add queue
|
Loading…
Reference in New Issue
Block a user