public static void CropMaceWorld(frmMace frmLogForm) { // thank you to Surrogard <*****@*****.**> for providing a linux friendly version of this code: Directory.CreateDirectory("macecopy".ToMinecraftSaveDirectory()); AnvilWorld awCopy = AnvilWorld.Create("macecopy".ToMinecraftSaveDirectory()); RegionChunkManager cmCopy = awCopy.GetChunkManager(); AnvilWorld awCrop = AnvilWorld.Open("mace".ToMinecraftSaveDirectory()); RegionChunkManager cmCrop = awCrop.GetChunkManager(); foreach (ChunkRef chunk in cmCrop) { if (chunk.X >= -7 && chunk.X <= 11 && chunk.Z >= 0 && chunk.Z <= 11) { Debug.WriteLine("Copying chunk " + chunk.X + "," + chunk.Z); cmCopy.SetChunk(chunk.X, chunk.Z, chunk.GetChunkRef()); } cmCopy.Save(); } awCopy.Level.GameType = GameType.CREATIVE; cmCopy.Save(); awCopy.Save(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { Process.Start("explorer.exe", @"/select," + "macecopy".ToMinecraftSaveDirectory() + "\\level.dat"); } }
public void initializeMinecraftWorld() { currentWorld = AnvilWorld.Create(Settings.Default.outputPath); // We can set different world parameters currentWorld.Level.LevelName = Settings.Default.levelName; currentWorld.Level.Spawn = new SpawnPoint(20, 255, 20); currentWorld.Level.GameType = GameType.CREATIVE; currentWorld.Level.AllowCommands = true; }
public void ExportMap(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; string path = e.Argument as string; worker.ReportProgress(0, "Exporting map to " + path); AnvilWorld world = AnvilWorld.Create(path); world.Level.LevelName = "Dwarf Fortress World"; world.Level.GameType = GameType.CREATIVE; world.Level.Spawn = new SpawnPoint(36, 255, 36); world.Save(); var chunkManager = world.GetChunkManager(); int total = (Tiles[0].Height * tileWidth / 16) * (Tiles[0].Width * tileWidth / 16); int done = 0; for (int chunkZ = 0; chunkZ < Tiles[0].Height * tileWidth / 16; chunkZ++) { for (int chunkX = 0; chunkX < Tiles[0].Width * tileWidth / 16; chunkX++) { var chunk = chunkManager.CreateChunk(chunkX, chunkZ); var blocks = chunk.Blocks; blocks.AutoLight = false; chunk.IsTerrainPopulated = true; int chunkY = 0; foreach (var level in Tiles) { if (!level.Enabled) { continue; } for (int y = 0; y < tileHeight; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { blocks.SetBlock(x, y + (chunkY * tileHeight), z, level.GetBlock(x + (chunkX * 16), y, z + (chunkZ * 16))); } } } chunkY++; } blocks.RebuildSkyLight(); blocks.RebuildBlockLight(); blocks.RebuildHeightMap(); chunkManager.Save(); done++; worker.ReportProgress(done * 100 / total, "Generating Chunks"); } } worker.ReportProgress(100, "Finished exporting map"); }
static void Main(string[] args) { if (args.Length != 3) { Console.WriteLine("Usage: Convert <world> <dest> <alpha|beta|anvil>"); return; } string src = args[0]; string dst = args[1]; string srctype = args[2]; if (!Directory.Exists(dst)) { Directory.CreateDirectory(dst); } // Open source and destrination worlds depending on conversion type NbtWorld srcWorld = NbtWorld.Open(src); NbtWorld dstWorld; switch (srctype) { case "alpha": dstWorld = AlphaWorld.Create(dst); break; case "beta": dstWorld = BetaWorld.Create(dst); break; case "anvil": dstWorld = AnvilWorld.Create(dst); break; default: throw new Exception("Invalid conversion type"); } // Grab chunk managers to copy chunks IChunkManager cmsrc = srcWorld.GetChunkManager(); IChunkManager cmdst = dstWorld.GetChunkManager(); // Copy each chunk from source to dest foreach (ChunkRef chunk in cmsrc) { cmdst.SetChunk(chunk.X, chunk.Z, chunk.GetChunkRef()); Console.WriteLine("Copying chunk: {0}, {1}", chunk.X, chunk.Z); } // Copy level data from source to dest dstWorld.Level.LoadTreeSafe(srcWorld.Level.BuildTree()); // Save level.dat dstWorld.Level.Save(); }
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Usage: flatmap <type> <target_dir>"); Console.WriteLine("Available Types: alpha, beta, anvil"); return; } string dest = args[1]; int xmin = -20; int xmax = 20; int zmin = -20; int zmaz = 20; NbtVerifier.InvalidTagType += (e) => { throw new Exception("Invalid Tag Type: " + e.TagName + " [" + e.Tag + "]"); }; NbtVerifier.InvalidTagValue += (e) => { throw new Exception("Invalid Tag Value: " + e.TagName + " [" + e.Tag + "]"); }; NbtVerifier.MissingTag += (e) => { throw new Exception("Missing Tag: " + e.TagName); }; if (!Directory.Exists(dest)) { Directory.CreateDirectory(dest); } // This will instantly create any necessary directory structure NbtWorld world; switch (args[0]) { case "alpha": world = AlphaWorld.Create(dest); break; case "beta": world = BetaWorld.Create(dest); break; case "anvil": world = AnvilWorld.Create(dest); break; default: throw new Exception("Invalid world type specified."); } IChunkManager cm = world.GetChunkManager(); // We can set different world parameters world.Level.LevelName = "Flatlands"; world.Level.Spawn = new SpawnPoint(20, 70, 20); // world.Level.SetDefaultPlayer(); // We'll let MC create the player for us, but you could use the above // line to create the SSP player entry in level.dat. // 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.Blocks.AutoLight = false; // Set the blocks FlatChunk(chunk, 64); // Reset and rebuild the lighting for the entire chunk at once chunk.Blocks.RebuildHeightMap(); chunk.Blocks.RebuildBlockLight(); chunk.Blocks.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 public void Generate(frmMace frmLogForm, string UserWorldName, string strWorldSeed, string strWorldType, bool booWorldMapFeatures, int TotalCities, string[] strCheckedThemes, int ChunksBetweenCities, string strSpawnPoint, bool booExportSchematics, string strSelectedNPCs, string strUndergroundOres) { frmLogForm.UpdateLog("Started at " + DateTime.Now.ToLocalTime(), false, true); worldCities = new WorldCity[TotalCities]; lstCityNames.Clear(); Chunks.biomes.Clear(); RNG.SetRandomSeed(); #region create minecraft world directory from a random unused world name string strFolder = String.Empty, strWorldName = String.Empty; UserWorldName = UserWorldName.ToSafeFilename(); if (UserWorldName.Trim().Length == 0) { UserWorldName = "random"; } if (UserWorldName.ToLower().Trim() != "random") { if (Directory.Exists(UserWorldName.ToMinecraftSaveDirectory())) { if (MessageBox.Show("A world called \"" + UserWorldName + "\" already exists. " + "Would you like to use a random name instead?", "World already exists", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel) { frmLogForm.UpdateLog("Cancelled, because a world with this name already exists.", false, false); return; } } else { strWorldName = UserWorldName; strFolder = strWorldName.ToMinecraftSaveDirectory(); } } if (strWorldName.Length == 0) { strWorldName = Utils.GenerateWorldName(); strFolder = strWorldName.ToMinecraftSaveDirectory(); } Directory.CreateDirectory(strFolder); frmLogForm.btnSaveLogNormal.Tag = Path.Combine(strFolder, "LogNormal.txt"); frmLogForm.btnSaveLogVerbose.Tag = Path.Combine(strFolder, "LogVerbose.txt"); frmLogForm.UpdateLog("World name: " + strWorldName, false, true); #endregion #region get handles to world, chunk manager and block manager AnvilWorld worldDest = AnvilWorld.Create(@strFolder); worldDest.Level.LevelName = "Creating. Don't open until Mace is finished."; RegionChunkManager cmDest = worldDest.GetChunkManager(); BlockManager bmDest = worldDest.GetBlockManager(); bmDest.AutoLight = false; #endregion #region Determine themes // "how does this work, robson?" // well, I'm glad you asked! // we keep selecting a random unused checked theme, until they've all been used once. // after that, all other cities will have a random checked theme int maxFarmSize = 0; strCheckedThemes = RNG.ShuffleArray(strCheckedThemes); for (int CurrentCityID = 0; CurrentCityID < TotalCities; CurrentCityID++) { if (CurrentCityID <= strCheckedThemes.GetUpperBound(0)) { worldCities[CurrentCityID].ThemeName = strCheckedThemes[CurrentCityID]; } else { worldCities[CurrentCityID].ThemeName = RNG.RandomItem(strCheckedThemes); } City.themeName = worldCities[CurrentCityID].ThemeName; worldCities[CurrentCityID].ChunkLength = GetThemeRandomXMLElementNumber("options", "city_size"); int farmSize = GetThemeLastXMLElementNumber("options", "farm_size"); maxFarmSize = Math.Max(maxFarmSize, farmSize); } #endregion GenerateCityLocations(TotalCities, ChunksBetweenCities + maxFarmSize); int intRandomCity = RNG.Next(TotalCities); for (int CurrentCityID = 0; CurrentCityID < TotalCities; CurrentCityID++) { MakeCitySettings(frmLogForm, worldCities[CurrentCityID].ThemeName, CurrentCityID, strSelectedNPCs); if (!GenerateCity.Generate(frmLogForm, worldDest, cmDest, bmDest, worldCities[CurrentCityID].x, worldCities[CurrentCityID].z, booExportSchematics, strUndergroundOres)) { frmLogForm.UpdateLog("World generation failed/cancelled.", false, false); return; } #region set spawn point if (City.id == intRandomCity) { switch (strSpawnPoint) { case "Away from the cities": worldDest.Level.Spawn = new SpawnPoint(0, 65, 0); break; case "Inside a random city": worldDest.Level.Spawn = new SpawnPoint(((worldCities[intRandomCity].x + Chunks.CITY_RELOCATION_CHUNKS) * 16) + (City.mapLength / 2), 65, ((worldCities[intRandomCity].z + Chunks.CITY_RELOCATION_CHUNKS) * 16) + (City.mapLength / 2)); break; case "Outside a random city": worldDest.Level.Spawn = new SpawnPoint(((worldCities[intRandomCity].x + Chunks.CITY_RELOCATION_CHUNKS) * 16) + (City.mapLength / 2), 65, ((worldCities[intRandomCity].z + Chunks.CITY_RELOCATION_CHUNKS) * 16) + 2); break; default: Debug.Fail("invalid spawn point"); break; } frmLogForm.UpdateLog("Spawn point set to " + worldDest.Level.Spawn.X + "," + worldDest.Level.Spawn.Y + "," + worldDest.Level.Spawn.Z, false, true); } #endregion } #region weather frmLogForm.UpdateLog("Setting weather", false, true); worldDest.Level.Time = RNG.Next(24000); if (RNG.NextDouble() < 0.15) { frmLogForm.UpdateLog("Rain", false, true); worldDest.Level.IsRaining = true; // one-quarter to three-quarters of a day worldDest.Level.RainTime = RNG.Next(6000, 18000); if (RNG.NextDouble() < 0.25) { frmLogForm.UpdateLog("Thunder", false, true); worldDest.Level.IsThundering = true; worldDest.Level.ThunderTime = worldDest.Level.RainTime; } } #endregion #region world details worldDest.Level.LevelName = strWorldName; frmLogForm.UpdateLog("Setting world type: " + strWorldType, false, true); switch (strWorldType.ToLower()) { case "creative": worldDest.Level.GameType = GameType.CREATIVE; break; case "survival": worldDest.Level.GameType = GameType.SURVIVAL; break; case "hardcore": worldDest.Level.GameType = GameType.SURVIVAL; worldDest.Level.Hardcore = true; break; default: Debug.Fail("Invalidate world type selected."); break; } frmLogForm.UpdateLog("World map features: " + booWorldMapFeatures.ToString(), false, true); worldDest.Level.UseMapFeatures = booWorldMapFeatures; if (strWorldSeed != String.Empty) { long seed = 0; if (long.TryParse(strWorldSeed, out seed)) { worldDest.Level.RandomSeed = seed; frmLogForm.UpdateLog("Specified world seed: " + worldDest.Level.RandomSeed, false, true); } else { worldDest.Level.RandomSeed = strWorldSeed.ToJavaHashCode(); frmLogForm.UpdateLog("Specified world seed: " + strWorldSeed, false, true); frmLogForm.UpdateLog("Specified world seed converted to a number: " + worldDest.Level.RandomSeed, false, true); } } else { worldDest.Level.RandomSeed = RNG.Next(); frmLogForm.UpdateLog("Random world seed: " + worldDest.Level.RandomSeed, false, true); } worldDest.Level.LastPlayed = (DateTime.UtcNow.Ticks - DateTime.Parse("01/01/1970 00:00:00").Ticks) / 10000; frmLogForm.UpdateLog("World time: " + worldDest.Level.LastPlayed, false, true); #endregion cmDest.Save(); worldDest.Save(); Chunks.SetBiomeData(@strFolder); frmLogForm.UpdateLog("\nCreated the " + strWorldName + "!", false, false); frmLogForm.UpdateLog("It'll be at the top of your MineCraft world list.", false, false); frmLogForm.UpdateLog("Finished at " + DateTime.Now.ToLocalTime(), false, true); }
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Usage: eina_to_nbt <source> <dest>"); return; } String dest = args[1]; System.Console.WriteLine("Creating EINA map..."); if (!Directory.Exists(dest)) { Directory.CreateDirectory(dest); } NbtWorld world = AnvilWorld.Create(dest); world.Level.LevelName = "EINA"; world.Level.Spawn = new SpawnPoint(292, 70, 270); world.Level.GameType = GameType.CREATIVE; world.Level.Initialized = true; Player p = new Player(); p.Position.X = 292; p.Position.Y = 130; p.Position.Z = 292; IPlayerManager pm = world.GetPlayerManager(); pm.SetPlayer("Player", p); IChunkManager cm = world.GetChunkManager(); string[] lines = System.IO.File.ReadAllLines(args[0]); string[] words; ChunkRef chunk; words = lines[0].Split(' '); int minx = Int32.Parse(words[0]); int maxx = Int32.Parse(words[0]); int miny = Int32.Parse(words[0]); int maxy = Int32.Parse(words[0]); for (int i = 0; i < lines.Length; i++) { words = lines[i].Split(' '); //System.Console.WriteLine(lines[i]); int x = Int32.Parse(words[0]); int y = Int32.Parse(words[1]); int z = Int32.Parse(words[2]); int color = Int32.Parse(words[3]); string text = ""; if (words.Length > 4) { text = words[4]; for (int j = 5; j < words.Length; j++) { text += ' ' + words[j]; } } else { text = ""; } int xLocal = x / 16; int yLocal = y / 16; if (xLocal < minx) { minx = xLocal; } if (xLocal > maxx) { maxx = xLocal; } if (yLocal < miny) { miny = yLocal; } if (yLocal > maxy) { maxy = yLocal; } if (!cm.ChunkExists(xLocal, yLocal)) { //System.Console.WriteLine(xLocal+" "+yLocal); cm.CreateChunk(xLocal, yLocal); } chunk = cm.GetChunkRef(xLocal, yLocal); //System.Console.WriteLine(x+" "+y+" "+z); //System.Console.WriteLine(xLocal+" "+yLocal); if (!chunk.IsDirty) { chunk.IsTerrainPopulated = true; chunk.Blocks.AutoLight = false; //FlatChunk(chunk, 64); chunk.Blocks.RebuildHeightMap(); chunk.Blocks.RebuildBlockLight(); chunk.Blocks.RebuildSkyLight(); //System.Console.WriteLine(chunk.IsDirty); for (int i2 = 0; i2 < 16; i2++) { for (int j = 0; j < 16; j++) { setBlock(chunk, i2, 64, j, 16, ""); } } if (((xLocal % 8) == 0) & ((yLocal % 8) == 0)) { cm.Save(); } setBlock(chunk, x % 16, z + 64, y % 16, color, text); } else { setBlock(chunk, x % 16, z + 64, y % 16, color, text); //System.Console.WriteLine("hola"); } if ((i + 1) % 500000 == 0) { System.Console.WriteLine("Guardando"); world.Save(); //System.Console.WriteLine("Hecho"); } } world.Save(); }
//------------------------------------------------------------ // GIGANTIC MAP CONVERSION FUNCTION! //------------------------------------------------------------ ///<summary> /// <para>This is the function that will be called when the big 'convert' button is pressed on the panel. /// Conversion is BIG. I have divided it into the following stages:</para> /// <para></para> /// <para>1) Open the Substrate directory, read it, and initialize cubiquity stuff </para> /// /// <para>2) Handle file names. Handle closing existing files, deleting them, replacing them, relinking them, etc. Make sure everything lines up smoothly, and /// minimize crashing as a result of overwriting things.</para> /// /// <para>3) Translate the 3D Array of Voxels from Substrate to Cubiquity, minding things like Regions and dimensions.</para> /// /// <para>4) Save all the materials we created and wish to keep. Again, ensure no naming conflict problems. </para> /// /// <para>5) Refresh everything dependent on the newly saved materials</para> /// <para></para> /// <para> Although this function takes no parameters, it is reliant heavily on class members; such as toAsset, toVdb, _options, _saveName, _toSubstrateMap, and in general /// pretty much every other part of SubstrateConverter. It also relies on Application., AssetDatabase., and File. calls.</para> /// </summary> public void ConvertMap() { //------------------------------------------------------------ //------- STAGE 1: GET THE MAPS OPEN AND CREATE SOME HANDLERS! //------------------------------------------------------------ //Load in the Substrate Map folder! (The three versions of map are 'Alpha, Beta, and Anvil.' Our //maps are served in Anvil format. We don't have to errorcheck; substrate will pop an error if we failed. AnvilWorld leWorld = AnvilWorld.Create(_toSubstrateMap); //The region actually contains data about the chunks. AnvilRegionManager leRegions = leWorld.GetRegionManager(); //I have no idea what a more clever way of getting the number of regions in leRegions might be, so let's do this for now int regionTotal = 0; foreach(AnvilRegion region in leRegions) { if(region != null) //I hate that warning in the editor that region is declared but never used... regionTotal++; } //debugging to make sure loops work and understand if any assets went mysteriously missing. Debug.Log ("Attempting to load " + regionTotal.ToString() + " regions"); //this exists ENTIRELY as a set of helpers so that I can concatenate strings together and perform sexy operations on them :| String pathVDB = ""; String pathAsset = ""; //this has helped tremendously during the debug phase int failDetector = 0; //this needs to be rooted at the Assets directory, or there shall be chaos! CHAOS! //(If improperly done it will result in 'unable to create asset' and DEATH! //Debug.Log ("Rooting _toAsset: " + _toAsset); String toAssetHelp = Paths.RootToDirectory(Application.dataPath, toAsset); //------------------------------------------------------------ //------- PROCEED REGION BY REGION! //------------------------------------------------------------ // I have added a wiki page on the evils of conversion. Right now, I am creating a VoxelData object per region //btw, we can use foreach on leRegions because leRegion is 'Enumerable'. Check out its inheritance. int regionCount = 0; foreach(AnvilRegion region in leRegions) { //well, since I put it in the above foreach, I suddenly feel obligated to do it here, also... Don't judge me! if(region == null) continue; //Chunk Size * chunks in region.... map is automatically 256 deep int xSize = region.XDim * this.subChunkSize; int zSize = region.ZDim * this.subChunkSize; int ySize = this.subMapDepth - _clipFromAbove; //it appears that while minecraft prefers xzy, cubiquity prefers xyz (height compes second) //meh, I nabbed this from a little deeper in Cubiquity than its top-level menu selectors, cause I wanted to be able to specify my own vdb name //it creates both the asset (which we are going to have to save) and the .vdb //anyway, make sure we create the new data with the proper file name!!! ColoredCubesVolumeData data = null; //------------------------------------------------------------ //------- STAGE 2: HANDLE NAMING CONFLICTS/REIMPORTING/ETC //------------------------------------------------------------ //This handy-dandy notebook is going to record for us information we need to regenerate copies of the VolumeData .asset that used to link to the //vdb previous to import AND it holds onto the original data structures so we can ask ColoredCubesVolume if their data == data we replaced. Dictionary<String, ColoredCubesVolumeData> relinker = new Dictionary<String, ColoredCubesVolumeData>(); //use that nice helper variable with this nice helper function to ensure our path is prepped for either single or multiple saves... //all without cluttering our code with loads of if/thens pathVDB = Paths.HelpMakePath(toVDB, regionTotal, regionCount, ".vdb"); pathAsset = Paths.HelpMakePath(toAssetHelp, regionTotal, regionCount, ".asset"); //Debug.Log ("Created pathAsset: " + pathAsset); //Alrighty then. What we want to do is check and see if this VDB already exists. //if it exists, we want to try and delete it. //to delete it, we have to figure out if it's somehow locked and then attempt to unlock it. //then we have to try and delete it and we might get some errors (for which we should prep a try/catch) if(File.Exists (pathVDB)) { Debug.Log ("A .vdb by this name already exists. Searching through .asset files to see if it is currently opened."); //Alright, so we're going to do some hacking and see if we can figure out how to delete the vdbs live. //this is gonna look for the .asset file that the vdb is attached to... //if we managed to find the .asset that links to this vdb, we must BURN IT MUAHAHAHAHHAHAA //I've changed if(oldData) to while(oldData) to account for the possibility that multiple Data .assets //might have the vdb open in read only mode failDetector = 0; foreach(ColoredCubesVolumeData oldData in FindVolumeMatchingPath(pathVDB)) { Debug.Log ("Successfully found an .asset reading from the .vdb. Attempting to shut it down to release the .vdb."); //I'm going out on a limb here to see if this works... If it doesn't, we can fudge around a little //more or just try to fail gracefully. oldData.ShutdownCubiquityVolume(); //referencing this function (GetAssetPath) takes a million bajillion years. String oldDataPath = AssetDatabase.GetAssetPath (oldData); //write down in our handy-dandy notebook that this oldData once existed at some location if(!relinker.ContainsKey (oldDataPath)) { relinker.Add (oldDataPath, oldData); } //now let's try and delete the asset itself so we get no linking errors... AssetDatabase.DeleteAsset(oldDataPath); failDetector++; if(failDetector >= 1000) break; } //this should no longer ever fire because olddata does a comparison now; but I'll leave it in place. if(failDetector >= 1000) { throw new System.ArgumentException("I need to write better while loops", failDetector.ToString()); } Debug.Log ("Attempting to delete the old .vdb under the assumption it is no longer open. If the deletion fails, the conversion will not proceed. The .vdb can be deleted manually with the Unity Editor closed, or you can specify a different save name for the .vdb."); //When this error is thrown, the entire conversion attempt stops; and we don't corrupt our existing data. File.Delete (pathVDB); } //checking for if VDB exists and deleting it/its .assets Debug.Log ("Creating new VDB"); //CREATE LE NEW DATA with the path we just got :) data = VolumeData.CreateEmptyVolumeData<ColoredCubesVolumeData>(new Region(0, 0, 0, xSize-1, ySize-1-_clipFromBelow, zSize-1), pathVDB); //Mayday! if(data == null) { Debug.Log("Unable to initialize ColoredCubesVolumeData. Attempting to fail gracefully by abandoning conversion attempt."); return; } //------------------------------------------------------------ //------- STAGE 3: TRANSFER THE 3D ARRAYS, BLOCK BY BLOCK //------------------------------------------------------------ //declare the chunk-reference-thingy we'll be using to access Substrate blocks! ChunkRef chunk = null; AlphaBlockCollection blocks = null; //I get the impression Substrate once thought it needed Alpha, Beta, and Anvil Block Collections... and then ended up only needing 1 kind... //----- The array CONVERSION! -----// //And here is where we will actually go through the loop's 3 dimensions and attempt to change the blocks //Scroll down to the super-interior 'k' loop to find the block replacement code //iterate through the chunks and blocks on x axis for(int iChunk = 0, iBlock = 0; iChunk < region.XDim;) { //iterate through the chunks and blocks on z axis (the odd initialization parameters will fire the blocks called 'ITERATION CODE' on the first run.) //(and the odd termination parameters should fire when jChunk = the last chunk and jBlock = the last block for(int jChunk = -1, jBlock = this.subChunkSize; jChunk < region.ZDim - 1 || jBlock < this.subChunkSize - 1; jBlock++) { //ITERATION CODE FOR J/Z if(jBlock >= this.subChunkSize) { jBlock = 0; jChunk ++; //nab the new chunk chunk = region.GetChunkRef(iChunk, jChunk); //determine if it's valid if(chunk == null) { //hehe, I'm cheating, I'm cheating. this allows the ITERATION CODE block to handle loading the next chunk ;) jBlock = this.subChunkSize; continue; } if(!chunk.IsTerrainPopulated) { jBlock = this.subChunkSize; continue; } //handily access its blocks blocks = chunk.Blocks; } //there is only 1 chunk on the y axis, so go straight through the blocks without worrking about kChunks or kBlocks for(int k = _clipFromBelow; k < ySize; k++) { //NAB THE ID! Using the Substrate block collections 'get id' int blockId = blocks.GetID (iBlock, k, jBlock); ///Translate the ID using our personal 'ConvertBlock' and throw that quantizedColor variable into Cubiquity's voxeldata collection! data.SetVoxel(iBlock, k-_clipFromBelow, jBlock, ConvertBlock (blockId)); }//K/Y loop }//J/Z loop //ITERATION CODE FOR I/X iBlock++; if(iBlock >= this.subChunkSize) { iBlock = 0; iChunk ++; } } //I/X loop //------------------------------------------------------------ //------- STAGE 4: SAVE EVERYTHING WHERE IT NEEDS TO GO, AGAIN PREVENT NAMING CONFLICTS //------------------------------------------------------------ //Now, data should be filled with all of the cubes we extracted from the chunks. We need to save the .asset files! We want to add on //the region number if we loaded more than one region, and leave the name the way it is if we didn't. //we just have to make the new asset(s) permenant //there is a possibility a nincompoop with good intentions somehow ended up with an .asset file that //has the name we're replacing, but a .vdb that's named something else entirely. //in this case we don't want to destroy that potentially valuable .vdb- but we've got to get rid of the //asset. And since the .vdb might be locked, we have to shut it down to prevent strange deletion difficulties. if(File.Exists (pathAsset)) { //check out if this is a ColoredCubesVolumeData or not ColoredCubesVolumeData oldData = AssetDatabase.LoadAssetAtPath(pathAsset, typeof(ColoredCubesVolumeData)) as ColoredCubesVolumeData; if(oldData != null) { Debug.Log ("A stray .asset file has been found with an identical name but with a .vdb at " + oldData.fullPathToVoxelDatabase + " Will attempt to shutdown and overwrite the .asset without harming the .vdb"); //again, this little bugger is going to help me refresh all the ColoredCubesVolumes at the end //replacer.Add (pathVDB, oldData); //I'm going out on a limb here to see if this works... If it doesn't, we can fudge around a little //more or just try to fail gracefully. oldData.ShutdownCubiquityVolume(); //I am on the fence about whether I want to relink this data. And I don't think I do. After all, our previous foreach iterator //would have found this current oldData if there wasn't a mixmatch with vdbs. } else { Debug.Log("An .asset of a different type (non ColoredCubesVolumeData) has been found at the save location. Attempting to overwrite it."); } //now let's try and delete the asset itself so we get no linking errors... AssetDatabase.DeleteAsset(pathAsset); } //Debug.Log ("The hell is pathAsset? " + pathAsset); //Create the asset AssetDatabase.CreateAsset(data, pathAsset); AssetDatabase.SaveAssets(); //Do some selection/saving/cleanup EditorUtility.FocusProjectWindow (); Selection.activeObject = data; //------------------------------------------------------------ //------- STAGE 5: REFRESH DEPENDENT COMPONENTS //------------------------------------------------------------ //This nifty little loop is going to handle refreshing our ColoredCubesVolumes! //right off the bat I'm not going to have it create .asset files; especially cause I haven't shared //so, let's iterate through all of the oldDatas we destroyed foreach(KeyValuePair<String, ColoredCubesVolumeData> toDo in relinker) { foreach(ColoredCubesVolume toLink in FindObjectMatchingData(toDo.Value)) { //update it toLink.data = data; } } AssetDatabase.SaveAssets(); //iterate :3 regionCount++; }//for each region AssetDatabase.Refresh (); Debug.Log ("Conversion attempt was successful"); }
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Usage: flatmap <type> <target_dir>"); Console.WriteLine("Available Types: alpha, beta, anvil"); return; } string dest = args[1]; int xmin = -20; int xmax = 30; int zmin = -20; int zmaz = 20; NbtVerifier.InvalidTagType += (e) => { throw new Exception("Invalid Tag Type: " + e.TagName + " [" + e.Tag + "]"); }; NbtVerifier.InvalidTagValue += (e) => { throw new Exception("Invalid Tag Value: " + e.TagName + " [" + e.Tag + "]"); }; NbtVerifier.MissingTag += (e) => { throw new Exception("Missing Tag: " + e.TagName); }; if (!Directory.Exists(dest)) { Directory.CreateDirectory(dest); } // This will instantly create any necessary directory structure NbtWorld world; switch (args[0]) { case "alpha": world = AlphaWorld.Create(dest); break; case "beta": world = BetaWorld.Create(dest); break; case "anvil": world = AnvilWorld.Create(dest); break; default: throw new Exception("Invalid world type specified."); } IChunkManager cm = world.GetChunkManager(); // We can set different world parameters world.Level.LevelName = "Flatlands"; world.Level.Spawn = new SpawnPoint(0, 70, 0); // world.Level.SetDefaultPlayer(); // We'll let minecraft create the player for us, but you could use the above // line to create the SSP player entry in level.dat. // 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.Blocks.AutoLight = false; // Set the blocks FlatChunk(chunk, 64); // Reset and rebuild the lighting for the entire chunk at once chunk.Blocks.RebuildHeightMap(); chunk.Blocks.RebuildBlockLight(); chunk.Blocks.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(); } } //Heightmap location string csv_file_path = @"D:\Univ\heightmap_Eglise.csv"; DataTable csvData = GetDataTableFromCSVFile(csv_file_path); Console.WriteLine("Rows count:" + csvData.Rows.Count); int currChunkX = 0; int currChunkZ = 0; int compRow = 0; int compLine = 0; foreach (DataRow csvRow in csvData.AsEnumerable()) { String strRow = String.Join(", ", csvRow.ItemArray); strRow = strRow.Remove(strRow.Length - 1); List <int> values = new List <int>(Array.ConvertAll(strRow.Split(';'), int.Parse)); foreach (int value in values) { currChunkX = compRow / 16; currChunkZ = compLine / 16; for (int i = 64; i < 64 + value; i++) { cm.GetChunkRef(currChunkX, currChunkZ).Blocks.SetID((compRow % 16), i, (compLine % 16), (int)BlockType.BRICK_BLOCK); cm.Save(); } Console.WriteLine("Building block " + (compRow % 16) + "," + (compLine % 16) + " to height " + (64 + value) + " in chunk " + currChunkX + "," + currChunkZ); compLine++; } Console.WriteLine("Row " + compRow + " finished building"); compLine = 0; compRow++; 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(); }