diff --git a/Form1.cs b/Form1.cs index b658522..7ddc958 100644 --- a/Form1.cs +++ b/Form1.cs @@ -148,10 +148,17 @@ namespace SCJMapper_V2 /// private void InitActionTree( ) { + // default profile handling + // TODO ?? change the data path away from the app directory as this is not Win policy if installed in "Program Files" + String dataPath = ""; + SCDefaultProfile SD = new SCDefaultProfile( ); + SD.GetDefaultProfile( dataPath ); + String defProf = SD.DefaultProfileName; // either "" or a valid full filename + // build TreeView and the ActionMaps m_AT = new ActionTree( ); m_AT.Ctrl = treeView1; // the ActionTree owns the TreeView control - m_AT.LoadTree( ); // Init + m_AT.LoadTree( defProf ); // Init with default profile filepath // default JS to Joystick mapping - can be changed and reloaded from XML if ( tc1.TabCount > 0 ) { cbJs1.SelectedIndex = 0; m_AT.ActionMaps.js1 = cbJs1.Text; } diff --git a/Joystick/ActionTree.cs b/Joystick/ActionTree.cs index 02a1e57..f9747c3 100644 --- a/Joystick/ActionTree.cs +++ b/Joystick/ActionTree.cs @@ -15,7 +15,7 @@ namespace SCJMapper_V2 // Load MappingVars.csv into the ActionList and create the Control TreeView - public void LoadTree( ) + public void LoadTree( String defaultProfile ) { TreeNode tn = null; TreeNode[] cnl = { }; @@ -33,14 +33,24 @@ namespace SCJMapper_V2 DProfileReader dpReader = new DProfileReader( ); // we may read a profile TextReader txReader = null; - // 1st choice is a user given MappingVars.csv file in the appdir + // 1st choice is a user given MappingVars.csv file in the appdir - this is only compatibilty and testing if ( File.Exists( "MappingVars.csv" ) ) { txReader = new StreamReader( "MappingVars.csv" ); } - // second choice a defaultProfile.xml in the app dir + // second choice a defaultProfile.xml in given path + else if ( File.Exists( defaultProfile ) ) { + using ( StreamReader sr = new StreamReader( defaultProfile ) ) { + String buff = sr.ReadToEnd( ); + dpReader.fromXML( buff ); + } + if ( dpReader.ValidContent ) { + txReader = new StringReader( dpReader.CSVMap ); + } + } + // third choice a defaultProfile.xml in the app dir distributed with the application ??? to be deleted ??? else { - if ( File.Exists( "defaultProfile.xml" ) ) { - using ( StreamReader sr = new StreamReader( "defaultProfile.xml" ) ) { + if ( File.Exists( SCPath.DefaultProfileName ) ) { + using ( StreamReader sr = new StreamReader( SCPath.DefaultProfileName ) ) { String buff = sr.ReadToEnd( ); dpReader.fromXML( buff ); } @@ -78,7 +88,7 @@ namespace SCJMapper_V2 } }//for tn = new TreeNode( acm.name, cnl ); tn.Name = acm.name; // name it to find it.. - tn.ImageIndex = 0; tn.NodeFont = new Font( Ctrl.Font, FontStyle.Bold ); + tn.ImageIndex = 0; tn.NodeFont = new Font( Ctrl.Font, FontStyle.Bold ); Ctrl.BackColor = Ctrl.BackColor; // fix for defect TreeView (cut off bold text) Ctrl.Nodes.Add( tn ); // add to control if ( topNode == null ) topNode = tn; // once to keep the start of list @@ -203,7 +213,7 @@ namespace SCJMapper_V2 if ( !String.IsNullOrEmpty( ActionMaps.js6 ) ) repList += String.Format( "** js6 = {0}\n", ActionMaps.js6 ); if ( !String.IsNullOrEmpty( ActionMaps.js7 ) ) repList += String.Format( "** js7 = {0}\n", ActionMaps.js7 ); if ( !String.IsNullOrEmpty( ActionMaps.js8 ) ) repList += String.Format( "** js8 = {0}\n", ActionMaps.js8 ); - repList += String.Format( "\n"); + repList += String.Format( "\n" ); foreach ( ActionMapCls acm in ActionMaps ) { String rep = String.Format( "*** {0}\n", acm.name ); repList += rep; diff --git a/Packages.dgml b/Packages.dgml new file mode 100644 index 0000000..f76e2a3 --- /dev/null +++ b/Packages.dgml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SC/SCDefaultProfile.cs b/SC/SCDefaultProfile.cs new file mode 100644 index 0000000..3c34d7b --- /dev/null +++ b/SC/SCDefaultProfile.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Ionic.Zip; +using System.IO; + +namespace SCJMapper_V2 +{ + + /// + /// Finds and returns the DefaultProfile from SC GameData.pak + /// it is located in GameData.pak \Libs\Config + /// + class SCDefaultProfile + { + private Boolean m_valid = false; + public Boolean IsValid { get { return m_valid; } } + + private String m_fileName = ""; + public String DefaultProfileName { get { return m_fileName; } } + + /// + /// Extracts the file to destPath + /// the subpath will be retained + /// + /// Destination path to extract to + private void ExtractDefaultProfile( String destPath ) + { + String scp = SCPath.SCClientDataPath; + if ( String.IsNullOrEmpty( scp ) ) return; // sorry did not work + + using ( ZipFile zip = ZipFile.Read( SCPath.SCGameData_pak ) ) { + zip.CaseSensitiveRetrieval = false; + + ICollection gdpak = zip.SelectEntries( "name = " + SCPath.DefaultProfileName, SCPath.DefaultProfilePath_rel ); + if ( gdpak != null ) { + gdpak.FirstOrDefault( ).Extract( destPath, ExtractExistingFileAction.OverwriteSilently ); + m_fileName = Path.Combine( destPath, SCPath.DefaultProfilePath_rel ); + m_fileName = Path.Combine( m_fileName, SCPath.DefaultProfileName ); + m_valid = true; + } + } + } + + + /// + /// Deletes the extracted version of the defaultProfile + /// + /// Destination path to delete from + public void ClearDefaultProfile( String destPath ) + { + try { + String p = Path.Combine( destPath, SCPath.DefaultProfilePath_rel ); + File.Delete( Path.Combine( p, SCPath.DefaultProfileName ) ); + m_fileName = ""; + m_valid = false; + } + catch { } + } + + /// + /// Retrieves the newest defaultProfile from GameData.pak + /// It deletes the last retrieved one first + /// + /// Destination path to extract to + /// True if successfull; if false there is no old file left in the path + public Boolean GetDefaultProfile( String destPath ) + { + ClearDefaultProfile( destPath ); + ExtractDefaultProfile( destPath ); + return m_valid; + } + + } +} diff --git a/SC/SCPath.cs b/SC/SCPath.cs new file mode 100644 index 0000000..bf33985 --- /dev/null +++ b/SC/SCPath.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using Microsoft.Win32; + +namespace SCJMapper_V2 +{ + /// + /// Find the SC pathes and folders + /// + class SCPath + { + + /// + /// Try to locate the launcher under "App Paths" + /// + static private String SCLauncherPath1 + { + get + { + String scpath = ( String )Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\App Paths\StarCitizen Launcher.exe", "", null ); + if ( scpath != null ) { + return scpath; + } + return ""; + } + } + + /// + /// Try to locate the launcher under "Uninstall" + /// + static private String SCLauncherPath2 + { + get + { + String scpath = ( String )Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\StarCitizen", "DisplayIcon", null ); + if ( scpath != null ) { + return scpath; + } + return ""; + } + } + + + /// + /// Returns the base SC install path from something like "E:\G\StarCitizen\Launcher\StarCitizenLauncher.exe" + /// + static private String SCBasePath + { + get + { + String scp = SCLauncherPath1; + if ( String.IsNullOrEmpty( scp ) ) { + scp = SCLauncherPath2; + if ( String.IsNullOrEmpty( scp ) ) { + return ""; // sorry did not found a thing.. + } + } + // found the launcher + scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen\Launcher" + scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen" + return scp; + } + } + + + + /// + /// Returns the SC installation path + /// + static public String SCInstallPath + { + get + { + return SCBasePath; + } + } + + + /// + /// Returns the SC ClientData path e.g. "E:\G\StarCitizen\CitizenClient\Data" + /// + static public String SCClientDataPath + { + get + { + String scp = SCBasePath; + if ( String.IsNullOrEmpty( scp ) ) return ""; + // + scp = Path.Combine( scp, "CitizenClient" ); + scp = Path.Combine( scp, "Data" ); + return scp; + } + } + + + /// + /// Returns the SC ClientData path e.g. "E:\G\StarCitizen\CitizenClient\USER" + /// + static public String SCClientUSERPath + { + get + { + String scp = SCBasePath; + if ( String.IsNullOrEmpty( scp ) ) return ""; + // + scp = Path.Combine( scp, "CitizenClient" ); + scp = Path.Combine( scp, "USER" ); + return scp; + } + } + + + /// + /// Returns the SC GameData.pak file path e.g. "E:\G\StarCitizen\CitizenClient\Data\GameData.pak" + /// + static public String SCGameData_pak + { + get + { + String scp = SCClientDataPath; + if ( String.IsNullOrEmpty( scp ) ) return ""; + // + scp = Path.Combine( scp, "GameData.pak" ); + return scp; + } + } + + + /// + /// Returns the relative path of DefaultProfile.xml + /// + static public String DefaultProfilePath_rel + { + get + { + return @"Libs\Config"; + } + } + + /// + /// Returns the name of the DefaultProfile.xml + /// + static public String DefaultProfileName + { + get + { + return @"defaultProfile.xml"; + } + } + + + } +} diff --git a/SCJMapper-V2.csproj b/SCJMapper-V2.csproj index 0b0f1c3..b087cf7 100644 --- a/SCJMapper-V2.csproj +++ b/SCJMapper-V2.csproj @@ -42,6 +42,9 @@ SCJMapper_V2.Program + + packages\DotNetZip.Reduced.1.9.1.8\lib\net20\Ionic.Zip.Reduced.dll + $(SharpDXPackageBinDir)\SharpDX.dll @@ -81,6 +84,8 @@ + + Form1.cs diff --git a/packages.config b/packages.config index 191e35d..e5778dd 100644 --- a/packages.config +++ b/packages.config @@ -1,5 +1,6 @@  + \ No newline at end of file diff --git a/packages/DotNetZip.Reduced.1.9.1.8/DotNetZip.Reduced.1.9.1.8.nupkg b/packages/DotNetZip.Reduced.1.9.1.8/DotNetZip.Reduced.1.9.1.8.nupkg new file mode 100644 index 0000000..5dbbf5f Binary files /dev/null and b/packages/DotNetZip.Reduced.1.9.1.8/DotNetZip.Reduced.1.9.1.8.nupkg differ diff --git a/packages/DotNetZip.Reduced.1.9.1.8/lib/net20/Ionic.Zip.Reduced.dll b/packages/DotNetZip.Reduced.1.9.1.8/lib/net20/Ionic.Zip.Reduced.dll new file mode 100644 index 0000000..9622cc5 Binary files /dev/null and b/packages/DotNetZip.Reduced.1.9.1.8/lib/net20/Ionic.Zip.Reduced.dll differ