V 2.33 - Build 67 BETA

- update for SC 3.0.0 Alpha public
- fix - finding SC game folder - may work automatically for 3.0 Alpha else define it in Settings
- add - get the defaultProfile.xml from LIVE\data.p4k file if possible (real game assets)
- improvement - caching def profile once it is read from disk
- removed - old SC path and folder locators (SCJM does not longer work with pre 3.0 game)
- removed - reference to Iconic.Zip DLL (replaced with Zstd)
- update - defaultProfile.xml as last resort from PTU 3.0-695052 (Dec 18, build)

- move and re-group devices etc.
pull/104/head v2.33beta
bm98 6 years ago
parent 6a76ed4cfc
commit 9696eb1752

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace SCJMapper_V2
namespace SCJMapper_V2.Common
{
/// <summary>
/// Provide the colors used

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Media;
namespace SCJMapper_V2
namespace SCJMapper_V2.Common
{
public class MySounds
{

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SCJMapper_V2
namespace SCJMapper_V2.Devices
{
/// <summary>

@ -1,14 +1,14 @@
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Keyboard;
using SCJMapper_V2.Mouse;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.Devices.Keyboard;
using SCJMapper_V2.Devices.Mouse;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2
namespace SCJMapper_V2.Devices
{
/// <summary>
/// Collects and provides the device instances throughout the application

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2
namespace SCJMapper_V2.Devices
{
public class DeviceList : List<DeviceCls>
{

@ -8,7 +8,9 @@ using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
namespace SCJMapper_V2.Gamepad
using SCJMapper_V2.Common;
namespace SCJMapper_V2.Devices.Gamepad
{
/// <summary>
/// Handles one JS device as DXInput device

@ -1,4 +1,4 @@
namespace SCJMapper_V2.Gamepad
namespace SCJMapper_V2.Devices.Gamepad
{
partial class UC_GpadPanel
{

@ -7,7 +7,7 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SCJMapper_V2.Gamepad
namespace SCJMapper_V2.Devices.Gamepad
{
public partial class UC_GpadPanel : UserControl
{

@ -1,4 +1,4 @@
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
partial class FormReassign
{

@ -7,7 +7,7 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
partial class FormReassign : Form
{

@ -8,7 +8,9 @@ using System.Windows.Forms;
using System.Drawing;
using System.Text.RegularExpressions;
namespace SCJMapper_V2.Joystick
using SCJMapper_V2.Common;
namespace SCJMapper_V2.Devices.Joystick
{
/// <summary>
/// Handles one JS device as DXInput device

@ -5,7 +5,9 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SCJMapper_V2.Joystick
using SCJMapper_V2.Common;
namespace SCJMapper_V2.Devices.Joystick
{
public class JoystickList : List<JoystickCls>, IDisposable
{

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
public struct JsReassingR
{

@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Xml;
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
/// <summary>
/// Maintain actionmap Modifiers

@ -1,4 +1,4 @@
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
partial class UC_JoyPanel
{

@ -7,7 +7,7 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
public partial class UC_JoyPanel : UserControl
{

@ -6,7 +6,7 @@ using System.Xml;
using System.IO;
using System.Xml.Linq;
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
/// <summary>
/// Maintains an CustomisationUIHeader - something like:

@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System;
using OpenTK;
namespace SCJMapper_V2.Joystick
namespace SCJMapper_V2.Devices.Joystick
{
/// <summary>
/// contains the x(in) and y(out) points of the nonlin curve for joysticks (MAX 3 interpolation pts)

@ -7,7 +7,9 @@ using System.Windows.Forms;
using SharpDX;
using System.Text.RegularExpressions;
namespace SCJMapper_V2.Keyboard
using SCJMapper_V2.Common;
namespace SCJMapper_V2.Devices.Keyboard
{
/// <summary>
/// Handles one Keyboard device as DXInput device
@ -138,6 +140,23 @@ namespace SCJMapper_V2.Keyboard
case ( int )Key.LeftControl: ctrlMod += "lctrl+"; break;
case ( int )Key.RightControl: ctrlMod += "rctrl+"; break;
// function keys first - modifier ??
case (int)Key.F1: key += "f1+"; break;
case (int)Key.F2: key += "f2+"; break;
case (int)Key.F3: key += "f3+"; break;
case (int)Key.F4: key += "f4+"; break;
case (int)Key.F5: key += "f5+"; break;
case (int)Key.F6: key += "f6+"; break;
case (int)Key.F7: key += "f7+"; break;
case (int)Key.F8: key += "f8+"; break;
case (int)Key.F9: key += "f9+"; break;
case (int)Key.F10: key += "f10+"; break;
case (int)Key.F11: key += "f11+"; break;
case (int)Key.F12: key += "f12+"; break;
case (int)Key.F13: key += "f13+"; break;
case (int)Key.F14: key += "f14+"; break;
case (int)Key.F15: key += "f15+"; break;
// all keys where the DX name does not match the SC name
// Numpad
case ( int )Key.NumberLock: key += "numlock+"; break;
@ -206,12 +225,14 @@ namespace SCJMapper_V2.Keyboard
// all where the lowercase DX name matches the SC name
default:
if ( ( ( int )k >= ( int )Key.Q ) && ( ( int )k <= ( int )Key.P ) ) key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else if ( ( ( int )k >= ( int )Key.A ) && ( ( int )k <= ( int )Key.L ) ) key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else if ( ( ( int )k >= ( int )Key.Z ) && ( ( int )k <= ( int )Key.M ) ) key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
if ( ( ( int )k >= ( int )Key.Q ) && ( ( int )k <= ( int )Key.P ) )
key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else if ( ( ( int )k >= ( int )Key.A ) && ( ( int )k <= ( int )Key.L ) )
key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else if ( ( ( int )k >= ( int )Key.F1 ) && ( ( int )k <= ( int )Key.F10 ) ) key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else if ( ( ( int )k >= ( int )Key.F11 ) && ( ( int )k <= ( int )Key.F15 ) ) key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else if ( ( ( int )k >= ( int )Key.Z ) && ( ( int )k <= ( int )Key.M ) )
key += k.ToString( ).ToLowerInvariant( ) + "+"; // ranges are based on the enum values...
else { } // no other ones handled
break;

@ -8,7 +8,9 @@ using SharpDX;
using System.Reflection;
using System.Text.RegularExpressions;
namespace SCJMapper_V2.Mouse
using SCJMapper_V2.Common;
namespace SCJMapper_V2.Devices.Mouse
{
/// <summary>
/// Handles one Mouse device as DXInput device

@ -3,7 +3,7 @@
using System;
namespace SCJMapper_V2.Options
namespace SCJMapper_V2.Devices.Options
{
public class DeviceOptionParameter : ICloneable
{
@ -99,7 +99,7 @@ namespace SCJMapper_V2.Options
m_saturationSupported = false;
m_saturation = "1.000";
m_saturationEnabled = false;
if ( Joystick.JoystickCls.IsDeviceClass( m_deviceClass ) ) {
if ( Devices.Joystick.JoystickCls.IsDeviceClass( m_deviceClass ) ) {
m_saturationSupported = true;
if ( !string.IsNullOrEmpty( sa ) ) {
m_saturation = sa;

@ -1,10 +1,11 @@
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using System;
using System;
using System.Collections.Generic;
using System.Xml;
namespace SCJMapper_V2.Options
using SCJMapper_V2.Actions;
using SCJMapper_V2.Devices.Joystick;
namespace SCJMapper_V2.Devices.Options
{
/// <summary>
/// set of parameters to tune the Joystick

@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Xml;
using System.IO;
using System.Xml.Linq;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.Devices.Gamepad;
using System.Linq;
namespace SCJMapper_V2.Options
namespace SCJMapper_V2.Devices.Options
{
/// <summary>
/// Maintains an Deviceoptions - something like:

@ -1,4 +1,4 @@
namespace SCJMapper_V2.Options
namespace SCJMapper_V2.Devices.Options
{
partial class FormOptions
{

@ -1,5 +1,5 @@
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.OGL;
using System;
using System.Collections.Generic;
@ -12,7 +12,9 @@ using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace SCJMapper_V2.Options
using SCJMapper_V2.Actions;
namespace SCJMapper_V2.Devices.Options
{
public partial class FormOptions : Form
{

@ -6,9 +6,8 @@ using System.Xml;
using System.IO;
using System.Xml.Linq;
using System.Windows.Forms;
using SCJMapper_V2.Joystick;
namespace SCJMapper_V2.Options
namespace SCJMapper_V2.Devices.Options
{
/// <summary>
/// Maintains an Options - something like:
@ -107,7 +106,7 @@ namespace SCJMapper_V2.Options
m_tuning.Add( "turret_aim_yaw", new DeviceTuningParameter( "turret_aim_yaw", device ) );
// Gamepad specific
if ( Gamepad.GamepadCls.IsDeviceClass( device.DevClass ) ) {
if ( Devices.Gamepad.GamepadCls.IsDeviceClass( device.DevClass ) ) {
m_tuning.Add( "fps_view_pitch", new DeviceTuningParameter( "fps_view_pitch", device ) );
m_tuning.Add( "fps_view_yaw", new DeviceTuningParameter( "fps_view_yaw", device ) );

@ -4,10 +4,10 @@ using System.Linq;
using System.Text;
using System.Xml;
using System.Windows.Forms;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.Devices.Gamepad;
namespace SCJMapper_V2.Options
namespace SCJMapper_V2.Devices.Options
{
public class OptionsInvert
{

@ -1,5 +1,5 @@
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using System;
using System.Collections.Generic;
using System.IO;
@ -8,7 +8,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace SCJMapper_V2.Options
namespace SCJMapper_V2.Devices.Options
{
public class Tuningoptions : CloneableDictionary<string, OptionTree>, ICloneable
{

@ -15,8 +15,8 @@
{
timer1.Stop( );
// Unacquire all DirectInput objects.
foreach ( Joystick.JoystickCls js in DeviceInst.JoystickListRef ) js.FinishDX( );
DeviceInst.JoystickListRef.Clear( );
foreach ( Devices.Joystick.JoystickCls js in Devices.DeviceInst.JoystickListRef ) js.FinishDX( );
Devices.DeviceInst.JoystickListRef.Clear( );
if ( disposing && ( components != null ) ) components.Dispose( );
if ( disposing && ( m_AT != null ) ) m_AT.Dispose( );
@ -91,7 +91,7 @@
this.tdiAddMod3 = new System.Windows.Forms.ToolStripMenuItem();
this.tc1 = new System.Windows.Forms.TabControl();
this.tabJS1 = new System.Windows.Forms.TabPage();
this.UC_JoyPanel = new SCJMapper_V2.Joystick.UC_JoyPanel();
this.UC_JoyPanel = new SCJMapper_V2.Devices.Joystick.UC_JoyPanel();
this.panel1 = new System.Windows.Forms.Panel();
this.btClip = new System.Windows.Forms.Button();
this.txRebind = new System.Windows.Forms.TextBox();
@ -1478,7 +1478,7 @@
private System.Windows.Forms.ToolStripMenuItem tsiSaveAs;
private System.Windows.Forms.SaveFileDialog SFD;
private System.Windows.Forms.ImageList IL;
private Joystick.UC_JoyPanel UC_JoyPanel;
private Devices.Joystick.UC_JoyPanel UC_JoyPanel;
private System.Windows.Forms.TableLayoutPanel tlpanel;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;

@ -10,13 +10,16 @@ using System.Windows.Forms;
using SharpDX.DirectInput;
using System.IO;
using SCJMapper_V2.Common;
using SCJMapper_V2.Actions;
using SCJMapper_V2.SC;
using SCJMapper_V2.Table;
using SCJMapper_V2.Keyboard;
using SCJMapper_V2.Mouse;
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Options;
using SCJMapper_V2.Devices;
using SCJMapper_V2.Devices.Keyboard;
using SCJMapper_V2.Devices.Mouse;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.Devices.Options;
namespace SCJMapper_V2
{
@ -414,7 +417,7 @@ namespace SCJMapper_V2
// provide the display items (init)
m_AT.DefineShowOptions( cbxShowJoystick.Checked, cbxShowGamepad.Checked, cbxShowKeyboard.Checked, cbxShowMouse.Checked, cbxShowMappedOnly.Checked );
// Init with default profile filepath
m_AT.LoadProfileTree( SCDefaultProfile.DefaultProfileName, addDefaultBinding );
m_AT.LoadProfileTree( addDefaultBinding );
lblProfileUsed.Text = SCDefaultProfile.UsedDefProfile; // SCA 2.2 show used profile
// Activation Update
@ -853,7 +856,7 @@ namespace SCJMapper_V2
{
AutoTabXML_Assignment( EATabXML.Tab_XML );
rtb.Text = SCDefaultProfile.DefaultProfile( SCDefaultProfile.DefaultProfileName );
rtb.Text = SCDefaultProfile.DefaultProfile( );
}
private void btGrab_Click( object sender, EventArgs e )

@ -7,6 +7,8 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
using SCJMapper_V2.Actions;
namespace SCJMapper_V2
{
partial class FormSettings : Form

@ -1,6 +1,8 @@
The MIT License (MIT)
Copyright (c) 2016 bm98
For SCJMapper:
Copyright (c) 2017 bm98
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -18,4 +20,118 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
SOFTWARE.
-------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------
Included components
-------------------------------------------------------------------------------------
BSD License
For ZstdNet software
Copyright (c) 2016-2017, SKB Kontur. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name SKB Kontur nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------------
BSD License
For Zstandard software
Copyright (c) 2016-present, Facebook, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name Facebook nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-------------------------------------------------------------------------------------
Apache License, Version 2.0
For log4net http://logging.apache.org/log4net/license.html
-------------------------------------------------------------------------------------
Copyright (c) 2010-2015 SharpDX - Alexandre Mutel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-------------------------------------------------------------------------------------
The Open Toolkit library license
Copyright (c) 2006 - 2014 Stefanos Apostolopoulos <stapostol@gmail.com> for
the Open Toolkit library.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in the
Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------------------------

@ -8,17 +8,16 @@ using System.Text;
using System.Windows.Forms;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms.DataVisualization.Charting;
using SCJMapper_V2.Actions;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.Devices.Options;
using SCJMapper_V2.OGL.TextureLoaders;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Options;
namespace SCJMapper_V2.OGL
{

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion( "2.32.0.66" )]
[assembly: AssemblyFileVersion( "2.32.0.66" )]
[assembly: AssemblyVersion( "2.33.0.67" )]
[assembly: AssemblyFileVersion( "2.33.0.67" )]

@ -1,9 +1,10 @@
SCJMapper-V2<br>
============<br>
<br>
SC Joystick Mapper (.Net 4; using sharpDX/OpenTK wrapper)<br>
this should work with Win8.x Win 10 out of the box<br>
SC Joystick Mapper (.Net 4.5.2; using sharpDX/OpenTK wrapper)<br>
this should work with Win7, Win8.x Win 10 out of the box<br>
<br>
Built using Windows Forms - Issues with display scaling may be encountered - set display scaling to 100%.
<br>
using sharpDX 2.6.3 .net wrapper (http://sharpdx.org/)<br>
<br>
@ -15,8 +16,9 @@ using OpenTK.1.1.1589.5942 .net wrapper (http://www.opentk.com/)<br>
NET40\OpenTK.dll<br>
NET40\OpenTK.GLControl.dll<br>
<br>
NET20\Ionic.Zip.Reduced.dll<br>
net40-full\log4net.dll<br>
using ZstdNet 1.3.1 (https://www.nuget.org/packages/ZstdNet/)<br>
<br>
using log4net.dll<br>
<br>
Built with VisualStudio 2017 Community free version<br>
<br>
@ -33,6 +35,9 @@ This file is licensed under the Creative Commons Attribution 2.0 Generic license
At Toyomi fishermen's wharf, Tokyo.<br>
Author: Author Masato OHTA<br>
<br>
SC_Area18, _GrimHex, _DyingStar, _BrokenMoon, _Kareah
by Rellim (SC handle)
<br>
OutThere1 and 3 made with Spacescape:<br>
http://alexcpeterson.com/spacescape<br>
<br>

@ -0,0 +1,289 @@
SC Joystick Mapper V 2.33 - Build 67 BETA
(c) Cassini, StandardToaster - 23-Dec-2017
Contains 12 files + graphics:
SCJMapper.exe The program (V2.33)
SCJMapper.exe.config Program config (V2.33) - MUST be in the same folder as the Exe file
SharpDX.DirectInput.dll Managed DirectInput Assembly - MUST be in the same folder as the Exe file
SharpDX.dll Managed DirectX Assembly - MUST be in the same folder as the Exe file
OpenTK.dll Managed OpenGL Assembly - MUST be in the same folder as the Exe file
OpenTK.GLControl.dll Managed OpenGL Assembly - MUST be in the same folder as the Exe file
ZstdNet.dll Managed Zip Assembly (v2.33) - MUST be in the same folder as the Exe file
x64/libzstd.dll Native dll for ZstdNet (v2.33) - MUST be in the same folder as the Exe file
x86/libzstd.dll Native dll for ZstdNet (v2.33) - MUST be in the same folder as the Exe file
log4net.dll Managed Logging Assembly - MUST be in the same folder as the Exe file
log4net.config.OFF Config file for logging - To use it - rename as log4net.config and run the program
then look for trace.log in the same folder
SCJMapper_QGuide V2.30beta.pdf Quick Guide
ReadMe.txt This file
graphics folder Skybox Images (V2.32) - graphics folder MUST be in the same folder as the Exe file
NOTE V 2.33:
search order for defaultProfile.xml to build the action tree is:
1. directory where SCJMapper Exe is located
2. directory of <SC>\LIVE\USER
3. extract from <SC>\LIVE\Data.p4k
4. extract from SCJMapper exe file (derived from 3.0 build 695052)
--> in order to get always the most current one use 3. (and therefore remove the ones in 1. and 2.)
--> The one used is shown below the actionTree (Profile: ....)
Read the Guide first RTFM ;-)
Put all files into one folder and hit SCJMapper.exe to run it
For Updates and information visit:
https://github.com/SCToolsfactory/SCJMapper-V2
Scanned for viruses before packing...
cassini@burri-web.org
Changelog:
V 2.33 - BETA Build 67
- update for SC 3.0.0 Alpha public
- fix - finding SC game folder - may work automatically for 3.0 Alpha else define it in Settings
- add - get the defaultProfile.xml from LIVE\data.p4k file if possible (real game assets)
- improvement - caching def profile once it is read from disk
- removed - old SC path and folder locators (SCJM does not longer work with pre 3.0 game)
- removed - reference to Iconic.Zip DLL (replaced with Zstd)
- update - defaultProfile.xml as last resort from PTU 3.0-695052 (Dec 18, build)
V 2.32 - BETA Build 66
- add - path to defaultProfile can be in USER directory of SC
- add - some skyboxes from game captures (thanks to Rellim)
- removed - PTU folders in Settings - no longer used in PTU 3.0
- fix - finding SC game folder - may work automatically for PTU 3.0 else define it in Settings
- update - defaultProfile from PTU 3.0-689345 (Dec 15, build)
V 2.30 - BETA Build 64
- add - Tab to show all mappings for the current input (Tabbed with XML other Dump items)
- add - Setting (enabled, disabled -> default) to automatically switch the new tabs - either Input or Dump
- add - addbind of Mouse input is possible for Keyboard actions - seems to work somehow in the game...
- improvement - mouse mappings in kbd entries in defaultProfile are collected as mouse now and allowed to map
- improvement - removed some unneeded tree scans - to speed things up
- fix - issue with user activations modes while dumping the mapping list
- fix - issue with loading a map with gamepad mappings and the gamepad is not connected
- fixes and refacturing while encountered...
- update - doc SCJMapper_QGuide V2.30beta.pdf
V 2.29 - BETA Build 63
- add - Calibrate gamepad thumb axes (press ABXY buttons all together and wait 2 sec - should zero all 4 axes)
- fix #56 - exception when entering Tuning
- fix - wrong gamepad action codes (xi1_xi_command instead of xi1_command)
- fix - some more issues with gamepads
- fix - options did not properly update when assigning them to another cmd or clearing the entry
- improvement - Options Dialog selection and deselection of items improved
- improvement - Tuning Dialog selection and deselection of items improved
- improvement - Dump Log: added some more interesting captures from the game log file
- improvement - Win7 / Win10 hidden text/controls with High DPI scaling issues partly resolved
- update - doc SCJMapper_QGuide V2.29beta.pdf
V 2.28 - BETA Build 62
- add #48 - Tune Strafe controls
- add - "Options ..." dialog to edit all device and control options
- add - 2 more three 3D scenes for Tuning
- improvement #49 - Mapping area: Current mapping is shown
- improvement - Gamepad support improved, Tab is now always the most left one if gamepads are enabled
- improvement - Dump Log: added some more interesting captures from the game log file
- improvement - Tuning is now closer to CIG implementation, remove Sensitivity, add Saturation instead
- fix #51 - accepting multiple actionmaps in default profile (collects only the first one found)
- fix - bug re- joystick hats (affected No 2..4)
- fixes and refacturing while encountered...
- update - fallback default profile from SC 2.6.3 alpha
- update - doc SCJMapper_QGuide V2.28beta.pdf
V 2.27 - BETA Build 61
- add - Collapse/Expand in context menu in Mapping tree
- improvement - actionmaps are taken from the defaultProfile and will no longer need a program update
- improvement - rename Blend to Disable
- fix - an issue in Seetings for actionmap ignore handling
- update - fallback default profile from SC 2.6.0 alpha
- update - doc SCJMapper_QGuide V2.27beta.pdf
V 2.26 - BETA Build 60
- add - new actionmaps from SC 2.5.0 alpha to choose from in Settings
- update - fallback default profile from SC 2.5.0 alpha
V 2.25 - BETA Build 59
- fix - an issue in parsing options from imported maps
- add - an option to show the actiontree as CSV list with more/less details (change in Settings)
- improvement - In table view add possibility to Blend All visible unmapped entries
V 2.24 - BETA Build 58
- fix - some trouble in SC path finding
V 2.23 - BETA Build 57
- update - Using .Net 4.5.2 Now (seems to handle some scaling issues WinForm apps)
- update - Try to find the SC path also as StarCitizen\Live (instead of Public) was mentioned for SC2.2.2 onwards ???
- fix - addbind UNDEF removed when assigned
- improvement - Issue a infobox if the Client folder cannot be found
(please submit the complete folder structure of your installation as bug report ...)
- add - a table display for mappings
- some internal stuff (namespaces etc)
- update - doc SCJMapper_QGuide V2.23beta.pdf
V 2.22 - BETA Build 56
- fix - try again to fix Win10 scaling issues for some PCs (hidden assignment area)
- improvement - actions with a profile modifier attached will show underlined in the action tree
- improvement - less offensive gamepad color mark ...
- add - a button to dump the used defaultProfile in the right area
- some internal stuff
- update - doc SCJMapper_QGuide V2.22beta.pdf
V 2.21 - BETA Build 55
- fix #40 added Tab entry in Ctrl. context menu
- fix - try to fix Win10 scaling issues (hidden assignment area)
- fix - profile tree color indication also applied when re-reading defaultProfile
- improvement - enumerates up to 12 devices now (though not tested as I don't have 12 ..)
- add - use of SCA 2.2 provided defaultProfile (new location and format)
- add - indication of the used defaultProfile
- add - built in defaultProfile updated to SCA 2.2
V 2.19 - BETA Build 52
- fix #37 improved defaultProfile Parsing
- fix #38 locale issue - changed App number formatting to US
- fix #39 changed equal to equals string for kbd entry
- add - default actionmap to choose from (it is on the ignore list)
V 2.18 - BETA Build 51
- fix - layout works now for Win10
- fix - uses game defaultProfile again
- fix - keyboard command for all Ctrl keys fixed
- fix - keyboard command formatting
- improvement - timeout ~4 sec for kbd modifiers in Joystick Mode (Esc no longer needed)
- improvement - ActivationMode handling finished
- improvement - user ActivationMode change indication in mapping tree
- improvement - Blending adds multiTap=1 to overwrite double taps
- improvement - Dump List: added ActivationModes; device checkBox applied to list
- update - doc SCJMapper_QGuide V2.18beta.pdf
V 2.17 - BETA Build 50
- update - Updated for SC Alpha 2.0/2.1PTU using new actionmap syntax (no longer use device attribute)
- update - Complete new QuickReference Guide
- update - Supports actionmaps with <profile version="1" optionsVersion="2" rebindVersion="2">
- add - ActivationMode - Use Context Menu in ActionTree (or read the manual)
- add - PTU file usage in Settings
- add - Prepared JS Modifiers (but SC cannot right now - so it is disabled)
- add - full mouse settings
- improvement - some GUI improvements
- improvement - reworked blending
- removed - global JS or GP blend options in Settings
- removed - ignoreversion from Settings
- NOTE: - Dump Log does not work right now as CIG does no longer list detected controllers in the log file
- NOTE: - Right now a number of binds behave erratically e.g. addbind does not work at all
so be aware that your map is not necessarily wrong but the game may just have a bug there
V 2.16 - BETA Build 49
- update - Updated for AC Alpha 1.3 defaultProfile does no longer have js1_ or xi_ marks form commands
- NOTE: - Dump Log does not work right now as CIG does no longer list detected controllers in the log file
V 2.15 - BETA Build 48
- update - Updated for AC Alpha 1.1.6 new files locations to find files and mappings
- NOTE: - Dump Log does not work right now as CIG does no longer list detected controllers in the log file
V 2.14 - BETA Build 47
- update - added new defaultProfile (CIG allows some more joystick mappings)
V 2.13 - BETA Build 46
- update - added new defaultProfile and actionmaps from AC 1.1.1
- add - keyboard modifier for joystick (e.g. rctrl+js1_xy) - Press ESC to clear modifiers
- fix - device checkboxes are now applied after Reassign
- fix - invert checkbox handling (removed flight invert - use the one in Tuning)
- fix - Add UICustomization Header and Devices List in any case
V 2.12 - BETA Build 45
- improvement - SCJM maintains mappings in USER rather than data folder (AC 1.03)
- improvement - UICustomization Header for joystick updated (label is the filename minus "layout_") (AC 1.03)
V 2.11 - BETA Build 44
- fix - reading of deadzone value (if not a number should not break anymore)
- fix - writing the proper deadzone XML if first used
- fix - reading addbind commands from existing mappings will appear now in the tree
- improvement - better handling of the default mapping name from config file
- improvement - mapping name added to XML mapping (first line comment extended with mapping name)
V 2.10 - Build 43 - Production
- new feature - added Action Tree context menu for Assign, Clear and Blend
- fix - issue for Js Reassignment if more than one was not yet assigned
- improvement - Right click in Action Tree selects the items (no need to select and then right click anymore)
V 2.10 - BETA Build 41
- fix - issue with null ptr assignment in Device Tuning (review and fix of AC1.0 changes)
- fix - disabled first joystick tab when gamepad is second or later
- improvement - added tooltips for device tabs showing Name and GUID
- improvement - added full 4 number version for beta builds
V 2.10 - BETA Build 40
- rework for AC 1.0
- new feature - add DumpLog to get the AC detected Controller assignments from logfile
- new feature - add Invert checkboxes for supported option items
- new feature - context menu in treeview allows to add/delete action sub items (support addbind mapping in XML)
- update - cannot longer assign cross device mappings (AC 1.0 related - use addbind above)
- update - new options naming and structure (not compatible with pre 2.10 - delete them in the file and then reload)
- update - Profile Version to 1
V 2.8 - BETA Build 37
- new feature - add checkboxes to show Joystick, Gamepad, Kbd and Mapped Only
- fix - Blended ones don't reload with proper visual
V 2.8 - BETA Build 36
- new feature - add invert for single mappings
- improvement - initialization and assignment of Joystick devices
V 2.8 - BETA Build 34
- new feature - add keyboard input
- new feature - add gamepad input as xboxpad
- new feature - add gamepad for tuning
- new feature - blend single entries with <Space>
- fix - tuning copy to all axis now applies immediately
- improvement - cleanup of some inconsistencies
V 2.7 - Build 33
- fix - if an axis is not mapped the prog will not longer crash (was null ptr exception)
- doc update 2.7
V 2.7 - BETA
- new feature - Joystick Tuning
V 2.6
- fix - taking actionmaps from config file now works
- improvement - added actionmap vehicle_driver
V 2.5
- new feature - support and maintain option tags
- improvement - support and maintain version and ignoreversion attribute / can force ignoreversion="1"
- improvement - makes backup copy before each save (in my documents e.g. layout_my_xyz.xml.backup)
- Update of the Guide for V2.5
V 2.4
- improvement - add new actionmaps for AC 0.9 (flycam, spaceship_turret)
- improvement - supports now assignment of js1 .. js8 - SC may not support all though...
- Update of the Guide for V2.4
V 2.3
- new feature - allow reassignment of the jsN group
- improvement - uniquely identified devices with the same name (use GUID)
- improvement - shows jsN assignment in Joystick tab
- improvement - detection of the SC install path extended to one more Registry entry
- fix - blend unmapped works properly now
- fix - manual entry of SC directory works now
- Update of the Guide for V2.3
V 2.2
- new feature - option to ignore actionmaps in Settings
- improvement - add actionmaps for multiplayer, singleplayer, player
- improvement - GUI layout of Joystick tabs for more than 4 devices
- Update of the Guide for V2.2
V 2.1
- program is maintained at "https://github.com/SCToolsfactory/SCJMapper-V2/releases"
- new feature - option to blend unmapped actions
- improvement - ignore buttons in Settings
- improvement - override the built in detection of the SC folder in Settings
- added - trace log for resolving crash and other issues
- Update of the Guide for V2.1
V 2.0
- program is maintained at "https://github.com/bm98/SCJMapper-V2/releases"
- new feature - get defaultProfile.xml from game assets
- new feature - get actionsmaps from game assets
- new feature - reset to defaults
- new feature - load and save own maps to gamefolders (makes backup in My Documents\SCJMapper)
- new feature - filter the action tree
- new feature - drag and drop an mapping file into the XML window
- new feature - make throttle assignment for any axis
- improved joystick detection (jitter avoidance, limit can be set in Program config file)
- improved button detection (blend buttons that are always on)
- improved sizeable window
- improved settings persist between sessions
- Update of the Guide for V2.0
- removed defaultProfile.xml from distribution (REMOVE IT FROM YOUR FOLDER - else it will be taken as action list)
V 1.4PRE
- using a new Managed DirectX assembly and built with .Net4 (Hope this works for Win8.1)
- added Joystick properties and Axis Names from the Joystick driver
V 1.3
- new feature - read the original defaultProfile.xml from SC to derive the actions (must be in the EXE folder)
- added support for up to 8 devices
- added multibinding i.e. bind the same action to multiple buttons, one for kbd, one for xbox etc. if the profile supports it
- added Dump List - a readable list of the commands (can be saved as txt file - using Save as)
- fixed "Find 1st"
- Update of the Guide
- removed MappingVars file from distribution (REMOVE IT FROM YOUR FOLDER - else it will be taken as action list)
V 1.2
- added support for rebinding xboxpad and ps3pad
- added Find 1st for a Control
- fixed Hat direction not maintained as last Control used
- some GUI refinements
- Update of the Guide (incl MappingVar.csv format)
MappingVar file
- added commands that where missing
- changed from keyboard to xboxpad rebinding where possible to leave kbd intact
V 1.1
- fixed issue with less than 3 joysticks attached
V 1.0 initial

@ -249,7 +249,7 @@ namespace SCJMapper_V2.SC
/// Returns the list of ActivationMode names
/// </summary>
/// <returns>A list of names</returns>
public List<string> Names
public IList<string> Names
{
get
{

@ -4,6 +4,8 @@ using System.Text;
using System.Xml;
using System.IO;
using SCJMapper_V2.Actions;
namespace SCJMapper_V2.SC
{
/// <summary>
@ -131,7 +133,8 @@ namespace SCJMapper_V2.SC
if ( attr.ContainsKey( "ActivationMode" ) ) {
actModeName = attr["ActivationMode"];
multiTap = ActivationModes.Instance.MultiTapFor( actModeName ).ToString( ); // given by the already collected items
} else {
}
else {
// name remains default - we handle multiTaps only here
multiTap = "1"; // default if not changed in the action to may be 2 or so..
if ( attr.ContainsKey( "multiTap" ) ) {
@ -148,9 +151,10 @@ namespace SCJMapper_V2.SC
ac.defBinding = attr["joystick"];
ac.defActivationMode = actMode;
if ( ac.defBinding == " " ) {
ac.defBinding = Joystick.JoystickCls.BlendedInput;
ac.defBinding = Devices.Joystick.JoystickCls.BlendedInput;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
} else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
}
else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
ac.defBinding = "js1_" + ac.defBinding;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
@ -163,9 +167,10 @@ namespace SCJMapper_V2.SC
ac.defBinding = attr["keyboard"];
ac.defActivationMode = actMode;
if ( ac.defBinding == " " ) {
ac.defBinding = Keyboard.KeyboardCls.BlendedInput;
ac.defBinding = Devices.Keyboard.KeyboardCls.BlendedInput;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
} else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
}
else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
ac.defBinding = "kb1_" + ac.defBinding;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
@ -178,9 +183,10 @@ namespace SCJMapper_V2.SC
ac.defBinding = attr["mouse"];
ac.defActivationMode = actMode;
if ( ac.defBinding == " " ) {
ac.defBinding = Mouse.MouseCls.BlendedInput;
ac.defBinding = Devices.Mouse.MouseCls.BlendedInput;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
} else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
}
else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
ac.defBinding = "mo1_" + ac.defBinding;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
@ -193,9 +199,10 @@ namespace SCJMapper_V2.SC
ac.defBinding = attr["xboxpad"];
ac.defActivationMode = actMode;
if ( ac.defBinding == " " ) {
ac.defBinding = Gamepad.GamepadCls.BlendedInput;
ac.defBinding = Devices.Gamepad.GamepadCls.BlendedInput;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
} else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
}
else if ( !string.IsNullOrEmpty( ac.defBinding ) ) {
ac.defBinding = "xi1_" + ac.defBinding;
m_currentMap.Add( ac ); // finally add it to the current map if it was bound
}
@ -324,10 +331,12 @@ namespace SCJMapper_V2.SC
// the element name is a control
if ( xr.NodeType == XmlNodeType.EndElement ) {
done = ( xr.Name == m_nodeNameStack.Peek( ) ); // EXIT if the end element matches the entry
} else if ( xr.IsEmptyElement ) {
}
else if ( xr.IsEmptyElement ) {
// an attribute only element
CollectActions( attr );
} else {
}
else {
// one with subelements again
m_nodeNameStack.Push( xr.Name ); // recursive .. push element name to terminate later (this is i.e. keyboard)
ReadActionSub( xr, actionName, xr.Name );
@ -370,13 +379,15 @@ namespace SCJMapper_V2.SC
m_currentMap.name = mapName;
if ( !m_aMap.ContainsKey( mapName ) ) { //20170325 - fix multiple map names - don't add the second, third etc. (CIG bug..)
m_aMap.Add( mapName, m_currentMap ); // add to our inventory
}else {
}
else {
log.DebugFormat( "ReadElement: IGNORED duplicate map with name: {0}", mapName );
}
m_state = EState.inActionMap; // now we are in and processing the map
}
}
} else if ( m_state == EState.inActionMap ) {
}
else if ( m_state == EState.inActionMap ) {
// processing a valid action map - collect actions
if ( eName.ToLower( ) == "action" ) {
// this is an action.. - collect it
@ -415,10 +426,12 @@ namespace SCJMapper_V2.SC
if ( xr.IsEmptyElement ) {
retVal = retVal && ReadEmptyElement( xr );
m_nodeNameStack.Pop( ); // empty ones end inline
} else {
}
else {
retVal = retVal && ReadElement( xr );
}
} else if ( xr.NodeType == XmlNodeType.EndElement ) {
}
else if ( xr.NodeType == XmlNodeType.EndElement ) {
//Console.Write( "</{0}>\n", xr.Name );
string exitElement = m_nodeNameStack.Pop( );
if ( m_state == EState.inActionMap )
@ -432,14 +445,20 @@ namespace SCJMapper_V2.SC
else
return false;
} catch ( Exception ex ) {
}
catch ( Exception ex ) {
// get any exceptions from reading
log.Error( "DProfileReader.ReadXML - unexpected", ex );
return false;
}
}
/*
//<ActivationModes >
// <ActivationMode name="tap" onPress="0" onHold="0" onRelease="1" multiTap="1" multiTapBlock="1" pressTriggerThreshold="-1" releaseTriggerThreshold="0.25" releaseTriggerDelay="0" />
...
//</ActivationModes>
*/
private bool ReadActivationModes( XmlReader xr )
{
log.Debug( "DProfileReader.ReadActivationModes - Entry" );
@ -458,7 +477,45 @@ namespace SCJMapper_V2.SC
} while ( xr.Read( ) );
return true;
} catch ( Exception ex ) {
}
catch ( Exception ex ) {
// get any exceptions from reading
log.Error( "DProfileReader.ReadXML - unexpected", ex );
return false;
}
}
// Read modifiers
//<modifiers>
// <mod input = "xi_shoulderl" />
// <mod input ="xi_triggerl_btn" />
// <mod input = "xi_dpad_down" />
// <mod input ="xi_y" />
// <mod input = "kb_z" />
// <mod input ="kb_f3" />
// <mod input = "kb_lalt" />
// <mod input = "kb_lalt" />
// <mod input = "kb_f4" />
// <mod input = "kb_mouse2" />
// <mod input = "xi_dpad_down" />
// <mod input = "xi_shoulderl" />
// <mod input = "xi_triggerl_btn" />
//</ modifiers >
private bool ReadModifiers( XmlReader xr )
{
log.Debug( "DProfileReader.ReadModifiers - Entry" );
try {
xr.ReadToFollowing( "modifiers" );
return Modifiers.Instance.FromXML( xr.ReadOuterXml(), true );
}
catch ( Exception ex ) {
// get any exceptions from reading
log.Error( "DProfileReader.ReadXML - unexpected", ex );
return false;
@ -494,6 +551,9 @@ namespace SCJMapper_V2.SC
reader.Read( );
ValidContent &= ReadActivationModes( reader );
Modifiers.Instance.Clear( );
ValidContent &= ReadModifiers( reader );
m_nodeNameStack.Push( "profile" ); // we are already in the XML now
ValidContent &= ReadXML( reader );

@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace SCJMapper_V2.SC
{
public class Modifier
{
public string Name = "";
public bool DefaultProfile = false;
public Modifier( string name, bool defaultProfile = false )
{
Name = name;
DefaultProfile = defaultProfile;
}
public string ToXML()
{
string r = string.Format( "\t\t<mod input =\"{0}\" />\n", Name );
return r;
}
public static bool operator ==( Modifier a, Modifier b )
{
// If both are null, or both are same instance, return true.
if ( ReferenceEquals( a, b ) ) {
return true;
}
// If one is null, but not both, return false.
if ( ( (object)a == null ) || ( (object)b == null ) ) {
return false;
}
// Return true if the fields match:
return a.Equals( b );
}
public static bool operator !=( Modifier a, Modifier b )
{
return !( a == b );
}
public override bool Equals( System.Object obj )
{
// If parameter is null return false.
if ( obj == null ) {
return false;
}
// If parameter cannot be cast to Point return false.
Modifier p = obj as Modifier;
if ( (System.Object)p == null ) {
return false;
}
// Return true if the fields match:
return ( this.Equals( p ) );
}
/// <summary>
/// Returns true if they are the same
/// </summary>
/// <param name="p">ActivationMode to compare with</param>
/// <returns>True if both are the same, else false</returns>
public bool Equals( Modifier p )
{
// If parameter is null return false:
if ( (object)p == null ) {
return false;
}
// Return true if the fields match:
return ( Name == p.Name );
}
public override int GetHashCode()
{
return Name.GetHashCode( ) ^ this.GetHashCode( );
}
}
/// <summary>
/// Contains the ActivationMode from SC
/// can be:
/// "Default" using the defActivationMode setting of the profile
/// any of the List of profileDefined ones
/// </summary>
public sealed class Modifiers : List<Modifier>
{
private static readonly Modifiers instance = new Modifiers( );
public static Modifiers Instance
{
get {
return instance;
}
}
/// <summary>
/// cTor: Empty - hidden
/// </summary>
private Modifiers() { }
/// <summary>
/// Returns the list of ActivationMode names
/// </summary>
/// <returns>A list of names</returns>
public IList<string> Names
{
get {
List<string> retVal = new List<string>( );
foreach ( Modifier am in this ) retVal.Add( am.Name );
return retVal;
}
}
/// <summary>
/// Returns the number of users added modifiers
/// </summary>
public int UserCount
{
get {
int cnt = 0;
foreach ( Modifier m in this ) {
if ( !m.DefaultProfile )
cnt++;
}
return cnt;
}
}
/// <summary>
/// Read the modifier node from profile or ActionMaps
/// </summary>
/// <param name="xml"></param>
/// <param name="defProfile"></param>
/// <returns></returns>
public bool FromXML( string xml, bool defProfile = false )
{
XmlReaderSettings settings = new XmlReaderSettings( );
settings.ConformanceLevel = ConformanceLevel.Fragment;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
XmlReader reader = XmlReader.Create( new StringReader( xml ), settings );
try {
reader.ReadToFollowing( "modifiers" );
reader.ReadToDescendant( "mod" );
do {
if ( reader.NodeType == XmlNodeType.EndElement ) {
reader.Read( );
break; // finished
}
string name = reader["input"];
if ( !string.IsNullOrEmpty( name ) ) {
var m = new Modifier( name, defProfile );
if ( !Contains( m ) )
Add( m );
}
} while ( reader.Read( ) );
return true;
}
catch ( Exception ex ) {
// get any exceptions from reading
return false;
}
}
/// <summary>
/// Returns the XML string of Non Profile items
/// </summary>
/// <returns>An XML string</returns>
public string ToXML()
{
if ( UserCount <= 0 ) return "";
string r = string.Format( "\t<modifiers>\n" );
foreach ( Modifier m in this ) {
if ( !m.DefaultProfile )
r += m.ToXML( );
}
r += string.Format( "\t</modifiers>\n\n" );
return r;
}
}
}

@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ionic.Zip;
using System.IO;
using SCJMapper_V2.CryXMLlib;
@ -18,17 +17,19 @@ namespace SCJMapper_V2.SC
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger( System.Reflection.MethodBase.GetCurrentMethod( ).DeclaringType );
private static string m_defProfileCached = ""; // cache...
/// <summary>
/// Ref to the used defaultProfile to inform the user about it.
/// </summary>
public static String UsedDefProfile = "n.a.";
public static string UsedDefProfile = "n.a.";
/// <summary>
/// Returns a list of files found that match 'defaultProfile*.xml'
/// 20151220BM: return only the single defaultProfile name
/// </summary>
/// <returns>A list of filenames - can be empty</returns>
static public String DefaultProfileName
static public string DefaultProfileName
{
get { return "defaultProfile.xml"; }
}
@ -37,140 +38,95 @@ namespace SCJMapper_V2.SC
/// Returns the sought default profile as string from various locations
/// SC Alpha 2.2: Have to find the new one in E:\G\StarCitizen\StarCitizen\Public\Data\DataXML.pak (contains the binary XML now)
/// </summary>
/// <param name="defaultProfileName">The filename of the profile to be extracted </param>
/// <returns>A string containing the file contents</returns>
static public String DefaultProfile( String defaultProfileName )
static public string DefaultProfile()
{
log.Debug( "DefaultProfile - Entry" );
String retVal = "";
string retVal = m_defProfileCached;
if ( !string.IsNullOrEmpty( retVal ) ) return retVal; // Return cached defaultProfile
// first choice a defaultProfile.xml in the app dir distributed with the application ??? to be deleted ???
if ( File.Exists( defaultProfileName ) ) { // 20170404 - use the given name, not the one from SCPATH...
using ( StreamReader sr = new StreamReader( defaultProfileName ) ) {
// first choice a defaultProfile.xml in the app dir distributed with the application ??? to be deleted ???
if ( File.Exists( DefaultProfileName ) ) { // 20170404 - use the given name, not the one from SCPATH...
using ( StreamReader sr = new StreamReader( DefaultProfileName ) ) {
retVal = sr.ReadToEnd( );
UsedDefProfile = "AppDirectory defaultProfile";
log.InfoFormat( "- Use {0}", UsedDefProfile );
m_defProfileCached = retVal;
return retVal; // EXIT
}
}
// second try to get the SC defaultProfile from the DataXML.pak
string patchProfile = Path.Combine( SCPath.SCClientUSERPath, defaultProfileName );
// second try to get the SC defaultProfile ..\USER\defaultProfile.xml
string patchProfile = Path.Combine( SCPath.SCClientUSERPath, DefaultProfileName );
if ( File.Exists( patchProfile ) ) { // 20171126 PTU patch location in ..\USER\defaultProfile.xml
using ( StreamReader sr = new StreamReader( patchProfile ) ) {
retVal = sr.ReadToEnd( );
UsedDefProfile = "USER Directory defaultProfile.xml";
log.InfoFormat( "- Use {0}", UsedDefProfile );
m_defProfileCached = retVal;
return retVal; // EXIT
}
}
// PTU 3.0 those cannot longer work - but let them in for a while
// second try to get the SC defaultProfile from the DataXML.pak
retVal = ExtractDefaultBinProfile( defaultProfileName );
if ( !String.IsNullOrEmpty( retVal ) ) {
UsedDefProfile = "DataXML defaultProfile";
log.InfoFormat( "- Use {0}", UsedDefProfile );
return retVal; // EXIT
}
// third try to get the SC defaultProfile from the GameData.pak
retVal = ExtractDefaultProfile( defaultProfileName );
if ( !String.IsNullOrEmpty( retVal ) ) {
// third try to get the SC defaultProfile from the Data.p4k
retVal = ExtractDefaultBinProfileP4k( DefaultProfileName );
if ( !string.IsNullOrEmpty( retVal ) ) {
UsedDefProfile = "GamePack defaultProfile";
log.InfoFormat( "- Use {0}", UsedDefProfile );
m_defProfileCached = retVal;
return retVal; // EXIT
}
// last resort is the built in one
retVal = SCJMapper_V2.Properties.Resources.defaultProfile;
retVal = Properties.Resources.defaultProfile;
UsedDefProfile = "App Resource defaultProfile";
log.InfoFormat( "- Use {0}", UsedDefProfile );
m_defProfileCached = retVal;
return retVal; // EXIT
}
/// <summary>
/// Zip Extracts the file to a string
/// SC Alpha 2.2: Have to find the new one in E:\G\StarCitizen\StarCitizen\Public\Data\DataXML.pak (contains the binary XML now)
/// SC Alpha 2.2: Have to find the new one in E:\G\StarCitizen\StarCitizen\LIVE\Data.p4k (contains the binary XML now)
/// </summary>
static private String ExtractDefaultBinProfile( String defaultProfileName )
static private string ExtractDefaultBinProfileP4k( string defaultProfileName )
{
log.Debug( "ExtractDefaultBinProfile - Entry" );
String retVal = "";
if ( File.Exists( SCPath.SCDataXML_pak ) ) {
using ( ZipFile zip = ZipFile.Read( SCPath.SCDataXML_pak ) ) {
zip.CaseSensitiveRetrieval = false;
try {
ICollection<ZipEntry> gdpak = zip.SelectEntries( "name = " + "'" + defaultProfileName + "'", SCPath.DefaultProfilePath_rel );
if ( gdpak != null ) {
try {
MemoryStream mst = new MemoryStream( );
gdpak.FirstOrDefault( ).Extract( mst );
// use the binary XML reader
CryXmlNodeRef ROOT = null;
CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error;
CryXmlBinReader cbr = new CryXmlBinReader( );
ROOT = cbr.LoadFromBuffer( mst.ToArray( ), out readResult );
if ( readResult == CryXmlBinReader.EResult.Success ) {
XmlTree tree = new XmlTree( );
tree.BuildXML( ROOT );
retVal = tree.XML_string;
}
else {
log.ErrorFormat( " Error in CryXmlBinReader: {0}", cbr.GetErrorDescription() );
retVal = ""; // clear any remanents
}
}
catch {
retVal = ""; // clear any remanents
}
log.Debug( "ExtractDefaultBinProfileP4k - Entry" );
string retVal = "";
if ( File.Exists( SCPath.SCData_p4k ) ) {
try {
var PD = new p4kFile.p4kDirectory( );
p4kFile.p4kFile p4K = PD.ScanDirectoryFor( SCPath.SCData_p4k, defaultProfileName );
if ( p4K != null ) {
byte[] fContent = PD.GetFile( SCPath.SCData_p4k, p4K );
// use the binary XML reader
CryXmlNodeRef ROOT = null;
CryXmlBinReader.EResult readResult = CryXmlBinReader.EResult.Error;
CryXmlBinReader cbr = new CryXmlBinReader( );
ROOT = cbr.LoadFromBuffer( fContent, out readResult );
if ( readResult == CryXmlBinReader.EResult.Success ) {
XmlTree tree = new XmlTree( );
tree.BuildXML( ROOT );
retVal = tree.XML_string;
}
else {
log.ErrorFormat( " Error in CryXmlBinReader: {0}", cbr.GetErrorDescription( ) );
retVal = ""; // clear any remanents
}
}
catch ( Exception ex ) {
log.Error( " Unexpected ", ex );
}
}
}
return retVal;
}
/// <summary>
/// Zip Extracts the file to a string
/// </summary>
static private String ExtractDefaultProfile( String defaultProfileName )
{
log.Debug( "ExtractDefaultProfile - Entry" );
String retVal = "";
if ( File.Exists( SCPath.SCGameData_pak ) ) {
using ( ZipFile zip = ZipFile.Read( SCPath.SCGameData_pak ) ) {
zip.CaseSensitiveRetrieval = false;
try {
ICollection<ZipEntry> gdpak = zip.SelectEntries( "name = " + "'" + defaultProfileName + "'", SCPath.DefaultProfilePath_rel );
if ( gdpak != null ) {
try {
MemoryStream mst = new MemoryStream( );
gdpak.FirstOrDefault( ).Extract( mst );
UTF8Encoding unc = new UTF8Encoding( );
retVal = unc.GetString( mst.ToArray( ) );
}
catch {
retVal = ""; // clear any remanents
}
}
}
catch ( Exception ex ) {
log.Error( " Unexpected", ex );
}
}
catch ( Exception ex ) {
log.Error( " Unexpected ", ex );
}
}
return retVal;
}

@ -19,6 +19,7 @@ namespace SCJMapper_V2.SC
if ( l.StartsWith( "log started" ) ) return String.Format("\t{0}\n", inLine);
if ( l.StartsWith( "executable:" ) ) return String.Format( "\t{0}\n", inLine );
if ( l.StartsWith( "productversion" ) ) return String.Format( "\t{0}\n", inLine );
if ( l.StartsWith( "host cpu" ) ) return String.Format( "\t{0}\n", inLine );
if ( l.StartsWith( "windows:" ) ) return String.Format( "\t{0}\n", inLine );

@ -18,95 +18,24 @@ namespace SCJMapper_V2.SC
private static bool hasInformed = false; // prevent msgbox chains..
/// <summary>
/// Try to locate the launcher under "App Paths"
/// Try to locate the launcher from Alpha 3.0.0 public - e.g. E:\G\StarCitizen\RSI Launcher
/// </summary>
static private String SCLauncherFile1
static private String SCLauncherDir6
{
get {
log.Debug( "SCLauncherFile1 - Entry" );
String scLauncher = (String)Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\App Paths\StarCitizen Launcher.exe", "", null );
log.Debug( "SCLauncherDir6 - Entry" );
String scLauncher = (String)Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\81bfc699-f883-50c7-b674-2483b6baae23", "InstallLocation", null );
if ( scLauncher != null ) {
log.Info( "SCLauncherFile1 - Found HKLM - AppPath - Launcher.exe" );
if ( File.Exists( scLauncher ) ) {
return scLauncher;
}
else {
log.WarnFormat( "SCLauncherFile1 - file does not exist: {0}", scLauncher );
return "";
}
}
log.Warn( "SCLauncherFile1 - did not found HKLM - AppPath - Launcher.exe" );
return "";
}
}
/// <summary>
/// Try to locate the launcher under "Uninstall"
/// </summary>
static private String SCLauncherFile2
{
get {
log.Debug( "SCLauncherFile2 - Entry" );
String scLauncher = (String)Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\StarCitizen", "DisplayIcon", null );
if ( scLauncher != null ) {
log.Info( "SCLauncherFile2 - Found HKLM - Uninstall - StarCitizen" );
if ( File.Exists( scLauncher ) ) {
return scLauncher;
}
else {
log.WarnFormat( "SCLauncherFile2 - file does not exist: {0}", scLauncher );
return "";
}
}
log.Warn( "SCLauncherFile2 - did not found HKLM - Uninstall - StarCitizen" );
return "";
}
}
/// <summary>
/// Try to locate the launcher under "Uninstall"
/// </summary>
static private String SCLauncherFile3
{
get {
log.Debug( "SCLauncherFile3 - Entry" );
String scLauncher = (String)Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Cloud Imperium Games\StarCitizen Launcher.exe", "", null );
if ( scLauncher != null ) {
log.Info( "SCLauncherFile3 - Found HKLM - CIG - Launcher.exe" );
if ( File.Exists( scLauncher ) ) {
return scLauncher;
}
else {
log.WarnFormat( "SCLauncherFile3 - file does not exist: {0}", scLauncher );
return "";
}
}
log.Warn( "SCLauncherFile3 - did not found HKLM - CIG - Launcher.exe" );
return "";
}
}
/// <summary>
/// Try to locate the launcher from Alpha 1.1.6 - e.g. E:\G\StarCitizen\CIGLauncher.exe
/// </summary>
static private String SCLauncherFile4
{
get {
log.Debug( "SCLauncherFile4 - Entry" );
String scLauncher = (String)Registry.GetValue( @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\App Paths\CIGLauncher.exe", "", null );
if ( scLauncher != null ) {
log.Info( "SCLauncherFile4 - Found HKCU - CIGLauncher.exe" );
if ( File.Exists( scLauncher ) ) {
log.Info( "SCLauncherDir6 - Found HKLM -InstallLocation" );
if ( Directory.Exists( scLauncher ) ) {
return scLauncher;
}
else {
log.WarnFormat( "SCLauncherFile4 - file does not exist: {0}", scLauncher );
log.WarnFormat( "SCLauncherDir6 - directory does not exist: {0}", scLauncher );
return "";
}
}
log.Warn( "SCLauncherFile4 - did not found HKCU - CIGLauncher.exe" );
log.Warn( "SCLauncherDir6 - did not found HKLM - InstallLocation" );
return "";
}
}
@ -120,7 +49,7 @@ namespace SCJMapper_V2.SC
log.Debug( "SCLauncherDir5 - Entry" );
String scLauncher = (String)Registry.GetValue( @"HKEY_LOCAL_MACHINE\SOFTWARE\94a6df8a-d3f9-558d-bb04-097c192530b9", "InstallLocation", null );
if ( scLauncher != null ) {
log.Info( "SCLauncherDir5 - Found HKLM -InstallLocation" );
log.Info( "SCLauncherDir5 - Found HKLM -InstallLocation (PTU)" );
if ( Directory.Exists( scLauncher ) ) {
return scLauncher;
}
@ -139,7 +68,7 @@ namespace SCJMapper_V2.SC
/// <summary>
/// Returns the base SC install path from something like "E:\G\StarCitizen\Launcher\StarCitizenLauncher.exe"
/// Returns the base SC install path from something like "E:\G\StarCitizen"
/// </summary>
static private String SCBasePath
{
@ -148,8 +77,8 @@ namespace SCJMapper_V2.SC
appSettings.Reload( ); // local instance - reload as it might be changed outside
String scp = "";
// User setting has Prio
if ( appSettings.UserSCPathUsed ) {
// User has priority
scp = appSettings.UserSCPath;
log.InfoFormat( "SCBasePath - user defined folder given: {0}", scp );
#if DEBUG
@ -177,65 +106,24 @@ namespace SCJMapper_V2.SC
else {
// start the registry search - sequence 5..1 to get the newest method first
scp = SCLauncherDir5;
scp = SCLauncherDir6; // 3.0 Public Launcher
#if DEBUG
//***************************************
//scp = ""; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
//***************************************
#endif
if ( !string.IsNullOrEmpty( scp ) ) {
// AC 1.1.6 path OK - this one needs no adjustments anymore but removing the filename
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen"
return scp;
}
scp = SCLauncherFile4;
scp = SCLauncherDir5; // 3.0 PTU Launcher
#if DEBUG
//***************************************
//scp = ""; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
//***************************************
#endif
if ( !string.IsNullOrEmpty( scp ) ) {
// AC 1.1.6 path OK - this one needs no adjustments anymore but removing the filename
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen"
return scp;
}
scp = SCLauncherFile3;
#if DEBUG
//***************************************
//scp = ""; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
//***************************************
#endif
if ( !string.IsNullOrEmpty( scp ) ) {
// found the launcher.exe file - path adjust for the old subdir (may be remove path find 1..3 later)
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen\Launcher"
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen"
return scp;
}
scp = SCLauncherFile2;
#if DEBUG
//***************************************
//scp = ""; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
//***************************************
#endif
if ( !string.IsNullOrEmpty( scp ) ) {
// found the launcher.exe file - path adjust for the old subdir (may be remove path find 1..3 later)
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen\Launcher"
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen"
return scp;
}
scp = SCLauncherFile1;
#if DEBUG
//***************************************
//scp = ""; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
//***************************************
#endif
if ( !string.IsNullOrEmpty( scp ) ) {
// found the launcher.exe file - path adjust for the old subdir (may be remove path find 1..3 later)
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen\Launcher"
scp = Path.GetDirectoryName( scp ); // "E:\G\StarCitizen"
return scp;
}
@ -274,9 +162,7 @@ namespace SCJMapper_V2.SC
/// <summary>
/// Returns the SC Client path
/// AC 1.1.6: E:\G\StarCitizen\StarCitizen\Public
/// SC 2x: alternatively use PTU path E:\G\StarCitizen\StarCitizen\Test
/// SC 2.2.2: alternatively search path in E:\G\StarCitizen\StarCitizen\Live (don't know but this was mentioned in CIGs relnotes lately)
/// SC 3.0.0: search path like E:\G\StarCitizen\StarCitizen\LIVE
/// </summary>
static public String SCClientPath
{
@ -294,23 +180,18 @@ namespace SCJMapper_V2.SC
//
scp = Path.Combine( scp, "StarCitizen" );
string scpX = "";
// regular game folder
scpX = Path.Combine( scp, "Public" );
if ( Directory.Exists( scpX ) ) return scpX;
// SC 2.2.2+ did not found it so try Live now
// SC 3.0 try LIVE
scpX = Path.Combine( scp, "LIVE" );
if ( Directory.Exists( scpX ) ) return scpX;
// Issue a warning here to let the user know
issue = string.Format( "Cannot find the SC Client Path !!\n\n" +
"Tried to look for:\n" +
"{0}\\Public or \n" +
"{0}\\LIVE \n" +
"The program cannot load or save in GameFolders\n\n" +
"Please submit a bug report, adding your complete SC game folder structure", scp );
log.WarnFormat( "SCClientPath - StarCitizen\\Public, StarCitizen\\Live subfolder does not exist: {0}", scp );
log.WarnFormat( "SCClientPath - StarCitizen\\Live subfolder does not exist: {0}", scp );
// Issue a warning here to let the user know
if ( !hasInformed ) System.Windows.Forms.MessageBox.Show( issue, "Cannot find SC Client Path !!", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Exclamation );
@ -323,7 +204,7 @@ namespace SCJMapper_V2.SC
/// <summary>
/// Returns the SC ClientData path
/// AC 1.1.6: E:\G\StarCitizen\StarCitizen\Public\Data
/// AC 3.0: E:\G\StarCitizen\StarCitizen\LIVE\Data
/// </summary>
static public String SCClientDataPath
{
@ -340,7 +221,7 @@ namespace SCJMapper_V2.SC
#endif
if ( Directory.Exists( scp ) ) return scp;
log.WarnFormat( "SCClientDataPath - StarCitizen\\Public\\Data subfolder does not exist: {0}", scp );
log.WarnFormat( "SCClientDataPath - StarCitizen\\LIVE\\Data subfolder does not exist: {0}", scp );
return "";
}
}
@ -348,7 +229,7 @@ namespace SCJMapper_V2.SC
/// <summary>
/// Returns the SC ClientData path
/// AC 1.1.6: E:\G\StarCitizen\StarCitizen\Public\USER
/// AC 3.0: E:\G\StarCitizen\StarCitizen\LIVE\USER
/// </summary>
static public String SCClientUSERPath
{
@ -365,7 +246,7 @@ namespace SCJMapper_V2.SC
#endif
if ( Directory.Exists( scp ) ) return scp;
log.WarnFormat( "SCClientUSERPath - StarCitizen\\Public\\USER subfolder does not exist: {0}", scp );
log.WarnFormat( "SCClientUSERPath - StarCitizen\\LIVE\\USER subfolder does not exist: {0}", scp );
return "";
}
}
@ -388,7 +269,7 @@ namespace SCJMapper_V2.SC
#endif
if ( Directory.Exists( scp ) ) return scp;
log.WarnFormat( "SCClientLogsPath - StarCitizen\\Public subfolder does not exist: {0}", scp );
log.WarnFormat( "SCClientLogsPath - StarCitizen\\LIVE subfolder does not exist: {0}", scp );
return "";
}
}
@ -414,49 +295,24 @@ namespace SCJMapper_V2.SC
#endif
if ( Directory.Exists( scp ) ) return scp;
log.WarnFormat( "SCClientMappingPath - StarCitizen\\Public\\USER\\Controls\\Mappings subfolder does not exist: {0}", scp );
return "";
}
}
/// <summary>
/// Returns the SC GameData.pak file path
/// AC 1.1.6: E:\G\StarCitizen\StarCitizen\Public\Data\GameData.pak
/// </summary>
static public String SCGameData_pak
{
get {
log.Debug( "SCGameData_pak - Entry" );
String scp = SCClientDataPath;
if ( String.IsNullOrEmpty( scp ) ) return "";
//
scp = Path.Combine( scp, "GameData.pak" );
#if DEBUG
//***************************************
// scp += "X"; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
//***************************************
#endif
if ( File.Exists( scp ) ) return scp;
log.WarnFormat( "SCGameData_pak - StarCitizen\\Public\\Data\\GameData.pak file does not exist: {0}", scp );
log.WarnFormat( "SCClientMappingPath - StarCitizen\\LIVE\\USER\\Controls\\Mappings subfolder does not exist: {0}", scp );
return "";
}
}
/// <summary>
/// Returns the SC DataXML.pak file path
/// SC Alpha 2.2: E:\G\StarCitizen\StarCitizen\Public\Data\DataXML.pak (contains the binary XML now)
/// Returns the SC Data.p4k file path
/// SC Alpha 3.0: E:\G\StarCitizen\StarCitizen\LIVE\Data.p4k (contains the binary XML now)
/// </summary>
static public String SCDataXML_pak
static public String SCData_p4k
{
get {
log.Debug( "SCDataXML_pak - Entry" );
String scp = SCClientDataPath;
log.Debug( "SCDataXML_p4k - Entry" );
String scp = SCClientPath;
if ( String.IsNullOrEmpty( scp ) ) return "";
//
scp = Path.Combine( scp, "DataXML.pak" );
scp = Path.Combine( scp, "Data.p4k" );
#if DEBUG
//***************************************
// scp += "X"; // TEST not found (COMMENT OUT FOR PRODUCTIVE BUILD)
@ -464,7 +320,7 @@ namespace SCJMapper_V2.SC
#endif
if ( File.Exists( scp ) ) return scp;
log.WarnFormat( "SCDataXML_pak - StarCitizen\\Public\\Data\\DataXML.pak file does not exist: {0}", scp );
log.WarnFormat( "SCData_p4k - StarCitizen\\Public\\Data\\Data.p4k file does not exist: {0}", scp );
return "";
}
}

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// <summary>
/// Limited Directory scanner for p4k files
/// </summary>
public class p4kDirectory
{
// 4.3.6 Overall.ZIP file format:
//[local file header 1]
//[encryption header 1]
//[file data 1]
//[data descriptor 1]
// .
// .
// .
//[local file header n]
//[encryption header n]
//[file data n]
//[data descriptor n]
//[archive decryption header]
//[archive extra data record]
//[central directory header 1]
// .
// .
// .
//[central directory header n]
//[zip64 end of central directory record]
//[zip64 end of central directory locator]
//[end of central directory record]
/// <summary>
/// Retrieve the file given by the descriptor (from our list)
/// and return the content as string
/// </summary>
/// <param name="file">A file descriptor from this list</param>
/// <returns>The content of the file or an empty string</returns>
public byte[] GetFile( string p4kFilename, p4kFile file )
{
if ( !File.Exists( p4kFilename ) ) return new byte[] { };
using ( p4kRecReader reader = new p4kRecReader( p4kFilename ) ) {
return file.GetFile( reader );
}
}
// scans file directory entries
// finds the directory structs and processes from there
private p4kEndOfCentralDirRecord m_endOfCentralDirRecord = null;
private p4kZ64EndOfCentralDirLocator m_z64EndOfCentralDirLocator = null;
private p4kZ64EndOfCentralDirRecord m_z64EndOfCentralDirRecord = null;
/// <summary>
/// Scans directory entries and extract a file (string.EndsWith is used)
/// </summary>
/// <param name="p4kFilename">The p4k file</param>
/// <param name="filename">The filename to look for</param>
/// <param name="bgw">A BackgroundWorker object</param>
public p4kFile ScanDirectoryFor( string p4kFilename, string filename )
{
if ( !File.Exists( p4kFilename ) ) return null;
using ( p4kRecReader reader = new p4kRecReader( p4kFilename ) ) {
// work from the end of the file
reader.GotoLastPage( );
m_endOfCentralDirRecord = new p4kEndOfCentralDirRecord( reader );
// position first
reader.Seek( m_endOfCentralDirRecord.RecordOffset - p4kRecReader.PageSize );
m_z64EndOfCentralDirLocator = new p4kZ64EndOfCentralDirLocator( reader );
// for the next the position should be found already - seek it
reader.Seek( m_z64EndOfCentralDirLocator.Z64EndOfCentralDir );
m_z64EndOfCentralDirRecord = new p4kZ64EndOfCentralDirRecord( reader );
// now we should have the start of the directory entries...
// position first
reader.Seek( m_z64EndOfCentralDirRecord.Z64StartOfCentralDir );
// loop all file - as per dir reporting
for ( long i = 0; i < m_z64EndOfCentralDirRecord.NumberOfEntries; i++ ) {
p4kDirectoryEntry de = new p4kDirectoryEntry( reader );
if ( !string.IsNullOrEmpty( filename ) && de.Filename.ToLower( ).EndsWith( filename.ToLower( ) ) ) {
var p = new p4kFile( de ); // FOUND
reader.TheReader.Close( );
return p; // bail out if found
}
}
}
return null;
}
}
}

@ -0,0 +1,206 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// <summary>
/// Represents a Directory entry in the p4k file
/// The file seems to be based on a Zip64 file structure
/// </summary>
internal class p4kDirectoryEntry
{
/// <summary>
/// ctor: Create class from data returned by the Reader; starts reading at current stream position
/// </summary>
/// <param name="reader">A binary data reader for this type of data - positioned already</param>
public p4kDirectoryEntry( p4kRecReader reader )
{
// sanity check only
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyRecord ) ) == RecordLength,
"Record size does not match!(" + Marshal.SizeOf( typeof( MyRecord ) ).ToString( ) + ")" );
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyZ64ExtraRecord ) ) == Z64ExtraRecordLength,
"Extra Record size does not match!(" + Marshal.SizeOf( typeof( MyZ64ExtraRecord ) ).ToString( ) + ")" );
if ( reader.IsOpen( ) ) {
try {
// get the next Directory record
long cPos = p4kSignatures.FindSignatureInPage( reader, p4kSignatures.CentralDirRecord );
if ( cPos >= 0 ) {
m_recordOffset = cPos;
reader.Seek( cPos );
m_item = p4kRecReader.ByteToType<MyRecord>( reader.TheReader );
m_itemValid = true; // implicite from Find..
}
// get some file attributes
if ( m_itemValid ) {
if ( m_item.FilenameLength > 0 ) {
ReadFilename( reader );
}
if ( m_item.ExtraFieldLength > 0 ) {
ReadExtradata( reader ); // Likely Zip64 extensions
}
m_fileDateTime = p4kFileTStamp.FromDos( m_item.LastModDate, m_item.LastModTime ); // get the file time given in the container
// check if standard fields or extension is used for size information
if ( m_item.CompressedSize < 0xffffffff ) {
m_fileSizeComp = m_item.CompressedSize;
m_fileSizeUnComp = m_item.UncompressedSize;
}
else {
m_fileSizeComp = (long)m_z64Item.CompressedSize;
m_fileSizeUnComp = (long)m_z64Item.UncompressedSize;
}
}
}
catch (Exception e) {
m_itemValid = false;
m_recordOffset = -1;
}
finally {
if ( !m_itemValid ) {
throw new OperationCanceledException( string.Format( "EOF - cannot find CentralDirRec in this page" ) );
}
}
}
}
/// <summary>
/// Get the filename from the data
/// </summary>
/// <param name="reader">The open and positioned reader</param>
private void ReadFilename( p4kRecReader reader )
{
byte[] fileNameBytes = new byte[m_item.FilenameLength];
fileNameBytes = reader.ReadBytes( m_item.FilenameLength );
m_filename = Encoding.ASCII.GetString( fileNameBytes );
}
/// <summary>
/// Read the extra data
/// </summary>
/// <param name="reader"></param>
private void ReadExtradata( p4kRecReader reader )
{
// first the Zip64 extra record
m_z64Item = p4kRecReader.ByteToType<MyZ64ExtraRecord>( reader.TheReader );
// then the rest of the extra record (is another item with tag 0x0666 and the rest lenght (ignored)
m_extraBytes = new byte[m_item.ExtraFieldLength - Z64ExtraRecordLength];
m_extraBytes = reader.ReadBytes( m_extraBytes.Length );
m_extraBytes = null; // dump it ...
// now we would be able to read the file content
}
/// <summary>
/// Return the file related to this entry
/// </summary>
/// <param name="reader">An open p4k File reader</param>
/// <returns>The content of the file or an empty string</returns>
public byte[] GetFile( p4kRecReader reader )
{
if ( !m_itemValid ) return new byte[] { }; // ERROR cannot..
reader.Seek( FileHeaderOffset );
p4kFileHeader p4Kfh = new p4kFileHeader( reader );
return p4Kfh.GetFile( reader );
}
public bool IsValid { get => m_itemValid; }
public long RecordOffset { get => m_recordOffset; }
public string Filename { get => m_filename; }
public long FileSizeComp { get => m_fileSizeComp; }
public long FileSizeUnComp { get => m_fileSizeUnComp; }
public DateTime FileModifyDate { get => m_fileDateTime; }
public long FileHeaderOffset
{
get {
if ( m_itemValid )
return (long)m_z64Item.LocalHeaderOffset;
else
return -1;
}
}
private MyRecord m_item;
private bool m_itemValid = false;
private MyZ64ExtraRecord m_z64Item;
private byte[] m_extraBytes = null;
private long m_recordOffset = -1; // offset from start (current position)
// Entry attributes
private string m_filename = "";
private DateTime m_fileDateTime = new DateTime( 1970,1,1 );
private long m_fileSizeComp = 0;
private long m_fileSizeUnComp = 0;
// 4.3.12 Central directory structure:
private const int RecordLength = 46;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyRecord
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] ID; // central file header signature 4 bytes(0x02014b50)
[MarshalAs( UnmanagedType.U2 )]
public UInt16 VersionMadeBy; // version made by 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ExtractVersion; // version made by 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 BitFlags; // general purpose bit flag 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 CompressionMethod; // compression method 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 LastModTime; // last mod file time 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 LastModDate; // last mod file date 2 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 CRC32; // crc-32 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 CompressedSize; // compressed size 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 UncompressedSize; // uncompressed size 4 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 FilenameLength; // file name length 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ExtraFieldLength; // extra field length 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 FilecommentLength; // file comment length 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 DiskNumberStart; // disk number start 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 IntFileAttr; // internal file attributes 2 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 ExtFileAttr; // external file attributes 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 RelOffsetHeader; // relative offset of local header 4 bytes
// file name( variable size )
// extra field( variable size )
// file comment( variable size )
}
private const int Z64ExtraRecordLength = 32;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyZ64ExtraRecord
{
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ID; // (Zip64 ExtraHeader Signature)
[MarshalAs( UnmanagedType.U2 )]
public UInt16 Size; // Size 2 bytes Size of this "extra" block
[MarshalAs( UnmanagedType.U8 )]
public UInt64 UncompressedSize; // Original Size 8 bytes Original uncompressed file size
[MarshalAs( UnmanagedType.U8 )]
public UInt64 CompressedSize; // Compressed Size 8 bytes Size of compressed data
[MarshalAs( UnmanagedType.U8 )]
public UInt64 LocalHeaderOffset; // Relative Header Offset 8 bytes Offset of local header record
[MarshalAs( UnmanagedType.U4 )]
public UInt32 DiskStart; // Disk Start Number 4 bytes Number of the disk on which this file starts
}
}
}

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// <summary>
/// Represents an EndOfCentralDirRecord entry in the p4k file
/// The file seems to be based on a Zip64 file structure
/// </summary>
internal class p4kEndOfCentralDirRecord
{
/// <summary>
/// ctor: Create class from data returned by the Reader
/// </summary>
/// <param name="reader">A binary data reader for this type of data - positioned at last page</param>
public p4kEndOfCentralDirRecord( p4kRecReader reader )
{
// sanity check only
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyRecord ) ) == RecordLength,
"Record size does not match!(" + Marshal.SizeOf( typeof( MyRecord ) ).ToString( ) + ")" );
if ( reader.IsOpen( ) ) {
try {
long cPos = p4kSignatures.FindSignatureInPage( reader, p4kSignatures.EndOfCentralDirRecord );
if ( cPos >= 0 ) {
m_recordOffset = cPos;
reader.Seek( cPos );
m_item = p4kRecReader.ByteToType<MyRecord>( reader.TheReader );
m_itemValid = true;
}
}
catch {
m_itemValid = false;
m_recordOffset = -1;
}
finally {
if ( !m_itemValid ) {
throw new OperationCanceledException( string.Format( "EOF - cannot find EndOfCentralDirRecord" ) );
}
}
}
}
public bool IsValid { get => m_itemValid; }
public long RecordOffset { get => m_recordOffset; }
private MyRecord m_item;
private bool m_itemValid = false;
private long m_recordOffset = -1; // offset from start (current position)
//4.3.16 End of central directory record:
private const int RecordLength = 22;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyRecord
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] ID; // end of central dir signature 4 bytes(0x06054b50)
[MarshalAs( UnmanagedType.U2 )]
public UInt16 DiskNumber; // number of this disk 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 DiskNumbersFromStart; // number of the disk with the start of the central directory 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 NumEntriesOnDisk; // total number of entries in the central directory on this disk 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 TotalNumEntries; // total number of entries in the central directory 2 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 SizeOfCDir; // size of the central directory 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 OffsetOfCDir; // offset of start of central directory with respect to the starting disk number 4 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 CommentLen; // .ZIP file comment length 2 bytes
// .ZIP file comment( variable size )
}
}
}

@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// <summary>
/// General File descriptor - knows about locations and can extract files
/// </summary>
public class p4kFile
{
// File Properties
private string m_filename = "";
public string Filename { get => m_filename; set => m_filename = value; }
private long m_fileHeaderOffset = -1; // file location of the fileheader in the p4k file
public long FileHeaderPosition { get => m_fileHeaderOffset; }
private long m_compressedSize = -1;
public long CompressedSize { get => m_compressedSize; }
private long m_uncompressedSize = -1;
public long FileSize { get => m_uncompressedSize; }
private DateTime m_fileDateTime = new DateTime( 1970, 1, 1 );
public DateTime FileModifyDate { get => m_fileDateTime; }
private string m_fileDateTimeS = new DateTime( 1970, 1, 1 ).ToString("s"); // pre fabricated is faster to sort than always creating the string...
public string FileModifyDateS { get => m_fileDateTimeS; }
/// <summary>
/// cTor: from fileHeader
/// </summary>
/// <param name="fileHeader">A File Header</param>
internal p4kFile( p4kFileHeader fileHeader )
{
Filename = fileHeader.Filename;
m_compressedSize = fileHeader.FileSizeComp;
m_uncompressedSize = fileHeader.FileSizeUnComp;
m_fileDateTime = fileHeader.FileModifyDate;
m_fileDateTimeS = m_fileDateTime.ToString( "s" );
m_fileHeaderOffset = fileHeader.RecordOffset;
}
/// <summary>
/// cTor: from Directory Entry
/// </summary>
/// <param name="dirEntry">A Directory Entry</param>
internal p4kFile( p4kDirectoryEntry dirEntry )
{
Filename = dirEntry.Filename;
m_compressedSize = dirEntry.FileSizeComp;
m_uncompressedSize = dirEntry.FileSizeUnComp;
m_fileDateTime = dirEntry.FileModifyDate;
m_fileDateTimeS = m_fileDateTime.ToString( "s" );
m_fileHeaderOffset = dirEntry.FileHeaderOffset;
}
public p4kFile()
{
}
/// <summary>
/// Return the file related to this entry
/// </summary>
/// <param name="reader">An open p4k File reader</param>
/// <returns>The content of the file or an empty string</returns>
internal byte[] GetFile( p4kRecReader reader )
{
if ( ( m_fileHeaderOffset >= 0 ) && reader.IsOpen( ) ) {
// seek file header
reader.Seek( m_fileHeaderOffset );
byte[] fContent = { };
// re-create the header
using ( p4kFileHeader p4KFileHeader = new p4kFileHeader( reader ) ) {
// dump the file
fContent = p4KFileHeader.GetFile( reader );
}
return fContent;
}
return new byte[] { };
}
}
}

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AAA80EE7-DE9C-4CE6-A6C9-5EAE48273FAE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>p4kFile</RootNamespace>
<AssemblyName>p4kFile</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="ZstdNet">
<HintPath>..\packages\ZstdNet.1.3.1\lib\net45\ZstdNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="p4kDirectory.cs" />
<Compile Include="p4kDirectoryEntry.cs" />
<Compile Include="p4kEndOfCentralDirRecord.cs" />
<Compile Include="p4kFile.cs" />
<Compile Include="p4kFileHeader.cs" />
<Compile Include="p4kFileTStamp.cs" />
<Compile Include="p4kRecReader.cs" />
<Compile Include="p4kSignatures.cs" />
<Compile Include="p4kZ64EndOfCentralDirLocator.cs" />
<Compile Include="p4kZ64EndOfCentralDirRecord.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SortableBindingList.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

@ -0,0 +1,324 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using ZstdNet;
namespace SCJMapper_V2.p4kFile
{
/// <summary>
/// Represents a Fileheader entry in the p4k File
/// seems to be a Zip64 based file and therefore using those headers
/// </summary>
internal class p4kFileHeader : IDisposable
{
//4.3.7 Local file header:
// local file header signature 4 bytes(0x04034b50)
// version needed to extract 2 bytes
// general purpose bit flag 2 bytes
// compression method 2 bytes
// last mod file time 2 bytes
// last mod file date 2 bytes
// crc-32 4 bytes
// compressed size 4 bytes
// uncompressed size 4 bytes
// file name length 2 bytes
// extra field length 2 bytes
// file name( variable size )
// extra field( variable size )
//4.3.8 File data
// Immediately following the local header for a file
// SHOULD be placed the compressed or stored data for the file.
// If the file is encrypted, the encryption header for the file
// SHOULD be placed after the local header and before the file
// data. The series of[local file header][encryption header]
// [file data][data descriptor] repeats for each file in the
// .ZIP archive.
// Zero-byte files, directories, and other file types that
// contain no content MUST not include file data.
// 4.5.3 -Zip64 Extended Information Extra Field(0x0001):
// The following is the layout of the zip64 extended
// information "extra" block.If one of the size or
// offset fields in the Local or Central directory
// record is too small to hold the required data,
// a Zip64 extended information record is created.
// The order of the fields in the zip64 extended
// information record is fixed, but the fields MUST
// only appear if the corresponding Local or Central
// directory record field is set to 0xFFFF or 0xFFFFFFFF.
// Note: all fields stored in Intel low - byte / high - byte order.
// Value Size Description
// ---- - ---------------
//(ZIP64)0x0001 2 bytes Tag for this "extra" block type
// Size 2 bytes Size of this "extra" block
// Original
// Size 8 bytes Original uncompressed file size
// Compressed
// Size 8 bytes Size of compressed data
// Relative Header
// Offset 8 bytes Offset of local header record
// Disk Start
// Number 4 bytes Number of the disk on which
// this file starts
// This entry in the Local header MUST include BOTH original
// and compressed file size fields.If encrypting the
// central directory and bit 13 of the general purpose bit
// flag is set indicating masking, the value stored in the
// Local Header for the original file size will be zero.
/// <summary>
/// ctor: Create class from data returned by the Reader
/// </summary>
/// <param name="reader">A binary data reader for this type of data</param>
public p4kFileHeader( p4kRecReader reader )
{
// sanity check only
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyRecord ) ) == RecordLength,
"Record size does not match!(" + Marshal.SizeOf( typeof( MyRecord ) ).ToString( ) + ")" );
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyZ64ExtraRecord ) ) == Z64ExtraRecordLength,
"Extra Record size does not match!(" + Marshal.SizeOf( typeof( MyZ64ExtraRecord ) ).ToString( ) + ")" );
if ( reader.IsOpen( ) ) {
try {
long cPos = reader.Position;
do {
// Fileheaders are Page aligned - scan to find one
reader.AdvancePage( ); // to next page
cPos = reader.Position;
string cPosS = cPos.ToString( "X" );
m_recordOffset = cPos;
m_item = p4kRecReader.ByteToType<MyRecord>( reader.TheReader );
m_itemValid = m_item.ID.SequenceEqual( p4kSignatures.LocalFileHeaderCry );
} while ( ( cPos < reader.Length ) && !m_itemValid );
// get some file attributes
if ( m_itemValid ) {
if ( m_item.FilenameLength > 0 ) {
ReadFilename( reader );
}
if ( m_item.ExtraFieldLength > 0 ) {
ReadExtradata( reader ); // Likely Zip64 extensions
}
m_fileDateTime = p4kFileTStamp.FromDos( m_item.LastModDate, m_item.LastModTime );
// check if standard fields or extension is used for size information
if ( m_item.CompressedSize < 0xffffffff ) {
m_fileSizeComp = m_item.CompressedSize;
m_fileSizeUnComp = m_item.UncompressedSize;
}
else {
m_fileSizeComp = (long)m_z64Item.CompressedSize;
m_fileSizeUnComp = (long)m_z64Item.UncompressedSize;
}
// now we would be able to read the file content
// but we skip it for now to process the next header
m_fileOffset = reader.TheReader.BaseStream.Position; // save position of this item
reader.TheReader.BaseStream.Seek( m_fileSizeComp, SeekOrigin.Current );
}
else {
// actually invalid but good manner ..
m_recordOffset = -1;
m_fileOffset = -1;
m_fileSizeComp = 0;
m_fileSizeUnComp = 0;
}
}
catch {
m_itemValid = false;
}
finally {
if ( !m_itemValid ) {
if ( m_item.ID.SequenceEqual( p4kSignatures.CentralDirRecord ) ) {
// read beyond the file entries
throw new OperationCanceledException( string.Format( "EOF - found Central Directory header {0}", m_item.ID.ToString( ) ) );
}
else {
// other error
throw new NotSupportedException( string.Format( "Cannot process fileheader ID {0}", m_item.ID.ToString( ) ) );
}
}
}
}
}
/// <summary>
/// Return the file related to this entry
/// </summary>
/// <param name="reader">An open p4k File reader</param>
/// <returns>The content of the file or an empty string</returns>
public byte[] GetFile( p4kRecReader reader )
{
if ( !m_itemValid ) return new byte[] { }; // ERROR cannot..
reader.Seek( m_fileOffset );
// ?? big files may have trouble here - may be we need to read and write chunks for this
// but for now we only want to get XMLs out and that is OK with byte alloc on the heap
byte[] fileBytes = new byte[m_fileSizeComp];
fileBytes = reader.ReadBytes( fileBytes.Length );
byte[] decompFile = null;
if ( m_item.CompressionMethod == 0x64 ) {
// this indicates p4k ZStd compression
using ( var decompressor = new Decompressor( ) ) {
try {
decompFile = decompressor.Unwrap( fileBytes );
return decompFile;
}
catch ( ZstdException e ) {
Console.WriteLine( "ZStd - Cannot decode file: " + m_filename );
Console.WriteLine( "Error: " + e.Message );
//Console.ReadLine();
return new byte[] { };
}
}
}
else {
// plain write - might be wrong if another compression was applied..
decompFile = fileBytes;
return decompFile;
}
}
public bool IsValid { get => m_itemValid; }
public string Filename { get => m_filename; }
public long RecordOffset { get => m_recordOffset; }
public long FileOffset { get => m_fileOffset; }
public long FileSizeComp { get => m_fileSizeComp; }
public long FileSizeUnComp { get => m_fileSizeUnComp; }
public DateTime FileModifyDate { get => m_fileDateTime; }
private void ReadFilename( p4kRecReader reader )
{
byte[] fileNameBytes = new byte[m_item.FilenameLength];
fileNameBytes = reader.ReadBytes( m_item.FilenameLength );
m_filename = Encoding.ASCII.GetString( fileNameBytes );
}
private void ReadExtradata( p4kRecReader reader )
{
// first the Zip64 extra record
m_z64Item = p4kRecReader.ByteToType<MyZ64ExtraRecord>( reader.TheReader );
// then the rest of the extra record (is another item with tag 0x0666 and the rest lenght (ignored)
m_extraBytes = new byte[m_item.ExtraFieldLength - Z64ExtraRecordLength];
m_extraBytes = reader.ReadBytes( m_extraBytes.Length );
m_extraBytes = null; // dump it ...
// now we would be able to read the file content
}
private MyRecord m_item;
private bool m_itemValid = false;
private MyZ64ExtraRecord m_z64Item;
private byte[] m_extraBytes = null;
private long m_recordOffset = -1; // offset from start (current position)
private long m_fileOffset = 0; // offset from start (current position)
// Entry attributes
private string m_filename = "";
private DateTime m_fileDateTime = new DateTime( 1970, 1, 1 );
private long m_fileSizeComp = 0;
private long m_fileSizeUnComp = 0;
private const int RecordLength = 30;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyRecord
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] ID; // local file header signature 4 bytes(0x14034b50) NOTE p4k here uses 0x14 and not 0x04
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ExtractVersion; // version made by 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 BitFlags; // general purpose bit flag 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 CompressionMethod; // compression method 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 LastModTime; // last mod file time 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 LastModDate; // last mod file date 2 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 CRC32; // crc-32 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 CompressedSize; // compressed size 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 UncompressedSize; // uncompressed size 4 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 FilenameLength; // file name length 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ExtraFieldLength; // extra field length 2 bytes
}
private const int Z64ExtraRecordLength = 32;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyZ64ExtraRecord
{
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ID; // (Zip64 ExtraHeader Signature)
[MarshalAs( UnmanagedType.U2 )]
public UInt16 Size; // Size 2 bytes Size of this "extra" block
[MarshalAs( UnmanagedType.U8 )]
public UInt64 UncompressedSize; // Original Size 8 bytes Original uncompressed file size
[MarshalAs( UnmanagedType.U8 )]
public UInt64 CompressedSize; // Compressed Size 8 bytes Size of compressed data
[MarshalAs( UnmanagedType.U8 )]
public UInt64 LocalHeaderOffset; // Relative Header Offset 8 bytes Offset of local header record
[MarshalAs( UnmanagedType.U4 )]
public UInt32 DiskStart; // Disk Start Number 4 bytes Number of the disk on which this file starts
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose( bool disposing )
{
if ( !disposedValue ) {
if ( disposing ) {
// TODO: dispose managed state (managed objects).
m_itemValid = false;
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
m_extraBytes = null;
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~p4kFileHeader() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose( true );
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
}

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
class p4kFileTStamp
{
/// <summary>
/// Converts from Zip (DOS) File date time to .Net DatetTime format
/// </summary>
/// <param name="date">A DOS file date integer</param>
/// <param name="time">A DOS file time integer</param>
/// <returns>The DateTime conversion of the input</returns>
public static DateTime FromDos( UInt16 date, UInt16 time )
{
// DOS date : hBit-- YYYYYYY MMMM TTTTT (year + 1980)
// DOS time : hBit-- hhhhh mmmmmm xxxxx (x*2 = sec)
int year = ( ( date >> 9 ) & 0x7f ) + 1980;
int month = ( date >> 5 ) & 0x0f;
int day = date & 0x01f;
int hour = ( time >> 11 ) & 0x1f;
int min = ( time >> 5 ) & 0x3f;
int sec = ( time & 0x01f ) * 2;
try {
var ret = new DateTime( year, month, day, hour, min, sec );
return ret;
}
catch ( Exception e ) {
return new DateTime( 1970, 1, 1 );
}
}
}
}

@ -0,0 +1,207 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// <summary>
/// Implements a binary reader for p4k files
/// </summary>
class p4kRecReader : IDisposable
{
public const long PageSize = 0x1000;
private FileStream m_filestr = null;
private BinaryReader m_reader = null;
private DateTime m_fileCreatedT; // hold the file creation time
/// <summary>
/// ctor:
/// </summary>
/// <param name="filename">The filename</param>
public p4kRecReader( String filename )
{
Open( filename );
m_fileCreatedT = File.GetCreationTimeUtc( m_filestr.Name );
}
/// <summary>
/// Open the file
/// </summary>
/// <param name="filename">The filename</param>
/// <returns>True when successfull</returns>
private bool Open( String filename )
{
if ( File.Exists( filename ) ) {
m_filestr = File.OpenRead( filename );
m_reader = new BinaryReader( m_filestr );
return true;
}
return false;
}
/// <summary>
/// Returns the Reader
/// </summary>
public BinaryReader TheReader
{
get { return m_reader; }
}
/// <summary>
/// Allocates and reads bytes of the size of one record
/// and returns the allocated bytes are structure - allowing structured access to binary data
/// Note: there is no error checking whatsoever here - so better make sure everything is OK
/// </summary>
/// <typeparam name="T">The record type to read</typeparam>
/// <param name="reader">A binary reader</param>
/// <returns>The read record</returns>
public static T ByteToType<T>( BinaryReader reader )
{
byte[] bytes = reader.ReadBytes( Marshal.SizeOf( typeof( T ) ) );
GCHandle handle = GCHandle.Alloc( bytes, GCHandleType.Pinned );
T theStructure = (T)Marshal.PtrToStructure( handle.AddrOfPinnedObject( ), typeof( T ) );
handle.Free( );
return theStructure;
}
/// <summary>
/// Returns the file status
/// </summary>
/// <returns>True if the file is open and the reader can read</returns>
public bool IsOpen()
{
if ( m_filestr != null ) return m_filestr.CanRead;
else return false;
}
/// <summary>
/// Returns the current Position of the underlying stream
/// </summary>
public long Position { get => m_filestr.Position; }
/// <summary>
/// Returns the Length of the underlying stream
/// </summary>
public long Length { get => m_filestr.Length; }
/// <summary>
/// Returns a number of bytes as array (from the underlying reader)
/// </summary>
/// <param name="count">Number of bytes to read</param>
/// <returns>A byte array</returns>
public byte[] ReadBytes(int count)
{
return m_reader.ReadBytes( count );
}
/// <summary>
/// Seeks from to pos from beginning
/// </summary>
/// <param name="pos">A position in the filestream</param>
/// <returns>The current starting position before seek</returns>
public long Seek( long pos )
{
long thisPos = m_filestr.Position;
m_filestr.Seek( pos, SeekOrigin.Begin );
return thisPos;
}
/// <summary>
/// As the file is 4k page oriented - this advances to the next page
/// </summary>
public void AdvancePage()
{
long current = TheReader.BaseStream.Position;
long remainder = current % PageSize;
if ( remainder > 0 ) {
long seek = PageSize - remainder;
TheReader.BaseStream.Seek( seek, SeekOrigin.Current );
}
}
/// <summary>
/// Places the stream at the last Page of the file
/// </summary>
/// <returns>Position of the stream</returns>
public long GotoLastPage()
{
TheReader.BaseStream.Seek( -PageSize, SeekOrigin.End );
return TheReader.BaseStream.Position;
}
/// <summary>
/// Returns one Page of the file @ current pos
/// </summary>
/// <returns>PageSize bytes at the current pos of the stream</returns>
public byte[] GetPage()
{
return TheReader.ReadBytes( (int)PageSize );
}
/// <summary>
/// Returns the file creation timestamp
/// </summary>
public DateTime FileDateTime
{
get { return m_fileCreatedT; }
set {; }
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose( bool disposing )
{
if ( !disposedValue ) {
if ( disposing ) {
// TODO: dispose managed state (managed objects).
if ( m_reader != null ) {
m_reader.Close( );
m_reader.Dispose( );
m_reader = null;
}
if ( m_filestr != null ) {
m_filestr.Close( );
m_filestr.Dispose( );
m_filestr = null;
}
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~p4kRecReader() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose( true );
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
}

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
internal class p4kSignatures
{
// From PKWare APPNOTE.TXT
//4.3.6 Overall.ZIP file format:
// [local file header 1] LocalFileHeader OR LocalFileHeaderCry for this p4k version
// [encryption header 1]
// [file data 1]
// [data descriptor 1]
// .
// .
// .
// [local file header n]
// [encryption header n]
// [file data n]
// [data descriptor n]
// [archive decryption header] CentralDirRec
// [archive extra data record] ExtraDataRecord
// [central directory header 1] CentralDirRec
// .
// .
// .
// [central directory header n] CentralDirRec
// [zip64 end of central directory record] Z64CentralDirRecEnd
// [zip64 end of central directory locator] Z64CentralDirLocEnd
// [end of central directory record] CentralDirRecEnd
public static readonly byte[] LocalFileHeader = { 0x50, 0x4B, 0x03, 0x04 }; // (0x04034b50) 4.3.7 Local file header:
public static readonly byte[] LocalFileHeaderCry = { 0x50, 0x4B, 0x03, 0x14 }; // as found in the p4k files
public static readonly byte[] ExtraDataRecord = { 0x50, 0x4B, 0x06, 0x08 }; // (0x08064b50) 4.3.11 Archive extra data record:
public static readonly byte[] CentralDirRecord = { 0x50, 0x4B, 0x01, 0x02 }; // (0x02014b50) 4.3.12 Central directory structure:
public static readonly byte[] DigitalSignature = { 0x50, 0x4B, 0x05, 0x05 }; // (0x05054b50) 4.3.13 Digital signature:
public static readonly byte[] Z64EndOfCentralDirRec = { 0x50, 0x4B, 0x06, 0x06 }; // (0x06064b50) 4.3.14 Zip64 end of central directory record
public static readonly byte[] Z64EndOfCentralDirLocator = { 0x50, 0x4B, 0x06, 0x07 }; // (0x07064b50) 4.3.15 Zip64 end of central directory locator
public static readonly byte[] EndOfCentralDirRecord = { 0x50, 0x4B, 0x05, 0x06 }; // (0x06054b50) 4.3.16 End of central directory record:
/// <summary>
/// Returns the position of the Signature within the stream
/// Searches one page from current location
/// </summary>
/// <param name="reader">A positioned reader</param>
/// <returns>The position within the stream or -1 if not found</returns>
public static long FindSignatureInPage( p4kRecReader reader, byte[] signature )
{
long pos = reader.Position;
byte[] lPage = reader.GetPage( );
for ( int i = 0; i < lPage.Length - 4; i++ ) {
if ( lPage.Skip( i ).Take( 4 ).SequenceEqual( signature ) ) {
// now this should be the start of the item
return pos + i;
}
}
return -1; // not found...
}
/// <summary>
/// Returns the position of the Signature within the stream
/// Searches one page from current location starting at the end of the page
/// </summary>
/// <param name="reader">A positioned reader</param>
/// <returns>The position within the stream or -1 if not found</returns>
public static long FindSignatureInPageBackwards( p4kRecReader reader, byte[] signature )
{
long pos = reader.Position;
byte[] lPage = reader.GetPage( );
for ( int i = lPage.Length - 4; i > 0; i-- ) {
if ( lPage.Skip( i ).Take( 4 ).SequenceEqual( signature ) ) {
// now this should be the start of the item [end of central directory record]
return pos + i;
}
}
return -1; // not found...
}
}
}

@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// Represents an Z64EndOfCentralDirLocator entry in the p4k file
/// The file seems to be based on a Zip64 file structure
internal class p4kZ64EndOfCentralDirLocator
{
/// <summary>
/// ctor: Create class from data returned by the Reader
/// </summary>
/// <param name="reader">A binary data reader for this type of data already positioned</param>
public p4kZ64EndOfCentralDirLocator( p4kRecReader reader )
{
// sanity check only
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyRecord ) ) == RecordLength,
"Record size does not match!(" + Marshal.SizeOf( typeof( MyRecord ) ).ToString( ) + ")" );
if ( reader.IsOpen( ) ) {
try {
long cPos = p4kSignatures.FindSignatureInPageBackwards( reader, p4kSignatures.Z64EndOfCentralDirLocator );
if ( cPos >= 0 ) {
m_recordOffset = cPos;
reader.Seek( cPos );
m_item = p4kRecReader.ByteToType<MyRecord>( reader.TheReader );
m_itemValid = true;
}
}
catch {
m_itemValid = false;
m_recordOffset = -1;
}
finally {
if ( !m_itemValid ) {
throw new OperationCanceledException( string.Format( "EOF - cannot find Z64EndOfCentralDirLocator" ) );
}
}
}
}
public bool IsValid { get => m_itemValid; }
public long RecordOffset { get => m_recordOffset; }
public long Z64EndOfCentralDir
{
get {
if ( m_itemValid )
return (long)m_item.OffsetOfz64EofCDir;
else
return -1;
}
}
private MyRecord m_item;
private bool m_itemValid = false;
private long m_recordOffset = -1; // offset from start (current position)
//4.3.15 Zip64 end of central directory locator
private const int RecordLength = 20;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyRecord
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] ID; // zip64 end of central dir locator signature 4 bytes(0x07064b50)
[MarshalAs( UnmanagedType.U4 )]
public UInt32 DiskNumber; // number of the disk with the start of the zip64 end of central directory 4 bytes
[MarshalAs( UnmanagedType.U8 )]
public UInt64 OffsetOfz64EofCDir; // relative offset of the zip64 end of central directory record 8 bytes (pts to Z64CentralDirRecEnd)
[MarshalAs( UnmanagedType.U4 )]
public UInt32 TotalNumEntries; // total number of disks 4 bytes
}
}
}

@ -0,0 +1,103 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2.p4kFile
{
/// Represents an Z64EndOfCentralDirRecord entry in the p4k file
/// The file seems to be based on a Zip64 file structure
internal class p4kZ64EndOfCentralDirRecord
{
/// <summary>
/// ctor: Create class from data returned by the Reader
/// </summary>
/// <param name="reader">A binary data reader for this type of data - positioned already</param>
public p4kZ64EndOfCentralDirRecord( p4kRecReader reader )
{
// sanity check only
System.Diagnostics.Trace.Assert( Marshal.SizeOf( typeof( MyRecord ) ) == RecordLength,
"Record size does not match!(" + Marshal.SizeOf( typeof( MyRecord ) ).ToString( ) + ")" );
if ( reader.IsOpen( ) ) {
try {
long cPos = p4kSignatures.FindSignatureInPage( reader, p4kSignatures.Z64EndOfCentralDirRec );
if ( cPos >= 0 ) {
m_recordOffset = cPos;
reader.Seek( cPos );
m_item = p4kRecReader.ByteToType<MyRecord>( reader.TheReader );
m_itemValid = true;
}
}
catch {
m_itemValid = false;
m_recordOffset = -1;
}
finally {
if ( !m_itemValid ) {
throw new OperationCanceledException( string.Format( "EOF - cannot find Z64EndOfCentralDirRecord" ) );
}
}
}
}
public bool IsValid { get => m_itemValid; }
public long RecordOffset { get => m_recordOffset; }
public long Z64StartOfCentralDir
{
get {
if ( m_itemValid )
return (long)m_item.OffsetOfZ64CDir;
else
return -1;
}
}
public long NumberOfEntries
{
get {
if ( m_itemValid )
return (long)m_item.NumEntriesTotal;
else
return -1;
}
}
private MyRecord m_item;
private bool m_itemValid = false;
private long m_recordOffset = -1; // offset from start (current position)
//4.3.14 Zip64 end of central directory record
private const int RecordLength = 56;
[StructLayout( LayoutKind.Sequential, Pack = 1 )] // , Size = RecordLength
private struct MyRecord
{
[MarshalAs( UnmanagedType.ByValArray, SizeConst = 4 )]
public byte[] ID; // zip64 end of central dir signature 4 bytes(0x06064b50)
[MarshalAs( UnmanagedType.U8 )]
public UInt64 SizeOfZ64CDir; // size of zip64 end of central directory record 8 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 VersionMadeBy; // version made by 2 bytes
[MarshalAs( UnmanagedType.U2 )]
public UInt16 ExtractVersion; // version made by 2 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 DiskNumber; // number of this disk 4 bytes
[MarshalAs( UnmanagedType.U4 )]
public UInt32 DiskNumbersFromStart; // number of the disk with the start of the central directory 4 bytes
[MarshalAs( UnmanagedType.U8 )]
public UInt64 NumEntriesOnDisk; // total number of entries in the central directory on this disk 8 bytes
[MarshalAs( UnmanagedType.U8 )]
public UInt64 NumEntriesTotal; // total number of entries in the central directory 8 bytes
[MarshalAs( UnmanagedType.U8 )]
public UInt64 SizeOfCDir; // size of the central directory 8 bytes
[MarshalAs( UnmanagedType.U8 )]
public UInt64 OffsetOfZ64CDir; // offset of start of central directory with respect to the starting disk number 8 bytes
// zip64 extensible data sector (variable size)
}
}
}

@ -14,7 +14,8 @@
<TargetFrameworkProfile>
</TargetFrameworkProfile>
<FileAlignment>512</FileAlignment>
<NuGetPackageImportStamp>3422add1</NuGetPackageImportStamp>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
@ -26,8 +27,8 @@
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>66</ApplicationRevision>
<ApplicationVersion>2.32.0.%2a</ApplicationVersion>
<ApplicationRevision>67</ApplicationRevision>
<ApplicationVersion>2.33.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
@ -85,9 +86,6 @@
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="Ionic.Zip.Reduced">
<HintPath>packages\DotNetZip.Reduced.1.9.1.8\lib\net20\Ionic.Zip.Reduced.dll</HintPath>
</Reference>
<Reference Include="log4net">
<HintPath>packages\log4net.2.0.3\lib\net40-full\log4net.dll</HintPath>
</Reference>
@ -121,26 +119,40 @@
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="ZstdNet, Version=1.3.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\ZstdNet.1.3.1\lib\net45\ZstdNet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="actions\ActionCommandCls.cs" />
<Compile Include="actions\ActionTreeEventArgs.cs" />
<Compile Include="actions\ActionTreeInputNode.cs" />
<Compile Include="actions\ActionTreeNode.cs" />
<Compile Include="Actions\ActionCommandCls.cs" />
<Compile Include="Actions\ActionTreeEventArgs.cs" />
<Compile Include="Actions\ActionTreeInputNode.cs" />
<Compile Include="Actions\ActionTreeNode.cs" />
<Compile Include="appConfiguration.cs" />
<Compile Include="AppSettings.cs" />
<Compile Include="CloneableItems.cs" />
<Compile Include="DeviceCls.cs" />
<Compile Include="DeviceInst.cs" />
<Compile Include="DeviceList.cs" />
<Compile Include="Options\FormOptions.cs">
<Compile Include="Common\CloneableItems.cs" />
<Compile Include="Devices\DeviceCls.cs" />
<Compile Include="Devices\DeviceInst.cs" />
<Compile Include="Devices\DeviceList.cs" />
<Compile Include="Devices\Options\FormOptions.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Options\FormOptions.Designer.cs">
<Compile Include="Devices\Options\FormOptions.Designer.cs">
<DependentUpon>FormOptions.cs</DependentUpon>
</Compile>
<Compile Include="Options\Tuningoptions.cs" />
<Compile Include="Devices\Options\Tuningoptions.cs" />
<Compile Include="RTF\RTFformatter.cs" />
<Compile Include="SC\Modifiers.cs" />
<Compile Include="SC\p4kFile\p4kDirectory.cs" />
<Compile Include="SC\p4kFile\p4kDirectoryEntry.cs" />
<Compile Include="SC\p4kFile\p4kEndOfCentralDirRecord.cs" />
<Compile Include="SC\p4kFile\p4kFile.cs" />
<Compile Include="SC\p4kFile\p4kFileHeader.cs" />
<Compile Include="SC\p4kFile\p4kFileTStamp.cs" />
<Compile Include="SC\p4kFile\p4kRecReader.cs" />
<Compile Include="SC\p4kFile\p4kSignatures.cs" />
<Compile Include="SC\p4kFile\p4kZ64EndOfCentralDirLocator.cs" />
<Compile Include="SC\p4kFile\p4kZ64EndOfCentralDirRecord.cs" />
<Compile Include="SC\SCActionMapList.cs" />
<Compile Include="Table\DS_ActionMap.cs" />
<Compile Include="Table\DS_ActionMaps.cs">
@ -158,16 +170,16 @@
<Compile Include="Table\FormTable.Designer.cs">
<DependentUpon>FormTable.cs</DependentUpon>
</Compile>
<Compile Include="Options\DeviceOptionParameter.cs" />
<Compile Include="Gamepad\GamepadCls.cs" />
<Compile Include="Joystick\JsReassingList.cs" />
<Compile Include="Keyboard\KeyboardCls.cs" />
<Compile Include="Joystick\Modifiers.cs" />
<Compile Include="Mouse\MouseCls.cs" />
<Compile Include="MySounds.cs" />
<Compile Include="Devices\Options\DeviceOptionParameter.cs" />
<Compile Include="Devices\Gamepad\GamepadCls.cs" />
<Compile Include="Devices\Joystick\JsReassingList.cs" />
<Compile Include="Devices\Keyboard\KeyboardCls.cs" />
<Compile Include="Devices\Joystick\Modifiers.cs" />
<Compile Include="Devices\Mouse\MouseCls.cs" />
<Compile Include="Common\MySounds.cs" />
<Compile Include="OGL\BezierSeries.cs" />
<Compile Include="OGL\CalcBezierCurve.cs" />
<Compile Include="Options\DeviceTuningParameter.cs" />
<Compile Include="Devices\Options\DeviceTuningParameter.cs" />
<Compile Include="OGL\CubicSpline.cs" />
<Compile Include="OGL\LoaderStatics.cs" />
<Compile Include="OGL\FormJSCalCurve.cs">
@ -176,17 +188,17 @@
<Compile Include="OGL\FormJSCalCurve.Designer.cs">
<DependentUpon>FormJSCalCurve.cs</DependentUpon>
</Compile>
<Compile Include="Options\Deviceoptions.cs" />
<Compile Include="Devices\Options\Deviceoptions.cs" />
<Compile Include="FormMain.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="FormMain.Designer.cs">
<DependentUpon>FormMain.cs</DependentUpon>
</Compile>
<Compile Include="Joystick\FormReassign.cs">
<Compile Include="Devices\Joystick\FormReassign.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Joystick\FormReassign.Designer.cs">
<Compile Include="Devices\Joystick\FormReassign.Designer.cs">
<DependentUpon>FormReassign.cs</DependentUpon>
</Compile>
<Compile Include="FormSettings.cs">
@ -195,11 +207,11 @@
<Compile Include="FormSettings.Designer.cs">
<DependentUpon>FormSettings.cs</DependentUpon>
</Compile>
<Compile Include="Joystick\JoystickList.cs" />
<Compile Include="actions\ActionCls.cs" />
<Compile Include="actions\ActionMapCls.cs" />
<Compile Include="actions\ActionMapsCls.cs" />
<Compile Include="actions\ActionTree.cs" />
<Compile Include="Devices\Joystick\JoystickList.cs" />
<Compile Include="Actions\ActionCls.cs" />
<Compile Include="Actions\ActionMapCls.cs" />
<Compile Include="Actions\ActionMapsCls.cs" />
<Compile Include="Actions\ActionTree.cs" />
<Compile Include="SC\ActivationModes.cs" />
<Compile Include="SC\CryXMLlib\Conversions.cs" />
<Compile Include="SC\CryXMLlib\CryIXml.cs" />
@ -210,17 +222,17 @@
<Compile Include="SC\CryXMLlib\CryXmlNodeRef.cs" />
<Compile Include="SC\CryXMLlib\XmlTree.cs" />
<Compile Include="SC\DProfileReader.cs" />
<Compile Include="Joystick\JoystickCls.cs" />
<Compile Include="actions\MyColors.cs" />
<Compile Include="Joystick\UC_JoyPanel.cs">
<Compile Include="Devices\Joystick\JoystickCls.cs" />
<Compile Include="Common\MyColors.cs" />
<Compile Include="Devices\Joystick\UC_JoyPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Joystick\UC_JoyPanel.Designer.cs">
<Compile Include="Devices\Joystick\UC_JoyPanel.Designer.cs">
<DependentUpon>UC_JoyPanel.cs</DependentUpon>
</Compile>
<Compile Include="Options\OptionTree.cs" />
<Compile Include="Devices\Options\OptionTree.cs" />
<Compile Include="OGL\LoaderDDS.cs" />
<Compile Include="Options\OptionsInvert.cs" />
<Compile Include="Devices\Options\OptionsInvert.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="OGL\RK4Integrator.cs" />
@ -229,20 +241,20 @@
<Compile Include="SC\SCMappings.cs" />
<Compile Include="SC\SCPath.cs" />
<Compile Include="TheUser.cs" />
<Compile Include="Joystick\UICustHeader.cs" />
<Compile Include="Devices\Joystick\UICustHeader.cs" />
<Compile Include="OGL\TriDiagonalMatrix.cs" />
<Compile Include="Joystick\xyPoints.cs" />
<Compile Include="Gamepad\UC_GpadPanel.cs">
<Compile Include="Devices\Joystick\xyPoints.cs" />
<Compile Include="Devices\Gamepad\UC_GpadPanel.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Gamepad\UC_GpadPanel.Designer.cs">
<Compile Include="Devices\Gamepad\UC_GpadPanel.Designer.cs">
<DependentUpon>UC_GpadPanel.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="FormMain.resx">
<DependentUpon>FormMain.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Options\FormOptions.resx">
<EmbeddedResource Include="Devices\Options\FormOptions.resx">
<DependentUpon>FormOptions.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Table\FormTable.resx">
@ -251,13 +263,13 @@
<EmbeddedResource Include="OGL\FormJSCalCurve.resx">
<DependentUpon>FormJSCalCurve.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Joystick\FormReassign.resx">
<EmbeddedResource Include="Devices\Joystick\FormReassign.resx">
<DependentUpon>FormReassign.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="FormSettings.resx">
<DependentUpon>FormSettings.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Joystick\UC_JoyPanel.resx">
<EmbeddedResource Include="Devices\Joystick\UC_JoyPanel.resx">
<DependentUpon>UC_JoyPanel.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
@ -270,7 +282,7 @@
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="Gamepad\UC_GpadPanel.resx">
<EmbeddedResource Include="Devices\Gamepad\UC_GpadPanel.resx">
<DependentUpon>UC_GpadPanel.cs</DependentUpon>
</EmbeddedResource>
<None Include="app.config" />
@ -286,6 +298,8 @@
<None Include="graphics\SB_Sunset.dds">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="LICENSE" />
<None Include="README.md" />
<None Include="Table\DS_ActionMaps.xsc">
<DependentUpon>DS_ActionMaps.xsd</DependentUpon>
</None>
@ -333,6 +347,7 @@
<Content Include="AC_Examples.txt" />
<Content Include="Cassini_Logo_Icon.ico" />
<Content Include="defaultProfile.xml" />
<Content Include="ReadMe.txt" />
<None Include="graphics\YPR.png" />
<None Include="graphics\300i.jpg" />
<None Include="graphics\aurora.jpg" />
@ -385,7 +400,9 @@
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\SharpDX.2.6.3\build\SharpDX.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\SharpDX.2.6.3\build\SharpDX.targets'))" />
<Error Condition="!Exists('packages\ZstdNet.1.3.1\build\ZstdNet.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\ZstdNet.1.3.1\build\ZstdNet.targets'))" />
</Target>
<Import Project="packages\ZstdNet.1.3.1\build\ZstdNet.targets" Condition="Exists('packages\ZstdNet.1.3.1\build\ZstdNet.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SCJMapper_V2.Devices;
namespace SCJMapper_V2.Table
{

@ -7,6 +7,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SCJMapper_V2.Devices;
namespace SCJMapper_V2.Table
{

@ -2,16 +2,19 @@
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Linq;
using System.IO;
using SCJMapper_V2.Common;
using SCJMapper_V2.SC;
using SCJMapper_V2.Keyboard;
using SCJMapper_V2.Mouse;
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using System.Linq;
using SCJMapper_V2.Devices;
using SCJMapper_V2.Devices.Keyboard;
using SCJMapper_V2.Devices.Mouse;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Maintains an action - something like:

@ -4,9 +4,10 @@ using System.Linq;
using System.Text;
using SCJMapper_V2.SC;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Devices;
using SCJMapper_V2.Devices.Joystick;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Maintains one ActionCommand

@ -4,10 +4,10 @@ using System.Text;
using System.Xml;
using System.IO;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Devices.Joystick;
using System.Linq;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Maintains an actionmap - something like:

@ -13,14 +13,15 @@ using System.Data;
using SCJMapper_V2.SC;
using SCJMapper_V2.Table;
using SCJMapper_V2.Keyboard;
using SCJMapper_V2.Mouse;
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Options;
using SCJMapper_V2.Devices;
using SCJMapper_V2.Devices.Keyboard;
using SCJMapper_V2.Devices.Mouse;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
using SCJMapper_V2.Devices.Options;
using System.Linq;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Maintains the complete ActionMaps - something like:
@ -109,10 +110,10 @@ namespace SCJMapper_V2
/// <returns>The ActionMaps copy with reassigned input</returns>
public ActionMapsCls ReassignJsN( JsReassingList newJsList )
{
var newMaps = new ActionMapsCls(this);
newMaps.m_uiCustHeader = ( UICustHeader )this.m_uiCustHeader.Clone( );
newMaps.m_tuningOptions = ( Tuningoptions )this.m_tuningOptions.Clone( );
newMaps.m_deviceOptions = ( Deviceoptions )this.m_deviceOptions.Clone( );
var newMaps = new ActionMapsCls( this );
newMaps.m_uiCustHeader = (UICustHeader)this.m_uiCustHeader.Clone( );
newMaps.m_tuningOptions = (Tuningoptions)this.m_tuningOptions.Clone( );
newMaps.m_deviceOptions = (Deviceoptions)this.m_deviceOptions.Clone( );
foreach ( ActionMapCls am in this ) {
newMaps.Add( am.ReassignJsN( newJsList ) ); // creates the deep copy of the tree
@ -135,7 +136,7 @@ namespace SCJMapper_V2
/// <summary>
/// ctor
/// </summary>
public ActionMapsCls( )
public ActionMapsCls()
{
version = ACM_VERSION;
@ -154,7 +155,7 @@ namespace SCJMapper_V2
private void CreateNewOptions( )
private void CreateNewOptions()
{
// create options objs
m_uiCustHeader = new UICustHeader( );
@ -172,12 +173,13 @@ namespace SCJMapper_V2
log.Debug( "Merge - Entry" );
// do we find an actionmap like the new one in our list ?
ActionMapCls ACM = this.Find( delegate( ActionMapCls acm ) {
ActionMapCls ACM = this.Find( delegate ( ActionMapCls acm ) {
return acm.name == newAcm.name;
} );
if ( ACM == null ) {
; // this.Add( newAcm ); // no, add new
} else {
}
else {
ACM.Merge( newAcm ); // yes, merge it
}
}
@ -192,8 +194,8 @@ namespace SCJMapper_V2
int AMcount = 1;
foreach ( ActionMapCls am in this ) {
DS_ActionMaps.T_ActionMapRow amr = dsa.T_ActionMap.NewT_ActionMapRow();
string amShown = DS_ActionMap.ActionMapShown(am.name, AMcount++);
DS_ActionMaps.T_ActionMapRow amr = dsa.T_ActionMap.NewT_ActionMapRow( );
string amShown = DS_ActionMap.ActionMapShown( am.name, AMcount++ );
amr.ID_ActionMap = amShown;
dsa.T_ActionMap.AddT_ActionMapRow( amr );
@ -201,7 +203,7 @@ namespace SCJMapper_V2
foreach ( ActionCls ac in am ) {
int ilIndex = 0;
while ( ac.inputList.Count > ilIndex ) {
DS_ActionMaps.T_ActionRow ar = dsa.T_Action.NewT_ActionRow();
DS_ActionMaps.T_ActionRow ar = dsa.T_Action.NewT_ActionRow( );
ar.ID_Action = DS_ActionMap.ActionID( am.name, ac.key, ac.inputList[ilIndex].NodeIndex ); // make a unique key
ar.AddBind = ( ilIndex > 0 ); // all but the first are addbinds
ar.REF_ActionMap = amShown;
@ -228,13 +230,13 @@ namespace SCJMapper_V2
public void updateDataSet( DS_ActionMaps dsa, string actionID )
{
foreach ( ActionMapCls am in this ) {
DS_ActionMaps.T_ActionMapRow amr = dsa.T_ActionMap.NewT_ActionMapRow();
DS_ActionMaps.T_ActionMapRow amr = dsa.T_ActionMap.NewT_ActionMapRow( );
foreach ( ActionCls ac in am ) {
int ilIndex = 0;
while ( ac.inputList.Count > ilIndex ) {
if ( actionID == DS_ActionMap.ActionID( am.name, ac.key, ac.inputList[ilIndex].NodeIndex ) ) {
DS_ActionMaps.T_ActionRow ar =dsa.T_Action.FindByID_Action(actionID);
DS_ActionMaps.T_ActionRow ar = dsa.T_Action.FindByID_Action( actionID );
ar.Usr_Binding = ac.inputList[ilIndex].DevInput;
ar.Usr_Modifier = ac.inputList[ilIndex].ActivationMode.Name;
ar.Disabled = DeviceCls.IsBlendedInput( ac.inputList[ilIndex].Input );
@ -260,7 +262,7 @@ namespace SCJMapper_V2
{
log.Debug( "ActionMapsCls.toXML - Entry" );
AppSettings appSettings = new AppSettings( );
AppSettings appSettings = new AppSettings( );
// *** HEADER
@ -308,8 +310,10 @@ namespace SCJMapper_V2
// *** DEVICE OPTIONS
if ( m_deviceOptions.Count > 0 ) r += m_deviceOptions.toXML( ) + string.Format( "\n" );
// *** ACTION MAPS
// *** MODIFIERS
if ( SC.Modifiers.Instance.UserCount > 0 ) r += SC.Modifiers.Instance.ToXML( ) + string.Format( "\n" );
// *** ACTION MAPS
foreach ( ActionMapCls amc in this ) {
r += string.Format( "{0}\n", amc.toXML( ) );
}
@ -347,7 +351,8 @@ namespace SCJMapper_V2
jsN[i] = reader[string.Format( "js{0}", i + 1 )];
jsNGUID[i] = reader[string.Format( "js{0}G", i + 1 )];
}
} else {
}
else {
return false;
}
}
@ -371,16 +376,24 @@ namespace SCJMapper_V2
if ( acm.fromXML( x ) ) {
this.Merge( acm ); // merge list
}
} else if ( reader.Name.ToLowerInvariant( ) == "customisationuiheader" ) {
}
else if ( reader.Name.ToLowerInvariant( ) == "customisationuiheader" ) {
string x = reader.ReadOuterXml( );
m_uiCustHeader.fromXML( x );
} else if ( reader.Name.ToLowerInvariant( ) == "deviceoptions" ) {
}
else if ( reader.Name.ToLowerInvariant( ) == "deviceoptions" ) {
string x = reader.ReadOuterXml( );
m_deviceOptions.fromXML( x );
} else if ( reader.Name.ToLowerInvariant( ) == "options" ) {
}
else if ( reader.Name.ToLowerInvariant( ) == "options" ) {
string x = reader.ReadOuterXml( );
m_tuningOptions.fromXML( x );
} else {
}
else if ( reader.Name.ToLowerInvariant( ) == "modifiers" ) {
string x = reader.ReadOuterXml( );
SC.Modifiers.Instance.FromXML( x ); // add as 'non profile'
}
else {
reader.Read( );
}

@ -8,13 +8,13 @@ using System.Drawing;
using SCJMapper_V2.Properties;
using SCJMapper_V2.SC;
using SCJMapper_V2.Table;
using SCJMapper_V2.Keyboard;
using SCJMapper_V2.Mouse;
using SCJMapper_V2.Gamepad;
using SCJMapper_V2.Joystick;
using SCJMapper_V2.Options;
using SCJMapper_V2.Devices;
using SCJMapper_V2.Devices.Keyboard;
using SCJMapper_V2.Devices.Mouse;
using SCJMapper_V2.Devices.Gamepad;
using SCJMapper_V2.Devices.Joystick;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Maintains the action tree and its GUI representation, the TreeView
@ -460,7 +460,7 @@ namespace SCJMapper_V2
/// </summary>
/// <param name="defaultProfileName">The name of the profile to load (w extension)</param>
/// <param name="applyDefaults">True if default mappings should be carried on</param>
public void LoadProfileTree( string defaultProfileName, bool applyDefaults )
public void LoadProfileTree( bool applyDefaults )
{
log.Debug( "LoadProfileTree - Entry" );
@ -480,7 +480,7 @@ namespace SCJMapper_V2
DProfileReader dpReader = new DProfileReader( ); // we may read a profile
TextReader txReader = null;
dpReader.fromXML( SCDefaultProfile.DefaultProfile( defaultProfileName ) );
dpReader.fromXML( SCDefaultProfile.DefaultProfile( ) );
if ( dpReader.ValidContent ) {
txReader = new StringReader( dpReader.CSVMap );
}

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Event class to automate selection,

@ -4,7 +4,7 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SCJMapper_V2
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Our INPUT TreeNode - inherits a regular one and adds some functionality

@ -4,7 +4,10 @@ using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SCJMapper_V2
using SCJMapper_V2.Common;
using SCJMapper_V2.Devices;
namespace SCJMapper_V2.Actions
{
/// <summary>
/// Our TreeNode - inherits a regular one and adds some functionality

@ -393,7 +393,7 @@
<action name="v_view_zoom_in" onPress="1" onHold="1" mouse="mwheel_up" xboxpad=" " joystick=" " UILabel="@ui_CIZoomIn" UIDescription="@ui_CIZoomInDesc" />
<action name="v_view_zoom_out" onPress="1" onHold="1" mouse="mwheel_down" xboxpad=" " joystick=" " UILabel="@ui_CIZoomOut" UIDescription="@ui_CIZoomOutDesc" />
<action name="v_view_interact" onPress="1" onRelease="1" keyboard="f" xboxpad="triggerr_btn" joystick=" " />
<action name="v_view_freelook_mode" ActivationMode="all" keyboard="lalt" xboxpad=" " joystick=" " UILabel="@ui_CIUnlockView" UIDescription="@ui_CIUnlockViewDesc" />
<action name="v_view_freelook_mode" ActivationMode="all" keyboard="z" xboxpad=" " joystick=" " UILabel="@ui_CIUnlockView" UIDescription="@ui_CIUnlockViewDesc" />
<action name="v_view_dynamic_focus" keyboard="maxis_z" xboxpad=" " joystick=" " optionGroup="flight_zoom" UILabel="@ui_CIDynamicZoomInOut" UIDescription="@ui_CIDynamicZoomInOutDesc" />
<action name="v_view_dynamic_focus_in" ActivationMode="all" keyboard=" " xboxpad=" " joystick=" " UILabel="@ui_CIDynamicZoomIn" UIDescription="@ui_CIDynamicZoomInDesc" />
<action name="v_view_dynamic_focus_out" ActivationMode="all" keyboard=" " xboxpad=" " joystick=" " UILabel="@ui_CIDynamicZoomOut" UIDescription="@ui_CIDynamicZoomOutDesc" />
@ -422,7 +422,7 @@
<action name="v_throttle_down" onPress="1" onRelease="1" always="1" keyboard="s" xboxpad="triggerl_btn" joystick=" " optiongroup="flight_move_throttle_down" UILabel="@ui_CIThrottleDown" UIDescription="@ui_CIThrottleDownDesc" UICategory="@ui_CCThrottleControl" />
<action name="v_throttle_abs" onPress="1" onRelease="1" always="1" joystick="throttlez" optionGroup="flight_throttle_abs" UILabel="@ui_CIThrottle" UIDescription="@ui_CIThrottleDesc" />
<action name="v_throttle_rel" keyboard=" " xboxpad=" " joystick=" " optionGroup="flight_throttle_rel" UILabel="@ui_CIThrottleRel" UIDescription="@ui_CIThrottleRelDesc" />
<action name="v_brake" onPress="1" onRelease="1" keyboard="z" xboxpad=" " joystick=" " UILabel="@ui_CIBrake" UIDescription="@ui_CIBrakeDesc" />
<action name="v_brake" onPress="1" onRelease="1" keyboard="capslock" xboxpad=" " joystick=" " UILabel="@ui_CIBrake" UIDescription="@ui_CIBrakeDesc" />
<action name="v_target_match_vel" ActivationMode="press" keyboard=" " xboxpad=" " joystick=" " UILabel="@ui_CIMatchTargetSpeed" UIDescription="@ui_CIMatchTargetSpeedDesc" />
<action name="v_ifcs_toggle_vector_decoupling" ActivationMode="smart_toggle" keyboard=" " xboxpad=" " joystick=" " UILabel="@ui_CIToggleDecoupledMode" UIDescription="@ui_CIToggleDecoupledModeDesc" UICategory="@ui_CCFlightModes" />
<action name="v_strafe_up" onPress="1" onRelease="1" always="1" keyboard="space" xboxpad=" " joystick="button9" optionGroup="flight_move_strafe_vertical" UILabel="@ui_CIStrafeUp" UIDescription="@ui_CIStrafeUpDesc" />
@ -461,7 +461,6 @@
<action name="v_boost" ActivationMode="all" keyboard="x" xboxpad="thumbl" joystick="button7" UILabel="@ui_CIboost" UIDescription="@ui_CIboostDesc" />
<action name="v_toggle_landing_system" ActivationMode="tap" keyboard="n" xboxpad="shoulderl+dpad_up" joystick="button12" UILabel="@ui_CIToggleLandingSystem" UIDescription="@ui_CIToggleLandingSystemDesc" />
<action name="v_autoland" ActivationMode="delayed_hold" keyboard="n" xboxpad="y" joystick="button12" UILabel="@ui_CIAutoland" UIDescription="@ui_CIAutolandDesc" />
<action name="v_toggle_qdrive_engagement" ActivationMode="delayed_press" keyboard="b" xboxpad="y" UILabel="@ui_CIQuantumDriveToggle" UIDescription="@ui_CIQuantumDriveToggleDesc" >
<joystick ActivationMode="press" input=" " />
</action>
@ -696,7 +695,7 @@
<joystick ActivationMode="press" input=" " />
</action>
<action name="prone" ActivationMode="hold" keyboard="z" joystick=" " UILabel="@ui_CIFPSStanceProne" UIDescription="@ui_CIFPSStanceProneDesc" >
<action name="prone" ActivationMode="hold" keyboard="capslock" joystick=" " UILabel="@ui_CIFPSStanceProne" UIDescription="@ui_CIFPSStanceProneDesc" >
<xboxpad ActivationMode="delayed_press" input="b" />
</action>
@ -748,7 +747,7 @@
<action name="cancelselect" ActivationMode="press" onRelease="1" keyboard="mouse2" xboxpad="b" />
<action name="thirdperson" ActivationMode="tap" noModifiers="1" keyboard="f4" xboxpad=" " joystick=" " UILabel="@ui_CIFPSToggleThirdPerson" UIDescription="@ui_CIFPSToggleThirdPersonDesc" />
<action name="toggle_cursor_input" ActivationMode="hold" keyboard="tab" xboxpad="back" />
<action name="free_thirdperson_camera" ActivationMode="tap" keyboard="lalt" xboxpad=" " joystick=" " UILabel="@ui_CIFPSToggle3rdPersonFreeView" UIDescription="@ui_CIFPSToggle3rdPersonFreeViewDesc" />
<action name="free_thirdperson_camera" ActivationMode="tap" keyboard="z" xboxpad=" " joystick=" " UILabel="@ui_CIFPSToggle3rdPersonFreeView" UIDescription="@ui_CIFPSToggle3rdPersonFreeViewDesc" />
<action name="pan_thirdperson_up" ActivationMode="press" keyboard="up" />
<action name="pan_thirdperson_down" ActivationMode="press" keyboard="down" />
<action name="break_conversation_effects" onPress="1" onRelease="1" keyboard="lshift" xboxpad="thumbl" UILabel="" UIDescription="" />
@ -823,9 +822,9 @@
<action name="eva_strafe_forward" ActivationMode="hold" always="1" keyboard="w" xboxpad=" " joystick=" " UILabel="@ui_CIEVAStrafeForward" UIDescription="@ui_CIEVAStrafeForwardDesc" />
<action name="eva_strafe_back" ActivationMode="hold" always="1" keyboard="s" xboxpad=" " joystick=" " UILabel="@ui_CIEVAStrafeBack" UIDescription="@ui_CIEVAStrafeBackDesc" />
<action name="eva_strafe_longitudinal" keyboard=" " xboxpad="thumbly" joystick=" " UILabel="@ui_CIEVAStrafeLongitudinal" UIDescription="@ui_CIEVAStrafeLongitudinalDesc" />
<action name="eva_brake" ActivationMode="hold" keyboard="z" xboxpad="b" joystick=" " UILabel="@ui_CIEVABrake" UIDescription="@ui_CIEVABrakeDesc" />
<action name="eva_brake" ActivationMode="hold" keyboard="capslock" xboxpad="b" joystick=" " UILabel="@ui_CIEVABrake" UIDescription="@ui_CIEVABrakeDesc" />
<action name="eva_boost" ActivationMode="hold" keyboard="lshift" xboxpad="thumbl" joystick=" " UILabel="@ui_CIEVABoost" UIDescription="@ui_CIEVABoostDesc" />
<action name="eva_toggle_headlook_mode" ActivationMode="tap" keyboard="lalt" xboxpad=" " joystick=" " UILabel="@ui_CIEVAFreelook" UIDescription="@ui_CIEVAFreelookDesc" />
<action name="eva_toggle_headlook_mode" ActivationMode="tap" keyboard="z" xboxpad=" " joystick=" " UILabel="@ui_CIEVAFreelook" UIDescription="@ui_CIEVAFreelookDesc" />
</actionmap>
<actionmap name="vehicle_general" version="27" UILabel="@ui_CGVehicleGeneral" UICategory="@ui_CCVehicle" >
@ -833,7 +832,7 @@
<xboxpad ActivationMode="delayed_press" input="shoulderl+y" />
</action>
<action name="v_horn" onPress="1" onRelease="1" keyboard="z" xboxpad="b" joystick="button8" UILabel="@ui_CIVehicleHorn" UIDescription="@ui_CIVehicleHornDesc" />
<action name="v_horn" onPress="1" onRelease="1" keyboard="capslock" xboxpad="b" joystick="button8" UILabel="@ui_CIVehicleHorn" UIDescription="@ui_CIVehicleHornDesc" />
<action name="v_view_cycle_fwd" ActivationMode="tap" keyboard="f4" xboxpad=" " joystick=" " UILabel="@ui_CICycleView" UIDescription="@ui_CICycleViewDesc" />
<action name="v_view_option" onPress="1" onRelease="1" keyboard="" xboxpad="" />
<action name="v_view_zoom_in" onPress="1" onHold="1" mouse="mwheel_up" xboxpad=" " joystick=" " UILabel="@ui_CIZoomIn" UIDescription="@ui_CIZoomInDesc" />
@ -948,7 +947,7 @@
<action name="spectate_moveup" ActivationMode="hold" keyboard="space" xboxpad="shoulderl+thumbr_up" UILabel="" UIDescription="" />
<action name="spectate_movedown" ActivationMode="hold" keyboard="lctrl" xboxpad="shoulderl+thumbr_down" UILabel="" UIDescription="" />
<action name="spectate_freecam_sprint" ActivationMode="hold" keyboard="lshift" xboxpad="thumbl" UILabel="" UIDescription="" />
<action name="spectate_toggle_freecam" ActivationMode="tap" keyboard="lalt" xboxpad="thumbr" UILabel="" UIDescription="" />
<action name="spectate_toggle_freecam" ActivationMode="tap" keyboard="z" xboxpad="thumbr" UILabel="" UIDescription="" />
</actionmap>
<actionmap name="default" version="24" UILabel="@ui_CGUIGeneral" UIDescription="@ui_CGUGeneralDesc" >
@ -1287,3 +1286,4 @@
</actionmap>
</profile>

@ -1,15 +1,17 @@
SC Joystick Mapper V 2.32 - Build 66 BETA
(c) Cassini, StandardToaster - 16-Dec-2017
SC Joystick Mapper V 2.33 - Build 67 BETA
(c) Cassini, StandardToaster - 23-Dec-2017
Contains 9 files:
Contains 12 files + graphics:
SCJMapper.exe The program (V2.32)
SCJMapper.exe.config Program config (V2.32) - MUST be in the same folder as the Exe file
SCJMapper.exe The program (V2.33)
SCJMapper.exe.config Program config (V2.33) - MUST be in the same folder as the Exe file
SharpDX.DirectInput.dll Managed DirectInput Assembly - MUST be in the same folder as the Exe file
SharpDX.dll Managed DirectX Assembly - MUST be in the same folder as the Exe file
OpenTK.dll Managed OpenGL Assembly - MUST be in the same folder as the Exe file
OpenTK.GLControl.dll Managed OpenGL Assembly - MUST be in the same folder as the Exe file
Ionic.Zip.Reduced.dll Managed Zip Assembly - MUST be in the same folder as the Exe file
ZstdNet.dll Managed Zip Assembly (v2.33) - MUST be in the same folder as the Exe file
x64/libzstd.dll Native dll for ZstdNet (v2.33) - MUST be in the same folder as the Exe file
x86/libzstd.dll Native dll for ZstdNet (v2.33) - MUST be in the same folder as the Exe file
log4net.dll Managed Logging Assembly - MUST be in the same folder as the Exe file
log4net.config.OFF Config file for logging - To use it - rename as log4net.config and run the program
then look for trace.log in the same folder
@ -18,6 +20,15 @@ ReadMe.txt This file
graphics folder Skybox Images (V2.32) - graphics folder MUST be in the same folder as the Exe file
NOTE V 2.33:
search order for defaultProfile.xml to build the action tree is:
1. directory where SCJMapper Exe is located
2. directory of <SC>\LIVE\USER
3. extract from <SC>\LIVE\Data.p4k
4. extract from SCJMapper exe file (derived from 3.0 build 695052)
--> in order to get always the most current one use 3. (and therefore remove the ones in 1. and 2.)
--> The one used is shown below the actionTree (Profile: ....)
Read the Guide first RTFM ;-)
Put all files into one folder and hit SCJMapper.exe to run it
@ -29,8 +40,17 @@ Scanned for viruses before packing...
cassini@burri-web.org
Changelog:
V 2.33 - BETA Build 67
- update for SC 3.0.0 Alpha public
- fix - finding SC game folder - may work automatically for 3.0 Alpha else define it in Settings
- add - get the defaultProfile.xml from LIVE\data.p4k file if possible (real game assets)
- improvement - caching def profile once it is read from disk
- removed - old SC path and folder locators (SCJM does not longer work with pre 3.0 game)
- removed - reference to Iconic.Zip DLL (replaced with Zstd)
- update - defaultProfile.xml as last resort from PTU 3.0-695052 (Dec 18, build)
V 2.32 - BETA Build 66
- add - path to defaultProfile can be in USER directory of SC
- add - some skyboxes from game captures (thanks to Rellim)
- removed - PTU folders in Settings - no longer used in PTU 3.0
- fix - finding SC game folder - may work automatically for PTU 3.0 else define it in Settings
- update - defaultProfile from PTU 3.0-689345 (Dec 15, build)
@ -44,7 +64,6 @@ V 2.30 - BETA Build 64
- fix - issue with loading a map with gamepad mappings and the gamepad is not connected
- fixes and refacturing while encountered...
- update - doc SCJMapper_QGuide V2.30beta.pdf
Changelog:
V 2.29 - BETA Build 63
- add - Calibrate gamepad thumb axes (press ABXY buttons all together and wait 2 sec - should zero all 4 axes)
- fix #56 - exception when entering Tuning

@ -1,5 +1,9 @@
Canyon, Highway, Shiodome, BigSight, LA Heliport:
Image Credits:
SC_Area18, _GrimHex, _DyingStar, _BrokenMoon, _Kareah
by Rellim (SC handle)
Canyon, Highway, Shiodome, BigSight, LA Heliport:
http://www.hdrlabs.com/sibl/archive.html
sIBL Archive - Free HDRI sets for smart Image-Based Lighting

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="DotNetZip.Reduced" version="1.9.1.8" targetFramework="net40" />
<package id="log4net" version="2.0.3" targetFramework="net40" />
<package id="OpenTK" version="1.1.1589.5942" targetFramework="net40" />
<package id="OpenTK.GLControl" version="1.1.1589.5942" targetFramework="net40" />
<package id="SharpDX" version="2.6.3" targetFramework="net40" />
<package id="SharpDX.DirectInput" version="2.6.3" targetFramework="net40" />
<package id="ZstdNet" version="1.3.1" targetFramework="net452" />
</packages>

Binary file not shown.

@ -0,0 +1,30 @@
BSD License
For ZstdNet software
Copyright (c) 2016-2017, SKB Kontur. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name SKB Kontur nor the names of its contributors may be used to
endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Binary file not shown.
Loading…
Cancel
Save