Substrate is a .NET/Mono SDK written in C# for reading, writing, and manipulating data in Minecraft worlds. Substrate isolates the different levels of map data such as blocks, chunks, and regions, and natively supports modifying Alpha and Beta worlds using the same block and chunk interfaces. Substrate also provides interfaces for other data such as Entities, players, and general level data.
--- Requirements
Substrate requires .NET Framework 2.0 or higher, or Mono, to run. Compiling Substrate source code requires a compiler that supports C# 3.0 or higher (Visual C# 2008 Express or higher, or comparable Linux tools).
For convenience to developers, Substrate ships with separate .NET-2.0 and .NET-4.0 assemblies, so that you can include the assembly that best matches your application's target framework.
If you are interested in the development of Substrate, follow or fork the project on the Github Project Page
--- Additional Information
See the Introduction wiki page for more information on important classes provided by Substrate: Introduction
Largely complete API documentation is included with the Substrate download. A number of example projects are also included in the download, and available in the source tree.
Substrate is provided under the permissive MIT license. If you find this project useful in your software, consider mentioning it in the credits or about box of your application, but this is not required.
Of course, any feedback, ideas, bug reports, etc. are welcome either in this thread, or on the project page.
--- Examples
using System;
using Substrate;
// This example replaces all instances of one block ID with another in a world.
// Substrate will handle all of the lower-level headaches that can pop up, such
// as maintaining correct lighting or replacing TileEntity records for blocks
// that need them.
// For a more advanced Block Replace example, see replace.cs in NBToolkit.
namespace BlockReplace
{
class Program
{
static void Main (string[] args)
{
if (args.Length != 3) {
Console.WriteLine("Usage: BlockReplace &--#60;world&--#62; &--#60;before-id&--#62; &--#60;after-id&--#62;");
return;
}
string dest = args[0];
int before = Convert.ToInt32(args[1]);
int after = Convert.ToInt32(args[2]);
// Open our world
BetaWorld world = BetaWorld.Open(dest);
// The chunk manager is more efficient than the block manager for
// this purpose, since we'll inspect every block
BetaChunkManager cm = world.GetChunkManager();
foreach (ChunkRef chunk in cm) {
// You could hardcode your dimensions, but maybe some day they
// won't always be 16. Also the CLR is a bit stupid and has
// trouble optimizing repeated calls to Chunk.Blocks.xx, so we
// cache them in locals
int xdim = chunk.Blocks.XDim;
int ydim = chunk.Blocks.YDim;
int zdim = chunk.Blocks.ZDim;
// x, z, y is the most efficient order to scan blocks (not that
// you should care about internal detail)
for (int x = 0; x &--#60; xdim; x++) {
for (int z = 0; z &--#60; zdim; z++) {
for (int y = 0; y &--#60; ydim; y++) {
// Replace the block with after if it matches before
if (chunk.Blocks.GetID(x, y, z) == before) {
chunk.Blocks.SetData(x, y, z, 0);
chunk.Blocks.SetID(x, y, z, after);
}
}
}
}
// Save the chunk
cm.Save();
}
}
}
}
--- Projects Using Substrate
- NBTExplorer - A graphical NBT data editor.
- MACE - Random cities generator.
- Teeth of Time - Simulates effects of weather and time on worlds.
- Eedit - A simple graphical editor for item enchantments.
- Avanti! - A Paint-like Minecraft world editor.
- SeeSharp - A Minecraft map exporter / renderer.
If you've published a tool using Substrate and would like it listed, post your request.
--- Update History
[1.3.8]
- Fix: Item enchantments no longer reset on tree load.
- Fix: TagNodeString will now accept null values.
- Fix: Casing error in 'playerGameType' tag.
- Fix: Initialize Source properties in INbtObjects.
- Fix: Region Loader no longer tries to pad out non-4KB-aligned files.
- Fix: Setters in FusedDataArray.
- Fix: Crash when parsing TAG_END in an NBT List type.
- Internalized Ionic.Zlib.
- Updated item and block info for MC 1.5 and 1.6.
- World classes now accept dimensions specified as strings.
- Allow setting TileEntity data on blocks not registered as Tile Entities.
- Regions are now sorted by y,x coordinates on enumeration (contrib. by Sukasa).
- Added support for GeneratorName setting (contrib. by cry-inc).
- Added many more attributes to Level (contrib. by snoopen).
[1.3.7]
- Fix: Wrong tag name for additional block IDs ("AddBlocks" instead of "Add")
- Fix: Anvil worlds can now handle block IDs >255
- Fix: Empty chunk sections below heightmap were not written
- Fix: NBT Tree discarding root node name on load
- Fix: Various Entity and TileEntity issues
- Raw NBT tree exposed on more objects (Entities, TileEntities, Items...)
- Generic TileEntity objects will be created if specific types are unknown
- Region files multithread safe
- MobSpawnerTileEntities have updated data fields
[1.3.6]
- Fix: Bug in index calculations of Anvil composite byte/nibble arrays, causing incorrect block updates.
- Block updates for Minecraft 1.4.
[1.3.5]
- Minor changes to RegionFile to make it easier to extend (e.g. for Cubic Chunks). (not released)
[1.3.4]
- Fix: Bug in unicode handling of NBT strings which could result in inconsistent NBT binaries being written.
[1.3.3]
- Fix: Bug in player loading that could cause Anvil 1.2 worlds to not load. Was introduced in 1.3.2.
[1.3.2]
- Fix: ChunkManager.SetChunk did not set chunks at the requested location correctly.
- Fix: ResetLava in BlockFluid could possibly convert lava blocks into water.
- Fix: BlockManager could not set blocks above 127. BlockManager is now abstract and split into two concrete classes for Alpha and Anvil.
- Block, item, and player data updates for Minecraft 1.3.
[1.3.1]
- Fixes bug in chunk creation causing the Z coordinate to be used for both X and Z.
[1.3.0]
- Unified Anvil map support
- Multiple breaking changes for Anvil support
- Block and item updates through Minecraft 1.2
[1.2.0]
- Anvil beta (not officially released)
[1.1.0]
- Adds TileTick management throughout most of the API
- AutoTileTick property in AlphaBlockCollection for automatically managing TileTicks.
[1.0.3]
- Fixes a bug where clearing the player spawn would have no effect
- Fixes a bug where deleting a chunk would correctly update the cache, resulting in lost work
[1.0.2]
- Fixes a bug reading items with enchantments
- Fixes a bug enumerating entities not registered with EntityFactory
- Fixes a bug setting text on sign TileEntities
- Exposes more direct access to the Chunk cache
[1.0.1]
- Fixes a serious bug where entities were written out with invalid data, causing chunk regeneration
- Several block data enums where updated with fixes
- Animal entity types are now subclasses of EntityAnimal
[1.0.0]
- Ionic.Zlib integrated into the Substrate assembly
- Project split into .NET2/.NET4 output
- Added full Enchantment API for items
- Player and Mob classes updated with additional data
- Entity/TileEntity registires are enumerable
- ChangeValueType added to TagNodeList class
[0.9.0]
- Data resource / map (item) editing
- Conversion utilities for map editing
- NbtFile updated to handle differing compression requirements
[0.8.4]
- Fixes TileEntity data not being copied with chunks
- Unknown/Nonstandard NBT tags are now round-tripped in most objects
[0.8.3]
- Fixes painting entities not being updated correctly when their chunk is relocated
- Entities and TileEntities support MoveBy method for special relocation handling
[0.8.2]
- Fixes a bug where Entity/TileEntity coordinates were not updated with chunk
[0.8.1]
- Fixes a bug where chunk modified chunk coordinates are not saved
[0.8.0]
- 1.9pre5 block, item, and entity types
- Fixed several bugs in Entities, including an exception caused by Enderman
- Entity/TileEntity architecture updated to support inheritance, avoid future bugs
- Optional cache size parameter in OpenWorld/CreateWorld
[0.7.3]
- Fixed crash when encountering XPOrb while enumerating entities
[0.7.2]
- 1.8 Entity types
- Added missing properties to Arrow and all Mob entities
- Fixed lighting bug with Chest blocks
[0.7.1]
- 1.8 Block and Item types
[0.7.0]
- Major refactoring. You will need to tweak your projects
- CHM documentation for most of the common APIs
- Intellisense XML file for the same
- 1.7 Block and Item types
- Schematic import and export support
- CLS Compliance
- Enumerable PlayerManager
- Timestamp data exposed
- NBT Validator event support
- Numerous bugfixes including cache and TileEntity bugs
[0.6.2]
- Fixes bugs with some entities and tile entities
[0.6.1]
- Fixes bug with TileEntity updates
[0.6.0]
- Added fluid simulation for water and lava
- AutoFluid property (disabled by default)
[0.5.2]
- Lighting bugfixes and performance improvements
- TileEntity fixes
- Beta 1.6 block and item types
- 'State' property to BlockInfo (solid/nonsolid/fluid)
- Chunk copying / setting
- ItemInfo classes and supporting data enums
- Re-exposed the PlayerManager
- All missing examples added
[0.5.1]
- Numerous lighting fixes including possible crashing bug
- Added Beta 1.5 level attributes
[0.5.0]
- Major refactoring of Chunk/ChunkRef breaks compatibility, but should be easy to repair
- Fixes missing Player attributes and bug in level.dat generation
- Fixes more lighting bugs. Now correctly lights half steps, stairs, and other special blocks
- Updated chunk caching back-end
[0.4.1]
- Lighting fixes for manual chunk relighting
- Performance fixes for lighting
[0.4.0]
- Fixes cache consistency bug, among others
- Adds manual chunk relighting
- Example code
[0.3.0]
- Adds automatic blocklight and skylight recalculation for all setblockid operations via ChunkRefs or the BlockManager.
[0.2.1]
- Fixes serious bug in creating TileEntity or Entity objects.
Yeah there's still some changes going on. I ripped these examples out of NBToolkit before I had it running correctly on the library. I'm actually working on a small set of complete, standalone, fully tested examples to include with the next release (such as block replace, world conversion, map generation, inventory editing, etc).
In the example code, change IBlockManager blockm to BlockManager blockm (actually, I don't think I ever used IBlockManager directly in that code?).
Due to changes in the interface hierarchy, directly using IBlockManager doesn't make sense anymore unless you're requesting an IBlock (which exposes access to ID and data fields, nothing else). This might come into play if I write in a support class for mcschema files or creative classic files, although for the later I need Java interop support so maybe that won't happen. This part of the design is still under review.
If you think something is overly weird or difficult to use, please mention it. I'll try to either justify it or come up with something different. If you would like something explained in more detail, I can also do that.
BlockManager bm = world.BlockManager as BlockManager
I'm missing a couple overrides in the alpha block container interface, once I put them in place the cast should not be necessary anymore.
Relighting is .. interesting. I don't really have an easy solution for it but it's next on my list of things to tackle. But as a general idea, you could do an initial sweep of a chunk you modified, and make sure that any block with a luminosity value greater than 0 (can be checked in each block's blockinfo) is set to that light level. Then repeatedly sweep through the chunk looking for blocks that are not set to max-1 of all the neighbor's light values, and update them. Repeat the process until the chunk converges. Edge cases may be tricky as you'll need to inspect neighboring chunks as well. This is one task that can't easily be accomplished with a global block view because of memory constraints, unless you want to thrash your disk.
The crash occurred on chests, furnaces, and similar because they have TileEntities attached. The routines to update block IDs automatically enforce TileEntity consistency, so if you create a furnace, it will create a reasonable default TileEntity record for it as well. Likewise when you change it back to cobblestone, the records will be removed.
You can also update TileEntities if, for example, you wanted to fill the new chest block with some items.
I'm probably not going to package another release for a couple days, unless it's another bugfix.
However, if you don't mind grabbing the source tree, I committed some block relighting code. Calling SetBlockID on a ChunkRef will immediately recalculate blocklight (but currently, not skylight). Actually, since BlockRef uses ChunkRefs, it will probably recalculate light as well. Eventually I will include some way of toggling this behavior, since realtime lighting recalculation will be too expensive for some use patterns.
There's still some problems calculating light past region boundaries. That will get patched later.
This fully incorporates automatic blocklight and sunlight recalculation whenever a block is updated. It seems to do a pretty good job, but it's possible that it violates some of the lighting rules. If you can identify a lighting pattern that occurs in Minecraft but is not faithfully reproduced by Substrate, please post a picture of it.
Great to hear. I was pleasantly surprised by how well it performs for general purpose tasks. However as I predicted, it's a disaster for map generation. So in recent pushes to the source tree (no new packaged downloads yet), auto-relighting can be toggled on a per-chunkref basis, and there are new methods to manually relight a chunk in one pass. The improvement for generating chunks from scratch (at least, simple flatland-style chunks) is at least 20-30x.
I've also pushed the first purpose-built, well-commented example, generating a flat map. On a powerful workstation, this generated 1600 solid, lit chunks in under 10 seconds. Of course, it represents a lower bound.
(Note, the API for World objects has been changed)
using System;
using Substrate;
// FlatMap is an example of generating worlds from scratch with Substrate.
// It will produce a completely flat, solid map with grass, dirt, stone,
// and bedrock layers. On a powerful workstation, creating 400 of these
// chunks only takes a few seconds.
namespace FlatMap
{
class Program
{
static void Main (string[] args)
{
string dest = "F:\\Minecraft\\test";
int xmin = -20;
int xmax = 20;
int zmin = -20;
int zmaz = 20;
// This will instantly create any necessary directory structure
BetaWorld world = BetaWorld.Create(dest);
ChunkManager cm = world.GetChunkManager();
// We can set different world parameters
world.Level.LevelName = "Flatlands";
world.Level.SetDefaultPlayer();
// We'll create chunks at chunk coordinates xmin,zmin to xmax,zmax
for (int xi = xmin; xi < xmax; xi++) {
for (int zi = zmin; zi < zmaz; zi++) {
// This line will create a default empty chunk, and create a
// backing region file if necessary (which will immediately be
// written to disk)
ChunkRef chunk = cm.CreateChunk(xi, zi);
// This will suppress generating caves, ores, and all those
// other goodies.
chunk.IsTerrainPopulated = true;
// Auto light recalculation is horrifically bad for creating
// chunks from scratch, because we're placing thousands
// of blocks. Turn it off.
chunk.AutoRecalcLight = false;
// Set the blocks
FlatChunk(chunk, 64);
// Reset and rebuild the lighting for the entire chunk at once
chunk.RebuildBlockLight();
chunk.RebuildSkyLight();
Console.WriteLine("Built Chunk {0},{1}", chunk.X, chunk.Z);
// Save the chunk to disk so it doesn't hang around in RAM
cm.Save();
}
}
// Save all remaining data (including a default level.dat)
// If we didn't save chunks earlier, they would be saved here
world.Save();
}
static void FlatChunk (ChunkRef chunk, int height)
{
// Create bedrock
for (int y = 0; y < 2; y++) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
chunk.SetBlockID(x, y, z, (int)BlockType.BEDROCK);
}
}
}
// Create stone
for (int y = 2; y < height - 5; y++) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
chunk.SetBlockID(x, y, z, (int)BlockType.STONE);
}
}
}
// Create dirt
for (int y = height - 5; y < height - 1; y++) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
chunk.SetBlockID(x, y, z, (int)BlockType.DIRT);
}
}
}
// Create grass
for (int y = height - 1; y < height; y++) {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
chunk.SetBlockID(x, y, z, (int)BlockType.GRASS);
}
}
}
}
}
}
I don't know how involved it would be to simulate the fluid physics. I'll look into it but no promises.
I would recommend trying to identify and remove the water. If you're feeling enterprising, you can attempt to do the simulation yourself, and manually set the data value on the water blocks to set their flow value (or rather, create the flow blocks that currently aren't there).
Version 0.4.0 is another pre-release version (I expect at least a couple more of these to follow before I'm happy enough to bless this project). It rolls up numerous bugfixes, some of them serious. It includes manual chunk relighting, and some example code.
Use the block manager to get/set a block by its absolute coordinates, e.g.:
INBTWorld world = new BetaWorld("/path/to/world");
BlockManager bm = world.GetBlockManager();
// Get a block ID @ 200, 63, 400. If it doesn't exit, you will get 0 back
int id = bm.GetBlockID(200, 63, 400);
Console.WriteLine("Block ID: " + id);
// Alternatively, you can get a blockref, if you want to do multiple operations on this block
// If it doesn't exist, it will be null
BlockRef block = bm.GetBlockRef(200, 63, 400);
Console.WriteLine("Block ID: " + block.ID);
There is no generator class, no. That would be a lot of infrastructure to try and emulate. Even simple ore generation is a healthy chunk of code and algorithm, if you ever flip through NBToolkit's source.
EDIT: Totally unrelated, but I've confirmed a performance bug someone posted to the project page, which will seriously degrade tool performance on large maps. I will post an updated build in the next day or two for this, but it will be accompanied by some compatibility-breaking interface changes that may or may not affect existing tools (if it does, it will be easy to fix).
I actually don't understand why a built-in map generator would be particularly useful, outside of naturally extending your map (which requires perfect duplication of the terrain generator).
On the other hand, there are a lot of different tools outside of mappers and graphical editors that manipulate existing game state (block replacement, ore generation, tree generation, terraforming, building generation, building destruction, map repair, etc.). Non-standard map generators create their own state from a blank canvas. Information tools, inventory editors, entity editors, etc. are also tools that need to manipulating existing game data. Manipulating game data can be a major pain when you consider different map formats, chunk and region boundaries, lighting and other consistency constraints. SDKs like Substrate or pymclevel deal with this issue.
Yes, since it is still in a "pre-release" phase, there is not much written documentation. Any documentation I write now is likely to become outdated. It's still perfectly usable, but you need to look at the provided examples to get a feel for current use.
Right now it's more about experimentation and feedback.
You might find the flatmap example to be of particular interest.
This mainly fixes bugs and improves performance, particularly for relighting. There's been some interface alteration (Chunks and ChunkRefs are created with factory methods now), but it's unlikely to affect existing code. Larger interface alterations are likely in the next release.
Are you a Python programmer by any chance? :wink.gif:
I think it's your use of nested dictionaries that is killing you. You should use a single dictionary (if you need to use one at all), and use a multi-value key. Substrate already has a BlockKey struct that you can use for this purpose; it's what I use to queue blocks for relight, for example.
Dictionary<BlockKey, int> blocks = new Dictionary<BlockKey, int>();
blocks.Add(new BlockKey(x, y, z), id);
Also, if you use the indexer on the dictionary, you could just overwrite anything that's already present and avoid an extra contains check.
blocks[new BlockKey(x, y, z)] = id;
But my opinion is that if you're copying changes between worlds, you should not bother with dictionaries. Just update the new world directly, on a per-chunk basis, and save the chunk when you're done processing it.
foreach (ChunkRef chunk in editedChunks)
{
int bCX = chunk.X*chunk.XDim;
int bCZ = chunk.Z*chunk.YDim;
ChunkRef oldChunk = oldWorld.GetChunkRef(chunk.X, chunk.Z);
for (int x = 0; x <= 15; x++)
{
for (int z = 0; z <= 15; z++)
{
for (int y = 0; y <= 127; y++)
{
int oldID = oldChunk.GetBlockID(x, y, z);
int EditedID = chunk.GetBlockID(x, y, z);
if (oldID != EditedID)
{
chunk.SetBlockID(x, y, z, oldID);
}
}
}
}
editedChunks.Save();
}
That should be sufficient. It has the same steps used in the FlatMap example. I suppose it's possible I broke something in 0.4.1. If that's the case, you could maybe get yourself out of a pinch by just copying an already valid level.dat into the world folder, and then try modifying it. I would try testing it, but I'm just wrapping up a major refactoring of some other parts of the SDK, which I hope to publish this weekend. I'll make sure to check that the world stuff is functioning correctly before I do.
There is a Player property in the Level class, which you should be able to directly modify, e.g.
world.Level.Player.IsSleeping = false;
However it appears I somehow missed some values like Health. This should also be corrected by this weekend.
Substrate is a .NET/Mono SDK written in C# for reading, writing, and manipulating data in Minecraft worlds. Substrate isolates the different levels of map data such as blocks, chunks, and regions, and natively supports modifying Alpha and Beta worlds using the same block and chunk interfaces. Substrate also provides interfaces for other data such as Entities, players, and general level data.
--- Requirements
Substrate requires .NET Framework 2.0 or higher, or Mono, to run. Compiling Substrate source code requires a compiler that supports C# 3.0 or higher (Visual C# 2008 Express or higher, or comparable Linux tools).
For convenience to developers, Substrate ships with separate .NET-2.0 and .NET-4.0 assemblies, so that you can include the assembly that best matches your application's target framework.
--- Download
Latest Version: 1.3.8
If you are interested in the development of Substrate, follow or fork the project on the Github Project Page
--- Additional Information
See the Introduction wiki page for more information on important classes provided by Substrate: Introduction
Largely complete API documentation is included with the Substrate download. A number of example projects are also included in the download, and available in the source tree.
Substrate is provided under the permissive MIT license. If you find this project useful in your software, consider mentioning it in the credits or about box of your application, but this is not required.
Of course, any feedback, ideas, bug reports, etc. are welcome either in this thread, or on the project page.
--- Examples
--- Projects Using Substrate
- NBTExplorer - A graphical NBT data editor.
- MACE - Random cities generator.
- Teeth of Time - Simulates effects of weather and time on worlds.
- Eedit - A simple graphical editor for item enchantments.
- Avanti! - A Paint-like Minecraft world editor.
- SeeSharp - A Minecraft map exporter / renderer.
If you've published a tool using Substrate and would like it listed, post your request.
--- Update History
[1.3.8]
- Fix: Item enchantments no longer reset on tree load.
- Fix: TagNodeString will now accept null values.
- Fix: Casing error in 'playerGameType' tag.
- Fix: Initialize Source properties in INbtObjects.
- Fix: Region Loader no longer tries to pad out non-4KB-aligned files.
- Fix: Setters in FusedDataArray.
- Fix: Crash when parsing TAG_END in an NBT List type.
- Internalized Ionic.Zlib.
- Updated item and block info for MC 1.5 and 1.6.
- World classes now accept dimensions specified as strings.
- Allow setting TileEntity data on blocks not registered as Tile Entities.
- Regions are now sorted by y,x coordinates on enumeration (contrib. by Sukasa).
- Added support for GeneratorName setting (contrib. by cry-inc).
- Added many more attributes to Level (contrib. by snoopen).
[1.3.7]
- Fix: Wrong tag name for additional block IDs ("AddBlocks" instead of "Add")
- Fix: Anvil worlds can now handle block IDs >255
- Fix: Empty chunk sections below heightmap were not written
- Fix: NBT Tree discarding root node name on load
- Fix: Various Entity and TileEntity issues
- Raw NBT tree exposed on more objects (Entities, TileEntities, Items...)
- Generic TileEntity objects will be created if specific types are unknown
- Region files multithread safe
- MobSpawnerTileEntities have updated data fields
[1.3.6]
- Fix: Bug in index calculations of Anvil composite byte/nibble arrays, causing incorrect block updates.
- Block updates for Minecraft 1.4.
[1.3.5]
- Minor changes to RegionFile to make it easier to extend (e.g. for Cubic Chunks). (not released)
[1.3.4]
- Fix: Bug in unicode handling of NBT strings which could result in inconsistent NBT binaries being written.
[1.3.3]
- Fix: Bug in player loading that could cause Anvil 1.2 worlds to not load. Was introduced in 1.3.2.
[1.3.2]
- Fix: ChunkManager.SetChunk did not set chunks at the requested location correctly.
- Fix: ResetLava in BlockFluid could possibly convert lava blocks into water.
- Fix: BlockManager could not set blocks above 127. BlockManager is now abstract and split into two concrete classes for Alpha and Anvil.
- Block, item, and player data updates for Minecraft 1.3.
[1.3.1]
- Fixes bug in chunk creation causing the Z coordinate to be used for both X and Z.
[1.3.0]
- Unified Anvil map support
- Multiple breaking changes for Anvil support
- Block and item updates through Minecraft 1.2
[1.2.0]
- Anvil beta (not officially released)
[1.1.0]
- Adds TileTick management throughout most of the API
- AutoTileTick property in AlphaBlockCollection for automatically managing TileTicks.
[1.0.3]
- Fixes a bug where clearing the player spawn would have no effect
- Fixes a bug where deleting a chunk would correctly update the cache, resulting in lost work
[1.0.2]
- Fixes a bug reading items with enchantments
- Fixes a bug enumerating entities not registered with EntityFactory
- Fixes a bug setting text on sign TileEntities
- Exposes more direct access to the Chunk cache
[1.0.1]
- Fixes a serious bug where entities were written out with invalid data, causing chunk regeneration
- Several block data enums where updated with fixes
- Animal entity types are now subclasses of EntityAnimal
[1.0.0]
- Ionic.Zlib integrated into the Substrate assembly
- Project split into .NET2/.NET4 output
- Added full Enchantment API for items
- Player and Mob classes updated with additional data
- Entity/TileEntity registires are enumerable
- ChangeValueType added to TagNodeList class
[0.9.0]
- Data resource / map (item) editing
- Conversion utilities for map editing
- NbtFile updated to handle differing compression requirements
[0.8.4]
- Fixes TileEntity data not being copied with chunks
- Unknown/Nonstandard NBT tags are now round-tripped in most objects
[0.8.3]
- Fixes painting entities not being updated correctly when their chunk is relocated
- Entities and TileEntities support MoveBy method for special relocation handling
[0.8.2]
- Fixes a bug where Entity/TileEntity coordinates were not updated with chunk
[0.8.1]
- Fixes a bug where chunk modified chunk coordinates are not saved
[0.8.0]
- 1.9pre5 block, item, and entity types
- Fixed several bugs in Entities, including an exception caused by Enderman
- Entity/TileEntity architecture updated to support inheritance, avoid future bugs
- Optional cache size parameter in OpenWorld/CreateWorld
[0.7.3]
- Fixed crash when encountering XPOrb while enumerating entities
[0.7.2]
- 1.8 Entity types
- Added missing properties to Arrow and all Mob entities
- Fixed lighting bug with Chest blocks
[0.7.1]
- 1.8 Block and Item types
[0.7.0]
- Major refactoring. You will need to tweak your projects
- CHM documentation for most of the common APIs
- Intellisense XML file for the same
- 1.7 Block and Item types
- Schematic import and export support
- CLS Compliance
- Enumerable PlayerManager
- Timestamp data exposed
- NBT Validator event support
- Numerous bugfixes including cache and TileEntity bugs
[0.6.2]
- Fixes bugs with some entities and tile entities
[0.6.1]
- Fixes bug with TileEntity updates
[0.6.0]
- Added fluid simulation for water and lava
- AutoFluid property (disabled by default)
[0.5.3]
- Fixes performance regression
- Fixes additional lighting bugs
[0.5.2]
- Lighting bugfixes and performance improvements
- TileEntity fixes
- Beta 1.6 block and item types
- 'State' property to BlockInfo (solid/nonsolid/fluid)
- Chunk copying / setting
- ItemInfo classes and supporting data enums
- Re-exposed the PlayerManager
- All missing examples added
[0.5.1]
- Numerous lighting fixes including possible crashing bug
- Added Beta 1.5 level attributes
[0.5.0]
- Major refactoring of Chunk/ChunkRef breaks compatibility, but should be easy to repair
- Fixes missing Player attributes and bug in level.dat generation
- Fixes more lighting bugs. Now correctly lights half steps, stairs, and other special blocks
- Updated chunk caching back-end
[0.4.1]
- Lighting fixes for manual chunk relighting
- Performance fixes for lighting
[0.4.0]
- Fixes cache consistency bug, among others
- Adds manual chunk relighting
- Example code
[0.3.0]
- Adds automatic blocklight and skylight recalculation for all setblockid operations via ChunkRefs or the BlockManager.
[0.2.1]
- Fixes serious bug in creating TileEntity or Entity objects.
[0.2.0]
- First public release
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
Download: http://code.google.com/p/substrate-mine ... loads/list
Source: http://code.google.com/p/substrate-mine ... S%2FSource
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
In the example code, change IBlockManager blockm to BlockManager blockm (actually, I don't think I ever used IBlockManager directly in that code?).
Due to changes in the interface hierarchy, directly using IBlockManager doesn't make sense anymore unless you're requesting an IBlock (which exposes access to ID and data fields, nothing else). This might come into play if I write in a support class for mcschema files or creative classic files, although for the later I need Java interop support so maybe that won't happen. This part of the design is still under review.
If you think something is overly weird or difficult to use, please mention it. I'll try to either justify it or come up with something different. If you would like something explained in more detail, I can also do that.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
BlockManager bm = world.BlockManager as BlockManager
I'm missing a couple overrides in the alpha block container interface, once I put them in place the cast should not be necessary anymore.
Relighting is .. interesting. I don't really have an easy solution for it but it's next on my list of things to tackle. But as a general idea, you could do an initial sweep of a chunk you modified, and make sure that any block with a luminosity value greater than 0 (can be checked in each block's blockinfo) is set to that light level. Then repeatedly sweep through the chunk looking for blocks that are not set to max-1 of all the neighbor's light values, and update them. Repeat the process until the chunk converges. Edge cases may be tricky as you'll need to inspect neighboring chunks as well. This is one task that can't easily be accomplished with a global block view because of memory constraints, unless you want to thrash your disk.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
http://code.google.com/p/substrate-mine ... loads/list
The crash occurred on chests, furnaces, and similar because they have TileEntities attached. The routines to update block IDs automatically enforce TileEntity consistency, so if you create a furnace, it will create a reasonable default TileEntity record for it as well. Likewise when you change it back to cobblestone, the records will be removed.
You can also update TileEntities if, for example, you wanted to fill the new chest block with some items.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
However, if you don't mind grabbing the source tree, I committed some block relighting code. Calling SetBlockID on a ChunkRef will immediately recalculate blocklight (but currently, not skylight). Actually, since BlockRef uses ChunkRefs, it will probably recalculate light as well. Eventually I will include some way of toggling this behavior, since realtime lighting recalculation will be too expensive for some use patterns.
There's still some problems calculating light past region boundaries. That will get patched later.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
http://code.google.com/p/substrate-mine ... loads/list
This fully incorporates automatic blocklight and sunlight recalculation whenever a block is updated. It seems to do a pretty good job, but it's possible that it violates some of the lighting rules. If you can identify a lighting pattern that occurs in Minecraft but is not faithfully reproduced by Substrate, please post a picture of it.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
I've also pushed the first purpose-built, well-commented example, generating a flat map. On a powerful workstation, this generated 1600 solid, lit chunks in under 10 seconds. Of course, it represents a lower bound.
(Note, the API for World objects has been changed)
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
I would recommend trying to identify and remove the water. If you're feeling enterprising, you can attempt to do the simulation yourself, and manually set the data value on the water blocks to set their flow value (or rather, create the flow blocks that currently aren't there).
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
Version 0.4.0 is another pre-release version (I expect at least a couple more of these to follow before I'm happy enough to bless this project). It rolls up numerous bugfixes, some of them serious. It includes manual chunk relighting, and some example code.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
EDIT: Totally unrelated, but I've confirmed a performance bug someone posted to the project page, which will seriously degrade tool performance on large maps. I will post an updated build in the next day or two for this, but it will be accompanied by some compatibility-breaking interface changes that may or may not affect existing tools (if it does, it will be easy to fix).
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
On the other hand, there are a lot of different tools outside of mappers and graphical editors that manipulate existing game state (block replacement, ore generation, tree generation, terraforming, building generation, building destruction, map repair, etc.). Non-standard map generators create their own state from a blank canvas. Information tools, inventory editors, entity editors, etc. are also tools that need to manipulating existing game data. Manipulating game data can be a major pain when you consider different map formats, chunk and region boundaries, lighting and other consistency constraints. SDKs like Substrate or pymclevel deal with this issue.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
Right now it's more about experimentation and feedback.
You might find the flatmap example to be of particular interest.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
This mainly fixes bugs and improves performance, particularly for relighting. There's been some interface alteration (Chunks and ChunkRefs are created with factory methods now), but it's unlikely to affect existing code. Larger interface alterations are likely in the next release.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
I think it's your use of nested dictionaries that is killing you. You should use a single dictionary (if you need to use one at all), and use a multi-value key. Substrate already has a BlockKey struct that you can use for this purpose; it's what I use to queue blocks for relight, for example.
Dictionary<BlockKey, int> blocks = new Dictionary<BlockKey, int>();
blocks.Add(new BlockKey(x, y, z), id);
Also, if you use the indexer on the dictionary, you could just overwrite anything that's already present and avoid an extra contains check.
blocks[new BlockKey(x, y, z)] = id;
But my opinion is that if you're copying changes between worlds, you should not bother with dictionaries. Just update the new world directly, on a per-chunk basis, and save the chunk when you're done processing it.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate
External server browser: Created by me, made for you.Not working atm, and will not get updated in the near future, sorry.
There is a Player property in the Level class, which you should be able to directly modify, e.g.
world.Level.Player.IsSleeping = false;
However it appears I somehow missed some values like Health. This should also be corrected by this weekend.
Mods I Develop: Garden Stuff -- Storage Drawers -- Hunger Strike
Tools I Develop: NBTExplorer -- Substrate