Skip to content

Commit

Permalink
Localize Data Fixers, Remap Old Wires, Cables and Pipes
Browse files Browse the repository at this point in the history
  • Loading branch information
IntegerLimit committed Jan 19, 2024
1 parent a1ee3d0 commit c2d444f
Show file tree
Hide file tree
Showing 11 changed files with 375 additions and 102 deletions.
137 changes: 137 additions & 0 deletions src/main/java/com/nomiceu/nomilabs/remap/LabsMessageHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package com.nomiceu.nomilabs.remap;

import net.minecraft.client.resources.I18n;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.StartupQuery;

import java.util.Arrays;

public class LabsMessageHelper {
/**
* Send Message. If Type is Confirm, and user presses no, Startup will abort.
* @param type Type of Message
* @param texts Texts, which will be joined together.
*/
public static void sendTranslatableMessage(MessageType type, Translatable[] texts) {
var backup = Arrays.stream(texts).map((text) -> text.backup).toArray(String[]::new);
var joiners = Arrays.stream(texts).map((text) -> text.joiner).toArray(String[]::new);

// If is dedicated server, I18n definitely doesn't exist
// Just use backup strings.
if (FMLCommonHandler.instance().getSide().isServer()) sendMessage(backup, joiners, type);

// Try Translating
try {
Class.forName("net.minecraft.client.resources.I18n"); // Try to get I18n Class
// Exists, use it!
var translated = Arrays.stream(texts)
.map((text) -> I18n.format(text.key, text.substitutions))
.toArray(String[]::new);
sendMessage(translated, joiners, type);
} catch (ClassNotFoundException e) {
// I18n not found, use backup
sendMessage(backup, joiners, type);
}
}

private static void sendMessage(String[] message, String[] joiners, MessageType type) {
// Loop do this for all elements except for last
for (int i = 0; i < message.length - 1; i++)
message[i] = message[i].concat(joiners[i]);

var finalMessage = String.join("", message);
switch (type) {
case NOTIFY -> StartupQuery.notify(finalMessage);
case CONFIRM -> {
if (!StartupQuery.confirm(finalMessage)) LabsRemapHelper.abort();
}
}
}

public enum MessageType {
NOTIFY,
CONFIRM
}

public static class Translatable {
public final String backup;
public final String key;
public final Object[] substitutions;
/**
* What will be appended to the next translatable obj.
*/
public String joiner = "\n\n";

public Translatable(String backup, String key) {
this.backup = backup;
this.key = key;
this.substitutions = new Object[0];
}
public Translatable(String backup, String key, Object... substitutions) {
this.backup = backup;
this.key = key;
this.substitutions = substitutions;
}
public Translatable setJoiner(String joiner) {
this.joiner = joiner;
return this;
}
}

// Don't forget to update this in en_us.lang as well!
public static class Components {
public static Translatable[] getIntro() {
return new Translatable[] {
new Translatable("This world must be remapped.", "nomilabs.fixer.intro.1"),
new Translatable(TextFormatting.BOLD + "A Backup will be made.", "nomilabs.fixer.intro.2")
.setJoiner("\n"),
new Translatable("Pressing 'No' will cancel world loading.", "nomilabs.fixer.intro.3"),
new Translatable(TextFormatting.RED + "Note that after the world is loaded with this, you CANNOT undo this!.",
"nomilabs.fixer.intro.4").setJoiner("\n"),
new Translatable(String.format("You %sWILL%s have to load from the backup in order to load in a previous version!",
TextFormatting.UNDERLINE, TextFormatting.RESET),
"nomilabs.fixer.intro.5"),
};
}

public static Translatable[] getIntroAddition() {
return new Translatable[] {
new Translatable(TextFormatting.GRAY + "The changes that must be made via Data Fixers have been printed to your log.",
"nomilabs.fixer.intro.6")
};
}

public static Translatable[] getModeCheck(String mode) {
return new Translatable[] {
new Translatable(
String.format("Are you sure you previously loaded this world with the pack mode '%s' ?",
TextFormatting.YELLOW + mode + TextFormatting.RESET),
"nomilabs.fixer.mode_check.1",
mode),
new Translatable(
String.format(TextFormatting.RED + "Launching with the wrong mode %sWILL%s void items and/or blocks!",
TextFormatting.UNDERLINE, TextFormatting.RESET),
"nomilabs.fixer.mode_check.2"
),
new Translatable(
TextFormatting.GRAY + "If you did not change it in your old instance, the default mode is 'Normal'.",
"nomilabs.fixer.mode_check.3"
),
new Translatable(
"Press 'No' if you are not sure! (It will cancel world loading)",
"nomilabs.fixer.mode_check.4"
)
};
}

public static Translatable[] getDoNotExit() {
return new Translatable[] {
new Translatable(TextFormatting.RED + "Do not interrupt the loading process!",
"nomilabs.fixer.do_not_exit.1"),
new Translatable("If interrupted, load again from the backup, as your world may be corrupted!",
"nomilabs.fixer.do_not_exit.2")
};
}
}
}
56 changes: 49 additions & 7 deletions src/main/java/com/nomiceu/nomilabs/remap/LabsRemapHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
import com.nomiceu.nomilabs.remap.datafixer.storage.BlockRewriter;
import com.nomiceu.nomilabs.remap.datafixer.storage.BlockStateLike;
import com.nomiceu.nomilabs.remap.datafixer.storage.CompoundRewriter;
import net.minecraft.block.Block;
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraftforge.fml.common.StartupQuery;
import net.minecraftforge.fml.common.ZipperUtil;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.registry.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;

