[Solved] Scribe References "Misaligned load ID request"

Started by 1000101, July 14, 2015, 02:49:55 PM

Previous topic - Next topic

1000101

For some reason when a part of my code is loading references from a save game, the reference being loaded changes class.

To wit:
Misaligned load ID request. Requests didn't match between the LoadingVars and ResolvingCrossRefs stage. Id MealSimple384145 was entered as a Verse.Thing but is being read as a Verse.Pawn.
Exception getting object with load id MealSimple384145 of type Verse.Pawn. What we loaded was MealSimple384145. Exception:
System.InvalidCastException: Cannot cast from source type to destination type.

  at (wrapper managed-to-native) object:__icall_wrapper_mono_object_castclass (object,intptr)

  at Verse.LoadedObjectDirectory.ObjectWithLoadID[Pawn] (System.String loadID) [0x00000] in <filename unknown>:0


This happens between the LoadingVars (which is done without issue) and ResolvingCrossRefs stage when the error is thrown.  However, when it tries to resolve the reference, it complains the other way:
Misaligned load ID request. Requests didn't match between the LoadingVars and ResolvingCrossRefs stage. Id null was entered as a Verse.Pawn but is being read as a Verse.Thing.

The code which causes this is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using RimWorld;
using UnityEngine;
using Verse;
using Verse.AI;

namespace CommunityCoreLibrary
{
    public class RefrigeratorContents : IExposable
    {
        // This is to handle the degredation of items in the refrigerator
        // It is capable of handling multiple items in multiple cells
        public Thing                    thing;
        public int                      HitPoints;
        public float                    rotProgress;

        public RefrigeratorContents()
        {
            // Default .ctor
            // Needed for Scribing
        }

        public RefrigeratorContents( Thing t, CompRottable compRottable )
        {
            thing = t;
            HitPoints = t.HitPoints;
            rotProgress = compRottable.rotProgress;
        }

        public void ExposeData()
        {
            Log.Message( "\tRefrigeratorContents::ExposeData() {\n\t\tScribeMode: " + Scribe.mode );
            Scribe_References.LookReference( ref thing, "thing" );
            Scribe_Values.LookValue( ref HitPoints, "HitPoints" );
            Scribe_Values.LookValue( ref rotProgress, "rotProgress" );
            Log.Message( "\t} // RefrigeratorContents" );
        }

    }

    public class CompRefrigerated : ThingComp
    {
        private List< RefrigeratorContents >    contents = new List< RefrigeratorContents >();

        private CompPowerTrader         compPower
        {
            get{ return parent.GetComp<CompPowerTrader>(); }
        }

        private Building_Storage        thisBuilding
        {
            get{ return (parent as Building_Storage); }
        }

        public override void PostExposeData()
        {
            base.PostExposeData();

            Log.Message( thisBuilding.ThingID + "::PostExposeData() {\n\tScribeMode: " + Scribe.mode );

            Scribe_Collections.LookList<RefrigeratorContents>( ref contents, "contents", LookMode.Deep );

            Log.Message( "} // " + thisBuilding.ThingID + "::PostExposeData()" );
        }

        public void ScanForRottables()
        {
            // Check for things removed
            bool restartScan;
            do
            {
                restartScan = false;
                foreach( RefrigeratorContents item in contents )
                {
                    if( ( item.thing.Destroyed )||
                        ( item.thing.StoringBuilding() != thisBuilding ) )
                    {
                        // Modifing list, restart scan
                        contents.Remove( item );
                        restartScan = true;
                        break;
                    }
                }
            }while( restartScan == true );

            // Add new things
            foreach( Thing t in thisBuilding.slotGroup.HeldThings )
            {
                CompRottable compRottable = t.TryGetComp<CompRottable>();
                if( ( compRottable != null )&&
                    ( contents.Find( item => item.thing == t ) == null ) )
                    contents.Add( new RefrigeratorContents( t, compRottable ) );
            }

        }

        public override void CompTick()
        {
            base.CompTick();

            // Only do it every 60 ticks to prevent lags
            if( !Gen.IsHashIntervalTick( parent, 60 ) )
                return;

            RefrigerateContents();
        }

        private void RefrigerateContents()
        {
            // Only refrigerate if it has power
            // Don't worry about idle power though
            if( compPower.PowerOn == false )
            {
                // Clear it out
                if( contents.Count > 0 )
                    contents = new List<RefrigeratorContents>();
                // Now leave
                return;
            }

            // Look for things
            ScanForRottables();

            // Refrigerate the items
            foreach( RefrigeratorContents item in contents )
            {
                CompRottable compRottable = item.thing.TryGetComp<CompRottable>();
                item.thing.HitPoints = item.HitPoints;
                compRottable.rotProgress = item.rotProgress;
            }
        }
    }
}


There are caveman debugging messages in the code which is how I tracked it to happening between the two stages, but I can't figure out why.

