LeavesFix.java
net.minecraft.util.datafix.fixes.LeavesFix
信息
- 全限定名:net.minecraft.util.datafix.fixes.LeavesFix
- 类型:public class
- 包:net.minecraft.util.datafix.fixes
- 源码路径:src/main/java/net/minecraft/util/datafix/fixes/LeavesFix.java
- 起始行号:L35
- 继承:DataFix
- 职责:
TODO
字段/常量
-
NORTH_WEST_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L36 - 说明:
TODO
- 类型:
-
WEST_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L37 - 说明:
TODO
- 类型:
-
SOUTH_WEST_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L38 - 说明:
TODO
- 类型:
-
SOUTH_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L39 - 说明:
TODO
- 类型:
-
SOUTH_EAST_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L40 - 说明:
TODO
- 类型:
-
EAST_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L41 - 说明:
TODO
- 类型:
-
NORTH_EAST_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L42 - 说明:
TODO
- 类型:
-
NORTH_MASK- 类型:
int - 修饰符:
private static final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
DIRECTIONS- 类型:
int[][] - 修饰符:
private static final - 源码定位:
L44 - 说明:
TODO
- 类型:
-
DECAY_DISTANCE- 类型:
int - 修饰符:
private static final - 源码定位:
L45 - 说明:
TODO
- 类型:
-
SIZE_BITS- 类型:
int - 修饰符:
private static final - 源码定位:
L46 - 说明:
TODO
- 类型:
-
SIZE- 类型:
int - 修饰符:
private static final - 源码定位:
L47 - 说明:
TODO
- 类型:
-
LEAVES- 类型:
Object2IntMap<String> - 修饰符:
private static final - 源码定位:
L48 - 说明:
TODO
- 类型:
-
LOGS- 类型:
Set<String> - 修饰符:
private static final - 源码定位:
L56 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.util.datafix.fixes.LeavesFix.LeavesSection- 类型:
class - 修饰符:
public static final - 源码定位:
L230 - 说明:
TODO
- 类型:
-
net.minecraft.util.datafix.fixes.LeavesFix.Section- 类型:
class - 修饰符:
public abstract static - 源码定位:
L314 - 说明:
TODO
- 类型:
构造器
public LeavesFix(Schema outputSchema, boolean changesType) @ L77
- 构造器名:LeavesFix
- 源码定位:L77
- 修饰符:public
参数:
- outputSchema: Schema
- changesType: boolean
说明:
TODO
方法
下面的方法块按源码顺序生成。
protected TypeRewriteRule makeRule() @ L81
- 方法名:makeRule
- 源码定位:L81
- 返回类型:TypeRewriteRule
- 修饰符:protected
参数:
- 无
说明:
TODO
public static int getIndex(int x, int y, int z) @ L187
- 方法名:getIndex
- 源码定位:L187
- 返回类型:int
- 修饰符:public static
参数:
- x: int
- y: int
- z: int
说明:
TODO
private int getX(int index) @ L191
- 方法名:getX
- 源码定位:L191
- 返回类型:int
- 修饰符:private
参数:
- index: int
说明:
TODO
private int getY(int index) @ L195
- 方法名:getY
- 源码定位:L195
- 返回类型:int
- 修饰符:private
参数:
- index: int
说明:
TODO
private int getZ(int index) @ L199
- 方法名:getZ
- 源码定位:L199
- 返回类型:int
- 修饰符:private
参数:
- index: int
说明:
TODO
public static int getSideMask(boolean west, boolean east, boolean north, boolean south) @ L203
- 方法名:getSideMask
- 源码定位:L203
- 返回类型:int
- 修饰符:public static
参数:
- west: boolean
- east: boolean
- north: boolean
- south: boolean
说明:
TODO
代码
public class LeavesFix extends DataFix {
private static final int NORTH_WEST_MASK = 128;
private static final int WEST_MASK = 64;
private static final int SOUTH_WEST_MASK = 32;
private static final int SOUTH_MASK = 16;
private static final int SOUTH_EAST_MASK = 8;
private static final int EAST_MASK = 4;
private static final int NORTH_EAST_MASK = 2;
private static final int NORTH_MASK = 1;
private static final int[][] DIRECTIONS = new int[][]{{-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
private static final int DECAY_DISTANCE = 7;
private static final int SIZE_BITS = 12;
private static final int SIZE = 4096;
private static final Object2IntMap<String> LEAVES = DataFixUtils.make(new Object2IntOpenHashMap<>(), map -> {
map.put("minecraft:acacia_leaves", 0);
map.put("minecraft:birch_leaves", 1);
map.put("minecraft:dark_oak_leaves", 2);
map.put("minecraft:jungle_leaves", 3);
map.put("minecraft:oak_leaves", 4);
map.put("minecraft:spruce_leaves", 5);
});
private static final Set<String> LOGS = ImmutableSet.of(
"minecraft:acacia_bark",
"minecraft:birch_bark",
"minecraft:dark_oak_bark",
"minecraft:jungle_bark",
"minecraft:oak_bark",
"minecraft:spruce_bark",
"minecraft:acacia_log",
"minecraft:birch_log",
"minecraft:dark_oak_log",
"minecraft:jungle_log",
"minecraft:oak_log",
"minecraft:spruce_log",
"minecraft:stripped_acacia_log",
"minecraft:stripped_birch_log",
"minecraft:stripped_dark_oak_log",
"minecraft:stripped_jungle_log",
"minecraft:stripped_oak_log",
"minecraft:stripped_spruce_log"
);
public LeavesFix(Schema outputSchema, boolean changesType) {
super(outputSchema, changesType);
}
@Override
protected TypeRewriteRule makeRule() {
Type<?> chunkType = this.getInputSchema().getType(References.CHUNK);
OpticFinder<?> levelFinder = chunkType.findField("Level");
OpticFinder<?> sectionsFinder = levelFinder.type().findField("Sections");
Type<?> sectionsType = sectionsFinder.type();
if (!(sectionsType instanceof ListType)) {
throw new IllegalStateException("Expecting sections to be a list.");
} else {
Type<?> sectionType = ((ListType)sectionsType).getElement();
OpticFinder<?> sectionFinder = DSL.typeFinder(sectionType);
return this.fixTypeEverywhereTyped(
"Leaves fix",
chunkType,
chunk -> chunk.updateTyped(
levelFinder,
level -> {
int[] sides = new int[]{0};
Typed<?> newLevel = level.updateTyped(
sectionsFinder,
sections -> {
Int2ObjectMap<LeavesFix.LeavesSection> sectionMap = new Int2ObjectOpenHashMap<>(
sections.getAllTyped(sectionFinder)
.stream()
.map(sectionx -> new LeavesFix.LeavesSection(sectionx, this.getInputSchema()))
.collect(Collectors.toMap(LeavesFix.Section::getIndex, s -> (LeavesFix.LeavesSection)s))
);
if (sectionMap.values().stream().allMatch(LeavesFix.Section::isSkippable)) {
return sections;
} else {
List<IntSet> queue = Lists.newArrayList();
for (int i = 0; i < 7; i++) {
queue.add(new IntOpenHashSet());
}
for (LeavesFix.LeavesSection section : sectionMap.values()) {
if (!section.isSkippable()) {
for (int i = 0; i < 4096; i++) {
int block = section.getBlock(i);
if (section.isLog(block)) {
queue.get(0).add(section.getIndex() << 12 | i);
} else if (section.isLeaf(block)) {
int x = this.getX(i);
int z = this.getZ(i);
sides[0] |= getSideMask(x == 0, x == 15, z == 0, z == 15);
}
}
}
}
for (int ix = 1; ix < 7; ix++) {
IntSet set = queue.get(ix - 1);
IntSet newSet = queue.get(ix);
IntIterator iterator = set.iterator();
while (iterator.hasNext()) {
int posChunk = iterator.nextInt();
int x = this.getX(posChunk);
int y = this.getY(posChunk);
int z = this.getZ(posChunk);
for (int[] direction : DIRECTIONS) {
int nx = x + direction[0];
int nyChunk = y + direction[1];
int nz = z + direction[2];
if (nx >= 0 && nx <= 15 && nz >= 0 && nz <= 15 && nyChunk >= 0 && nyChunk <= 255) {
LeavesFix.LeavesSection sectionx = sectionMap.get(nyChunk >> 4);
if (sectionx != null && !sectionx.isSkippable()) {
int posSection = getIndex(nx, nyChunk & 15, nz);
int block = sectionx.getBlock(posSection);
if (sectionx.isLeaf(block)) {
int oldDistance = sectionx.getDistance(block);
if (oldDistance > ix) {
sectionx.setDistance(posSection, block, ix);
newSet.add(getIndex(nx, nyChunk, nz));
}
}
}
}
}
}
}
return sections.updateTyped(
sectionFinder, sectionx -> sectionMap.get(sectionx.get(DSL.remainderFinder()).get("Y").asInt(0)).write(sectionx)
);
}
}
);
if (sides[0] != 0) {
newLevel = newLevel.update(DSL.remainderFinder(), tag -> {
Dynamic<?> upgradeData = DataFixUtils.orElse(tag.get("UpgradeData").result(), tag.emptyMap());
return tag.set(
"UpgradeData", upgradeData.set("Sides", tag.createByte((byte)(upgradeData.get("Sides").asByte((byte)0) | sides[0])))
);
});
}
return newLevel;
}
)
);
}
}
public static int getIndex(int x, int y, int z) {
return y << 8 | z << 4 | x;
}
private int getX(int index) {
return index & 15;
}
private int getY(int index) {
return index >> 8 & 0xFF;
}
private int getZ(int index) {
return index >> 4 & 15;
}
public static int getSideMask(boolean west, boolean east, boolean north, boolean south) {
int s = 0;
if (north) {
if (east) {
s |= 2;
} else if (west) {
s |= 128;
} else {
s |= 1;
}
} else if (south) {
if (west) {
s |= 32;
} else if (east) {
s |= 8;
} else {
s |= 16;
}
} else if (east) {
s |= 4;
} else if (west) {
s |= 64;
}
return s;
}
public static final class LeavesSection extends LeavesFix.Section {
private static final String PERSISTENT = "persistent";
private static final String DECAYABLE = "decayable";
private static final String DISTANCE = "distance";
private @Nullable IntSet leaveIds;
private @Nullable IntSet logIds;
private @Nullable Int2IntMap stateToIdMap;
public LeavesSection(Typed<?> section, Schema inputSchema) {
super(section, inputSchema);
}
@Override
protected boolean skippable() {
this.leaveIds = new IntOpenHashSet();
this.logIds = new IntOpenHashSet();
this.stateToIdMap = new Int2IntOpenHashMap();
for (int i = 0; i < this.palette.size(); i++) {
Dynamic<?> paletteTag = this.palette.get(i);
String blockName = paletteTag.get("Name").asString("");
if (LeavesFix.LEAVES.containsKey(blockName)) {
boolean persistent = Objects.equals(paletteTag.get("Properties").get("decayable").asString(""), "false");
this.leaveIds.add(i);
this.stateToIdMap.put(this.getStateId(blockName, persistent, 7), i);
this.palette.set(i, this.makeLeafTag(paletteTag, blockName, persistent, 7));
}
if (LeavesFix.LOGS.contains(blockName)) {
this.logIds.add(i);
}
}
return this.leaveIds.isEmpty() && this.logIds.isEmpty();
}
private Dynamic<?> makeLeafTag(Dynamic<?> input, String blockName, boolean persistent, int distance) {
Dynamic<?> properties = input.emptyMap();
properties = properties.set("persistent", properties.createString(persistent ? "true" : "false"));
properties = properties.set("distance", properties.createString(Integer.toString(distance)));
Dynamic<?> tag = input.emptyMap();
tag = tag.set("Properties", properties);
return tag.set("Name", tag.createString(blockName));
}
public boolean isLog(int block) {
return this.logIds.contains(block);
}
public boolean isLeaf(int block) {
return this.leaveIds.contains(block);
}
private int getDistance(int block) {
return this.isLog(block) ? 0 : Integer.parseInt(this.palette.get(block).get("Properties").get("distance").asString(""));
}
private void setDistance(int pos, int block, int distance) {
Dynamic<?> baseTag = this.palette.get(block);
String blockName = baseTag.get("Name").asString("");
boolean persistent = Objects.equals(baseTag.get("Properties").get("persistent").asString(""), "true");
int stateId = this.getStateId(blockName, persistent, distance);
if (!this.stateToIdMap.containsKey(stateId)) {
int id = this.palette.size();
this.leaveIds.add(id);
this.stateToIdMap.put(stateId, id);
this.palette.add(this.makeLeafTag(baseTag, blockName, persistent, distance));
}
int id = this.stateToIdMap.get(stateId);
if (1 << this.storage.getBits() <= id) {
PackedBitStorage newStorage = new PackedBitStorage(this.storage.getBits() + 1, 4096);
for (int i = 0; i < 4096; i++) {
newStorage.set(i, this.storage.get(i));
}
this.storage = newStorage;
}
this.storage.set(pos, id);
}
}
public abstract static class Section {
protected static final String BLOCK_STATES_TAG = "BlockStates";
protected static final String NAME_TAG = "Name";
protected static final String PROPERTIES_TAG = "Properties";
private final Type<Pair<String, Dynamic<?>>> blockStateType = DSL.named(References.BLOCK_STATE.typeName(), DSL.remainderType());
protected final OpticFinder<List<Pair<String, Dynamic<?>>>> paletteFinder = DSL.fieldFinder("Palette", DSL.list(this.blockStateType));
protected final List<Dynamic<?>> palette;
protected final int index;
protected @Nullable PackedBitStorage storage;
public Section(Typed<?> section, Schema inputSchema) {
if (!Objects.equals(inputSchema.getType(References.BLOCK_STATE), this.blockStateType)) {
throw new IllegalStateException("Block state type is not what was expected.");
} else {
Optional<List<Pair<String, Dynamic<?>>>> typedPalette = section.getOptional(this.paletteFinder);
this.palette = typedPalette.<List>map(p -> p.stream().map(Pair::getSecond).collect(Collectors.toList())).orElse(ImmutableList.of());
Dynamic<?> tag = section.get(DSL.remainderFinder());
this.index = tag.get("Y").asInt(0);
this.readStorage(tag);
}
}
protected void readStorage(Dynamic<?> tag) {
if (this.skippable()) {
this.storage = null;
} else {
long[] states = tag.get("BlockStates").asLongStream().toArray();
int size = Math.max(4, DataFixUtils.ceillog2(this.palette.size()));
this.storage = new PackedBitStorage(size, 4096, states);
}
}
public Typed<?> write(Typed<?> section) {
return this.isSkippable()
? section
: section.update(DSL.remainderFinder(), tag -> tag.set("BlockStates", tag.createLongList(Arrays.stream(this.storage.getRaw()))))
.set(this.paletteFinder, this.palette.stream().<Pair<String,Dynamic<?>>>map(b -> Pair.of(References.BLOCK_STATE.typeName(), b)).collect(Collectors.toList()));
}
public boolean isSkippable() {
return this.storage == null;
}
public int getBlock(int pos) {
return this.storage.get(pos);
}
protected int getStateId(String blockName, boolean persistent, int distance) {
return LeavesFix.LEAVES.get(blockName) << 5 | (persistent ? 16 : 0) | distance;
}
int getIndex() {
return this.index;
}
protected abstract boolean skippable();
}
}引用的其他类
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
PackedBitStorage()
- 引用位置: