234 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			234 lines
		
	
	
	
		
			8.7 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.util.datafix.fixes;
 | |
| 
 | |
| import com.google.common.base.Suppliers;
 | |
| import com.google.common.collect.ImmutableMap;
 | |
| import com.google.common.collect.ImmutableSet;
 | |
| import com.mojang.datafixers.DSL;
 | |
| import com.mojang.datafixers.DataFix;
 | |
| import com.mojang.datafixers.DataFixUtils;
 | |
| import com.mojang.datafixers.OpticFinder;
 | |
| import com.mojang.datafixers.TypeRewriteRule;
 | |
| import com.mojang.datafixers.Typed;
 | |
| import com.mojang.datafixers.schemas.Schema;
 | |
| import com.mojang.datafixers.types.Type;
 | |
| import com.mojang.datafixers.types.templates.List.ListType;
 | |
| import com.mojang.datafixers.util.Pair;
 | |
| import com.mojang.serialization.Dynamic;
 | |
| import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
 | |
| import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
 | |
| import java.util.Collections;
 | |
| import java.util.List;
 | |
| import java.util.Optional;
 | |
| import java.util.function.Function;
 | |
| import java.util.function.Supplier;
 | |
| import java.util.stream.Stream;
 | |
| import org.apache.commons.lang3.mutable.MutableInt;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| public class ChunkProtoTickListFix extends DataFix {
 | |
| 	private static final int SECTION_WIDTH = 16;
 | |
| 	private static final ImmutableSet<String> ALWAYS_WATERLOGGED = ImmutableSet.of(
 | |
| 		"minecraft:bubble_column", "minecraft:kelp", "minecraft:kelp_plant", "minecraft:seagrass", "minecraft:tall_seagrass"
 | |
| 	);
 | |
| 
 | |
| 	public ChunkProtoTickListFix(Schema outputSchema) {
 | |
| 		super(outputSchema, false);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected TypeRewriteRule makeRule() {
 | |
| 		Type<?> type = this.getInputSchema().getType(References.CHUNK);
 | |
| 		OpticFinder<?> opticFinder = type.findField("Level");
 | |
| 		OpticFinder<?> opticFinder2 = opticFinder.type().findField("Sections");
 | |
| 		OpticFinder<?> opticFinder3 = ((ListType)opticFinder2.type()).getElement().finder();
 | |
| 		OpticFinder<?> opticFinder4 = opticFinder3.type().findField("block_states");
 | |
| 		OpticFinder<?> opticFinder5 = opticFinder3.type().findField("biomes");
 | |
| 		OpticFinder<?> opticFinder6 = opticFinder4.type().findField("palette");
 | |
| 		OpticFinder<?> opticFinder7 = opticFinder.type().findField("TileTicks");
 | |
| 		return this.fixTypeEverywhereTyped(
 | |
| 			"ChunkProtoTickListFix",
 | |
| 			type,
 | |
| 			typed -> typed.updateTyped(
 | |
| 				opticFinder,
 | |
| 				typedx -> {
 | |
| 					typedx = typedx.update(
 | |
| 						DSL.remainderFinder(),
 | |
| 						dynamicx -> DataFixUtils.orElse(
 | |
| 							dynamicx.get("LiquidTicks").result().map(dynamic2x -> dynamicx.set("fluid_ticks", dynamic2x).remove("LiquidTicks")), dynamicx
 | |
| 						)
 | |
| 					);
 | |
| 					Dynamic<?> dynamic = typedx.get(DSL.remainderFinder());
 | |
| 					MutableInt mutableInt = new MutableInt();
 | |
| 					Int2ObjectMap<Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>> int2ObjectMap = new Int2ObjectArrayMap<>();
 | |
| 					typedx.getOptionalTyped(opticFinder2)
 | |
| 						.ifPresent(
 | |
| 							typedxx -> typedxx.getAllTyped(opticFinder3)
 | |
| 								.forEach(
 | |
| 									typedxxx -> {
 | |
| 										Dynamic<?> dynamicx = typedxxx.get(DSL.remainderFinder());
 | |
| 										int ix = dynamicx.get("Y").asInt(Integer.MAX_VALUE);
 | |
| 										if (ix != Integer.MAX_VALUE) {
 | |
| 											if (typedxxx.getOptionalTyped(opticFinder5).isPresent()) {
 | |
| 												mutableInt.setValue(Math.min(ix, mutableInt.getValue()));
 | |
| 											}
 | |
| 
 | |
| 											typedxxx.getOptionalTyped(opticFinder4)
 | |
| 												.ifPresent(
 | |
| 													typedxxxx -> int2ObjectMap.put(
 | |
| 														ix,
 | |
| 														Suppliers.memoize(
 | |
| 															() -> {
 | |
| 																List<? extends Dynamic<?>> list = (List<? extends Dynamic<?>>)typedxxxx.getOptionalTyped(opticFinder6)
 | |
| 																	.map(typedxxxxxx -> (List)typedxxxxxx.write().result().map(dynamicxx -> dynamicxx.asList(Function.identity())).orElse(Collections.emptyList()))
 | |
| 																	.orElse(Collections.emptyList());
 | |
| 																long[] ls = typedxxxx.get(DSL.remainderFinder()).get("data").asLongStream().toArray();
 | |
| 																return new ChunkProtoTickListFix.PoorMansPalettedContainer(list, ls);
 | |
| 															}
 | |
| 														)
 | |
| 													)
 | |
| 												);
 | |
| 										}
 | |
| 									}
 | |
| 								)
 | |
| 						);
 | |
| 					byte b = mutableInt.getValue().byteValue();
 | |
| 					typedx = typedx.update(DSL.remainderFinder(), dynamicx -> dynamicx.update("yPos", dynamicxx -> dynamicxx.createByte(b)));
 | |
| 					if (!typedx.getOptionalTyped(opticFinder7).isPresent() && !dynamic.get("fluid_ticks").result().isPresent()) {
 | |
| 						int i = dynamic.get("xPos").asInt(0);
 | |
| 						int j = dynamic.get("zPos").asInt(0);
 | |
| 						Dynamic<?> dynamic2 = this.makeTickList(dynamic, int2ObjectMap, b, i, j, "LiquidsToBeTicked", ChunkProtoTickListFix::getLiquid);
 | |
| 						Dynamic<?> dynamic3 = this.makeTickList(dynamic, int2ObjectMap, b, i, j, "ToBeTicked", ChunkProtoTickListFix::getBlock);
 | |
| 						Optional<? extends Pair<? extends Typed<?>, ?>> optional = opticFinder7.type().readTyped(dynamic3).result();
 | |
| 						if (optional.isPresent()) {
 | |
| 							typedx = typedx.set(opticFinder7, (Typed)((Pair)optional.get()).getFirst());
 | |
| 						}
 | |
| 
 | |
| 						return typedx.update(DSL.remainderFinder(), dynamic2x -> dynamic2x.remove("ToBeTicked").remove("LiquidsToBeTicked").set("fluid_ticks", dynamic2));
 | |
| 					} else {
 | |
| 						return typedx;
 | |
| 					}
 | |
| 				}
 | |
| 			)
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	private Dynamic<?> makeTickList(
 | |
| 		Dynamic<?> data,
 | |
| 		Int2ObjectMap<Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer>> palette,
 | |
| 		byte y,
 | |
| 		int x,
 | |
| 		int z,
 | |
| 		String name,
 | |
| 		Function<Dynamic<?>, String> idGetter
 | |
| 	) {
 | |
| 		Stream<Dynamic<?>> stream = Stream.empty();
 | |
| 		List<? extends Dynamic<?>> list = data.get(name).asList(Function.identity());
 | |
| 
 | |
| 		for (int i = 0; i < list.size(); i++) {
 | |
| 			int j = i + y;
 | |
| 			Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer> supplier = palette.get(j);
 | |
| 			Stream<? extends Dynamic<?>> stream2 = ((Dynamic)list.get(i))
 | |
| 				.asStream()
 | |
| 				.mapToInt(dynamic -> dynamic.asShort((short)-1))
 | |
| 				.filter(ix -> ix > 0)
 | |
| 				.mapToObj(l -> this.createTick(data, supplier, x, j, z, l, idGetter));
 | |
| 			stream = Stream.concat(stream, stream2);
 | |
| 		}
 | |
| 
 | |
| 		return data.createList(stream);
 | |
| 	}
 | |
| 
 | |
| 	private static String getBlock(@Nullable Dynamic<?> data) {
 | |
| 		return data != null ? data.get("Name").asString("minecraft:air") : "minecraft:air";
 | |
| 	}
 | |
| 
 | |
| 	private static String getLiquid(@Nullable Dynamic<?> data) {
 | |
| 		if (data == null) {
 | |
| 			return "minecraft:empty";
 | |
| 		} else {
 | |
| 			String string = data.get("Name").asString("");
 | |
| 			if ("minecraft:water".equals(string)) {
 | |
| 				return data.get("Properties").get("level").asInt(0) == 0 ? "minecraft:water" : "minecraft:flowing_water";
 | |
| 			} else if ("minecraft:lava".equals(string)) {
 | |
| 				return data.get("Properties").get("level").asInt(0) == 0 ? "minecraft:lava" : "minecraft:flowing_lava";
 | |
| 			} else {
 | |
| 				return !ALWAYS_WATERLOGGED.contains(string) && !data.get("Properties").get("waterlogged").asBoolean(false) ? "minecraft:empty" : "minecraft:water";
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private Dynamic<?> createTick(
 | |
| 		Dynamic<?> data,
 | |
| 		@Nullable Supplier<ChunkProtoTickListFix.PoorMansPalettedContainer> palette,
 | |
| 		int x,
 | |
| 		int y,
 | |
| 		int z,
 | |
| 		int index,
 | |
| 		Function<Dynamic<?>, String> idGetter
 | |
| 	) {
 | |
| 		int i = index & 15;
 | |
| 		int j = index >>> 4 & 15;
 | |
| 		int k = index >>> 8 & 15;
 | |
| 		String string = (String)idGetter.apply(palette != null ? ((ChunkProtoTickListFix.PoorMansPalettedContainer)palette.get()).get(i, j, k) : null);
 | |
| 		return data.createMap(
 | |
| 			ImmutableMap.builder()
 | |
| 				.put(data.createString("i"), data.createString(string))
 | |
| 				.put(data.createString("x"), data.createInt(x * 16 + i))
 | |
| 				.put(data.createString("y"), data.createInt(y * 16 + j))
 | |
| 				.put(data.createString("z"), data.createInt(z * 16 + k))
 | |
| 				.put(data.createString("t"), data.createInt(0))
 | |
| 				.put(data.createString("p"), data.createInt(0))
 | |
| 				.build()
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	public static final class PoorMansPalettedContainer {
 | |
| 		private static final long SIZE_BITS = 4L;
 | |
| 		private final List<? extends Dynamic<?>> palette;
 | |
| 		private final long[] data;
 | |
| 		private final int bits;
 | |
| 		private final long mask;
 | |
| 		private final int valuesPerLong;
 | |
| 
 | |
| 		public PoorMansPalettedContainer(List<? extends Dynamic<?>> palette, long[] data) {
 | |
| 			this.palette = palette;
 | |
| 			this.data = data;
 | |
| 			this.bits = Math.max(4, ChunkHeightAndBiomeFix.ceillog2(palette.size()));
 | |
| 			this.mask = (1L << this.bits) - 1L;
 | |
| 			this.valuesPerLong = (char)(64 / this.bits);
 | |
| 		}
 | |
| 
 | |
| 		@Nullable
 | |
| 		public Dynamic<?> get(int x, int y, int z) {
 | |
| 			int i = this.palette.size();
 | |
| 			if (i < 1) {
 | |
| 				return null;
 | |
| 			} else if (i == 1) {
 | |
| 				return (Dynamic<?>)this.palette.get(0);
 | |
| 			} else {
 | |
| 				int j = this.getIndex(x, y, z);
 | |
| 				int k = j / this.valuesPerLong;
 | |
| 				if (k >= 0 && k < this.data.length) {
 | |
| 					long l = this.data[k];
 | |
| 					int m = (j - k * this.valuesPerLong) * this.bits;
 | |
| 					int n = (int)(l >> m & this.mask);
 | |
| 					return n >= 0 && n < i ? (Dynamic)this.palette.get(n) : null;
 | |
| 				} else {
 | |
| 					return null;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private int getIndex(int x, int y, int z) {
 | |
| 			return (y << 4 | z) << 4 | x;
 | |
| 		}
 | |
| 
 | |
| 		public List<? extends Dynamic<?>> palette() {
 | |
| 			return this.palette;
 | |
| 		}
 | |
| 
 | |
| 		public long[] data() {
 | |
| 			return this.data;
 | |
| 		}
 | |
| 	}
 | |
| }
 |