Replies: 2 (Who?), Viewed: 169 times.
Test Subject
Original Poster
#1 Old 10th Jun 2021 at 4:43 PM
Default Fixing Glitch with Geyser Rifts (ITF)
Hey guys,
dunno if it was brought to anyones attention, but there is a bug when you visit the dystopian future world. Whenever my sim climbs into a geyser rift for exploring and should get rewarded with a gem/metal, it just gets resettet. I dunno whether it is a general bug, that just nobody cared about or it has specific conditions to occur. So before i get deeper in my coding investigation, maybe you should check, if you have the same problem. At least on my installation it occurs, no matter which family, which save, even with fresh install and without all mods and store objects.
Anyways - I examined the error log file which was produced by nraas error trap, when I had this problem. It says the following (sorry, my client is in german and so are some of the information in the log file, i hope the main problem will still be clear.

Code:
<?xml version="1.0" encoding="utf-8"?>
<NRaas.ErrorTrap>
<ModVersion value="100"/>
<BuildVersion value="0.2.0.209"/>
<Installed value="BaseGame, EP1, SP1, EP2, SP2, EP3, SP3, EP4, SP4, EP5, SP5, EP6, SP7, EP7, EP8, SP8, EP9, EP10, SP9, EP11"/>
<Enumerator value="22"/>
<Content>


-- Script Errors --

Interactions:
1: Spalte erkunden
Sims3.Gameplay.Objects.Environment.GeyserRift+ExploreRift+Definition
Sims3.Gameplay.Objects.Environment.GeyserRift+ExploreRift+Definition
UserDirected

 Counter: 19
 Sim-Time: Sa. um 14:54
 Start-Time: 05/24/2021 10:34:03
 PreLoadup-Time: 05/24/2021 10:46:29
 Loadup-Time: 05/24/2021 14:50:30
 Log-Time: 05/24/2021 22:27:48

System.ArgumentException: The list is empty.
#0: 0x0000e throw      in Sims3.Gameplay.Core.Sims3.Gameplay.Core.RandomUtil:GetRandomObjectFromList (System.Collections.Generic.List`1) ([1940057520/0x73a2edb0] )
#1: 0x0004e call       in Sims3.Gameplay.Abstracts.Sims3.Gameplay.Abstracts.RockGemMetalBase:GetRandomGemOfRarity (string) ([31B2DEA0] )
#2: 0x00090 call       in Sims3.Gameplay.Objects.Environment.GeyserRift+ExploreRift:Run () ()
#3: 0x000db stloc.u1   in Sims3.Gameplay.Interactions.Sims3.Gameplay.Interactions.InteractionInstance:RunInteractionWithoutCleanup () ()
#4: 0x00348 stloc.u1   in Sims3.Gameplay.ActorSystems.Sims3.Gameplay.ActorSystems.InteractionQueue:ProcessOneInteraction () ()
#5: 0x0011c stfld.u1   in Sims3.Gameplay.Actors.Sims3.Gameplay.Actors.Sim:DoInteraction () ()
#6: 0x00015 br.s       in Sims3.Gameplay.Actors.Sims3.Gameplay.Actors.Sim:Simulate () ()
#7: 0x00027 leave.s    in ScriptCore.ScriptCore.ScriptProxy:Simulate () ()



Loaded Assemblies:
 ArsilCustomizableNewDrinks
 NRaasDebugEnabler: Version 54
 NRaasDecensor: Version 14
 NRaasErrorTrap: Version 100
 NRaasMasterController: Version 134
 NRaasMasterControllerCheats: Version 134
 NRaasOverwatch: Version 121
 NRaasRetuner: Version 10
 NRaasTraveler: Version 87
 NonaGigPoster
 ScriptCore
 SimIFace
 Sims3GameplayObjects
 Sims3GameplaySystems
 Sims3Metadata
 Sims3StoreObjects
 System
 System.Xml
 UI
 mscorlib
</Content>
</NRaas.ErrorTrap>


So the problem here is, that for some reason the game doesnt produce a random list with gems/metals properly when this happens and getting this error:
System.ArgumentException: The list is empty.
#0: 0x0000e throw in Sims3.Gameplay.Core.Sims3.Gameplay.Core.RandomUtil:GetRandomObjectFromList (System.Collections.Generic.List`1) ([1940057520/0x73a2edb0] )
#1: 0x0004e call in Sims3.Gameplay.Abstracts.Sims3.Gameplay.Abstracts.RockGemMetalBase:GetRandomGemOfRarity (string) ([31B2DEA0] )

So i made some research, if anything could cause this. So far I think in one of the following code lines lies the problem. To see the whole code, I post in which .dll I found the code with an assembly explorer.

First of all the GeyserRift.cs in Sims3GameplayObjects (Sims3.Gameplay.Objects.Environment):

Code:
public class ExploreRift : Interaction<Sim, GeyserRift>
    {
      [TunableComment("Range: 0 - 100 : Percentage chance of falling into the rift - PAB")]
      [Tunable]
      private static float kChanceToFallInRift = 30f;
      [Tunable]
      [TunableComment("Range: 0 - x : Time in Sim Minutes that Sim spends in the rift - PAB")]
      private static float kTimeInRift = 10f;
      [TunableComment("Range: 0 - 100 : Chance of finding a gem or metal in the rift - PAB")]
      [Tunable]
      private static float kChanceForGemOrMetal = 50f;
      [Tunable]
      [TunableComment("Range: 0 - 100 : Chance gem / metal is common - PAB")]
      private static float kChanceForCommonGemOrMetal = 65f;
      [Tunable]
      [TunableComment("Range: 0 - 100 : Chance gem / metal is uncommon - PAB")]
      private static float kChanceForUncommonGemOrMetal = 30f;
      [TunableComment("Range: Buffs.  Description: Buffs that could be applied to sim if they fail to find a gem or metal in the rift (Note if you add a new buff here you will need to add a new string with the buffname appended..  example = BuffAddedGiddy in localization) - PAB")]
      [Tunable]

 protected override bool Run()
      {
bool succeeded = this.DoLoop(ExitReason.Default, new InteractionInstance.InsideLoopFunction(this.RiftLoopCallback), (StateMachineClient) null);
        bool flag1 = false;
        IGameObject gameObject = (IGameObject) null;
        bool flag2 = false;
        BuffNames guid = BuffNames.Undefined;
        if (succeeded)
        {
          if (RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForGemOrMetal))
          {
            flag2 = RandomUtil.CoinFlip();
            string rarity = !RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForCommonGemOrMetal) ? (!RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForUncommonGemOrMetal) ? "Rare" : "Uncommon") : "Common";
            gameObject = !flag2 ? RockGemMetalBase.Make(RockGemMetalBase.GetRandomMetalOfRarity(rarity), false) : RockGemMetalBase.Make(RockGemMetalBase.GetRandomGemOfRarity(rarity), false);
            if (gameObject == null)
            {
              if (!this.Actor.SimDescription.IsEP11Bot)
              {
                guid = GeyserRift.ExploreRift.kRiftBuffs[RandomUtil.GetInt(GeyserRift.ExploreRift.kRiftBuffs.Length - 1)];
                this.Actor.BuffManager.AddElement(guid, Origin.FromGeyserRift);
              }
            }
            else
              flag1 = true;
          }
 if (gameObject != null && flag1)
        {
          this.Actor.Inventory.TryToAdd(gameObject);
          string name = "Gem";
          if (!flag2)
            name = "Metal";
          this.Actor.ShowTNSIfSelectable(GeyserRift.LocalizeString((this.Actor.IsFemale ? 1 : 0) != 0, name, (object) this.Actor.SimDescription.FullName, (object) gameObject), (StyledNotification.NotificationStyle) 3, gameObject.ObjectId, this.Actor.ObjectId);
        }
        else if (guid != BuffNames.Undefined)
          this.Actor.ShowTNSIfSelectable(GeyserRift.LocalizeString((this.Actor.IsFemale ? 1 : 0) != 0, "BuffAdded" + guid.ToString(), (object) this.Actor, (object) this.Target), (StyledNotification.NotificationStyle) 3, this.Target.ObjectId, this.Actor.ObjectId);
        this.EndCommodityUpdates(succeeded);


Second the RockGemMetalBase.cs from Sims3GameplaySystems (Sims3.Gameplay.Abstracts.RockGemMetalBase)

Code:
public static IGameObject Make(RockGemMetal guid, bool setCollected)
    {
      RockGemMetalData rockGemMetalData;
      if (!RockGemMetalBase.sData.TryGetValue(guid, out rockGemMetalData))
        return (IGameObject) null;
      RgmInitParameters rgmInitParameters = new RgmInitParameters(guid);
      RockGemMetalBase objectOutOfWorld = GlobalFunctions.CreateObjectOutOfWorld(rockGemMetalData.MedatorName, (string) null, (Simulator.ObjectInitParameters) rgmInitParameters) as RockGemMetalBase;
      if (setCollected)
        objectOutOfWorld.mCollected = true;
      return (IGameObject) objectOutOfWorld;
    }

    public static RockGemMetal GetRandomGemOfRarity(string rarity)
    {
      List<RockGemMetal> randomList = new List<RockGemMetal>();
      foreach (RockGemMetal sGem in RockGemMetalBase.sGems)
      {
        RockGemMetalData rockGemMetalData;
        if (RockGemMetalBase.sData.TryGetValue(sGem, out rockGemMetalData) && rarity == rockGemMetalData.Rarity)
          randomList.Add(sGem);
      }
      return RandomUtil.GetRandomObjectFromList<RockGemMetal>(randomList);
    }

    public static RockGemMetal GetRandomGem() => RandomUtil.GetRandomObjectFromList<RockGemMetal>(RockGemMetalBase.sGems);

    public static RockGemMetal GetRandomMetalOfRarity(string rarity)
    {
      List<RockGemMetal> randomList = new List<RockGemMetal>();
      foreach (RockGemMetal sMetal in RockGemMetalBase.sMetals)
      {
        RockGemMetalData rockGemMetalData;
        if (RockGemMetalBase.sData.TryGetValue(sMetal, out rockGemMetalData) && rarity == rockGemMetalData.Rarity)
          randomList.Add(sMetal);
      }
      return RandomUtil.GetRandomObjectFromList<RockGemMetal>(randomList);
    }

    public static RockGemMetal GetRandomMetal() => RandomUtil.GetRandomObjectFromList<RockGemMetal>(RockGemMetalBase.sMetals);


I also looked at the RandomUtil (Sims3.Gameplay.Core.RandomUtil in Sims3GameplaySystems) and the List´1 (System.Collections.Generic.List´1 in the mscorlib) from the first error line. But they aren't used only in this specific interaction. And the rest of the game works fine, so I assume, there shouldn't lie the error. Especially since these are core elements in the scriptcode. So if there would be anything wrong, we should have noticed Plus the List´1 line just seems to refer to a generic error report, if - for some reason - there are no elements in a list.

My first guess was this:
From the geyserrift.cs
gameObject = !flag2 ? RockGemMetalBase.Make(RockGemMetalBase.GetRandomMetalOfRarity(rarity), false) : RockGemMetalBase.Make(RockGemMetalBase.GetRandomGemOfRarity(rarity), false);

From the RockGemMetalbase:
if (setCollected)
objectOutOfWorld.mCollected = true;
return (IGameObject) objectOutOfWorld;

If you are about to get a collectible from the geyser rift, it states, that it should not count as collected. But maybe this causes an error the Make command, because there is a line, that has the condition, that setcollected should be true.

Maybe we could solve this together and write a little "community patch" for this, since there is no support from EA any more.
Advertisement
Field Researcher
#2 Old 10th Jun 2021 at 7:49 PM Last edited by gamefreak130 : 11th Jun 2021 at 3:19 PM.
Interesting find! I'm always up for a bit of bug hunting.

Is your game set to a language other than English? If so, then I think that's the culprit, as odd as that may sound. Let me explain.

GetRandomObjectFromList() takes a list of things as an argument and returns a single random thing from the list. The error you're getting means that the list that was passed had nothing in it, and so nothing could be returned. Take another look at GetRandomGemOfRarity(), which makes the GetRandomObjectFromList() call that throws the empty list error:

Code:
public static RockGemMetal GetRandomGemOfRarity(string rarity)
{
    List<RockGemMetal> randomList = new List<RockGemMetal>();
    foreach (RockGemMetal sGem in RockGemMetalBase.sGems)
    {
        RockGemMetalData rockGemMetalData;
        if (RockGemMetalBase.sData.TryGetValue(sGem, out rockGemMetalData) && rarity == rockGemMetalData.Rarity)
        {
            randomList.Add(sGem);
        }
    }
    return RandomUtil.GetRandomObjectFromList<RockGemMetal>(randomList);
}


In order for the list we're pulling from, randomList, to be empty, then one of two things has to happen: either there are no gems that exist in your game's tuning, or none of them have a Rarity property that is equal to the "rarity" string that was passed to the method. The former obviously can't be true, since I assume you're still able to collect gems just fine normally. However, shouldn't the latter explanation be just as unlikely? After all, this is the code that calls the GetRandomGemOfRarity() function:

Code:
flag3 = RandomUtil.CoinFlip();
string rarity;
if (RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForCommonGemOrMetal))
{
    rarity = "Common";
}
else if (RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForUncommonGemOrMetal))
{
    rarity = "Uncommon";
}
else
{
    rarity = "Rare";
}
if (flag3)
{
    gameObject = RockGemMetalBase.Make(RockGemMetalBase.GetRandomGemOfRarity(rarity), false);
}
else
{
    gameObject = RockGemMetalBase.Make(RockGemMetalBase.GetRandomMetalOfRarity(rarity), false);
}


That does seem rather clear-cut: the rarity is either "Common," "Uncommon," or "Rare," all of which are valid categories. So what else could be the problem? Well, let's take a look at Rarity property of RockGemMetalData:

Code:
public string Rarity
{
    get
    {
        return Localization.LocalizeString(this.mRarity, new object[0]);
    }
}


In case you aren't aware, LocalizeString() is a method that takes a "key" string and looks up and returns its associated "value" in the string table associated with the current game language. This means that the Rarity property will not always return in English; it will return whatever the associated translation of "Common," "Rare," etc. is in the game's current language.

Furthermore, if you analyze the method in ILSpy (or equivalent), you'll note that there are only three places this Rarity property is used: GetCollectionInfo, a method used solely for updating the UI of the skill journal, and the get random gem/metal functions throwing errors here -- functions that are ONLY used by this ExploreRift interaction and presumably written exclusively for them. All of this furthers my hypothesis that the Rarity property was not meant to be used in the way ExploreRift uses it. The most likely explanation, then, is that this slipped by QA testing because QA testing was done exclusively (or at least mostly) with the game language set to English.

Anyway, that's probably way more than you wanted to know. Assuming that is indeed the bug, it would be rather easy to work around by just tacking on the rest of the "key" used to lookup the rarity's translation and comparing the keys directly, rather than using the property:

