Welcome to Keen Software House Forums! Log in or Sign up to interact with the KSH community.
  1. You are currently browsing our forum as a guest. Create your own forum account to access all forum functionality.

vx2 Cleanup Tool (Workaround for "File Path Too Long" error)

Discussion in 'Programming Guides and Tools' started by Tim Wilson, Mar 26, 2018.

Thread Status:
This last post in this thread was made more than 31 days old.
  1. Tim Wilson Trainee Engineer

    Messages:
    7
    Hey all! First post on here, been playing Space Engineers for a while, finally got into it when I realized I could script in C# haha.

    So I ran into an issue a couple weeks ago where I couldn't save my game because the voxel file names had gotten too long making the path more than 256 characters. Looking around Google I stumbled upon a post here with a workaround to remove the --LongNumbers..etc ID from the file name and clean up the corresponding parts of the SANDBOX-0-0-0.sbc and sbcPB files. This fixed the issue for me but I was finding I was having to use it regularly as I was doing a large creative map with a ton of voxel digging for a base operating system script I was working on. Needless to say the time spent got annoying pretty quick.

    So what I've done is write up a quick tool to clean the stuff up for me. All it does it look through the .vx2 files in a save directory and remove the -######## from them (ex: Moon--3983712712399000.vx2 becomes just Moon.vx2). It also resets the naming in both the .sbs and .sbsPB files. It's just a command line program that takes the save path (ex: C:\Users\UserName\AppData\Roaming\SpaceEngineers\Saves\##############\SaveName\) as an argument. Thing takes maybe 5-10 seconds to run and will print out a "Successfully Processed Save Directory" when it's done.

    It's fairly rudimentary - I've been running it about 3 days now without issue and figured I'd post the source on here. There's a ton of optimization I could do and I'll likely clean it up to be generic and work on any vx2 files rather than the default "Earthlike, Moon, Mars, Titan, Alien..etc" ones. Anyone who wants to download it and take a crack is welcome to. Rather than post a link to an exe I figured I'd post the source since it's pretty short anyway -- feel free to copy this into Visual Studio and just run it with the argument. Make sure you backup the save directory of course though it's been working without issue for me so far.

    Update:
    Download Link (9kb)

    Steps:
    1) Backup save folder first
    2) To use it just run command prompt (Start > Run > type cmd)
    3) Navigate to the folder it's in (ex: cd C:\Users\USERNAME\Downloads )
    4) Type VoxelCleanup <path to Save folder> (ex: VoxelCleanup ---C:\Users\USERNAME\AppData\Roaming\SpaceEngineers\Saves\LONGNUMBER\SaveFolder\) -- Change the bold parts to match your username/ID/Savefolder

    Should give you a Successfully Processed Save Directory when it's done. If you get any errors send me details and I'll take a look. :)

    Thanks all!


    Code:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.IO;
    
    namespace VoxelCleanup
    {
    	class Program
    	{
    		public static SaveFile Save = new SaveFile();
    
    		static void Main(string[] args)
    		{
    			string Path = args[0];
    
    			 if (PathIsValid(Path))
    			{
    				ProcessPath(Path);
    				Console.WriteLine("Successfully Processed Save Directory");
    			}
    			else
    			{
    				Console.WriteLine("Critical: Path is not valid.  Please check you have formatted it correctly (ex: C:\\Users\\YourName\\AppData\\Roaming\\SpaceEngineers\\Saves\\LongNumber\\SaveName)");
    				Environment.Exit(-1);
    			}
    
    		}
    
    		public static Boolean PathIsValid(string Path)
    		{
    			return Directory.Exists(Path);
    		}
    		public static Boolean FileIsValid(string Path)
    		{
    			return File.Exists(Path);
    		}
    
    		public static void ProcessPath(string Path)
    		{
    
    			DirectoryInfo PathInfo = new DirectoryInfo(Path);
    
    			if (!GetSandBoxPaths(PathInfo))
    			{
    				Console.WriteLine("FATAL: Unable to get Sandbox Paths (SBS/SBSPB)");
    				Environment.Exit(-1);
    			}
    
    			foreach (FileInfo file in PathInfo.GetFiles())
    			{
    				Boolean Success = true;
    				//Alien
    				if (file.Name.StartsWith(Save.AlienEnd))
    				{
    					Save.Alien = file.Name;
    					Success = ProcessPlanet(SaveFile.Planets.Alien, file);
    				}
    				//Earthlike
    				if (file.Name.StartsWith(Save.EarthlikeEnd))
    				{
    					Save.Earthlike = file.Name;
    					Success = ProcessPlanet(SaveFile.Planets.Earthlike, file);
    				}
    				//Europa
    				if (file.Name.StartsWith(Save.EuropaEnd))
    				{
    					Save.Europa = file.Name;
    					Success = ProcessPlanet(SaveFile.Planets.Europa, file);
    				}
    				//Mars
    				if (file.Name.StartsWith(Save.MarsEnd))
    				{
    					Save.Mars = file.Name;
    					Success = ProcessPlanet(SaveFile.Planets.Mars, file);
    				}
    				//Moon
    				if (file.Name.StartsWith(Save.MoonEnd))
    				{
    					Save.Moon = file.Name;
    					Success = ProcessPlanet(SaveFile.Planets.Moon, file);
    				}
    				//Titan
    				if (file.Name.StartsWith(Save.TitanEnd))
    				{
    					Save.Titan = file.Name;
    					Success = ProcessPlanet(SaveFile.Planets.Titan, file);
    				}
    				if (!Success)
    				{
    					Environment.Exit(-1);
    				}
    			}
    
    
    		}
    
    		public static Boolean GetSandBoxPaths(DirectoryInfo PathInfo)
    		{
    			string SbsPath = PathInfo.FullName + "\\SANDBOX_0_0_0_.sbs";
    			string SbsPBPath = PathInfo.FullName + "\\SANDBOX_0_0_0_.sbsPB";
    			if (FileIsValid(SbsPath) && FileIsValid(SbsPBPath))
    			{
    				Save.SandboxSbs = SbsPath;
    				Save.SandboxSbsPB = SbsPBPath;
    				return true;			
    			}
    			else
    			{
    				return false;
    			}
    
    		}
    
    		public static Boolean ProcessPlanet(SaveFile.Planets Planet, FileInfo file)
    		{
    			try
    			{
    				//Rename vx2
    				string NewPath = Path.GetDirectoryName(file.FullName) + "\\" + Save.GetEndName(Planet) + ".vx2";
    				file.MoveTo(NewPath);
    				//ProcessSandBoxes
    				ProcessSandBoxes(Planet);
    				return true;
    			}
    			catch (IOException ex)
    			{
    				Console.WriteLine("FATAL: " + ex.Message);
    				return false;
    			}
    		}
    
    		public static Boolean ProcessSandBoxes(SaveFile.Planets Planet)
    		{
    			string[] SBSData = File.ReadAllLines(Save.SandboxSbs);
    			string[] SBSPBData = File.ReadAllLines(Save.SandboxSbsPB);
    
    
    			string ReplaceString = Save.GetReplaceString(Planet);
    			ReplaceString = ReplaceString.Replace(".vx2", "");
    			string ReplaceString2 = "";
    
    			
    			//SBS
    			for (int i = 0; i < SBSData.Length - 1; i++)
    			{
    				SBSData[i] = SBSData[i].Replace(ReplaceString, Save.GetEndName(Planet));
    				if (ReplaceString2 != "")
    				{
    					SBSData[i] = SBSData[i].Replace(ReplaceString2, Save.GetEndName(Planet));
    				}
    				else
    				{
    					string FullString = GetFullString(SBSData[i], Planet);
    					if (FullString != "")
    					{
    						if (FullString != ReplaceString && FullString != Save.GetEndName(Planet))
    						{
    							ReplaceString2 = FullString;
    						}
    					}
    				}
    
    			}
    			File.WriteAllLines(Save.SandboxSbs, SBSData);
    
    			//SBSPB
    			for (int i = 0; i < SBSPBData.Length - 1; i++)
    			{
    				SBSPBData[i] = SBSPBData[i].Replace(ReplaceString, Save.GetEndName(Planet));
    				if (ReplaceString2 != "")
    				{
    					SBSPBData[i].Replace(ReplaceString2, Save.GetEndName(Planet));
    				}
    			}
    			File.WriteAllLines(Save.SandboxSbsPB, SBSPBData);
    			return true;
    		}
    
    		public static string GetFullString(string Line, SaveFile.Planets Planet)
    		{
    			string Prefix = "<StorageName>";
    			string Suffix = "</StorageName>";
    
    			if (Line.Contains(Save.GetEndName(Planet)) && Line.Contains(Prefix))
    			{
    				string ReturnLine = Line.Trim().Substring(Prefix.Length, Line.Trim().Length - (Prefix.Length + Suffix.Length));
    				return ReturnLine;
    			}
    			else
    			{
    				return "";
    			}
    		}
    
    	}
    
    	public class SaveFile
    	{
    		public enum Planets
    		{
    			Alien,
    			Earthlike,
    			Europa,
    			Mars,
    			Moon,
    			Titan
    		}
    
    		public string Alien = "";
    		public string Earthlike = "";
    		public string Europa = "";
    		public string Mars = "";
    		public string Moon = "";
    		public string Titan = "";
    
    		public string SandboxSbs = "";
    		public string SandboxSbsPB = "";
    
    		private string _AlienEnd = "Alien";
    		private string _EarthlikeEnd = "EarthLike";
    		private string _EuropaEnd = "Europa";
    		private string _MarsEnd = "Mars";
    		private string _MoonEnd = "Moon";
    		private string _TitanEnd = "Titan";
    		
    		public string AlienEnd
    		{
    			get
    			{
    				return _AlienEnd;
    			}
    		}
    		public string EarthlikeEnd
    		{
    			get
    			{
    				return _EarthlikeEnd;
    			}
    		}
    		public string EuropaEnd
    		{
    			get
    			{
    				return _EuropaEnd;
    			}
    		}
    		public string MarsEnd
    		{
    			get
    			{
    				return _MarsEnd;
    			}
    		}
    		public string MoonEnd
    		{
    			get
    			{
    				return _MoonEnd;
    			}
    		}
    		public string TitanEnd
    		{
    			get
    			{
    				return _TitanEnd;
    			}
    		}
    
    		public string GetReplaceString(Planets Planet)
    		{
    			switch (Planet)
    			{
    				case Planets.Alien:
    					return Alien;
    				case Planets.Earthlike:
    					return Earthlike;
    				case Planets.Europa:
    					return Europa;
    				case Planets.Mars:
    					return Mars;
    				case Planets.Moon:
    					return Moon;
    				case Planets.Titan:
    					return Titan;
    				default:
    					return "";
    			}
    		}
    		public string GetEndName(Planets Planet)
    		{
    			switch (Planet)
    			{
    				case Planets.Alien:
    					return AlienEnd;
    				case Planets.Earthlike:
    					return EarthlikeEnd;
    				case Planets.Europa:
    					return EuropaEnd;
    				case Planets.Mars:
    					return MarsEnd;
    				case Planets.Moon:
    					return MoonEnd;
    				case Planets.Titan:
    					return TitanEnd;
    				default:
    					return "";
    			}
    		}
    
    	}
    
    }
    
     
    Last edited: Apr 6, 2018
    • Like Like x 1
  2. Cetric Junior Engineer

    Messages:
    792
    So this is bascially a renaming tool for existing planets? Can you describe how to handle it for those of us who are no programmers/modders (as bloody myself)?
    --- Automerge ---
    I had been wanting for something to change the generic numbers and double names for planets and asteroids for a while...
    --- Automerge ---
    Or, let me add, could you include an option not just to cut out numbers in long names but a renaming function which changes a planet name in all relevant places to something the user specifies?
     
  3. Tim Wilson Trainee Engineer

    Messages:
    7
    It wasn't intended to be used as you're describing though it wouldn't be hard to actually do that I would imagine -- I'd have to prototype/test to make sure it didn't break anything. SE saves planet data (voxel stuff) into a save directory with a .vx2 extension. Problem is there's a bug that cause those names to get excessively long when you do a ton of voxel digging. To answer your third paragraph -- This just cleans up those .vx2 file names -- not the actual planet names in the game. Those are under a different xml tag in the files as far as I can tell but I'd need to do more research before I could say for sure. If thats the only place, as I said, it'd probably be easy to expand the tool to handle that too -- though it wasn't the original purpose of it.

    Edit: I'll compile this into a command line program and post a link later on to make it a bit easier if you actually desire to use the program as-is.

    Thanks!
     
    • Like Like x 2
  4. Cetric Junior Engineer

    Messages:
    792
    Let me just close by encouraging you to develop a tool which does what I hoped for. I am sure it will be a hit with most gamers who want to have personalized space this way - by giving new names to celestial bodies. Maybe could be published as a mod once it is finished?
    And you are right. Testing has to make sure it does not botch up the game files. So good luck. Perhaps some programmer from the modder front who reads this will want to join you if you hit on trouble? Keep us posted.
     
  5. CapRoope Trainee Engineer

    Messages:
    1
    I get this error when trying to run the script in Visual Studio. [​IMG]
    I have no experience in programming so I couldn't figure it out myself. I'd appreciate some help. :)
     
  6. Roxette Senior Engineer

    Messages:
    1,399
    Broken image link - try uploading it to a free image website like imgur and posting the link...

    @Cetric - I'm not sure what you're trying to achieve with planet naming as the names don't really appear anywhere in the game itself during play ?
     
  7. Cetric Junior Engineer

    Messages:
    792
    I have the habit to name things in game. With given names to celestial bodies I can tag builds, function groups to the place they are related to. Let's say a satellite chain from planet Utopia to planet Hephraistos II. It's better for immersion than having to use "from planet Earthlike-043728645 to planet Earthlike-073647721". Definitely.
    --- Automerge ---
    Some time ago I also bothered Midspace with a request to integrate a renaming function in his famous SE Toolbox. He pointed to the necessity of affecting two files alike so there would have to be a mechanism which prevents accidential renaming only one and the other would stay original, thus creating confusion.
     
  8. Tim Wilson Trainee Engineer

    Messages:
    7
    Got dragged off by distractions last week -- I'll try to get a compiled command line exe up this evening -- more than welcome to keep trying to get it working in VS if you want though! #TeachAManToFish

    @Cetric -- Haven't had a chance to look into the renaming function yet, I'll try to update if I can get around to it. Sorry :\

    Update:
    Download Link (9kb)

    Steps:
    1) Backup save folder first
    2) To use it just run command prompt (Start > Run > type cmd)
    3) Navigate to the folder it's in (ex: cd C:\Users\USERNAME\Downloads )
    4) Type VoxelCleanup <path to Save folder> (ex: VoxelCleanup ---C:\Users\USERNAME\AppData\Roaming\SpaceEngineers\Saves\LONGNUMBER\SaveFolder\) -- Change the bold parts to match your username/ID/Savefolder

    Should give you a Successfully Processed Save Directory when it's done. If you get any errors send me details and I'll take a look. :)
     
    Last edited: Apr 6, 2018
    • Like Like x 1
  9. DCam2016 Trainee Engineer

    Messages:
    22
    A really handy tool :) Do you think it would be much to add the ability for your tool to keep track of what it renames so you could undo changes in case anything goes wrong? The only reason I ask, is my save folder is enormous :D
     
  10. Tim Wilson Trainee Engineer

    Messages:
    7
    You don't need to do the entire folder, just the individual save folder. eg: If I have a save called "Moon Base Alpha", I just make a copy of that folder so I'll have "Moon Base Alpha" and "Moon Base Alpha (Copy)" sort of thing. If you're copying the entire "Saves\LongNumber\" folder you're definitely backing up way more than necessary here.

    That being said, I could definitely have it log something to a "vx2Clean.log" file in the saves\LongNumber root. I'll add that in when able.
     
  11. DCam2016 Trainee Engineer

    Messages:
    22
    Ah that's cool. I haven't actually used your tool. I was just reading the post and thought it was useful. The last time I backed up (or moved rather) my save folder, I thought... yeah I'm not doing that again :D
     
  12. Cetric Junior Engineer

    Messages:
    792
    Tool seems not to be able to read folder names with spaces between names, because I get an error message when trying to feed it a folder called "Down on planet Adlovy"
     
  13. Roxette Senior Engineer

    Messages:
    1,399
    Did you enclose it in quotes? eg VoxelCleanup.exe "76561198218741327\Empty World 2018-04-09 18-17"

    https://support.microsoft.com/en-us...-or-paths-with-spaces-require-quotation-marks
     
    Last edited: Apr 9, 2018
    • Informative Informative x 1
  14. Cetric Junior Engineer

    Messages:
    792
    Yeah, that did it. Afterwards message went like "Successfully processed file directory". Expected an opportunity popping up for me editing planet names, but alas, that's still science-fiction. :)
     
Thread Status:
This last post in this thread was made more than 31 days old.