Added my code and the build
This commit is contained in:
parent
56b8d24117
commit
d6ce6a59c3
60 changed files with 1451 additions and 0 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
36
build/classes/java/main/song-player-refmap.json
Normal file
36
build/classes/java/main/song-player-refmap.json
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"mappings": {
|
||||
"com/github/hhhzzzsss/songplayer/mixin/KeyboardMixin": {
|
||||
"onKey(JIIII)V": "Lnet/minecraft/class_309;method_1466(JIIII)V"
|
||||
},
|
||||
"com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin": {
|
||||
"sendPacket(Lnet/minecraft/network/Packet;)V": "Lnet/minecraft/class_634;method_2883(Lnet/minecraft/class_2596;)V",
|
||||
"onBlockUpdate(Lnet/minecraft/network/packet/s2c/play/BlockUpdateS2CPacket;)V": "Lnet/minecraft/class_634;method_11136(Lnet/minecraft/class_2626;)V",
|
||||
"onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V": "Lnet/minecraft/class_634;method_11120(Lnet/minecraft/class_2678;)V"
|
||||
},
|
||||
"com/github/hhhzzzsss/songplayer/mixin/ClientPlayerEntityMixin": {
|
||||
"sendChatMessage(Ljava/lang/String;)V": "Lnet/minecraft/class_746;method_3142(Ljava/lang/String;)V"
|
||||
},
|
||||
"com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin": {
|
||||
"doItemUse()V": "Lnet/minecraft/class_310;method_1583()V"
|
||||
}
|
||||
},
|
||||
"data": {
|
||||
"named:intermediary": {
|
||||
"com/github/hhhzzzsss/songplayer/mixin/KeyboardMixin": {
|
||||
"onKey(JIIII)V": "Lnet/minecraft/class_309;method_1466(JIIII)V"
|
||||
},
|
||||
"com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin": {
|
||||
"sendPacket(Lnet/minecraft/network/Packet;)V": "Lnet/minecraft/class_634;method_2883(Lnet/minecraft/class_2596;)V",
|
||||
"onBlockUpdate(Lnet/minecraft/network/packet/s2c/play/BlockUpdateS2CPacket;)V": "Lnet/minecraft/class_634;method_11136(Lnet/minecraft/class_2626;)V",
|
||||
"onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V": "Lnet/minecraft/class_634;method_11120(Lnet/minecraft/class_2678;)V"
|
||||
},
|
||||
"com/github/hhhzzzsss/songplayer/mixin/ClientPlayerEntityMixin": {
|
||||
"sendChatMessage(Ljava/lang/String;)V": "Lnet/minecraft/class_746;method_3142(Ljava/lang/String;)V"
|
||||
},
|
||||
"com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin": {
|
||||
"doItemUse()V": "Lnet/minecraft/class_310;method_1583()V"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
build/libs/song-player-1.0.0-dev.jar
Normal file
BIN
build/libs/song-player-1.0.0-dev.jar
Normal file
Binary file not shown.
BIN
build/libs/song-player-1.0.0-sources-dev.jar
Normal file
BIN
build/libs/song-player-1.0.0-sources-dev.jar
Normal file
Binary file not shown.
BIN
build/libs/song-player-1.0.0-sources.jar
Normal file
BIN
build/libs/song-player-1.0.0-sources.jar
Normal file
Binary file not shown.
BIN
build/libs/song-player-1.0.0.jar
Normal file
BIN
build/libs/song-player-1.0.0.jar
Normal file
Binary file not shown.
2
build/loom-cache/mixin-map-1.16.1-1.16.1+build.1-v2.tiny
Normal file
2
build/loom-cache/mixin-map-1.16.1-1.16.1+build.1-v2.tiny
Normal file
|
@ -0,0 +1,2 @@
|
|||
v1 named intermediary
|
||||
FIELD com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin Lnet/minecraft/network/ClientConnection; connection field_3689
|
BIN
build/resources/main/assets/songplayer/icon.png
Normal file
BIN
build/resources/main/assets/songplayer/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 453 B |
37
build/resources/main/fabric.mod.json
Normal file
37
build/resources/main/fabric.mod.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "songplayer",
|
||||
"version": "1.0.0",
|
||||
|
||||
"name": "Song Player",
|
||||
"description": "Builds and plays noteblocks",
|
||||
"authors": [
|
||||
"hhhzzzsss"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net/",
|
||||
"sources": "https://github.com/FabricMC/fabric-example-mod"
|
||||
},
|
||||
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/songplayer/icon.png",
|
||||
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.github.hhhzzzsss.songplayer.SongPlayer"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"songplayer.mixins.json"
|
||||
],
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric": "*",
|
||||
"minecraft": "1.16.x"
|
||||
},
|
||||
"suggests": {
|
||||
"flamingo": "*"
|
||||
}
|
||||
}
|
15
build/resources/main/songplayer.mixins.json
Normal file
15
build/resources/main/songplayer.mixins.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "com.github.hhhzzzsss.songplayer.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"ClientPlayerEntityMixin",
|
||||
"ClientPlayNetworkHandlerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
44
build/tmp/compileJava/source-classes-mapping.txt
Normal file
44
build/tmp/compileJava/source-classes-mapping.txt
Normal file
|
@ -0,0 +1,44 @@
|
|||
com/github/hhhzzzsss/songplayer/SongPlayer.java
|
||||
com.github.hhhzzzsss.songplayer.SongPlayer
|
||||
com.github.hhhzzzsss.songplayer.SongPlayer$Mode
|
||||
com/github/hhhzzzsss/songplayer/mixin/ClientPlayerEntityMixin.java
|
||||
com.github.hhhzzzsss.songplayer.mixin.ClientPlayerEntityMixin
|
||||
com/github/hhhzzzsss/songplayer/mixin/KeyboardMixin.java
|
||||
com.github.hhhzzzsss.songplayer.mixin.KeyboardMixin
|
||||
com/github/hhhzzzsss/songplayer/mixin/MinecraftClientMixin.java
|
||||
com.github.hhhzzzsss.songplayer.mixin.MinecraftClientMixin
|
||||
com/github/hhhzzzsss/songplayer/noteblocks/Stage.java
|
||||
com.github.hhhzzzsss.songplayer.noteblocks.Stage
|
||||
com/github/hhhzzzsss/songplayer/song/MidiConverter.java
|
||||
com.github.hhhzzzsss.songplayer.song.MidiConverter
|
||||
com.github.hhhzzzsss.songplayer.song.MidiConverter$1
|
||||
com/github/hhhzzzsss/songplayer/song/NoteEvent.java
|
||||
com.github.hhhzzzsss.songplayer.song.NoteEvent
|
||||
com/github/hhhzzzsss/songplayer/noteblocks/BuildingThread.java
|
||||
com.github.hhhzzzsss.songplayer.noteblocks.BuildingThread
|
||||
com/github/hhhzzzsss/songplayer/FakePlayerEntity.java
|
||||
com.github.hhhzzzsss.songplayer.FakePlayerEntity
|
||||
com/github/hhhzzzsss/songplayer/Freecam.java
|
||||
com.github.hhhzzzsss.songplayer.Freecam
|
||||
com/github/hhhzzzsss/songplayer/song/Song.java
|
||||
com.github.hhhzzzsss.songplayer.song.Song
|
||||
com/github/hhhzzzsss/songplayer/CommandProcessor.java
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$1
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$Command
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$currentCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$gotoCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$helpCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$loopCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$playCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$playurlCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$setCreativeCommandCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$setSurvivalCommandCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$songsCommand
|
||||
com.github.hhhzzzsss.songplayer.CommandProcessor$stopCommand
|
||||
com/github/hhhzzzsss/songplayer/mixin/ClientPlayNetworkHandlerMixin.java
|
||||
com.github.hhhzzzsss.songplayer.mixin.ClientPlayNetworkHandlerMixin
|
||||
com/github/hhhzzzsss/songplayer/noteblocks/PlayingThread.java
|
||||
com.github.hhhzzzsss.songplayer.noteblocks.PlayingThread
|
||||
com/github/hhhzzzsss/songplayer/song/DownloadingThread.java
|
||||
com.github.hhhzzzsss.songplayer.song.DownloadingThread
|
2
build/tmp/jar/MANIFEST.MF
Normal file
2
build/tmp/jar/MANIFEST.MF
Normal file
|
@ -0,0 +1,2 @@
|
|||
Manifest-Version: 1.0
|
||||
|
2
build/tmp/remapJar/MANIFEST.MF
Normal file
2
build/tmp/remapJar/MANIFEST.MF
Normal file
|
@ -0,0 +1,2 @@
|
|||
Manifest-Version: 1.0
|
||||
|
2
build/tmp/sourcesJar/MANIFEST.MF
Normal file
2
build/tmp/sourcesJar/MANIFEST.MF
Normal file
|
@ -0,0 +1,2 @@
|
|||
Manifest-Version: 1.0
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer.Mode;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.BuildingThread;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.Stage;
|
||||
import com.github.hhhzzzsss.songplayer.song.DownloadingThread;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
public class CommandProcessor {
|
||||
public static ArrayList<Command> commands = new ArrayList<>();
|
||||
|
||||
public static void initCommands() {
|
||||
commands.add(new helpCommand());
|
||||
commands.add(new playCommand());
|
||||
commands.add(new playurlCommand());
|
||||
commands.add(new stopCommand());
|
||||
commands.add(new gotoCommand());
|
||||
commands.add(new loopCommand());
|
||||
commands.add(new currentCommand());
|
||||
commands.add(new songsCommand());
|
||||
commands.add(new setCreativeCommandCommand());
|
||||
commands.add(new setSurvivalCommandCommand());
|
||||
}
|
||||
|
||||
// returns true if it is a command and should be cancelled
|
||||
public static boolean processChatMessage(String message) {
|
||||
if (message.startsWith("$")) {
|
||||
String[] parts = message.substring(1).split(" ", 2);
|
||||
String name = parts.length>0 ? parts[0] : "";
|
||||
String args = parts.length>1 ? parts[1] : "";
|
||||
for (Command c : commands) {
|
||||
if (c.getName().equalsIgnoreCase(name)) {
|
||||
boolean success = c.processCommand(args);
|
||||
if (!success) {
|
||||
SongPlayer.addChatMessage("§cSyntax - " + c.getSyntax());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static abstract class Command {
|
||||
public abstract String getName();
|
||||
public abstract String getSyntax();
|
||||
public abstract String getDescription();
|
||||
public abstract boolean processCommand(String args);
|
||||
}
|
||||
|
||||
private static class helpCommand extends Command {
|
||||
public String getName() {
|
||||
return "help";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$help [command]";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Lists commands or explains command";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (args.length() == 0) {
|
||||
StringBuilder helpMessage = new StringBuilder("§6Commands -");
|
||||
for (Command c : commands) {
|
||||
helpMessage.append(" $" + c.getName());
|
||||
}
|
||||
SongPlayer.addChatMessage(helpMessage.toString());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
for (Command c : commands) {
|
||||
if (c.getName().equalsIgnoreCase(args)) {
|
||||
SongPlayer.addChatMessage("§6" + c.getName() + ": " + c.getDescription() + " - " + c.getSyntax());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
SongPlayer.addChatMessage("§cCommand not recognized: " + args);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class playCommand extends Command {
|
||||
public String getName() {
|
||||
return "play";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$play <song>";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Plays a song";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.IDLE) {
|
||||
SongPlayer.addChatMessage("§cCannot do that while building or playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() > 0) {
|
||||
try {
|
||||
SongPlayer.song = Song.getSongFromFile(args);
|
||||
}
|
||||
catch (IOException e) {
|
||||
SongPlayer.addChatMessage("§cCould not find song §4" + args);
|
||||
return true;
|
||||
}
|
||||
|
||||
SongPlayer.stage = new Stage();
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
SongPlayer.mode = Mode.BUILDING;
|
||||
SongPlayer.addChatMessage("§6Starting building.");
|
||||
SongPlayer.song.position = 0;
|
||||
(new BuildingThread()).start();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class playurlCommand extends Command {
|
||||
public String getName() {
|
||||
return "playurl";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$playurl <midi url>";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Plays a song from a direct link to the midi";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.IDLE) {
|
||||
SongPlayer.addChatMessage("§cCannot do that while building or playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() > 0) {
|
||||
SongPlayer.stage = new Stage();
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
SongPlayer.addChatMessage("§6Downloading song from url");
|
||||
SongPlayer.mode = Mode.DOWNLOADING;
|
||||
(new DownloadingThread(args)).start();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class stopCommand extends Command {
|
||||
public String getName() {
|
||||
return "stop";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$stop";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Stops playing";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING && SongPlayer.mode != Mode.BUILDING) {
|
||||
SongPlayer.addChatMessage("§6No song is currently playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() == 0) {
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
SongPlayer.mode = Mode.IDLE;
|
||||
SongPlayer.song.loop = false;
|
||||
SongPlayer.addChatMessage("§6Stopped playing");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class gotoCommand extends Command {
|
||||
public String getName() {
|
||||
return "goto";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$goto <mm:ss>";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Goes to a specific time in the song";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING) {
|
||||
SongPlayer.addChatMessage("§cNo song is currently playing");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length() > 0) {
|
||||
Pattern timestamp_pattern = Pattern.compile("(\\d+):(\\d+)");
|
||||
Matcher timestamp_matcher = timestamp_pattern.matcher(args);
|
||||
|
||||
if (timestamp_matcher.matches()) {
|
||||
String minutes = timestamp_matcher.group(1);
|
||||
String seconds = timestamp_matcher.group(2);
|
||||
SongPlayer.song.gotoTime = Integer.parseInt(minutes)*60*1000 + Integer.parseInt(seconds)*1000;
|
||||
System.out.println("set time to " + SongPlayer.song.gotoTime);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
SongPlayer.addChatMessage("§cNot a valid time stamp");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class loopCommand extends Command {
|
||||
public String getName() {
|
||||
return "loop";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$loop";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Toggles song looping";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING) {
|
||||
SongPlayer.addChatMessage("§cNo song is currently playing");
|
||||
return true;
|
||||
}
|
||||
|
||||
SongPlayer.song.loop = !SongPlayer.song.loop;
|
||||
if (SongPlayer.song.loop) {
|
||||
SongPlayer.addChatMessage("§6Enabled looping");
|
||||
}
|
||||
else {
|
||||
SongPlayer.addChatMessage("§6Disabled looping");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class currentCommand extends Command {
|
||||
public String getName() {
|
||||
return "current";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$current";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Gets the song that is currently playing";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (SongPlayer.mode != Mode.PLAYING) {
|
||||
SongPlayer.addChatMessage("§6No song is currently playing");
|
||||
return true;
|
||||
}
|
||||
if (args.length() == 0) {
|
||||
int currTime = (int) (SongPlayer.song.get(SongPlayer.song.position).time/1000);
|
||||
int totTime = (int) (SongPlayer.song.get(SongPlayer.song.size()-1).time/1000);
|
||||
int currTimeSeconds = currTime % 60;
|
||||
int totTimeSeconds = totTime % 60;
|
||||
int currTimeMinutes = currTime / 60;
|
||||
int totTimeMinutes = totTime / 60;
|
||||
SongPlayer.addChatMessage(String.format("§6Currently playing %s §3(%d:%02d/%d:%02d)", SongPlayer.song.name, currTimeMinutes, currTimeSeconds, totTimeMinutes, totTimeSeconds));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class songsCommand extends Command {
|
||||
public String getName() {
|
||||
return "songs";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$songs";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Lists available songs";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (args.length() == 0) {
|
||||
StringBuilder sb = new StringBuilder("§6");
|
||||
boolean firstItem = true;
|
||||
for (File songFile : SongPlayer.SONG_DIR.listFiles()) {
|
||||
String fileName = songFile.getName();
|
||||
if (firstItem) {
|
||||
firstItem = false;
|
||||
}
|
||||
else {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(fileName);
|
||||
}
|
||||
SongPlayer.addChatMessage(sb.toString());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class setCreativeCommandCommand extends Command {
|
||||
public String getName() {
|
||||
return "setCreativeCommand";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$setCreativeCommand";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Sets the command used to go into creative mode";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (args.length() > 0) {
|
||||
SongPlayer.creativeCommand = args;
|
||||
SongPlayer.addChatMessage("Set creative command to " + SongPlayer.creativeCommand);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class setSurvivalCommandCommand extends Command {
|
||||
public String getName() {
|
||||
return "setSurvivalCommand";
|
||||
}
|
||||
public String getSyntax() {
|
||||
return "$setSurvivalCommand";
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Sets the command used to go into survival mode";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (args.length() > 0) {
|
||||
SongPlayer.survivalCommand = args;
|
||||
SongPlayer.addChatMessage("Set survival command to " + SongPlayer.survivalCommand);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.network.OtherClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
public class FakePlayerEntity extends OtherClientPlayerEntity {
|
||||
ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
ClientWorld world = SongPlayer.MC.world;
|
||||
|
||||
public FakePlayerEntity() {
|
||||
super(SongPlayer.MC.world, SongPlayer.MC.player.getGameProfile());
|
||||
|
||||
copyPositionAndRotation(player);
|
||||
|
||||
inventory.clone(player.inventory);
|
||||
|
||||
Byte playerModel = player.getDataTracker().get(PlayerEntity.PLAYER_MODEL_PARTS);
|
||||
getDataTracker().set(PlayerEntity.PLAYER_MODEL_PARTS, playerModel);
|
||||
|
||||
headYaw = player.headYaw;
|
||||
bodyYaw = player.bodyYaw;
|
||||
|
||||
capeX = getX();
|
||||
capeY = getY();
|
||||
capeZ = getZ();
|
||||
|
||||
world.addEntity(getEntityId(), this);
|
||||
}
|
||||
|
||||
public void resetPlayerPosition() {
|
||||
player.refreshPositionAndAngles(getX(), getY(), getZ(), yaw, pitch);
|
||||
}
|
||||
}
|
58
src/main/java/com/github/hhhzzzsss/songplayer/Freecam.java
Normal file
58
src/main/java/com/github/hhhzzzsss/songplayer/Freecam.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class Freecam {
|
||||
private static Freecam instance = null;
|
||||
public static Freecam getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Freecam();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
boolean enabled = false;
|
||||
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
private FakePlayerEntity fakePlayer;
|
||||
|
||||
private Freecam() {
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
enabled = true;
|
||||
fakePlayer = new FakePlayerEntity();
|
||||
SongPlayer.addChatMessage("Freecam is enabled");
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
enabled = false;
|
||||
if (fakePlayer != null) {
|
||||
fakePlayer.resetPlayerPosition();
|
||||
fakePlayer.remove();
|
||||
fakePlayer = null;
|
||||
player.setVelocity(Vec3d.ZERO);
|
||||
}
|
||||
SongPlayer.addChatMessage("Freecam is disabled");
|
||||
}
|
||||
|
||||
public void onGameJoin() {
|
||||
enabled = false;
|
||||
fakePlayer = null;
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
if (enabled) {
|
||||
disable();
|
||||
}
|
||||
else {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.github.hhhzzzsss.songplayer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.Stage;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.text.LiteralText;
|
||||
|
||||
public class SongPlayer implements ModInitializer {
|
||||
|
||||
public static final MinecraftClient MC = MinecraftClient.getInstance();
|
||||
Freecam freecam;
|
||||
|
||||
public static final File SONG_DIR = new File("songs");
|
||||
public static Song song;
|
||||
public static Stage stage;
|
||||
public static String creativeCommand = "/gmc";
|
||||
public static String survivalCommand = "/gms";
|
||||
|
||||
public static enum Mode {
|
||||
IDLE,
|
||||
BUILDING,
|
||||
PLAYING,
|
||||
DOWNLOADING,
|
||||
}
|
||||
public static Mode mode = Mode.IDLE;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
if (!SONG_DIR.exists()) {
|
||||
SONG_DIR.mkdir();
|
||||
}
|
||||
|
||||
freecam = Freecam.getInstance();
|
||||
CommandProcessor.initCommands();
|
||||
}
|
||||
|
||||
public static void addChatMessage(String message) {
|
||||
MC.player.sendMessage(new LiteralText(message), false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.play.BlockUpdateS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
|
||||
@Mixin(ClientPlayNetworkHandler.class)
|
||||
public class ClientPlayNetworkHandlerMixin {
|
||||
@Shadow
|
||||
private final ClientConnection connection;
|
||||
|
||||
public ClientPlayNetworkHandlerMixin() {
|
||||
connection = null;
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "sendPacket(Lnet/minecraft/network/Packet;)V", cancellable = true)
|
||||
private void onSendPacket(Packet<?> packet, CallbackInfo ci) {
|
||||
/*if (Freecam.getInstance().isEnabled() && packet instanceof PlayerMoveC2SPacket) {
|
||||
ci.cancel();
|
||||
}*/
|
||||
if (SongPlayer.mode != SongPlayer.Mode.IDLE && packet instanceof PlayerMoveC2SPacket) {
|
||||
connection.send(new PlayerMoveC2SPacket.Both(SongPlayer.stage.position.getX()+0.5, SongPlayer.stage.position.getY(), SongPlayer.stage.position.getZ()+0.5, SongPlayer.MC.player.yaw, SongPlayer.MC.player.pitch, true));
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "onGameJoin(Lnet/minecraft/network/packet/s2c/play/GameJoinS2CPacket;)V")
|
||||
public void onOnGameJoin(GameJoinS2CPacket packet, CallbackInfo ci) {
|
||||
//Freecam.getInstance().onGameJoin();
|
||||
SongPlayer.mode = SongPlayer.Mode.IDLE;
|
||||
}
|
||||
|
||||
@Inject(at = @At("HEAD"), method = "onBlockUpdate(Lnet/minecraft/network/packet/s2c/play/BlockUpdateS2CPacket;)V")
|
||||
public void onOnBlockUpdate(BlockUpdateS2CPacket packet, CallbackInfo ci) {
|
||||
if (SongPlayer.mode == SongPlayer.Mode.PLAYING && SongPlayer.stage.noteblockPositions.contains(packet.getPos())) {
|
||||
SongPlayer.stage.rebuild = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.CommandProcessor;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public class ClientPlayerEntityMixin {
|
||||
@Inject(at = @At("HEAD"), method = "sendChatMessage(Ljava/lang/String;)V", cancellable=true)
|
||||
private void onSendChatMessage(String message, CallbackInfo ci) {
|
||||
boolean isCommand = CommandProcessor.processChatMessage(message);
|
||||
if (isCommand) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.Freecam;
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import net.minecraft.client.Keyboard;
|
||||
import net.minecraft.client.util.InputUtil;
|
||||
|
||||
@Mixin(Keyboard.class)
|
||||
public class KeyboardMixin {
|
||||
@Inject(at = @At("HEAD"), method = "onKey(JIIII)V")
|
||||
private void onOnKey(long window, int key, int scancode, int i, int j, CallbackInfo ci) {
|
||||
if (SongPlayer.MC.currentScreen == null && i == GLFW.GLFW_PRESS && InputUtil.fromKeyCode(key, scancode).getTranslationKey().equals("key.keyboard.p")) {
|
||||
Freecam.getInstance().toggle();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.github.hhhzzzsss.songplayer.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.hit.HitResult.Type;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public class MinecraftClientMixin {
|
||||
@Inject(at = @At("HEAD"), method = "doItemUse()V")
|
||||
public void onDoItemUse(CallbackInfo ci) {
|
||||
Type type = SongPlayer.MC.crosshairTarget.getType();
|
||||
if (type == Type.BLOCK) {
|
||||
BlockHitResult blockHitResult = (BlockHitResult) SongPlayer.MC.crosshairTarget;
|
||||
BlockPos pos = blockHitResult.getBlockPos();
|
||||
System.out.println(blockHitResult.getSide() + ": " + pos.getX() + " " + pos.getY() + " " + pos.getZ());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.GameMode;
|
||||
|
||||
public class BuildingThread extends Thread {
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
private final PlayerInventory inventory = SongPlayer.MC.player.inventory;
|
||||
private final ClientWorld world = SongPlayer.MC.world;
|
||||
private final Stage stage = SongPlayer.stage;
|
||||
private final BlockPos stagePos = SongPlayer.stage.position;
|
||||
private final Song song = SongPlayer.song;
|
||||
private final int NOTEBLOCK_BASE_ID = 249;
|
||||
private final String[] instrumentNames = {"harp", "basedrum", "snare", "hat", "bass", "flute", "bell", "guitar", "chime", "xylophone", "iron_xylophone", "cow_bell", "didgeridoo", "bit", "banjo", "pling"};
|
||||
private boolean[] missingNotes = new boolean[400];
|
||||
|
||||
public void run() {
|
||||
for (int i=0; i<400; i++) {
|
||||
missingNotes[i] = song.requiredNotes[i];
|
||||
}
|
||||
stage.noteblockPositions.clear();
|
||||
ArrayList<BlockPos> unusedNoteblockLocations = new ArrayList<>();
|
||||
for (int dy : new int[] {-1,2}) {
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
for (int dz = -4; dz <= 4; dz++) {
|
||||
if (Math.abs(dx) == 4 && Math.abs(dz) == 4) continue;
|
||||
BlockPos pos = new BlockPos(stagePos.getX()+dx, stagePos.getY()+dy, stagePos.getZ()+dz);
|
||||
BlockState bs = world.getBlockState(pos);
|
||||
int blockId = Block.getRawIdFromState(bs);
|
||||
if (blockId >= 249 && blockId <= 1048) {
|
||||
int noteId = (blockId-NOTEBLOCK_BASE_ID)/2;
|
||||
if (missingNotes[noteId]) {
|
||||
stage.tunedNoteblocks[noteId] = pos;
|
||||
missingNotes[noteId] = false;
|
||||
stage.noteblockPositions.add(pos);
|
||||
}
|
||||
else {
|
||||
unusedNoteblockLocations.add(pos);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unusedNoteblockLocations.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int idx = 0;
|
||||
for (int i=0; i<400; i++) {
|
||||
if (idx == unusedNoteblockLocations.size()) {
|
||||
System.out.println("Too many noteblocks!");
|
||||
break;
|
||||
}
|
||||
if (missingNotes[i]) {
|
||||
stage.tunedNoteblocks[i] = unusedNoteblockLocations.get(idx++);
|
||||
stage.noteblockPositions.add(stage.tunedNoteblocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
player.sendChatMessage(SongPlayer.creativeCommand);
|
||||
try { //delay in case of block updates
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
while (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.BUILDING) {return;}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
player.abilities.allowFlying = true;
|
||||
player.abilities.flying = true;
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
for (int dy : new int[] {0,1,3}) {
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
for (int dz = -4; dz <= 4; dz++) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.BUILDING) {return;}
|
||||
|
||||
if (Math.abs(dx) == 4 && Math.abs(dz) == 4) continue;
|
||||
int x = stagePos.getX() + dx;
|
||||
int y = stagePos.getY() + dy;
|
||||
int z = stagePos.getZ() + dz;
|
||||
if (Block.getRawIdFromState(world.getBlockState(new BlockPos(x, y, z))) != 0) {
|
||||
SongPlayer.MC.interactionManager.attackBlock(new BlockPos(x, y, z), Direction.UP);
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("done clearing blocks");
|
||||
|
||||
for (int i=0; i<400; i++) if (song.requiredNotes[i]) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.BUILDING) {return;}
|
||||
|
||||
BlockPos p = stage.tunedNoteblocks[i];
|
||||
int blockId = Block.getRawIdFromState(world.getBlockState(p));
|
||||
int currentNoteId = (blockId-NOTEBLOCK_BASE_ID)/2;
|
||||
int desiredNoteId = i;
|
||||
|
||||
if (currentNoteId != desiredNoteId) {
|
||||
holdNoteblock(desiredNoteId);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
if (blockId != 0) {
|
||||
SongPlayer.MC.interactionManager.attackBlock(p, Direction.UP);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
placeBlock(p);
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("done placing blocks");
|
||||
|
||||
stage.rebuild = false;
|
||||
SongPlayer.mode = SongPlayer.Mode.PLAYING;
|
||||
SongPlayer.addChatMessage("§6Noteblocks are built. Now playing " + song.name + ".");
|
||||
(new PlayingThread()).start();
|
||||
}
|
||||
|
||||
private void holdNoteblock(int id) {
|
||||
int instrument = id/25;
|
||||
int note = id%25;
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.putString("id", "minecraft:note_block");
|
||||
nbt.putByte("Count", (byte) 1);
|
||||
CompoundTag tag = new CompoundTag();
|
||||
CompoundTag bsTag = new CompoundTag();
|
||||
bsTag.putString("instrument", instrumentNames[instrument]);
|
||||
bsTag.putString("note", Integer.toString(note));
|
||||
tag.put("BlockStateTag", bsTag);
|
||||
nbt.put("tag", tag);
|
||||
inventory.main.set(inventory.selectedSlot, ItemStack.fromTag(nbt));
|
||||
SongPlayer.MC.interactionManager.clickCreativeStack(player.getStackInHand(Hand.MAIN_HAND), 36 + inventory.selectedSlot);
|
||||
}
|
||||
|
||||
private void placeBlock(BlockPos p) {
|
||||
double fx = Math.max(0.0, Math.min(1.0, (stage.position.getX() + 0.5 - p.getX())));
|
||||
double fy = Math.max(0.0, Math.min(1.0, (stage.position.getY() + 0.0 - p.getY())));
|
||||
double fz = Math.max(0.0, Math.min(1.0, (stage.position.getZ() + 0.5 - p.getZ())));
|
||||
fx += p.getX();
|
||||
fy += p.getY();
|
||||
fz += p.getZ();
|
||||
SongPlayer.MC.interactionManager.interactBlock(player, world, Hand.MAIN_HAND, new BlockHitResult(new Vec3d(fx, fy, fz), Direction.UP, p, false));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.GameMode;
|
||||
|
||||
public class PlayingThread extends Thread{
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
private final Stage stage = SongPlayer.stage;
|
||||
private final Song song = SongPlayer.song;
|
||||
|
||||
public void run() {
|
||||
player.sendChatMessage(SongPlayer.survivalCommand);
|
||||
while (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.SURVIVAL) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.PLAYING) {return;}
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
}
|
||||
stage.rebuild = false;
|
||||
|
||||
player.abilities.allowFlying = true;
|
||||
player.abilities.flying = true;
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
long songStartTime = System.currentTimeMillis() - song.get(song.position).time;
|
||||
while (song.position < song.size()) {
|
||||
long playTime = System.currentTimeMillis() - songStartTime;
|
||||
while (song.position < song.size() && song.get(song.position).time <= playTime) {
|
||||
if (SongPlayer.mode != SongPlayer.Mode.PLAYING) {return;}
|
||||
SongPlayer.MC.interactionManager.attackBlock(stage.tunedNoteblocks[song.get(song.position).note], Direction.UP);
|
||||
SongPlayer.MC.interactionManager.cancelBlockBreaking();
|
||||
song.position++;
|
||||
if (stage.rebuild) {
|
||||
SongPlayer.addChatMessage("§6Stage has been modified. Retuning!");
|
||||
SongPlayer.mode = SongPlayer.Mode.BUILDING;
|
||||
(new BuildingThread()).start();
|
||||
return;
|
||||
}
|
||||
if (song.gotoTime > -1) {
|
||||
for (int i = 0; i < song.size(); i++) {
|
||||
if (song.get(i).time >= song.gotoTime) {
|
||||
song.position = i;
|
||||
song.gotoTime = -1;
|
||||
SongPlayer.addChatMessage("§6Changed song position");
|
||||
(new PlayingThread()).start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
SongPlayer.addChatMessage("§cNot a valid time stamp");
|
||||
song.gotoTime = -1;
|
||||
}
|
||||
}
|
||||
if (song.position < song.size()) {
|
||||
playTime = System.currentTimeMillis() - songStartTime;
|
||||
long sleepTime = playTime - song.get(song.position).time;
|
||||
if (sleepTime > 0) {
|
||||
if (sleepTime > 200) {
|
||||
System.out.println("Big sleep time: " + sleepTime);
|
||||
}
|
||||
try {
|
||||
Thread.sleep(playTime-song.get(song.position).time);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (song.loop) {
|
||||
song.position = 0;
|
||||
songStartTime = System.currentTimeMillis();
|
||||
}
|
||||
else {
|
||||
// Do nothing. While loop condition is false so loop exits.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player.abilities.allowFlying = true;
|
||||
player.abilities.flying = true;
|
||||
SongPlayer.stage.movePlayerToStagePosition();
|
||||
|
||||
SongPlayer.addChatMessage("§6Finished playing.");
|
||||
SongPlayer.mode = SongPlayer.Mode.IDLE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.github.hhhzzzsss.songplayer.noteblocks;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class Stage {
|
||||
private final ClientPlayerEntity player = SongPlayer.MC.player;
|
||||
|
||||
public BlockPos position;
|
||||
public BlockPos[] tunedNoteblocks = new BlockPos[400];
|
||||
public HashSet<BlockPos> noteblockPositions = new HashSet<>();
|
||||
public boolean rebuild = false;
|
||||
|
||||
public Stage() {
|
||||
position = player.getBlockPos();
|
||||
}
|
||||
|
||||
public void movePlayerToStagePosition() {
|
||||
player.refreshPositionAndAngles(position.getX() + 0.5, position.getY() + 0.0, position.getZ() + 0.5, player.yaw, player.pitch);
|
||||
player.setVelocity(Vec3d.ZERO);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.noteblocks.BuildingThread;
|
||||
|
||||
public class DownloadingThread extends Thread{
|
||||
|
||||
private String url;
|
||||
public DownloadingThread(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
SongPlayer.song = Song.getSongFromUrl(url);
|
||||
SongPlayer.addChatMessage("§6Finished downloading song");
|
||||
SongPlayer.mode = SongPlayer.Mode.BUILDING;
|
||||
SongPlayer.addChatMessage("§6Starting building.");
|
||||
(new BuildingThread()).start();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
SongPlayer.addChatMessage("§cError getting song from url: " + e.getMessage());
|
||||
SongPlayer.mode = SongPlayer.Mode.IDLE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,230 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.sound.midi.MetaMessage;
|
||||
import javax.sound.midi.MidiEvent;
|
||||
import javax.sound.midi.MidiMessage;
|
||||
import javax.sound.midi.MidiSystem;
|
||||
import javax.sound.midi.Sequence;
|
||||
import javax.sound.midi.ShortMessage;
|
||||
import javax.sound.midi.Track;
|
||||
|
||||
public class MidiConverter {
|
||||
public static final int SET_INSTRUMENT = 0xC0;
|
||||
public static final int SET_TEMPO = 0x51;
|
||||
public static final int NOTE_ON = 0x90;
|
||||
public static final int NOTE_OFF = 0x80;
|
||||
|
||||
public static int[] instrument_offsets = new int[] {
|
||||
54, //harp
|
||||
0, //basedrum
|
||||
0, //snare
|
||||
0, //hat
|
||||
30, //bass
|
||||
66, //flute
|
||||
78, //bell
|
||||
42, //guitar
|
||||
78, //chime
|
||||
78, //xylophone
|
||||
54, //iron xylophone
|
||||
66, //cow bell
|
||||
30, //didgeridoo
|
||||
54, //bit
|
||||
54, //banjo
|
||||
54, //electric piano
|
||||
};
|
||||
|
||||
public static String fileName = "moskau";
|
||||
public static TreeMap<Long, ArrayList<Integer>> noteMap;
|
||||
|
||||
public static TreeMap<Long, ArrayList<Integer>> getMidi(String url) throws Exception {
|
||||
noteMap = new TreeMap<>();
|
||||
|
||||
//SocketAddress addr = new InetSocketAddress("34.94.90.93", 3128);
|
||||
//Proxy proxy = new Proxy(Proxy.Type.HTTP, addr);
|
||||
URLConnection conn = (new URL(url)).openConnection();
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0");
|
||||
BufferedInputStream downloadStream = new BufferedInputStream(conn.getInputStream());
|
||||
boolean fileTooLarge = true;
|
||||
byte tempbuf[] = new byte[10240];
|
||||
for (int i=0; i<1024; i++) {
|
||||
if (downloadStream.read(tempbuf, 0, 1024) == -1) {
|
||||
fileTooLarge = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fileTooLarge) {
|
||||
throw new IOException("File too large");
|
||||
}
|
||||
downloadStream.close();
|
||||
downloadStream = new BufferedInputStream(new URL(url).openStream());
|
||||
|
||||
Sequence sequence = MidiSystem.getSequence(downloadStream);
|
||||
|
||||
long tpq = sequence.getResolution();
|
||||
|
||||
ArrayList<MidiEvent> tempoEvents = new ArrayList<>();
|
||||
for (Track track : sequence.getTracks()) {
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
MidiEvent event = track.get(i);
|
||||
MidiMessage message = event.getMessage();
|
||||
if (message instanceof MetaMessage) {
|
||||
MetaMessage mm = (MetaMessage) message;
|
||||
if (mm.getType() == SET_TEMPO) {
|
||||
tempoEvents.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(tempoEvents, new Comparator<MidiEvent>() {
|
||||
@Override
|
||||
public int compare(MidiEvent a, MidiEvent b) {
|
||||
return (new Long(a.getTick())).compareTo(b.getTick());
|
||||
}
|
||||
});
|
||||
|
||||
for (Track track : sequence.getTracks()) {
|
||||
|
||||
long microTime = 0;
|
||||
int[] instrumentIds = new int[16];
|
||||
//int apparent_mpq = (int) (sequence.getMicrosecondLength()/sequence.getTickLength()*tpq);
|
||||
int mpq = 500000;
|
||||
int tempoEventIdx = 0;
|
||||
long prevTick = 0;
|
||||
|
||||
for (int i = 0; i < track.size(); i++) {
|
||||
MidiEvent event = track.get(i);
|
||||
MidiMessage message = event.getMessage();
|
||||
|
||||
while (tempoEventIdx < tempoEvents.size() && event.getTick() > tempoEvents.get(tempoEventIdx).getTick()) {
|
||||
long deltaTick = tempoEvents.get(tempoEventIdx).getTick() - prevTick;
|
||||
prevTick = tempoEvents.get(tempoEventIdx).getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
|
||||
MetaMessage mm = (MetaMessage) tempoEvents.get(tempoEventIdx).getMessage();
|
||||
byte[] data = mm.getData();
|
||||
int new_mpq = (data[2]&0xFF) | ((data[1]&0xFF)<<8) | ((data[0]&0xFF)<<16);
|
||||
if (new_mpq != 0) mpq = new_mpq;
|
||||
tempoEventIdx++;
|
||||
}
|
||||
|
||||
if (message instanceof ShortMessage) {
|
||||
ShortMessage sm = (ShortMessage) message;
|
||||
if (sm.getCommand() == SET_INSTRUMENT) {
|
||||
instrumentIds[sm.getChannel()] = sm.getData1();
|
||||
}
|
||||
else if (sm.getCommand() == NOTE_ON) {
|
||||
if (sm.getData2() == 0) continue;
|
||||
int key = sm.getData1();
|
||||
long deltaTick = event.getTick() - prevTick;
|
||||
prevTick = event.getTick();
|
||||
microTime += (mpq/tpq) * deltaTick;
|
||||
if (sm.getChannel() == 9) {
|
||||
processMidiNote(128, sm.getData1(), microTime);
|
||||
}
|
||||
else {
|
||||
processMidiNote(instrumentIds[sm.getChannel()], sm.getData1(), microTime);
|
||||
}
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadStream.close();
|
||||
|
||||
return noteMap;
|
||||
}
|
||||
|
||||
public static void processMidiNote(int midiInstrument, int midiPitch, long microTime) {
|
||||
int minecraftInstrument = -1;
|
||||
if ((midiInstrument >= 0 && midiInstrument <= 7) || (midiInstrument >= 24 && midiInstrument <= 31)) { //normal
|
||||
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 0; //piano
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||
minecraftInstrument = 4; //bass
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||
minecraftInstrument = 6; //bells
|
||||
}
|
||||
}
|
||||
else if (midiInstrument >= 8 && midiInstrument <= 15) { //chromatic percussion
|
||||
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 10; //iron xylophone
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) {
|
||||
minecraftInstrument = 9; //xylophone
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) {
|
||||
minecraftInstrument = 4; //bass
|
||||
}
|
||||
}
|
||||
else if ((midiInstrument >= 16 && midiInstrument <= 23) || (midiInstrument >= 32 && midiInstrument <= 71) || (midiInstrument >= 80 && midiInstrument <= 111)) { //synth
|
||||
if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 13; //bit
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) { //didgeridoo
|
||||
minecraftInstrument = 12;
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) { //bells
|
||||
minecraftInstrument = 6;
|
||||
}
|
||||
}
|
||||
else if ((midiInstrument >= 72 && midiInstrument <= 79)) { //woodwind
|
||||
if (midiPitch >= 66 && midiPitch <= 90) {
|
||||
minecraftInstrument = 5; //flute
|
||||
}
|
||||
else if (midiPitch >= 30 && midiPitch <= 54) { //didgeridoo
|
||||
minecraftInstrument = 12;
|
||||
}
|
||||
else if (midiPitch >= 54 && midiPitch <= 78) {
|
||||
minecraftInstrument = 13; //bit
|
||||
}
|
||||
else if (midiPitch >= 78 && midiPitch <= 102) { //bells
|
||||
minecraftInstrument = 6;
|
||||
}
|
||||
}
|
||||
else if (midiInstrument == 128) {
|
||||
if (midiPitch == 35 || midiPitch == 36 || midiPitch == 41 || midiPitch == 43 || midiPitch == 45 || midiPitch == 57) {
|
||||
minecraftInstrument = 1; //bass drum
|
||||
}
|
||||
else if (midiPitch == 38 || midiPitch == 39 || midiPitch == 40 || midiPitch == 54 || midiPitch == 69 || midiPitch == 70 || midiPitch == 73 || midiPitch == 74 || midiPitch == 78 || midiPitch == 79) {
|
||||
minecraftInstrument = 2; //snare
|
||||
}
|
||||
else if (midiPitch == 37 || midiPitch == 42 || midiPitch == 44 || midiPitch == 46 || midiPitch == 49 || midiPitch == 51 || midiPitch == 52 || midiPitch == 55 || midiPitch == 57 || midiPitch == 59) {
|
||||
minecraftInstrument = 3; //hat
|
||||
}
|
||||
midiPitch = 0;
|
||||
}
|
||||
|
||||
long milliTime = microTime / 1000;
|
||||
if (minecraftInstrument >= 0) {
|
||||
int noteId = (midiPitch-instrument_offsets[minecraftInstrument]) + minecraftInstrument*25;
|
||||
|
||||
if (!noteMap.containsKey(milliTime)) {
|
||||
noteMap.put(milliTime, new ArrayList<Integer>());
|
||||
}
|
||||
if (!noteMap.get(milliTime).contains(noteId)) {
|
||||
noteMap.get(milliTime).add(noteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
public class NoteEvent {
|
||||
public int note;
|
||||
public long time;
|
||||
public NoteEvent(int note, long time) {
|
||||
this.note = note;
|
||||
this.time = time;
|
||||
}
|
||||
}
|
74
src/main/java/com/github/hhhzzzsss/songplayer/song/Song.java
Normal file
74
src/main/java/com/github/hhhzzzsss/songplayer/song/Song.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
|
||||
public class Song {
|
||||
public ArrayList<NoteEvent> notes = new ArrayList<>();
|
||||
public String name;
|
||||
public int position = 0;
|
||||
public boolean[] requiredNotes = new boolean[400];
|
||||
public boolean loop = false;
|
||||
public int gotoTime = -1;
|
||||
|
||||
private Song() {}
|
||||
|
||||
public NoteEvent get(int i) {
|
||||
return notes.get(i);
|
||||
}
|
||||
|
||||
public void add(NoteEvent e) {
|
||||
notes.add(e);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return notes.size();
|
||||
}
|
||||
|
||||
public static Song getSongFromFile(String file) throws IOException {
|
||||
Song song = new Song();
|
||||
if (file.contains("/") || file.contains("\\")) throw new FileNotFoundException();
|
||||
File songPath = new File(SongPlayer.SONG_DIR, file);
|
||||
if (!songPath.exists()) songPath = new File(SongPlayer.SONG_DIR, file + ".txt");
|
||||
if (!songPath.exists()) throw new FileNotFoundException();
|
||||
song.notes.clear();
|
||||
BufferedReader br = new BufferedReader(new FileReader(songPath));
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
String[] split = line.split(" ");
|
||||
long time = Long.parseLong(split[0]);
|
||||
int note = Integer.parseInt(split[1]);
|
||||
song.requiredNotes[note] = true;
|
||||
song.notes.add(new NoteEvent(note, time));
|
||||
}
|
||||
br.close();
|
||||
song.name = songPath.getName();
|
||||
return song;
|
||||
}
|
||||
|
||||
public static Song getSongFromUrl(String url) throws Exception {
|
||||
Song song = new Song();
|
||||
song.notes.clear();
|
||||
TreeMap<Long, ArrayList<Integer>> noteMap = MidiConverter.getMidi(url);
|
||||
System.out.println(noteMap.size());
|
||||
for (int i=0; i<400; i++) song.requiredNotes[i] = false;
|
||||
for (Map.Entry<Long, ArrayList<Integer>> entry : noteMap.entrySet()) {
|
||||
for (int note : entry.getValue()) {
|
||||
long time = entry.getKey();
|
||||
song.requiredNotes[note] = true;
|
||||
song.add(new NoteEvent(note, time));
|
||||
}
|
||||
}
|
||||
song.name = url.substring(url.lastIndexOf('/')+1, url.length());
|
||||
|
||||
return song;
|
||||
}
|
||||
}
|
BIN
src/main/resources/assets/songplayer/icon.png
Normal file
BIN
src/main/resources/assets/songplayer/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 453 B |
37
src/main/resources/fabric.mod.json
Normal file
37
src/main/resources/fabric.mod.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "songplayer",
|
||||
"version": "${version}",
|
||||
|
||||
"name": "Song Player",
|
||||
"description": "Builds and plays noteblocks",
|
||||
"authors": [
|
||||
"hhhzzzsss"
|
||||
],
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net/",
|
||||
"sources": "https://github.com/FabricMC/fabric-example-mod"
|
||||
},
|
||||
|
||||
"license": "CC0-1.0",
|
||||
"icon": "assets/songplayer/icon.png",
|
||||
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"com.github.hhhzzzsss.songplayer.SongPlayer"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"songplayer.mixins.json"
|
||||
],
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.7.4",
|
||||
"fabric": "*",
|
||||
"minecraft": "1.16.x"
|
||||
},
|
||||
"suggests": {
|
||||
"flamingo": "*"
|
||||
}
|
||||
}
|
15
src/main/resources/songplayer.mixins.json
Normal file
15
src/main/resources/songplayer.mixins.json
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "com.github.hhhzzzsss.songplayer.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"ClientPlayerEntityMixin",
|
||||
"ClientPlayNetworkHandlerMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue