public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var schematicManager = rootItem.FindChild("Persistent_Level:PersistentLevel.schematicManager", false); if (schematicManager == null) { MissingTagMsg("schematicManager"); return(false); } var available = schematicManager.FindField <ArrayPropertyViewModel>("mAvailableSchematics"); var found = new HashSet <string>(); var removed = 0; foreach (var obj in available.Elements.Cast <ObjectPropertyViewModel>().ToList()) { if (found.Contains(obj.Str2)) { available.RemoveElementCommand.Execute(obj); removed++; } else { found.Add(obj.Str2); } } MessageBox.Show($"Removed {removed} duplicate schematics.", "Success", MessageBoxButton.OK, MessageBoxImage.Information); return(true); }
private static int GetNextDoggoID(int currentId, SaveObjectModel rootItem) { while (rootItem.FindChild($"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentId}", false) != null) { currentId++; } return(currentId); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { int doggocount = 1; var dialog = new StringPromptWindow { Owner = Application.Current.MainWindow }; var cvm = (StringPromptViewModel)dialog.DataContext; cvm.WindowTitle = "Enter doggo count"; cvm.PromptMessage = "Count (integer):"; cvm.ValueChosen = "1"; cvm.OldValueMessage = ""; dialog.ShowDialog(); try { doggocount = int.Parse(cvm.ValueChosen); //MessageBox.Show("" + doggocount); if (doggocount > 0) { int counter; bool pastSuccess = true; //don't keep running the loop if one run fails for (counter = 0; counter < doggocount && pastSuccess; counter++) { pastSuccess = deleteEnemiesCheat.AddDoggo(rootItem, saveGame); } if (pastSuccess) { MessageBox.Show("Spawned " + counter + " doggo(s) at the host player."); return(true); } else { //failed to spawn some doggos for some reason return(false); } } else { MessageBox.Show("You can't spawn " + doggocount + " doggos."); return(false); } } catch (Exception) { if (!(cvm.ValueChosen == "cancel")) { MessageBox.Show("Could not parse: " + cvm.ValueChosen); } return(false); } }
private static SaveObjectModel FindOrCreatePath(SaveObjectModel start, string[] path, int index = 0) { if (index == path.Length) { return(start); } if (start.FindChild(path[index], false) == null) { start.Items.Add(new SaveObjectModel(path[index])); } return(FindOrCreatePath(start.FindChild(path[index], false), path, index + 1)); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var animalSpawners = rootItem.FindChild("BP_CreatureSpawner.BP_CreatureSpawner_C", false); if (animalSpawners == null) { MessageBox.Show("This save does not contain animals or it is corrupt.", "Cannot find animals", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } float offset = -50000; var hostPlayerModel = rootItem.FindChild("Char_Player.Char_Player_C", false); if (hostPlayerModel == null || hostPlayerModel.Items.Count < 1) { MessageBox.Show("This save does not contain a host player or it is corrupt.", "Cannot find host player", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } Vector3 playerPosition = ((SaveEntityModel)hostPlayerModel.Items[0]).Position; foreach (SaveObjectModel animalSpawner in animalSpawners.DescendantSelfViewModel) { // Some crab hatchers are marked as CreatureSpawner instead of EnemySpawner and there is no other trace of the difference between enemy and friendly in the savefile //if (animalSpawner.Title.ToLower().Contains("enemy")) //{ ((SaveEntityModel)animalSpawner).Position.Z += offset; // Move the spawn under the map animalSpawner.FindField("mSpawnData", (ArrayPropertyViewModel arrayProperty) => { foreach (StructPropertyViewModel elem in arrayProperty.Elements) { ((Vector)((StructProperty)((DynamicStructDataViewModel)elem.StructData).Fields[0].Model).Data).Data.Z += offset; // Move the spawn point under the map // Set WasKilled to true so they don't respawn after deleting them ((BoolPropertyViewModel)((DynamicStructDataViewModel)elem.StructData).Fields[2]).Value = true; // Set KilledOnDayNumber to a huge number (some far away animals respawn if the number is too small) ((IntPropertyViewModel)((DynamicStructDataViewModel)elem.StructData).Fields[3]).Value = (int)(Distance(playerPosition, ((Vector)((StructProperty)((DynamicStructDataViewModel)elem.StructData).Fields[0].Model).Data).Data) / 10000); } }); } // Delete the already spawned enemies var enemies = rootItem.FindChild("Creature", false).FindChild("Enemy", false); rootItem.Remove(enemies); if (MessageBox.Show($"Deleted all spawned enemies, and all unspawned creatures (enemy & friendly). Would you like 3 tamed Lizzard Doggos as a compensation?", "Success", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { for (int i = 0; i < 3; i++) { AddDoggo(rootItem, saveGame); } } return(true); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave save) { var animalSpawners = rootItem.FindChild("BP_CreatureSpawner.BP_CreatureSpawner_C", false); if (animalSpawners == null) { MessageBox.Show("This save does not contain animals or it is corrupt.", "Cannot find animals", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } float offset = -50000; var hostPlayerModel = rootItem.FindChild("Char_Player.Char_Player_C", false); if (hostPlayerModel == null || hostPlayerModel.Items.Count < 1) { MessageBox.Show("This save does not contain a host player or it is corrupt.", "Cannot find host player", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } Vector3 playerPosition = ((SaveEntityModel)hostPlayerModel.Items[0]).Position; foreach (SaveObjectModel animalSpawner in animalSpawners.DescendantSelfViewModel) { var probablyEdited = ((SaveEntityModel)animalSpawner).Position.Z < -14200f; // Some crab hatchers are marked as CreatureSpawner instead of EnemySpawner and there is no other trace of the difference between enemy and friendly in the savefile //if (animalSpawner.Title.ToLower().Contains("enemy")) //{ if (probablyEdited) { ((SaveEntityModel)animalSpawner).Position.Z -= offset; // Move the spawn under the map } animalSpawner.FindField("mSpawnData", (ArrayPropertyViewModel arrayProperty) => { foreach (StructPropertyViewModel elem in arrayProperty.Elements) { if (probablyEdited) { ((Vector)((StructProperty)((DynamicStructDataViewModel)elem.StructData).Fields[0].Model).Data).Data.Z -= offset; // Move the spawn point under the map } // Set WasKilled to true so they don't respawn after deleting them ((BoolPropertyViewModel)((DynamicStructDataViewModel)elem.StructData).Fields[2]).Value = false; // Set KilledOnDayNumber to a huge number (some far away animals respawn if the number is too small) ((IntPropertyViewModel)((DynamicStructDataViewModel)elem.StructData).Fields[3]).Value = (int)0; } }); } return(true); }
public bool Apply(SaveObjectModel rootItem) { var players = rootItem.FindChild("Char_Player.Char_Player_C", false); if (players == null) { MessageBox.Show("This save does not contain a Player.\nThis means that the loaded save is probably corrupt. Aborting.", "Cannot find Player", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } int currentStorageID = 0; foreach (SaveObjectModel player in players.DescendantSelfViewModel) { string inventoryPath = player.FindField <ObjectPropertyViewModel>("mInventory").Str2; SaveObjectModel inventoryState = rootItem.FindChild(inventoryPath, false); SaveComponent inventoryComponent = (SaveComponent)inventoryState.Model; currentStorageID = GetNextStorageID(currentStorageID, rootItem); SaveComponent newInventory = new SaveComponent(inventoryComponent.TypePath, inventoryComponent.RootObject, $"Persistent_Level:PersistentLevel.BP_Crate_C_{currentStorageID}.inventory") { ParentEntityName = $"Persistent_Level:PersistentLevel.BP_Crate_C_{currentStorageID}", DataFields = inventoryComponent.DataFields }; rootItem.FindChild("FactoryGame.FGInventoryComponent", false).Items.Add(new SaveComponentModel(newInventory)); SaveEntity newSaveObject = new SaveEntity("/Game/FactoryGame/-Shared/Crate/BP_Crate.BP_Crate_C", "Persistent_Level", $"Persistent_Level:PersistentLevel.BP_Crate_C_{currentStorageID}") { NeedTransform = true, Rotation = ((SaveEntity)player.Model).Rotation, Position = ((SaveEntity)player.Model).Position, Scale = new SatisfactorySaveParser.Structures.Vector3() { X = 1, Y = 1, Z = 1 }, WasPlacedInLevel = false, ParentObjectName = "", ParentObjectRoot = "" }; newSaveObject.DataFields = new SerializedFields(); newSaveObject.DataFields.Add(new ObjectProperty("mInventory", 0) { LevelName = "Persistent_Level", PathName = $"Persistent_Level:PersistentLevel.BP_Crate_C_{currentStorageID}.inventory" }); rootItem.FindChild("BP_Crate.BP_Crate_C", false).Items.Add(new SaveEntityModel(newSaveObject)); rootItem.Remove(player); rootItem.Remove(inventoryState); MessageBox.Show($"Killed {player.Title}.", "Success", MessageBoxButton.OK, MessageBoxImage.Information); } return(true); }
public bool Apply(SaveObjectModel rootItem) { var gameState = rootItem.FindChild("Persistent_Level:PersistentLevel.BP_GameState_C_0", false); if (gameState == null) { MessageBox.Show("This save does not contain a GameState.\nThis means that the loaded save is probably corrupt. Aborting.", "Cannot find GameState", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var isMapUnlocked = gameState.FindOrCreateField <BoolPropertyViewModel>("mIsMapUnlocked"); isMapUnlocked.Value = true; MessageBox.Show("Map unlocked", "Success", MessageBoxButton.OK, MessageBoxImage.Information); return(true); }
public bool Apply(SaveObjectModel rootItem) { var gameState = rootItem.FindChild("Persistent_Level:PersistentLevel.BP_GameState_C_0", false); if (gameState == null) { MessageBox.Show("This save does not contain a GameState.\nThis means that the loaded save is probably corrupt. Aborting.", "Cannot find GameState", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var numAdditionalSlots = gameState.FindOrCreateField <BoolPropertyViewModel>("mCheatNoCost"); numAdditionalSlots.Value = !numAdditionalSlots.Value; MessageBox.Show($"{(numAdditionalSlots.Value ? "Enabled" : "Disabled")} no cost cheat", "Success", MessageBoxButton.OK, MessageBoxImage.Information); return(true); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var slugTypes = new[] { "/Game/FactoryGame/Resource/Environment/Crystal/BP_Crystal.BP_Crystal_C", "/Game/FactoryGame/Resource/Environment/Crystal/BP_Crystal_mk2.BP_Crystal_mk2_C", "/Game/FactoryGame/Resource/Environment/Crystal/BP_Crystal_mk3.BP_Crystal_mk3_C" }; var slugs = saveGame.Entries.Where(x => slugTypes.Contains(x.TypePath)); saveGame.CollectedObjects.RemoveAll(x => x.PathName.Contains("PersistentLevel.BP_Crystal")); saveGame.CollectedObjects.AddRange(slugs.Select(s => new ObjectReference { LevelName = s.RootObject, PathName = s.InstanceName })); return(true); }
public bool Apply(SaveObjectModel rootItem) { var animalSpawners = rootItem.FindChild("BP_CreatureSpawner.BP_CreatureSpawner_C", false); if (animalSpawners == null) { MessageBox.Show("This save does not contain animals or it is corrupt.", "Cannot find animals", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } foreach (SaveObjectModel animalSpawner in animalSpawners.DescendantSelfViewModel) { // Some crab hatchers are marked as CreatureSpawner instead of EnemySpawner and there is no other trace of the difference between enemy and friendly in the savefile //if (animalSpawner.Title.ToLower().Contains("enemy")) //{ animalSpawner.FindField("mSpawnData", (ArrayPropertyViewModel arrayProperty) => { foreach (StructPropertyViewModel elem in arrayProperty.Elements) { // Set WasKilled to true so they don't respawn after deleting them ((BoolPropertyViewModel)((DynamicStructDataViewModel)elem.StructData).Fields[2]).Value = true; // Set KilledOnDayNumber to a huge number (some far away animals respawn if the number is too small) ((IntPropertyViewModel)((DynamicStructDataViewModel)elem.StructData).Fields[3]).Value = 1000000000; } }); //} } // Delete the already spawned enemies var enemies = rootItem.FindChild("Creature", false).FindChild("Enemy", false); rootItem.Remove(enemies); if (MessageBox.Show($"Deleted all spawned enemies, and all unspawned creatures (enemy & friendly). Would you like 3 tamed Lizzard Doggos as a compensation?", "Success", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { for (int i = 0; i < 3; i++) { AddDoggo(rootItem); } } return(true); }
public bool Apply(SaveObjectModel rootItem) { var cratesList = rootItem.FindChild("BP_Crate.BP_Crate_C", false); if (cratesList == null) { MessageBox.Show("This save does not appear to have any crates.\nCrates appear on death and when your inventory is too full to hold items during deconstruction.", "Cannot find any Crates", MessageBoxButton.OK, MessageBoxImage.Information); return(false); } var hostPlayerModel = rootItem.FindChild("Char_Player.Char_Player_C", false); if (hostPlayerModel == null || hostPlayerModel.Items.Count < 1) { MessageBox.Show("This save does not contain a host player or it is corrupt.\nTry loading and re-saving the save from within the game.", "Cannot find host player", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var playerEntityModel = (SaveEntityModel)hostPlayerModel.Items[0]; int crateSpacingOffset = 80; int stackHeight = 5; float playerX = playerEntityModel.Position.X + (1.5f * crateSpacingOffset); float playerY = playerEntityModel.Position.Y; float playerZ = playerEntityModel.Position.Z - crateSpacingOffset; int counter = 0; foreach (SaveObjectModel thisCrate in cratesList.DescendantSelfViewModel) { //MessageBox.Show($"Modifying crate {counter}: {thisCrate.ToString()}"); ((SaveEntityModel)thisCrate).Position.X = playerX + ((counter / stackHeight) * crateSpacingOffset);//((counter % stackHeight == 0) ? crateHeightSpacingOffset * counter / stackHeight : 0); ((SaveEntityModel)thisCrate).Position.Y = playerY; ((SaveEntityModel)thisCrate).Position.Z = playerZ + (crateSpacingOffset * (counter % stackHeight)); counter++; } MessageBox.Show($"Successfully moved {counter} crates to the host player. They are stacked in piles of 5 slightly east of you."); return(true); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var tutorialManager = rootItem.FindChild("Persistent_Level:PersistentLevel.TutorialIntroManager", false); if (tutorialManager == null) { MissingTagMsg("TutorialIntroManager"); return(false); } var schematicManager = rootItem.FindChild("Persistent_Level:PersistentLevel.schematicManager", false); if (schematicManager == null) { MissingTagMsg("schematicManager"); return(false); } var gameState = rootItem.FindChild("Persistent_Level:PersistentLevel.BP_GameState_C_*", false); if (gameState == null) { MissingTagMsg("GameState"); return(false); } var gamePhaseManager = rootItem.FindChild("Persistent_Level:PersistentLevel.GamePhaseManager", false); if (gamePhaseManager == null) { MissingTagMsg("GamePhaseManager"); return(false); } var unlockSystem = rootItem.FindChild("Persistent_Level:PersistentLevel.UnlockSubsystem", false); if (unlockSystem == null) { MissingTagMsg("UnlockSubsystem"); return(false); } var tradingPostBuilt = tutorialManager.FindField <BoolPropertyViewModel>("mTradingPostBuilt"); if (tradingPostBuilt == null) { MessageBox.Show("You should build a hub before attempting to unlock all research.", "No hub found", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var availableSchematics = schematicManager.FindField <ArrayPropertyViewModel>("mAvailableSchematics"); var purchasedSchematics = schematicManager.FindField <ArrayPropertyViewModel>("mPurchasedSchematics"); var researches = Research.GetResearches().Select(r => r.Path); var purchasedList = purchasedSchematics.Elements.Cast <ObjectPropertyViewModel>().Select(o => o.Str2); var availableList = researches.Union(availableSchematics.Elements.Cast <ObjectPropertyViewModel>().Select(o => o.Str2)).Except(purchasedList); var window = new UnlockResearchWindow() { Owner = Application.Current.MainWindow }; var vm = (UnlockResearchWindowViewModel)window.DataContext; vm.Available = new ObservableCollection <string>(availableList); vm.Unlocked = new ObservableCollection <string>(purchasedList); if (!window.ShowDialog().Value) { return(false); } purchasedSchematics.Elements.Clear(); foreach (var item in vm.Unlocked) { purchasedSchematics.Elements.Add(new ObjectPropertyViewModel(new ObjectProperty(null, "", item))); //if (!availableList.Any(x => x == item)) //{ // availableSchematics.Elements.Add(new ObjectPropertyViewModel(new ObjectProperty(null, "", item))); //} } //clear PaidOffSchematic and ActiveSchematic fields so the progress indicator in the top right doesn't linger after unlocking var paidOffSchematicField = schematicManager.FindField <ArrayPropertyViewModel>("mPaidOffSchematic"); var activeSchematicField = schematicManager.FindField <ObjectPropertyViewModel>("mActiveSchematic"); schematicManager.RemovePropertyCommand.Execute(paidOffSchematicField); schematicManager.RemovePropertyCommand.Execute(activeSchematicField); tutorialManager.FindOrCreateField <EnumPropertyViewModel>("mPendingTutorial", f => f.Value = "EIntroTutorialSteps::ITS_DONE"); tutorialManager.FindOrCreateField <IntPropertyViewModel>("mTradingPostLevel", f => f.Value = 6); CreateOrSetBoolField(tutorialManager, "mHasCompletedIntroTutorial", true); CreateOrSetBoolField(tutorialManager, "mHasCompletedIntroSequence", true); CreateOrSetBoolField(tutorialManager, "mDidStep1Upgrade", true); CreateOrSetBoolField(tutorialManager, "mDidStep1_5Upgrade", true); CreateOrSetBoolField(tutorialManager, "mDidStep2Upgrade", true); CreateOrSetBoolField(tutorialManager, "mDidStep3Upgrade", true); CreateOrSetBoolField(tutorialManager, "mDidStep4Upgrade", true); CreateOrSetBoolField(tutorialManager, "mDidStep5Upgrade", true); CreateOrSetBoolField(tutorialManager, "mDidPickUpIronOre", true); CreateOrSetBoolField(tutorialManager, "mDidDismantleDropPod", true); CreateOrSetBoolField(tutorialManager, "mDidEquipStunSpear", true); CreateOrSetBoolField(tutorialManager, "mDidOpenCodex", true); // TODO: Set GameState->mScannableResources CreateOrSetBoolField(unlockSystem, "mIsMapUnlocked", true); CreateOrSetBoolField(unlockSystem, "mIsBuildingEfficiencyUnlocked", true); CreateOrSetBoolField(unlockSystem, "mIsBuildingOverclockUnlocked", true); gamePhaseManager.FindOrCreateField <BytePropertyViewModel>("mGamePhase", f => { f.Value = "EGP_EndGame"; f.Type = "EGamePhase"; }); MessageBox.Show("Research successfully unlocked.", "Success", MessageBoxButton.OK, MessageBoxImage.Information); return(true); }
public bool AddDoggo(SaveObjectModel rootItem, SatisfactorySave saveGame) { currentDoggoID = GetNextDoggoID(currentDoggoID, rootItem); var hostPlayerModel = rootItem.FindChild("Char_Player.Char_Player_C", false); if (hostPlayerModel == null || hostPlayerModel.Items.Count < 1) { MessageBox.Show("This save does not contain a host player or it is corrupt.", "Cannot find host player", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var player = (SaveEntityModel)hostPlayerModel.Items[0]; SaveComponent healthComponent = new SaveComponent("/Script/FactoryGame.FGHealthComponent", "Persistent_Level", $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}.HealthComponent") { DataFields = new SerializedFields(), ParentEntityName = $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}" }; byte[] bytes = PrepareForParse("", 0); SaveComponent inventoryComponent; using (BinaryReader reader = new BinaryReader(new MemoryStream(bytes))) { inventoryComponent = new SaveComponent("/Script/FactoryGame.FGInventoryComponent", "Persistent_Level", $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}.mInventory") { DataFields = new SerializedFields() { new ArrayProperty("mInventoryStacks") { Type = StructProperty.TypeName, Elements = new System.Collections.Generic.List <SerializedProperty>() { SerializedProperty.Parse(reader, saveGame.Header.BuildVersion) } }, new ArrayProperty("mArbitrarySlotSizes") { Type = IntProperty.TypeName, Elements = new System.Collections.Generic.List <SerializedProperty>() { new IntProperty("Element") { Value = 0 } } }, new ArrayProperty("mAllowedItemDescriptors") { Type = ObjectProperty.TypeName, Elements = new System.Collections.Generic.List <SerializedProperty>() { new ObjectProperty("Element") { LevelName = "", PathName = "" } } } }, ParentEntityName = $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}" }; } SaveEntity doggo = new SaveEntity("/Game/FactoryGame/Character/Creature/Wildlife/SpaceRabbit/Char_SpaceRabbit.Char_SpaceRabbit_C", "Persistent_Level", $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}") { NeedTransform = true, Rotation = ((SaveEntity)player.Model).Rotation, Position = new Vector3() { X = ((SaveEntity)player.Model).Position.X, Y = ((SaveEntity)player.Model).Position.Y + 100 + 10 * currentDoggoID, // so they don't glitch one into another like the tractors did Z = ((SaveEntity)player.Model).Position.Z + 10 }, Scale = new Vector3() { X = 1, Y = 1, Z = 1 }, WasPlacedInLevel = false, ParentObjectName = "", ParentObjectRoot = "" }; doggo.Components = new System.Collections.Generic.List <SatisfactorySaveParser.Structures.ObjectReference>() { new SatisfactorySaveParser.Structures.ObjectReference() { LevelName = "Persistent_Level", PathName = $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}.mInventory" }, new SatisfactorySaveParser.Structures.ObjectReference() { LevelName = "Persistent_Level", PathName = $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}.HealthComponent" } }; byte[] emptyDynamicStructData = { 0x05, 0x00, 0x00, 0x00, 0x4e, 0x6f, 0x6e, 0x65 }; // Length prefixed "None" using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(emptyDynamicStructData))) { doggo.DataFields = new SerializedFields() { new ObjectProperty("mFriendActor") { LevelName = "Persistent_Level", PathName = player.Title }, new IntProperty("mLootTableIndex") { Value = 0 }, new StructProperty("mLootTimerHandle") { Data = new DynamicStructData(binaryReader, "TimerHandle", saveGame.Header.BuildVersion), Unk1 = 0, Unk2 = 0, Unk3 = 0, Unk4 = 0, Unk5 = 0 }, new BoolProperty("mIsPersistent") { Value = true }, new ObjectProperty("mHealthComponent") { LevelName = "Persistent_Level", PathName = $"Persistent_Level:PersistentLevel.Char_SpaceRabbit_C_{currentDoggoID}.HealthComponent" } }; } FindOrCreatePath(rootItem, new string[] { "Character", "Creature", "Wildlife", "SpaceRabbit", "Char_SpaceRabbit.Char_SpaceRabbit_C" }).Items.Add(new SaveEntityModel(doggo)); rootItem.FindChild("FactoryGame.FGInventoryComponent", false).Items.Add(new SaveComponentModel(inventoryComponent)); rootItem.FindChild("FactoryGame.FGHealthComponent", false).Items.Add(new SaveComponentModel(healthComponent)); return(true); }
private int MassDismantle(List <SaveObjectModel> objects, ArrayProperty inventory, SaveObjectModel rootItem) { int count = 0; foreach (SaveObjectModel item in objects) { if (item is SaveEntityModel) { if (IsPointInPolygon(((SaveEntityModel)item).Position, polygon) && minZ <= ((SaveEntityModel)item).Position.Z && ((SaveEntityModel)item).Position.Z <= maxZ) { ArrayPropertyViewModel dismantleRefund = ((SaveEntityModel)item).FindField <ArrayPropertyViewModel>("mDismantleRefund"); if (dismantleRefund != null) { foreach (SerializedPropertyViewModel property in dismantleRefund.Elements) { DynamicStructData itemAmountStruct = (DynamicStructData)((StructProperty)property.Model).Data; string itemPath = ((ObjectProperty)itemAmountStruct.Fields[0]).PathName; int itemAmount = ((IntProperty)itemAmountStruct.Fields[1]).Value; byte[] bytes = PrepareForParse(itemPath, itemAmount); using (MemoryStream ms = new MemoryStream(bytes)) using (BinaryReader reader = new BinaryReader(ms)) { SerializedProperty prop = SerializedProperty.Parse(reader); inventory.Elements.Add(prop); } } } if (item.FindField <ObjectPropertyViewModel>("mInventory") != null) { inventory.Elements.AddRange(((ArrayProperty)rootItem.FindChild(item.FindField <ObjectPropertyViewModel>("mInventory").Str2, false).FindField <ArrayPropertyViewModel>("mInventoryStacks").Model).Elements); } if (item.FindField <ObjectPropertyViewModel>("mStorageInventory") != null) { inventory.Elements.AddRange(((ArrayProperty)rootItem.FindChild(item.FindField <ObjectPropertyViewModel>("mStorageInventory").Str2, false).FindField <ArrayPropertyViewModel>("mInventoryStacks").Model).Elements); } if (item.FindField <ObjectPropertyViewModel>("mInputInventory") != null) { inventory.Elements.AddRange(((ArrayProperty)rootItem.FindChild(item.FindField <ObjectPropertyViewModel>("mInputInventory").Str2, false).FindField <ArrayPropertyViewModel>("mInventoryStacks").Model).Elements); } if (item.FindField <ObjectPropertyViewModel>("mOutputInventory") != null) { inventory.Elements.AddRange(((ArrayProperty)rootItem.FindChild(item.FindField <ObjectPropertyViewModel>("mOutputInventory").Str2, false).FindField <ArrayPropertyViewModel>("mInventoryStacks").Model).Elements); } rootItem.Remove(item); count++; } } } return(count); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var hostPlayerModel = rootItem.FindChild("Char_Player.Char_Player_C", false); if (hostPlayerModel == null || hostPlayerModel.Items.Count < 1) { MessageBox.Show("This save does not contain a host player or it is corrupt.\nTry loading and re-saving the save from within the game.", "Cannot find host player", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var playerEntityModel = (SaveEntityModel)hostPlayerModel.Items[0]; int itemStackQuantity = 500; var dialog = new StringPromptWindow { Owner = Application.Current.MainWindow }; var cvm = (StringPromptViewModel)dialog.DataContext; cvm.WindowTitle = "Enter quantity of each item to spawn"; cvm.PromptMessage = "Count (integer):"; cvm.ValueChosen = "500"; cvm.OldValueMessage = ""; dialog.ShowDialog(); try { itemStackQuantity = int.Parse(cvm.ValueChosen); if (itemStackQuantity <= 0) { MessageBox.Show("The quantity you entered is invalid."); return(false); } } catch (Exception) { if (!(cvm.ValueChosen == "cancel")) { MessageBox.Show("Could not parse: " + cvm.ValueChosen); } return(false); } ArrayProperty inventory = new ArrayProperty("mInventoryStacks") { Type = "StructProperty" }; HashSet <string> resourceStrings = new HashSet <string>(); HashSet <string> radioactiveStrings = new HashSet <string>(); //dump all resources in a hashset first to remove duplicates TODO consider making a hashmap to numbers so they maintain order foreach (var resource in Resource.GetResources()) { if (resource.IsRadioactive) { radioactiveStrings.Add(resource.Path); } else { resourceStrings.Add(resource.Path); } } //Populate the inventory with every item in ResourcesUnfiltered.xml foreach (var resource in resourceStrings) { if (!radioactiveStrings.Contains(resource))//because duplicates can be in the xml file in order, still need to check every string here for radioactivity { //MessageBox.Show($"Processing resource {resource}"); byte[] bytes = MassDismantleCheat.PrepareForParse(resource, itemStackQuantity); //reuse mass dismantle cheat's parsing method using (MemoryStream ms = new MemoryStream(bytes)) using (BinaryReader reader = new BinaryReader(ms)) { SerializedProperty prop = SerializedProperty.Parse(reader); inventory.Elements.Add(prop); } } } string skipped = ""; foreach (string radioactiveResource in radioactiveStrings) { skipped += $"{radioactiveResource.Split('.')[1]}\n"; } //Use Mass Dismantle Cheat's crate creation function to package the items into a crate entity MassDismantleCheat.CreateCrateEntityFromInventory(rootItem, inventory); //MessageBox.Show("Player name " + playerEntityModel.Title); MessageBox.Show($"Crate created.\nNote that normally unstackable items will visually display as being stacked to 1. Use Ctrl+Click to transfer items out of the crate without deleting part of the stack.\n\nSkipped the following items marked as radioactive:\n\n{skipped}", $"Processed {resourceStrings.Count} resource paths"); //Ask the player if they'd like the be equipped with a hazmat suit and filters since the box will be radioactive /*MessageBoxResult result = MessageBox.Show("A crate with all resources has been generated at your feet. This includes radioactive items. Would you like a Hazmat suit and filters? They will replace your current equipment and first inventory item.", $"Processed {resourceStrings.Count} resource paths", MessageBoxButton.YesNo, MessageBoxImage.Question); * if (result == MessageBoxResult.Yes) * { * string hazmatPath = "/Game/FactoryGame/Resource/Equipment/HazmatSuit/BP_EquipmentDescriptorHazmatSuit.BP_EquipmentDescriptorHazmatSuit_C"; * string filterPath = "/Game/FactoryGame/Resource/Parts/IodineInfusedFilter/Desc_HazmatFilter.Desc_HazmatFilter_C"; * * //playerEntityModel.FindOrCreateField<ObjectProperty>("mInventory"); * var playerName = playerEntityModel.Title; * var playerBackSlot = rootItem.FindChild(playerName + ".BackSlot", true); * if (playerBackSlot == null) * { * MessageBox.Show("Your player does not seem to have an associated back slot.\nThe crate has still been created, but you have not been given Hazmat equipment.", "Cannot find host player inventory.", MessageBoxButton.OK, MessageBoxImage.Warning); * } * else * { * //MessageBox.Show(playerBackSlot.FindOrCreateField<ArrayPropertyViewModel>("mInventoryStacks").Elements[0]); * MessageBox.Show("Currently unimplemented"); * } * }*/ return(true); }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var sinkSubsystem = rootItem.FindChild("Persistent_Level:PersistentLevel.ResourceSinkSubsystem", false); if (sinkSubsystem == null) { MessageBox.Show("This save does not contain a ResourceSinkSubsystem.\nThis means that the loaded save is probably corrupt. Aborting.", "Cannot find ResourceSinkSubsystem", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } var pointsTowardsCurrentTicket = sinkSubsystem.FindOrCreateField <Int64PropertyViewModel>("mTotalResourceSinkPoints"); var mCurrentPointLevel = sinkSubsystem.FindOrCreateField <IntPropertyViewModel>("mCurrentPointLevel"); var dialog = new StringPromptWindow { Owner = Application.Current.MainWindow }; var cvm = (StringPromptViewModel)dialog.DataContext; cvm.WindowTitle = "Enter earned ticket count"; cvm.PromptMessage = "Tickets"; cvm.ValueChosen = "0"; cvm.OldValueMessage = $"Sets the AWESOME Sink ticket prices as if you had earned N tickets.\nFor example, entering 0 sets the price for the next ticket back to 1,000\nCurrent tickets earned: {mCurrentPointLevel.Value}\nMore info on AWESOME Sink wiki page"; dialog.ShowDialog(); int requestedTicketCount = 0; try { requestedTicketCount = int.Parse(cvm.ValueChosen); if (requestedTicketCount < 0) { MessageBox.Show("You must enter a number greater than 0.", "Ticket count unchanged.", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } else if (requestedTicketCount > 288100000) { MessageBox.Show("The highest ticket count supported is about 288,100,000, since the highest supported points per ticket is around 9,223,372,036,854,775,807 (int64 max value)", "That's a lot of tickets!"); return(false); } mCurrentPointLevel.Value = requestedTicketCount; //"point level" is 0 if no tickets have been earned, 1 if one ticket has, etc. pointsTowardsCurrentTicket.Value = 0; //reset progress towards the current ticket so the game GUI doesn't get confused long calculatedPointsCount = pointsRequiredFromTicketCount(requestedTicketCount); MessageBox.Show($"Earned ticket count set to {requestedTicketCount}.", "Success", MessageBoxButton.OK, MessageBoxImage.Information); //MessageBox.Show($"Ticket count set to {requestedTicketCount}. The next ticket will take {calculatedPointsCount} points to earn.", "Success", MessageBoxButton.OK, MessageBoxImage.Information); return(true); } catch (Exception) { if (!(cvm.ValueChosen == "cancel")) { MessageBox.Show($"Could not parse: {cvm.ValueChosen}"); } return(false); } }
public bool Apply(SaveObjectModel rootItem, SatisfactorySave saveGame) { var mapManager = rootItem.FindChild("Persistent_Level:PersistentLevel.MapManager", false); if (mapManager == null) { MessageBox.Show("This save does not contain a MapManager.\nThis means that the loaded save is probably corrupt. Aborting.", "Cannot find MapManager", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } //map data is an Array(Byte) containing 1048576 elements ranging from 0 to 255, where 255 is fully revealed. var fogOfWarRawData = mapManager.FindOrCreateField <ArrayPropertyViewModel>("mFogOfWarRawData"); if (!(fogOfWarRawData is ArrayPropertyViewModel)) { MessageBox.Show("FogOfWarRawData is of wrong type.\nThis means that the loaded save is probably corrupt. Aborting.", "Wrong property type", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } if (fogOfWarRawData.Elements.Count != 1048576) { MessageBox.Show($"Expected 1048576 fog of war elements to be present, but there were actually {fogOfWarRawData.Elements.Count}.\nThis does not necessarily mean that the process will fail. Please report this error on the Github Issues page regardless.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning); } int mapRevealThreshold = 0; var dialog = new StringPromptWindow { Owner = Application.Current.MainWindow }; var cvm = (StringPromptViewModel)dialog.DataContext; cvm.WindowTitle = "Enter map reveal threshold"; cvm.PromptMessage = "Enter a number between 0 and 255 (integer):"; cvm.ValueChosen = "255"; cvm.OldValueMessage = "Sets the reveal state of every map region to the value you choose.\n255 is fully explored\n0 is entirely unexplored"; dialog.ShowDialog(); try { mapRevealThreshold = int.Parse(cvm.ValueChosen); if (mapRevealThreshold >= 0 && mapRevealThreshold <= 255) { for (int i = 0; i < fogOfWarRawData.Elements.Count; i++) { ((BytePropertyViewModel)fogOfWarRawData.Elements[i]).Value = $"{mapRevealThreshold}"; } } else { MessageBox.Show("You must enter a number between 0 and 255."); return(false); } } catch (Exception) { if (!(cvm.ValueChosen == "cancel")) { MessageBox.Show($"Could not parse: {cvm.ValueChosen}"); } return(false); } MessageBox.Show("Map data uncovered. Remember to enable the map as well if desired.", "Success", MessageBoxButton.OK, MessageBoxImage.Information); return(true); }