Ejemplo n.º 1
0
        public SelectRegion(AnvilRegionManager regs, Form main)
        {
            InitializeComponent(main);

            foreach (IRegion re in regs)
            {
                String insert = "Region ( " + re.X + ", " + re.Z + " )";
                cmbRegion.Items.Add(insert);
            }

            cmbRegion.SelectedIndex = 0;
        }
		//------------------------------------------------------------
		//          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");
		}