I have been working on making something with functionality similar to a hopper. In doing so, I have implemented the interface SlotGroupParent that seems to be responsible for storage in rimworld. I have implemented all the methods as they have been implemented in Building_Storage (I think, will add code below).
Here's where the issue is. I want to then implement the ITab_Storage so that users can designate what will be stored in the building.
XML Excerpt:
<fixedStorageSettings>
<priority>Normal</priority>
<allowances>
<categories>
<li>Manufactured</li>
<li>ResourcesRaw</li>
</categories>
</allowances>
</fixedStorageSettings>
<defaultStorageSettings>
<priority>Normal</priority>
<allowances>
<categories>
<li>Manufactured</li>
<li>ResourcesRaw</li>
</categories>
</allowances>
</defaultStorageSettings>
<inspectorTabs>
<li>UI.ITab_Storage</li>
</inspectorTabs>
Code implementing SlotGroupParent:
public class Accessor : DBuilding, SlotGroupParent
{
public Enum.accessorMode mode
{
get
{
return ((Digitisation.AccessorProperties)def).mode;
}
}
public int speed
{
get
{
return ((Digitisation.AccessorProperties)def).speed;
}
}
public ThingDef item;
public StorageSettings settings;
public SlotGroup slotGroup;
private List<IntVec3> cachedOccupiedSquares;
public override void SpawnSetup()
{
base.SpawnSetup();
slotGroup = new SlotGroup(this);
cachedOccupiedSquares = this.AllSlotSquares().ToList<IntVec3>();
}
public override void PostMake()
{
base.PostMake();
settings = new StorageSettings(this);
if (def.defaultStorageSettings != null)
settings.CopyFrom(def.defaultStorageSettings);
}
public override void Tick()
{
base.Tick();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Deep.LookDeep<StorageSettings>(ref settings, "settings", this);
}
public override void Destroy()
{
slotGroup.Notify_ParentDestroying();
base.Destroy();
}
public virtual IEnumerable<IntVec3> AllSlotSquares()
{
foreach (IntVec3 sq in GenAdj.SquaresOccupiedBy(this))
{
yield return sq;
}
}
public List<IntVec3> AllSlotSquaresListFast()
{
return cachedOccupiedSquares;
}
public StorageSettings GetParentStoreSettings()
{
return def.fixedStorageSettings;
}
public StorageSettings GetStoreSettings()
{
return settings;
}
public void Notify_LostThing(Thing newItem)
{
}
public void Notify_ReceivedThing(Thing newItem)
{
}
public string SlotYielderLabel()
{
return Label;
}
*note* DBuilding just extends Building
Now, when I click to open the UI the game's control freezes (colonists move in background but I can't click anything) and the log gets filled with the following over and over:
InvalidCastException: Cannot cast from source type to destination type.
at UI.ITab_Storage.FillTab () [0x00000] in <filename unknown>:0
at UI.ITab.DoTabGui () [0x00000] in <filename unknown>:0
at UI.InspectPane.DoTabs (IEnumerable`1 tabs) [0x00000] in <filename unknown>:0
at UI.InspectPane.InspectPaneOnGUI () [0x00000] in <filename unknown>:0
at UI.TabInspect.PanelOnGUI (Rect fillRect) [0x00000] in <filename unknown>:0
at UI.UIPanel.PanelOnGUI () [0x00000] in <filename unknown>:0
at UI.MainTabsRoot.GameControlsOnGUI () [0x00000] in <filename unknown>:0
at UI.UIMapRoot.UIRootOnGUI () [0x00000] in <filename unknown>:0
at Root.OnGUI () [0x00000] in <filename unknown>:0
(Filename: Line: -1)
Not sure what I'm doing wrong or what's really going on here. Any help at all would be appreciated.
This is the FillTab code. All I could suggest is that you're passing something that is not a SlotGroupParent and it fails on the cast to SlotGroupParent. Make sure your thing is actually using the correct ThingClass.
protected override void FillTab()
{
KnowledgeDatabase.KnowledgeDemonstrated( ConceptDefOf.StorageTab, KnowledgeAmount.GuiFrame );
Find.ConceptTracker.TeachOpportunity( ConceptDefOf.StorageTabCategories, OpportunityType.GuiFrame );
Find.ConceptTracker.TeachOpportunity( ConceptDefOf.StoragePriority, OpportunityType.GuiFrame );
StorageSettings settings = ((SlotGroupParent)Find.Selector.Selected.First()).GetStoreSettings();
Rect inRect = new Rect(0,0,WinSize.x, WinSize.y).GetInnerRect(GenUI.Pad);
GUI.BeginGroup(inRect);
{
//Priority setting
{
GenFont.SetFontSmall();
Rect labRect = new Rect(0,0,150,TopAreaHeight-6);
GUI.Label( labRect, "Priority".Translate() + ": " );
Rect butRect = new Rect(100,0,130,TopAreaHeight-6);
if( Widgets.TextButton( butRect, settings.priority.Label() ) )
{
List<FloatMenuOption> opts = new List<FloatMenuOption>();
foreach( StoragePriority pr in System.Enum.GetValues( typeof(StoragePriority)))
{
if( pr == StoragePriority.Unstored )
continue;
StoragePriority localPr = pr;
opts.Add( new FloatMenuOption( localPr.Label(), ()=>
{
settings.priority = localPr;
KnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.StoragePriority, KnowledgeAmount.Total);
}) );
}
Find.LayerStack.Add( new Layer_FloatMenu(opts) );
}
TutorUIHighlighter.HighlightOpportunity( "StoragePriority", butRect );
}
ThingFilter parentAllowances = null;
if (settings.owner.GetParentStoreSettings() != null)
parentAllowances = settings.owner.GetParentStoreSettings().allowances;
//Configure allowances
Rect outRect = new Rect(0,TopAreaHeight,inRect.width,inRect.height-TopAreaHeight);
ThingFilterGui.DoThingFilterConfigWindow( outRect,
ref scrollPosition,
settings.allowances,
parentAllowances);
}
GUI.EndGroup();
}