Skip to content

Commit

Permalink
Merge pull request #497 from mircokroon/1.12.2-forge
Browse files Browse the repository at this point in the history
Support for Forge on 1.12.2
  • Loading branch information
mircokroon authored Mar 18, 2023
2 parents c6abccb + 1fb60e7 commit 49c5ba5
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 17 deletions.
14 changes: 14 additions & 0 deletions src/main/java/game/data/LevelData.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import game.data.coordinates.Coordinate3D;
import game.data.coordinates.CoordinateDouble3D;
import game.data.dimension.Dimension;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import se.llbit.nbt.*;
import util.NbtUtil;
import util.PathUtils;
Expand All @@ -27,10 +30,18 @@ public class LevelData {
private CompoundTag data;
private boolean savingBroken;


private List<Consumer<Tag>> levelDataModifiers;

public LevelData(WorldManager worldManager) {
this.worldManager = worldManager;
this.outputDir = PathUtils.toPath(Config.getWorldOutputDir());
this.file = Paths.get(outputDir.toString(), "level.dat").toFile();
this.levelDataModifiers = new ArrayList<>();
}

public void registerModifier(Consumer<Tag> fn) {
levelDataModifiers.add(fn);
}

public CoordinateDouble3D getPlayerPosition() {
Expand Down Expand Up @@ -162,6 +173,9 @@ public void save() throws IOException {
enableWorldGeneration(data);
}

// check for modifiers
levelDataModifiers.forEach(fn -> fn.accept(root));

// write the file
NbtUtil.write(root, file.toPath());
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/game/data/WorldManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;

import java.util.function.Consumer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

Expand Down Expand Up @@ -52,6 +53,8 @@
import packets.DataTypeProvider;
import packets.builder.PacketBuilder;
import proxy.PacketInjector;
import se.llbit.nbt.CompoundTag;
import se.llbit.nbt.Tag;
import util.PathUtils;

/**
Expand Down Expand Up @@ -105,6 +108,10 @@ public WorldManager() {
this.renderDistanceExtender = new RenderDistanceExtender(this);
}

public void registerLevelDataModifier(Consumer<Tag> fn) {
this.levelData.registerModifier(fn);
}

public static WorldManager getInstance() {
if (instance == null) {
instance = new WorldManager();
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/game/data/chunk/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import game.data.coordinates.CoordinateDim2D;
import game.data.dimension.Dimension;
import game.protocol.Protocol;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import packets.DataTypeProvider;
import packets.builder.PacketBuilder;
import se.llbit.nbt.*;
Expand All @@ -22,6 +24,11 @@
* Basic chunk class. May be extended by version-specific ones as they can have implementation differences.
*/
public abstract class Chunk extends ChunkEntities {
private static final List<BiConsumer<Chunk, Tag>> chunkNbtModifiers = new ArrayList<>();
public static void registerNbtModifier(BiConsumer<Chunk, Tag> fn) {
chunkNbtModifiers.add(fn);
}

public static final int SECTION_HEIGHT = 16;
public static final int SECTION_WIDTH = 16;
protected static final int LIGHT_SIZE = 2048;
Expand Down Expand Up @@ -207,6 +214,8 @@ public NamedTag toNbt() {
root.add("Level", createNbtLevel());
root.add("DataVersion", new IntTag(getDataVersion()));

chunkNbtModifiers.forEach(fn -> fn.accept(this, root));

return new NamedTag("", root);
}

Expand Down
6 changes: 5 additions & 1 deletion src/main/java/game/data/chunk/palette/BlockState.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public String getProperty(String name) {
return properties.get(name).stringValue();
}

CompoundTag getProperties() {
return properties;
}

public boolean isChest() {
return name.equals("minecraft:chest") || name.equals("minecraft:trapped_chest");
}
Expand Down Expand Up @@ -114,7 +118,7 @@ public String toString() {
return "BlockState{" +
"name='" + name + '\'' +
", id=" + id +
", properties=" + properties +
// ", properties=" + properties +
'}';
}
}
14 changes: 11 additions & 3 deletions src/main/java/game/data/chunk/palette/GlobalPalette.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ public GlobalPalette(InputStream input) {

CompoundTag properties = state.getProperties();

BlockState s = new BlockState(name, state.id, properties);
states.put(state.id, s);
nameStates.put(new BlockStateIdentifier(name, properties), s);
addBlockState(new BlockState(name, state.id, properties));
}));
}

Expand Down Expand Up @@ -84,6 +82,16 @@ public int getStateId(SpecificTag nbt) {
}
return state.getNumericId();
}

