Compare commits
No commits in common. "master" and "tweaks-0.1.14" have entirely different histories.
master
...
tweaks-0.1
10 changed files with 8 additions and 508 deletions
10
README.md
10
README.md
|
@ -99,14 +99,8 @@ Quickly kills (terminates) the server on trigger, via command or HTTP request.
|
||||||
Self-explanatory
|
Self-explanatory
|
||||||
|
|
||||||
### Durability alert
|
### Durability alert
|
||||||
Self-explanatory too.
|
Self-explanatory too. \
|
||||||
|
For simplicity, there's no configuration. Control with `tweaks724.durabilityalert`
|
||||||
`/durabilityalert` (`tweaks724.durabilityalert`)
|
|
||||||
|
|
||||||
### Word coords
|
|
||||||
Convert coordinates to easier to remember words
|
|
||||||
|
|
||||||
`/wordcoords` (`tweaks724.tauth`)
|
|
||||||
|
|
||||||
### Utility commands
|
### Utility commands
|
||||||
|
|
||||||
|
|
6
pom.xml
6
pom.xml
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<groupId>eu.m724</groupId>
|
<groupId>eu.m724</groupId>
|
||||||
<artifactId>tweaks</artifactId>
|
<artifactId>tweaks</artifactId>
|
||||||
<version>0.1.15-SNAPSHOT</version>
|
<version>0.1.14</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
@ -147,7 +147,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>eu.m724</groupId>
|
<groupId>eu.m724</groupId>
|
||||||
<artifactId>mstats-spigot</artifactId>
|
<artifactId>mstats-spigot</artifactId>
|
||||||
<version>0.1.2</version>
|
<version>0.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -168,6 +168,6 @@
|
||||||
|
|
||||||
<scm>
|
<scm>
|
||||||
<developerConnection>scm:git:git@git.m724.eu:Minecon724/tweaks724.git</developerConnection>
|
<developerConnection>scm:git:git@git.m724.eu:Minecon724/tweaks724.git</developerConnection>
|
||||||
<tag>HEAD</tag>
|
<tag>tweaks-0.1.14</tag>
|
||||||
</scm>
|
</scm>
|
||||||
</project>
|
</project>
|
|
@ -27,7 +27,6 @@ import eu.m724.tweaks.module.redstone.RedstoneModule;
|
||||||
import eu.m724.tweaks.module.sleep.SleepModule;
|
import eu.m724.tweaks.module.sleep.SleepModule;
|
||||||
import eu.m724.tweaks.module.swing.SwingModule;
|
import eu.m724.tweaks.module.swing.SwingModule;
|
||||||
import eu.m724.tweaks.module.updater.UpdaterModule;
|
import eu.m724.tweaks.module.updater.UpdaterModule;
|
||||||
import eu.m724.tweaks.module.wordcoords.WordCoordsModule;
|
|
||||||
import eu.m724.tweaks.module.worldborder.WorldBorderExpandModule;
|
import eu.m724.tweaks.module.worldborder.WorldBorderExpandModule;
|
||||||
import eu.m724.tweaks.module.worldborder.WorldBorderHideModule;
|
import eu.m724.tweaks.module.worldborder.WorldBorderHideModule;
|
||||||
|
|
||||||
|
@ -158,8 +157,6 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
|
|
||||||
TweaksModule.init(DurabilityModule.class);
|
TweaksModule.init(DurabilityModule.class);
|
||||||
|
|
||||||
TweaksModule.init(WordCoordsModule.class);
|
|
||||||
|
|
||||||
/* end modules */
|
/* end modules */
|
||||||
|
|
||||||
if (config.metrics()) {
|
if (config.metrics()) {
|
||||||
|
@ -167,7 +164,7 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
mStats(1);
|
mStats(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLogger.fine("Took %.3f milliseconds", (System.nanoTime() - start) / 1000000.0);
|
DebugLogger.fine("Took %.3f milliseconds".formatted((System.nanoTime() - start) / 1000000.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTargetVersion() {
|
private String getTargetVersion() {
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.module.wordcoords;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.module.wordcoords.converter.Decoder;
|
|
||||||
import eu.m724.tweaks.module.wordcoords.converter.Encoder;
|
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
public class WordCoordsConverter {
|
|
||||||
private final Encoder encoder;
|
|
||||||
private final Decoder decoder;
|
|
||||||
|
|
||||||
|
|
||||||
public WordCoordsConverter(WordList wordList) {
|
|
||||||
this.encoder = new Encoder(wordList);
|
|
||||||
this.decoder = new Decoder(wordList);
|
|
||||||
|
|
||||||
DebugLogger.fine("Words: %d (%d bits)", wordList.getWordCount(), wordList.getBitsPerWord());
|
|
||||||
DebugLogger.fine("Bits per word: %d", wordList.getBitsPerWord());
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] encode(int x, int z) {
|
|
||||||
return encoder.encode(x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] decode(String[] words) throws NoSuchElementException {
|
|
||||||
return decoder.decode(words);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,166 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.module.wordcoords;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.Language;
|
|
||||||
import eu.m724.tweaks.module.TweaksModule;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
public class WordCoordsModule extends TweaksModule implements CommandExecutor, Listener {
|
|
||||||
private WordList wordList;
|
|
||||||
private WordCoordsConverter converter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
try {
|
|
||||||
this.wordList = WordList.fromFile(getPlugin().getDataFolder().toPath().resolve("storage/wordlist.txt"));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.converter = new WordCoordsConverter(wordList);
|
|
||||||
|
|
||||||
registerCommand("wordcoords", this);
|
|
||||||
registerEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
int x = 0, z = 0;
|
|
||||||
String[] words = new String[0];
|
|
||||||
|
|
||||||
boolean encode = false; // means encode pos to words
|
|
||||||
|
|
||||||
if (args.length == 0) {
|
|
||||||
if (!(sender instanceof Player player)) {
|
|
||||||
sender.sendMessage(Language.getString("wordCoordsPlayerOnly"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = player.getLocation().getBlockX();
|
|
||||||
z = player.getLocation().getBlockZ();
|
|
||||||
|
|
||||||
encode = true;
|
|
||||||
} else if (args.length > 1) {
|
|
||||||
try {
|
|
||||||
double dx = Double.parseDouble(args[0]);
|
|
||||||
double dz = Double.parseDouble(args[args.length > 2 ? 2 : 1]);
|
|
||||||
|
|
||||||
if (dx > Integer.MAX_VALUE || dx < Integer.MIN_VALUE || dz > Integer.MAX_VALUE || dz < Integer.MIN_VALUE) {
|
|
||||||
sender.spigot().sendMessage(Language.getComponent("wordCoordsOutOfRange", ChatColor.RED));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = (int) dx;
|
|
||||||
z = (int) dz;
|
|
||||||
|
|
||||||
encode = true;
|
|
||||||
} catch (NumberFormatException ignored) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encode) {
|
|
||||||
words = converter.encode(x, z);
|
|
||||||
String encoded = "///" + String.join(".", words);
|
|
||||||
|
|
||||||
BaseComponent[] components = new ComponentBuilder()
|
|
||||||
.append(String.format("%d, %d encodes to ", x, z))
|
|
||||||
.color(ChatColor.GRAY)
|
|
||||||
.append(encoded)
|
|
||||||
.color(ChatColor.AQUA) // TODO improve color
|
|
||||||
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, encoded))
|
|
||||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Click to copy")))
|
|
||||||
.create();
|
|
||||||
|
|
||||||
sender.spigot().sendMessage(components);
|
|
||||||
} else {
|
|
||||||
String strArgs = String.join(" ", args);
|
|
||||||
words = smartDetectWords(strArgs);
|
|
||||||
|
|
||||||
if (words.length == 0) {
|
|
||||||
sender.spigot().sendMessage(Language.getComponent("wordCoordsNoWords", ChatColor.GRAY));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
int[] xz = converter.decode(words);
|
|
||||||
x = xz[0];
|
|
||||||
z = xz[1];
|
|
||||||
} catch (NoSuchElementException e) {
|
|
||||||
sender.spigot().sendMessage(Language.getComponent("wordCoordsInvalidWord", ChatColor.RED, e.getMessage()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String encoded = "///" + String.join(".", words);
|
|
||||||
|
|
||||||
BaseComponent[] components = new ComponentBuilder()
|
|
||||||
.append(encoded + " decodes to ")
|
|
||||||
.color(ChatColor.GRAY)
|
|
||||||
.append("%d, %d".formatted(x, z))
|
|
||||||
.color(ChatColor.AQUA) // TODO improve color
|
|
||||||
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, "%d, %d".formatted(x, z)))
|
|
||||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Click to copy")))
|
|
||||||
.append(" ±8")
|
|
||||||
.color(ChatColor.GRAY)
|
|
||||||
.create();
|
|
||||||
sender.spigot().sendMessage(components);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String[] smartDetectWords(String str) {
|
|
||||||
List<String> words = new ArrayList<>();
|
|
||||||
StringBuilder currentWord = new StringBuilder();
|
|
||||||
|
|
||||||
for (int i=0; i<str.length(); i++) {
|
|
||||||
char c = str.charAt(i);
|
|
||||||
|
|
||||||
if (Character.isLetter(c)) {
|
|
||||||
currentWord.append(c);
|
|
||||||
} else {
|
|
||||||
if (!currentWord.isEmpty()) {
|
|
||||||
words.add(currentWord.toString());
|
|
||||||
currentWord.setLength(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!currentWord.isEmpty()) {
|
|
||||||
words.add(currentWord.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return words.toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onCommand(PlayerCommandPreprocessEvent event) {
|
|
||||||
if (event.getMessage().startsWith("///")) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
|
|
||||||
event.getPlayer().performCommand("wordcoords " + event.getMessage().substring(3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.module.wordcoords;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class WordList {
|
|
||||||
private final List<String> wordList;
|
|
||||||
private final int bitsPerWord;
|
|
||||||
|
|
||||||
public WordList(List<String> words) {
|
|
||||||
this.wordList = words;
|
|
||||||
this.bitsPerWord = 32 - Integer.numberOfLeadingZeros(words.size()) - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getWord(int index) {
|
|
||||||
return wordList.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWordIndex(String word) {
|
|
||||||
return wordList.indexOf(word);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getWords(int... indexes) {
|
|
||||||
return Arrays.stream(indexes)
|
|
||||||
.mapToObj(this::getWord)
|
|
||||||
.toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getIndexes(String... words) {
|
|
||||||
return Arrays.stream(words)
|
|
||||||
.mapToInt(wordList::indexOf)
|
|
||||||
.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWordCount() {
|
|
||||||
return wordList.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBitsPerWord() {
|
|
||||||
return bitsPerWord;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static WordList fromFile(Path path) throws IOException {
|
|
||||||
try (var lines = Files.lines(path)) {
|
|
||||||
var list = lines.filter(s -> !s.isBlank())
|
|
||||||
.map(String::toLowerCase)
|
|
||||||
.distinct()
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
return new WordList(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.module.wordcoords.converter;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.module.wordcoords.WordList;
|
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class Decoder {
|
|
||||||
private final WordList wordList;
|
|
||||||
private final int bitsPerWord;
|
|
||||||
|
|
||||||
public Decoder(WordList wordList) {
|
|
||||||
this.wordList = wordList;
|
|
||||||
this.bitsPerWord = wordList.getBitsPerWord();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] decode(String[] words) throws NoSuchElementException {
|
|
||||||
int[] wordIndexes = new int[words.length];
|
|
||||||
|
|
||||||
for (int i=0; i<words.length; i++) {
|
|
||||||
wordIndexes[i] = wordList.getWordIndex(words[i]);
|
|
||||||
if (wordIndexes[i] == -1)
|
|
||||||
throw new NoSuchElementException(words[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return decode(wordIndexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] decode(int[] wordIndexes) {
|
|
||||||
DebugLogger.finer("Decoding word indexes: %s", Arrays.toString(wordIndexes));
|
|
||||||
|
|
||||||
int bitsRequired = wordIndexes.length * wordList.getBitsPerWord();
|
|
||||||
int bitsRequiredPerCoordinate = bitsRequired / 2;
|
|
||||||
DebugLogger.finer("Bits required: %d (per coord: %d)", bitsRequired, bitsRequiredPerCoordinate);
|
|
||||||
|
|
||||||
|
|
||||||
long combinedValue = wordIndexesToCombinedValue(wordIndexes);
|
|
||||||
DebugLogger.finer("Combined value: %d", combinedValue);
|
|
||||||
|
|
||||||
|
|
||||||
int[] decodedCoords = decodeCoords(combinedValue, bitsRequiredPerCoordinate);
|
|
||||||
int chunkX = decodedCoords[0];
|
|
||||||
int chunkZ = decodedCoords[1];
|
|
||||||
DebugLogger.finer("Chunk: %d, %d", chunkX, chunkZ);
|
|
||||||
|
|
||||||
// +8 to make it center of chunk
|
|
||||||
int xCoord = chunkX * 16 + 8;
|
|
||||||
int zCoord = chunkZ * 16 + 8;
|
|
||||||
DebugLogger.finer("Decoded to coordinates: %d, %d", xCoord, zCoord);
|
|
||||||
|
|
||||||
return new int[] { xCoord, zCoord };
|
|
||||||
}
|
|
||||||
|
|
||||||
private long wordIndexesToCombinedValue(int[] wordIndexes) {
|
|
||||||
long combinedValue = 0;
|
|
||||||
|
|
||||||
for (int i=0; i<wordIndexes.length; i++) {
|
|
||||||
combinedValue <<= bitsPerWord;
|
|
||||||
combinedValue |= wordIndexes[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return combinedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] decodeCoords(long combinedValue, int bitsRequiredPerCoordinate) {
|
|
||||||
int coordinateMask = (1 << bitsRequiredPerCoordinate) - 1;
|
|
||||||
int coordinateOffset = 1 << (bitsRequiredPerCoordinate - 1);
|
|
||||||
|
|
||||||
int z = (int) (combinedValue & coordinateMask) - coordinateOffset;
|
|
||||||
int x = (int) (combinedValue >> bitsRequiredPerCoordinate) - coordinateOffset;
|
|
||||||
|
|
||||||
return new int[] { x, z };
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.module.wordcoords.converter;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.module.wordcoords.WordList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
public class Encoder {
|
|
||||||
private final WordList wordList;
|
|
||||||
private final int bitsPerWord;
|
|
||||||
|
|
||||||
public Encoder(WordList wordList) {
|
|
||||||
this.wordList = wordList;
|
|
||||||
this.bitsPerWord = wordList.getBitsPerWord();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] encode(int xCoord, int zCoord) {
|
|
||||||
int chunkX = Math.floorDiv(xCoord, 16);
|
|
||||||
int chunkZ = Math.floorDiv(zCoord, 16);
|
|
||||||
DebugLogger.finer("Chunk: %d, %d", chunkX, chunkZ);
|
|
||||||
|
|
||||||
// Calculate minimum bits required per coordinate based on range
|
|
||||||
int bitsRequiredPerCoordinate = findBitsRequiredPerCoordinate(chunkX, chunkZ);
|
|
||||||
int minTotalBits = bitsRequiredPerCoordinate * 2;
|
|
||||||
DebugLogger.finer("Min bits required per coordinate: %d (total: %d)", bitsRequiredPerCoordinate, minTotalBits);
|
|
||||||
|
|
||||||
// Calculate words required, ensuring total bits is sufficient and even
|
|
||||||
int wordsRequired = 0;
|
|
||||||
int actualTotalBits = 0;
|
|
||||||
if (minTotalBits > 0) { // Avoid division by zero if bitsPerWord is 0, or log(0)
|
|
||||||
wordsRequired = Math.ceilDiv(minTotalBits, bitsPerWord);
|
|
||||||
actualTotalBits = wordsRequired * bitsPerWord;
|
|
||||||
// Ensure total bits is sufficient
|
|
||||||
while (actualTotalBits < minTotalBits) {
|
|
||||||
wordsRequired++;
|
|
||||||
actualTotalBits = wordsRequired * bitsPerWord;
|
|
||||||
}
|
|
||||||
} // else: coords are 0 or -1, minTotalBits=0, wordsRequired=0, actualTotalBits=0. Need special handling?
|
|
||||||
// If x/z are 0/-1, findBitsRequired returns 1, minTotalBits=2. The loop handles it.
|
|
||||||
|
|
||||||
// Final bits per coordinate based on words
|
|
||||||
bitsRequiredPerCoordinate = actualTotalBits / 2;
|
|
||||||
DebugLogger.finer("Final Words required: %d", wordsRequired);
|
|
||||||
DebugLogger.finer("Final Bits required: %d (per coord: %d)", actualTotalBits, bitsRequiredPerCoordinate);
|
|
||||||
|
|
||||||
int encodedX = encodeCoord(chunkX, bitsRequiredPerCoordinate);
|
|
||||||
int encodedZ = encodeCoord(chunkZ, bitsRequiredPerCoordinate);
|
|
||||||
DebugLogger.finer("Encoded coordinates: %d, %d", encodedX, encodedZ);
|
|
||||||
|
|
||||||
long combinedValue = ((long) encodedX << bitsRequiredPerCoordinate) | encodedZ;
|
|
||||||
DebugLogger.finer("Combined value: %d", combinedValue);
|
|
||||||
|
|
||||||
int[] wordIndexes = combinedValueToWordIndexes(combinedValue, wordsRequired);
|
|
||||||
DebugLogger.finer("Word indexes: %s", Arrays.toString(wordIndexes));
|
|
||||||
|
|
||||||
return wordList.getWords(wordIndexes);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculates the minimum number of bits required to represent the coordinate
|
|
||||||
// using the encoding scheme (offset + coord) & mask, such that the coordinate
|
|
||||||
// fits within the range [-(1 << (bits - 1)), (1 << (bits - 1)) - 1].
|
|
||||||
private int findBitsRequiredPerCoordinate(int x, int z) {
|
|
||||||
int maxVal = Math.max(x, z);
|
|
||||||
int minVal = Math.min(x, z);
|
|
||||||
|
|
||||||
// Determine the required positive magnitude for the encoding range's positive side.
|
|
||||||
// We need `(1 << (bits - 1)) >= max(maxVal + 1, -minVal)`
|
|
||||||
int requiredPositiveMagnitude = Math.max(maxVal + 1, -minVal);
|
|
||||||
|
|
||||||
if (requiredPositiveMagnitude <= 0) {
|
|
||||||
// Occurs only if maxVal <= -1 and minVal >= 0, which is impossible,
|
|
||||||
// OR maxVal <= 0 and -minVal <= 0 => maxVal <= 0 and minVal >= 0.
|
|
||||||
// This means x and z are both 0.
|
|
||||||
// The range for 1 bit is [-1, 0]. If coords are 0, 1 bit is not enough for offset+coord.
|
|
||||||
// Example: bits=1. offset=1<<0=1. mask=(1<<1)-1=1.
|
|
||||||
// encodeCoord(0, 1) = (1+0)&1 = 1.
|
|
||||||
// decodeCoord(1, 1): val=1. mask=1. offset=1. (1&1)-1 = 0. Correct.
|
|
||||||
// What if we need to represent -1? encodeCoord(-1, 1) = (1-1)&1 = 0.
|
|
||||||
// decodeCoord(0, 1): val=0. (0&1)-1 = -1. Correct.
|
|
||||||
// So 1 bit works for range [-1, 0]. Let's check the condition:
|
|
||||||
// x=0, z=0 -> maxVal=0, minVal=0. reqPosMag = max(1, 0) = 1.
|
|
||||||
// x=-1, z=-1 -> maxVal=-1, minVal=-1. reqPosMag = max(0, 1) = 1.
|
|
||||||
// x=0, z=-1 -> maxVal=0, minVal=-1. reqPosMag = max(1, 1) = 1.
|
|
||||||
// So requiredPositiveMagnitude is 1 for the range [-1, 0].
|
|
||||||
requiredPositiveMagnitude = 1; // Ensure it's at least 1 if coords are 0 or -1.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate p = bits - 1
|
|
||||||
// We need the smallest integer p such that (1 << p) >= requiredPositiveMagnitude.
|
|
||||||
// If requiredPositiveMagnitude = 1, we need 1 << p >= 1, smallest p is 0.
|
|
||||||
// If requiredPositiveMagnitude > 1, this is equivalent to finding the number of bits
|
|
||||||
// needed to represent (requiredPositiveMagnitude - 1) in binary.
|
|
||||||
int p;
|
|
||||||
if (requiredPositiveMagnitude == 1) {
|
|
||||||
p = 0;
|
|
||||||
} else {
|
|
||||||
p = 32 - Integer.numberOfLeadingZeros(requiredPositiveMagnitude - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bits = p + 1
|
|
||||||
return p + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int encodeCoord(int coord, int bitsRequiredPerCoordinate) {
|
|
||||||
// Bitmask and offset for positive integer conversion
|
|
||||||
int coordinateMask = (1 << bitsRequiredPerCoordinate) - 1;
|
|
||||||
int coordinateOffset = 1 << (bitsRequiredPerCoordinate - 1);
|
|
||||||
|
|
||||||
// Encode coordinates with offset into positive range
|
|
||||||
return (coordinateOffset + coord) & coordinateMask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[] combinedValueToWordIndexes(long combinedValue, int wordsRequired) {
|
|
||||||
int bitsRequired = wordsRequired * bitsPerWord;
|
|
||||||
|
|
||||||
// Break into word indexes
|
|
||||||
int[] wordIndexes = new int[wordsRequired];
|
|
||||||
int currentIndex = wordsRequired; // Start filling from end of array
|
|
||||||
|
|
||||||
for (int remainingBits = bitsRequired; remainingBits > 0; remainingBits -= bitsPerWord) {
|
|
||||||
int wordMask = (1 << bitsPerWord) - 1;
|
|
||||||
wordIndexes[--currentIndex] = (int) (combinedValue & wordMask);
|
|
||||||
combinedValue >>= bitsPerWord;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wordIndexes;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,7 +8,7 @@ api-version: 1.21.1
|
||||||
softdepend: [ProtocolLib]
|
softdepend: [ProtocolLib]
|
||||||
|
|
||||||
libraries:
|
libraries:
|
||||||
- eu.m724:mstats-spigot:0.1.2
|
- eu.m724:mstats-spigot:0.1.0
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
chat:
|
chat:
|
||||||
|
@ -43,10 +43,6 @@ commands:
|
||||||
durabilityalert:
|
durabilityalert:
|
||||||
description: Durability alert toggle
|
description: Durability alert toggle
|
||||||
permission: tweaks724.durabilityalert
|
permission: tweaks724.durabilityalert
|
||||||
wordcoords:
|
|
||||||
description: Word to coords conversion
|
|
||||||
permission: tweaks724.wordcoords
|
|
||||||
aliases: [woco, wc, w3w]
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
tweaks724.chatmanage:
|
tweaks724.chatmanage:
|
||||||
|
@ -67,8 +63,6 @@ permissions:
|
||||||
default: false
|
default: false
|
||||||
tweaks724.durabilityalert:
|
tweaks724.durabilityalert:
|
||||||
default: true
|
default: true
|
||||||
tweaks724.wordcoords:
|
|
||||||
default: true
|
|
||||||
|
|
||||||
7weaks724.ignore.this:
|
7weaks724.ignore.this:
|
||||||
description: "Internal, not for use. ${project.spigot.version}"
|
description: "Internal, not for use. ${project.spigot.version}"
|
||||||
|
|
|
@ -39,9 +39,3 @@ clickToExecuteCommand = Click to execute command
|
||||||
|
|
||||||
durabilityEnabled = Enabled durability alert
|
durabilityEnabled = Enabled durability alert
|
||||||
durabilityDisabled = Disabled durability alert
|
durabilityDisabled = Disabled durability alert
|
||||||
|
|
||||||
# When console executes /wordcoords without arguments
|
|
||||||
wordCoordsPlayerOnly = Only players can execute this command without arguments.
|
|
||||||
wordCoordsOutOfRange = Those coordinates are invalid.
|
|
||||||
wordCoordsInvalidWord = Invalid word: "%s"
|
|
||||||
wordCoordsNoWords = Please provide the Z coordinate.
|
|
Loading…
Add table
Add a link
Reference in a new issue