import java.util.Map;
import java.util.regex.Pattern;

public class LabsRemapHelper {
Expand All @@ -24,6 +24,8 @@ public class LabsRemapHelper {
public static final int MIN_META_ITEM_BASE_ID = 32000; // The Base ID where the Old Meta Items/Materials started from
public static final int MIN_META_BLOCK_BASE_ID = 2000; // The Base ID where the Old Meta Blocks started from

private static Map<BlockPos, NBTTagCompound> posToTileEntityCache;

public static void createWorldBackup() {
try {
NomiLabs.LOGGER.info("Creating world backup...");
Expand Down Expand Up @@ -69,16 +71,34 @@ public static void rewriteCompoundTags(NBTTagList tag, CompoundRewriter rewriter
}
}

public static void rewriteBlocks(NBTTagCompound chunkSectionTag, BlockRewriter rewriter) {
public static void rewriteBlocks(NBTTagCompound compound, BlockRewriter rewriter) {
clearTECache();
NBTTagCompound levelTag = compound.getCompoundTag("Level");
int x = levelTag.getInteger("xPos");
int z = levelTag.getInteger("zPos");
NBTTagList sectionListTag = levelTag.getTagList("Sections", Constants.NBT.TAG_COMPOUND);
for (int i = 0; i < sectionListTag.tagCount(); i++) {
sectionListTag.set(i, rewriteBlocksInSection(sectionListTag.getCompoundTagAt(i), x, z, rewriter));
}
if (posToTileEntityCache != null) {
var tagList = new NBTTagList();
posToTileEntityCache.values().forEach(tagList::appendTag);
levelTag.setTag("TileEntities", tagList);
}
}

private static NBTTagCompound rewriteBlocksInSection(NBTTagCompound chunkSectionTag, int chunkX, int chunkZ, BlockRewriter rewriter) {
byte[] blockIds = chunkSectionTag.getByteArray("Blocks");
int chunkY = chunkSectionTag.getInteger("Y");
NibbleArray blockMetadata = new NibbleArray(chunkSectionTag.getByteArray("Data"));
NibbleArray extendedIds = chunkSectionTag.hasKey("Add", Constants.NBT.TAG_BYTE_ARRAY)
? new NibbleArray(chunkSectionTag.getByteArray("Add")) : null;
for (int i = 0; i < 4096; ++i) {
int x = i & 0x0F, y = i >> 8 & 0x0F, z = i >> 4 & 0x0F;
int id = extendedIds == null ? (blockIds[i] & 0xFF)
: ((blockIds[i] & 0xFF) | (extendedIds.get(x, y, z) << 8));
var state = new BlockStateLike(id, (short) blockMetadata.get(x, y, z));
var state = new BlockStateLike(id, (short) blockMetadata.get(x, y, z),
new BlockPos(chunkX * 16 + x, chunkY * 16 + y, chunkZ * 16 + z));
if (state.invalid) continue;
BlockStateLike remapped = rewriter.rewrite(state);
if (remapped != null) {
Expand All @@ -91,15 +111,37 @@ public static void rewriteBlocks(NBTTagCompound chunkSectionTag, BlockRewriter r
extendedIds.set(x, y, z, idExt);
}
blockMetadata.set(x, y, z, remapped.meta & 0x0F);

if (posToTileEntityCache != null && remapped.tileEntityTag != null)
posToTileEntityCache.put(remapped.pos, remapped.tileEntityTag);
}
}
if (extendedIds != null) {
chunkSectionTag.setByteArray("Add", extendedIds.getData());
}
return chunkSectionTag;
}

public static void clearTECache() {
posToTileEntityCache = null;
}

public static ForgeRegistry<Block> getBlockRegistry() {
return (ForgeRegistry<Block>) ForgeRegistries.BLOCKS;
/**
* Call Clear TE Cache every time doing this on a new section!
* <br>
* {@link LabsRemapHelper#rewriteBlocks(NBTTagCompound, BlockRewriter)} does this for you!
*/
public static Map<BlockPos, NBTTagCompound> getPosToTileEntityMap(NBTTagCompound chunkTag) {
if (posToTileEntityCache != null) return posToTileEntityCache;
posToTileEntityCache = new Object2ObjectLinkedOpenHashMap<>();
NBTTagCompound levelTag = chunkTag.getCompoundTag("Level");
NBTTagList tileEntities = levelTag.getTagList("TileEntities", Constants.NBT.TAG_COMPOUND); // Returns empty if doesn't exist
for (var te : tileEntities) {
var tag = (NBTTagCompound) te;
posToTileEntityCache.put(
new BlockPos(tag.getInteger("x"), tag.getInteger("y"), tag.getInteger("z")), tag);
}
return posToTileEntityCache;
}

public static void abort() {
Expand Down
17 changes: 5 additions & 12 deletions src/main/java/com/nomiceu/nomilabs/remap/LabsRemappers.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextFormatting;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.StartupQuery;
import net.minecraftforge.registries.IForgeRegistryEntry;
import org.spongepowered.include.com.google.common.collect.ImmutableList;

Expand All @@ -23,6 +21,7 @@
import java.util.regex.PatternSyntaxException;

import static com.nomiceu.nomilabs.LabsValues.*;
import static com.nomiceu.nomilabs.remap.LabsMessageHelper.sendTranslatableMessage;
import static com.nomiceu.nomilabs.remap.Remapper.RemapTypes;

public class LabsRemappers {
Expand Down Expand Up @@ -200,16 +199,10 @@ public static <T extends IForgeRegistryEntry<T>> void remapAndIgnoreEntries(Regi

// Check with user
if (!checked && !DataFixerHandler.checked) {
var message = new StringBuilder("This world must be remapped.\n\n")
.append(TextFormatting.BOLD).append("A Backup will be made.\n")
.append("Pressing 'No' will cancel world loading.\n\n")
.append(TextFormatting.RED)
.append("Note that after the world is loaded with this, you CANNOT undo this!\n")
.append("You WILL have to load from the backup in order to load in a previous version!");

if (!StartupQuery.confirm(message.toString())) {
LabsRemapHelper.abort();
}
sendTranslatableMessage(
LabsMessageHelper.MessageType.CONFIRM,
LabsMessageHelper.Components.getIntro()
);

LabsRemapHelper.createWorldBackup();

Expand Down
17 changes: 11 additions & 6 deletions src/main/java/com/nomiceu/nomilabs/remap/datafixer/DataFix.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import com.nomiceu.nomilabs.remap.datafixer.storage.BlockStateLike;
import com.nomiceu.nomilabs.remap.datafixer.storage.ItemStackLike;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;

import javax.annotation.Nullable;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
Expand Down Expand Up @@ -34,12 +34,17 @@ public ItemFix(String name, String description, boolean needsMode, Function<Inte
}
}

@SuppressWarnings("unused")
public static class BlockFix extends DataFix<BlockStateLike> {
public final ResourceLocation[] neededLocations;
public BlockFix(String name, String description, boolean needsMode, Function<Integer, Boolean> validVersion, Function<Map<String, String>, Boolean> validModList, Function<BlockStateLike, Boolean> validEntry, Consumer<BlockStateLike> transform, ResourceLocation... neededLocations) {
super(name, description, needsMode, validVersion, validModList, validEntry, transform);
this.neededLocations = neededLocations;
public final boolean teNeeded;
@Nullable
public final Function<BlockStateLike, Boolean> secondaryValidEntry;

public BlockFix(String name, String description, boolean needsMode, Function<Integer, Boolean> validVersion,
Function<Map<String, String>, Boolean> validModList, boolean teNeeded, Function<BlockStateLike, Boolean> validEntry,
@Nullable Function<BlockStateLike, Boolean> secondaryValidEntry, Consumer<BlockStateLike> blockTransform) {
super(name, description, needsMode, validVersion, validModList, validEntry, blockTransform);
this.secondaryValidEntry = secondaryValidEntry;
this.teNeeded = teNeeded;
}
}

Expand Down
Loading

0 comments on commit c2d444f

Please sign in to comment.