Saving works and it writes the "contents" as it should.
<thing Class="Building_Storage">
<def>RefrigeratedMealShelf</def>
<id>RefrigeratedMealShelf147715</id>
<pos>(128, 0, 54)</pos>
<rot>3</rot>
<health>100</health>
<stuff>Steel</stuff>
<faction>Colony915677562</faction>
<contents>
<li>
<thing>MealSimple314344</thing>
<HitPoints>50</HitPoints>
<rotProgress>39310</rotProgress>
</li>
<li>
<thing>MealSimple384145</thing>
<HitPoints>50</HitPoints>
<rotProgress>855</rotProgress>
</li>
</contents>
<parentThing>RopeLight149507</parentThing>
<keepOnTicks>180</keepOnTicks>
<curPower>-200</curPower>
<curUser>null</curUser>
<settings>
<priority>Important</priority>
<filter>
<disallowedSpecialFilters>
<li>AllowCorpsesColonist</li>
<li>AllowCorpsesStranger</li>
<li>AllowBuried</li>
</disallowedSpecialFilters>
<allowedDefs>
<li>MealNutrientPaste</li>
<li>MealSimple</li>
<li>MealFine</li>
<li>MealLavish</li>
</allowedDefs>
<allowedHitPointsPercents>0~1</allowedHitPointsPercents>
<allowedQualityLevels>Awful~Legendary</allowedQualityLevels>
</filter>
</settings>
</thing>


And the meals exist in the save file:
<thing Class="Meal">
<def>MealSimple</def>
<id>MealSimple314344</id>
<pos>(128, 0, 54)</pos>
<health>50</health>
<stackCount>10</stackCount>
<rotProg>39310</rotProg>
<ingredients>
<li>WildBoar_Meat</li>
<li>Muffalo_Meat</li>
<li>Squirrel_Meat</li>
</ingredients>
</thing>
<thing Class="Meal">
<def>MealSimple</def>
<id>MealSimple384145</id>
<pos>(128, 0, 55)</pos>
<health>50</health>
<stackCount>2</stackCount>
<rotProg>855</rotProg>
<ingredients>
<li>Squirrel_Meat</li>
<li>WildBoar_Meat</li>
</ingredients>
</thing>


The full error log (less spam) of this problem:
RefrigeratedMealShelf147715::PostExposeData() {
ScribeMode: LoadingVars
RefrigeratorContents::ExposeData() {
ScribeMode: LoadingVars
} // RefrigeratorContents
RefrigeratorContents::ExposeData() {
ScribeMode: LoadingVars
} // RefrigeratorContents
} // RefrigeratedMealShelf147715::PostExposeData()
RefrigeratedMealShelf147715::PostExposeData() {
ScribeMode: ResolvingCrossRefs
} // RefrigeratedMealShelf147715::PostExposeData()
Misaligned load ID request. Requests didn't match between the LoadingVars and ResolvingCrossRefs stage. Id MealSimple384145 was entered as a Verse.Thing but is being read as a Verse.Pawn.
Exception getting object with load id MealSimple384145 of type Verse.Pawn. What we loaded was MealSimple384145. Exception:
System.InvalidCastException: Cannot cast from source type to destination type.

  at (wrapper managed-to-native) object:__icall_wrapper_mono_object_castclass (object,intptr)

  at Verse.LoadedObjectDirectory.ObjectWithLoadID[Pawn] (System.String loadID) [0x00000] in <filename unknown>:0
RefrigeratorContents::ExposeData() {
ScribeMode: ResolvingCrossRefs
} // RefrigeratorContents
RefrigeratorContents::ExposeData() {
ScribeMode: ResolvingCrossRefs
Misaligned load ID request. Requests didn't match between the LoadingVars and ResolvingCrossRefs stage. Id null was entered as a Verse.Pawn but is being read as a Verse.Thing.
} // RefrigeratorContents
RefrigeratorContents::ExposeData() {
ScribeMode: PostLoadInit
} // RefrigeratorContents
RefrigeratorContents::ExposeData() {
ScribeMode: PostLoadInit
} // RefrigeratorContents
RefrigeratedMealShelf147715::PostExposeData() {
ScribeMode: PostLoadInit
} // RefrigeratedMealShelf147715::PostExposeData()


Anyone with any thoughts?
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

mrofa

Try this in expose data
Scribe_References.LookReference<Thing>(ref this.thing, "thing");
All i do is clutter all around.

1000101

(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

mipen

Have you tried looking into how ThingContainer saves its contents? Also check the scribe references method and see if it is trying to cast the result as a pawn for some reason.

mrofa

Not sure if you solved it or not but i think it this case you could add a method in tick or spawn  to find it via id number and save only the id number.
Thrugh its strictly theoretical since i didnt really play with comps yet.

But from my experiance with bookshelf, saving Things and Pawns is very problematic :/
All i do is clutter all around.

RawCode

It will throw exception before any tick can happen, there is no way to fix such error "after" load.

There is only location in code that allow both null and arbitrary load type -LookReference<T> and only at LoadSaveMode.LoadingVars stage.

Provide complete code + savefile for deep inspection, current error message indicate data corruption, at "RegisterLoadIDReadFromXml" stage (few steps before).

1000101

Well, this isn't actually solved as far as the scribe error is concerned, but I managed to do a work around by storing the thingID and resolving it later in a tick.

No matter what I did, Scribe_References<Thing> would just cause errors.  I'm using it in other places for pawns without issue, why a Thing would cause an issue, I don't know.  Bug perhaps?

Anyway, works now, thanks for your help people.  :)
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By

Tynan

There's actually a very difficult bug in the scribe references loader. I haven't been able to fix yet after several days of effort.

But -

The workaround is to do all Scribe_References operations after all Scribe_Values. In fact, in general, do all references after all values. That's what I tend to do now.
Tynan Sylvester - @TynanSylvester - Tynan's Blog

1000101

I'll give it a shot, thanks for personally responding.  :)
(2*b)||!(2*b) - That is the question.
There are 10 kinds of people in this world - those that understand binary and those that don't.

Powered By