├── CP77SaveEditor.Core ├── Savegame │ ├── Values │ │ ├── Engine │ │ │ ├── Handle.cs │ │ │ ├── GameTime.cs │ │ │ ├── EntityHandle.cs │ │ │ └── EulerAngles.cs │ │ ├── Gwint │ │ │ ├── CollectionSize.cs │ │ │ ├── GwintDeckCard.cs │ │ │ ├── GwintDecks.cs │ │ │ ├── SelectedDeckIndex.cs │ │ │ ├── CollectionCard.cs │ │ │ ├── GwintDeck.cs │ │ │ └── GwintManager.cs │ │ ├── TagList.cs │ │ ├── W3Enum.cs │ │ ├── Facts.cs │ │ ├── W3EnvironmentManager.cs │ │ ├── Journal │ │ │ ├── JTrackedQuest.cs │ │ │ ├── JMonsterKnownGuid.cs │ │ │ ├── JHighlightedObjective.cs │ │ │ ├── JEntryAdvancedInfoGuid.cs │ │ │ ├── JHuntingClues.cs │ │ │ ├── JObjectiveCounters.cs │ │ │ ├── JObjectiveCounter.cs │ │ │ ├── JHuntingClue.cs │ │ │ ├── JMonsterKnown.cs │ │ │ ├── JEntryAdvancedInfo.cs │ │ │ └── CWitcherJournalManager.cs │ │ ├── EntityStateChangeRequests.cs │ │ ├── IdTagManager.cs │ │ ├── WorldInfo.cs │ │ ├── AdditionalContent.cs │ │ ├── CWitcherGameResource.cs │ │ ├── WorldState.cs │ │ ├── IdTag.cs │ │ ├── Quests │ │ │ ├── QuestSystem.cs │ │ │ ├── Quest.cs │ │ │ ├── QuestCondition.cs │ │ │ ├── ExternalDialog.cs │ │ │ ├── QuestConditions.cs │ │ │ ├── QuestThreadKeyValue.cs │ │ │ ├── QuestExternalScenePlayer.cs │ │ │ ├── QuestExternalScenePlayers.cs │ │ │ ├── QuestThread.cs │ │ │ └── QuestBlock.cs │ │ ├── SGameplayFact.cs │ │ ├── FactEntry.cs │ │ ├── SGameplayFactRemoval.cs │ │ ├── Fact.cs │ │ ├── SaveInfoItem.cs │ │ ├── SaveInfo.cs │ │ ├── TimerManager.cs │ │ ├── Universe.cs │ │ ├── EnvManager.cs │ │ ├── GameProp.cs │ │ └── SavegameRoot.cs │ ├── Variables │ │ ├── BsVariable.cs │ │ ├── OpVariable.cs │ │ ├── SsVariable.cs │ │ ├── BlckVariable.cs │ │ ├── AvalVariable.cs │ │ ├── PorpVariable.cs │ │ ├── VlVariable.cs │ │ ├── VariableSet.cs │ │ ├── SxapVariable.cs │ │ ├── InvalidVariable.cs │ │ ├── ManuVariable.cs │ │ ├── TypedVariable.cs │ │ ├── Variable.cs │ │ ├── UnknownVariable.cs │ │ └── VariableValue.cs │ ├── VariableTableEntry.cs │ ├── Attributes │ │ ├── CNameAttribute.cs │ │ ├── EnumNameAttribute.cs │ │ ├── CSerializableAttribute.cs │ │ └── CArrayAttribute.cs │ ├── VariableParsers │ │ ├── SxapVariableParser.cs │ │ ├── VlVariableParser.cs │ │ ├── AvalVariableParser.cs │ │ ├── OpVariableParser.cs │ │ ├── PorpVariableParser.cs │ │ ├── ManuVariableParser.cs │ │ ├── BsVariableParser.cs │ │ ├── BlckVariableParser.cs │ │ ├── SsVariableParser.cs │ │ └── VariableParserBase.cs │ ├── VariableParser.cs │ ├── VariableValueParser.cs │ └── SavegameFile.cs ├── Common │ ├── IReadSavegameProgress.cs │ └── ReadSavegameProgress.cs ├── Exceptions │ └── ParseVariableException.cs ├── CP77SaveEditor.Core.csproj ├── ChunkedLz4 │ ├── Lz4Chunk.cs │ ├── ChunkedLz4FileTable.cs │ ├── ChunkedLz4FileHeader.cs │ └── ChunkedLz4File.cs └── ExtensionMethods.cs ├── CP77SaveEditor ├── FodyWeavers.xml ├── App.xaml.cs ├── App.config ├── Properties │ ├── Settings.settings │ ├── AssemblyInfo.cs │ ├── Settings.Designer.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── MainWindow.xaml.cs ├── Models │ ├── SavegameModel.cs │ ├── SavegameDataModel.cs │ └── VariableModel.cs ├── DelegateCommand.cs ├── App.xaml ├── ViewModels │ └── SavegameViewModel.cs ├── CP77SaveEditor.csproj ├── FodyWeavers.xsd └── MainWindow.xaml ├── README.md ├── LICENSE ├── CP77SaveEditor.sln ├── .gitattributes └── .gitignore /CP77SaveEditor.Core/Savegame/Values/Engine/Handle.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values.Engine 2 | { 3 | public class Handle 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /CP77SaveEditor/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /CP77SaveEditor/App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor 2 | { 3 | /// 4 | /// Interaktionslogik für "App.xaml" 5 | /// 6 | public partial class App 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/CollectionSize.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 2 | { 3 | public class CollectionSize 4 | { 5 | public uint Size { get; set; } 6 | 7 | } 8 | } -------------------------------------------------------------------------------- /CP77SaveEditor/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Common/IReadSavegameProgress.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Common 2 | { 3 | public interface IReadSavegameProgress 4 | { 5 | void Report(bool running, bool indeterministic, int value, int max); 6 | } 7 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/TagList.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values 2 | { 3 | public class TagList 4 | { 5 | public bool Flag { get; set; } 6 | public short[] Entities { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/W3Enum.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values 2 | { 3 | public class W3Enum 4 | { 5 | public byte Unknown1 { get; set; } 6 | public byte Unknown2 { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Engine/GameTime.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Engine 4 | { 5 | [CSerializable("gameTime")] 6 | public class GameTime 7 | { 8 | } 9 | } -------------------------------------------------------------------------------- /CP77SaveEditor/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/BsVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class BsVariable : VariableSet 4 | { 5 | public override string ToString() 6 | { 7 | return "BS " + base.ToString(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/OpVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class OpVariable : TypedVariable 4 | { 5 | public override string ToString() 6 | { 7 | return "OP " + base.ToString(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/SsVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class SsVariable : VariableSet 4 | { 5 | public override string ToString() 6 | { 7 | return "SS " + base.ToString(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Facts.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CSerializable("facts")] 6 | public class Facts 7 | { 8 | [CArray] 9 | public Fact[] Items { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/W3EnvironmentManager.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | public class W3EnvironmentManager 6 | { 7 | [CName("m_envId")] 8 | public int EnvId { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/GwintDeckCard.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 4 | { 5 | public class GwintDeckCard 6 | { 7 | [CName("cardIndex")] 8 | public int CardIndex { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/BlckVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class BlckVariable : VariableSet 4 | { 5 | public override string ToString() 6 | { 7 | return "BLCK " + base.ToString(); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/AvalVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class AvalVariable : TypedVariable 4 | { 5 | public override string ToString() 6 | { 7 | return "AVAL " + base.ToString(); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/PorpVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class PorpVariable : TypedVariable 4 | { 5 | public override string ToString() 6 | { 7 | return "PORP " + base.ToString(); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Engine/EntityHandle.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values.Engine 2 | { 3 | public class EntityHandle 4 | { 5 | public byte Unknown1 { get; set; } 6 | public byte Unknown2 { get; set; } 7 | public byte[] Unknown3 { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JTrackedQuest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 5 | { 6 | public class JTrackedQuest 7 | { 8 | [CName("guid")] 9 | public Guid Guid { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/EntityStateChangeRequests.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | public class EntityStateChangeRequests 6 | { 7 | [CName("requestsCount")] 8 | public uint RequestsCount { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/IdTagManager.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CName("idTagManager")] 6 | public class IdTagManager 7 | { 8 | [CName("tagIndex")] 9 | public ulong TagIndex { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor 2 | { 3 | /// 4 | /// Interaktionslogik für MainWindow.xaml 5 | /// 6 | public partial class MainWindow 7 | { 8 | public MainWindow() 9 | { 10 | InitializeComponent(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JMonsterKnownGuid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 5 | { 6 | public class JMonsterKnownGuid 7 | { 8 | [CName("guid")] 9 | public Guid Guid { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/WorldInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values 5 | { 6 | [CName("worldInfo")] 7 | public class WorldInfo 8 | { 9 | [CName("world")] 10 | public String World { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JHighlightedObjective.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 5 | { 6 | public class JHighlightedObjective 7 | { 8 | [CName("guid")] 9 | public Guid Guid { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JEntryAdvancedInfoGuid.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 5 | { 6 | public class JEntryAdvancedInfoGuid 7 | { 8 | [CName("guid")] 9 | public Guid Guid { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/AdditionalContent.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | public class AdditionalContent 6 | { 7 | [CName("count")] 8 | public uint Count { get; set; } 9 | 10 | public string[] Items { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /CP77SaveEditor/Models/SavegameModel.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Models 2 | { 3 | public class SavegameModel 4 | { 5 | public string Name { get; set; } 6 | 7 | public string Path { get; set; } 8 | 9 | public string ThumbnailPath { get; set; } 10 | 11 | public SavegameDataModel Data { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/CWitcherGameResource.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CSerializable("CWitcherGameResource")] 6 | public class CWitcherGameResource 7 | { 8 | [CName("path")] 9 | public string Path { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Engine/EulerAngles.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values.Engine 2 | { 3 | public class EulerAngles 4 | { 5 | public byte[] Unknown1 { get; set; } 6 | public double Pitch { get; set; } 7 | public double Yaw { get; set; } 8 | public double Roll { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/GwintDecks.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 4 | { 5 | public class GwintDecks 6 | { 7 | [CName("DeckCount")] 8 | public uint DeckCount { get; set; } 9 | 10 | public GwintDeck[] Decks { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/SelectedDeckIndex.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 4 | { 5 | public class SelectedDeckIndex 6 | { 7 | [CName("deckIndex")] 8 | [EnumName("eGwintFaction")] 9 | public W3Enum DeckIndex { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JHuntingClues.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 4 | { 5 | public class JHuntingClues 6 | { 7 | [CName("Size")] 8 | public uint Size { get; set; } 9 | 10 | public JHuntingClue[] Clues { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/WorldState.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CName("worldState")] 6 | public class WorldState 7 | { 8 | [CName("entityStateChangeRequests")] 9 | public EntityStateChangeRequests EntityStateChangeRequests { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/VlVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | /// 4 | /// A single variable 5 | /// 6 | public class VlVariable : TypedVariable 7 | { 8 | public override string ToString() 9 | { 10 | return "VL " + base.ToString(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/IdTag.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Values 2 | { 3 | public class IdTag 4 | { 5 | public byte Unknown1 { get; set; } 6 | public int Unknown2 { get; set; } 7 | public int Unknown3 { get; set; } 8 | public int Unknown4 { get; set; } 9 | public int Unknown5 { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JObjectiveCounters.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 4 | { 5 | public class JObjectiveCounters 6 | { 7 | [CName("Size")] 8 | public uint Size { get; set; } 9 | 10 | public JObjectiveCounter[] Counters { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/VariableSet.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class VariableSet : Variable 4 | { 5 | public Variable[] Variables { get; set; } 6 | 7 | public override string ToString() 8 | { 9 | return string.Format("{0}[{1}]", base.ToString(), Variables.Length); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/CollectionCard.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 4 | { 5 | public class CollectionCard 6 | { 7 | [CName("cardIndex")] 8 | public uint CardIndex { get; set; } 9 | 10 | [CName("numCopies")] 11 | public uint NumCopies { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableTableEntry.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame 2 | { 3 | public class VariableTableEntry 4 | { 5 | public int Offset { get; set; } 6 | public int Size { get; set; } 7 | 8 | public override string ToString() 9 | { 10 | return string.Format("Offset: {0}, Size: {1}", Offset, Size); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestSystem.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("questSystem")] 6 | public class QuestSystem 7 | { 8 | [CName("questExternalScenePlayers")] 9 | public QuestExternalScenePlayers QuestExternalScenePlayers { get; set; } 10 | 11 | } 12 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JObjectiveCounter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 5 | { 6 | public class JObjectiveCounter 7 | { 8 | [CName("guid")] 9 | public Guid Guid { get; set; } 10 | 11 | [CName("count")] 12 | public int Count { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/SGameplayFact.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CName("SGameplayFact")] 6 | public class SGameplayFact 7 | { 8 | [CName("factName")] 9 | public string FactName { get; set; } 10 | 11 | [CName("value")] 12 | public int Value { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JHuntingClue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 5 | { 6 | public class JHuntingClue 7 | { 8 | [CName("JHuntingQuestGuid")] 9 | public Guid HuntingQuestGuid { get; set; } 10 | 11 | [CName("Size")] 12 | public uint Size { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JMonsterKnown.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 4 | { 5 | public class JMonsterKnown 6 | { 7 | [CName("Size")] 8 | public uint Size { get; set; } 9 | 10 | [CName("JMonsterKnownGuid")] 11 | public JMonsterKnownGuid[] MonsterKnownGuid { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/Quest.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("quest")] 6 | public class Quest 7 | { 8 | [CName("fileName")] 9 | public string FileName { get; set; } 10 | 11 | [CName("questThread")] 12 | public QuestThread QuestThread { get; set; } 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestCondition.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("questCondition", Custom = true)] 6 | public class QuestCondition 7 | { 8 | [CName("nP")] 9 | public uint Np { get; set; } 10 | 11 | [CName("active")] 12 | public bool Active { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Attributes/CNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)] 6 | public class CNameAttribute : Attribute 7 | { 8 | public string Name { get; set; } 9 | 10 | public CNameAttribute(string name) 11 | { 12 | Name = name; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/JEntryAdvancedInfo.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 4 | { 5 | public class JEntryAdvancedInfo 6 | { 7 | [CName("Size")] 8 | public uint Size { get; set; } 9 | 10 | [CName("JEntryAdvancedInfoGuid")] 11 | public JEntryAdvancedInfoGuid[] JEntryAdvancedInfoGuid { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Attributes/EnumNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Property)] 6 | public class EnumNameAttribute : Attribute 7 | { 8 | private string Name { get; set; } 9 | 10 | public EnumNameAttribute(string name) 11 | { 12 | Name = name; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/ExternalDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 5 | { 6 | [CSerializable("ExternalDialog")] 7 | public class ExternalDialog 8 | { 9 | [CName("tag")] 10 | public string Tag { get; set; } 11 | [CArray("dialogsCount")] 12 | public Guid[] Dialogs { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/SxapVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class SxapVariable : Variable 4 | { 5 | public int TypeCode1 { get; set; } 6 | public int TypeCode2 { get; set; } 7 | public int TypeCode3 { get; set; } 8 | 9 | public override string ToString() 10 | { 11 | return "SXAP " + base.ToString(); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/InvalidVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class InvalidVariable : Variable 4 | { 5 | private readonly string message; 6 | 7 | public InvalidVariable(string message) 8 | { 9 | this.message = message; 10 | } 11 | 12 | public override string ToString() 13 | { 14 | return message; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/FactEntry.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CSerializable("entry")] 6 | public class FactEntry 7 | { 8 | [CName("value")] 9 | public int Value { get; set; } 10 | [CName("time")] 11 | public double Time { get; set; } 12 | [CName("expiryTime")] 13 | public double ExpiryTime { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/SGameplayFactRemoval.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | public class SGameplayFactRemoval 6 | { 7 | [CName("factName")] 8 | public string FactName { get; set; } 9 | 10 | [CName("value")] 11 | public int Value { get; set; } 12 | 13 | [CName("timerID")] 14 | public int TimerId { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Fact.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CSerializable("fact")] 6 | public class Fact 7 | { 8 | [CName("id")] 9 | public string Id { get; set; } 10 | [CName("expiringCount")] 11 | public uint ExpiringCount { get; set; } 12 | [CArray("entryCount")] 13 | public FactEntry[] Entries { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestConditions.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("conditions")] 6 | public class QuestConditions 7 | { 8 | public QuestConditions() 9 | { 10 | 11 | } 12 | 13 | [CArray("numConditions", ElementName = "p")] 14 | public QuestCondition[] Conditions { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/SaveInfoItem.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CSerializable("SaveInfoItem", Custom = true)] 6 | public class SaveInfoItem 7 | { 8 | [CName("time")] 9 | public ulong Time { get; set; } 10 | 11 | [CName("type")] 12 | public byte Type { get; set; } 13 | 14 | [CName("v")] 15 | public ushort V { get; set; } 16 | } 17 | } -------------------------------------------------------------------------------- /CP77SaveEditor/Models/SavegameDataModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | namespace CP77SaveEditor.Models 4 | { 5 | public class SavegameDataModel 6 | { 7 | public int Version1 { get; set; } 8 | public int Version2 { get; set; } 9 | public int Version3 { get; set; } 10 | 11 | public ObservableCollection VariableNames { get; set; } 12 | 13 | public ObservableCollection Variables { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/ManuVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | /// 4 | /// A set of strings. 5 | /// 6 | public class ManuVariable : Variable 7 | { 8 | public string[] Strings { get; set; } 9 | public override string ToString() 10 | { 11 | return string.Format("MANU[{0}] {1}", (Strings == null ? "null" : Strings.Length.ToString()), base.ToString()); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/TypedVariable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Variables 4 | { 5 | public class TypedVariable : Variable 6 | { 7 | public string Type { get; set; } 8 | public Type ClrType { get; set; } 9 | public VariableValue Value { get; set; } 10 | 11 | public override string ToString() 12 | { 13 | return string.Format("{0} {1} {2}", Type, base.ToString(), Value); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/Variable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public abstract class Variable 4 | { 5 | public string Name { get; set; } 6 | 7 | public int Size { get; set; } 8 | 9 | public int TokenSize { get; set; } 10 | 11 | public Variable() 12 | { 13 | Name = "None"; 14 | } 15 | 16 | public override string ToString() 17 | { 18 | return Name; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/UnknownVariable.cs: -------------------------------------------------------------------------------- 1 | namespace CP77SaveEditor.Core.Savegame.Variables 2 | { 3 | public class UnknownVariable : Variable 4 | { 5 | public static readonly UnknownVariable None = new UnknownVariable { Name = "None" }; 6 | 7 | public byte[] Data { get; set; } 8 | 9 | public override string ToString() 10 | { 11 | return string.Format("Unknown[{0}] {1}", (Data == null ? "null" : Data.Length.ToString()), base.ToString()); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Exceptions/ParseVariableException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Exceptions 4 | { 5 | 6 | [Serializable] 7 | public class ParseVariableException : Exception 8 | { 9 | public ParseVariableException() 10 | { 11 | } 12 | 13 | public ParseVariableException(string message) : base(message) 14 | { 15 | } 16 | 17 | public ParseVariableException(string message, Exception inner) : base(message, inner) 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/GwintDeck.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 4 | { 5 | public class GwintDeck 6 | { 7 | [CName("DeckUnlocked")] 8 | public bool DeckUnlocked { get; set; } 9 | 10 | [CName("LeaderIndex")] 11 | public int LeaderIndex { get; set; } 12 | 13 | [CName("CardCount")] 14 | public uint CardCount { get; set; } 15 | 16 | public GwintDeckCard[] GwintDeckCards { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestThreadKeyValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 5 | { 6 | [CSerializable("questThreadKeyValue", Custom = true)] 7 | public class QuestThreadKeyValue 8 | { 9 | public QuestThreadKeyValue() 10 | { 11 | 12 | } 13 | 14 | [CName("GUID")] 15 | public Guid Guid { get; set; } 16 | 17 | [CName("questThread")] 18 | public QuestThread Thread { get; set; } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestExternalScenePlayer.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("CQuestExternalScenePlayer")] 6 | public class QuestExternalScenePlayer 7 | { 8 | public QuestExternalScenePlayer() 9 | { 10 | 11 | } 12 | 13 | [CArray("tagsCount")] 14 | public ExternalDialog[] ExternalDialogs { get; set; } 15 | 16 | [CArray("numQuests")] 17 | public Quest[] Quests { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/SaveInfo.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CSerializable("saveInfo")] 6 | public class SaveInfo 7 | { 8 | [CName("magic_number")] 9 | public byte[] MagicNumber { get; set; } 10 | 11 | [CName("description")] 12 | public string Description { get; set; } 13 | 14 | [CName("runtimeGUIDCounter")] 15 | public ulong RuntimeGuidCounter { get; set; } 16 | 17 | [CArray] 18 | public SaveInfoItem[] Items { get; set; } 19 | } 20 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestExternalScenePlayers.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("questExternalScenePlayers")] 6 | public class QuestExternalScenePlayers 7 | { 8 | 9 | public QuestExternalScenePlayers() 10 | { 11 | 12 | } 13 | 14 | [CName("")] 15 | public QuestExternalScenePlayer QuestExternalScenePlayer1 { get; set; } 16 | 17 | 18 | [CName("")] 19 | public QuestExternalScenePlayer QuestExternalScenePlayer2 { get; set; } 20 | } 21 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Attributes/CSerializableAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Attributes 4 | { 5 | [AttributeUsage(AttributeTargets.Class)] 6 | public class CSerializableAttribute : Attribute 7 | { 8 | public string TypeName { get; set; } 9 | 10 | /// 11 | /// Flag that symbolizes that the name of the type is guessed. 12 | /// 13 | public bool Custom { get; set; } 14 | 15 | public CSerializableAttribute(string typeName) 16 | { 17 | TypeName = typeName; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /CP77SaveEditor/Models/VariableModel.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.ObjectModel; 2 | 3 | namespace CP77SaveEditor.Models 4 | { 5 | public class VariableModel 6 | { 7 | public int Index { get; set; } 8 | 9 | public string Name { get; set; } 10 | 11 | public string Type { get; set; } 12 | 13 | public string Value { get; set; } 14 | 15 | public string DebugString { get; set; } 16 | 17 | public ObservableCollection Children { get; set; } 18 | 19 | public override string ToString() 20 | { 21 | return DebugString; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CP77SaveEditor 2 | A tool for unpacking savegames of the game Cyberpunk 2077. 3 | 4 | Uses [W3SavegameEditor](https://github.com/Atvaark/W3SavegameEditor) as the base code, and is modified for Cyberpunk. 5 | 6 | Currently all it can do is decompress the data and write it to the Cyberpunk save folder. 7 | Working on deciphering the decompressed data. 8 | 9 | Requirements 10 | -------- 11 | [Microsoft .NET Framework 4.7.1][0] 12 | 13 | Dependencies 14 | -------- 15 | [K4os.Compression.LZ4][1] 16 | 17 | 18 | [0]:https://dotnet.microsoft.com/download/dotnet-framework/net471 19 | [1]:https://github.com/MiloszKrajewski/K4os.Compression.LZ4 20 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/TimerManager.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | using CP77SaveEditor.Core.Savegame.Values.Engine; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values 5 | { 6 | [CName("timerManager")] 7 | public class TimerManager 8 | { 9 | [CName("time")] 10 | public GameTime Time { get; set; } 11 | 12 | public object Unknown1 { get; set; } 13 | 14 | [CName("isPaused")] 15 | public bool IsPaused { get; set; } 16 | 17 | [CName("timeScalePriorityIndexGenerator")] 18 | public uint TimeScalePriorityIndexGenerator { get; set; } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Attributes/CArrayAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Attributes 4 | { 5 | 6 | [AttributeUsage(AttributeTargets.Property)] 7 | public class CArrayAttribute : Attribute 8 | { 9 | private const string DefaultCountName = "count"; 10 | public string CountName { get; set; } 11 | public string ElementName { get; set; } 12 | 13 | public CArrayAttribute() : this(DefaultCountName) 14 | { 15 | 16 | } 17 | 18 | 19 | public CArrayAttribute(string countName) 20 | { 21 | CountName = countName; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestThread.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 4 | { 5 | [CSerializable("questThread")] 6 | public class QuestThread 7 | { 8 | public QuestThread() 9 | { 10 | 11 | } 12 | 13 | [CArray("numBlocksToActivate")] 14 | public QuestBlock[] QuestBlocksToActivate { get; set; } 15 | 16 | [CArray("numBlocks")] 17 | public QuestBlock[] QuestBlocks { get; set; } 18 | 19 | [CArray("numThreads", ElementName = "questThread")] 20 | public QuestThreadKeyValue[] QuestThreads { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /CP77SaveEditor/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | 5 | [assembly: AssemblyTitle("CP77SaveEditor")] 6 | [assembly: AssemblyDescription("")] 7 | [assembly: AssemblyConfiguration("")] 8 | [assembly: AssemblyCompany("")] 9 | [assembly: AssemblyProduct("CP77SaveEditor")] 10 | [assembly: AssemblyCopyright("Copyright © 2020 blendermf")] 11 | [assembly: AssemblyTrademark("")] 12 | [assembly: AssemblyCulture("")] 13 | [assembly: ComVisible(false)] 14 | [assembly: ThemeInfo( 15 | ResourceDictionaryLocation.None, 16 | ResourceDictionaryLocation.SourceAssembly 17 | )] 18 | [assembly: AssemblyVersion("0.1.0.0")] 19 | [assembly: AssemblyFileVersion("0.1.0.0")] 20 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Universe.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | using CP77SaveEditor.Core.Savegame.Values.Engine; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values 5 | { 6 | public class Universe 7 | { 8 | [CName("Player")] 9 | public Player Player { get; set; } 10 | } 11 | 12 | public class Player 13 | { 14 | [CName("id")] 15 | public IdTag Id { get; set; } 16 | 17 | [CName("position")] 18 | //[CType("Vector")] 19 | public object Position { get; set; } 20 | 21 | [CName("Rotation")] 22 | public EulerAngles Rotation { get; set; } 23 | 24 | [CName("template")] 25 | public string Template { get; set; } 26 | } 27 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/EnvManager.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values 4 | { 5 | [CName("envManager")] 6 | public class EnvManager 7 | { 8 | [CName("sepiaActive")] 9 | public uint SepiaActive { get; set; } 10 | 11 | [CName("weatherConditionName")] 12 | //[CType("CName")] 13 | public string WeatherConditionName { get; set; } 14 | 15 | [CName("QuestEnvDepotPath")] 16 | public string QuestEnvDepotPath { get; set; } 17 | 18 | [CName("QuestEnvPriority")] 19 | public int QuestEnvPriority { get; set; } 20 | 21 | [CName("QuestEnvBlendFactor")] 22 | public float QuestEnvBlendFactor { get; set; } 23 | } 24 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/CP77SaveEditor.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 7.3 6 | 0.2.0 7 | blendermf 8 | Copyright © 2020 blendermf 9 | https://github.com/blendermf/CP77SaveEditor/blob/master/LICENSE 10 | https://github.com/blendermf/CP77SaveEditor 11 | git 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/SxapVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CP77SaveEditor.Core.Exceptions; 3 | using CP77SaveEditor.Core.Savegame.Variables; 4 | 5 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 6 | { 7 | public class SxapVariableParser : VariableParserBase 8 | { 9 | public override string MagicNumber => "SXAP"; 10 | 11 | public override SxapVariable ParseImpl(BinaryReader reader, ref int size) 12 | { 13 | int typeCode1 = reader.ReadInt32(); 14 | int typeCode2 = reader.ReadInt32(); 15 | int typeCode3 = reader.ReadInt32(); 16 | size -= 3 * sizeof(int); 17 | 18 | return new SxapVariable 19 | { 20 | TypeCode1 = typeCode1, 21 | TypeCode2 = typeCode2, 22 | TypeCode3 = typeCode3 23 | }; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Journal/CWitcherJournalManager.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Journal 4 | { 5 | public class CWitcherJournalManager /* : CJournalManager */ 6 | { 7 | [CName("JObjectiveCounters")] 8 | public JObjectiveCounters ObjectiveCounters { get; set; } 9 | 10 | [CName("JTrackedQuest")] 11 | public JTrackedQuest TrackedQuest { get; set; } 12 | 13 | [CName("JHighlightedObjective")] 14 | public JHighlightedObjective HighlightedObjective { get; set; } 15 | 16 | [CName("JHuntingClues")] 17 | public JHuntingClues HuntingClues { get; set; } 18 | 19 | [CName("JMonsterKnown")] 20 | public JMonsterKnown MonsterKnown { get; set; } 21 | 22 | [CName("JEntryAdvancedInfo")] 23 | public JEntryAdvancedInfo EntryAdvancedInfo { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Quests/QuestBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using CP77SaveEditor.Core.Savegame.Attributes; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values.Quests 5 | { 6 | [CSerializable("questBlock")] 7 | public class QuestBlock 8 | { 9 | [CName("GUID")] 10 | public Guid Guid { get; set; } 11 | 12 | [CArray("inputNamesCount")] 13 | public string[] InputNames { get; set; } 14 | 15 | [CName("activationState")] 16 | public int ActivationState { get; set; } 17 | 18 | [CName("wasInputActivated")] 19 | public bool WasInputActivated { get; set; } 20 | 21 | [CName("wasOutputActivated")] 22 | public bool WasOutputActivated { get; set; } 23 | 24 | [CName("conditions")] 25 | public QuestConditions Conditions { get; set; } 26 | 27 | // TODO: Continue here. This is a VL Variable without properties. 28 | //[CName("timeRemaining")] 29 | //public GameTime TimeRemaining { get; set; } 30 | } 31 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/VlVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CP77SaveEditor.Core.Savegame.Variables; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 5 | { 6 | public class VlVariableParser : VariableParserBase 7 | { 8 | public override string MagicNumber 9 | { 10 | get { return "VL"; } 11 | } 12 | 13 | public override VlVariable ParseImpl(BinaryReader reader, ref int size) 14 | { 15 | short nameIndex = reader.ReadInt16(); 16 | short typeIndex = reader.ReadInt16(); 17 | size -= 2 * sizeof(short); 18 | string name = Names[nameIndex - 1]; 19 | string type = Names[typeIndex - 1]; 20 | 21 | var value = ReadValue(reader, type, ref size); 22 | 23 | return new VlVariable 24 | { 25 | Name = name, 26 | Type = type, 27 | Value = value 28 | }; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/ChunkedLz4/Lz4Chunk.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using K4os.Compression.LZ4; 5 | 6 | namespace CP77SaveEditor.Core.ChunkedLz4 7 | { 8 | public class Lz4Chunk 9 | { 10 | public int CompressedChunkSize { get; set; } 11 | 12 | public int DecompressedChunkSize { get; set; } 13 | 14 | public int EndOfChunkOffset { get; set; } 15 | 16 | public Span Read(Stream inputStream) 17 | { 18 | Span inputData = stackalloc byte[CompressedChunkSize - 8]; 19 | Span outputData = new byte[DecompressedChunkSize]; 20 | inputStream.Seek(8, SeekOrigin.Current); 21 | inputStream.Read(inputData); 22 | int bytesDecoded = LZ4Codec.Decode(inputData, outputData); 23 | 24 | Debug.Assert(bytesDecoded == DecompressedChunkSize); 25 | 26 | Debug.Assert(inputStream.Position == EndOfChunkOffset || EndOfChunkOffset == 0); 27 | 28 | return outputData; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/Gwint/GwintManager.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Values.Gwint 4 | { 5 | [CName("CR4GwintManager")] 6 | public class GwintManager 7 | { 8 | [CName("SBCollectionCardSize")] 9 | public CollectionSize CollectionCardSize { get; set; } 10 | 11 | public CollectionCard[] CollectionCards { get; set; } 12 | 13 | [CName("SBLeaderCollectionCardSize")] 14 | public CollectionSize LeaderCollectionCardSize { get; set; } 15 | 16 | public CollectionCard[] LeaderCollectionCards { get; set; } 17 | 18 | [CName("SBSelectedDeckIndex")] 19 | public SelectedDeckIndex SelectedDeckIndex { get; set; } 20 | 21 | [CName("GwintDecks")] 22 | public GwintDecks GwintDecks { get; set; } 23 | 24 | [CName("GwintTutorialsDone")] 25 | public bool GwintTutorialsDone { get; set; } 26 | 27 | [CName("GwintDeckTutorialsDone")] 28 | public bool GwintDeckTutorialsDone { get; set; } 29 | } 30 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/AvalVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CP77SaveEditor.Core.Exceptions; 3 | using CP77SaveEditor.Core.Savegame.Variables; 4 | 5 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 6 | { 7 | public class AvalVariableParser : VariableParserBase 8 | { 9 | public override string MagicNumber => "AVAL"; 10 | 11 | public override AvalVariable ParseImpl(BinaryReader reader, ref int size) 12 | { 13 | short nameIndex = reader.ReadInt16(); 14 | string name = Names[nameIndex - 1]; 15 | short typeIndex = reader.ReadInt16(); 16 | string type = Names[typeIndex - 1]; 17 | size -= 2 * sizeof(short); 18 | 19 | int unknown = reader.ReadInt32(); 20 | size -= sizeof(int); 21 | 22 | var value = ReadValue(reader, type, ref size); 23 | 24 | return new AvalVariable 25 | { 26 | Name = name, 27 | Type = type, 28 | Value = value 29 | }; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/ChunkedLz4/ChunkedLz4FileTable.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Text; 3 | 4 | namespace CP77SaveEditor.Core.ChunkedLz4 5 | { 6 | public class ChunkedLz4FileTable 7 | { 8 | public Lz4Chunk[] Chunks { get; set; } 9 | 10 | public static ChunkedLz4FileTable Read(Stream input, int chunkCount) 11 | { 12 | using (var reader = new BinaryReader(input, Encoding.ASCII, true)) 13 | { 14 | Lz4Chunk[] chunks = new Lz4Chunk[chunkCount]; 15 | for (int i = 0; i < chunkCount; i++) 16 | { 17 | chunks[i] = new Lz4Chunk 18 | { 19 | CompressedChunkSize = reader.ReadInt32(), 20 | DecompressedChunkSize = reader.ReadInt32(), 21 | EndOfChunkOffset = reader.ReadInt32() 22 | }; 23 | } 24 | 25 | return new ChunkedLz4FileTable 26 | { 27 | Chunks = chunks, 28 | }; 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/OpVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CP77SaveEditor.Core.Savegame.Variables; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 5 | { 6 | public class OpVariableParser : VariableParserBase 7 | { 8 | public override string MagicNumber => "OP"; 9 | 10 | public override OpVariable ParseImpl(BinaryReader reader, ref int size) 11 | { 12 | ushort nameIndex = reader.ReadUInt16(); 13 | ushort typeIndex = reader.ReadUInt16(); 14 | size -= 2 * sizeof(short); 15 | 16 | // BUG: Can read invalid indices 17 | string name = nameIndex - 1 < Names.Length ? Names[nameIndex - 1] : "Unknown"; 18 | string type = typeIndex - 1 < Names.Length ? Names[typeIndex - 1] : "Unknown"; 19 | 20 | var value = ReadValue(reader, type, ref size); 21 | 22 | return new OpVariable 23 | { 24 | Name = name, 25 | Type = type, 26 | Value = value 27 | }; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /CP77SaveEditor/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Input; 3 | 4 | namespace CP77SaveEditor 5 | { 6 | public class DelegateCommand : ICommand 7 | { 8 | private readonly Action _execute; 9 | private readonly Predicate _canExecute; 10 | 11 | public DelegateCommand(Action execute, Predicate canExecute = null) 12 | { 13 | _execute = execute; 14 | _canExecute = canExecute; 15 | } 16 | 17 | public bool CanExecute(object parameter) 18 | { 19 | return _canExecute == null || _canExecute(parameter); 20 | } 21 | 22 | public void Execute(object parameter) 23 | { 24 | if (_execute != null) 25 | { 26 | _execute(parameter); 27 | } 28 | } 29 | 30 | public event EventHandler CanExecuteChanged; 31 | 32 | protected virtual void OnCanExecuteChanged() 33 | { 34 | var handler = CanExecuteChanged; 35 | if (handler != null) handler(this, EventArgs.Empty); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Atvaark 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 | 23 | -------------------------------------------------------------------------------- /CP77SaveEditor/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CP77SaveEditor.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/PorpVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using CP77SaveEditor.Core.Exceptions; 4 | using CP77SaveEditor.Core.Savegame.Variables; 5 | 6 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 7 | { 8 | public class PorpVariableParser : VariableParserBase 9 | { 10 | public override string MagicNumber => "PORP"; 11 | 12 | public override PorpVariable ParseImpl(BinaryReader reader, ref int size) 13 | { 14 | short nameIndex = reader.ReadInt16(); 15 | string name = Names[nameIndex - 1]; 16 | 17 | short typeIndex = reader.ReadInt16(); 18 | string type = Names[typeIndex - 1]; 19 | 20 | size -= 2 * sizeof(short); 21 | 22 | int valueSize = reader.ReadInt32(); 23 | size -= sizeof(int); 24 | 25 | int readValueSize = valueSize; 26 | var value = ReadValue(reader, type, ref readValueSize); 27 | size -= valueSize; 28 | Debug.Assert(readValueSize == 0); 29 | 30 | return new PorpVariable 31 | { 32 | Name = name, 33 | Type = type, 34 | Value = value 35 | }; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/ChunkedLz4/ChunkedLz4FileHeader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace CP77SaveEditor.Core.ChunkedLz4 6 | { 7 | public class ChunkedLz4FileHeader 8 | { 9 | public int ChunkCount { get; set; } 10 | public int HeaderSize { get; set; } 11 | 12 | public static ChunkedLz4FileHeader Read(Stream input) 13 | { 14 | using (var reader = new BinaryReader(input, Encoding.ASCII, true)) 15 | { 16 | string saveFileHeader = reader.ReadString(4); 17 | if (saveFileHeader != "VASC") 18 | { 19 | throw new InvalidOperationException(); 20 | } 21 | 22 | // Currently Unknown data 23 | reader.ReadString(21); 24 | 25 | string chunkedLz4FileHeader = reader.ReadString(4); 26 | if (chunkedLz4FileHeader != "FZLC") 27 | { 28 | throw new InvalidOperationException(); 29 | } 30 | 31 | return new ChunkedLz4FileHeader 32 | { 33 | ChunkCount = reader.ReadInt32(), 34 | HeaderSize = reader.ReadInt32() 35 | }; 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /CP77SaveEditor/App.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/ManuVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using CP77SaveEditor.Core.Exceptions; 3 | using CP77SaveEditor.Core.Savegame.Variables; 4 | 5 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 6 | { 7 | public class ManuVariableParser : VariableParserBase 8 | { 9 | public override string MagicNumber => "MANU"; 10 | 11 | public override ManuVariable ParseImpl(BinaryReader reader, ref int size) 12 | { 13 | int stringCount = reader.ReadInt32(); 14 | int unknown1 = reader.ReadInt32(); 15 | size -= 2*sizeof (int); 16 | 17 | var strings = new string[stringCount]; 18 | for (int i = 0; i < stringCount; i++) 19 | { 20 | byte stringSize = reader.ReadByte(); 21 | strings[i] = reader.ReadString(stringSize); 22 | size -= sizeof (byte) + stringSize; 23 | } 24 | 25 | int unknown2 = reader.ReadInt32(); 26 | string doneMagicNumber = reader.ReadString(4); 27 | size -= sizeof (int) + 4; 28 | if (doneMagicNumber != "ENOD") 29 | { 30 | throw new ParseVariableException(); 31 | } 32 | 33 | return new ManuVariable 34 | { 35 | Strings = strings 36 | }; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/ChunkedLz4/ChunkedLz4File.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace CP77SaveEditor.Core.ChunkedLz4 7 | { 8 | public static class ChunkedLz4File 9 | { 10 | public static Stream Decompress(Stream input, string name) 11 | { 12 | ChunkedLz4FileHeader header = ChunkedLz4FileHeader.Read(input); 13 | var table = ChunkedLz4FileTable.Read(input, header.ChunkCount); 14 | input.Position = header.HeaderSize; 15 | 16 | var data = new byte[header.HeaderSize + table.Chunks.Sum(c => c.DecompressedChunkSize)]; 17 | var memoryStream = new MemoryStream(data) { Position = header.HeaderSize }; 18 | 19 | string fName = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "Saved Games\\CD Projekt Red\\Cyberpunk 2077\\" + name + "-Uncompressed.dat"); 20 | 21 | using (BinaryWriter writer = new BinaryWriter(File.Open(fName, FileMode.Create))) 22 | { 23 | foreach (var chunk in table.Chunks) 24 | { 25 | Span chunkData = chunk.Read(input); 26 | writer.Write(chunkData.ToArray()); 27 | memoryStream.Write(chunkData); 28 | Debug.Assert(input.Position == chunk.EndOfChunkOffset || chunk.EndOfChunkOffset == 0); 29 | } 30 | } 31 | 32 | memoryStream.Position = header.HeaderSize; 33 | return memoryStream; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/BsVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using CP77SaveEditor.Core.Exceptions; 4 | using CP77SaveEditor.Core.Savegame.Variables; 5 | 6 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 7 | { 8 | /// 9 | /// A set of variables 10 | /// 11 | public class BsVariableParser : VariableParserBase 12 | { 13 | private readonly VariableParser _parser; 14 | 15 | public BsVariableParser(VariableParser parser) 16 | { 17 | _parser = parser; 18 | } 19 | 20 | public override string MagicNumber => "BS"; 21 | 22 | public override void Verify(BinaryReader reader, ref int size) 23 | { 24 | base.Verify(reader, ref size); 25 | 26 | const int expectedSize = sizeof(short); 27 | if (size != expectedSize) 28 | throw new ParseVariableException($"BSVariable: Expected to read {expectedSize} bytes but found {size} at {reader.BaseStream.Position}"); 29 | } 30 | 31 | public override BsVariable ParseImpl(BinaryReader reader, ref int size) 32 | { 33 | short nameStringIndex = reader.ReadInt16(); 34 | string name = Names[nameStringIndex - 1]; 35 | size -= sizeof(short); 36 | Debug.Assert(size == 0); 37 | 38 | return new BsVariable 39 | { 40 | Name = name, 41 | Variables = new Variable[0] 42 | }; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/GameProp.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | using CP77SaveEditor.Core.Savegame.Values.Engine; 3 | 4 | namespace CP77SaveEditor.Core.Savegame.Values 5 | { 6 | [CName("gameProp")] 7 | public class GameProp 8 | { 9 | [CName("EngineTime")] 10 | public double EngineTime { get; set; } 11 | 12 | [CName("nP")] 13 | public uint Np { get; set; } 14 | 15 | 16 | /* CR4Game */ 17 | 18 | [CName("zoneName")] 19 | public W3Enum ZoneName { get; set; } 20 | 21 | [CName("recentDialogOrCutsceneEndGameTime")] 22 | public GameTime RecentDialogOrCutsceneEndGameTime { get; set; } 23 | 24 | public object Unknown1 { get; set; } 25 | 26 | [CName("gameplayFactsForRemoval")] 27 | public SGameplayFactRemoval[] GameplayFactsForRemoval { get; set; } 28 | 29 | [CName("gameplayFacts")] 30 | public SGameplayFact[] GameplayFacts { get; set; } 31 | 32 | [CName("tutorialManagerHandle")] 33 | public EntityHandle TutorialManagerHandle { get; set; } 34 | 35 | [CName("diffChangePostponed")] 36 | [EnumName("EDifficultyMode")] 37 | public W3Enum DiffChangePostponed { get; set; } 38 | 39 | [CName("dynamicallySpawnedBoats")] 40 | public EntityHandle[] DynamicallySpawnedBoats { get; set; } 41 | 42 | [CName("dynamicallySpawnedBoats")] 43 | public EntityHandle[] DynamicallySpawnedBoatsToDestroy { get; set; } 44 | 45 | /* /CR4Game */ 46 | 47 | [CName("envMgr")] 48 | public Handle EnvMgr { get; set; } 49 | 50 | public object Unknown2 { get; set; } 51 | } 52 | } -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/BlckVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using CP77SaveEditor.Core.Exceptions; 4 | using CP77SaveEditor.Core.Savegame.Variables; 5 | 6 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 7 | { 8 | public class BlckVariableParser : VariableParserBase 9 | { 10 | private readonly VariableParser _parser; 11 | 12 | public BlckVariableParser(VariableParser parser) 13 | { 14 | _parser = parser; 15 | } 16 | 17 | public override string MagicNumber => "BLCK"; 18 | 19 | public override BlckVariable ParseImpl(BinaryReader reader, ref int size) 20 | { 21 | ushort nameIndex = reader.ReadUInt16(); 22 | string name = Names[nameIndex - 1]; 23 | ushort blckSize = reader.ReadUInt16(); 24 | ushort unknown3 = reader.ReadUInt16(); 25 | size -= 3 * sizeof(short); 26 | 27 | // TODO: Only read blckSize 28 | List variables = new List(); 29 | 30 | Variable debugLastVariable = null; 31 | long debugStartPos = reader.BaseStream.Position; 32 | int debugIndex = 0; 33 | while (size > 0) 34 | { 35 | var variable = _parser.Parse(reader, ref size); 36 | variables.Add(variable); 37 | 38 | debugLastVariable = variable; 39 | debugIndex++; 40 | } 41 | 42 | return new BlckVariable 43 | { 44 | Name = name, 45 | Variables = variables.ToArray() 46 | }; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParsers/SsVariableParser.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using CP77SaveEditor.Core.Exceptions; 5 | using CP77SaveEditor.Core.Savegame.Variables; 6 | 7 | namespace CP77SaveEditor.Core.Savegame.VariableParsers 8 | { 9 | public class SsVariableParser : VariableParserBase 10 | { 11 | private readonly VariableParser _parser; 12 | 13 | public SsVariableParser(VariableParser parser) 14 | { 15 | _parser = parser; 16 | } 17 | 18 | public override string MagicNumber => "SS"; 19 | 20 | public override void Verify(BinaryReader reader, ref int size) 21 | { 22 | base.Verify(reader, ref size); 23 | 24 | var position = reader.BaseStream.Position; 25 | var sizeInner = reader.ReadInt32(); 26 | reader.BaseStream.Position = position; 27 | var expectedSize = sizeof(int) + sizeInner; 28 | 29 | if (size != expectedSize) 30 | throw new ParseVariableException($"SSVariable: Expected to read {expectedSize} bytes but found {size} at {reader.BaseStream.Position}"); 31 | } 32 | 33 | public override SsVariable ParseImpl(BinaryReader reader, ref int size) 34 | { 35 | int sizeInner = reader.ReadInt32(); 36 | size -= sizeof(int); 37 | Debug.Assert(sizeInner == size); 38 | 39 | List variables = new List(); 40 | while (size > 0) 41 | { 42 | var variable = _parser.Parse(reader, ref size); 43 | variables.Add(variable); 44 | } 45 | 46 | Debug.Assert(size == 0); 47 | 48 | return new SsVariable 49 | { 50 | Name = "None", 51 | Variables = variables.ToArray() 52 | }; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /CP77SaveEditor.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30204.135 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CP77SaveEditor", "CP77SaveEditor\CP77SaveEditor.csproj", "{92054529-EA59-4CD9-9C24-019D8B5A0867}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CP77SaveEditor.Core", "CP77SaveEditor.Core\CP77SaveEditor.Core.csproj", "{9C026DA7-481D-43C6-8C18-635D69FDB423}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CF9C2986-1DCD-4617-94B8-CFF8815DD156}" 11 | ProjectSection(SolutionItems) = preProject 12 | README.md = README.md 13 | EndProjectSection 14 | EndProject 15 | Global 16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 17 | Debug|Any CPU = Debug|Any CPU 18 | Release|Any CPU = Release|Any CPU 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {92054529-EA59-4CD9-9C24-019D8B5A0867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {92054529-EA59-4CD9-9C24-019D8B5A0867}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {92054529-EA59-4CD9-9C24-019D8B5A0867}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {92054529-EA59-4CD9-9C24-019D8B5A0867}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {9C026DA7-481D-43C6-8C18-635D69FDB423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {9C026DA7-481D-43C6-8C18-635D69FDB423}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {9C026DA7-481D-43C6-8C18-635D69FDB423}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {9C026DA7-481D-43C6-8C18-635D69FDB423}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | GlobalSection(SolutionProperties) = preSolution 31 | HideSolutionNode = FALSE 32 | EndGlobalSection 33 | GlobalSection(ExtensibilityGlobals) = postSolution 34 | SolutionGuid = {EF02657F-858C-49B8-B05E-EE812844FBA4} 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Values/SavegameRoot.cs: -------------------------------------------------------------------------------- 1 | using CP77SaveEditor.Core.Savegame.Attributes; 2 | using CP77SaveEditor.Core.Savegame.Values.Gwint; 3 | using CP77SaveEditor.Core.Savegame.Values.Journal; 4 | using CP77SaveEditor.Core.Savegame.Values.Quests; 5 | 6 | namespace CP77SaveEditor.Core.Savegame.Values 7 | { 8 | [CSerializable("SavegameRoot", Custom = true)] 9 | public class SavegameRoot 10 | { 11 | [CName("CWitcherGameResource")] 12 | public CWitcherGameResource WitcherGameResource { get; set; } 13 | [CName("saveInfo")] 14 | public SaveInfo SaveInfo { get; set; } 15 | [CName("facts")] 16 | public Facts Facts { get; set; } 17 | [CName("questSystem")] 18 | public QuestSystem QuestSystem { get; set; } 19 | public object Community { get; set; } 20 | public object Attitudes { get; set; } 21 | public object ParentGroups { get; set; } 22 | public object ActorAttitudes { get; set; } 23 | public CWitcherJournalManager JournalManager { get; set; } 24 | public object TelemetrySessionId { get; set; } 25 | public GwintManager GwintManager { get; set; } 26 | public object StrayActiors { get; set; } 27 | public object SoundClues { get; set; } 28 | public object ScentClues { get; set; } 29 | public object FocusModeVisibility { get; set; } 30 | public object CCommonMapManager { get; set; } 31 | public object LootManager { get; set; } 32 | public object TutorialSystem { get; set; } 33 | public object SoundSystem { get; set; } 34 | public object NewGamePlus { get; set; } 35 | public object WorldInfo { get; set; } 36 | public object AdditionalSaveInfo { get; set; } 37 | public object AdditionalContent { get; set; } 38 | public object ContainerManagerSaveInfo { get; set; } 39 | public object TimeScale { get; set; } 40 | public object TickManager { get; set; } 41 | public object Universe { get; set; } 42 | public object WorldState { get; set; } 43 | public object GameProp { get; set; } 44 | public object TimeManager { get; set; } 45 | public object IdTagManger { get; set; } 46 | public object EnvManger { get; set; } 47 | public object StringTable { get; set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Common/ReadSavegameProgress.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace CP77SaveEditor.Core.Common 5 | { 6 | public class ReadSavegameProgress : IReadSavegameProgress, INotifyPropertyChanged 7 | { 8 | private bool _running; 9 | private bool _indeterministic; 10 | private int _value; 11 | private int _max; 12 | 13 | public bool Running 14 | { 15 | get { return _running; } 16 | set 17 | { 18 | if (_running != value) 19 | { 20 | _running = value; 21 | OnPropertyChanged(); 22 | } 23 | } 24 | } 25 | 26 | public bool Indeterministic 27 | { 28 | get { return _indeterministic; } 29 | set 30 | { 31 | if (_indeterministic != value) 32 | { 33 | _indeterministic = value; 34 | OnPropertyChanged(); 35 | } 36 | } 37 | } 38 | 39 | public int Value 40 | { 41 | get { return _value; } 42 | set 43 | { 44 | if (_value != value) 45 | { 46 | _value = value; 47 | OnPropertyChanged(); 48 | } 49 | } 50 | } 51 | 52 | public int Max 53 | { 54 | get { return _max; } 55 | set 56 | { 57 | if (_max != value) 58 | { 59 | _max = value; 60 | OnPropertyChanged(); 61 | } 62 | } 63 | } 64 | 65 | public void Report(bool running, bool indeterministic, int value, int max) 66 | { 67 | Running = running; 68 | Indeterministic = indeterministic; 69 | Value = value; 70 | Max = max; 71 | } 72 | 73 | public event PropertyChangedEventHandler PropertyChanged; 74 | 75 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 76 | { 77 | var handler = PropertyChanged; 78 | if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers; 3 | using System.IO; 4 | 5 | namespace CP77SaveEditor.Core 6 | { 7 | internal static class ExtensionMethods 8 | { 9 | public static string ReadString(this BinaryReader reader, int count) 10 | { 11 | return new string(reader.ReadChars(count)); 12 | } 13 | 14 | public static string PeekString(this BinaryReader reader, int count) 15 | { 16 | long position = reader.BaseStream.Position; 17 | string value = new string(reader.ReadChars(count)); 18 | reader.BaseStream.Position = position; 19 | return value; 20 | } 21 | 22 | public static byte PeekByte(this BinaryReader reader) 23 | { 24 | long position = reader.BaseStream.Position; 25 | byte value = reader.ReadByte(); 26 | reader.BaseStream.Position = position; 27 | return value; 28 | } 29 | 30 | public static void Skip(this BinaryReader reader, int count) 31 | { 32 | reader.BaseStream.Position += count; 33 | } 34 | 35 | // TODO: The following two methods are copied from source. Can remove this once library is moved to target .net standard 2.1 36 | // can also remove System.Buffers package reference 37 | // https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/IO/Stream.cs#L737 38 | public static int Read(this Stream stream, Span buffer) 39 | { 40 | byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Length); 41 | try 42 | { 43 | int numRead = stream.Read(sharedBuffer, 0, buffer.Length); 44 | if ((uint)numRead > (uint)buffer.Length) 45 | { 46 | throw new IOException("Stream Too Long"); 47 | } 48 | new Span(sharedBuffer, 0, numRead).CopyTo(buffer); 49 | return numRead; 50 | } 51 | finally { ArrayPool.Shared.Return(sharedBuffer); } 52 | } 53 | 54 | // https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/IO/Stream.cs#L770 55 | public static void Write(this Stream stream, ReadOnlySpan buffer) 56 | { 57 | byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Length); 58 | try 59 | { 60 | buffer.CopyTo(sharedBuffer); 61 | stream.Write(sharedBuffer, 0, buffer.Length); 62 | } 63 | finally { ArrayPool.Shared.Return(sharedBuffer); } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using CP77SaveEditor.Core.Savegame.VariableParsers; 6 | using CP77SaveEditor.Core.Savegame.Variables; 7 | 8 | namespace CP77SaveEditor.Core.Savegame 9 | { 10 | public class VariableParser 11 | { 12 | private readonly string[] _names; 13 | private readonly Dictionary _magicNumberToParserDictionary; 14 | private readonly Dictionary _typeToParserDictionary; 15 | 16 | public VariableParser(string[] names) 17 | { 18 | _names = names; 19 | _magicNumberToParserDictionary = new Dictionary(); 20 | _typeToParserDictionary = new Dictionary(); 21 | } 22 | 23 | public void RegisterParsers(IEnumerable parsers) 24 | { 25 | foreach (var parser in parsers) 26 | { 27 | parser.Names = _names; 28 | _magicNumberToParserDictionary[parser.MagicNumber] = parser; 29 | _typeToParserDictionary[parser.SupportedType] = parser; 30 | } 31 | } 32 | 33 | public T Parse(BinaryReader reader, ref int size) where T : Variable 34 | { 35 | var parser = _typeToParserDictionary[typeof (T)]; 36 | parser.Verify(reader, ref size); 37 | return (T)parser.Parse(reader, ref size); 38 | } 39 | 40 | [DebuggerHidden] 41 | public Variable Parse(BinaryReader reader, ref int size) 42 | { 43 | if (_magicNumberToParserDictionary.TryGetValue(reader.PeekString(4), out var parser) || 44 | _magicNumberToParserDictionary.TryGetValue(reader.PeekString(2), out parser)) 45 | { 46 | parser.Verify(reader, ref size); 47 | var variable = parser.Parse(reader, ref size); 48 | return variable; 49 | } 50 | else 51 | { 52 | //string hexMagicNumber = BitConverter.ToString(Encoding.ASCII.GetBytes(magicNumber)); 53 | //Debug.WriteLine( 54 | // "Failed to parse {0} bytes of data at {1}. Magic number was {2}", 55 | // size, 56 | // reader.BaseStream.Position, 57 | // hexMagicNumber); 58 | 59 | var unknownVariable = new UnknownVariable 60 | { 61 | Name = "Unknown", 62 | Data = reader.ReadBytes(size) 63 | }; 64 | size = 0; 65 | return unknownVariable; 66 | } 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/Variables/VariableValue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace CP77SaveEditor.Core.Savegame.Variables 4 | { 5 | public abstract class VariableValue 6 | { 7 | public abstract object Object { get; } 8 | } 9 | 10 | public class VariableValue : VariableValue 11 | { 12 | public T Value { get; set; } 13 | public static VariableValue Create(T value) 14 | { 15 | return new VariableValue 16 | { 17 | Value = value 18 | }; 19 | } 20 | 21 | public override object Object 22 | { 23 | get { return Value; } 24 | } 25 | 26 | 27 | public override string ToString() 28 | { 29 | return Value.ToString(); 30 | } 31 | } 32 | 33 | public class VariableArrayValue : VariableValue 34 | { 35 | public new static VariableArrayValue Create(T[] value) 36 | { 37 | return new VariableArrayValue 38 | { 39 | Value = value 40 | }; 41 | } 42 | } 43 | 44 | public class VariableArrayValue : VariableValue 45 | { 46 | public Array Value { get; private set; } 47 | 48 | public object this[int i] 49 | { 50 | get 51 | { 52 | return Value.GetValue(i); 53 | } 54 | set 55 | { 56 | Value.SetValue(value, i); 57 | } 58 | } 59 | 60 | public int Length 61 | { 62 | get { return Value.Length; } 63 | } 64 | 65 | public override object Object 66 | { 67 | get { return Value; } 68 | } 69 | 70 | public static VariableArrayValue Create(Type type, int length) 71 | { 72 | return new VariableArrayValue 73 | { 74 | Value = Array.CreateInstance(type, length) 75 | }; 76 | } 77 | 78 | public override string ToString() 79 | { 80 | return "VariableArrayValue[" + Length + "]"; 81 | } 82 | } 83 | 84 | public class VariableHandleValue : VariableValue 85 | { 86 | public new static VariableHandleValue Create(T value) 87 | { 88 | return new VariableHandleValue 89 | { 90 | Value = value 91 | }; 92 | } 93 | } 94 | 95 | public class VariableSoftValue : VariableValue 96 | { 97 | public new static VariableSoftValue Create(T value) 98 | { 99 | return new VariableSoftValue 100 | { 101 | Value = value 102 | }; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /CP77SaveEditor/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CP77SaveEditor.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CP77SaveEditor.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /.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 | *.sln.docstates 8 | .vs 9 | 10 | # Build results 11 | [Dd]ebug/ 12 | [Dd]ebugPublic/ 13 | [Rr]elease/ 14 | [Rr]eleases/ 15 | x64/ 16 | x86/ 17 | build/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | 22 | # Roslyn cache directories 23 | *.ide/ 24 | 25 | # MSTest test Results 26 | [Tt]est[Rr]esult*/ 27 | [Bb]uild[Ll]og.* 28 | 29 | #NUNIT 30 | *.VisualState.xml 31 | TestResult.xml 32 | 33 | # Build Results of an ATL Project 34 | [Dd]ebugPS/ 35 | [Rr]eleasePS/ 36 | dlldata.c 37 | 38 | *_i.c 39 | *_p.c 40 | *_i.h 41 | *.ilk 42 | *.meta 43 | *.obj 44 | *.pch 45 | *.pdb 46 | *.pgc 47 | *.pgd 48 | *.rsp 49 | *.sbr 50 | *.tlb 51 | *.tli 52 | *.tlh 53 | *.tmp 54 | *.tmp_proj 55 | *.log 56 | *.vspscc 57 | *.vssscc 58 | .builds 59 | *.pidb 60 | *.svclog 61 | *.scc 62 | 63 | # Chutzpah Test files 64 | _Chutzpah* 65 | 66 | # Visual C++ cache files 67 | ipch/ 68 | *.aps 69 | *.ncb 70 | *.opensdf 71 | *.sdf 72 | *.cachefile 73 | 74 | # Visual Studio profiler 75 | *.psess 76 | *.vsp 77 | *.vspx 78 | 79 | # TFS 2012 Local Workspace 80 | $tf/ 81 | 82 | # Guidance Automation Toolkit 83 | *.gpState 84 | 85 | # ReSharper is a .NET coding add-in 86 | _ReSharper*/ 87 | *.[Rr]e[Ss]harper 88 | *.DotSettings.user 89 | 90 | # Idea is the platform on which Rider runs 91 | .idea 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # If using the old MSBuild-Integrated Package Restore, uncomment this: 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | sql/ 155 | *.Cache 156 | ClientBin/ 157 | [Ss]tyle[Cc]op.* 158 | ~$* 159 | *~ 160 | *.dbmdl 161 | *.dbproj.schemaview 162 | *.pfx 163 | *.publishsettings 164 | node_modules/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ -------------------------------------------------------------------------------- /CP77SaveEditor/ViewModels/SavegameViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.ObjectModel; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.CompilerServices; 7 | using System.Windows.Input; 8 | using CP77SaveEditor.Core.Common; 9 | using CP77SaveEditor.Core.Savegame; 10 | using CP77SaveEditor.Core.Savegame.Variables; 11 | using CP77SaveEditor.Models; 12 | 13 | namespace CP77SaveEditor.ViewModels 14 | { 15 | public class SavegameViewModel : INotifyPropertyChanged 16 | { 17 | private SavegameModel _selectedSavegame; 18 | 19 | public ObservableCollection Savegames { get; set; } 20 | 21 | public SavegameModel SelectedSavegame 22 | { 23 | get 24 | { 25 | return _selectedSavegame; 26 | } 27 | set 28 | { 29 | if (_selectedSavegame != value) 30 | { 31 | _selectedSavegame = value; 32 | OnPropertyChanged(); 33 | } 34 | } 35 | } 36 | 37 | public ReadSavegameProgress Progress { get; set; } 38 | 39 | public ICommand InitializeSavegames { get; private set; } 40 | 41 | public ICommand OpenSavegame { get; private set; } 42 | 43 | public SavegameViewModel() 44 | { 45 | InitializeSavegames = new DelegateCommand(ExecuteInitializeSavegameList); 46 | OpenSavegame = new DelegateCommand(ExecuteOpenSavegame); 47 | Savegames = new ObservableCollection(); 48 | Progress = new ReadSavegameProgress(); 49 | ExecuteInitializeSavegameList(null); 50 | } 51 | 52 | public event PropertyChangedEventHandler PropertyChanged; 53 | 54 | protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 55 | { 56 | var handler = PropertyChanged; 57 | if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 58 | } 59 | 60 | private void ExecuteInitializeSavegameList(object obj) 61 | { 62 | Savegames.Clear(); 63 | string gamesavesPath = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "Saved Games\\CD Projekt Red\\Cyberpunk 2077"); 64 | var filesPaths = Directory.GetDirectories(gamesavesPath, "*", SearchOption.TopDirectoryOnly); 65 | 66 | foreach (var filePath in filesPaths) 67 | { 68 | var thumbnailFilePath = Path.Combine(filePath, "screenshot.png"); 69 | var model = new SavegameModel 70 | { 71 | Name = Path.GetFileName(filePath), 72 | Path = Path.Combine(filePath, "sav.dat"), 73 | ThumbnailPath = thumbnailFilePath 74 | }; 75 | Savegames.Add(model); 76 | } 77 | } 78 | 79 | private void ExecuteOpenSavegame(object parameter) 80 | { 81 | if (parameter == null) 82 | { 83 | return; 84 | } 85 | 86 | var savegame = parameter as SavegameModel; 87 | if (savegame == null) 88 | { 89 | throw new ArgumentException("parameter"); 90 | } 91 | 92 | SavegameFile.ReadAsync(savegame.Path, savegame.Name, Progress) 93 | .ContinueWith(t => 94 | { 95 | var file = t.Result; 96 | var savegameDataModel = new SavegameDataModel 97 | { 98 | Version1 = file.TypeCode1, 99 | Version2 = file.TypeCode2, 100 | Version3 = file.TypeCode3, 101 | VariableNames = new ObservableCollection(file.VariableNames), 102 | Variables = new ObservableCollection(file.Variables.Select(ToVariableModel)) 103 | }; 104 | SelectedSavegame = new SavegameModel 105 | { 106 | Name = savegame.Name, 107 | Path = savegame.Path, 108 | Data = savegameDataModel 109 | }; 110 | }); 111 | } 112 | 113 | 114 | private static VariableModel ToVariableModel(Variable v, int i) 115 | { 116 | var set = v as VariableSet; 117 | var children = set == null 118 | ? new ObservableCollection() 119 | : new ObservableCollection(set.Variables.Select(ToVariableModel)); 120 | 121 | var typed = v as TypedVariable; 122 | var type = typed == null 123 | ? "None" 124 | : typed.Type; 125 | 126 | var value = typed == null || typed.Value == null 127 | ? "" 128 | : typed.Value.ToString(); 129 | 130 | return new VariableModel 131 | { 132 | Index = i, 133 | Name = v == null ? "" : v.Name, 134 | Type = type, 135 | Value = value, 136 | DebugString = v == null ? "" : v.ToString(), 137 | Children = children 138 | }; 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /CP77SaveEditor/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /CP77SaveEditor/CP77SaveEditor.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {92054529-EA59-4CD9-9C24-019D8B5A0867} 8 | WinExe 9 | Properties 10 | CP77SaveEditor 11 | CP77SaveEditor 12 | v4.7.1 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | 19 | PackageReference 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 4.0 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | MSBuild:Compile 58 | Designer 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | MSBuild:Compile 67 | Designer 68 | 69 | 70 | App.xaml 71 | Code 72 | 73 | 74 | MainWindow.xaml 75 | Code 76 | 77 | 78 | 79 | 80 | Code 81 | 82 | 83 | True 84 | True 85 | Resources.resx 86 | 87 | 88 | True 89 | Settings.settings 90 | True 91 | 92 | 93 | ResXFileCodeGenerator 94 | Resources.Designer.cs 95 | 96 | 97 | SettingsSingleFileGenerator 98 | Settings.Designer.cs 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | {9c026da7-481d-43c6-8c18-635d69fdb423} 111 | CP77SaveEditor.Core 112 | 113 | 114 | 115 | 116 | 3.3.1 117 | 118 | 119 | 1.6.5 120 | 121 | 122 | 123 | 124 | 125 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 126 | 127 | 128 | 135 | -------------------------------------------------------------------------------- /CP77SaveEditor/FodyWeavers.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks 13 | 14 | 15 | 16 | 17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks. 18 | 19 | 20 | 21 | 22 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks. 23 | 24 | 25 | 26 | 27 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks. 28 | 29 | 30 | 31 | 32 | The order of preloaded assemblies, delimited with line breaks. 33 | 34 | 35 | 36 | 37 | 38 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file. 39 | 40 | 41 | 42 | 43 | Controls if .pdbs for reference assemblies are also embedded. 44 | 45 | 46 | 47 | 48 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option. 49 | 50 | 51 | 52 | 53 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off. 54 | 55 | 56 | 57 | 58 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code. 59 | 60 | 61 | 62 | 63 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior. 64 | 65 | 66 | 67 | 68 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with | 69 | 70 | 71 | 72 | 73 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |. 74 | 75 | 76 | 77 | 78 | A list of unmanaged 32 bit assembly names to include, delimited with |. 79 | 80 | 81 | 82 | 83 | A list of unmanaged 64 bit assembly names to include, delimited with |. 84 | 85 | 86 | 87 | 88 | The order of preloaded assemblies, delimited with |. 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. 97 | 98 | 99 | 100 | 101 | A comma-separated list of error codes that can be safely ignored in assembly verification. 102 | 103 | 104 | 105 | 106 | 'false' to turn off automatic generation of the XML Schema file. 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /CP77SaveEditor.Core/Savegame/VariableValueParser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using CP77SaveEditor.Core.Savegame.Attributes; 6 | using CP77SaveEditor.Core.Savegame.Variables; 7 | 8 | namespace CP77SaveEditor.Core.Savegame 9 | { 10 | public class VariableValueParser 11 | { 12 | private class VariablePropertyInfo 13 | { 14 | public string CName { get; set; } 15 | public string CType { get; set; } 16 | 17 | public bool IsArray { get; set; } 18 | public string ArrayCountName { get; set; } 19 | public string ArrayElementName { get; set; } 20 | public string ArrayElementCType { get; set; } 21 | public Type ArrayElementType { get; set; } 22 | 23 | public PropertyInfo Info { get; set; } 24 | } 25 | 26 | private readonly Dictionary, object>> _factories; 27 | 28 | public VariableValueParser() 29 | { 30 | _factories = new Dictionary, object>>(); 31 | 32 | foreach (var serializableType in GetSerializableTypes()) 33 | { 34 | var type = serializableType; 35 | Func, object> deserializationFunction = v => Deserialize(type.Key, type.Value, v); 36 | _factories.Add(serializableType.Key, deserializationFunction); 37 | } 38 | } 39 | 40 | private static void SkipName(Stack variables, string name) 41 | { 42 | var variable = variables.Peek() as BsVariable; 43 | if (variable != null && variable.Name == name) 44 | { 45 | variables.Pop(); 46 | } 47 | } 48 | 49 | private object Deserialize(string typeName, Type type, Stack variables) 50 | { 51 | var instance = Activator.CreateInstance(type); 52 | SkipName(variables, typeName); 53 | 54 | foreach (var serializableProperty in GetNamedOrArrayProperties(type)) 55 | { 56 | object propertyValue = null; 57 | if (serializableProperty.CType != null) 58 | { 59 | SkipName(variables, serializableProperty.CName); 60 | 61 | propertyValue = _factories[serializableProperty.CType](variables); 62 | } 63 | else 64 | { 65 | var typedVariable = variables.Peek() as TypedVariable; 66 | if(typedVariable == null) 67 | { 68 | continue; 69 | } 70 | 71 | if (serializableProperty.IsArray && typedVariable.Name == serializableProperty.ArrayCountName) 72 | { 73 | variables.Pop(); 74 | uint count = (uint) typedVariable.Value.Object; 75 | var array = Array.CreateInstance(serializableProperty.ArrayElementType, count); 76 | for (int i = 0; i < count; i++) 77 | { 78 | object element; 79 | if (serializableProperty.ArrayElementCType == null) 80 | { 81 | // TODO: Check the element type name (e.g. CGUID) 82 | element = ((TypedVariable) variables.Pop()).Value.Object; 83 | } 84 | else 85 | { 86 | SkipName(variables, serializableProperty.ArrayElementName); 87 | element = Deserialize(serializableProperty.ArrayElementCType, serializableProperty.ArrayElementType, variables); 88 | } 89 | 90 | array.SetValue(element, i); 91 | } 92 | propertyValue = array; 93 | } 94 | else if (typedVariable.Name == serializableProperty.CName) 95 | { 96 | variables.Pop(); 97 | propertyValue = typedVariable.Value.Object; 98 | } 99 | } 100 | 101 | serializableProperty.Info.SetValue(instance, propertyValue); 102 | } 103 | return instance; 104 | } 105 | 106 | public object Parse(string type, Stack variables) 107 | { 108 | return _factories[type](variables); 109 | } 110 | 111 | public T Parse(Stack variables) 112 | { 113 | return (T)Deserialize(null, typeof (T), variables); 114 | } 115 | 116 | private static IEnumerable GetNamedOrArrayProperties(Type serializableType) 117 | { 118 | // TODO: Add an order attribute 119 | foreach (var property in serializableType.GetProperties()) 120 | { 121 | var cNameAttribute = property.GetCustomAttributes(typeof(CNameAttribute), true).SingleOrDefault() as CNameAttribute; 122 | var cArrayAttribute = property.GetCustomAttributes(typeof(CArrayAttribute), true).SingleOrDefault() as CArrayAttribute; 123 | var cArrayElementType = cArrayAttribute != null ? GetCSerializableAttribute(property.PropertyType.GetElementType()) : null; 124 | var cSerializableAttribute = GetCSerializableAttribute(property.PropertyType); 125 | if (cNameAttribute != null || cArrayAttribute != null) 126 | { 127 | yield return new VariablePropertyInfo 128 | { 129 | CName = cNameAttribute != null ? cNameAttribute.Name : null, 130 | CType = cSerializableAttribute != null ? cSerializableAttribute.TypeName : null, 131 | IsArray = cArrayAttribute != null, 132 | ArrayCountName = cArrayAttribute != null ? cArrayAttribute.CountName : null, 133 | ArrayElementName = cArrayAttribute != null ? cArrayAttribute.ElementName : null, 134 | ArrayElementType = cArrayAttribute != null ? property.PropertyType.GetElementType() : null, 135 | ArrayElementCType = cArrayElementType != null ? cArrayElementType.TypeName : null, 136 | Info = property 137 | }; 138 | } 139 | } 140 | } 141 | 142 | private static IEnumerable> GetSerializableTypes() 143 | { 144 | foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) 145 | { 146 | var cSerializableAttribute = GetCSerializableAttribute(type); 147 | if (cSerializableAttribute != null) 148 | { 149 | yield return new KeyValuePair(cSerializableAttribute.TypeName, type); 150 | } 151 | } 152 | } 153 | 154 | private static CSerializableAttribute GetCSerializableAttribute(Type type) 155 | { 156 | return type.GetCustomAttributes(typeof(CSerializableAttribute), true).SingleOrDefault() as CSerializableAttribute; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /CP77SaveEditor/MainWindow.xaml: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |