Add some update helper utilities

This commit is contained in:
Nassim Jahnke 2024-11-30 17:02:51 +01:00
parent 0a9ae7dc73
commit fd0a16aaf5
No known key found for this signature in database
GPG Key ID: EF6771C01F6EF02F
6 changed files with 455 additions and 0 deletions

2
.gitignore vendored
View File

@ -2,6 +2,8 @@ libraries/
logs/ logs/
generated/ generated/
output/ output/
states.txt
states_output.txt
### Java files ### ### Java files ###
*.class *.class

View File

@ -0,0 +1,88 @@
package com.viaversion.mappingsgenerator.helper;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.viaversion.mappingsgenerator.util.GsonUtil;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import static com.viaversion.mappingsgenerator.MappingsOptimizer.MAPPINGS_DIR;
/**
* Similar to {@link BlockStateMapper} in use, except for the array of wood/stone-based building blocks.
* <p>
* Directly edits the diff file.
*/
final class AnnoyingBlockStateMapper {
private static final List<Function<String, String>> MAPPERS = new ArrayList<>();
private static final List<String> WONDERFUL_STATES = List.of(
"_wood", "_log", "_sapling", "_wall", "_slab", "_stairs",
"_trapdoor", "_door", "_button", "_hanging_sign", "_wall_sign", "_sign",
"_leaves", "_fence_gate", "_fence", "_pressure_plate"
);
public static void main(final String[] args) throws IOException {
// Input examples
final String from = "1.21.4";
final String to = "1.21.2";
replace("resin_brick", "brick");
replace("tuff", "andesite");
contains("copper", "brick");
final Path path = MAPPINGS_DIR.resolve("diff").resolve(String.format("mapping-%sto%s.json", from, to));
final JsonObject object = GsonUtil.GSON.fromJson(Files.readString(path), JsonObject.class);
final JsonObject blockStates = object.getAsJsonObject("blockstates");
final JsonObject outputStates = new JsonObject();
final Set<String> handled = new HashSet<>();
for (final Map.Entry<String, JsonElement> entry : blockStates.entrySet()) {
final String value = entry.getValue().getAsString();
final String key = entry.getKey();
if (!value.isEmpty()) {
outputStates.add(key, entry.getValue());
continue;
}
final String keyPart = key.split("\\[")[0];
if (handled.contains(keyPart)) {
outputStates.add(key, entry.getValue());
continue;
}
final String wonderfulState = WONDERFUL_STATES.stream().filter(keyPart::endsWith).findAny().orElse(null);
if (wonderfulState == null) {
outputStates.add(key, entry.getValue());
continue;
}
handled.add(key);
String outputKey = keyPart.replace(wonderfulState, "");
for (final Function<String, String> mapper : MAPPERS) {
outputKey = mapper.apply(outputKey);
}
outputStates.addProperty(keyPart, outputKey + wonderfulState + "[");
}
object.add("blockstates", outputStates);
Files.writeString(path, GsonUtil.GSON.toJson(object));
}
private static void equals(final String from, final String to) {
MAPPERS.add(s -> s.equals(from) ? to : s);
}
private static void contains(final String from, final String to) {
MAPPERS.add(s -> s.contains(from) ? to : s);
}
private static void replace(final String from, final String to) {
MAPPERS.add(s -> s.replace(from, to));
}
}

View File

