├── Psarc
├── Models
│ ├── Sng
│ │ ├── Dna.cs
│ │ ├── Tone.cs
│ │ ├── Bpm.cs
│ │ ├── Event.cs
│ │ ├── Action.cs
│ │ ├── SymbolsHeader.cs
│ │ ├── PhraseIteration.cs
│ │ ├── SymbolsTexture.cs
│ │ ├── PhraseExtraInfoByLevel.cs
│ │ ├── Vocal.cs
│ │ ├── Phrase.cs
│ │ ├── BendData.cs
│ │ ├── SymbolDefinition.cs
│ │ ├── Section.cs
│ │ ├── Chord.cs
│ │ ├── NLinkedDifficulty.cs
│ │ ├── ChordNotes.cs
│ │ ├── Metadata.cs
│ │ └── Arrangement.cs
│ ├── IBinarySerializable.cs
│ ├── ToolkitInfo.cs
│ └── Json
│ │ └── SongArrangement.cs
├── Asset
│ ├── PsarcAsset.cs
│ ├── JsonLinqAsset.cs
│ ├── JsonObjectAsset.cs
│ ├── TextPsarcAsset.cs
│ ├── ToolkitInfoAsset.cs
│ ├── DdsAsset.cs
│ └── SngAsset.cs
├── PsarcArchiveFlags.cs
├── PsarcTOCEntry.cs
├── PsarcFileHeader.cs
├── PsarcTOC.cs
└── PsarcFile.cs
├── Rocksmith2014PsarcLib.csproj
├── ReaderExtensions
├── GeneralReaderExtensions.cs
├── ArrayReaderExtensions.cs
├── StructReaderExtensions.cs
└── BigEndianReaderExtensions.cs
├── LICENSE
├── README.md
├── .gitignore
└── Crypto
└── DecryptStream.cs
/Psarc/Models/Sng/Dna.cs:
--------------------------------------------------------------------------------
1 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
2 | {
3 | public struct Dna
4 | {
5 | public float Time;
6 | public int DnaId;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Tone.cs:
--------------------------------------------------------------------------------
1 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
2 | {
3 | public struct Tone
4 | {
5 | public float Time;
6 | public int ToneId;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Psarc/Models/IBinarySerializable.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models
4 | {
5 | public interface IBinarySerializable
6 | {
7 | IBinarySerializable Read(BinaryReader reader);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Psarc/Asset/PsarcAsset.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Asset
4 | {
5 | public abstract class PsarcAsset
6 | {
7 | public virtual void ReadFrom(MemoryStream stream)
8 | {
9 |
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Bpm.cs:
--------------------------------------------------------------------------------
1 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
2 | {
3 | public struct Bpm
4 | {
5 | public float Time;
6 | public short Measure;
7 | public short Beat;
8 | public int PhraseIteration;
9 | public int Mask;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Event.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Event
6 | {
7 | public float Time;
8 |
9 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
10 | public string EventName;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Action.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Action
6 | {
7 | public float Time;
8 |
9 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
10 | public string ActionName;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/SymbolsHeader.cs:
--------------------------------------------------------------------------------
1 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
2 | {
3 | public struct SymbolsHeader
4 | {
5 | public int Unk1;
6 | public int Unk2;
7 | public int Unk3;
8 | public int Unk4;
9 | public int Unk5;
10 | public int Unk6;
11 | public int Unk7;
12 | public int Unk8;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Psarc/PsarcArchiveFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc
4 | {
5 | [Flags]
6 | public enum PsarcArchiveFlags
7 | {
8 | NONE = 0,
9 | UNK1 = 1,
10 | UNK2 = 2,
11 | TOC_ENCRYPTED = 4,
12 | UNK8 = 8,
13 | UNK16 = 16,
14 | UNK32 = 32,
15 | UNK64 = 64,
16 | UNK128 = 128
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/PhraseIteration.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct PhraseIteration
6 | {
7 | public int PhraseId;
8 | public float StartTime;
9 | public float NextPhraseTime;
10 |
11 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
12 | public int[] Difficulty;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/SymbolsTexture.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct SymbolsTexture
6 | {
7 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
8 | public string Font;
9 |
10 | public int FontpathLength;
11 | public int Unk1_0;
12 | public int Width;
13 | public int Height;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Psarc/PsarcTOCEntry.cs:
--------------------------------------------------------------------------------
1 | namespace Rocksmith2014PsarcLib.Psarc
2 | {
3 | public class PsarcTOCEntry
4 | {
5 | public int Index { get; internal set; }
6 | public string Hash { get; internal set; }
7 | public uint StartBlock { get; internal set; }
8 | public ulong Length { get; internal set; }
9 | public ulong Offset { get; internal set; }
10 | public string Path { get; internal set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/PhraseExtraInfoByLevel.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | [StructLayout(LayoutKind.Sequential, Pack = 1)]
6 | public struct PhraseExtraInfoByLevel
7 | {
8 | public int PhraseId;
9 | public int Difficulty;
10 | public int Empty;
11 | public byte LevelJump;
12 | public short Redundant;
13 | public byte Padding;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Vocal.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Vocal
6 | {
7 | public float Time;
8 | public int Note;
9 | public float Length;
10 |
11 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
12 | public byte[] LyricBytes;
13 |
14 | public string Lyric => System.Text.Encoding.UTF8.GetString(LyricBytes);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Phrase.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Phrase
6 | {
7 | public byte Solo;
8 | public byte Disparity;
9 | public byte Ignore;
10 | public byte Padding;
11 |
12 | public int MaxDifficulty;
13 | public int PhraseIterationLinks;
14 |
15 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
16 | public string Name;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/BendData.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct BendData32
6 | {
7 | public float Time;
8 | public float Step;
9 | public short Unk3_0;
10 | public byte Unk4_0;
11 | public byte Unk5;
12 | }
13 |
14 | public struct BendData
15 | {
16 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
17 | public BendData32[] BendData32;
18 |
19 | public int UsedCount;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/SymbolDefinition.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Rect
6 | {
7 | public float yMin;
8 | public float xMin;
9 | public float yMax;
10 | public float xMax;
11 | }
12 |
13 | public struct SymbolDefinition
14 | {
15 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 12)]
16 | public string Text;
17 | public Rect Rect_Outter;
18 | public Rect Rect_Inner;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Section.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Section
6 | {
7 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
8 | public string Name;
9 |
10 | public int Number;
11 | public float StartTime;
12 | public float EndTime;
13 | public int StartPhraseIterationId;
14 | public int EndPhraseIterationId;
15 |
16 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 36)]
17 | public string StringMask;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Chord.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct Chord
6 | {
7 | public uint Mask;
8 |
9 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
10 | public byte[] Frets;
11 |
12 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
13 | public byte[] Fingers;
14 |
15 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
16 | public int[] Notes;
17 |
18 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
19 | public string Name;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/NLinkedDifficulty.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Rocksmith2014PsarcLib.ReaderExtensions;
3 |
4 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
5 | {
6 | public struct NLinkedDifficulty : IBinarySerializable
7 | {
8 | public int LevelBreak;
9 | public int PhraseCount;
10 |
11 | public int[] NLD_Phrase;
12 |
13 | public IBinarySerializable Read(BinaryReader reader)
14 | {
15 | LevelBreak = reader.ReadInt32();
16 | PhraseCount = reader.ReadInt32();
17 |
18 | NLD_Phrase = reader.ReadIntArray(PhraseCount);
19 |
20 | return this;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/ChordNotes.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
4 | {
5 | public struct ChordNotes
6 | {
7 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
8 | public int[] NoteMask;
9 |
10 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
11 | public BendData[] BendData;
12 |
13 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
14 | public byte[] SlideTo;
15 |
16 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
17 | public byte[] SlideUnpitchTo;
18 |
19 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
20 | public short[] Vibrato;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Rocksmith2014PsarcLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | default
5 | AnyCPU;x64
6 | enable
7 | true
8 |
9 |
10 | none
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Psarc/Asset/JsonLinqAsset.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using System.IO;
4 |
5 | namespace Rocksmith2014PsarcLib.Psarc.Asset
6 | {
7 | public class JsonLinqAsset : PsarcAsset
8 | {
9 | public JObject JsonObject { get; private set; }
10 |
11 | public override void ReadFrom(MemoryStream stream)
12 | {
13 | base.ReadFrom(stream);
14 |
15 | using (var reader = new StreamReader(stream))
16 | {
17 | using (var jsonReader = new JsonTextReader(reader))
18 | {
19 | var serializer = new JsonSerializer();
20 |
21 | JsonObject = serializer.Deserialize(jsonReader);
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/ReaderExtensions/GeneralReaderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace Rocksmith2014PsarcLib.ReaderExtensions
5 | {
6 | public static class GeneralReaderExtensions
7 | {
8 | ///
9 | /// Reads a zero terminated string
10 | ///
11 | ///
12 | ///
13 | ///
14 | ///
15 | public static string ReadString(this BinaryReader reader, int size, Encoding encoding = null)
16 | {
17 | var bytes = reader.ReadBytes(size);
18 |
19 | encoding ??= Encoding.UTF8;
20 |
21 | return encoding.GetString(bytes).TrimEnd((char)0);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Psarc/Asset/JsonObjectAsset.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.IO;
3 |
4 | namespace Rocksmith2014PsarcLib.Psarc.Asset
5 | {
6 | public class JsonObjectAsset : PsarcAsset
7 | {
8 | public T JsonObject { get; private set; }
9 |
10 | private static JsonSerializer Serializer { get; } = new JsonSerializer
11 | {
12 | TypeNameHandling = TypeNameHandling.None,
13 | MetadataPropertyHandling = MetadataPropertyHandling.Ignore
14 | };
15 |
16 | public override void ReadFrom(MemoryStream stream)
17 | {
18 | base.ReadFrom(stream);
19 |
20 | using var reader = new StreamReader(stream);
21 | using var jsonReader = new JsonTextReader(reader);
22 |
23 | JsonObject = Serializer.Deserialize(jsonReader);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 kokolihapihvi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Psarc/Asset/TextPsarcAsset.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace Rocksmith2014PsarcLib.Psarc.Asset
4 | {
5 | public class TextPsarcAsset : PsarcAsset
6 | {
7 | ///
8 | /// The text contents of this asset
9 | ///
10 | public string Text { get; private set; }
11 |
12 | ///
13 | /// Line separators for the property
14 | ///
15 | public string[] LineSeparators { get; set; } = new string[] { "\r\n", "\n" };
16 |
17 | ///
18 | /// The text contents of this asset, split into an array of lines.
19 | ///
20 | /// Uses
21 | ///
22 | public string[] Lines
23 | {
24 | get
25 | {
26 | return Text.Split(LineSeparators, System.StringSplitOptions.None);
27 | }
28 | }
29 |
30 | public override void ReadFrom(MemoryStream stream)
31 | {
32 | using (var reader = new StreamReader(stream))
33 | {
34 | Text = reader.ReadToEnd();
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Psarc/Models/ToolkitInfo.cs:
--------------------------------------------------------------------------------
1 | namespace Rocksmith2014PsarcLib.Psarc.Models
2 | {
3 | ///
4 | /// For CDLC provides information about Toolkit version,
5 | /// the package author, the package version and a comment.
6 | ///
7 | //https://github.com/rscustom/rocksmith-custom-song-toolkit/blob/master/RocksmithToolkitLib/DLCPackage/ToolkitInfo.cs
8 | public class ToolkitInfo
9 | {
10 | public string ToolkitVersion { get; set; }
11 | public string PackageAuthor { get; set; }
12 | public string PackageVersion { get; set; }
13 | public string PackageComment { get; set; }
14 | public string PackageRating { get; set; }
15 |
16 | ///
17 | /// Was the psarc file created with the rs custom toolkit
18 | ///
19 | public bool IsCustom
20 | {
21 | get
22 | {
23 | return ToolkitVersion != "Null";
24 | }
25 | }
26 |
27 | public ToolkitInfo()
28 | {
29 | ToolkitVersion = "Null";
30 | PackageAuthor = "Ubisoft";
31 | PackageVersion = "0";
32 | PackageComment = "Null";
33 | PackageRating = "5";
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Psarc/PsarcFileHeader.cs:
--------------------------------------------------------------------------------
1 | using Rocksmith2014PsarcLib.ReaderExtensions;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace Rocksmith2014PsarcLib.Psarc
6 | {
7 | public class PsarcFileHeader
8 | {
9 | public string Identifier { get; private set; }
10 | public uint Version { get; private set; }
11 | public string Compression { get; private set; }
12 | public uint TOCSize { get; private set; }
13 | public uint TOCEntrySize { get; private set; }
14 | public long TOCOffset { get; private set; }
15 | public uint EntryCount { get; private set; }
16 | public uint BlockSize { get; private set; }
17 | public PsarcArchiveFlags ArchiveFlags { get; private set; }
18 |
19 | public PsarcFileHeader(PsarcFile psarcFile)
20 | {
21 | var reader = psarcFile.Reader;
22 |
23 | //Seek to the beginning
24 | reader.BaseStream.Seek(0, SeekOrigin.Begin);
25 |
26 | Identifier = Encoding.ASCII.GetString(reader.ReadBytes(4));
27 | Version = reader.ReadUInt32Be();
28 | Compression = Encoding.ASCII.GetString(reader.ReadBytes(4));
29 | TOCSize = reader.ReadUInt32Be();
30 | TOCEntrySize = reader.ReadUInt32Be(); // -32?
31 | EntryCount = reader.ReadUInt32Be();
32 | BlockSize = reader.ReadUInt32Be();
33 | ArchiveFlags = (PsarcArchiveFlags)reader.ReadUInt32Be();
34 |
35 | TOCOffset = reader.BaseStream.Position;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Metadata.cs:
--------------------------------------------------------------------------------
1 | using Rocksmith2014PsarcLib.ReaderExtensions;
2 | using System.IO;
3 |
4 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
5 | {
6 | public struct Metadata : IBinarySerializable
7 | {
8 | public double MaxScore;
9 | public double MaxNotesAndChords;
10 | public double MaxNotesAndChords_Real;
11 | public double PointsPerNote;
12 | public float FirstBeatLength;
13 | public float StartTime;
14 | public byte CapoFretId;
15 | public string LastConversionDateTime;
16 | public short Part;
17 | public float SongLength;
18 | public int StringCount;
19 | public short[] Tuning;
20 | public float Unk11_FirstNoteTime;
21 | public float Unk12_FirstNoteTime;
22 | public int MaxDifficulty;
23 |
24 | public IBinarySerializable Read(BinaryReader reader)
25 | {
26 | MaxScore = reader.ReadDouble();
27 | MaxNotesAndChords = reader.ReadDouble();
28 | MaxNotesAndChords_Real = reader.ReadDouble();
29 | PointsPerNote = reader.ReadDouble();
30 | FirstBeatLength = reader.ReadSingle();
31 | StartTime = reader.ReadSingle();
32 | CapoFretId = reader.ReadByte();
33 | LastConversionDateTime = reader.ReadString(32);
34 | Part = reader.ReadInt16();
35 | SongLength = reader.ReadSingle();
36 |
37 | StringCount = reader.ReadInt32();
38 | Tuning = reader.ReadShortArray(StringCount);
39 |
40 | Unk11_FirstNoteTime = reader.ReadSingle();
41 | Unk12_FirstNoteTime = reader.ReadSingle();
42 | MaxDifficulty = reader.ReadInt32();
43 |
44 | return this;
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ReaderExtensions/ArrayReaderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace Rocksmith2014PsarcLib.ReaderExtensions
4 | {
5 | public static class ArrayReaderExtensions
6 | {
7 | ///
8 | /// Read an array of count floats
9 | ///
10 | ///
11 | ///
12 | ///
13 | public static float[] ReadFloatArray(this BinaryReader reader, int count)
14 | {
15 | var arr = new float[count];
16 |
17 | for (var i = 0; i < arr.Length; i++)
18 | {
19 | arr[i] = reader.ReadSingle();
20 | }
21 |
22 | return arr;
23 | }
24 |
25 | ///
26 | /// Read an array of count ints
27 | ///
28 | ///
29 | ///
30 | ///
31 | public static int[] ReadIntArray(this BinaryReader reader, int count)
32 | {
33 | var arr = new int[count];
34 |
35 | for (var i = 0; i < arr.Length; i++)
36 | {
37 | arr[i] = reader.ReadInt32();
38 | }
39 |
40 | return arr;
41 | }
42 |
43 | ///
44 | /// Read an array of count shorts
45 | ///
46 | ///
47 | ///
48 | ///
49 | public static short[] ReadShortArray(this BinaryReader reader, int count)
50 | {
51 | var arr = new short[count];
52 |
53 | for (var i = 0; i < arr.Length; i++)
54 | {
55 | arr[i] = reader.ReadInt16();
56 | }
57 |
58 | return arr;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rocksmith2014PsarcLib
2 | Yet another rocksmith2014 psarc reader lib
3 |
4 | Designed to parse faster, but only supports unpacking
5 |
6 | # Example usage
7 | ```cs
8 | // Count total time elapsed
9 | var totaltime = new Stopwatch();
10 | totaltime.Start();
11 |
12 | // A concurrent collection for the dlc keys
13 | var allDlcKeys = new ConcurrentBag();
14 |
15 | // Find all files in the dlc folder and subfolders
16 | var allfiles = Directory.GetFiles(@"G:\SteamLibrary\steamapps\common\Rocksmith2014\dlc", "*.psarc", SearchOption.AllDirectories).ToList();
17 | // Manually add songs.psarc
18 | allfiles.Add(@"G:\SteamLibrary\steamapps\common\Rocksmith2014\songs.psarc");
19 |
20 | // Go through all dlc files in parallel
21 | var partask = Parallel.ForEach(allfiles, (file) =>
22 | {
23 | // Unnecessary list just for printing how many dlc keys it found in each psarc
24 | var dlckeys = new List();
25 | try
26 | {
27 | // Use psarclib to parse the psarc
28 | using (var psarc = new PsarcFile(file))
29 | {
30 | // Go through all manifests, add each arrangements song key to the list
31 | foreach (var manifest in psarc.ExtractArrangementManifests())
32 | {
33 | dlckeys.Add(manifest.Attributes.SongKey);
34 | allDlcKeys.Add(manifest.Attributes.SongKey);
35 | }
36 | }
37 |
38 | Console.WriteLine($"Found {dlckeys.Distinct().Count()} dlc in {file}");
39 | }
40 | // Handle exceptions, since corrupt cdlc is very common
41 | catch (Exception e)
42 | {
43 | Console.WriteLine($"Unable to read {file}");
44 | Console.WriteLine(e.Message);
45 | Console.WriteLine(e.StackTrace);
46 | }
47 | });
48 |
49 | // Wait for the parallel loop to complete
50 | while (!partask.IsCompleted)
51 | {
52 | Thread.Sleep(100);
53 | }
54 |
55 | // Stop timer
56 | totaltime.Stop();
57 |
58 | // Remove all duplicate keys from the list, because all arrangements of a song have the same key
59 | var result = allDlcKeys.ToArray().Distinct().ToArray();
60 |
61 | Console.WriteLine($"Completed in {totaltime.ElapsedMilliseconds}ms");
62 | Console.WriteLine($"Parsed {allfiles.Count} files");
63 | Console.WriteLine($"Found {result.Length} song keys");
64 |
65 | Console.ReadLine();
66 | ```
67 |
--------------------------------------------------------------------------------
/Psarc/Asset/ToolkitInfoAsset.cs:
--------------------------------------------------------------------------------
1 | using Rocksmith2014PsarcLib.Psarc.Models;
2 | using System;
3 | using System.IO;
4 |
5 | namespace Rocksmith2014PsarcLib.Psarc.Asset
6 | {
7 | public class ToolkitInfoAsset : TextPsarcAsset
8 | {
9 | public ToolkitInfo ToolkitInfo { get; private set; } = new ToolkitInfo();
10 |
11 | public override void ReadFrom(MemoryStream stream)
12 | {
13 | base.ReadFrom(stream);
14 |
15 | //Single line means only toolkit version is included
16 | if (Lines.Length == 1)
17 | {
18 | ToolkitInfo.ToolkitVersion = Lines[0].Trim();
19 | }
20 | else
21 | {
22 | //Go through all lines and parse "key: value" pairs
23 | foreach (var line in Lines)
24 | {
25 | var tokens = line.Split(':');
26 |
27 | if (tokens.Length != 2)
28 | {
29 | Console.WriteLine(" Notice: Unrecognized line in toolkit.version: {0}", line);
30 | continue;
31 | }
32 |
33 | var key = tokens[0].Trim().ToLower();
34 |
35 | switch (key)
36 | {
37 | case "toolkit version":
38 | ToolkitInfo.ToolkitVersion = tokens[1];
39 | break;
40 | case "package author":
41 | ToolkitInfo.PackageAuthor = tokens[1];
42 | break;
43 | case "package version":
44 | ToolkitInfo.PackageVersion = tokens[1];
45 | break;
46 | case "package comment":
47 | ToolkitInfo.PackageComment = tokens[1];
48 | break;
49 | case "package rating":
50 | ToolkitInfo.PackageRating = tokens[1];
51 | break;
52 | default:
53 | Console.WriteLine(" Notice: Unknown key in toolkit.version: {0}", key);
54 | break;
55 | }
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Psarc/Asset/DdsAsset.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Buffers;
3 | using System.Drawing;
4 | using System.Drawing.Imaging;
5 | using System.IO;
6 | using System.Runtime.InteropServices;
7 | using Pfim;
8 |
9 | namespace Rocksmith2014PsarcLib.Psarc.Asset
10 | {
11 | public class DdsAsset : PsarcAsset
12 | {
13 | ///
14 | /// Uses ArrayPool to rent byte arrays to Pfim, by default Pfim creates a new byte array each time
15 | ///
16 | private class ArrayPoolAllocator : IImageAllocator
17 | {
18 | // Use the shared byte array pool
19 | private readonly ArrayPool pool = ArrayPool.Shared;
20 |
21 | public byte[] Rent(int size)
22 | {
23 | return pool.Rent(size);
24 | }
25 |
26 | public void Return(byte[] data)
27 | {
28 | pool.Return(data);
29 | }
30 | }
31 |
32 | ///
33 | /// Config used by Pfim to parse dds assets
34 | ///
35 | private readonly PfimConfig config = new PfimConfig(allocator: new ArrayPoolAllocator());
36 |
37 | public Bitmap Bitmap { get; private set; }
38 |
39 | public override void ReadFrom(MemoryStream stream)
40 | {
41 | base.ReadFrom(stream);
42 |
43 | using var image = Pfimage.FromStream(stream, config);
44 | PixelFormat format;
45 |
46 | switch (image.Format)
47 | {
48 | case Pfim.ImageFormat.Rgba32:
49 | format = PixelFormat.Format32bppArgb;
50 | break;
51 | case Pfim.ImageFormat.Rgb24:
52 | format = PixelFormat.Format24bppRgb;
53 | break;
54 | default:
55 | // see the sample for more details
56 | throw new NotImplementedException();
57 | }
58 |
59 | var handle = GCHandle.Alloc(image.Data, GCHandleType.Pinned);
60 | try
61 | {
62 | var data = Marshal.UnsafeAddrOfPinnedArrayElement(image.Data, 0);
63 |
64 | using var bm = new Bitmap(image.Width, image.Height, image.Stride, format, data);
65 | Bitmap = new Bitmap(bm);
66 | }
67 | finally
68 | {
69 | handle.Free();
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/ReaderExtensions/StructReaderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Buffers;
2 | using Rocksmith2014PsarcLib.Psarc.Models;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace Rocksmith2014PsarcLib.ReaderExtensions
7 | {
8 | public static class StructReaderExtensions
9 | {
10 | ///
11 | /// Reads count structs from the stream
12 | ///
13 | ///
14 | ///
15 | ///
16 | ///
17 | public static T[] ReadStructArray(this BinaryReader reader, int count) where T : struct
18 | {
19 | var arr = new T[count];
20 |
21 | for (var i = 0; i < arr.Length; i++)
22 | {
23 | arr[i] = reader.ReadStruct();
24 | }
25 |
26 | return arr;
27 | }
28 |
29 | ///
30 | /// Reads first 4 bytes as n, then reads n structs from the stream
31 | ///
32 | ///
33 | ///
34 | ///
35 | public static T[] ReadStructArray(this BinaryReader reader) where T : struct
36 | {
37 | var count = reader.ReadInt32();
38 |
39 | return ReadStructArray(reader, count);
40 | }
41 |
42 | ///
43 | /// Reads a struct from the stream
44 | ///
45 | ///
46 | ///
47 | ///
48 | public static T ReadStruct(this BinaryReader reader) where T : struct
49 | {
50 | T _struct;
51 |
52 | //Some structs need more advanced logic, for example dynamic length arrays
53 | if (typeof(IBinarySerializable).IsAssignableFrom(typeof(T)))
54 | {
55 | _struct = new T();
56 | return (T)(_struct as IBinarySerializable).Read(reader);
57 | }
58 |
59 | var size = Marshal.SizeOf(typeof(T));
60 |
61 | var readBuffer = ArrayPool.Shared.Rent(size);
62 | reader.Read(readBuffer, 0, size);
63 |
64 | var handle = GCHandle.Alloc(readBuffer, GCHandleType.Pinned);
65 |
66 | _struct = Marshal.PtrToStructure(handle.AddrOfPinnedObject());
67 |
68 | handle.Free();
69 |
70 | ArrayPool.Shared.Return(readBuffer);
71 |
72 | return _struct;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/ReaderExtensions/BigEndianReaderExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace Rocksmith2014PsarcLib.ReaderExtensions
5 | {
6 | public static class BigEndianReaderExtensions
7 | {
8 | ///
9 | /// Read bytes in big endian (reverse byte order)
10 | ///
11 | ///
12 | ///
13 | private static void ReadBytesBe(this BinaryReader reader, Span span)
14 | {
15 | reader.Read(span);
16 | span.Reverse();
17 | }
18 |
19 | ///
20 | /// Read a 2 byte unsigned int in big endian (reverse byte order)
21 | ///
22 | ///
23 | ///
24 | public static ushort ReadUInt16Be(this BinaryReader reader)
25 | {
26 | Span span = stackalloc byte[2];
27 | reader.ReadBytesBe(span);
28 |
29 | return BitConverter.ToUInt16(span);
30 | }
31 |
32 | ///
33 | /// Read a 3 byte unsigned int in big endian (reverse byte order)
34 | ///
35 | ///
36 | ///
37 | public static uint ReadUInt24Be(this BinaryReader reader)
38 | {
39 | //3 bytes
40 | var bytes = new byte[4];
41 |
42 | Span span = stackalloc byte[3];
43 | reader.ReadBytesBe(span);
44 |
45 | span.CopyTo(bytes);
46 |
47 | return BitConverter.ToUInt32(bytes, 0);
48 | }
49 |
50 | ///
51 | /// Read a 4 byte unsigned int in big endian (reverse byte order)
52 | ///
53 | ///
54 | ///
55 | public static uint ReadUInt32Be(this BinaryReader reader)
56 | {
57 | Span span = stackalloc byte[4];
58 | reader.ReadBytesBe(span);
59 |
60 | return BitConverter.ToUInt32(span);
61 | }
62 |
63 | ///
64 | /// Read a 5 byte unsigned int in big endian (reverse byte order)
65 | ///
66 | ///
67 | ///
68 | public static ulong ReadUInt40Be(this BinaryReader reader)
69 | {
70 | //5 bytes
71 | var bytes = new byte[8];
72 |
73 | Span span = stackalloc byte[5];
74 | reader.ReadBytesBe(span);
75 |
76 | span.CopyTo(bytes);
77 |
78 | return BitConverter.ToUInt64(bytes, 0);
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Psarc/PsarcTOC.cs:
--------------------------------------------------------------------------------
1 | using Rocksmith2014PsarcLib.Crypto;
2 | using Rocksmith2014PsarcLib.ReaderExtensions;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace Rocksmith2014PsarcLib.Psarc
7 | {
8 | public class PsarcTOC : IDisposable
9 | {
10 | public List Entries { get; }
11 | public bool Encrypted { get; }
12 |
13 | private DecryptStream Decryptor { get; }
14 |
15 | public uint[] ZipBlockSizes { get; }
16 |
17 | public PsarcTOC(PsarcFile psarcFile)
18 | {
19 | Entries = new List((int)psarcFile.Header.EntryCount);
20 |
21 | Encrypted = psarcFile.Header.ArchiveFlags.HasFlag(PsarcArchiveFlags.TOC_ENCRYPTED);
22 |
23 | var reader = psarcFile.Reader;
24 | if (Encrypted)
25 | {
26 | //Setup decrypting stream
27 | Decryptor = new DecryptStream(psarcFile.FileStream, DecryptStream.DecryptMode.PSARC, psarcFile.Header.TOCSize);
28 |
29 | reader = Decryptor.Reader;
30 | }
31 |
32 | for (var i = 0; i < psarcFile.Header.EntryCount; i++)
33 | {
34 | Entries.Add(new PsarcTOCEntry
35 | {
36 | Index = i,
37 | Hash = BitConverter.ToString(reader.ReadBytes(16)).Replace("-", ""),
38 | StartBlock = reader.ReadUInt32Be(),
39 | Length = reader.ReadUInt40Be(),
40 | Offset = reader.ReadUInt40Be()
41 | });
42 | }
43 |
44 | var bNum = (int)Math.Log(psarcFile.Header.BlockSize, 256);
45 |
46 | var tocChunkSize = (int)(psarcFile.Header.EntryCount * psarcFile.Header.TOCEntrySize);//(int)_reader.BaseStream.Position //don't alter this with. causes issues
47 | var zNum = (int)((psarcFile.Header.TOCSize - 32u - tocChunkSize) / bNum);
48 | ZipBlockSizes = new uint[zNum];
49 |
50 | for (var i = 0; i < zNum; i++)
51 | {
52 | switch (bNum)
53 | {
54 | case 2://64KB
55 | ZipBlockSizes[i] = reader.ReadUInt16Be();
56 | break;
57 | case 3://16MB
58 | ZipBlockSizes[i] = reader.ReadUInt24Be();
59 | break;
60 | case 4://4GB
61 | ZipBlockSizes[i] = reader.ReadUInt32Be();
62 | break;
63 | }
64 | }
65 |
66 | Decryptor?.Dispose();
67 | Decryptor = null;
68 | }
69 |
70 | public void Dispose()
71 | {
72 | Decryptor?.Dispose();
73 | GC.SuppressFinalize(this);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Psarc/Asset/SngAsset.cs:
--------------------------------------------------------------------------------
1 | using Rocksmith2014PsarcLib.Crypto;
2 | using Rocksmith2014PsarcLib.Psarc.Models.Sng;
3 | using Rocksmith2014PsarcLib.ReaderExtensions;
4 | using System;
5 | using System.IO;
6 | using Action = Rocksmith2014PsarcLib.Psarc.Models.Sng.Action;
7 |
8 | namespace Rocksmith2014PsarcLib.Psarc.Asset
9 | {
10 | public class SngAsset : PsarcAsset
11 | {
12 | [Flags]
13 | public enum AssetFlags
14 | {
15 | None = 0,
16 | Compressed = 1,
17 | Encrypted = 2
18 | }
19 |
20 | public Bpm[] BPMs;
21 | public Phrase[] Phrases;
22 | public Chord[] Chords;
23 | public ChordNotes[] ChordNotes;
24 | public Vocal[] Vocals;
25 | public SymbolsHeader[] SymbolHeaders;
26 | public SymbolsTexture[] SymbolTextures;
27 | public SymbolDefinition[] SymbolDefinitions;
28 | public PhraseIteration[] PhraseIterations;
29 | public PhraseExtraInfoByLevel[] PhraseExtraInfo;
30 | public NLinkedDifficulty[] NLD;
31 | public Action[] Actions;
32 | public Event[] Events;
33 | public Tone[] Tones;
34 | public Dna[] DNAs;
35 | public Section[] Sections;
36 | public Arrangement[] Arrangements;
37 | public Metadata Metadata;
38 |
39 | public override void ReadFrom(MemoryStream stream)
40 | {
41 | base.ReadFrom(stream);
42 |
43 | //Decrypt/uncompress
44 | using (var dcStream = new DecryptStream(stream, DecryptStream.DecryptMode.SNG, stream.Length))
45 | {
46 | //Read beats
47 | BPMs = dcStream.Reader.ReadStructArray();
48 |
49 | //Read phrases
50 | Phrases = dcStream.Reader.ReadStructArray();
51 |
52 | //Read chords
53 | Chords = dcStream.Reader.ReadStructArray();
54 |
55 | //Read chord notes
56 | ChordNotes = dcStream.Reader.ReadStructArray();
57 |
58 | //Read vocals
59 | Vocals = dcStream.Reader.ReadStructArray();
60 |
61 | //Read symbols if there were vocals
62 | if (Vocals.Length > 0)
63 | {
64 | //Read symbols header
65 | SymbolHeaders = dcStream.Reader.ReadStructArray();
66 |
67 | //Read symbols texture
68 | SymbolTextures = dcStream.Reader.ReadStructArray();
69 |
70 | //Read symbols definition
71 | SymbolDefinitions = dcStream.Reader.ReadStructArray();
72 | }
73 |
74 | //Read phrase iterations
75 | PhraseIterations = dcStream.Reader.ReadStructArray();
76 |
77 | //Read phrase extra info
78 | PhraseExtraInfo = dcStream.Reader.ReadStructArray();
79 |
80 | //Read linked difficulties
81 | NLD = dcStream.Reader.ReadStructArray();
82 |
83 | //Read actions
84 | Actions = dcStream.Reader.ReadStructArray();
85 |
86 | //Read events
87 | Events = dcStream.Reader.ReadStructArray();
88 |
89 | //Read tones switch events
90 | Tones = dcStream.Reader.ReadStructArray();
91 |
92 | //Read DNAs
93 | DNAs = dcStream.Reader.ReadStructArray();
94 |
95 | //Read sections
96 | Sections = dcStream.Reader.ReadStructArray();
97 |
98 | //Read arrangements
99 | Arrangements = dcStream.Reader.ReadStructArray();
100 |
101 | //Read metadata
102 | Metadata = dcStream.Reader.ReadStruct();
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Windows Store app package directory
170 | AppPackages/
171 | BundleArtifacts/
172 |
173 | # Visual Studio cache files
174 | # files ending in .cache can be ignored
175 | *.[Cc]ache
176 | # but keep track of directories ending in .cache
177 | !*.[Cc]ache/
178 |
179 | # Others
180 | ClientBin/
181 | [Ss]tyle[Cc]op.*
182 | ~$*
183 | *~
184 | *.dbmdl
185 | *.dbproj.schemaview
186 | *.pfx
187 | *.publishsettings
188 | node_modules/
189 | orleans.codegen.cs
190 |
191 | # RIA/Silverlight projects
192 | Generated_Code/
193 |
194 | # Backup & report files from converting an old project file
195 | # to a newer Visual Studio version. Backup files are not needed,
196 | # because we have git ;-)
197 | _UpgradeReport_Files/
198 | Backup*/
199 | UpgradeLog*.XML
200 | UpgradeLog*.htm
201 |
202 | # SQL Server files
203 | *.mdf
204 | *.ldf
205 |
206 | # Business Intelligence projects
207 | *.rdl.data
208 | *.bim.layout
209 | *.bim_*.settings
210 |
211 | # Microsoft Fakes
212 | FakesAssemblies/
213 |
214 | # GhostDoc plugin setting file
215 | *.GhostDoc.xml
216 |
217 | # Node.js Tools for Visual Studio
218 | .ntvs_analysis.dat
219 |
220 | # Visual Studio 6 build log
221 | *.plg
222 |
223 | # Visual Studio 6 workspace options file
224 | *.opt
225 |
226 | # Visual Studio LightSwitch build output
227 | **/*.HTMLClient/GeneratedArtifacts
228 | **/*.DesktopClient/GeneratedArtifacts
229 | **/*.DesktopClient/ModelManifest.xml
230 | **/*.Server/GeneratedArtifacts
231 | **/*.Server/ModelManifest.xml
232 | _Pvt_Extensions
233 |
234 | # LightSwitch generated files
235 | GeneratedArtifacts/
236 | ModelManifest.xml
237 |
238 | # Paket dependency manager
239 | .paket/paket.exe
240 |
241 | # FAKE - F# Make
242 | .fake/
243 | .idea
244 |
--------------------------------------------------------------------------------
/Psarc/Models/Sng/Arrangement.cs:
--------------------------------------------------------------------------------
1 | using Rocksmith2014PsarcLib.ReaderExtensions;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace Rocksmith2014PsarcLib.Psarc.Models.Sng
6 | {
7 | public struct Anchor
8 | {
9 | public float StartBeatTime;
10 | public float EndBeatTime;
11 | public float Unk3_FirstNoteTime;
12 | public float Unk4_LastNoteTime;
13 | public byte FretId;
14 |
15 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
16 | public byte[] Padding;
17 |
18 | public int Width;
19 | public int PhraseIterationId;
20 | }
21 |
22 | [StructLayout(LayoutKind.Sequential, Pack = 1)]
23 | public struct AnchorExtension
24 | {
25 | public float BeatTime;
26 | public byte FretId;
27 | public int Unk2_0;
28 | public short Unk3_0;
29 | public byte Unk4_0;
30 | }
31 |
32 | public struct Fingerprint
33 | {
34 | public int ChordId;
35 | public float StartTime;
36 | public float EndTime;
37 | public float Unk3_FirstNoteTime;
38 | public float Unk4_LastNoteTime;
39 | }
40 |
41 | public struct Note : IBinarySerializable
42 | {
43 | public uint NoteMask;
44 | public uint NoteFlags;
45 | public uint Hash;
46 | public float Time;
47 | public byte StringIndex;
48 | public byte FretId;
49 | public byte AnchorFretId;
50 | public byte AnchorWidth;
51 | public int ChordId;
52 | public int ChordNotesId;
53 | public int PhraseId;
54 | public int PhraseIterationId;
55 | public short[] FingerPrintId;
56 | public short NextIterNote;
57 | public short PrevIterNote;
58 | public short ParentPrevNote;
59 | public byte SlideTo;
60 | public byte SlideUnpitchTo;
61 | public byte LeftHand;
62 | public byte Tap;
63 | public byte PickDirection;
64 | public byte Slap;
65 | public byte Pluck;
66 | public short Vibrato;
67 | public float Sustain;
68 | public float MaxBend;
69 | public BendData32[] BendData;
70 |
71 | public IBinarySerializable Read(BinaryReader reader)
72 | {
73 | NoteMask = reader.ReadUInt32();
74 | NoteFlags = reader.ReadUInt32();
75 | Hash = reader.ReadUInt32();
76 | Time = reader.ReadSingle();
77 | StringIndex = reader.ReadByte();
78 | FretId = reader.ReadByte();
79 | AnchorFretId = reader.ReadByte();
80 | AnchorWidth = reader.ReadByte();
81 | ChordId = reader.ReadInt32();
82 | ChordNotesId = reader.ReadInt32();
83 | PhraseId = reader.ReadInt32();
84 | PhraseIterationId = reader.ReadInt32();
85 |
86 | FingerPrintId = reader.ReadShortArray(2);
87 |
88 | NextIterNote = reader.ReadInt16();
89 | PrevIterNote = reader.ReadInt16();
90 | ParentPrevNote = reader.ReadInt16();
91 | SlideTo = reader.ReadByte();
92 | SlideUnpitchTo = reader.ReadByte();
93 | LeftHand = reader.ReadByte();
94 | Tap = reader.ReadByte();
95 | PickDirection = reader.ReadByte();
96 | Slap = reader.ReadByte();
97 | Pluck = reader.ReadByte();
98 | Vibrato = reader.ReadInt16();
99 | Sustain = reader.ReadSingle();
100 | MaxBend = reader.ReadSingle();
101 | BendData = reader.ReadStructArray();
102 |
103 | return this;
104 | }
105 | }
106 |
107 | public struct Arrangement : IBinarySerializable
108 | {
109 | public int Difficulty;
110 | public Anchor[] Anchors;
111 | public AnchorExtension[] AnchorExtensions;
112 | public Fingerprint[] Fingerprints1;
113 | public Fingerprint[] Fingerprints2;
114 | public Note[] Notes;
115 |
116 | public int PhraseCount;
117 | public float[] AverageNotesPerIteration;
118 | public int PhraseIterationCount1;
119 | public int[] NotesInIteration1;
120 | public int PhraseIterationCount2;
121 | public int[] NotesInIteration2;
122 |
123 | public IBinarySerializable Read(BinaryReader reader)
124 | {
125 | Difficulty = reader.ReadInt32();
126 |
127 | Anchors = reader.ReadStructArray();
128 | AnchorExtensions = reader.ReadStructArray();
129 | Fingerprints1 = reader.ReadStructArray();
130 | Fingerprints2 = reader.ReadStructArray();
131 | Notes = reader.ReadStructArray();
132 |
133 | PhraseCount = reader.ReadInt32();
134 | AverageNotesPerIteration = reader.ReadFloatArray(PhraseCount);
135 |
136 | PhraseIterationCount1 = reader.ReadInt32();
137 | NotesInIteration1 = reader.ReadIntArray(PhraseIterationCount1);
138 |
139 | PhraseIterationCount2 = reader.ReadInt32();
140 | NotesInIteration2 = reader.ReadIntArray(PhraseIterationCount2);
141 |
142 | return this;
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/Crypto/DecryptStream.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Utilities.Zlib;
2 | using Rocksmith2014PsarcLib.Psarc.Asset;
3 | using System;
4 | using System.Buffers;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Security.Cryptography;
8 |
9 | namespace Rocksmith2014PsarcLib.Crypto
10 | {
11 | public class DecryptStream : IDisposable
12 | {
13 | public static readonly byte[] PsarcKey = new byte[32]
14 | {
15 | 0xC5, 0x3D, 0xB2, 0x38, 0x70, 0xA1, 0xA2, 0xF7,
16 | 0x1C, 0xAE, 0x64, 0x06, 0x1F, 0xDD, 0x0E, 0x11,
17 | 0x57, 0x30, 0x9D, 0xC8, 0x52, 0x04, 0xD4, 0xC5,
18 | 0xBF, 0xDF, 0x25, 0x09, 0x0D, 0xF2, 0x57, 0x2C
19 | };
20 |
21 | public static readonly byte[] PsarcIV = new byte[16]
22 | {
23 | 0xE9, 0x15, 0xAA, 0x01,
24 | 0x8F, 0xEF, 0x71, 0xFC,
25 | 0x50, 0x81, 0x32, 0xE4,
26 | 0xBB, 0x4C, 0xEB, 0x42
27 | };
28 |
29 | public static byte[] SngKeyPC = new byte[32]
30 | {
31 | 0xCB, 0x64, 0x8D, 0xF3, 0xD1, 0x2A, 0x16, 0xBF,
32 | 0x71, 0x70, 0x14, 0x14, 0xE6, 0x96, 0x19, 0xEC,
33 | 0x17, 0x1C, 0xCA, 0x5D, 0x2A, 0x14, 0x2E, 0x3E,
34 | 0x59, 0xDE, 0x7A, 0xDD, 0xA1, 0x8A, 0x3A, 0x30
35 | };
36 |
37 | public static byte[] PCMetaDatKey = new byte[32]
38 | {
39 | 0x5F, 0xB0, 0x23, 0xEF, 0x19, 0xD5, 0xDC, 0x37,
40 | 0xAD, 0xDA, 0xC8, 0xF0, 0x17, 0xF8, 0x8F, 0x0E,
41 | 0x98, 0x18, 0xA3, 0xAC, 0x2F, 0x72, 0x46, 0x96,
42 | 0xA5, 0x9D, 0xE2, 0xBF, 0x05, 0x25, 0x12, 0xEB
43 | };
44 |
45 | public enum DecryptMode
46 | {
47 | PSARC,
48 | SNG
49 | }
50 |
51 | public DecryptMode Mode { get; private set; }
52 |
53 | public BinaryReader Reader { get; private set; }
54 |
55 | private MemoryStream _decryptedStream;
56 |
57 | public DecryptStream(Stream input, DecryptMode mode, long length)
58 | {
59 | Mode = mode;
60 |
61 | switch (Mode)
62 | {
63 | case DecryptMode.PSARC:
64 | InitializePsarcDecryptor(input, length);
65 | break;
66 | case DecryptMode.SNG:
67 | InitializeSngDecryptor(input, length);
68 | break;
69 | default:
70 | throw new ArgumentException("Invalid decrypt mode", nameof(mode));
71 | }
72 | }
73 |
74 | private void InitializePsarcDecryptor(Stream input, long length)
75 | {
76 | _decryptedStream = new MemoryStream((int)length);
77 |
78 | //Setup decrypting stream
79 | using (var decryptor = new RijndaelManaged())
80 | {
81 | decryptor.Mode = CipherMode.CFB;
82 | decryptor.Padding = PaddingMode.None;
83 | decryptor.BlockSize = 128;
84 | decryptor.IV = new byte[16];
85 | decryptor.Key = PsarcKey;
86 |
87 | using (var decryptStream = new CryptoStream(_decryptedStream, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
88 | {
89 | var buffer = new byte[512];
90 | var pad = buffer.Length - (int)(length % buffer.Length);
91 |
92 | while (input.Position < length)
93 | {
94 | var size = (int)Math.Min(length - input.Position, buffer.Length);
95 | input.Read(buffer, 0, size);
96 | decryptStream.Write(buffer, 0, size);
97 | }
98 |
99 | if (pad > 0)
100 | decryptStream.Write(new byte[pad], 0, pad);
101 |
102 | decryptStream.Flush();
103 | _decryptedStream = new MemoryStream(_decryptedStream.ToArray());
104 | }
105 | }
106 |
107 | Reader = new BinaryReader(_decryptedStream);
108 | }
109 |
110 | private void InitializeSngDecryptor(Stream input, long length)
111 | {
112 | var sngFlags = SngAsset.AssetFlags.None;
113 |
114 | var decryptIV = new byte[16];
115 |
116 | //Check and prepare for sng decrypting
117 | using (var rdr = new BinaryReader(input, System.Text.Encoding.Default, true))
118 | {
119 | //Identifier?
120 | if (rdr.ReadUInt32() != 0x4A)
121 | {
122 | throw new InvalidDataException("Not a valid sng file");
123 | }
124 |
125 | //Read asset flags
126 | sngFlags = (SngAsset.AssetFlags)rdr.ReadUInt32();
127 |
128 | //Read encryption IV
129 | decryptIV = rdr.ReadBytes(16);
130 |
131 | //Adjust length by removing header size
132 | length -= 24;
133 | }
134 |
135 | _decryptedStream = new MemoryStream((int)length);
136 |
137 | // Decrypt using aes counter mode
138 | AesCtrTransform(SngKeyPC, decryptIV, input, _decryptedStream);
139 |
140 | Reader = new BinaryReader(_decryptedStream);
141 | _decryptedStream.Seek(0, SeekOrigin.Begin);
142 |
143 | if (sngFlags.HasFlag(SngAsset.AssetFlags.Compressed))
144 | {
145 | //Uncompress
146 | long uncompressedSize = Reader.ReadUInt32();
147 |
148 | _decryptedStream.Seek(4, SeekOrigin.Begin);
149 | using (var zOutputStream = new ZInputStream(_decryptedStream))
150 | {
151 | var unzippedStream = new MemoryStream((int)uncompressedSize);
152 |
153 | zOutputStream.CopyTo(unzippedStream);
154 |
155 | unzippedStream.Seek(0, SeekOrigin.Begin);
156 |
157 | // Dispose the previous reader
158 | Reader.Dispose();
159 |
160 | Reader = new BinaryReader(unzippedStream);
161 | }
162 |
163 | _decryptedStream.Dispose();
164 | }
165 | }
166 |
167 | ///
168 | /// AES counter mode transform
169 | /// https://stackoverflow.com/a/51188472
170 | ///
171 | ///
172 | ///
173 | ///
174 | ///
175 | private static void AesCtrTransform(byte[] key, byte[] salt, Stream inputStream, Stream outputStream)
176 | {
177 | SymmetricAlgorithm aes = new AesManaged { Mode = CipherMode.ECB, Padding = PaddingMode.None };
178 |
179 | var blockSize = aes.BlockSize / 8;
180 |
181 | if (salt.Length != blockSize)
182 | {
183 | throw new ArgumentException($"Salt size must be same as block size (actual: {salt.Length}, expected: {blockSize})");
184 | }
185 |
186 | var counter = (byte[])salt.Clone();
187 |
188 | var xorMask = new Queue();
189 |
190 | var zeroIv = new byte[blockSize];
191 | var counterEncryptor = aes.CreateEncryptor(key, zeroIv);
192 |
193 | var counterModeBlock = ArrayPool.Shared.Rent(blockSize);
194 |
195 | int b;
196 | while ((b = inputStream.ReadByte()) != -1)
197 | {
198 | if (xorMask.Count == 0)
199 | {
200 | counterEncryptor.TransformBlock(counter, 0, counter.Length, counterModeBlock, 0);
201 |
202 | for (var i2 = counter.Length - 1; i2 >= 0; i2--)
203 | {
204 | if (++counter[i2] != 0)
205 | {
206 | break;
207 | }
208 | }
209 |
210 | for (var index = 0; index < blockSize; index++)
211 | {
212 | var b2 = counterModeBlock[index];
213 | xorMask.Enqueue(b2);
214 | }
215 | }
216 |
217 | var mask = xorMask.Dequeue();
218 | outputStream.WriteByte((byte)(((byte)b) ^ mask));
219 | }
220 |
221 | ArrayPool.Shared.Return(counterModeBlock);
222 | }
223 |
224 | #region Disposable
225 | private bool disposedValue;
226 | protected virtual void Dispose(bool disposing)
227 | {
228 | if (!disposedValue)
229 | {
230 | if (disposing)
231 | {
232 | // TODO: dispose managed state (managed objects)
233 | Reader.Dispose();
234 | _decryptedStream.Dispose();
235 | }
236 |
237 | // TODO: free unmanaged resources (unmanaged objects) and override finalizer
238 | // TODO: set large fields to null
239 | disposedValue = true;
240 | }
241 | }
242 |
243 | // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
244 | // ~DecryptStream()
245 | // {
246 | // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
247 | // Dispose(disposing: false);
248 | // }
249 |
250 | public void Dispose()
251 | {
252 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
253 | Dispose(disposing: true);
254 | GC.SuppressFinalize(this);
255 | }
256 | #endregion
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/Psarc/PsarcFile.cs:
--------------------------------------------------------------------------------
1 | using Org.BouncyCastle.Utilities.Zlib;
2 | using Rocksmith2014PsarcLib.Psarc.Asset;
3 | using Rocksmith2014PsarcLib.Psarc.Models;
4 | using Rocksmith2014PsarcLib.Psarc.Models.Json;
5 | using Rocksmith2014PsarcLib.ReaderExtensions;
6 | using System;
7 | using System.Buffers;
8 | using System.Collections.Generic;
9 | using System.IO;
10 | using System.IO.Compression;
11 | using System.Linq;
12 |
13 | namespace Rocksmith2014PsarcLib.Psarc
14 | {
15 | public class PsarcFile : IDisposable
16 | {
17 | public string FilePath { get; }
18 |
19 | public PsarcFileHeader Header { get; }
20 |
21 | public PsarcTOC TOC { get; }
22 |
23 | internal FileStream FileStream { get; }
24 |
25 | internal BinaryReader Reader { get; }
26 |
27 | public PsarcFile(string filePath)
28 | {
29 | FilePath = filePath;
30 |
31 | // Setup file stream
32 | FileStream = File.OpenRead(filePath);
33 |
34 | // Setup reader
35 | Reader = new BinaryReader(FileStream);
36 |
37 | // Read header
38 | Header = new PsarcFileHeader(this);
39 |
40 | // Load/decrypt table of contents
41 | TOC = new PsarcTOC(this);
42 |
43 | // Read manifest
44 | ReadManifest();
45 | }
46 |
47 | public PsarcFile(FileInfo fileInfo) : this(fileInfo.FullName)
48 | {
49 | }
50 |
51 | ///
52 | /// Reads the filepath of all assets inside the psarc
53 | ///
54 | private void ReadManifest()
55 | {
56 | TOC.Entries[0].Path = "NamesBlock.bin";
57 |
58 | var asset = InflateEntry(TOC.Entries[0]);
59 |
60 | var names = asset.Lines;
61 |
62 | for (var i = 0; i < names.Length; i++)
63 | {
64 | TOC.Entries[i + 1].Path = names[i];
65 | }
66 | }
67 |
68 | ///
69 | /// Uncompresses a ZIP compressed byte array
70 | ///
71 | ///
72 | ///
73 | private byte[] UnzipBlock(byte[] zipped)
74 | {
75 | using var inStream = new MemoryStream(zipped);
76 | using var zOutputStream = new ZInputStream(inStream);
77 | using var outStream = new MemoryStream();
78 |
79 | zOutputStream.CopyTo(outStream);
80 |
81 | return outStream.ToArray();
82 | }
83 |
84 | private unsafe void UnzipBlock(BinaryReader from, Stream to, int size)
85 | {
86 | // Skip the header bytes, because DeflateStream does not recognize them for some reason
87 | var readsize = size - 2;
88 | Reader.BaseStream.Seek(2, SeekOrigin.Current);
89 |
90 | Span span = stackalloc byte[readsize];
91 |
92 | from.Read(span);
93 |
94 | fixed (byte* pBuffer = &span[0])
95 | {
96 | using var inStream = new UnmanagedMemoryStream(pBuffer, span.Length);
97 | using var decompressStream = new DeflateStream(inStream, CompressionMode.Decompress);
98 |
99 | decompressStream.CopyTo(to);
100 | }
101 | }
102 |
103 | ///
104 | /// Inflates entry into a stream, uncompressing if needed
105 | ///
106 | ///
107 | ///
108 | public void InflateEntry(PsarcTOCEntry entry, Stream stream)
109 | {
110 | const int ZipHeader = 0x78DA;
111 | var blockSize = (int)Header.BlockSize;
112 |
113 | var lastBlock = (int)(Math.Ceiling(entry.Length / (float)Header.BlockSize) + entry.StartBlock - 1);
114 |
115 | Reader.BaseStream.Seek((long)entry.Offset, SeekOrigin.Begin);
116 |
117 | Span buffer = stackalloc byte[blockSize];
118 |
119 | for (var block = entry.StartBlock; block <= lastBlock; block++)
120 | {
121 | // Size of this zip block (0 for uncompressed)
122 | var zipblockSize = (int)TOC.ZipBlockSizes[block];
123 |
124 | if (zipblockSize == 0) // raw. full cluster used.
125 | {
126 | Reader.Read(buffer);
127 | stream.Write(buffer);
128 | }
129 | else
130 | {
131 | var header = Reader.ReadUInt16Be();
132 | // Seek 2 bytes backwards to include the header (or first 2 data bytes) still in the stream
133 | Reader.BaseStream.Seek(-2, SeekOrigin.Current);
134 |
135 | if (header == ZipHeader) // compressed
136 | {
137 | UnzipBlock(Reader, stream, zipblockSize);
138 | }
139 | else // uncompressed block
140 | {
141 | stream.Write(Reader.ReadBytes(zipblockSize), 0, zipblockSize);
142 | }
143 | }
144 | }
145 |
146 | stream.Seek(0, SeekOrigin.Begin);
147 | stream.Flush();
148 | }
149 |
150 | ///
151 | /// Inflates entry into an asset object
152 | ///
153 | ///
154 | ///
155 | ///
156 | public T InflateEntry(PsarcTOCEntry entry) where T : PsarcAsset, new()
157 | {
158 | if (entry == null) return null;
159 |
160 | var asset = new T();
161 |
162 | // Rent a buffer for inflating
163 | var inflatebuffer = ArrayPool.Shared.Rent((int)entry.Length);
164 |
165 | using var ms = new MemoryStream(inflatebuffer);
166 | // Resize the stream, as the buffer may be larger
167 | ms.SetLength((int)entry.Length);
168 |
169 | try
170 | {
171 | InflateEntry(entry, ms);
172 |
173 | asset.ReadFrom(ms);
174 | }
175 | catch (Exception e)
176 | {
177 | Console.WriteLine($"Error inflating entry {entry.Path}");
178 | Console.WriteLine(e);
179 | throw;
180 | }
181 | finally // Always return rented buffer
182 | {
183 | ArrayPool.Shared.Return(inflatebuffer);
184 | }
185 |
186 | return asset;
187 | }
188 |
189 | ///
190 | /// Inflates the first entry that matches the pattern
191 | ///
192 | ///
193 | ///
194 | ///
195 | public T InflateEntry(Func where) where T : PsarcAsset, new()
196 | {
197 | var entry = TOC.Entries.FirstOrDefault(where);
198 |
199 | return InflateEntry(entry);
200 | }
201 |
202 | public List InflateEntries(Func where) where T : PsarcAsset, new()
203 | {
204 | var inflatedEntries = new List();
205 |
206 | var entries = TOC.Entries.Where(where);
207 |
208 | foreach (var entry in entries)
209 | {
210 | inflatedEntries.Add(InflateEntry(entry));
211 | }
212 |
213 | return inflatedEntries;
214 | }
215 |
216 | #region Convenience Zone
217 |
218 | public DdsAsset ExtractAlbumArt(SongArrangement.ArrangementAttributes attr)
219 | {
220 | string artPath = $"gfxassets/album_art/{attr.AlbumArt.Substring(14)}_256.dds";
221 |
222 | var entry = TOC.Entries.FirstOrDefault(a => a.Path == artPath);
223 |
224 | if (entry == null) throw new KeyNotFoundException();
225 |
226 | return InflateEntry(entry);
227 | }
228 |
229 | ///
230 | /// Extract toolkitinfo, returns default values if not found
231 | ///
232 | ///
233 | public ToolkitInfo ExtractToolkitInfo()
234 | {
235 | var tkAsset = InflateEntry(entry => entry.Path?.Equals("toolkit.version") ?? false);
236 |
237 | if (tkAsset != null) return tkAsset.ToolkitInfo;
238 |
239 | return new ToolkitInfo();
240 | }
241 |
242 | ///
243 | /// Extracts all json files and assumes they are song arrangements, should work for all song psarc files
244 | ///
245 | ///
246 | public List ExtractArrangementManifests()
247 | {
248 | var list = InflateEntries>(asset => asset.Path.EndsWith(".json"));
249 |
250 | return list.Select(l => l.JsonObject).ToList();
251 | }
252 |
253 | #endregion
254 |
255 | #region Disposable
256 |
257 | private bool disposedValue;
258 |
259 | protected virtual void Dispose(bool disposing)
260 | {
261 | if (!disposedValue)
262 | {
263 | if (disposing)
264 | {
265 | // TODO: dispose managed state (managed objects)
266 | Reader.Dispose();
267 | FileStream.Dispose();
268 | }
269 |
270 | // TODO: free unmanaged resources (unmanaged objects) and override finalizer
271 | // TODO: set large fields to null
272 | disposedValue = true;
273 | }
274 | }
275 |
276 | // // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
277 | // ~PsarcFile()
278 | // {
279 | // // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
280 | // Dispose(disposing: false);
281 | // }
282 |
283 | public void Dispose()
284 | {
285 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
286 | Dispose(disposing: true);
287 | GC.SuppressFinalize(this);
288 | }
289 |
290 | #endregion
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/Psarc/Models/Json/SongArrangement.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 |
6 | namespace Rocksmith2014PsarcLib.Psarc.Models.Json
7 | {
8 | [Serializable]
9 | public class SongArrangement
10 | {
11 | [Serializable]
12 | public class ArrangementAttributes
13 | {
14 | [Serializable]
15 | public class Properties
16 | {
17 | [JsonProperty("represent")]
18 | public int Represent { get; set; }
19 | [JsonProperty("bonusArr")]
20 | public int BonusArr { get; set; }
21 | [JsonProperty("standardTuning")]
22 | public int StandardTuning { get; set; }
23 | [JsonProperty("nonStandardChords")]
24 | public int NonStandardChords { get; set; }
25 | [JsonProperty("barreChords")]
26 | public int BarreChords { get; set; }
27 | [JsonProperty("powerChords")]
28 | public int PowerChords { get; set; }
29 | [JsonProperty("dropDPower")]
30 | public int DropDPower { get; set; }
31 | [JsonProperty("openChords")]
32 | public int OpenChords { get; set; }
33 | [JsonProperty("fingerPicking")]
34 | public int FingerPicking { get; set; }
35 | [JsonProperty("pickDirection")]
36 | public int PickDirection { get; set; }
37 | [JsonProperty("doubleStops")]
38 | public int DoubleStops { get; set; }
39 | [JsonProperty("palmMutes")]
40 | public int PalmMutes { get; set; }
41 | [JsonProperty("harmonics")]
42 | public int Harmonics { get; set; }
43 | [JsonProperty("pinchHarmonics")]
44 | public int PinchHarmonics { get; set; }
45 | [JsonProperty("hopo")]
46 | public int Hopo { get; set; }
47 | [JsonProperty("tremolo")]
48 | public int Tremolo { get; set; }
49 | [JsonProperty("slides")]
50 | public int Slides { get; set; }
51 | [JsonProperty("unpitchedSlides")]
52 | public int UnpitchedSlides { get; set; }
53 | [JsonProperty("bends")]
54 | public int Bends { get; set; }
55 | [JsonProperty("tapping")]
56 | public int Tapping { get; set; }
57 | [JsonProperty("vibrato")]
58 | public int Vibrato { get; set; }
59 | [JsonProperty("fretHandMutes")]
60 | public int FretHandMutes { get; set; }
61 | [JsonProperty("slapPop")]
62 | public int SlapPop { get; set; }
63 | [JsonProperty("twoFingerPicking")]
64 | public int TwoFingerPicking { get; set; }
65 | [JsonProperty("fifthsAndOctaves")]
66 | public int FifthsAndOctaves { get; set; }
67 | [JsonProperty("syncopation")]
68 | public int Syncopation { get; set; }
69 | [JsonProperty("bassPick")]
70 | public int BassPick { get; set; }
71 | [JsonProperty("sustain")]
72 | public int Sustain { get; set; }
73 | [JsonProperty("pathLead")]
74 | public int PathLead { get; set; }
75 | [JsonProperty("pathRhythm")]
76 | public int PathRhythm { get; set; }
77 | [JsonProperty("pathBass")]
78 | public int PathBass { get; set; }
79 | [JsonProperty("routeMask")]
80 | public int RouteMask { get; set; }
81 | }
82 |
83 | [Serializable]
84 | public class PhraseIteration
85 | {
86 | public int PhraseIndex { get; set; }
87 | public int MaxDifficulty { get; set; }
88 |
89 | public string Name { get; set; }
90 |
91 | public float StartTime { get; set; }
92 | public float EndTime { get; set; }
93 | }
94 |
95 | [Serializable]
96 | public class Phrase
97 | {
98 | public int MaxDifficulty { get; set; }
99 |
100 | public string Name { get; set; }
101 |
102 | public int IterationCount { get; set; }
103 | }
104 |
105 | [Serializable]
106 | public class Section
107 | {
108 | public string Name { get; set; }
109 | public string UIName { get; set; }
110 |
111 | public int Number { get; set; }
112 |
113 | public float StartTime { get; set; }
114 | public float EndTime { get; set; }
115 |
116 | public int StartPhraseIterationIndex { get; set; }
117 | public int EndPhraseIterationIndex { get; set; }
118 |
119 | public bool IsSolo { get; set; }
120 | }
121 |
122 | [Serializable]
123 | public class Tone
124 | {
125 | [Serializable]
126 | public class ToneGear
127 | {
128 | [JsonProperty("Type")]
129 | public string Type { get; set; }
130 | public string Key { get; set; }
131 | public string Category { get; set; }
132 |
133 | public Dictionary KnobValues { get; set; }
134 | }
135 |
136 | public Dictionary> GearList { get; set; }
137 | public List ToneDescriptors { get; set; }
138 |
139 | public string NameSeparator { get; set; }
140 | public bool IsCustom { get; set; }
141 | public string Volume { get; set; }
142 | public string Key { get; set; }
143 | public string Name { get; set; }
144 | public float SortOrder { get; set; }
145 | }
146 |
147 | public class ArrangementTuning
148 | {
149 | [JsonProperty("string0")]
150 | public int String0 { get; set; }
151 | [JsonProperty("string1")]
152 | public int String1 { get; set; }
153 | [JsonProperty("string2")]
154 | public int String2 { get; set; }
155 | [JsonProperty("string3")]
156 | public int String3 { get; set; }
157 | [JsonProperty("string4")]
158 | public int String4 { get; set; }
159 | [JsonProperty("string5")]
160 | public int String5 { get; set; }
161 | }
162 |
163 | public string AlbumArt { get; set; }
164 | public string AlbumName { get; set; }
165 | public string AlbumNameSort { get; set; }
166 | public string ArrangementName { get; set; }
167 |
168 | public Properties ArrangementProperties { get; set; }
169 |
170 | public int ArrangementSort { get; set; }
171 | public int ArrangementType { get; set; }
172 |
173 | public string ArtistName { get; set; }
174 | public string ArtistNameSort { get; set; }
175 | public string BlockAsset { get; set; }
176 |
177 | public float CapoFret { get; set; }
178 | public float CentOffset { get; set; }
179 |
180 | public bool DLC { get; set; }
181 |
182 | public float DNA_Chords { get; set; }
183 | public float DNA_Riffs { get; set; }
184 | public float DNA_Solo { get; set; }
185 |
186 | public List DynamicVisualDensity { get; set; }
187 |
188 | public float EasyMastery { get; set; }
189 |
190 | public string FullName { get; set; }
191 | public string LastConversionDateTime { get; set; }
192 |
193 | public int? LeaderboardChallengeRating { get; set; }
194 |
195 | public string ManifestUrn { get; set; }
196 |
197 | public int MasterID_PS3 { get; set; }
198 | public int MasterID_RDV { get; set; }
199 | public int MasterID_XBox360 { get; set; }
200 | public int MaxPhraseDifficulty { get; set; }
201 |
202 | public float MediumMastery { get; set; }
203 | public float NotesEasy { get; set; }
204 | public float NotesHard { get; set; }
205 | public float NotesMedium { get; set; }
206 |
207 | public List PhraseIterations { get; set; }
208 | public List Phrases { get; set; }
209 |
210 | public string PreviewBankPath { get; set; }
211 |
212 | public int RelativeDifficulty { get; set; }
213 |
214 | public float Score_MaxNotes { get; set; }
215 | public float Score_PNV { get; set; }
216 |
217 | public List Sections { get; set; }
218 |
219 | public bool Shipping { get; set; }
220 |
221 | public string ShowlightsXML { get; set; }
222 | public string SKU { get; set; }
223 | public string SongAsset { get; set; }
224 |
225 | public float SongAverageTempo { get; set; }
226 |
227 | public string SongBank { get; set; }
228 |
229 | public float SongDiffEasy { get; set; }
230 | public float SongDiffHard { get; set; }
231 | public float SongDifficulty { get; set; }
232 | public float SongDiffMed { get; set; }
233 |
234 | public string SongEvent { get; set; }
235 | public string SongKey { get; set; }
236 |
237 | public float SongLength { get; set; }
238 |
239 | public string SongName { get; set; }
240 | public string SongNameSort { get; set; }
241 |
242 | public float SongOffset { get; set; }
243 |
244 | public int SongPartition { get; set; }
245 |
246 | public string SongXml { get; set; }
247 |
248 | public int SongYear { get; set; }
249 |
250 | public long TargetScore { get; set; }
251 |
252 | public Dictionary>> Techniques { get; set; }
253 |
254 | public string Tone_A { get; set; }
255 | public string Tone_B { get; set; }
256 | public string Tone_Base { get; set; }
257 | public string Tone_C { get; set; }
258 | public string Tone_D { get; set; }
259 | public string Tone_Multiplayer { get; set; }
260 |
261 | //public List Tones { get; set; }
262 |
263 | public ArrangementTuning Tuning { get; set; }
264 |
265 | public string PersistentID { get; set; }
266 | }
267 |
268 | public ArrangementAttributes Attributes { get; private set; }
269 |
270 | ///
271 | /// This is probably illegal in more than 100 countries, but who needs json converters when you can do this
272 | ///
273 | public Dictionary> Entries
274 | {
275 | set
276 | {
277 | Attributes = value.First().Value.First().Value;
278 | }
279 | }
280 |
281 | public string ModelName { get; set; }
282 | public int IterationVersion { get; set; }
283 | public string InsertRoot { get; set; }
284 | }
285 | }
286 |
--------------------------------------------------------------------------------