minecraft-dotnet / Substrate

Comprehensive .NET SDK for reading and writing Minecraft worlds and data
http://code.google.com/p/substrate-minecraft/
MIT License
195 stars 70 forks source link

Level is no longer valid after player has first item in inventory. #35

Open apapdev007 opened 9 years ago

apapdev007 commented 9 years ago

I got the upgrade to Minecraft 1.8.4 and decided to start a new single player world. I have some custom utilities that use Substrate to read the map and after doing a few things in my new 1.8.4 world I tried to run these utilities, but NbtWorld.Open is returning null. After drilling down a bit from there I found that NbtValidator.Verify is the cause of the null. Several items in the world are failing the tests in NbtValidator.Verify(TagNode, TagNode, SchemaNode). Figuring my world had got corrupted somehow, I started a new one and it didn't have this issue, so I did some more debugging, set some break points, and looked at the items that were failing in the 1st new world. Upon doing this I noted that it was items that were in my chests and inventory that were failing. I went into that 2nd new 1.8.4 world that was passing the validation, broke a dirt block, picked it up, exited minecraft, and ran my utility again. Now the 2nd new world is failing validation just like the first. They have changed something about items that aren't located directly in the world and Substrate is no longer working. BTW, this was from a clone of the latest source.

syntap commented 9 years ago

I maintain a utility that maps signs in a world and can confirm similar issues. If I have any objects in inventory in a 1.8.n save, NbtWorld.Open will return null. If I create a 1.8.n world and save it without doing anything beyond moving a bit and saving (i.e. picking up nothing, doing nothing in the game aside from moving), NbtWorld.Open will return a value but iterating through chunks to hunt for my sign objects in my defined IChunkManager fails. I cloned latest source and verified that everything I described works fine in both a fresh no-inventory 1.7.10 world save and one with inventory.

redwyre commented 9 years ago

@syntap is it the validation that's failing in your example?

syntap commented 9 years ago

Hi @redwyre here's most if the relevant code I'm using to iterate through an assigned chunk and hopefully it will be helpful.

edit: to clarify a little, the below is with no inventory items, just create world, move, exit and save within Minecraft 1.8.n. So this may be a different 1.8 issue than the OP's issue. I'll need to re-run loading a world with inventory saved to confirm validation exceptions, I don't recall seeing validation exceptions in my case, only that NbtWorld.Open returned null. On to original comment...

... in my sample world, according to the chunk count I do for the progress bar it has 657 chunks in the ChunkManager. After getting to the eighth chunk (finding no TileEntitySigns in the process), int xdim = chunk.Blocks.XDim; below stops with a NullReferenceException. If I check the state of "chunk" at that line, "IsTerrainPopulated" is showing the NullReferenceException, with base showing {"Object reference not set to an instance of an object."}.

         // Load world based on selected path
        NbtWorld world = NbtWorld.Open(worldPath);
        IBlockManager bm = world.GetBlockManager();
        IChunkManager cm = world.GetChunkManager();

        // prep progress bar
        progressBar.Maximum = 0;  // 

        foreach (ChunkRef chunk in cm)
        {
            progressBar.Maximum++;  // gets to 657 in sample world
        }

        // iterate through all the chunks
        foreach (ChunkRef chunk in cm)
        {
            // get dimensions of world
            int xdim = chunk.Blocks.XDim;
            int ydim = chunk.Blocks.YDim;
            int zdim = chunk.Blocks.ZDim;

            // cycle through all blocks, list all signs
            for (int x = 0; x < xdim; x++)
            {
                string test = chunk.ToString();
                for (int z = 0; z < zdim; z++)
                {
                    for (int y = 0; y < ydim; y++)
                    {
                        TileEntitySign sign = chunk.Blocks.GetTileEntity(x, y, z) as TileEntitySign;
                        if (sign != null)
                        {  
                           //do stuff here with the found sign, no iterations got here in the test
                        }
                    }
                }
            }                

            // Increment progress bar
            progressBar.Value++;  // got to 8, so problem happened in 9th chunk
        }
DarkExceptionSoftware commented 1 year ago

In my case 'TagNodeCompound ctree' has no key for 'AttackTime'. i commented that key out and the level loads again.

Substrate 2.x branch, player.cs, line 367

// AttackTime = ctree["AttackTime"].ToTagShort();

i´m not sure about sideeffects happening after load/save, just making it work, so be carefull!

Found a post where this was discussed and people dont know that it ever exists... Maybe its a relief from beta?