public void addBlockState(BlockState state) {
// skip existing states, these should be the same but might have different names
if (states.containsKey(state.getNumericId())) {
return;
}

states.put(state.getNumericId(), state);
nameStates.put(new BlockStateIdentifier(state.getName(), state.getProperties()), state);
}
}

class BlockStateIdentifier {
Expand Down
41 changes: 36 additions & 5 deletions src/main/java/game/data/chunk/palette/GlobalPaletteProvider.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package game.data.chunk.palette;

import config.Config;
import game.protocol.ProtocolVersionHandler;
import game.data.registries.RegistryLoader;
import game.protocol.Protocol;

import game.protocol.ProtocolVersionHandler;
import java.io.IOException;
import java.util.HashMap;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import se.llbit.nbt.CompoundTag;

/**
* This class manages the global palettes. It can hold not only a palette for the current game version, but also for
Expand All @@ -16,16 +18,19 @@ public final class GlobalPaletteProvider {
private GlobalPaletteProvider() { }

private static HashMap<Integer, GlobalPalette> palettes = new HashMap<>();
private static Queue<BlockState> uninitialised;

/**
* Retrieves a global palette based on the data version number. If the palette is not already known, it will be
* created through requestPalette.
*/
public static GlobalPalette getGlobalPalette(int dataVersion) {
if (palettes.containsKey(dataVersion)) {
return palettes.get(dataVersion);
GlobalPalette palette = palettes.get(dataVersion);

if (palette == null) {
return requestPalette(dataVersion);
}
return requestPalette(dataVersion);
return palette;
}

/**
Expand All @@ -45,10 +50,36 @@ private static GlobalPalette requestPalette(int dataVersion) {
try {
GlobalPalette p = RegistryLoader.forVersion(version.getVersion()).generateGlobalPalette();
palettes.put(dataVersion, p);

if (uninitialised != null) {
while (!uninitialised.isEmpty()) {
p.addBlockState(uninitialised.remove());
}
}
return p;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

public static void registerBlock(String name, int id) {
GlobalPalette palette = palettes.get(Config.getDataVersion());

BlockState state = new BlockState(name, id, new CompoundTag());

if (palette == null) {
enqueueBlock(state);
return;
}

palette.addBlockState(state);
}

private static void enqueueBlock(BlockState state) {
if (uninitialised == null) {
uninitialised = new ConcurrentLinkedDeque<>();
}
uninitialised.add(state);
}
}
30 changes: 26 additions & 4 deletions src/main/java/game/data/chunk/version/ChunkSection_1_12.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import game.data.chunk.palette.PaletteBuilder;
import game.data.coordinates.Coordinate3D;
import game.data.dimension.Dimension;
import java.util.Optional;
import javafx.util.Pair;
import packets.builder.PacketBuilder;
import se.llbit.nbt.ByteArrayTag;
import se.llbit.nbt.CompoundTag;
Expand Down Expand Up @@ -59,21 +61,41 @@ public void setBlocks(long[] blocks) {

@Override
protected void addNbtTags(CompoundTag map) {
map.add("Blocks", new ByteArrayTag(getBlockIds()));
Pair<byte[], Optional<byte[]>> blocks = getBlockIds();

map.add("Blocks", new ByteArrayTag(blocks.getKey()));
map.add("Data", new ByteArrayTag(getBlockStates()));

if (blocks.getValue().isPresent()) {
map.add("Add", new ByteArrayTag(blocks.getValue().get()));
}
}

private byte[] getBlockIds() {
private Pair<byte[], Optional<byte[]>> getBlockIds() {
byte[] blockData = new byte[4096];
byte[] additional = new byte[2048];
boolean hasAdditionalData = false;

for (int x = 0; x < 16; x++) {
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
blockData[getBlockIndex(x, y, z)] = (byte) (blockStates[x][y][z] >>> 4);
int blockState = blockStates[x][y][z] >>> 4;
int index = getBlockIndex(x, y, z);
blockData[index] = (byte) (blockState);

// excess data is packed into half a byte per block, for Forge
int excess = blockState >>> 8;
if (excess > 0) {
hasAdditionalData = true;

// if index is odd, shift by 4, otherwise leave unchanged
additional[index / 2] |= (byte) (excess << ((index % 2) * 4));;
}
}
}
}
return blockData;

return new Pair<>(blockData, hasAdditionalData ? Optional.of(additional) : Optional.empty());
}

private byte[] getBlockStates() {
Expand Down
Loading

0 comments on commit 49c5ba5

Please sign in to comment.