@ -0,0 +1,227 @@
package com.viaversion.mappingsgenerator.helper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import org.jetbrains.annotations.Nullable;
/**
* Utility to more easily map blockstates.
* <p>
* Copy the stubbed lines from diff mappings into a file called states.txt and update the CONSUMER contents.
* Different methods will do different things, the result will be printed to the console.
*/
final class BlockStateMapper {
private static final Function<BlockState, BlockState> CONSUMER = state -> {
state.addProperty(5, "waterlogged", "false");
state.setState("glow_lichen");
return state;
};
public static void main(final String[] args) throws IOException {
applyFunction();
}
public static void applyFunction() throws IOException {
final String content = Files.readString(Path.of("states.txt"));
for (final String line : content.split("\n")) {
String trimmedLine = line.replace("\"", "").trim();
if (trimmedLine.endsWith(": ,")) {
trimmedLine = trimmedLine.substring(0, trimmedLine.length() - 3);
}
final BlockState state = new BlockState(trimmedLine);
System.out.println("\"" + trimmedLine + "\": \"" + CONSUMER.apply(state) + "\",");
}
}
public static void replace(final String... replacements) throws IOException {
final String content = Files.readString(Path.of("states.txt"));
for (final String line : content.split("\n")) {
boolean found = false;
for (int i = 0; i < replacements.length; i += 2) {
final String from = replacements[i];
if (!line.contains(from)) {
continue;
}
final String to = replacements[i + 1];
final String[] split = line.split("\": \"", 2);
System.out.println(split[0] + "\": \"" + split[1].replace(from, to));
found = true;
break;
}
if (!found) {
System.out.println(line);
}
}
}
public static void editKey() throws IOException {
final String newName = "dark_oak_slab";
final String content = Files.readString(Path.of("states.txt"));
for (String line : content.split("\"\",")) {
if (line.trim().equals("}")) {
continue;
}
final String firstPart = line;
line = line.replace("\"", "").replace(": ", "").trim();
final String[] split = line.split("\\[", 2);
System.out.println(firstPart + "\"minecraft:" + newName + "[" + split[1] + "\",");
}
}
public static final class BlockState {
private final List<Property> properties = new ArrayList<>();
private String state;
public BlockState(final String state) {
final int start = state.indexOf('[');
if (start == -1) {
this.state = state;
return;
}
if (!state.endsWith("]")) {
throw new IllegalArgumentException("Invalid block state: " + state);
}
this.state = state.substring(0, start);
int lastCommaIndex = start;
int commaIndex;
while ((commaIndex = state.indexOf(',', lastCommaIndex + 1)) != -1) {
final String part = state.substring(lastCommaIndex + 1, commaIndex);
final String[] split = part.split("=", 2);
properties.add(new Property(split[0], split[1]));
lastCommaIndex = commaIndex;
}
final String part = state.substring(lastCommaIndex + 1, state.length() - 1);
final String[] split = part.split("=", 2);
properties.add(new Property(split[0], split[1]));
}
public @Nullable Property getProperty(final String key) {
for (final Property property : properties) {
if (property.key.equals(key)) {
return property;
}
}
return null;
}
public void addProperty(final String key, final String value) {
properties.add(new Property(key, value));
}
public void addProperty(final int index, final String key, final String value) {
properties.add(index, new Property(key, value));
}
public @Nullable Property removeProperty(final String key) {
for (int i = 0; i < properties.size(); i++) {
final Property property = properties.get(i);
if (property.key.equals(key)) {
properties.remove(i);
return property;
}
}
return null;
}
public List<Property> getProperties() {
return properties;
}
public String getState() {
return state;
}
public void setState(final String state) {
this.state = state;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder(state).append('[');
for (final Property property : properties) {
builder.append(property.getKey()).append('=').append(property.getValue()).append(',');
}
return builder.substring(0, builder.length() - 1) + "]";
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final BlockState that = (BlockState) o;
if (!properties.equals(that.properties)) return false;
return state.equals(that.state);
}
@Override
public int hashCode() {
int result = properties.hashCode();
result = 31 * result + state.hashCode();
return result;
}
public BlockState copy() {
return new BlockState(toString());
}
}
public static final class Property {
private String key;
private String value;
public Property(final String key, final String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(final String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(final String value) {
this.value = value;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Property property = (Property) o;
if (!key.equals(property.key)) return false;
return value.equals(property.value);
}
@Override
public int hashCode() {
int result = key.hashCode();
result = 31 * result + value.hashCode();
return result;
}
}
}

View File

@ -0,0 +1,107 @@
package com.viaversion.mappingsgenerator.helper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.viaversion.mappingsgenerator.util.PathUtil;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility to compare generate a diff of translations between two Minecraft versions.
* Copy the output into VB's translations file.
*/
final class TranslationMapper {
private static final Logger LOGGER = LoggerFactory.getLogger(TranslationMapper.class.getSimpleName());
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
public static void main(final String[] args) throws IOException {
final String oldVer = "1.21.2";
final String newVer = "1.21.4-rc3";
final Map<String, String> oldTranslations = load(oldVer);
final Set<String> oldValues = new HashSet<>(oldTranslations.values());
final Map<String, String> newTranslations = load(newVer);
final JsonObject diff = new JsonObject();
for (final Map.Entry<String, String> entry : newTranslations.entrySet()) {
if (oldTranslations.containsKey(entry.getKey())) {
continue;
}
if (oldValues.contains(entry.getValue())) {
LOGGER.warn("Changed value: {}", entry.getValue());
continue;
}
diff.addProperty(entry.getKey(), entry.getValue());
}
// Check for removed translations
for (final Map.Entry<String, String> entry : oldTranslations.entrySet()) {
if (!newTranslations.containsKey(entry.getKey())) {
//LOGGER.warn("mappings.put(\"" + entry.getKey() + "\", \"" + entry.getValue() + "\");");
}
}
LOGGER.info(diff.toString());
LOGGER.info("Mappings size: {}", diff.size());
}
private static Map<String, String> load(final String version) throws IOException {
final File jarFile = PathUtil.minecraftDir().resolve("versions").resolve(version).resolve(version + ".jar").toFile();
if (!jarFile.exists()) {
throw new IllegalArgumentException("File " + jarFile + " does not exist");
}
final String contents;
try (final ZipFile file = new ZipFile(jarFile)) {
ZipEntry langEntry = file.getEntry("assets/minecraft/lang/en_us.json");
if (langEntry == null) {
// Pre 1.13 translations
langEntry = file.getEntry("assets/minecraft/lang/en_us.lang");
if (langEntry != null) {
try (final InputStream inputStream = file.getInputStream(langEntry)) {
contents = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
}
return loadLegacyTranslations(contents);
}
throw new IllegalArgumentException("File " + jarFile + " does not contain en_us.json");
}
try (final InputStream inputStream = file.getInputStream(langEntry)) {
contents = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
}
}
final JsonObject object = GSON.fromJson(contents, JsonObject.class);
final Map<String, String> translations = new LinkedHashMap<>();
for (final Map.Entry<String, JsonElement> entry : object.entrySet()) {
translations.put(entry.getKey(), entry.getValue().getAsString());
}
return translations;
}
private static Map<String, String> loadLegacyTranslations(final String contents) {
final Map<String, String> translations = new LinkedHashMap<>();
contents.lines().forEach(line -> {
final int index = line.indexOf('=');
if (index != -1) {
translations.put(line.substring(0, index), line.substring(index + 1));
}
});
return translations;
}
}

View File

@ -0,0 +1,9 @@
package com.viaversion.mappingsgenerator.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public final class GsonUtil {
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
}

View File

@ -0,0 +1,22 @@
package com.viaversion.mappingsgenerator.util;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public final class PathUtil {
public static Path minecraftDir() {
// Windows path
Path minecraftDir = Paths.get(home(), "AppData", "Roaming", ".minecraft");
if (!Files.isDirectory(minecraftDir)) {
// MacOS path
minecraftDir = Paths.get(home(), "Library", "Application Support", "minecraft");
}
return minecraftDir;
}
private static String home() {
return System.getProperty("user.home");
}
}