LB-- / MCModify

WIP Java/C++ library for dealing with Minecraft files.
The Unlicense
21 stars 10 forks source link

Can't edit any region except r.0.0.mca #5

Open PanierAvide opened 10 years ago

PanierAvide commented 10 years ago

Hello, I'm trying to edit chunks in different regions files (r.1.0.mca for example) but it doesn't seems to work. The edited chunks aren't rendered in Minecraft, meaning that they are probably incorrect. Here's a simple way to reproduce the bug :

Region from = new Region(new File(newWorld.toString()+File.separator+"region"+File.separator+"r.0.0.mca"));
Region to = new Region(new File(newWorld.toString()+File.separator+"region"+File.separator+"r.1.0.mca"));
Chunk ch = from.ReadChunk(0, 0);
Chunk chNew = new Chunk(ch.ToNBT(null).clone());
to.WriteChunk(0, 0, chNew);

Before executing this code, the region r.0.0.mca exists, the r.1.0.mca doesn't. The selected chunk was generated in Minecraft and is working. Making a simple copy without any edit makes the same chunk in the other region not work. However, it's possible to edit chunks in the region r.0.0.mca without problems. I'm using Minecraft 1.6.4 under Linux.

Regards.

LB-- commented 10 years ago

I won't have time to debug this until the weekend, but I'm pretty sure that even renaming a completely natural region file won't even work - entity coordinates will be incorrect, etc. However I'm not exactly sure why. I also don't think .clone() is implemented properly in my code, can you replicate the bug without using .clone()?

PanierAvide commented 10 years ago

It does the same by not using clone(). I will continue my investigation and focus on entity coordinates. Thanks for your support.

PanierAvide commented 10 years ago

I found it : Chunk position isn't limited between 0 and 31, it has to be the absolute coordinates of Chunk in the whole world, not in the region file. So to edit the Chunk at (0,0) in r.1.0.mca, the Chunk position should be (32,0) in data. So you need to remove conditions in Chunk.java :

public void Pos(int x, int z) /*throws IllegalArgumentException*/
{
//  if(x < 0 || x > 31
//  || z < 0 || z > 31)
//  {
//      throw new IllegalArgumentException("Invalid Chunk Coordinates: ("+x+", "+z+")");
//  }
    xpos = x;
    zpos = z;
}

And that will work :) You may want to check that coordinates are correct when calling Region.WriteChunk :

public void WriteChunk(int X, int Z, Chunk c) throws IOException, IllegalArgumentException
{
    try(RandomAccessFile region = new RandomAccessFile(rf, "rw"))
    {
        final int index = ((X%32) + (Z%32)*32);
        if(c == null)
        {
            OffSect(region, index, -SectorOffset, 0);
            return;
        }
        int chunkXinReg = (c.PosX() >= 0) ? c.PosX() % 32 : 32 - Math.abs(c.PosX()%32);
        int chunkZinReg = (c.PosZ() >= 0) ? c.PosZ() % 32 : 32 - Math.abs(c.PosZ()%32);
        if(chunkXinReg != X || chunkZinReg != Z) {
            throw new IllegalArgumentException("Invalid Chunk Coordinates ("+c.PosX()+", "+c.PosZ()+") regarding to Chunk position ("+X+", "+Z+")");
        }
        int chunksize, newsectors;
        ByteBuffer chunkbytes;
[...]

This test could be improved by testing if chunk coordinates are good compared to region position. Regards.

LB-- commented 10 years ago

Hm, I think I will change it so the chunk class doesn't even store the X and Y coordinates at all. I had no idea Minecraft even used them anymore, it seems pretty pointless. To ensure it's always fine I'll have the Region class handle the X and Y coords from now on. But I will have to figure out how to make the region aware what its coordinates are...