Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

import java.lang.invoke.MethodHandles;

import static net.modificationstation.stationapi.api.vanillafix.datafixer.schema.StationFlatteningItemStackSchema.putItem;
import static net.modificationstation.stationapi.api.vanillafix.datafixer.schema.StationFlatteningItemStackSchema.putState;
import static net.modificationstation.stationapi.api.vanillafix.datafixer.schema.StationFlatteningItemStackSchema.*;

public class DataFixerListener {
static {
Expand All @@ -23,6 +22,7 @@ private static void registerFixer(DataFixerRegisterEvent event) {
putState(99, "sltest:farlands_block", Util.make(new NbtCompound(), tag -> tag.putString("facing", "north")));
putState(100, "sltest:freezer");
putState(101, "sltest:altar");
putStateMetaRule(17, 2, "minecraft:wool", 10);
putItem(360, "sltest:test_item");
putItem(361, "sltest:test_pickaxe");
putItem(362, "sltest:nbt_item");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@

import static net.modificationstation.stationapi.impl.world.FlattenedWorldManager.SECTIONS;

/**
* Reverses Station API's block conversion into identifiers and reverts blocks into numeric IDs
*/
public class StationFlatteningToMcRegionChunkDamage extends DataFix {
private final static int CHUNK_SIZE = 16 * 128 * 16;
private final static byte[] DEFAULT_BLOCK_LIGHT = new byte[CHUNK_SIZE >> 1];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import net.modificationstation.stationapi.api.util.collection.PackedIntegerArray;
import net.modificationstation.stationapi.api.util.math.MathHelper;
import net.modificationstation.stationapi.api.vanillafix.datafixer.schema.StationFlatteningItemStackSchema;
import net.modificationstation.stationapi.api.vanillafix.util.MetaDependentIdConversion;

import java.nio.ByteBuffer;
import java.util.Arrays;
Expand All @@ -24,6 +25,11 @@

import static net.modificationstation.stationapi.impl.world.FlattenedWorldManager.SECTIONS;

/**
* Datafixer used for converting McRegion worlds (Vanilla Beta 1.7.3 world format)
* <p>
* Handles block conversions
*/
public class McRegionToStationFlatteningChunkFix extends DataFix {
private final String name;

Expand Down Expand Up @@ -75,7 +81,7 @@ public Level(Dynamic<?> dynamic) {
public Dynamic<?> transform() {
Dynamic<?> self = this.level;

// create sections with blocks
// Create sections with blocks
Section[] sections = new Section[8];
for (int i = 0; i < 32768; i++) {
int worldY = i & 0b1111111;
Expand All @@ -84,17 +90,24 @@ public Dynamic<?> transform() {
int z = i >> 7 & 0b1111;
int x = i >> 11;
int block = Byte.toUnsignedInt(blocks.get(i));
int data = this.data.get(x, worldY, z);
if (block > 0 || data > 0) {
int metadata = this.data.get(x, worldY, z);
if (block > 0 || metadata > 0) {
if (sections[sectionY] == null)
sections[sectionY] = new Section(self.createMap(Map.of(self.createString("y"), self.createByte((byte) sectionY))));
Section section = sections[sectionY];
section.setBlock(x, y, z, StationFlatteningItemStackSchema.lookupState(block)); // do not convert just yet. we need same references for faster key comparison
section.setData(x, y, z, data);
// Preparation for conversion. References are maintained for faster key comparison
// See "transform" method at the bottom of this file for actual conversion
section.setBlock(x, y, z, StationFlatteningItemStackSchema.lookupState(block, metadata));
// Replace old metadata with new one if specified
int newMetadata = StationFlatteningItemStackSchema.lookupMetadata(block, metadata);
if (newMetadata == MetaDependentIdConversion.UNSPECIFIED_META) {
newMetadata = metadata;
}
section.setMetadata(x, y, z, newMetadata);
}
}

// add lighting in created sections
// Add lighting in created sections
for (Section section : sections) {
if (section != null) {
int sectionY = section.y;
Expand All @@ -110,13 +123,13 @@ public Dynamic<?> transform() {
}
}

// expand height map
byte[] height_map = new byte[512];
for (int i = 0; i < height_map.length >> 1; i++) height_map[i << 1] = this.height_map.get(i);
// Expand height map
byte[] heightMap = new byte[512];
for (int i = 0; i < heightMap.length >> 1; i++) heightMap[i << 1] = this.height_map.get(i);

return self
.set(SECTIONS, self.createList(Arrays.stream(sections).filter(Objects::nonNull).map(Section::transform)))
.set("height_map", self.createByteList(ByteBuffer.wrap(height_map)))
.set("height_map", self.createByteList(ByteBuffer.wrap(heightMap)))
.remove("BlockLight")
.remove("Blocks")
.remove("Data")
Expand Down Expand Up @@ -155,7 +168,7 @@ static final class Section {
public Section(Dynamic<?> section) {
this.section = section;
y = section.get("y").asInt(0);
Dynamic<?> air = StationFlatteningItemStackSchema.lookupState(0); // same applies
Dynamic<?> air = StationFlatteningItemStackSchema.lookupState(0, 0); // same applies
seenStates.add(air);
paletteData.add(air);
paletteMap.add(air);
Expand All @@ -170,7 +183,7 @@ public void setBlock(int x, int y, int z, Dynamic<?> state) {
states[(y << 4 | z) << 4 | x] = addTo(paletteMap, state);
}

public void setData(int x, int y, int z, int data) {
public void setMetadata(int x, int y, int z, int data) {
this.data.setValue(x << 8 | y << 4 | z, data);
}

Expand All @@ -180,7 +193,8 @@ public void setBlockLight(int x, int y, int z, int blockLight) {

public Dynamic<?> transform() {
Dynamic<?> self = this.section;
Dynamic<?> palette = self.createList(paletteData.stream().map(dynamic -> dynamic.convert(self.getOps()))); // instead, convert when used
// Convert previously prepared values
Dynamic<?> palette = self.createList(paletteData.stream().map(dynamic -> dynamic.convert(self.getOps())));
PackedIntegerArray array = new PackedIntegerArray(Math.max(4, MathHelper.ceilLog2(paletteData.size())), states.length);
for (int i = 0; i < states.length; i++) array.set(i, states[i]);
Dynamic<?> data = self.createLongList(Arrays.stream(array.getData()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
import java.util.Map;
import java.util.function.Supplier;

/**
* Defines conversion rules for different parts of the chunk data
* <p>
* Includes registries for Vanilla entities and block entities
*/
public class McRegionSchemaB1_7_3 extends Schema {
public McRegionSchemaB1_7_3(int versionKey, Schema parent) {
super(versionKey, parent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.nbt.NbtCompound;
import net.modificationstation.stationapi.api.datafixer.TypeReferences;
import net.modificationstation.stationapi.api.nbt.NbtOps;
import net.modificationstation.stationapi.api.util.Util;
import net.modificationstation.stationapi.api.vanillafix.util.MetaDependentIdConversion;

import java.util.Map;
import java.util.function.Supplier;

import static net.modificationstation.stationapi.impl.vanillafix.datafixer.VanillaDataFixerImpl.STATION_ID;

public class StationFlatteningItemStackSchema extends Schema {
private static final Dynamic<?>[] OLD_ID_TO_BLOCKSTATE = new Dynamic[256];
private static final MetaDependentIdConversion[] OLD_ID_TO_BLOCKSTATE = new MetaDependentIdConversion[256];
private static final Object2IntOpenHashMap<String> BLOCK_TO_OLD_ID = Util.make(new Object2IntOpenHashMap<>(256), map -> map.defaultReturnValue(0));
private static final String[] OLD_ID_TO_ITEM = new String[32000];
private static final Object2IntOpenHashMap<String> ITEM_TO_OLD_ID = Util.make(new Object2IntOpenHashMap<>(512), map -> map.defaultReturnValue(0));
Expand All @@ -28,34 +28,103 @@ public static void putState(int oldId, String id, NbtCompound properties) {
}));
}

/**
* Assigns a numeric block ID to its new identifier
* @param oldId Numeric block ID to be converted
* @param id New identifier (including the namespace)
*/
public static void putState(int oldId, String id) {
putState(oldId, Util.make(new NbtCompound(), tag -> tag.putString("Name", id)));
}

/**
* Assigns a numeric block ID to an NBT compound with the new identifier and block state rules
* @param oldId Numeric block ID to be converted
* @param tag Tag with the identifier and block state rules
*/
public static void putState(int oldId, NbtCompound tag) {
String id = tag.getString("Name");
BLOCK_TO_OLD_ID.put(id, oldId);
Dynamic<?> dynamic = new Dynamic<>(NbtOps.INSTANCE, tag);
OLD_ID_TO_BLOCKSTATE[oldId] = dynamic;
OLD_ID_TO_BLOCKSTATE[oldId] = new MetaDependentIdConversion(tag);
putItem(oldId, id);
}

public static Dynamic<?> lookupState(int stateId) {
Dynamic<?> dynamic = null;
/**
* Creates a metadata specific conversion rule for a block
* <p>
* <em>Must be used after the putState method<em/>
* @param oldId Numeric block ID to add the rule to
* @param meta Old metadata
* @param id New identifier (including the namespace)
* @param outputMeta New metadata, or {@link MetaDependentIdConversion#UNSPECIFIED_META} to keep the old one
* @throws IllegalArgumentException if oldId has no state mapping,
* or if oldId, meta or outputMeta is out of range
*/
public static void putStateMetaRule(int oldId, int meta, String id, int outputMeta) {
putStateMetaRule(oldId, meta, Util.make(new NbtCompound(), tag -> tag.putString("Name", id)), outputMeta);
}

/**
* Creates a metadata specific conversion rule for a block
* <p>
* <em>Must be used after the putState method<em/>
* @param oldId Numeric block ID to add the rule to
* @param meta Old metadata
* @param tag Tag with the identifier and block state rules
* @param outputMeta New metadata, or {@link MetaDependentIdConversion#UNSPECIFIED_META} to keep the old one
* @throws IllegalArgumentException if oldId has no state mapping,
* or if oldId, meta or outputMeta is out of range
*/
public static void putStateMetaRule(int oldId, int meta, NbtCompound tag, int outputMeta) {
if (oldId < 0 || oldId >= OLD_ID_TO_BLOCKSTATE.length) {
throw new IllegalArgumentException(
"Block ID " + oldId + " is out of range, it must be between 0 and " +
(OLD_ID_TO_BLOCKSTATE.length - 1)
);
}
MetaDependentIdConversion rule = OLD_ID_TO_BLOCKSTATE[oldId];
if (rule == null) {
throw new IllegalArgumentException(
"Block ID " + oldId + " has no state mapping, call putState for it before adding metadata rules"
);
}
rule.addMetaDependentTag(meta, tag, outputMeta);
}

/**
* Takes a numeric block ID and returns a block entry for the datafixer
* @param stateId Numeric ID of the block
* @param metadata Metadata of the block
* @return Dynamic which contains the new ID
*/
public static Dynamic<?> lookupState(int stateId, int metadata) {
MetaDependentIdConversion rule = null;
if (stateId >= 0 && stateId < OLD_ID_TO_BLOCKSTATE.length) {
dynamic = OLD_ID_TO_BLOCKSTATE[stateId];
rule = OLD_ID_TO_BLOCKSTATE[stateId];
}
return dynamic == null ? OLD_ID_TO_BLOCKSTATE[0] : dynamic;
return rule == null ? OLD_ID_TO_BLOCKSTATE[0].getDefaultTag() : rule.getTagForMeta(metadata);
}

public static String lookupBlockId(int id) {
if (id < 0 || id >= OLD_ID_TO_BLOCKSTATE.length) {
return "minecraft:air";
/**
* Replaces an old metadata with a new one for the given block
* @param stateId Numeric ID of the block
* @param metadata Old metadata
* @return New metadata or -1 if not specified
*/
public static int lookupMetadata(int stateId, int metadata) {
MetaDependentIdConversion rule = null;
if (stateId >= 0 && stateId < OLD_ID_TO_BLOCKSTATE.length) {
rule = OLD_ID_TO_BLOCKSTATE[stateId];
}
Dynamic<?> dynamic = OLD_ID_TO_BLOCKSTATE[id];
return dynamic == null ? "minecraft:air" : dynamic.get("Name").asString("");
return rule == null ? MetaDependentIdConversion.UNSPECIFIED_META : rule.getOutputMeta(metadata);
}

/**
* Reversed direction converter which turns an identifier into a numeric ID
* @param dynamic Dynamic with an identifier inside
* @return numeric ID
* @param <T> Type of the dynamic
*/
public static <T> int lookupOldBlockId(Dynamic<T> dynamic) {
return BLOCK_TO_OLD_ID.getInt(dynamic.get("Name").asString(""));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package net.modificationstation.stationapi.api.vanillafix.util;

import com.mojang.serialization.Dynamic;
import lombok.Getter;
import net.minecraft.nbt.NbtCompound;
import net.modificationstation.stationapi.api.nbt.NbtOps;

import java.util.Arrays;

/**
* Provides advanced conversion rules which depend on metadata
* <p>
* Contains a default tag for unspecified metadata rules and arrays which are null by default to save memory
*/
public class MetaDependentIdConversion {
private static final int META_COUNT = 16;
public static final int UNSPECIFIED_META = -1;

@Getter
private final Dynamic<?> defaultTag;

private Dynamic<?>[] metaDependentTags = null;
private int[] outputMetas = null;

/**
* @param defaultTag Tag to be used for unspecified metadata rules
*/
public MetaDependentIdConversion(NbtCompound defaultTag) {
this.defaultTag = toDynamic(defaultTag);
}

/**
* Adds a meta rule and initializes arrays if necessary
* @param meta Metadata of the rule, must be a valid metadata value
* @param metaDependentTag Rule to be added
* @param outputMeta New metadata of the converted block,
* or {@link #UNSPECIFIED_META} to keep the original metadata
* @throws IllegalArgumentException if meta is out of range, or if outputMeta is neither
* {@link #UNSPECIFIED_META} nor a valid metadata value
*/
public void addMetaDependentTag(int meta, NbtCompound metaDependentTag, int outputMeta) {
if (isOutOfRange(meta)) {
throw new IllegalArgumentException(
"Metadata " + meta + " is out of range, it must be between 0 and " + (META_COUNT - 1)
);
}
if (outputMeta != UNSPECIFIED_META && isOutOfRange(outputMeta)) {
throw new IllegalArgumentException(
"Output metadata " + outputMeta + " is out of range, it must be between 0 and " +
(META_COUNT - 1) + ", or " + UNSPECIFIED_META + " to keep the original metadata"
);
}
if (metaDependentTags == null || outputMetas == null) {
metaDependentTags = new Dynamic[META_COUNT];
outputMetas = new int[META_COUNT];
Arrays.fill(outputMetas, UNSPECIFIED_META);
}
metaDependentTags[meta] = toDynamic(metaDependentTag);
outputMetas[meta] = outputMeta;
}

/**
* Provides a conversion rule for a given metadata value
* @param meta Metadata to check the rule for
* @return Specific rule, or default if unspecified or out of range
*/
public Dynamic<?> getTagForMeta(int meta) {
if (metaDependentTags == null || isOutOfRange(meta)) {
return defaultTag;
}
Dynamic<?> tag = metaDependentTags[meta];
if (tag == null) {
return defaultTag;
}
return tag;
}

/**
* Replaces an old metadata value with a new one
* @param meta Old metadata to be replaced
* @return New metadata, or {@link #UNSPECIFIED_META} if unspecified or out of range
*/
public int getOutputMeta(int meta) {
if (outputMetas == null || isOutOfRange(meta)) {
return UNSPECIFIED_META;
}
return outputMetas[meta];
}

private static boolean isOutOfRange(int meta) {
return meta < 0 || meta >= META_COUNT;
}

private Dynamic<?> toDynamic(NbtCompound tag) {
return new Dynamic<>(NbtOps.INSTANCE, tag);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ public final class VanillaDataFixerImpl {
private static void registerFixer(DataFixerRegisterEvent event) {
DataFixers.registerFixer(NAMESPACE, executor -> {
DataFixerBuilder builder = new DataFixerBuilder(CURRENT_VERSION);
// This schema provides the conversion rules for everything found inside chunks:
// Entities, block entities, players, and items
Schema schema19132 = builder.addSchema(19132, McRegionSchemaB1_7_3::new);
Schema schema69420 = builder.addSchema(69420, StationFlatteningItemStackSchema::new);
builder.addFixer(new McRegionToStationFlatteningItemStackFix(schema69420, "McRegionToStationFlatteningItemStackFix"));
// This schema gets used for converting blocks from the standard Beta 1.7.3 world format
Schema schema69421 = builder.addSchema(69421, StationFlatteningChunkSchema::new);
builder.addFixer(new McRegionToStationFlatteningChunkFix(schema69421, "McRegionToStationFlatteningChunkFix"));
return builder.build().fixer();
Expand Down