Survival only mode
This commit is contained in:
parent
44c614d6f0
commit
e0c87ffda0
5 changed files with 237 additions and 69 deletions
|
@ -9,17 +9,14 @@ import com.github.hhhzzzsss.songplayer.song.Playlist;
|
|||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.component.DataComponentTypes;
|
||||
import net.minecraft.component.type.NbtComponent;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.state.property.Property;
|
||||
import net.minecraft.text.*;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.world.GameMode;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -61,6 +58,7 @@ public class CommandProcessor {
|
|||
commands.add(new cleanupLastStageCommand());
|
||||
commands.add(new announcementCommand());
|
||||
commands.add(new songItemCommand());
|
||||
commands.add(new toggleSurvivalOnly());
|
||||
commands.add(new testSongCommand());
|
||||
|
||||
for (Command command : commands) {
|
||||
|
@ -1003,7 +1001,6 @@ public class CommandProcessor {
|
|||
return true;
|
||||
}
|
||||
if (SongPlayer.MC.player.getPos().squaredDistanceTo(lastStage.getOriginBottomCenter()) > 3*3) {
|
||||
System.out.println(SongPlayer.MC.player.getPos().squaredDistanceTo(lastStage.getOriginBottomCenter()));
|
||||
String coordStr = String.format(
|
||||
"%d %d %d",
|
||||
lastStage.position.getX(), lastStage.position.getY(), lastStage.position.getZ()
|
||||
|
@ -1165,6 +1162,37 @@ public class CommandProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private static class toggleSurvivalOnly extends Command {
|
||||
public String getName() {
|
||||
return "toggleSurvivalOnly";
|
||||
}
|
||||
public String[] getAliases() {
|
||||
return new String[]{"survivalOnly"};
|
||||
}
|
||||
public String[] getSyntax() {
|
||||
return new String[0];
|
||||
}
|
||||
public String getDescription() {
|
||||
return "Enables or disables survival-only mode, in which automatic noteblock placement is disabled and automatic tuning is done by right-clicking..";
|
||||
}
|
||||
public boolean processCommand(String args) {
|
||||
if (args.length() == 0) {
|
||||
Config.getConfig().survivalOnly = !Config.getConfig().survivalOnly;
|
||||
if (Config.getConfig().survivalOnly) {
|
||||
SongPlayer.addChatMessage("§6Enabled survival only mode");
|
||||
}
|
||||
else {
|
||||
SongPlayer.addChatMessage("§6Disabled survival only mode");
|
||||
}
|
||||
Config.saveConfigWithErrorHandling();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class testSongCommand extends Command {
|
||||
public String getName() {
|
||||
return "testSong";
|
||||
|
|
|
@ -27,6 +27,7 @@ public class Config {
|
|||
public boolean doAnnouncement = false;
|
||||
public String announcementMessage = "&6Now playing: &3[name]";
|
||||
public boolean autoCleanup = false;
|
||||
public boolean survivalOnly = false;
|
||||
|
||||
public static Config getConfig() {
|
||||
if (config == null) {
|
||||
|
|
|
@ -150,7 +150,7 @@ public class SongHandler {
|
|||
// Otherwise, handle cleanup if necessary
|
||||
else {
|
||||
if (dirty) {
|
||||
if (Config.getConfig().autoCleanup && originalBlocks.size() != 0) {
|
||||
if (Config.getConfig().autoCleanup && originalBlocks.size() != 0 && !Config.getConfig().survivalOnly) {
|
||||
partialResetAndCleanup();
|
||||
} else {
|
||||
restoreStateAndReset();
|
||||
|
@ -198,12 +198,12 @@ public class SongHandler {
|
|||
dirty = true;
|
||||
currentSong = song;
|
||||
building = true;
|
||||
setCreativeIfNeeded();
|
||||
if (!Config.getConfig().survivalOnly) setCreativeIfNeeded();
|
||||
if (Config.getConfig().doAnnouncement) {
|
||||
sendMessage(Config.getConfig().announcementMessage.replaceAll("\\[name\\]", song.name));
|
||||
}
|
||||
prepareStage();
|
||||
getAndSaveBuildSlot();
|
||||
if (!Config.getConfig().survivalOnly) getAndSaveBuildSlot();
|
||||
SongPlayer.addChatMessage("§6Building noteblocks");
|
||||
}
|
||||
|
||||
|
@ -259,52 +259,73 @@ public class SongHandler {
|
|||
return;
|
||||
}
|
||||
ClientWorld world = SongPlayer.MC.world;
|
||||
if (SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) {
|
||||
if (!Config.getConfig().survivalOnly && SongPlayer.MC.interactionManager.getCurrentGameMode() != GameMode.CREATIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stage.nothingToBuild()) {
|
||||
if (buildEndDelay > 0) {
|
||||
if (stage.nothingToBuild()) { // If there's nothing to build, wait for end delay then check build status
|
||||
if (buildEndDelay > 0) { // Wait for end delay
|
||||
buildEndDelay--;
|
||||
return;
|
||||
} else {
|
||||
stage.checkBuildStatus(currentSong);
|
||||
recordStageBlocks();
|
||||
} else { // Check build status when end delay is over
|
||||
if (!Config.getConfig().survivalOnly) {
|
||||
stage.checkBuildStatus(currentSong);
|
||||
recordStageBlocks();
|
||||
} else {
|
||||
try {
|
||||
stage.checkSurvivalBuildStatus(currentSong);
|
||||
} catch (Stage.NotEnoughInstrumentsException e) {
|
||||
e.giveInstrumentSummary();
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
stage.sendMovementPacketToStagePosition();
|
||||
}
|
||||
}
|
||||
|
||||
if (!stage.requiredBreaks.isEmpty()) {
|
||||
for (int i=0; i<5; i++) {
|
||||
if (stage.requiredBreaks.isEmpty()) break;
|
||||
BlockPos bp = stage.requiredBreaks.poll();
|
||||
attackBlock(bp);
|
||||
}
|
||||
buildEndDelay = 20;
|
||||
} else if (!stage.missingNotes.isEmpty()) {
|
||||
int desiredNoteId = stage.missingNotes.pollFirst();
|
||||
BlockPos bp = stage.noteblockPositions.get(desiredNoteId);
|
||||
if (bp == null) {
|
||||
return;
|
||||
}
|
||||
int blockId = Block.getRawIdFromState(world.getBlockState(bp));
|
||||
int currentNoteId = (blockId-SongPlayer.NOTEBLOCK_BASE_ID)/2;
|
||||
if (currentNoteId != desiredNoteId) {
|
||||
holdNoteblock(desiredNoteId, buildSlot);
|
||||
if (blockId != 0) {
|
||||
attackBlock(bp);
|
||||
}
|
||||
placeBlock(bp);
|
||||
}
|
||||
buildCooldown = 0; // No cooldown, so it places a block every tick
|
||||
buildEndDelay = 20;
|
||||
} else { // Switch to playing
|
||||
restoreBuildSlot();
|
||||
if (stage.nothingToBuild()) { // If there's still nothing to build after checking build status, switch to playing
|
||||
if (!Config.getConfig().survivalOnly) restoreBuildSlot();
|
||||
building = false;
|
||||
setSurvivalIfNeeded();
|
||||
stage.sendMovementPacketToStagePosition();
|
||||
SongPlayer.addChatMessage("§6Now playing §3" + currentSong.name);
|
||||
}
|
||||
|
||||
if (!Config.getConfig().survivalOnly) { // Regular mode
|
||||
if (!stage.requiredBreaks.isEmpty()) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (stage.requiredBreaks.isEmpty()) break;
|
||||
BlockPos bp = stage.requiredBreaks.poll();
|
||||
attackBlock(bp);
|
||||
}
|
||||
buildEndDelay = 20;
|
||||
} else if (!stage.missingNotes.isEmpty()) {
|
||||
int desiredNoteId = stage.missingNotes.pollFirst();
|
||||
BlockPos bp = stage.noteblockPositions.get(desiredNoteId);
|
||||
if (bp == null) {
|
||||
return;
|
||||
}
|
||||
int blockId = Block.getRawIdFromState(world.getBlockState(bp));
|
||||
int currentNoteId = (blockId - SongPlayer.NOTEBLOCK_BASE_ID) / 2;
|
||||
if (currentNoteId != desiredNoteId) {
|
||||
holdNoteblock(desiredNoteId, buildSlot);
|
||||
if (blockId != 0) {
|
||||
attackBlock(bp);
|
||||
}
|
||||
placeBlock(bp);
|
||||
}
|
||||
buildCooldown = 0; // No cooldown, so it places a block every tick
|
||||
buildEndDelay = 20;
|
||||
}
|
||||
} else { // Survival only mode
|
||||
if (!stage.requiredClicks.isEmpty()) {
|
||||
BlockPos bp = stage.requiredClicks.pollFirst();
|
||||
if (SongPlayer.MC.world.getBlockState(bp).getBlock() == Blocks.NOTE_BLOCK) {
|
||||
placeBlock(bp);
|
||||
}
|
||||
buildEndDelay = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void setBuildProgressDisplay() {
|
||||
MutableText buildText = Text.empty()
|
||||
|
@ -339,12 +360,22 @@ public class SongHandler {
|
|||
|
||||
if (tick) {
|
||||
if (stage.hasBreakingModification()) {
|
||||
stage.checkBuildStatus(currentSong);
|
||||
recordStageBlocks();
|
||||
if (!Config.getConfig().survivalOnly) {
|
||||
stage.checkBuildStatus(currentSong);
|
||||
recordStageBlocks();
|
||||
} else {
|
||||
try {
|
||||
stage.checkSurvivalBuildStatus(currentSong);
|
||||
} catch (Stage.NotEnoughInstrumentsException e) {
|
||||
SongPlayer.addChatMessage("§6Stopped because stage is missing instruments required for song.");
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!stage.nothingToBuild()) { // Switch to building
|
||||
building = true;
|
||||
setCreativeIfNeeded();
|
||||
if (!Config.getConfig().survivalOnly) setCreativeIfNeeded();
|
||||
stage.sendMovementPacketToStagePosition();
|
||||
currentSong.pause();
|
||||
buildStartDelay = 20;
|
||||
|
@ -354,7 +385,7 @@ public class SongHandler {
|
|||
int instrumentId = note / 25;
|
||||
System.out.println("Missing note: " + Instrument.getInstrumentFromId(instrumentId).name() + ":" + pitch);
|
||||
}
|
||||
getAndSaveBuildSlot();
|
||||
if (!Config.getConfig().survivalOnly) getAndSaveBuildSlot();
|
||||
SongPlayer.addChatMessage("§6Stage was altered. Rebuilding!");
|
||||
return;
|
||||
}
|
||||
|
@ -585,10 +616,6 @@ public class SongHandler {
|
|||
cleanupPlaceList = cleanupPlaceList.reversed();
|
||||
cleanupTotalBlocksToPlace = cleanupPlaceList.size();
|
||||
|
||||
for (BlockPos bp : cleanupPlaceList) {
|
||||
System.out.println(world.getBlockState(bp).getBlock() + " " + originalBlocks.get(bp).getBlock());
|
||||
}
|
||||
|
||||
boolean noNecessaryBreaks = cleanupBreakList.stream().allMatch(
|
||||
bp -> world.getBlockState(bp).getBlock().getDefaultState().equals(originalBlocks.get(bp).getBlock().getDefaultState())
|
||||
);
|
||||
|
@ -624,7 +651,7 @@ public class SongHandler {
|
|||
if (lastStage != null) {
|
||||
lastStage.movePlayerToStagePosition();
|
||||
}
|
||||
if (originalGamemode != SongPlayer.MC.interactionManager.getCurrentGameMode()) {
|
||||
if (originalGamemode != SongPlayer.MC.interactionManager.getCurrentGameMode() && !Config.getConfig().survivalOnly) {
|
||||
if (originalGamemode == GameMode.CREATIVE) {
|
||||
sendGamemodeCommand(Config.getConfig().creativeCommand);
|
||||
}
|
||||
|
@ -635,7 +662,7 @@ public class SongHandler {
|
|||
if (SongPlayer.MC.player.getAbilities().allowFlying == false) {
|
||||
SongPlayer.MC.player.getAbilities().flying = false;
|
||||
}
|
||||
restoreBuildSlot();
|
||||
if (!Config.getConfig().survivalOnly) restoreBuildSlot();
|
||||
reset();
|
||||
}
|
||||
public void partialResetAndCleanup() {
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.github.hhhzzzsss.songplayer.playing;
|
|||
|
||||
import com.github.hhhzzzsss.songplayer.Config;
|
||||
import com.github.hhhzzzsss.songplayer.SongPlayer;
|
||||
import com.github.hhhzzzsss.songplayer.song.Instrument;
|
||||
import com.github.hhhzzzsss.songplayer.song.Song;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
|
@ -25,10 +26,16 @@ public class Stage {
|
|||
public BlockPos position;
|
||||
public HashMap<Integer, BlockPos> noteblockPositions = new HashMap<>();
|
||||
|
||||
// Not used in survival-only mode
|
||||
public LinkedList<BlockPos> requiredBreaks = new LinkedList<>();
|
||||
public TreeSet<Integer> missingNotes = new TreeSet<>();
|
||||
public int totalMissingNotes = 0;
|
||||
|
||||
// Only used in survival-only mode
|
||||
public LinkedList<BlockPos> untunedNoteblocks = new LinkedList<>();
|
||||
public LinkedList<BlockPos> requiredClicks = new LinkedList<>();
|
||||
public int totalUntunedNoteblocks = 0;
|
||||
|
||||
public Stage() {
|
||||
position = player.getBlockPos();
|
||||
}
|
||||
|
@ -195,6 +202,82 @@ public class Stage {
|
|||
totalMissingNotes = missingNotes.size();
|
||||
}
|
||||
|
||||
public void checkSurvivalBuildStatus(Song song) throws NotEnoughInstrumentsException {
|
||||
noteblockPositions.clear();
|
||||
|
||||
Map<BlockPos, Integer>[] instrumentMap = loadSurvivalBlocks();
|
||||
|
||||
int[] requiredInstruments = new int[16];
|
||||
boolean hasMissing = false;
|
||||
for (int instrumentId = 0; instrumentId < 16; instrumentId++) {
|
||||
for (int pitch = 0; pitch < 25; pitch++) {
|
||||
int noteId = instrumentId*25 + pitch;
|
||||
if (song.requiredNotes[noteId]) {
|
||||
requiredInstruments[instrumentId]++;
|
||||
}
|
||||
}
|
||||
if (requiredInstruments[instrumentId] > instrumentMap[instrumentId].size()) {
|
||||
hasMissing = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasMissing) {
|
||||
int[] foundInstruments = new int[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
foundInstruments[i] = instrumentMap[i].size();
|
||||
}
|
||||
throw new NotEnoughInstrumentsException(requiredInstruments, foundInstruments);
|
||||
}
|
||||
|
||||
for (int noteid=0; noteid<400; noteid++) {
|
||||
if (song.requiredNotes[noteid]) {
|
||||
int instrumentId = noteid / 25;
|
||||
int targetPitch = noteid % 25;
|
||||
Map.Entry<BlockPos, Integer> closest = instrumentMap[instrumentId].entrySet()
|
||||
.stream()
|
||||
.min((a, b) -> {
|
||||
int adist = (targetPitch - a.getValue() + 25) % 25;
|
||||
int bdist = (targetPitch - b.getValue() + 25) % 25;
|
||||
return Integer.compare(adist, bdist);
|
||||
})
|
||||
.get();
|
||||
BlockPos bp = closest.getKey();
|
||||
int closestPitch = closest.getValue();
|
||||
instrumentMap[instrumentId].remove(bp);
|
||||
noteblockPositions.put(noteid, bp);
|
||||
int repetitions = (targetPitch - closestPitch + 25) % 25;
|
||||
for (int i = 0; i < repetitions; i++) {
|
||||
requiredClicks.add(bp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class NotEnoughInstrumentsException extends Exception {
|
||||
public int[] requiredInstruments;
|
||||
public int[] foundInstruments;
|
||||
public NotEnoughInstrumentsException(int[] requiredInstruments, int[] foundInstruments) {
|
||||
this.requiredInstruments = requiredInstruments;
|
||||
this.foundInstruments = foundInstruments;
|
||||
}
|
||||
public void giveInstrumentSummary() {
|
||||
SongPlayer.addChatMessage("§c------------------------------");
|
||||
SongPlayer.addChatMessage("§cMissing instruments required to play song:");
|
||||
for (int instrumentId = 0; instrumentId < 16; instrumentId++) {
|
||||
if (requiredInstruments[instrumentId] > 0) {
|
||||
Instrument instrument = Instrument.getInstrumentFromId(instrumentId);
|
||||
SongPlayer.addChatMessage(String.format(
|
||||
" §3%s (%s): §%s%d/%d",
|
||||
instrument.name(), instrument.material,
|
||||
foundInstruments[instrumentId] < requiredInstruments[instrumentId] ? "c" : "a",
|
||||
foundInstruments[instrumentId], requiredInstruments[instrumentId]
|
||||
));
|
||||
}
|
||||
}
|
||||
SongPlayer.addChatMessage("§c------------------------------");
|
||||
}
|
||||
}
|
||||
|
||||
void loadDefaultBlocks(Collection<BlockPos> noteblockLocations, Collection<BlockPos> breakLocations) {
|
||||
for (int dx = -4; dx <= 4; dx++) {
|
||||
for (int dz = -4; dz <= 4; dz++) {
|
||||
|
@ -425,6 +508,29 @@ public class Stage {
|
|||
}
|
||||
}
|
||||
|
||||
Map<BlockPos, Integer>[] loadSurvivalBlocks() {
|
||||
Map<BlockPos, Integer>[] instrumentMap = new Map[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
instrumentMap[i] = new TreeMap<>();
|
||||
}
|
||||
for (int dx = -5; dx <= 5; dx++) {
|
||||
for (int dz = -5; dz <= 5; dz++) {
|
||||
for (int dy : new int[]{-1, 0, 1, 2, -2, 3, -3, 4, -4, 5, 6}) {
|
||||
BlockPos bp = position.add(dx, dy, dz);
|
||||
BlockState bs = SongPlayer.MC.world.getBlockState(bp);
|
||||
int blockId = Block.getRawIdFromState(bs);
|
||||
if (blockId >= SongPlayer.NOTEBLOCK_BASE_ID && blockId < SongPlayer.NOTEBLOCK_BASE_ID + 800) {
|
||||
int noteId = (blockId - SongPlayer.NOTEBLOCK_BASE_ID) / 2;
|
||||
int instrument = noteId / 25;
|
||||
int pitch = noteId % 25;
|
||||
instrumentMap[instrument].put(bp, pitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return instrumentMap;
|
||||
}
|
||||
|
||||
// This doesn't check for whether the block above the noteblock position is also reachable
|
||||
// Usually there is sky above you though so hopefully this doesn't cause a problem most of the time
|
||||
boolean withinBreakingDist(int dx, int dy, int dz) {
|
||||
|
@ -434,7 +540,11 @@ public class Stage {
|
|||
}
|
||||
|
||||
public boolean nothingToBuild() {
|
||||
return requiredBreaks.isEmpty() && missingNotes.isEmpty();
|
||||
if (!Config.getConfig().survivalOnly) {
|
||||
return requiredBreaks.isEmpty() && missingNotes.isEmpty();
|
||||
} else {
|
||||
return requiredClicks.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int WRONG_INSTRUMENT_TOLERANCE = 3;
|
||||
|
|
|
@ -1,29 +1,31 @@
|
|||
package com.github.hhhzzzsss.songplayer.song;
|
||||
|
||||
public enum Instrument {
|
||||
HARP(0, 54),
|
||||
BASEDRUM(1, 0),
|
||||
SNARE(2, 0),
|
||||
HAT(3, 0),
|
||||
BASS(4, 30),
|
||||
FLUTE(5, 66),
|
||||
BELL(6, 78),
|
||||
GUITAR(7, 42),
|
||||
CHIME(8, 78),
|
||||
XYLOPHONE(9, 78),
|
||||
IRON_XYLOPHONE(10, 54),
|
||||
COW_BELL(11, 66),
|
||||
DIDGERIDOO(12, 30),
|
||||
BIT(13, 54),
|
||||
BANJO(14, 54),
|
||||
PLING(15, 54);
|
||||
HARP(0, 54, "Dirt/Other"),
|
||||
BASEDRUM(1, 0, "Any Stone"),
|
||||
SNARE(2, 0, "Sand/Gravel"),
|
||||
HAT(3, 0, "Glass"),
|
||||
BASS(4, 30, "Any Wood"),
|
||||
FLUTE(5, 66, "Clay"),
|
||||
BELL(6, 78, "Block of Gold"),
|
||||
GUITAR(7, 42, "Wool"),
|
||||
CHIME(8, 78, "Packed Ice"),
|
||||
XYLOPHONE(9, 78, "Bone Block"),
|
||||
IRON_XYLOPHONE(10, 54, "Block of Iron"),
|
||||
COW_BELL(11, 66, "Soul Sand"),
|
||||
DIDGERIDOO(12, 30, "Pumpkin"),
|
||||
BIT(13, 54, "Block of Emerald"),
|
||||
BANJO(14, 54, "Hay Bale"),
|
||||
PLING(15, 54, "Glowstone");
|
||||
|
||||
public final int instrumentId;
|
||||
public final int offset;
|
||||
public final String material;
|
||||
|
||||
Instrument(int instrumentId, int offset) {
|
||||
Instrument(int instrumentId, int offset, String material) {
|
||||
this.instrumentId = instrumentId;
|
||||
this.offset = offset;
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
private static Instrument[] values = values();
|
||||
|
|
Loading…
Reference in a new issue