aaaaaaaaaaa
This commit is contained in:
parent
8cc8f6a427
commit
5d3f71cef5
@ -6,7 +6,7 @@ minecraft_version=1.21.4
|
|||||||
yarn_mappings=1.21.4+build.8
|
yarn_mappings=1.21.4+build.8
|
||||||
loader_version=0.16.10
|
loader_version=0.16.10
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=1.14.514.034
|
mod_version=1.14.514.037
|
||||||
maven_group=semmiedev
|
maven_group=semmiedev
|
||||||
archives_base_name=disc_jockey_revive
|
archives_base_name=disc_jockey_revive
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
25
src/main/java/semmiedev/disc_jockey_revive/DebugLogger.java
Normal file
25
src/main/java/semmiedev/disc_jockey_revive/DebugLogger.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package semmiedev.disc_jockey_revive;
|
||||||
|
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
// 这玩意一般不用,我自己用的,但是不想删
|
||||||
|
public class DebugLogger {
|
||||||
|
|
||||||
|
public static void log(String message) {
|
||||||
|
if (Main.config != null && Main.config.debugModeEnabled) {
|
||||||
|
Main.LOGGER.info("[DiscJockeyRevive-调试] " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(String format, Object... arguments) {
|
||||||
|
if (Main.config != null && Main.config.debugModeEnabled) {
|
||||||
|
Main.LOGGER.info("[DiscJockeyRevive-调试] " + format, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void log(String message, Throwable t) {
|
||||||
|
if (Main.config != null && Main.config.debugModeEnabled) {
|
||||||
|
Main.LOGGER.error("[DiscJockeyRevive-调试] " + message, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,172 @@
|
|||||||
|
package semmiedev.disc_jockey_revive;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.block.enums.NoteBlockInstrument;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class KeyMappingManager {
|
||||||
|
private static final File MAPPINGS_FILE = new File(FabricLoader.getInstance().getConfigDir().toFile(), "disc_jockey" + "/key_mappings.json");
|
||||||
|
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
private static final Type MAPPING_TYPE = new TypeToken<HashMap<String, NoteData>>() {}.getType();
|
||||||
|
|
||||||
|
private Map<InputUtil.Key, Note> mappings = new HashMap<>();
|
||||||
|
|
||||||
|
private static class NoteData {
|
||||||
|
String instrument;
|
||||||
|
byte note;
|
||||||
|
|
||||||
|
public NoteData(Note note) {
|
||||||
|
this.instrument = note.instrument().name();
|
||||||
|
this.note = note.note();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Note toNote() {
|
||||||
|
try {
|
||||||
|
NoteBlockInstrument instrumentEnum = NoteBlockInstrument.valueOf(instrument);
|
||||||
|
return new Note(instrumentEnum, note);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Main.LOGGER.error("键位映射中出现未知乐器 '{}' ", instrument);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyMappingManager() {
|
||||||
|
loadMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadMappings() {
|
||||||
|
if (!MAPPINGS_FILE.exists()) {
|
||||||
|
Main.LOGGER.info("未找到键映射文件,正在创建默认的类似于 FL Studio 的映射。");
|
||||||
|
mappings.clear();
|
||||||
|
|
||||||
|
NoteBlockInstrument dirt = NoteBlockInstrument.HARP;
|
||||||
|
NoteBlockInstrument wood = NoteBlockInstrument.BASS;
|
||||||
|
// NoteBlockInstrument gold = NoteBlockInstrument.BELL;
|
||||||
|
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_Z, 0), new Note(wood, (byte) 6));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_S, 0), new Note(wood, (byte) 7));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_X, 0), new Note(wood, (byte) 8));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_D, 0), new Note(wood, (byte) 9));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_C, 0), new Note(wood, (byte) 10));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_V, 0), new Note(wood, (byte) 11));
|
||||||
|
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_G, 0), new Note(dirt, (byte) 0));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_B, 0), new Note(dirt, (byte) 1));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_H, 0), new Note(dirt, (byte) 2));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_N, 0), new Note(dirt, (byte) 3));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_J, 0), new Note(dirt, (byte) 4));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_M, 0), new Note(dirt, (byte) 5));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_COMMA, 0), new Note(dirt, (byte) 6));
|
||||||
|
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_Q, 0), new Note(dirt, (byte) 6));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_2, 0), new Note(dirt, (byte) 7));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_W, 0), new Note(dirt, (byte) 8));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_3, 0), new Note(dirt, (byte) 9));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_E, 0), new Note(dirt, (byte) 10));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_R, 0), new Note(dirt, (byte) 11));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_5, 0), new Note(dirt, (byte) 12));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_T, 0), new Note(dirt, (byte) 13));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_6, 0), new Note(dirt, (byte) 14));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_Y, 0), new Note(dirt, (byte) 15));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_7, 0), new Note(dirt, (byte) 16));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_U, 0), new Note(dirt, (byte) 17));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_I, 0), new Note(dirt, (byte) 18));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_9, 0), new Note(dirt, (byte) 19));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_O, 0), new Note(dirt, (byte) 20));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_0, 0), new Note(dirt, (byte) 21));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_P, 0), new Note(dirt, (byte) 22));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_LEFT_BRACKET, 0), new Note(dirt, (byte) 23));
|
||||||
|
mappings.put(InputUtil.fromKeyCode(InputUtil.GLFW_KEY_EQUAL, 0), new Note(dirt, (byte) 24));
|
||||||
|
|
||||||
|
|
||||||
|
saveMappings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (FileReader reader = new FileReader(MAPPINGS_FILE)) {
|
||||||
|
HashMap<String, NoteData> loadedData = GSON.fromJson(reader, MAPPING_TYPE);
|
||||||
|
mappings.clear();
|
||||||
|
if (loadedData != null) {
|
||||||
|
for (Map.Entry<String, NoteData> entry : loadedData.entrySet()) {
|
||||||
|
InputUtil.Key key = InputUtil.fromTranslationKey(entry.getKey());
|
||||||
|
Note note = entry.getValue().toNote();
|
||||||
|
if (key != InputUtil.UNKNOWN_KEY && note != null) {
|
||||||
|
mappings.put(key, note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Main.LOGGER.info("已加载按键映射。");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Main.LOGGER.error("加载按键映射失败。", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void saveMappings() {
|
||||||
|
MAPPINGS_FILE.getParentFile().mkdirs();
|
||||||
|
try (FileWriter writer = new FileWriter(MAPPINGS_FILE)) {
|
||||||
|
HashMap<String, NoteData> dataToSave = new HashMap<>();
|
||||||
|
for (Map.Entry<InputUtil.Key, Note> entry : mappings.entrySet()) {
|
||||||
|
dataToSave.put(entry.getKey().getTranslationKey(), new NoteData(entry.getValue()));
|
||||||
|
}
|
||||||
|
GSON.toJson(dataToSave, writer);
|
||||||
|
Main.LOGGER.info("已保存按键映射。");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Main.LOGGER.error("保存按键映射失败。", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Note getNoteForKey(InputUtil.Key key) {
|
||||||
|
return mappings.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMapping(InputUtil.Key key, Note note) {
|
||||||
|
mappings.put(key, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeMapping(InputUtil.Key key) {
|
||||||
|
mappings.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<InputUtil.Key, Note> getMappings() {
|
||||||
|
return new HashMap<>(mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getNoteDisplayName(Note note) {
|
||||||
|
if (note == null) return "未设置";
|
||||||
|
|
||||||
|
String instrumentTranslationKey = "block.minecraft.note_block.instrument." + note.instrument().asString();
|
||||||
|
String instrumentName = Text.translatable(instrumentTranslationKey).getString();
|
||||||
|
|
||||||
|
int pitch = note.note();
|
||||||
|
String[] noteNames = {"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F"};
|
||||||
|
|
||||||
|
int octave;
|
||||||
|
if (pitch >= 19) {
|
||||||
|
octave = 1;
|
||||||
|
} else if (pitch >= 7) {
|
||||||
|
octave = 0;
|
||||||
|
} else {
|
||||||
|
octave = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int noteIndexInArray = (pitch - 7 + 12 * 2) % 12;
|
||||||
|
String noteName = noteNames[noteIndexInArray];
|
||||||
|
|
||||||
|
return instrumentName + " " + noteName + "(" + octave + ")";
|
||||||
|
}
|
||||||
|
}
|
475
src/main/java/semmiedev/disc_jockey_revive/LiveDjPlayer.java
Normal file
475
src/main/java/semmiedev/disc_jockey_revive/LiveDjPlayer.java
Normal file
@ -0,0 +1,475 @@
|
|||||||
|
package semmiedev.disc_jockey_revive;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.Blocks;
|
||||||
|
import net.minecraft.block.enums.NoteBlockInstrument;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.hud.ChatHud;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.client.network.PlayerListEntry;
|
||||||
|
import net.minecraft.client.world.ClientWorld;
|
||||||
|
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
|
||||||
|
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
|
||||||
|
import net.minecraft.state.property.Properties;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Formatting;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Pair;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.*;
|
||||||
|
import net.minecraft.world.GameMode;
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class LiveDjPlayer implements ClientTickEvents.StartWorldTick {
|
||||||
|
|
||||||
|
private HashMap<NoteBlockInstrument, HashMap<Byte, BlockPos>> noteBlocks = null;
|
||||||
|
private boolean tuned = false;
|
||||||
|
private boolean tuningRequested = false;
|
||||||
|
|
||||||
|
private long last100MsSpanAt = -1L;
|
||||||
|
private int last100MsSpanEstimatedPackets = 0;
|
||||||
|
final private int last100MsReducePacketsAfter = 300 / 10, last100MsStopPacketsAfter = 450 / 10;
|
||||||
|
private long reducePacketsUntil = -1L, stopPacketsUntil = -1L;
|
||||||
|
private long lastLookSentAt = -1L, lastSwingSentAt = -1L;
|
||||||
|
private long lastInteractAt = -1;
|
||||||
|
private float availableInteracts = 8;
|
||||||
|
private int tuneInitialUntunedBlocks = -1;
|
||||||
|
private HashMap<BlockPos, Pair<Integer, Long>> notePredictions = new HashMap<>();
|
||||||
|
|
||||||
|
public HashMap<Block, Integer> missingInstrumentBlocks = new HashMap<>();
|
||||||
|
|
||||||
|
public LiveDjPlayer() {
|
||||||
|
Main.TICK_LISTENERS.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调音
|
||||||
|
public synchronized void startTuning() {
|
||||||
|
if (tuned && noteBlocks != null) {
|
||||||
|
MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(Text.translatable(Main.MOD_ID+".player.retuning").formatted(Formatting.YELLOW));
|
||||||
|
} else {
|
||||||
|
MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(Text.translatable(Main.MOD_ID+".player.tuning_started").formatted(Formatting.YELLOW));
|
||||||
|
}
|
||||||
|
noteBlocks = null;
|
||||||
|
notePredictions.clear();
|
||||||
|
tuned = false;
|
||||||
|
tuneInitialUntunedBlocks = -1;
|
||||||
|
tuningRequested = true;
|
||||||
|
|
||||||
|
last100MsSpanAt = System.currentTimeMillis();
|
||||||
|
last100MsSpanEstimatedPackets = 0;
|
||||||
|
reducePacketsUntil = -1L;
|
||||||
|
stopPacketsUntil = -1L;
|
||||||
|
lastLookSentAt = -1L;
|
||||||
|
lastSwingSentAt = -1L;
|
||||||
|
lastInteractAt = -1;
|
||||||
|
availableInteracts = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止调音
|
||||||
|
public synchronized void stopTuning() {
|
||||||
|
tuningRequested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否正在调音
|
||||||
|
public boolean isTuningActive() {
|
||||||
|
return tuningRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否已调音
|
||||||
|
public boolean isTuned() {
|
||||||
|
return tuned;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<NoteBlockInstrument, HashMap<Byte, BlockPos>> getNoteBlocks() {
|
||||||
|
return noteBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放
|
||||||
|
public boolean playNoteBlock(Note note) {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
ClientWorld world = client.world;
|
||||||
|
ClientPlayerEntity player = client.player;
|
||||||
|
GameMode gameMode = client.interactionManager == null ? null : client.interactionManager.getCurrentGameMode();
|
||||||
|
|
||||||
|
if (world == null || player == null || gameMode == null || !gameMode.isSurvivalLike()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noteBlocks == null || !tuned) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable BlockPos blockPos = noteBlocks.get(note.instrument()).get(note.note());
|
||||||
|
if(blockPos == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canInteractWith(player, blockPos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendNotePacket(blockPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取可交互的
|
||||||
|
private boolean sendNotePacket(BlockPos blockPos) {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
ClientPlayerEntity player = client.player;
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
if(last100MsSpanAt != -1L && now - last100MsSpanAt >= 100) {
|
||||||
|
last100MsSpanEstimatedPackets = 0;
|
||||||
|
last100MsSpanAt = now;
|
||||||
|
}else if (last100MsSpanAt == -1L) {
|
||||||
|
last100MsSpanAt = now;
|
||||||
|
last100MsSpanEstimatedPackets = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stopPacketsUntil != -1L && stopPacketsUntil >= now) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (reducePacketsUntil != -1L && reducePacketsUntil >= now && last100MsSpanEstimatedPackets >= last100MsReducePacketsAfter) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lastInteractAt != -1L) {
|
||||||
|
availableInteracts += ((System.currentTimeMillis() - lastInteractAt) / (310.0f / 8.0f));
|
||||||
|
availableInteracts = Math.min(8f, Math.max(0f, availableInteracts));
|
||||||
|
}else {
|
||||||
|
availableInteracts = 8f;
|
||||||
|
lastInteractAt = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (availableInteracts < 1f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3d unit = Vec3d.ofCenter(blockPos, 0.5).subtract(player.getEyePos()).normalize();
|
||||||
|
boolean packetsSent = false;
|
||||||
|
|
||||||
|
if((lastLookSentAt == -1L || now - lastLookSentAt >= 50) && last100MsSpanEstimatedPackets < last100MsReducePacketsAfter) {
|
||||||
|
client.getNetworkHandler().sendPacket(new PlayerMoveC2SPacket.LookAndOnGround(MathHelper.wrapDegrees((float) (MathHelper.atan2(unit.z, unit.x) * 57.2957763671875) - 90.0f), MathHelper.wrapDegrees((float) (-(MathHelper.atan2(unit.y, Math.sqrt(unit.x * unit.x + unit.z * unit.z)) * 57.2957763671875))), true, false));
|
||||||
|
last100MsSpanEstimatedPackets++;
|
||||||
|
lastLookSentAt = now;
|
||||||
|
packetsSent = true;
|
||||||
|
} else if (last100MsSpanEstimatedPackets >= last100MsReducePacketsAfter) {
|
||||||
|
reducePacketsUntil = Math.max(reducePacketsUntil, now + 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(last100MsSpanEstimatedPackets < last100MsStopPacketsAfter) {
|
||||||
|
client.player.networkHandler.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, blockPos, Direction.UP, 0));
|
||||||
|
last100MsSpanEstimatedPackets++;
|
||||||
|
client.player.networkHandler.sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.ABORT_DESTROY_BLOCK, blockPos, Direction.UP, 0));
|
||||||
|
last100MsSpanEstimatedPackets++;
|
||||||
|
lastInteractAt = now;
|
||||||
|
availableInteracts -= 1f;
|
||||||
|
packetsSent = true;
|
||||||
|
} else {
|
||||||
|
Main.LOGGER.info("LiveDjPlayer: 短暂暂停所有数据包,因为速率受限!");
|
||||||
|
stopPacketsUntil = Math.max(stopPacketsUntil, now + 250);
|
||||||
|
reducePacketsUntil = Math.max(reducePacketsUntil, now + 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((lastSwingSentAt == -1L || now - lastSwingSentAt >= 50) && last100MsSpanEstimatedPackets < last100MsReducePacketsAfter) {
|
||||||
|
client.executeSync(() -> client.player.swingHand(Hand.MAIN_HAND));
|
||||||
|
lastSwingSentAt = now;
|
||||||
|
last100MsSpanEstimatedPackets++;
|
||||||
|
packetsSent = true;
|
||||||
|
} else if (last100MsSpanEstimatedPackets >= last100MsReducePacketsAfter) {
|
||||||
|
reducePacketsUntil = Math.max(reducePacketsUntil, now + 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return packetsSent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartTick(ClientWorld world) {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
if(world == null || client.world == null || client.player == null) return;
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if(last100MsSpanAt != -1L && now - last100MsSpanAt >= 100) {
|
||||||
|
last100MsSpanEstimatedPackets = 0;
|
||||||
|
last100MsSpanAt = now;
|
||||||
|
}else if (last100MsSpanAt == -1L) {
|
||||||
|
last100MsSpanAt = now;
|
||||||
|
last100MsSpanEstimatedPackets = 0;
|
||||||
|
}
|
||||||
|
if(lastInteractAt != -1L) {
|
||||||
|
availableInteracts += ((System.currentTimeMillis() - lastInteractAt) / (310.0f / 8.0f));
|
||||||
|
availableInteracts = Math.min(8f, Math.max(0f, availableInteracts));
|
||||||
|
}else {
|
||||||
|
availableInteracts = 8f;
|
||||||
|
lastInteractAt = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<BlockPos> outdatedPredictions = new ArrayList<>();
|
||||||
|
for(Map.Entry<BlockPos, Pair<Integer, Long>> entry : notePredictions.entrySet()) {
|
||||||
|
if(entry.getValue().getRight() < System.currentTimeMillis())
|
||||||
|
outdatedPredictions.add(entry.getKey());
|
||||||
|
}
|
||||||
|
for(BlockPos outdatedPrediction : outdatedPredictions) notePredictions.remove(outdatedPrediction);
|
||||||
|
|
||||||
|
if (tuningRequested && !tuned) {
|
||||||
|
ClientPlayerEntity player = client.getInstance().player;
|
||||||
|
GameMode gameMode = client.interactionManager == null ? null : client.interactionManager.getCurrentGameMode();
|
||||||
|
if (player == null || gameMode == null || !gameMode.isSurvivalLike()) {
|
||||||
|
noteBlocks = null;
|
||||||
|
notePredictions.clear();
|
||||||
|
tuned = false;
|
||||||
|
tuneInitialUntunedBlocks = -1;
|
||||||
|
tuningRequested = false;
|
||||||
|
client.inGameHud.getChatHud().addMessage(Text.translatable(Main.MOD_ID+".player.invalid_state_tuning").formatted(Formatting.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noteBlocks == null) {
|
||||||
|
noteBlocks = new HashMap<>();
|
||||||
|
|
||||||
|
HashMap<NoteBlockInstrument, ArrayList<BlockPos>> noteblocksForInstrument = new HashMap<>();
|
||||||
|
for(NoteBlockInstrument instrument : NoteBlockInstrument.values())
|
||||||
|
noteblocksForInstrument.put(instrument, new ArrayList<>());
|
||||||
|
final Vec3d playerEyePos = player.getEyePos();
|
||||||
|
|
||||||
|
final int maxOffset;
|
||||||
|
if(Main.config.expectedServerVersion == ModConfig.ExpectedServerVersion.v1_20_4_Or_Earlier) {
|
||||||
|
maxOffset = 7;
|
||||||
|
}else if(Main.config.expectedServerVersion == ModConfig.ExpectedServerVersion.v1_20_5_Or_Later) {
|
||||||
|
maxOffset = (int) Math.ceil(player.getBlockInteractionRange() + 1.0 + 1.0);
|
||||||
|
}else if(Main.config.expectedServerVersion == ModConfig.ExpectedServerVersion.All) {
|
||||||
|
maxOffset = Math.min(7, (int) Math.ceil(player.getBlockInteractionRange() + 1.0 + 1.0));
|
||||||
|
}else {
|
||||||
|
throw new NotImplementedException("ExpectedServerVersion Value not implemented: " + Main.config.expectedServerVersion.name());
|
||||||
|
}
|
||||||
|
final ArrayList<Integer> orderedOffsets = new ArrayList<>();
|
||||||
|
for(int offset = 0; offset <= maxOffset; offset++) {
|
||||||
|
orderedOffsets.add(offset);
|
||||||
|
if(offset != 0) orderedOffsets.add(offset * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(NoteBlockInstrument instrument : noteblocksForInstrument.keySet().toArray(new NoteBlockInstrument[0])) {
|
||||||
|
for (int y : orderedOffsets) {
|
||||||
|
for (int x : orderedOffsets) {
|
||||||
|
for (int z : orderedOffsets) {
|
||||||
|
Vec3d vec3d = playerEyePos.add(x, y, z);
|
||||||
|
BlockPos blockPos = new BlockPos(MathHelper.floor(vec3d.x), MathHelper.floor(vec3d.y), MathHelper.floor(vec3d.z));
|
||||||
|
if (!canInteractWith(player, blockPos))
|
||||||
|
continue;
|
||||||
|
BlockState blockState = world.getBlockState(blockPos);
|
||||||
|
if (!blockState.isOf(Blocks.NOTE_BLOCK) || !world.isAir(blockPos.up()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (blockState.get(Properties.INSTRUMENT) == instrument)
|
||||||
|
noteblocksForInstrument.get(instrument).add(blockPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Note> neededNotes = new ArrayList<>();
|
||||||
|
|
||||||
|
if (Main.keyMappingManager != null) {
|
||||||
|
for (Note mappedNote : Main.keyMappingManager.getMappings().values()) {
|
||||||
|
if (mappedNote != null && !neededNotes.contains(mappedNote)) {
|
||||||
|
neededNotes.add(mappedNote);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Note> capturedNotes = new ArrayList<>();
|
||||||
|
for(Note note : neededNotes) {
|
||||||
|
ArrayList<BlockPos> availableBlocks = noteblocksForInstrument.get(note.instrument());
|
||||||
|
if(availableBlocks == null) {
|
||||||
|
getNotesMapForInstrument(note.instrument()).put(note.note(), null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BlockPos bestBlockPos = null;
|
||||||
|
int bestBlockTuningSteps = Integer.MAX_VALUE;
|
||||||
|
for(BlockPos blockPos : availableBlocks) {
|
||||||
|
boolean alreadyAssigned = false;
|
||||||
|
if (noteBlocks != null) {
|
||||||
|
for (HashMap<Byte, BlockPos> instrumentNotes : noteBlocks.values()) {
|
||||||
|
if (instrumentNotes != null && instrumentNotes.containsValue(blockPos)) {
|
||||||
|
alreadyAssigned = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (alreadyAssigned) continue;
|
||||||
|
|
||||||
|
int wantedNote = note.note();
|
||||||
|
BlockState blockState = world.getBlockState(blockPos);
|
||||||
|
if (!blockState.contains(Properties.NOTE)) continue;
|
||||||
|
int currentNote = blockState.get(Properties.NOTE);
|
||||||
|
int tuningSteps = wantedNote >= currentNote ? wantedNote - currentNote : (25 - currentNote) + wantedNote;
|
||||||
|
|
||||||
|
if(tuningSteps < bestBlockTuningSteps) {
|
||||||
|
bestBlockPos = blockPos;
|
||||||
|
bestBlockTuningSteps = tuningSteps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bestBlockPos != null) {
|
||||||
|
capturedNotes.add(note);
|
||||||
|
availableBlocks.remove(bestBlockPos);
|
||||||
|
getNotesMapForInstrument(note.instrument()).put(note.note(), bestBlockPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Note> missingNotes = new ArrayList<>(neededNotes);
|
||||||
|
missingNotes.removeAll(capturedNotes);
|
||||||
|
if (!missingNotes.isEmpty()) {
|
||||||
|
ChatHud chatHud = MinecraftClient.getInstance().inGameHud.getChatHud();
|
||||||
|
chatHud.addMessage(Text.translatable(Main.MOD_ID+".player.invalid_note_blocks").formatted(Formatting.RED));
|
||||||
|
|
||||||
|
HashMap<Block, Integer> missing = new HashMap<>();
|
||||||
|
for (Note note : missingNotes) {
|
||||||
|
Block block = Note.INSTRUMENT_BLOCKS.get(note.instrument());
|
||||||
|
Integer got = missing.get(block);
|
||||||
|
if (got == null) got = 0;
|
||||||
|
missing.put(block, got + 1);
|
||||||
|
}
|
||||||
|
missingInstrumentBlocks = missing;
|
||||||
|
missing.forEach((block, integer) -> chatHud.addMessage(Text.literal(block.getName().getString()+" × "+integer).formatted(Formatting.RED)));
|
||||||
|
} else {
|
||||||
|
missingInstrumentBlocks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ping = 0;
|
||||||
|
{
|
||||||
|
PlayerListEntry playerListEntry;
|
||||||
|
if (client.getNetworkHandler() != null && (playerListEntry = client.getNetworkHandler().getPlayerListEntry(client.player.getGameProfile().getId())) != null)
|
||||||
|
ping = playerListEntry.getLatency();
|
||||||
|
}
|
||||||
|
|
||||||
|
int fullyTunedBlocks = 0;
|
||||||
|
HashMap<BlockPos, Integer> untunedNotes = new HashMap<>();
|
||||||
|
|
||||||
|
if (noteBlocks != null) {
|
||||||
|
for (HashMap<Byte, BlockPos> instrumentNotes : noteBlocks.values()) {
|
||||||
|
if (instrumentNotes == null) continue;
|
||||||
|
for (Map.Entry<Byte, BlockPos> entry : instrumentNotes.entrySet()) {
|
||||||
|
BlockPos blockPos = entry.getValue();
|
||||||
|
Byte wantedNote = entry.getKey();
|
||||||
|
|
||||||
|
if (blockPos == null) continue;
|
||||||
|
|
||||||
|
BlockState blockState = world.getBlockState(blockPos);
|
||||||
|
if (!blockState.contains(Properties.NOTE)) {
|
||||||
|
Main.LOGGER.warn("LiveDjPlayer: 音符盒在 {} 处在调音过程中改变了状态", blockPos);
|
||||||
|
noteBlocks = null;
|
||||||
|
tuned = false;
|
||||||
|
tuningRequested = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int assumedNote = notePredictions.containsKey(blockPos) ? notePredictions.get(blockPos).getLeft() : blockState.get(Properties.NOTE);
|
||||||
|
|
||||||
|
byte wantedNotePrimitive = wantedNote.byteValue();
|
||||||
|
|
||||||
|
if(assumedNote == wantedNotePrimitive && blockState.get(Properties.NOTE).intValue() == wantedNotePrimitive) {
|
||||||
|
fullyTunedBlocks++;
|
||||||
|
} else if (assumedNote != wantedNotePrimitive) {
|
||||||
|
untunedNotes.put(blockPos, blockState.get(Properties.NOTE).intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int existingUniqueNotesCount = 0;
|
||||||
|
if (noteBlocks != null) {
|
||||||
|
for(HashMap<Byte, BlockPos> instrumentNotes : noteBlocks.values()) {
|
||||||
|
if (instrumentNotes != null) {
|
||||||
|
for (BlockPos pos : instrumentNotes.values()) {
|
||||||
|
if (pos != null) {
|
||||||
|
existingUniqueNotesCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(untunedNotes.isEmpty() && fullyTunedBlocks == existingUniqueNotesCount) {
|
||||||
|
if(lastInteractAt == -1 || System.currentTimeMillis() - lastInteractAt >= ping * 2 + 100) {
|
||||||
|
tuned = true;
|
||||||
|
tuningRequested = false;
|
||||||
|
tuneInitialUntunedBlocks = -1;
|
||||||
|
client.inGameHud.getChatHud().addMessage(Text.translatable(Main.MOD_ID+".player.tuned").formatted(Formatting.GREEN));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tuned = false;
|
||||||
|
if(tuneInitialUntunedBlocks == -1 || tuneInitialUntunedBlocks < untunedNotes.size())
|
||||||
|
tuneInitialUntunedBlocks = untunedNotes.size();
|
||||||
|
if (availableInteracts >= 1f && !untunedNotes.isEmpty()) {
|
||||||
|
BlockPos blockPosToTune = untunedNotes.keySet().iterator().next();
|
||||||
|
int currentNote = untunedNotes.get(blockPosToTune);
|
||||||
|
Byte targetNote = null;
|
||||||
|
if (noteBlocks != null) {
|
||||||
|
for (HashMap<Byte, BlockPos> instrumentNotes : noteBlocks.values()) {
|
||||||
|
if (instrumentNotes != null) {
|
||||||
|
for (Map.Entry<Byte, BlockPos> entry : instrumentNotes.entrySet()) {
|
||||||
|
if (blockPosToTune.equals(entry.getValue())) {
|
||||||
|
targetNote = entry.getKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetNote != null) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetNote != null) {
|
||||||
|
byte targetNotePrimitive = targetNote.byteValue();
|
||||||
|
int tuningSteps = targetNotePrimitive >= currentNote ? targetNotePrimitive - currentNote : (25 - currentNote) + targetNotePrimitive;
|
||||||
|
|
||||||
|
if (tuningSteps > 0) {
|
||||||
|
int predictedNote = (currentNote + 1) % 25;
|
||||||
|
notePredictions.put(blockPosToTune, new Pair<>(predictedNote, System.currentTimeMillis() + ping * 2 + 100));
|
||||||
|
client.interactionManager.interactBlock(client.player, Hand.MAIN_HAND, new BlockHitResult(Vec3d.of(blockPosToTune), Direction.UP, blockPosToTune, false));
|
||||||
|
lastInteractAt = System.currentTimeMillis();
|
||||||
|
availableInteracts -= 1f;
|
||||||
|
client.player.swingHand(Hand.MAIN_HAND);
|
||||||
|
} else {
|
||||||
|
untunedNotes.remove(blockPosToTune);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
untunedNotes.remove(blockPosToTune);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashMap<Byte, BlockPos> getNotesMapForInstrument(NoteBlockInstrument instrument) {
|
||||||
|
if (noteBlocks == null) {
|
||||||
|
noteBlocks = new HashMap<>();
|
||||||
|
}
|
||||||
|
return noteBlocks.computeIfAbsent(instrument, k -> new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检测玩家是否可以与指定方块进行交互
|
||||||
|
public boolean canInteractWith(ClientPlayerEntity player, BlockPos blockPos) {
|
||||||
|
final Vec3d eyePos = player.getEyePos();
|
||||||
|
if(Main.config.expectedServerVersion == ModConfig.ExpectedServerVersion.v1_20_4_Or_Earlier) {
|
||||||
|
return eyePos.squaredDistanceTo(blockPos.toCenterPos()) <= 6.0 * 6.0;
|
||||||
|
}else if(Main.config.expectedServerVersion == ModConfig.ExpectedServerVersion.v1_20_5_Or_Later) {
|
||||||
|
double blockInteractRange = player.getBlockInteractionRange() + 1.0;
|
||||||
|
return new Box(blockPos).squaredMagnitude(eyePos) < blockInteractRange * blockInteractRange;
|
||||||
|
}else if(Main.config.expectedServerVersion == ModConfig.ExpectedServerVersion.All) {
|
||||||
|
double blockInteractRange = player.getBlockInteractionRange() + 1.0;
|
||||||
|
return eyePos.squaredDistanceTo(blockPos.toCenterPos()) <= 6.0 * 6.0 && new Box(blockPos).squaredMagnitude(eyePos) < blockInteractRange * blockInteractRange;
|
||||||
|
}else {
|
||||||
|
throw new NotImplementedException("ExpectedServerVersion Value not implemented: " + Main.config.expectedServerVersion.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ import org.lwjgl.glfw.GLFW;
|
|||||||
import semmiedev.disc_jockey_revive.gui.hud.BlocksOverlay;
|
import semmiedev.disc_jockey_revive.gui.hud.BlocksOverlay;
|
||||||
import semmiedev.disc_jockey_revive.gui.hud.PlaybackProgressOverlay;
|
import semmiedev.disc_jockey_revive.gui.hud.PlaybackProgressOverlay;
|
||||||
import semmiedev.disc_jockey_revive.gui.screen.DiscJockeyScreen;
|
import semmiedev.disc_jockey_revive.gui.screen.DiscJockeyScreen;
|
||||||
|
import semmiedev.disc_jockey_revive.gui.screen.LiveDjScreen;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -34,10 +35,13 @@ public class Main implements ClientModInitializer {
|
|||||||
public static final ArrayList<ClientTickEvents.StartWorldTick> TICK_LISTENERS = new ArrayList<>();
|
public static final ArrayList<ClientTickEvents.StartWorldTick> TICK_LISTENERS = new ArrayList<>();
|
||||||
public static final Previewer PREVIEWER = new Previewer();
|
public static final Previewer PREVIEWER = new Previewer();
|
||||||
public static final SongPlayer SONG_PLAYER = new SongPlayer();
|
public static final SongPlayer SONG_PLAYER = new SongPlayer();
|
||||||
|
public static final LiveDjPlayer LIVE_DJ_PLAYER = new LiveDjPlayer();
|
||||||
|
|
||||||
public static File songsFolder;
|
public static File songsFolder;
|
||||||
public static ModConfig config;
|
public static ModConfig config;
|
||||||
public static ConfigHolder<ModConfig> configHolder;
|
public static ConfigHolder<ModConfig> configHolder;
|
||||||
|
public static KeyMappingManager keyMappingManager;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
@ -49,8 +53,12 @@ public class Main implements ClientModInitializer {
|
|||||||
|
|
||||||
SongLoader.loadSongs();
|
SongLoader.loadSongs();
|
||||||
|
|
||||||
|
keyMappingManager = new KeyMappingManager();
|
||||||
|
|
||||||
KeyBinding openScreenKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(MOD_ID+".key_bind.open_screen", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_J, "key.category."+MOD_ID));
|
KeyBinding openScreenKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(MOD_ID+".key_bind.open_screen", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_J, "key.category."+MOD_ID));
|
||||||
|
|
||||||
|
KeyBinding openLiveDjScreenKeyBind = KeyBindingHelper.registerKeyBinding(new KeyBinding(MOD_ID+".key_bind.open_live_dj_screen", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, "key.category."+MOD_ID));
|
||||||
|
|
||||||
ClientTickEvents.START_CLIENT_TICK.register(new ClientTickEvents.StartTick() {
|
ClientTickEvents.START_CLIENT_TICK.register(new ClientTickEvents.StartTick() {
|
||||||
private ClientWorld prevWorld;
|
private ClientWorld prevWorld;
|
||||||
|
|
||||||
@ -59,6 +67,7 @@ public class Main implements ClientModInitializer {
|
|||||||
if (prevWorld != client.world) {
|
if (prevWorld != client.world) {
|
||||||
PREVIEWER.stop();
|
PREVIEWER.stop();
|
||||||
SONG_PLAYER.stop();
|
SONG_PLAYER.stop();
|
||||||
|
LIVE_DJ_PLAYER.stopTuning();
|
||||||
}
|
}
|
||||||
prevWorld = client.world;
|
prevWorld = client.world;
|
||||||
|
|
||||||
@ -70,6 +79,14 @@ public class Main implements ClientModInitializer {
|
|||||||
client.setScreen(new DiscJockeyScreen());
|
client.setScreen(new DiscJockeyScreen());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (openLiveDjScreenKeyBind.wasPressed()) {
|
||||||
|
if (SongLoader.loadingSongs) {
|
||||||
|
client.inGameHud.getChatHud().addMessage(Text.translatable(Main.MOD_ID+".still_loading").formatted(Formatting.RED));
|
||||||
|
SongLoader.showToast = true;
|
||||||
|
} else {
|
||||||
|
client.setScreen(new LiveDjScreen());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -84,6 +101,7 @@ public class Main implements ClientModInitializer {
|
|||||||
ClientLoginConnectionEvents.DISCONNECT.register((handler, client) -> {
|
ClientLoginConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||||
PREVIEWER.stop();
|
PREVIEWER.stop();
|
||||||
SONG_PLAYER.stop();
|
SONG_PLAYER.stop();
|
||||||
|
LIVE_DJ_PLAYER.stopTuning();
|
||||||
});
|
});
|
||||||
|
|
||||||
HudRenderCallback.EVENT.register(new PlaybackProgressOverlay());
|
HudRenderCallback.EVENT.register(new PlaybackProgressOverlay());
|
||||||
|
@ -49,4 +49,7 @@ public class ModConfig implements ConfigData {
|
|||||||
|
|
||||||
@ConfigEntry.Gui.Tooltip(count = 1)
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
public boolean showHudProgressBar = true;
|
public boolean showHudProgressBar = true;
|
||||||
|
|
||||||
|
@ConfigEntry.Gui.Tooltip(count = 1)
|
||||||
|
public boolean debugModeEnabled = false;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,135 @@
|
|||||||
|
package semmiedev.disc_jockey_revive.gui;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationPart;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.EntryListWidget;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import semmiedev.disc_jockey_revive.KeyMappingManager;
|
||||||
|
import semmiedev.disc_jockey_revive.Main;
|
||||||
|
import semmiedev.disc_jockey_revive.Note;
|
||||||
|
import semmiedev.disc_jockey_revive.gui.screen.EditKeyMappingsScreen;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class KeyMappingListWidget extends EntryListWidget<KeyMappingListWidget.KeyMappingEntry> {
|
||||||
|
|
||||||
|
private final EditKeyMappingsScreen parentScreen;
|
||||||
|
private boolean buttonsActive = true;
|
||||||
|
|
||||||
|
public KeyMappingListWidget(MinecraftClient client, int width, int height, int top, int itemHeight, EditKeyMappingsScreen parentScreen) {
|
||||||
|
super(client, width, height, top, itemHeight);
|
||||||
|
this.parentScreen = parentScreen;
|
||||||
|
this.centerListVertically = false;
|
||||||
|
}
|
||||||
|
public void setMappings(Map<InputUtil.Key, Note> mappings) {
|
||||||
|
this.clearEntries();
|
||||||
|
for (Map.Entry<InputUtil.Key, Note> entry : mappings.entrySet()) {
|
||||||
|
|
||||||
|
this.addEntry(new KeyMappingEntry(entry.getKey(), entry.getValue(), this.parentScreen));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.children().sort(Comparator.comparing(entry -> entry.getKey().getTranslationKey()));
|
||||||
|
|
||||||
|
setButtonsActive(this.buttonsActive);
|
||||||
|
}
|
||||||
|
public void setButtonsActive(boolean active) {
|
||||||
|
this.buttonsActive = active;
|
||||||
|
|
||||||
|
for (KeyMappingEntry entry : children()) {
|
||||||
|
entry.setButtonsActive(active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int getRowWidth() {
|
||||||
|
return this.width - 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getScrollbarX() {
|
||||||
|
return this.width - 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public class KeyMappingEntry extends EntryListWidget.Entry<KeyMappingEntry> {
|
||||||
|
private final InputUtil.Key key;
|
||||||
|
private final Note note;
|
||||||
|
private final EditKeyMappingsScreen screen;
|
||||||
|
|
||||||
|
private ButtonWidget changeButton;
|
||||||
|
private ButtonWidget removeButton;
|
||||||
|
|
||||||
|
public KeyMappingEntry(InputUtil.Key key, Note note, EditKeyMappingsScreen screen) {
|
||||||
|
this.key = key;
|
||||||
|
this.note = note;
|
||||||
|
this.screen = screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputUtil.Key getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Note getNote() {
|
||||||
|
return note;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setButtonsActive(boolean active) {
|
||||||
|
if (changeButton != null) changeButton.active = active;
|
||||||
|
if (removeButton != null) removeButton.active = active;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
int textY = y + (entryHeight - client.textRenderer.fontHeight) / 2;
|
||||||
|
Text keyText = Text.translatable(key.getTranslationKey());
|
||||||
|
context.drawTextWithShadow(client.textRenderer, keyText, x + 5, textY, 0xFFFFFF);
|
||||||
|
String noteDisplayName = KeyMappingManager.getNoteDisplayName(note);
|
||||||
|
context.drawTextWithShadow(client.textRenderer, noteDisplayName, x + 100, textY, 0xAAAAAA);
|
||||||
|
int buttonWidth = 50;
|
||||||
|
int buttonHeight = 18;
|
||||||
|
int buttonY = y + (entryHeight - buttonHeight) / 2;
|
||||||
|
int buttonX = x + entryWidth - buttonWidth - 5;
|
||||||
|
changeButton = ButtonWidget.builder(Text.translatable(Main.MOD_ID + ".screen.edit_mappings.change"), button -> {
|
||||||
|
screen.startWaitingForKeyPress(this);
|
||||||
|
}).dimensions(buttonX - buttonWidth - 5, buttonY, buttonWidth, buttonHeight).build();
|
||||||
|
changeButton.render(context, mouseX, mouseY, tickDelta);
|
||||||
|
changeButton.active = buttonsActive;
|
||||||
|
removeButton = ButtonWidget.builder(Text.translatable(Main.MOD_ID + ".screen.edit_mappings.remove"), button -> {
|
||||||
|
screen.removeMapping(key);
|
||||||
|
}).dimensions(buttonX, buttonY, buttonWidth, buttonHeight).build();
|
||||||
|
removeButton.render(context, mouseX, mouseY, tickDelta);
|
||||||
|
removeButton.active = buttonsActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
|
||||||
|
if (changeButton.mouseClicked(mouseX, mouseY, button)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (removeButton.mouseClicked(mouseX, mouseY, button)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMouseOver(double mouseX, double mouseY) {
|
||||||
|
return super.isMouseOver(mouseX, mouseY) ||
|
||||||
|
(changeButton != null && changeButton.isMouseOver(mouseX, mouseY)) ||
|
||||||
|
(removeButton != null && removeButton.isMouseOver(mouseX, mouseY));
|
||||||
|
}
|
||||||
|
public void appendClickableNarrations(NarrationMessageBuilder builder) {
|
||||||
|
builder.put(NarrationPart.TITLE, Text.translatable(key.getTranslationKey()).append(" -> ").append(KeyMappingManager.getNoteDisplayName(note)));
|
||||||
|
if (changeButton != null) changeButton.appendNarrations(builder);
|
||||||
|
if (removeButton != null) removeButton.appendNarrations(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -29,7 +29,7 @@ public class PlaybackProgressOverlay implements HudRenderCallback {
|
|||||||
int screenHeight = context.getScaledWindowHeight();
|
int screenHeight = context.getScaledWindowHeight();
|
||||||
|
|
||||||
int barX = screenWidth / 2 - PROGRESS_BAR_WIDTH / 2;
|
int barX = screenWidth / 2 - PROGRESS_BAR_WIDTH / 2;
|
||||||
int barY = screenHeight - 50;
|
int barY = screenHeight - 55;
|
||||||
|
|
||||||
progressBarRenderer.renderProgressBar(
|
progressBarRenderer.renderProgressBar(
|
||||||
context,
|
context,
|
||||||
|
@ -56,14 +56,12 @@ public class DiscJockeyScreen extends Screen {
|
|||||||
|
|
||||||
private static final MutableText
|
private static final MutableText
|
||||||
OPEN_FOLDER = Text.translatable(Main.MOD_ID+".screen.open_folder"),
|
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"),
|
||||||
|
LIVE_DJ = Text.translatable(Main.MOD_ID+".screen.live_dj").formatted(Formatting.GOLD);
|
||||||
|
|
||||||
private ButtonWidget folderUpButton, playModeButton;
|
private ButtonWidget folderUpButton, playModeButton;
|
||||||
public SongFolder currentFolder;
|
public SongFolder currentFolder;
|
||||||
private PlayMode currentPlayMode = PlayMode.STOP_AFTER;
|
private PlayMode currentPlayMode = PlayMode.STOP_AFTER;
|
||||||
private int progressBarWidth = 200; // 进度条宽度
|
|
||||||
private int progressBarHeight = 5; // 进度条高度
|
|
||||||
private int progressBarYOffset = 5; // 进度条Y偏移
|
|
||||||
|
|
||||||
private ProgressBarRenderer progressBarRenderer;
|
private ProgressBarRenderer progressBarRenderer;
|
||||||
|
|
||||||
@ -126,14 +124,14 @@ public class DiscJockeyScreen extends Screen {
|
|||||||
if (isLargeScreen){
|
if (isLargeScreen){
|
||||||
buttonY = height - 30;
|
buttonY = height - 30;
|
||||||
} else {
|
} else {
|
||||||
buttonY = height - 60;
|
buttonY = height - 30; // awa
|
||||||
}
|
}
|
||||||
int centerX = width / 2;
|
int centerX = width / 2;
|
||||||
|
|
||||||
// 上一首
|
// 上一首
|
||||||
addDrawableChild(ButtonWidget.builder(Text.literal("◀◀◀"), button -> {
|
addDrawableChild(ButtonWidget.builder(Text.literal("◀◀◀"), button -> {
|
||||||
Main.SONG_PLAYER.playPreviousSong();
|
Main.SONG_PLAYER.playPreviousSong();
|
||||||
}).dimensions(centerX - 110, buttonY, 40, 20).build());
|
}).dimensions(centerX - 100, buttonY, 40, 20).build());
|
||||||
|
|
||||||
// 播放暂停
|
// 播放暂停
|
||||||
playButton = ButtonWidget.builder(PLAY, button -> {
|
playButton = ButtonWidget.builder(PLAY, button -> {
|
||||||
@ -168,44 +166,47 @@ public class DiscJockeyScreen extends Screen {
|
|||||||
int bottomY = height - 30;
|
int bottomY = height - 30;
|
||||||
|
|
||||||
|
|
||||||
addDrawableChild(ButtonWidget.builder(Text.translatable(Main.MOD_ID+".screen.blocks"), button -> {
|
// 音符盒
|
||||||
// TODO: 6/2/2022 Add an auto build mode
|
if (isLargeScreen) {
|
||||||
if (BlocksOverlay.itemStacks == null) {
|
addDrawableChild(ButtonWidget.builder(Text.translatable(Main.MOD_ID + ".screen.blocks"), button -> {
|
||||||
SongListWidget.SongEntry entry = songListWidget.getSelectedSongOrNull();
|
// TODO: 6/2/2022 Add an auto build mode
|
||||||
if (entry != null) {
|
if (BlocksOverlay.itemStacks == null) {
|
||||||
client.setScreen(null);
|
SongListWidget.SongEntry entry = songListWidget.getSelectedSongOrNull();
|
||||||
|
if (entry != null) {
|
||||||
|
client.setScreen(null);
|
||||||
|
|
||||||
BlocksOverlay.itemStacks = new ItemStack[0];
|
BlocksOverlay.itemStacks = new ItemStack[0];
|
||||||
BlocksOverlay.amounts = new int[0];
|
BlocksOverlay.amounts = new int[0];
|
||||||
BlocksOverlay.amountOfNoteBlocks = entry.song.uniqueNotes.size();
|
BlocksOverlay.amountOfNoteBlocks = entry.song.uniqueNotes.size();
|
||||||
|
|
||||||
for (Note note : entry.song.uniqueNotes) {
|
for (Note note : entry.song.uniqueNotes) {
|
||||||
ItemStack itemStack = Note.INSTRUMENT_BLOCKS.get(note.instrument()).asItem().getDefaultStack();
|
ItemStack itemStack = Note.INSTRUMENT_BLOCKS.get(note.instrument()).asItem().getDefaultStack();
|
||||||
int index = -1;
|
int index = -1;
|
||||||
|
|
||||||
for (int i = 0; i < BlocksOverlay.itemStacks.length; i++) {
|
for (int i = 0; i < BlocksOverlay.itemStacks.length; i++) {
|
||||||
if (BlocksOverlay.itemStacks[i].getItem() == itemStack.getItem()) {
|
if (BlocksOverlay.itemStacks[i].getItem() == itemStack.getItem()) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
BlocksOverlay.itemStacks = Arrays.copyOf(BlocksOverlay.itemStacks, BlocksOverlay.itemStacks.length + 1);
|
||||||
|
BlocksOverlay.amounts = Arrays.copyOf(BlocksOverlay.amounts, BlocksOverlay.amounts.length + 1);
|
||||||
|
|
||||||
|
BlocksOverlay.itemStacks[BlocksOverlay.itemStacks.length - 1] = itemStack;
|
||||||
|
BlocksOverlay.amounts[BlocksOverlay.amounts.length - 1] = 1;
|
||||||
|
} else {
|
||||||
|
BlocksOverlay.amounts[index] = BlocksOverlay.amounts[index] + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index == -1) {
|
|
||||||
BlocksOverlay.itemStacks = Arrays.copyOf(BlocksOverlay.itemStacks, BlocksOverlay.itemStacks.length + 1);
|
|
||||||
BlocksOverlay.amounts = Arrays.copyOf(BlocksOverlay.amounts, BlocksOverlay.amounts.length + 1);
|
|
||||||
|
|
||||||
BlocksOverlay.itemStacks[BlocksOverlay.itemStacks.length - 1] = itemStack;
|
|
||||||
BlocksOverlay.amounts[BlocksOverlay.amounts.length - 1] = 1;
|
|
||||||
} else {
|
|
||||||
BlocksOverlay.amounts[index] = BlocksOverlay.amounts[index] + 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
BlocksOverlay.itemStacks = null;
|
||||||
|
client.setScreen(null);
|
||||||
}
|
}
|
||||||
} else {
|
}).dimensions(width - 110, height - 31, 100, 20).build());
|
||||||
BlocksOverlay.itemStacks = null;
|
}
|
||||||
client.setScreen(null);
|
|
||||||
}
|
|
||||||
}).dimensions(width - 110, height - 31, 100, 20).build());
|
|
||||||
|
|
||||||
// 打开文件夹
|
// 打开文件夹
|
||||||
addDrawableChild(ButtonWidget.builder(OPEN_FOLDER, button -> {
|
addDrawableChild(ButtonWidget.builder(OPEN_FOLDER, button -> {
|
||||||
@ -238,19 +239,31 @@ public class DiscJockeyScreen extends Screen {
|
|||||||
|
|
||||||
|
|
||||||
// 重新加载
|
// 重新加载
|
||||||
addDrawableChild(ButtonWidget.builder(RELOAD, button -> {
|
if (isLargeScreen) {
|
||||||
SongLoader.loadSongs();
|
addDrawableChild(ButtonWidget.builder(RELOAD, button -> {
|
||||||
client.setScreen(null);
|
SongLoader.loadSongs();
|
||||||
}).dimensions(120, bottomY, 100, 20).build());
|
client.setScreen(null);
|
||||||
|
}).dimensions(120, bottomY, 100, 20).build());
|
||||||
|
}
|
||||||
|
|
||||||
TextFieldWidget searchBar = new TextFieldWidget(textRenderer, 230, height - 31, 100, 20, Text.translatable(Main.MOD_ID+".screen.search"));
|
// 即兴演奏
|
||||||
searchBar.setChangedListener(query -> {
|
if (isLargeScreen) {
|
||||||
query = query.toLowerCase().replaceAll("\\s", "");
|
addDrawableChild(ButtonWidget.builder(LIVE_DJ, button -> {
|
||||||
if (this.query.equals(query)) return;
|
client.setScreen(new LiveDjScreen());
|
||||||
this.query = query;
|
}).dimensions(width - 220, bottomY, 100, 20).build());
|
||||||
shouldFilter = true;
|
}
|
||||||
});
|
|
||||||
addDrawableChild(searchBar);
|
// 搜索框
|
||||||
|
if (isLargeScreen) {
|
||||||
|
TextFieldWidget searchBar = new TextFieldWidget(textRenderer, 230, height - 31, 100, 20, Text.translatable(Main.MOD_ID + ".screen.search"));
|
||||||
|
searchBar.setChangedListener(query -> {
|
||||||
|
query = query.toLowerCase().replaceAll("\\s", "");
|
||||||
|
if (this.query.equals(query)) return;
|
||||||
|
this.query = query;
|
||||||
|
shouldFilter = true;
|
||||||
|
});
|
||||||
|
addDrawableChild(searchBar);
|
||||||
|
}
|
||||||
|
|
||||||
// Main.LOGGER.info("播放界面初始化完成!");
|
// Main.LOGGER.info("播放界面初始化完成!");
|
||||||
|
|
||||||
@ -328,7 +341,7 @@ public class DiscJockeyScreen extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 只有在songs目录或其子目录中才显示歌曲(原作者的💩跑我这了)
|
// 只有在songs目录或其子目录中才显示歌曲(在搞了在搞了)
|
||||||
if (isInSongsOrSubfolder) {
|
if (isInSongsOrSubfolder) {
|
||||||
// 歌曲条目
|
// 歌曲条目
|
||||||
List<Song> songsToShow = currentFolder == null ?
|
List<Song> songsToShow = currentFolder == null ?
|
||||||
|
@ -0,0 +1,146 @@
|
|||||||
|
package semmiedev.disc_jockey_revive.gui.screen;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import semmiedev.disc_jockey_revive.Main;
|
||||||
|
import semmiedev.disc_jockey_revive.Note;
|
||||||
|
import semmiedev.disc_jockey_revive.gui.KeyMappingListWidget;
|
||||||
|
|
||||||
|
public class EditKeyMappingsScreen extends Screen {
|
||||||
|
|
||||||
|
private static final Text TITLE = Text.translatable(Main.MOD_ID + ".screen.edit_mappings.title");
|
||||||
|
private static final Text ADD_MAPPING_BUTTON_TEXT = Text.translatable(Main.MOD_ID + ".screen.edit_mappings.add_mapping");
|
||||||
|
private static final Text DONE_BUTTON_TEXT = Text.translatable("gui.done");
|
||||||
|
private static final Text PRESS_KEY_INSTRUCTION = Text.translatable(Main.MOD_ID + ".screen.edit_mappings.press_key");
|
||||||
|
|
||||||
|
private final Screen parent;
|
||||||
|
private KeyMappingListWidget mappingListWidget;
|
||||||
|
private ButtonWidget addMappingButton;
|
||||||
|
private ButtonWidget doneButton;
|
||||||
|
|
||||||
|
private boolean waitingForKeyPress = false;
|
||||||
|
private KeyMappingListWidget.KeyMappingEntry entryToEdit = null;
|
||||||
|
|
||||||
|
public EditKeyMappingsScreen(Screen parent) {
|
||||||
|
super(TITLE);
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
int listTop = 40;
|
||||||
|
int listBottom = this.height - 50;
|
||||||
|
int listHeight = listBottom - listTop;
|
||||||
|
|
||||||
|
mappingListWidget = new KeyMappingListWidget(this.client, this.width, listHeight, listTop, 20, this);
|
||||||
|
addDrawableChild(mappingListWidget);
|
||||||
|
refreshMappingList();
|
||||||
|
int buttonWidth = 100;
|
||||||
|
int buttonHeight = 20;
|
||||||
|
int buttonY = this.height - 30;
|
||||||
|
int buttonX = this.width / 2 - buttonWidth - 5;
|
||||||
|
|
||||||
|
addMappingButton = ButtonWidget.builder(ADD_MAPPING_BUTTON_TEXT, button -> {
|
||||||
|
startWaitingForKeyPress(null);
|
||||||
|
}).dimensions(buttonX, buttonY, buttonWidth, buttonHeight).build();
|
||||||
|
addDrawableChild(addMappingButton);
|
||||||
|
buttonX = this.width / 2 + 5;
|
||||||
|
doneButton = ButtonWidget.builder(DONE_BUTTON_TEXT, button -> {
|
||||||
|
Main.keyMappingManager.saveMappings();
|
||||||
|
this.client.setScreen(this.parent);
|
||||||
|
}).dimensions(buttonX, buttonY, buttonWidth, buttonHeight).build();
|
||||||
|
addDrawableChild(doneButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshMappingList() {
|
||||||
|
|
||||||
|
mappingListWidget.setMappings(Main.keyMappingManager.getMappings());
|
||||||
|
}
|
||||||
|
public void startWaitingForKeyPress(KeyMappingListWidget.KeyMappingEntry entry) {
|
||||||
|
this.waitingForKeyPress = true;
|
||||||
|
this.entryToEdit = entry;
|
||||||
|
|
||||||
|
addMappingButton.active = false;
|
||||||
|
doneButton.active = false;
|
||||||
|
mappingListWidget.setButtonsActive(false);
|
||||||
|
}
|
||||||
|
public void addNewMapping(InputUtil.Key key, Note note) {
|
||||||
|
Main.keyMappingManager.setMapping(key, note);
|
||||||
|
refreshMappingList();
|
||||||
|
|
||||||
|
}
|
||||||
|
public void removeMapping(InputUtil.Key key) {
|
||||||
|
Main.keyMappingManager.removeMapping(key);
|
||||||
|
refreshMappingList();
|
||||||
|
}
|
||||||
|
public void stopWaitingForKeyPress() {
|
||||||
|
this.waitingForKeyPress = false;
|
||||||
|
this.entryToEdit = null;
|
||||||
|
|
||||||
|
addMappingButton.active = true;
|
||||||
|
doneButton.active = true;
|
||||||
|
mappingListWidget.setButtonsActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
if (waitingForKeyPress) {
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
|
||||||
|
stopWaitingForKeyPress();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputUtil.Key pressedKey = InputUtil.fromKeyCode(keyCode, scanCode);
|
||||||
|
|
||||||
|
if (entryToEdit != null) {
|
||||||
|
|
||||||
|
Note note = entryToEdit.getNote();
|
||||||
|
|
||||||
|
Main.keyMappingManager.removeMapping(entryToEdit.getKey());
|
||||||
|
|
||||||
|
Main.keyMappingManager.setMapping(pressedKey, note);
|
||||||
|
refreshMappingList();
|
||||||
|
stopWaitingForKeyPress();
|
||||||
|
} else {
|
||||||
|
this.client.setScreen(new SelectNoteScreen(this, pressedKey));
|
||||||
|
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mappingListWidget.keyPressed(keyCode, scanCode, modifiers)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
Main.keyMappingManager.saveMappings();
|
||||||
|
this.client.setScreen(this.parent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, TITLE, this.width / 2, 10, 0xFFFFFF);
|
||||||
|
if (waitingForKeyPress) {
|
||||||
|
|
||||||
|
context.fill(0, 0, this.width, this.height, 0x80000000);
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, PRESS_KEY_INSTRUCTION, this.width / 2, this.height / 2 - 10, 0xFFFFFF);
|
||||||
|
}
|
||||||
|
mappingListWidget.render(context, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPause() {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,179 @@
|
|||||||
|
package semmiedev.disc_jockey_revive.gui.screen;
|
||||||
|
|
||||||
|
import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.annotation.Nullable;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.enums.NoteBlockInstrument;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import semmiedev.disc_jockey_revive.DebugLogger;
|
||||||
|
import semmiedev.disc_jockey_revive.Main;
|
||||||
|
import semmiedev.disc_jockey_revive.Note;
|
||||||
|
import semmiedev.disc_jockey_revive.KeyMappingManager;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class LiveDjScreen extends Screen {
|
||||||
|
|
||||||
|
private static final Text TITLE = Text.translatable(Main.MOD_ID + ".screen.live_dj.title");
|
||||||
|
private static final Text INSTRUCTIONS = Text.translatable(Main.MOD_ID + ".screen.live_dj.instructions");
|
||||||
|
private static final Text EDIT_MAPPINGS_BUTTON_TEXT = Text.translatable(Main.MOD_ID + ".screen.live_dj.edit_mappings");
|
||||||
|
private static final Text START_TUNING_BUTTON_TEXT = Text.translatable(Main.MOD_ID + ".screen.live_dj.start_tuning");
|
||||||
|
private static final Text NOT_TUNED_MESSAGE = Text.translatable(Main.MOD_ID + ".player.not_tuned").formatted(net.minecraft.util.Formatting.RED);
|
||||||
|
private static final Text NOTE_BLOCK_MISSING_MESSAGE = Text.translatable(Main.MOD_ID + ".player.note_block_missing_live").formatted(net.minecraft.util.Formatting.RED);
|
||||||
|
private static final Text TOO_FAR_MESSAGE = Text.translatable(Main.MOD_ID + ".player.to_far_live").formatted(net.minecraft.util.Formatting.RED);
|
||||||
|
private static final Text RATE_LIMITED_MESSAGE = Text.translatable(Main.MOD_ID + ".player.rate_limited_live").formatted(net.minecraft.util.Formatting.YELLOW);
|
||||||
|
private ButtonWidget startTuningButton;
|
||||||
|
|
||||||
|
public LiveDjScreen() {
|
||||||
|
super(TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
int centerX = this.width / 2;
|
||||||
|
int buttonWidth = 150;
|
||||||
|
int buttonHeight = 20;
|
||||||
|
int buttonY = this.height - 30;
|
||||||
|
int margin = 5;
|
||||||
|
addDrawableChild(ButtonWidget.builder(EDIT_MAPPINGS_BUTTON_TEXT, button -> {
|
||||||
|
MinecraftClient.getInstance().setScreen(new EditKeyMappingsScreen(this));
|
||||||
|
}).dimensions(centerX - buttonWidth - margin, buttonY, buttonWidth, buttonHeight).build());
|
||||||
|
startTuningButton = ButtonWidget.builder(START_TUNING_BUTTON_TEXT, button -> {
|
||||||
|
Main.LIVE_DJ_PLAYER.startTuning();
|
||||||
|
}).dimensions(centerX + margin, buttonY, buttonWidth, buttonHeight).build();
|
||||||
|
addDrawableChild(startTuningButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, TITLE, this.width / 2, 10, 0xFFFFFF);
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, INSTRUCTIONS, this.width / 2, 30, 0xFFFFFF);
|
||||||
|
|
||||||
|
Text tuningStatusText;
|
||||||
|
if (Main.LIVE_DJ_PLAYER.getNoteBlocks() == null) {
|
||||||
|
tuningStatusText = Text.translatable(Main.MOD_ID + ".player.discovering").formatted(net.minecraft.util.Formatting.YELLOW);
|
||||||
|
startTuningButton.active = true;
|
||||||
|
startTuningButton.visible = true;
|
||||||
|
} else if (!Main.LIVE_DJ_PLAYER.isTuned()) {
|
||||||
|
int totalNeeded = 0;
|
||||||
|
if (Main.LIVE_DJ_PLAYER.getNoteBlocks() != null) {
|
||||||
|
for (HashMap<Byte, net.minecraft.util.math.BlockPos> instrumentNotes : Main.LIVE_DJ_PLAYER.getNoteBlocks().values()) {
|
||||||
|
if (instrumentNotes != null) {
|
||||||
|
for (net.minecraft.util.math.BlockPos pos : instrumentNotes.values()) {
|
||||||
|
if (pos != null) {
|
||||||
|
totalNeeded++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int tunedCount = 0;
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
if (client.world != null && Main.LIVE_DJ_PLAYER.getNoteBlocks() != null) {
|
||||||
|
for (HashMap<Byte, net.minecraft.util.math.BlockPos> instrumentNotes : Main.LIVE_DJ_PLAYER.getNoteBlocks().values()) {
|
||||||
|
if (instrumentNotes != null) {
|
||||||
|
for (Map.Entry<Byte, net.minecraft.util.math.BlockPos> entry : instrumentNotes.entrySet()) {
|
||||||
|
net.minecraft.util.math.BlockPos pos = entry.getValue();
|
||||||
|
Byte wantedNote = entry.getKey();
|
||||||
|
if (pos != null) {
|
||||||
|
if (client.world.getBlockState(pos).contains(net.minecraft.state.property.Properties.NOTE)) {
|
||||||
|
int currentNote = client.world.getBlockState(pos).get(net.minecraft.state.property.Properties.NOTE);
|
||||||
|
if (currentNote == wantedNote.byteValue()) {
|
||||||
|
tunedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (totalNeeded > 0) {
|
||||||
|
tuningStatusText = Text.translatable(Main.MOD_ID + ".player.tuning_progress", tunedCount, totalNeeded).formatted(net.minecraft.util.Formatting.YELLOW);
|
||||||
|
} else {
|
||||||
|
tuningStatusText = Text.translatable(Main.MOD_ID + ".player.finding_blocks").formatted(net.minecraft.util.Formatting.YELLOW);
|
||||||
|
}
|
||||||
|
startTuningButton.active = true;
|
||||||
|
startTuningButton.visible = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
tuningStatusText = Text.translatable(Main.MOD_ID + ".player.tuned").formatted(net.minecraft.util.Formatting.GREEN);
|
||||||
|
startTuningButton.active = false;
|
||||||
|
startTuningButton.visible = false;
|
||||||
|
}
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, tuningStatusText, this.width / 2, 50, 0xFFFFFF);
|
||||||
|
|
||||||
|
|
||||||
|
if (!Main.LIVE_DJ_PLAYER.missingInstrumentBlocks.isEmpty()) {
|
||||||
|
int yOffset = 70;
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, Text.translatable(Main.MOD_ID+".player.invalid_note_blocks").formatted(net.minecraft.util.Formatting.RED), this.width / 2, yOffset, 0xFFFFFF);
|
||||||
|
yOffset += 12;
|
||||||
|
for (Map.Entry<Block, Integer> entry : Main.LIVE_DJ_PLAYER.missingInstrumentBlocks.entrySet()) {
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, Text.literal(entry.getKey().getName().getString()+" × "+entry.getValue()).formatted(net.minecraft.util.Formatting.RED), this.width / 2, yOffset, 0xFFFFFF);
|
||||||
|
yOffset += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
InputUtil.Key key = InputUtil.fromKeyCode(keyCode, scanCode);
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
this.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Note note = Main.keyMappingManager.getNoteForKey(key);
|
||||||
|
|
||||||
|
if (note != null) {
|
||||||
|
if (!Main.LIVE_DJ_PLAYER.isTuned()) {
|
||||||
|
MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(NOT_TUNED_MESSAGE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
boolean played = Main.LIVE_DJ_PLAYER.playNoteBlock(note);
|
||||||
|
if (!played) {
|
||||||
|
@Nullable net.minecraft.util.math.BlockPos blockPos = null;
|
||||||
|
if (Main.LIVE_DJ_PLAYER.getNoteBlocks() != null && Main.LIVE_DJ_PLAYER.getNoteBlocks().containsKey(note.instrument())) {
|
||||||
|
blockPos = Main.LIVE_DJ_PLAYER.getNoteBlocks().get(note.instrument()).get(note.note());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockPos == null) {
|
||||||
|
MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(NOTE_BLOCK_MISSING_MESSAGE.copy().append(" (" + KeyMappingManager.getNoteDisplayName(note) + ")"));
|
||||||
|
} else if (!Main.LIVE_DJ_PLAYER.canInteractWith(MinecraftClient.getInstance().player, blockPos)) {
|
||||||
|
MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(TOO_FAR_MESSAGE.copy().append(" (" + KeyMappingManager.getNoteDisplayName(note) + ")"));
|
||||||
|
} else {
|
||||||
|
MinecraftClient.getInstance().inGameHud.getChatHud().addMessage(RATE_LIMITED_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (startTuningButton != null) {
|
||||||
|
startTuningButton.visible = !Main.LIVE_DJ_PLAYER.isTuned();
|
||||||
|
startTuningButton.active = !Main.LIVE_DJ_PLAYER.isTuningActive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPause() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
super.close();
|
||||||
|
Main.LIVE_DJ_PLAYER.stopTuning();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,173 @@
|
|||||||
|
package semmiedev.disc_jockey_revive.gui.screen;
|
||||||
|
|
||||||
|
import net.minecraft.block.enums.NoteBlockInstrument;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.CyclingButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.SliderWidget;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import semmiedev.disc_jockey_revive.Main;
|
||||||
|
import semmiedev.disc_jockey_revive.Note;
|
||||||
|
import semmiedev.disc_jockey_revive.KeyMappingManager;
|
||||||
|
|
||||||
|
public class SelectNoteScreen extends Screen {
|
||||||
|
|
||||||
|
private static final Text TITLE = Text.translatable(Main.MOD_ID + ".screen.select_note.title");
|
||||||
|
private static final Text INSTRUMENT_TEXT = Text.translatable(Main.MOD_ID + ".screen.select_note.instrument");
|
||||||
|
private static final Text PITCH_TEXT = Text.translatable(Main.MOD_ID + ".screen.select_note.pitch");
|
||||||
|
private static final Text DONE_BUTTON_TEXT = Text.translatable("gui.done");
|
||||||
|
private static final Text CANCEL_BUTTON_TEXT = Text.translatable("gui.cancel");
|
||||||
|
private static final Text PREVIEW_BUTTON_TEXT = Text.translatable(Main.MOD_ID + ".screen.select_note.preview");
|
||||||
|
private final EditKeyMappingsScreen parent;
|
||||||
|
private final InputUtil.Key keyToMap;
|
||||||
|
|
||||||
|
private NoteBlockInstrument selectedInstrument = NoteBlockInstrument.HARP;
|
||||||
|
private int selectedPitch = 12;
|
||||||
|
private CustomPitchSlider pitchSlider;
|
||||||
|
|
||||||
|
private ButtonWidget previewButton;
|
||||||
|
|
||||||
|
public SelectNoteScreen(EditKeyMappingsScreen parent, InputUtil.Key keyToMap) {
|
||||||
|
super(TITLE);
|
||||||
|
this.parent = parent;
|
||||||
|
this.keyToMap = keyToMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
|
||||||
|
int centerX = this.width / 2;
|
||||||
|
int startY = this.height / 2 - 50;
|
||||||
|
int widgetWidth = 200;
|
||||||
|
int widgetHeight = 20;
|
||||||
|
int margin = 5;
|
||||||
|
CyclingButtonWidget<NoteBlockInstrument> instrumentButton = CyclingButtonWidget.builder((NoteBlockInstrument instrument) -> Text.translatable("block.minecraft.note_block.instrument." + instrument.asString()))
|
||||||
|
.values(NoteBlockInstrument.values())
|
||||||
|
.initially(selectedInstrument)
|
||||||
|
|
||||||
|
.build(centerX - widgetWidth / 2, startY, widgetWidth, widgetHeight, INSTRUMENT_TEXT, (button, instrument) -> {
|
||||||
|
this.selectedInstrument = instrument;
|
||||||
|
updatePitchSliderDisplay();
|
||||||
|
updatePreviewButton();
|
||||||
|
});
|
||||||
|
addDrawableChild(instrumentButton);
|
||||||
|
pitchSlider = new CustomPitchSlider(centerX - widgetWidth / 2, startY + widgetHeight + margin, widgetWidth, widgetHeight, PITCH_TEXT, (selectedPitch / 24.0));
|
||||||
|
updatePitchSliderDisplay();
|
||||||
|
addDrawableChild(pitchSlider);
|
||||||
|
previewButton = ButtonWidget.builder(PREVIEW_BUTTON_TEXT, button -> {
|
||||||
|
playPreviewNote();
|
||||||
|
}).dimensions(centerX - widgetWidth / 2, startY + (widgetHeight + margin) * 2, widgetWidth, widgetHeight).build();
|
||||||
|
addDrawableChild(previewButton);
|
||||||
|
int buttonWidth = 100;
|
||||||
|
int buttonY = this.height - 30;
|
||||||
|
int doneButtonX = centerX - buttonWidth - margin;
|
||||||
|
addDrawableChild(ButtonWidget.builder(DONE_BUTTON_TEXT, button -> {
|
||||||
|
Note selectedNote = new Note(selectedInstrument, (byte) selectedPitch);
|
||||||
|
parent.addNewMapping(keyToMap, selectedNote);
|
||||||
|
this.client.setScreen(this.parent);
|
||||||
|
parent.stopWaitingForKeyPress();
|
||||||
|
}).dimensions(doneButtonX, buttonY, buttonWidth, widgetHeight).build());
|
||||||
|
int cancelButtonX = centerX + margin;
|
||||||
|
addDrawableChild(ButtonWidget.builder(CANCEL_BUTTON_TEXT, button -> {
|
||||||
|
this.client.setScreen(this.parent);
|
||||||
|
parent.stopWaitingForKeyPress();
|
||||||
|
}).dimensions(cancelButtonX, buttonY, buttonWidth, widgetHeight).build());
|
||||||
|
}
|
||||||
|
private class CustomPitchSlider extends SliderWidget {
|
||||||
|
public CustomPitchSlider(int x, int y, int width, int height, Text text, double value) {
|
||||||
|
super(x, y, width, height, text, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateMessage() {
|
||||||
|
|
||||||
|
this.setMessage(PITCH_TEXT.copy().append(": " + KeyMappingManager.getNoteDisplayName(new Note(selectedInstrument, (byte) selectedPitch))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyValue() {
|
||||||
|
selectedPitch = (int) Math.round(MathHelper.lerp(this.value, 0.0, 24.0));
|
||||||
|
updateMessage();
|
||||||
|
updatePreviewButton();
|
||||||
|
}
|
||||||
|
public void forceUpdateDisplay() {
|
||||||
|
this.updateMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void updatePitchSliderDisplay() {
|
||||||
|
if (pitchSlider != null) {
|
||||||
|
|
||||||
|
pitchSlider.forceUpdateDisplay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePreviewButton() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playPreviewNote() {
|
||||||
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
if (client.world != null && client.gameRenderer != null) {
|
||||||
|
Vec3d pos = client.gameRenderer.getCamera().getPos();
|
||||||
|
try {
|
||||||
|
Note note = new Note(selectedInstrument, (byte) selectedPitch);
|
||||||
|
|
||||||
|
if (note.instrument().canBePitched()) {
|
||||||
|
Identifier soundId = note.instrument().getSound().value().id();
|
||||||
|
float pitchMultiplier = (float) Math.pow(2.0, (note.note() - 12) / 12.0);
|
||||||
|
client.world.playSound(pos.x, pos.y, pos.z, SoundEvent.of(soundId), SoundCategory.RECORDS, 3.0f, pitchMultiplier, false);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Identifier soundId = note.instrument().getSound().value().id();
|
||||||
|
client.world.playSound(pos.x, pos.y, pos.z, SoundEvent.of(soundId), SoundCategory.RECORDS, 3.0f, 1.0f, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Main.LOGGER.error("无法播放预览声音。", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, TITLE, this.width / 2, 10, 0xFFFFFF);
|
||||||
|
|
||||||
|
context.drawCenteredTextWithShadow(textRenderer, Text.translatable(Main.MOD_ID + ".screen.select_note.mapping_key", Text.translatable(keyToMap.getTranslationKey())), this.width / 2, 30, 0xFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldPause() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||||
|
this.client.setScreen(this.parent);
|
||||||
|
parent.stopWaitingForKeyPress();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
|
||||||
|
Note selectedNote = new Note(selectedInstrument, (byte) selectedPitch);
|
||||||
|
parent.addNewMapping(keyToMap, selectedNote);
|
||||||
|
this.client.setScreen(this.parent);
|
||||||
|
parent.stopWaitingForKeyPress();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
}
|
@ -63,5 +63,35 @@
|
|||||||
"disc_jockey_revive.screen.reload": "Reload Songs",
|
"disc_jockey_revive.screen.reload": "Reload Songs",
|
||||||
"disc_jockey_revive.screen.reloading": "Reloading songs...",
|
"disc_jockey_revive.screen.reloading": "Reloading songs...",
|
||||||
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar": "Show HUD progress bar",
|
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar": "Show HUD progress bar",
|
||||||
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar.@Tooltip": "Show song playback progress bar in game。"
|
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar.@Tooltip": "Show song playback progress bar in game。",
|
||||||
|
|
||||||
|
"disc_jockey_revive.key_bind.open_live_dj_screen": "Open Live DJ Screen",
|
||||||
|
"disc_jockey_revive.screen.live_dj": "Live DJ",
|
||||||
|
"disc_jockey_revive.screen.live_dj.title": "Live DJ Performance",
|
||||||
|
"disc_jockey_revive.screen.live_dj.instructions": "Press mapped keys to play notes. Tune note blocks first!",
|
||||||
|
"disc_jockey_revive.screen.live_dj.edit_mappings": "Edit Key Mappings",
|
||||||
|
"disc_jockey_revive.screen.live_dj.start_tuning": "Start Tuning",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.title": "Edit Key Mappings",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.add_mapping": "Add New Mapping",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.change": "Change Key",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.remove": "Remove",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.press_key": "Press a key to map...",
|
||||||
|
"disc_jockey_revive.screen.select_note.title": "Select Note for Key",
|
||||||
|
"disc_jockey_revive.screen.select_note.instrument": "Instrument",
|
||||||
|
"disc_jockey_revive.screen.select_note.pitch": "Pitch",
|
||||||
|
"disc_jockey_revive.screen.select_note.preview": "Preview Note",
|
||||||
|
"disc_jockey_revive.screen.select_note.mapping_key": "Mapping Key: %s",
|
||||||
|
"disc_jockey_revive.player.not_tuned": "Note blocks are not tuned yet!",
|
||||||
|
"disc_jockey_revive.player.note_block_missing_live": "Missing note block for this note!",
|
||||||
|
"disc_jockey_revive.player.to_far_live": "You are too far from the note block!",
|
||||||
|
"disc_jockey_revive.player.rate_limited_live": "Rate limited by server, try again soon.",
|
||||||
|
"disc_jockey_revive.player.discovering": "Discovering note blocks...",
|
||||||
|
"disc_jockey_revive.player.tuning_progress": "Tuning: %s/%s tuned",
|
||||||
|
"disc_jockey_revive.player.finding_blocks": "Finding note blocks...",
|
||||||
|
"disc_jockey_revive.player.retuning": "Retuning note blocks...",
|
||||||
|
"disc_jockey_revive.player.tuning_started": "Tuning started. Please wait...",
|
||||||
|
"disc_jockey_revive.player.invalid_state_tuning": "Cannot tune: Invalid game state or mode.",
|
||||||
|
"disc_jockey_revive.player.tuned": "Tuning completed。",
|
||||||
|
"text.autoconfig.disc_jockey_revive.option.debugModeEnabled": "Enable Debug Mode",
|
||||||
|
"text.autoconfig.disc_jockey_revive.option.debugModeEnabled.@Tooltip": "Enables verbose logging for debugging purposes. \nKeep off unless troubleshooting. \nOf course, many debug-related parts have already been removed."
|
||||||
}
|
}
|
@ -10,7 +10,7 @@
|
|||||||
"disc_jockey_revive.screen.drop_hint": "将歌曲文件拖入此窗口以添加",
|
"disc_jockey_revive.screen.drop_hint": "将歌曲文件拖入此窗口以添加",
|
||||||
"disc_jockey_revive.screen.drop_confirm": "是否将以下歌曲添加到 Disc Jockey?",
|
"disc_jockey_revive.screen.drop_confirm": "是否将以下歌曲添加到 Disc Jockey?",
|
||||||
"disc_jockey_revive.player.invalid_note_blocks": "附近的音符盒配置不正确。缺失:",
|
"disc_jockey_revive.player.invalid_note_blocks": "附近的音符盒配置不正确。缺失:",
|
||||||
"disc_jockey_revive.player.invalid_game_mode": "无法在 %s 模式下播放",
|
"disc_jockey_revive.player.invalid_game_mode": "无法在 %s 下播放",
|
||||||
"disc_jockey_revive.player.to_far": "你距离太远了",
|
"disc_jockey_revive.player.to_far": "你距离太远了",
|
||||||
"disc_jockey_revive.still_loading": "歌曲仍在加载中",
|
"disc_jockey_revive.still_loading": "歌曲仍在加载中",
|
||||||
"disc_jockey_revive.reloading": "正在重新加载所有歌曲",
|
"disc_jockey_revive.reloading": "正在重新加载所有歌曲",
|
||||||
@ -57,10 +57,41 @@
|
|||||||
"disc_jockey_revive.screen.mode_single": "单曲循环",
|
"disc_jockey_revive.screen.mode_single": "单曲循环",
|
||||||
"disc_jockey_revive.screen.mode_list": "列表循环",
|
"disc_jockey_revive.screen.mode_list": "列表循环",
|
||||||
"disc_jockey_revive.screen.mode_random": "随机播放",
|
"disc_jockey_revive.screen.mode_random": "随机播放",
|
||||||
"disc_jockey_revive.screen.mode_stop": "播完停止","disc_jockey_revive.screen.open_folder": "打开文件夹",
|
"disc_jockey_revive.screen.mode_stop": "播完停止",
|
||||||
|
"disc_jockey_revive.screen.open_folder": "打开文件夹",
|
||||||
"disc_jockey_revive.screen.open_folder_failed": "无法打开文件夹",
|
"disc_jockey_revive.screen.open_folder_failed": "无法打开文件夹",
|
||||||
"disc_jockey_revive.screen.reload": "重新加载",
|
"disc_jockey_revive.screen.reload": "重新加载",
|
||||||
"disc_jockey_revive.screen.reloading": "正在重新加载...",
|
"disc_jockey_revive.screen.reloading": "正在重新加载...",
|
||||||
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar": "显示HUD进度条",
|
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar": "显示HUD进度条",
|
||||||
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar.@Tooltip": "在游戏界面显示歌曲播放进度条"
|
"text.autoconfig.disc_jockey_revive.option.showHudProgressBar.@Tooltip": "在游戏界面显示歌曲播放进度条",
|
||||||
|
|
||||||
|
"disc_jockey_revive.key_bind.open_live_dj_screen": "打开即兴演奏界面",
|
||||||
|
"disc_jockey_revive.screen.live_dj": "即兴演奏",
|
||||||
|
"disc_jockey_revive.screen.live_dj.title": "即兴演奏",
|
||||||
|
"disc_jockey_revive.screen.live_dj.instructions": "按下映射的按键来演奏音符。请先调音音符盒!",
|
||||||
|
"disc_jockey_revive.screen.live_dj.edit_mappings": "编辑按键映射",
|
||||||
|
"disc_jockey_revive.screen.live_dj.start_tuning": "开始调音",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.title": "编辑按键映射",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.add_mapping": "添加新映射",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.change": "更改按键",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.remove": "移除",
|
||||||
|
"disc_jockey_revive.screen.edit_mappings.press_key": "按下要映射的按键...",
|
||||||
|
"disc_jockey_revive.screen.select_note.title": "为按键选择音符",
|
||||||
|
"disc_jockey_revive.screen.select_note.instrument": "乐器",
|
||||||
|
"disc_jockey_revive.screen.select_note.pitch": "音高",
|
||||||
|
"disc_jockey_revive.screen.select_note.preview": "试听音符",
|
||||||
|
"disc_jockey_revive.screen.select_note.mapping_key": "映射按键:%s",
|
||||||
|
"disc_jockey_revive.player.not_tuned": "音符盒尚未调音!",
|
||||||
|
"disc_jockey_revive.player.note_block_missing_live": "缺少此音符的音符盒!",
|
||||||
|
"disc_jockey_revive.player.to_far_live": "你离音符盒太远了!",
|
||||||
|
"disc_jockey_revive.player.rate_limited_live": "服务器限速,请稍后再试。",
|
||||||
|
"disc_jockey_revive.player.discovering": "正在发现音符盒...",
|
||||||
|
"disc_jockey_revive.player.tuning_progress": "调音中:%s/%s 已调音",
|
||||||
|
"disc_jockey_revive.player.finding_blocks": "正在寻找音符盒...",
|
||||||
|
"disc_jockey_revive.player.retuning": "正在重新调音音符盒...",
|
||||||
|
"disc_jockey_revive.player.tuning_started": "调音已开始。请稍候...",
|
||||||
|
"disc_jockey_revive.player.invalid_state_tuning": "无法调音:游戏状态或模式无效。",
|
||||||
|
"disc_jockey_revive.player.tuned": "调音完成。",
|
||||||
|
"text.autoconfig.disc_jockey_revive.option.debugModeEnabled": "启用调试模式",
|
||||||
|
"text.autoconfig.disc_jockey_revive.option.debugModeEnabled.@Tooltip": "启用详细日志输出以进行调试。\n除非排查问题,否则请保持关闭。\n当然,很多调试用的部分已经移除。"
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user