public override void Process(PDAEntryAdd packet) { using (packetSender.Suppress <PDAEntryAdd>()) using (packetSender.Suppress <PDAEntryProgress>()) { TechType techType = packet.TechType.ToUnity(); PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); if (!PDAScanner.GetPartialEntryByKey(techType, out PDAScanner.Entry entry)) { entry = PDAScanner.Add(techType, packet.Unlocked); } if (entry != null) { entry.unlocked++; if (entry.unlocked >= entryData.totalFragments) { PDAScanner.partial.Remove(entry); PDAScanner.complete.Add(entry.techType); } else { int totalFragments = entryData.totalFragments; if (totalFragments > 1) { float num2 = (float)entry.unlocked / (float)totalFragments; float arg = (float)Mathf.RoundToInt(num2 * 100f); ErrorMessage.AddError(Language.main.GetFormat <string, float, int, int>("ScannerInstanceScanned", Language.main.Get(entry.techType.AsString(false)), arg, entry.unlocked, totalFragments)); } } } } }
public override void Process(PDAEntryProgress packet) { using (packetSender.Suppress <PDAEntryAdd>()) using (packetSender.Suppress <PDAEntryProgress>()) { TechType techType = packet.TechType.ToUnity(); PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); PDAScanner.Entry entry; if (PDAScanner.GetPartialEntryByKey(techType, out entry)) { if (packet.Unlocked > entry.unlocked) { Log.Info("PDAEntryProgress Upldate Old:" + entry.unlocked + " New" + packet.Unlocked); entry.unlocked = packet.Unlocked; } } else { Log.Info("PDAEntryProgress New TechType:" + techType + " Unlocked:" + packet.Unlocked); MethodInfo methodAdd = typeof(PDAScanner).GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(TechType), typeof(int) }, null); entry = (PDAScanner.Entry)methodAdd.Invoke(null, new object[] { techType, packet.Unlocked }); } } }
private void Process(ClientScanProgress msg) { var entryData = PDAScanner.GetEntryData(msg.tech); if (entryData == null) { return; } using (new MessageBlocker()) { PDAScanner.Entry entry; if (!PDAScanner.GetPartialEntryByKey(msg.tech, out entry)) { var methodAdd = typeof(PDAScanner).GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(TechType), typeof(int) }, null); entry = (PDAScanner.Entry)methodAdd.Invoke(null, new object[] { msg.tech, 0 }); } if (entry != null) { entry.unlocked = msg.progress; if (entry.unlocked >= entryData.totalFragments) { var partial = (List <PDAScanner.Entry>)(typeof(PDAScanner).GetField("partial", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null)); var complete = (HashSet <TechType>)(typeof(PDAScanner).GetField("complete", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null)); partial.Remove(entry); complete.Add(entry.techType); } } } }
public static bool Prefix(TechType techType, bool verbose) { if (Main.Config.Hardcore) { var entryData = PDAScanner.GetEntryData(techType); return(!verbose || entryData == null || (entryData != null && PDAScanner.ContainsCompleteEntry(techType))); } return(true); }
public static void Postfix(ref StringBuilder sb, TechType techType) { PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); if (entryData == null || PDAScanner.ContainsCompleteEntry(techType) || CrafterLogic.IsCraftRecipeUnlocked(techType)) { return; } sb.Clear(); TooltipFactory.WriteTitle(sb, Main.config.UnKnownTitle); TooltipFactory.WriteDescription(sb, Main.config.UnKnownDescription); }
public static void Prefix(PDAData data) { List <TechType> types = new List <TechType>(data.defaultTech); foreach (TechType techType in types) { PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); if (entryData != null && entryData.locked) { data.defaultTech.Remove(techType); } } }
public static void Postfix() { if (PDAScanner.ContainsCompleteEntry(techType) || KnownTech.Contains(techType)) { if (techType == TechType.ScrapMetal && !KnownTech.Contains(TechType.Titanium)) { PDAScanner.AddByUnlockable(TechType.Titanium, 1); KnownTech.Add(TechType.Titanium); } if (!KnownTech.Contains(techType)) { KnownTech.Add(techType); } var entryData = PDAScanner.GetEntryData(techType); if (entryData != null && entryData.locked) { PDAScanner.Unlock(entryData, true, true); if (!KnownTech.Contains(entryData.blueprint)) { KnownTech.Add(entryData.blueprint); } } #if SN1 var techType2 = CraftData.GetHarvestOutputData(techType); #elif BZ var techType2 = TechData.GetHarvestOutput(techType); #endif if (techType2 != TechType.None) { if (!KnownTech.Contains(techType2)) { KnownTech.Add(techType2); } var entryData2 = PDAScanner.GetEntryData(techType2); if (entryData2 != null && entryData2.locked) { PDAScanner.Unlock(entryData, true, true); if (!KnownTech.Contains(entryData2.blueprint)) { KnownTech.Add(entryData2.blueprint); } } } } }
public static void Callback() { // When a player scans a fragment, it will be deleted from the world. We want to send out a pickup event // before the object can be removed and corresponding scan data is invalidated. TechType techType = PDAScanner.scanTarget.techType; PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); // Only do this for fragments and player scans or nearby fish if (entryData != null && entryData.destroyAfterScan && PDAScanner.scanTarget.gameObject && !PDAScanner.scanTarget.isPlayer) { // A lot of fragments are virtual entities (spawned by placeholders in the world). Sometimes the server only knows the id // of the placeholder and not the virtual entity. TODO: we will need to propagate deterministic ids to children entities for // these virtual entities. NitroxServiceLocator.LocateService <Item>().PickedUp(PDAScanner.scanTarget.gameObject, techType); } }
public static void Postfix() { PDAScanner.ScanTarget scanTarget = PDAScanner.scanTarget; PDAScanner.EntryData entryData = PDAScanner.GetEntryData(scanTarget.techType); TechType key = entryData?.key ?? TechType.None; TechType blueprint = entryData?.blueprint ?? TechType.None; if (scanTarget.techType != TechType.None && CrafterLogic.IsCraftRecipeUnlocked(scanTarget.techType) || (entryData != null && ((blueprint != TechType.None && CrafterLogic.IsCraftRecipeUnlocked(entryData.blueprint)) || (key != TechType.None && CrafterLogic.IsCraftRecipeUnlocked(entryData.key)))) || !scanTarget.isValid || !GameModeUtils.RequiresBlueprints()) { return; } #if SN1 HandReticle.main.SetInteractText(Main.config.UnKnownLabel, false, HandReticle.Hand.None); #elif BZ HandReticle.main.SetText(HandReticle.TextType.Hand, Main.config.UnKnownLabel, true, GameInput.Button.None); #endif }
public static void Postfix(Pickupable pickupable) { if (newgame && Main.config.Hardcore && !Utils.GetContinueMode() && pickupable.GetTechType() != TechType.FireExtinguisher) { CoroutineHost.StartCoroutine(GiveHardcoreScanner()); newgame = false; SMLHelper.V2.Handlers.IngameMenuHandler.RegisterOnQuitEvent(() => newgame = true); } TechType techType = pickupable.GetTechType(); PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); GameObject gameObject = pickupable.gameObject; if (Main.config.ScanOnPickup && Inventory.main.container.Contains(TechType.Scanner) && entryData != null) { if (!PDAScanner.GetPartialEntryByKey(techType, out PDAScanner.Entry entry)) { entry = PDAScanner.Add(techType, 1); } if (entry != null) { PDAScanner.partial.Remove(entry); PDAScanner.complete.Add(entry.techType); PDAScanner.NotifyRemove(entry); PDAScanner.Unlock(entryData, true, true, true); KnownTech.Add(techType, false); if (gameObject != null) { gameObject.SendMessage("OnScanned", null, SendMessageOptions.DontRequireReceiver); } #if SN1 ResourceTracker.UpdateFragments(); #endif } } if (!Main.config.Hardcore && entryData == null) { KnownTech.Add(techType, true); } }
public static void Postfix(ScannerTool __instance) { PDAScanner.ScanTarget scanTarget = PDAScanner.scanTarget; #if SN1 PDAScanner.Result result = PDAScanner.CanScan(); #elif BZ PDAScanner.Result result = PDAScanner.CanScan(scanTarget); #endif PDAScanner.EntryData entryData = PDAScanner.GetEntryData(PDAScanner.scanTarget.techType); if ((entryData != null && (CrafterLogic.IsCraftRecipeUnlocked(entryData.blueprint) || CrafterLogic.IsCraftRecipeUnlocked(entryData.key))) || PDAScanner.ContainsCompleteEntry(scanTarget.techType) || __instance.energyMixin.charge <= 0f || !scanTarget.isValid || result != PDAScanner.Result.Scan || !GameModeUtils.RequiresBlueprints()) { return; } #if SN1 HandReticle.main.SetInteractText(Main.config.UnKnownLabel, false, HandReticle.Hand.None); #elif BZ HandReticle.main.SetText(HandReticle.TextType.Hand, Main.config.UnKnownLabel, true, GameInput.Button.None); #endif }
static void unlockPopupsUpdate() { KnownTech.AnalysisTech _getEntry(TechType techType) => KnownTech.analysisTech.FirstOrDefault(tech => tech.techType == techType); foreach (var popup in unlockPopups) { var tech = _getEntry(popup.Key); var sprite = _getEntry(popup.Value)?.unlockPopup; if (sprite == null && PDAScanner.GetEntryData(popup.Value) is PDAScanner.EntryData fragData) { sprite = _getEntry(fragData.blueprint)?.unlockPopup; // try popup.Value as fragment tech type } if (sprite != null) { tech.unlockPopup = sprite; } } }
public override void Process(PDAEntryAdd packet) { using (packetSender.Suppress <PDAEntryAdd>()) using (packetSender.Suppress <PDAEntryProgress>()) { TechType techType = packet.TechType.Enum(); PDAScanner.EntryData entryData = PDAScanner.GetEntryData(techType); PDAScanner.Entry entry; if (!PDAScanner.GetPartialEntryByKey(techType, out entry)) { MethodInfo methodAdd = typeof(PDAScanner).GetMethod("Add", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(TechType), typeof(int) }, null); entry = (PDAScanner.Entry)methodAdd.Invoke(null, new object[] { techType, packet.Unlocked }); } if (entry != null) { entry.unlocked++; if (entry.unlocked >= entryData.totalFragments) { List <PDAScanner.Entry> partial = (List <PDAScanner.Entry>)(typeof(PDAScanner).GetField("partial", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null)); HashSet <TechType> complete = (HashSet <TechType>)(typeof(PDAScanner).GetField("complete", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null)); partial.Remove(entry); complete.Add(entry.techType); } else { int totalFragments = entryData.totalFragments; if (totalFragments > 1) { float num2 = (float)entry.unlocked / (float)totalFragments; float arg = (float)Mathf.RoundToInt(num2 * 100f); ErrorMessage.AddError(Language.main.GetFormat <string, float, int, int>("ScannerInstanceScanned", Language.main.Get(entry.techType.AsString(false)), arg, entry.unlocked, totalFragments)); } } } } }
private static bool Prefix(TechType techType, int num = 1, bool noMessage = false, bool spawnIfCantAdd = true) { if (techType == TechType.Titanium && num == 2 && !noMessage && spawnIfCantAdd) { TechType scannedFragment = PDAScanner.scanTarget.techType; #if !RELEASE Logger.Log(Logger.Level.Debug, $"Intercepting scan of fragment {scannedFragment.ToString()}"); #endif TechData recipe; // "Variable declaration can be inlined" says Visual Studio, but I'm not sure if it would remain in-scope further down the function if it is. if (IngredientsFromScanning.Main.config.TryOverrideRecipe(scannedFragment, out recipe)) { #if !RELEASE Logger.Log(Logger.Level.Debug, $"Using OverrideRecipe: {JsonConvert.SerializeObject(recipe, Oculus.Newtonsoft.Json.Formatting.Indented)}"); #endif } else if ((int)scannedFragment > 1112 && (int)scannedFragment < 1117) { // TechTypes 1113 to 1116 are Cyclops fragments, which have no blueprint associated, so we need to process them specially. recipe = new TechData(); /*CyclopsHullFragment = 1113, * CyclopsBridgeFragment = 1114, * CyclopsEngineFragment = 1115, * CyclopsDockingBayFragment = 1116,*/ switch ((int)scannedFragment) { case 1113: recipe.Ingredients.Add(new Ingredient(TechType.PlasteelIngot, 2)); recipe.Ingredients.Add(new Ingredient(TechType.Lead, 1)); break; case 1114: recipe.Ingredients.Add(new Ingredient(TechType.EnameledGlass, 3)); break; case 1115: recipe.Ingredients.Add(new Ingredient(TechType.Lubricant, 1)); recipe.Ingredients.Add(new Ingredient(TechType.AdvancedWiringKit, 1)); recipe.Ingredients.Add(new Ingredient(TechType.Lead, 1)); break; case 1116: recipe.Ingredients.Add(new Ingredient(TechType.PlasteelIngot, 2)); break; } recipe.Ingredients.Add(new Ingredient(TechType.Lead, 1)); recipe.Ingredients.Add(new Ingredient(TechType.PlasteelIngot, 1)); #if !RELEASE Logger.Log(Logger.Level.Debug, $"Using recipe from manual override: {JsonConvert.SerializeObject(recipe, Oculus.Newtonsoft.Json.Formatting.Indented)}"); #endif } else { PDAScanner.EntryData entryData = PDAScanner.GetEntryData(scannedFragment); if (entryData == null) // Sanity check; this should always be true { #if !RELEASE Logger.Log(Logger.Level.Debug, $"Failed to find EntryData for fragment"); #endif /*CraftData.AddToInventory(TechType.Titanium); * CraftData.AddToInventory(TechType.Titanium); // Adding them one-by-one so as to prevent it being caught by this very routine.*/ return(true); } //Logger.Log(Logger.Level.Debug, $"Found entryData {entryData.ToString()}"); #if !RELEASE Logger.Log(Logger.Level.Debug, $"Found entryData {JsonConvert.SerializeObject(entryData, Oculus.Newtonsoft.Json.Formatting.Indented)}"); #endif //CraftData.AddToInventory(TechType.Titanium); //CraftData.AddToInventory(TechType.Copper); recipe = CraftDataHandler.GetTechData(entryData.blueprint); if (recipe == null) { #if !RELEASE Logger.Log(Logger.Level.Debug, $"Failed to find blueprint for EntryData"); #endif /*CraftData.AddToInventory(TechType.Titanium); * CraftData.AddToInventory(TechType.Titanium); // One-by-one again, as above.*/ return(true); } //Logger.Log(Logger.Level.Debug, $"Found recipe {recipe.ToString()}"); #if !RELEASE Logger.Log(Logger.Level.Debug, $"Using recipe from EntryData: {JsonConvert.SerializeObject(recipe, Oculus.Newtonsoft.Json.Formatting.Indented)}"); #endif } for (int i = 0; i < recipe.Ingredients.Count; i++) { if (IngredientsFromScanning.Main.config.TrySubstituteIngredient(recipe.Ingredients[i].techType, out List <Ingredient> Substitutes)) { foreach (Ingredient sub in Substitutes) { recipe.Ingredients.Add(sub); } recipe.Ingredients.RemoveAt(i); // Remove the current ingredient... i--; // ...and make sure the loop continues at the item after this, not the one after that. } } // I believe the easiest way to get a random item from the blueprint would be to make a list of techTypes; if an ingredient is used twice in the recipe, it will appear in the list twice. // That way, we can generate a random number where 0<=rnd<list.count, and select that item. List <TechType> bp = new List <TechType> { }; for (int i = 0; i < recipe.Ingredients.Count; i++) { for (int j = 0; j < recipe.Ingredients[i].amount; j++) { bp.Add(recipe.Ingredients[i].techType); } } // Now build up weights List <WeightedItem> BlueprintPairs = new List <WeightedItem>(); float TotalWeight = 0f; //Logger.Log(Logger.Level.Error, "Unidentified Vehicle Type!"); for (int i = 0; i < bp.Count; i++) { float thisWeight = IngredientsFromScanning.Main.config.GetWeightForTechType(bp[i]); TotalWeight += thisWeight; WeightedItem thisWeightedItem = new WeightedItem(TotalWeight, bp[i]); #if !RELEASE Logger.Log(Logger.Level.Debug, $"Adding item to drop list, TechType = {thisWeightedItem.tech.ToString()}, this weight = {thisWeight}, cumulative weight = {thisWeightedItem.Weight}"); #endif BlueprintPairs.Add(thisWeightedItem); } // Now we should be able to pick a few random numbers between 0 and the list's total weight, and add those. We want to remove that entry afterwards, but that's not a big ask. System.Random rng = new System.Random(); int numIngredients = Math.Min(IngredientsFromScanning.Main.config.GenerateGiftValue(), BlueprintPairs.Count); #if !RELEASE Logger.Log(Logger.Level.Debug, $"Generated a value for this scan of {numIngredients} components."); #endif int awards = 0; double r; for (int i = 0; i < numIngredients && BlueprintPairs.Count > 0; i++) { r = rng.NextDouble() * TotalWeight; for (int j = 0; j < BlueprintPairs.Count; j++) { // This part is for sanity checking // ___________________________|______________________________ // / \ if (r < BlueprintPairs[j].Weight || ((j + 1) == BlueprintPairs.Count && awards < numIngredients)) { #if !RELEASE Logger.Log(Logger.Level.Debug, $"With randomised weight of {r}, adding tech {BlueprintPairs[j].tech} to player inventory"); #endif AddInventory(BlueprintPairs[j].tech, 1, false, true); //CraftData.AddToInventory(BlueprintPairs[j].tech, 1, false, true); awards++; TotalWeight -= IngredientsFromScanning.Main.config.GetWeightForTechType(BlueprintPairs[j].tech); BlueprintPairs.RemoveAt(j); break; } } } return(false); } return(true); }