Compare commits
2 Commits
5369823d2b
...
f3586dce44
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f3586dce44 | ||
![]() |
dfa80c8e47 |
@ -6,7 +6,7 @@ minecraft_version=1.21.4
|
||||
yarn_mappings=1.21.4+build.8
|
||||
loader_version=0.16.10
|
||||
# Mod Properties
|
||||
mod_version=1.14.514.021
|
||||
mod_version=1.14.514.022
|
||||
maven_group=semmiedev
|
||||
archives_base_name=disc_jockey_revive
|
||||
# Dependencies
|
||||
|
@ -20,6 +20,7 @@ import net.minecraft.util.Formatting;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import semmiedev.disc_jockey_revive.gui.SongListWidget;
|
||||
import semmiedev.disc_jockey_revive.gui.hud.BlocksOverlay;
|
||||
import semmiedev.disc_jockey_revive.gui.screen.DiscJockeyScreen;
|
||||
|
||||
@ -38,6 +39,15 @@ public class Main implements ClientModInitializer {
|
||||
public static ModConfig config;
|
||||
public static ConfigHolder<ModConfig> configHolder;
|
||||
|
||||
public static KeyBinding nextSongKeyBind;
|
||||
// public static KeyBinding prevSongKeyBind;
|
||||
static KeyBinding playStopKeyBind;
|
||||
public static KeyBinding reloadKeyBind;
|
||||
|
||||
private static long lastNextSongPress = 0;
|
||||
public MinecraftClient client;
|
||||
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
configHolder = AutoConfig.register(ModConfig.class, JanksonConfigSerializer::new);
|
||||
@ -48,8 +58,40 @@ public class Main implements ClientModInitializer {
|
||||
|
||||
SongLoader.loadSongs();
|
||||
|
||||
// 打开菜单
|
||||
KeyBinding openScreenKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(MOD_ID+".key_bind.open_screen", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_J, "key.category."+MOD_ID));
|
||||
|
||||
// 下一首和上一首快捷键
|
||||
nextSongKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
MOD_ID+".key_bind.next_song",
|
||||
InputUtil.Type.KEYSYM,
|
||||
InputUtil.UNKNOWN_KEY.getCode(), // Default to unbound
|
||||
"key.category."+MOD_ID
|
||||
));
|
||||
// 上一首不要了,没啥用
|
||||
// prevSongKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
// MOD_ID+".key_bind.prev_song",
|
||||
// InputUtil.Type.KEYSYM,
|
||||
// InputUtil.UNKNOWN_KEY.getCode(), // Default to unbound
|
||||
// "key.category."+MOD_ID
|
||||
// ));
|
||||
|
||||
// 停止
|
||||
playStopKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
MOD_ID+".key_bind.play_stop",
|
||||
InputUtil.Type.KEYSYM,
|
||||
InputUtil.UNKNOWN_KEY.getCode(), // Default unbound
|
||||
"key.category."+MOD_ID
|
||||
));
|
||||
|
||||
// 重载
|
||||
reloadKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||
MOD_ID+".key_bind.reload",
|
||||
InputUtil.Type.KEYSYM,
|
||||
InputUtil.UNKNOWN_KEY.getCode(), // Default unbound
|
||||
"key.category."+MOD_ID
|
||||
));
|
||||
|
||||
ClientTickEvents.START_CLIENT_TICK.register(new ClientTickEvents.StartTick() {
|
||||
private ClientWorld prevWorld;
|
||||
|
||||
@ -69,9 +111,31 @@ public class Main implements ClientModInitializer {
|
||||
client.setScreen(new DiscJockeyScreen());
|
||||
}
|
||||
}
|
||||
if (nextSongKeyBind.wasPressed()) {
|
||||
if (SONG_PLAYER.running) {
|
||||
SONG_PLAYER.playNextSong();
|
||||
}
|
||||
}
|
||||
// if (prevSongKeyBind.wasPressed()) {
|
||||
// SONG_PLAYER.playPreviousSong();
|
||||
// }
|
||||
if (playStopKeyBind.wasPressed()) {
|
||||
if (SONG_PLAYER.running) {
|
||||
SONG_PLAYER.stop();
|
||||
}
|
||||
}
|
||||
if (reloadKeyBind.wasPressed()) {
|
||||
SongLoader.loadSongs();
|
||||
if (client.currentScreen instanceof DiscJockeyScreen) {
|
||||
client.setScreen(new DiscJockeyScreen());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
ClientTickEvents.START_WORLD_TICK.register(world -> {
|
||||
for (ClientTickEvents.StartWorldTick listener : TICK_LISTENERS) listener.onStartTick(world);
|
||||
});
|
||||
|
@ -2,6 +2,7 @@ package semmiedev.disc_jockey_revive;
|
||||
|
||||
import me.shedaniel.autoconfig.ConfigData;
|
||||
import me.shedaniel.autoconfig.annotation.ConfigEntry;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -37,6 +38,29 @@ public class ModConfig implements ConfigData {
|
||||
}
|
||||
}
|
||||
|
||||
public enum ErrorHandlingMode {
|
||||
STOP_PLAYBACK(Text.translatable(Main.MOD_ID+".config.error_handling.stop")),
|
||||
PLAY_NEXT(Text.translatable(Main.MOD_ID+".config.error_handling.next"));
|
||||
|
||||
private final Text displayText;
|
||||
|
||||
ErrorHandlingMode(Text displayText) {
|
||||
this.displayText = displayText;
|
||||
}
|
||||
|
||||
public Text getDisplayText() {
|
||||
return displayText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayText.getString();
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
|
||||
public ErrorHandlingMode errorHandlingMode = ErrorHandlingMode.STOP_PLAYBACK;
|
||||
|
||||
@ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
|
||||
@ConfigEntry.Gui.Tooltip(count = 4)
|
||||
public ExpectedServerVersion expectedServerVersion = ExpectedServerVersion.All;
|
||||
|
@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class SongPlayer implements ClientTickEvents.StartWorldTick {
|
||||
@ -98,7 +99,7 @@ public class SongPlayer implements ClientTickEvents.StartWorldTick {
|
||||
STOP_AFTER // 播完就停
|
||||
}
|
||||
|
||||
private PlayMode playMode = PlayMode.STOP_AFTER;
|
||||
public PlayMode playMode = PlayMode.STOP_AFTER;
|
||||
private boolean isRandomPlaying = false;
|
||||
private int randomIndex = -1;
|
||||
|
||||
@ -160,6 +161,27 @@ public class SongPlayer implements ClientTickEvents.StartWorldTick {
|
||||
didSongReachEnd = false; // Change after running stop() if actually ended cleanly
|
||||
}
|
||||
|
||||
|
||||
public synchronized void playPreviousSong() {
|
||||
if (!running || song == null) return;
|
||||
|
||||
if (SongLoader.currentFolder == null || SongLoader.currentFolder.songs.isEmpty()) return;
|
||||
|
||||
int currentIndex = SongLoader.currentFolder.songs.indexOf(song);
|
||||
if (currentIndex == -1) return;
|
||||
|
||||
if (playMode == PlayMode.RANDOM) {
|
||||
int newIndex;
|
||||
do {
|
||||
newIndex = (int) (Math.random() * SongLoader.currentFolder.songs.size());
|
||||
} while (newIndex == currentIndex && SongLoader.currentFolder.songs.size() > 1);
|
||||
start(SongLoader.currentFolder.songs.get(newIndex));
|
||||
} else {
|
||||
int prevIndex = (currentIndex - 1 + SongLoader.currentFolder.songs.size()) % SongLoader.currentFolder.songs.size();
|
||||
start(SongLoader.currentFolder.songs.get(prevIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void tickPlayback() {
|
||||
if (!running) {
|
||||
lastPlaybackTickAt = -1L;
|
||||
@ -197,8 +219,14 @@ public class SongPlayer implements ClientTickEvents.StartWorldTick {
|
||||
continue;
|
||||
}
|
||||
if (!canInteractWith(client.player, blockPos)) {
|
||||
if (Main.config.errorHandlingMode == ModConfig.ErrorHandlingMode.PLAY_NEXT) {
|
||||
playNextSong();
|
||||
} else {
|
||||
stop();
|
||||
client.inGameHud.getChatHud().addMessage(Text.translatable(Main.MOD_ID+".player.to_far").formatted(Formatting.RED));
|
||||
if (client.player != null) {
|
||||
client.player.sendMessage(Text.translatable(Main.MOD_ID+".player.to_far").formatted(Formatting.RED), false);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
Vec3d unit = Vec3d.ofCenter(blockPos, 0.5).subtract(client.player.getEyePos()).normalize();
|
||||
@ -256,24 +284,39 @@ public class SongPlayer implements ClientTickEvents.StartWorldTick {
|
||||
}
|
||||
}
|
||||
|
||||
private void playNextSong() {
|
||||
if (SongLoader.currentFolder == null || SongLoader.currentFolder.songs.isEmpty()) return;
|
||||
public synchronized void playNextSong() {
|
||||
if (!running || song == null) return;
|
||||
|
||||
int currentIndex = SongLoader.currentFolder.songs.indexOf(song);
|
||||
if (currentIndex == -1) return;
|
||||
if (SongLoader.currentFolder == null ||
|
||||
(SongLoader.currentFolder.songs.isEmpty() && SongLoader.SONGS.isEmpty())) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Song> availableSongs = SongLoader.currentFolder != null ?
|
||||
SongLoader.currentFolder.songs : SongLoader.SONGS;
|
||||
|
||||
if (availableSongs.isEmpty()) return;
|
||||
|
||||
if (playMode == PlayMode.RANDOM) {
|
||||
// 随机播放
|
||||
int newIndex;
|
||||
do {
|
||||
newIndex = (int) (Math.random() * SongLoader.currentFolder.songs.size());
|
||||
} while (newIndex == currentIndex && SongLoader.currentFolder.songs.size() > 1);
|
||||
start(SongLoader.currentFolder.songs.get(newIndex));
|
||||
} else if (playMode == PlayMode.LIST_LOOP) {
|
||||
int nextIndex = (currentIndex + 1) % SongLoader.currentFolder.songs.size();
|
||||
start(SongLoader.currentFolder.songs.get(nextIndex));
|
||||
newIndex = (int)(Math.random() * availableSongs.size());
|
||||
} while (availableSongs.size() > 1 &&
|
||||
availableSongs.get(newIndex).fileName.equals(song.fileName));
|
||||
|
||||
start(availableSongs.get(newIndex));
|
||||
}
|
||||
else { // 列表循环和单曲循环
|
||||
int currentIndex = availableSongs.indexOf(song);
|
||||
if (currentIndex == -1) return;
|
||||
|
||||
int nextIndex = (currentIndex + 1) % availableSongs.size();
|
||||
start(availableSongs.get(nextIndex));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void setPlayMode(PlayMode mode) {
|
||||
this.playMode = mode;
|
||||
this.loopSong = mode == PlayMode.SINGLE_LOOP;
|
||||
|
@ -9,10 +9,7 @@ import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import semmiedev.disc_jockey_revive.Main;
|
||||
import semmiedev.disc_jockey_revive.Note;
|
||||
import semmiedev.disc_jockey_revive.Song;
|
||||
import semmiedev.disc_jockey_revive.SongLoader;
|
||||
import semmiedev.disc_jockey_revive.*;
|
||||
import semmiedev.disc_jockey_revive.gui.SongListWidget;
|
||||
import semmiedev.disc_jockey_revive.gui.hud.BlocksOverlay;
|
||||
|
||||
@ -34,26 +31,25 @@ public class DiscJockeyScreen extends Screen {
|
||||
PLAY_STOP = Text.translatable(Main.MOD_ID+".screen.play.stop"),
|
||||
PREVIEW = Text.translatable(Main.MOD_ID+".screen.preview"),
|
||||
PREVIEW_STOP = Text.translatable(Main.MOD_ID+".screen.preview.stop"),
|
||||
DROP_HINT = Text.translatable(Main.MOD_ID+".screen.drop_hint").formatted(Formatting.GRAY)
|
||||
;
|
||||
DROP_HINT = Text.translatable(Main.MOD_ID+".screen.drop_hint").formatted(Formatting.GRAY),
|
||||
|
||||
private SongListWidget songListWidget;
|
||||
private ButtonWidget playButton, previewButton;
|
||||
public boolean shouldFilter;
|
||||
private String query = "";
|
||||
|
||||
private static final MutableText
|
||||
FOLDER_UP = Text.literal("↑"),
|
||||
CURRENT_FOLDER = Text.translatable(Main.MOD_ID+".screen.current_folder"),
|
||||
PLAY_MODE = Text.translatable(Main.MOD_ID+".screen.play_mode"),
|
||||
MODE_SINGLE = Text.translatable(Main.MOD_ID+".screen.mode_single"),
|
||||
MODE_LIST = Text.translatable(Main.MOD_ID+".screen.mode_list"),
|
||||
MODE_RANDOM = Text.translatable(Main.MOD_ID+".screen.mode_random"),
|
||||
MODE_STOP = Text.translatable(Main.MOD_ID+".screen.mode_stop");
|
||||
|
||||
private static final MutableText
|
||||
MODE_STOP = Text.translatable(Main.MOD_ID+".screen.mode_stop"),
|
||||
OPEN_FOLDER = Text.translatable(Main.MOD_ID+".screen.open_folder"),
|
||||
RELOAD = Text.translatable(Main.MOD_ID+".screen.reload");
|
||||
RELOAD = Text.translatable(Main.MOD_ID+".screen.reload"),
|
||||
NEXT_SONG = Text.translatable(Main.MOD_ID+".screen.next_song"),
|
||||
PREV_SONG = Text.translatable(Main.MOD_ID+".screen.prev_song");
|
||||
|
||||
public SongListWidget songListWidget;
|
||||
private ButtonWidget playButton, previewButton;
|
||||
public boolean shouldFilter;
|
||||
private String query = "";
|
||||
|
||||
|
||||
private ButtonWidget folderUpButton, playModeButton;
|
||||
public SongFolder currentFolder;
|
||||
@ -209,6 +205,38 @@ public class DiscJockeyScreen extends Screen {
|
||||
client.setScreen(null);
|
||||
}).dimensions(width / 2 + 60, height - 31, 100, 20).build());
|
||||
|
||||
// 下一首
|
||||
addDrawableChild(ButtonWidget.builder(NEXT_SONG, button -> {
|
||||
SongPlayer player = Main.SONG_PLAYER;
|
||||
if (player.running) {
|
||||
player.playNextSong();
|
||||
} else {
|
||||
SongListWidget.SongEntry entry = songListWidget.getSelectedSongOrNull();
|
||||
if (entry != null) {
|
||||
List<Song> availableSongs = SongLoader.currentFolder != null ?
|
||||
SongLoader.currentFolder.songs : SongLoader.SONGS;
|
||||
|
||||
int currentIndex = availableSongs.indexOf(entry.song);
|
||||
if (currentIndex != -1) {
|
||||
int nextIndex;
|
||||
if (player.playMode == PlayMode.RANDOM) {
|
||||
// Get random song in menu too
|
||||
do {
|
||||
nextIndex = (int)(Math.random() * availableSongs.size());
|
||||
} while (availableSongs.size() > 1 && nextIndex == currentIndex);
|
||||
} else {
|
||||
nextIndex = (currentIndex + 1) % availableSongs.size();
|
||||
}
|
||||
songListWidget.setSelected(availableSongs.get(nextIndex).entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).dimensions(width / 2 + 60 + 110 + 5, height - 61, 100, 20).build());
|
||||
|
||||
|
||||
|
||||
|
||||
// 搜索框
|
||||
TextFieldWidget searchBar = new TextFieldWidget(textRenderer, width / 2 - 50, height - 31, 100, 20, Text.translatable(Main.MOD_ID+".screen.search"));
|
||||
searchBar.setChangedListener(query -> {
|
||||
query = query.toLowerCase().replaceAll("\\s", "");
|
||||
|
@ -61,5 +61,15 @@
|
||||
"disc_jockey_revive.screen.open_folder": "Open Folder",
|
||||
"disc_jockey_revive.screen.open_folder_failed": "Failed to open folder",
|
||||
"disc_jockey_revive.screen.reload": "Reload Songs",
|
||||
"disc_jockey_revive.screen.reloading": "Reloading songs..."
|
||||
"disc_jockey_revive.screen.reloading": "Reloading songs...",
|
||||
"disc_jockey_revive.screen.next_song": "Next Song",
|
||||
"disc_jockey_revive.screen.prev_song": "Previous Song",
|
||||
"disc_jockey_revive.key_bind.next_song": "Next Song",
|
||||
"disc_jockey_revive.key_bind.prev_song": "Previous Song",
|
||||
"text.autoconfig.disc_jockey_revive.option.errorHandlingMode": "Error Handling",
|
||||
"text.autoconfig.disc_jockey_revive.option.errorHandlingMode.@Tooltip": "What to do when errors occur",
|
||||
"disc_jockey_revive.config.error_handling.stop": "Stop Playback",
|
||||
"disc_jockey_revive.config.error_handling.next": "Play Next Song",
|
||||
"disc_jockey_revive.key_bind.play_stop": "Play/Stop",
|
||||
"disc_jockey_revive.key_bind.reload": "Reload"
|
||||
}
|
@ -60,5 +60,15 @@
|
||||
"disc_jockey_revive.screen.mode_stop": "播完停止","disc_jockey_revive.screen.open_folder": "打开文件夹",
|
||||
"disc_jockey_revive.screen.open_folder_failed": "无法打开文件夹",
|
||||
"disc_jockey_revive.screen.reload": "重新加载",
|
||||
"disc_jockey_revive.screen.reloading": "正在重新加载..."
|
||||
"disc_jockey_revive.screen.reloading": "正在重新加载...",
|
||||
"disc_jockey_revive.screen.next_song": "下一首",
|
||||
"disc_jockey_revive.screen.prev_song": "上一首",
|
||||
"disc_jockey_revive.key_bind.next_song": "下一首",
|
||||
"disc_jockey_revive.key_bind.prev_song": "上一首",
|
||||
"text.autoconfig.disc_jockey_revive.option.errorHandlingMode": "错误处理",
|
||||
"text.autoconfig.disc_jockey_revive.option.errorHandlingMode.@Tooltip": "播放错误时的处理方式",
|
||||
"disc_jockey_revive.config.error_handling.stop": "停止播放",
|
||||
"disc_jockey_revive.config.error_handling.next": "播放下一首",
|
||||
"disc_jockey_revive.key_bind.play_stop": "播放/停止",
|
||||
"disc_jockey_revive.key_bind.reload": "重新加载"
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user