Code:
flag3 = RandomUtil.CoinFlip();
string rarity;
if (RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForCommonGemOrMetal))
{
    rarity = "Common";
}
else if (RandomUtil.RandomChance(GeyserRift.ExploreRift.kChanceForUncommonGemOrMetal))
{
    rarity = "Uncommon";
}
else
{
    rarity = "Rare";
}
rarity = "Gameplay/Excel/RockGemMetal/Rarity:" + rarity;
if (flag3)
{
    gameObject = RockGemMetalBase.Make(RockGemMetalBase.GetRandomGemOfRarity(rarity), false);
}
else
{
    gameObject = RockGemMetalBase.Make(RockGemMetalBase.GetRandomMetalOfRarity(rarity), false);
}

Code:
public static RockGemMetal GetRandomGemOfRarity(string rarity)
{
    List<RockGemMetal> randomList = new List<RockGemMetal>();
    foreach (RockGemMetal sGem in RockGemMetalBase.sGems)
    {
        RockGemMetalData rockGemMetalData;
        if (RockGemMetalBase.sData.TryGetValue(sGem, out rockGemMetalData) && rarity == rockGemMetalData.mRarity)
        {
            randomList.Add(sGem);
        }
    }
    return RandomUtil.GetRandomObjectFromList<RockGemMetal>(randomList);
}


Heck, I could probably code it up myself in the next few days, if you wanted me to.

"The Internet is the first thing that humanity has built that humanity doesn't understand, the largest experiment in anarchy that we have ever had." - Eric Schmidt

If you enjoy the mods I put out, consider supporting me on patreon: www.patreon.com/Gamefreak130
Test Subject
Original Poster
#3 Old 11th Jun 2021 at 1:33 PM
I don't want to be too rash, but you are a frickin genius!

I changed my client to english (didnt change anything else, just the locale string in the registry from de to en-us) - and the bug is gone. So it seems you traced the right path here.
I would really appreciate and you have my gratitude, if you code this. Do you need anything? More information? some files?
Back to top