Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Fluffy (l2032)

#1
Enums are hardcoded and make modding harder. Please consider replacing this enum with a def-based system. I do realize that this might be a performance-sensitive area, but perhaps something smart could be done. For example, generating a bitmask from defs at game start should be possible?
#2
Enums are hardcoded and make modding harder. Please consider replacing this enum with a def.
#3
I would expect this function to allow custom logic for when to allow placing over things. Instead, it is only ever called when placing objects over a Steam Geyser.

I have to assume that this is not working as intended, or otherwise, the virtual(!) function is severely mislabeled.
#4
Unfinished / [WIP] Mod Manager
September 14, 2018, 06:56:28 PM
I've been working on a more flexible mod config screen, and I'd like your feedback!

The current version is rough, and not all functionality is implemented. Here's what it does;
- Two side-by-side lists of mods, available and active
- search (filter) both lists (with an option to highlight matches (vanilla way, default for active), or only show matches (more useful for large lists, default for avaiable)).
- drag and drop activate and reorder
- keyboard navigation (tab switches between filters and lists, arrows select mods, enter activates/deactives - there is currently no way to reorder)
- deals with multiple versions of the same mod (click the little icons to switch between versions).
- create local copies of steam mods (icon in bottom right)
- delete local mods

What I plan to implement;
- finetune/expand keyboard navigation
- create/load modlists
- mass create local copies of all steam mods in your mod list
- ModSync integration (either modsync itself, or a similar approach)

Current issues;
Translation strings are not yet set, so you'll see weird (but readable) characters, much shorter tooltips, etc.

[attachment deleted due to age]
#5
Unfinished / test 2
September 12, 2018, 04:24:59 AM
still a test
#6
Please keep any discussion civil and to the point.

#7
Problem description;
RequestHash uses the short hash of the buildableDef, optionally adjusted with the hash of the stuffdef, to cache the production costs of a buildableDef/stuffDef combinations.

There's two ways collisions can slip in here. First, buildableDefs can be either TerrainDef or ThingDef, each has their own hashtable - so the sets of hashes may overlap. Second, by offsetting with the stuff used, we're deviating from the unique hashes enforced while originally handing out hashes, again introducing a risk of collisions.

Reproduction;
I ran into this issue with the following defs;
MultiAnalyzer
Jade_StuffedStoneRoughTiles

You can test by adding my StuffedFloors mod (which requires ArchitectSense), and trying to build the jade rough stone tiles and the multianalyzer. Whichever you look at first will be the cost for the other as well.


[attachment deleted by admin due to age]
#8
Problem description;
ThoughtMaker.MakeThought( ThoughtDef, int ), applies the stage after Init() is called. This is a problem for thoughts that have the Thought_MemorySocial worker class, and have multiple stages.

(to my knowledge, this combination doesn't exist in vanilla so, for now, it's mostly a modding problem).


Specifically, ThoughtMaker has the following method;

public static Thought_Memory MakeThought(ThoughtDef def, int forcedStage)
{
Thought_Memory thought_Memory = (Thought_Memory)Activator.CreateInstance(def.ThoughtClass);
thought_Memory.def = def;
thought_Memory.Init();
thought_Memory.SetForcedStage(forcedStage);
return thought_Memory;
}
      

And Thought_MemorySocial has the following Init() method;
// RimWorld.Thought_MemorySocial
public override void Init()
{
base.Init();
this.opinionOffset = base.CurStage.baseOpinionOffset;
}


Since Init() is called before SetForcedStage(), which in turn sets CurStage, the opinionOffset will default to that of the zeroth stage, regardless of the forcedStage argument.

How to resolve;
Simply switch the Init() and SetForcedStage() lines.

#9
Description; as per title, and attached screenshot.
Steps to reproduce; make a pawn loose a limb.
Expected outcome; only the 'root' missing part is listed.

[attachment deleted by admin due to age]
#10
Help / A17; changes
May 06, 2017, 08:40:27 AM
Let's consolidate our efforts, and report changes in the modding API in this thread.

Patches
You can now use xpath selectors to surgically change properties in vanilla and other mods' defs - so you don't have to replace them!.
Some examples; https://gist.github.com/zorbathut/99a3858fafd2dc9bea8f685ed6b35556
Xpath selectors; https://msdn.microsoft.com/en-us/library/ms256086(v=vs.110).aspx

I'd like to invite Zorba and/or any modders that have tested this system to provide more examples and pointers.

Scribing
All the Scribe_XXX.LookXXX() methods are now just Scribe_XXX.Look(), API doesn't appear to have any further changes.

Under the hood, saving and loading of data has been split into two subcomponents of the Scribe; Scribe.loader & Scribe.saver. If you used Scribe to manually load/save data, you'll have to do some minor refactoring. API doesn't appear to have any further changes. Note that the addition of Settings (see below) might mean you don't need to manually call the scribe at all anymore.

Mod Class
There's now a 'Mod' class you can inherit from. It's a simple base class, which gets constructed after all defs are loaded. As such, it's a useful entry point, but it can't completely replace HugsLib's ModBase class (specifically, there's no hook for running code after this mod is loaded, but before other mods further down the list are loaded).

Settings Class
The Mod class also gives access to a Settings object. Settings can basically be anything (but not references to objects in a game!), you'll have to provide your own ExposeData method to save/load the data. You'll also need to provide a Mod.DoSettingsWindowContents() method to render the UI parts. As far as I can see, there's no default settings handlers for simple data types, but they're easy enough to make yourself (hint; Verse.Widgets, or Verse.Listing).

Components
GameComponent, WorldComponent, MapComponent
All of these now have a handy amount of virtual methods corresponding to various events in their lifecycles, making it much easier to attach data to the correct 'scope'. (e.g. attaching data to game/world/mapComponent to make sure it doesn't 'bleed' over when a player starts/loads another game, world, map). Finally, MapComponents are now injected into existing save games when the map is loaded and new mods are added! (or at least I think they are, that's what the code seems to imply).

MainTabs
'Pawn list' main tabs have been completely refactored, and are now def-based, with a def for each table and column. MainTabDefs themselves are now MainButtonDefs.

Commonality
ApparelProperties.commonality appears to have been refactored into ThingDef.generateCommonality. The same may be true for weapons, etc.
#11
Bugs / [A16] Modding: ResearchMod class broken.
January 09, 2017, 04:29:48 PM
There are two problems with researchMods;
1; The class itself is useless as a base class; the Apply() function is not virtual, and the specialAction field is private.
2; Assigning a researchMod type to the researchMods field in ResearchProjectDef XML leads to a 'Trying to parse to unknown data type' error.

Expected behaviour;
1; Apply() is virtual, and/or specialAction is public.
2; Setting workers in XML functions the same as setting workers for e.g. hediffs.
#12
If the steam version is loaded outside of steam it gives a popup stating this fact, and that the game will now close.

Pressing <Esc> completely ignores this, and allows playing the game as normal. Possibly the worst DRM ever :P.
#13
The in-game debug window cuts off the first line of output - this can be quite annoying, since the first line is often the most pertinent.

Replicate; clear the log, then log something.
#14
Problem:
Two different mods create custom Def class (that is class in the C# sense), with the same name, but in different namespaces.
The game errors during mod load, mod config is reset.

Expectation:
Since the classes are namespaced, there should be no conflict an the game should run fine.

Replication:
Load the attached mod. It does absolutely nothing, but highlights the problem.

Solution:
In Verse.XmlLoader.AllDefsFromAsset, change
typeof(Def).AllSubclasses().ToDictionary((Type x) => x.Name);
to
typeof(Def).AllSubclasses().ToDictionary((Type x) => x.FullName);

( there may be more changes to be made, but this is the source of the issue ).



[attachment deleted by admin - too old]
#15
In my latest mod, I'm trying to map colors to relationshipdefs. This works fine with a DefMap<PawnRelationDef, Color>, until I want to scribe the DefMap. The DefMap uses Scribe_Collections.LookList( x, x, LookMode.Undefined ) to automatically resolve to the correct mode, but for colors it erroneously picks LookMode.Deep.

Expected behaviour: LookMode.Undefined resolves to LookMode.Value for Color objects.
#16
Help / [A13 and Assets loading]
April 08, 2016, 03:43:53 AM
The following is a breakdown from what others and I have found when trying to use textures in .dlls. This is by no means final information, as there's quite a few oddities going on that we don't understand. I'll try and keep this thread updated with new developments.

See also my bug report here.


definitely_not_fluffy [09:30]
ok so here's the breakdown

[09:30]
mods are loaded in a separate thread

[09:31]
which means any 'assets' (textures, sounds, materials, etc) won't load correctly

[09:31]
you get a vague 'couldn't find it' error, which is very misleading

[09:31]
there's theoretically two solutions

[09:32]
the first, and prefered solution is to put a [StaticConstructorOnStartup] attribute above any classes that have static resources defined in them

[09:32]
that ​_should_​ cause them to be loaded in hte main thread, before anything else

[09:32]
this doesn't actually appear to work however

[09:33]
the seond solution is to somehow defer loading of textures until after the main mod loading phase is complete

[09:33]
again, there's two ways

[09:33]
the first is to call LongEventHandler.ExecuteWhenFinished( Action ) in the constructor

[09:34]
if the mod is loaded in the asynchchronous thread, your action is then queued to be executed on the main thread after mod loading is complete

[09:34]
this works for me, but appears not to work for some others

[09:34]
the final solution is to not load textures at all until you need them

[09:34]
e.g. do an if (texture ==null) loadTexture kind of thing in the Draw() method (or something similar).

[09:35]
that's a bit risky, since if it fails, it'll keep failing very noisily

[09:35]
but the approach should work


And a little more background info from Ison through Skullywag on how it's supposed to work:
skullywag [11:59]
added a C# snippet
This happens because from now on mods are loaded in a different thread. This, combined with the fact that it's impossible to use Unity's functions like loading a texture in threads other than the main one, means that you get an error in such cases. Does your new class have any static resources like Texture, Material or Graphic? If so, it means that during loading the game, when an object of this class is loaded, its static constructor is called and the game tries to load a texture in a different thread. With StaticConstructorOnStartup attribute, class' static constructor is called in the main thread before loading everything else.
Add Comment
skullywag [12:00]
he also said this, which might mean something to you guys:
skullywag [12:00]
added a C# snippet
Making those Material fields non-static doesn't work, because they are instantiated from a different thread during loading an instance of Building_WindTurbineStuffed. You can also schedule a task to be executed from the main thread after the loading has finished like this: LongEventHandler.ExecuteWhenFinished(() => DoSomething()); but in your case you should just use static fields and [StaticConstructorOnStartup].
Add Comment
skullywag [12:01]
and heres the bit about the game laoding thingy
skullywag [12:01]
added a C# snippet
It's because static constructor is called only once when a class is first used, so it won't be called again until you restart the game. If a class is first used during gameplay (e.g. you build a wind turbine), then wind turbine's textures are loaded in the main thread so everything's fine, but if it's first used during loading (e.g. you try to load an instance of a wind turbine), then it throws errors because it tries to load a texture from a different thread.
Add Comment
definitely_not_fluffy [12:01]
that is actually an entrance point for bootstrapping right there, isn't it?
[12:02]
if we can set code to be run on main thread, we can get to gameobjects and everything
skullywag [12:02]
mebbe
[12:02]
like i said it might mean more to you guys than me (edited)
definitely_not_fluffy [12:02]
this is really good info to have, thanks!
#17
Steps to reproduce:

       
  • Create a mod with an assembly, add classes that contain static assets (textures, etc)
  • Add the [StaticConstructorOnStartup] tag
  • Try to use ContentFinder<>.Get() in the constructor
I've used the following snippet of code to obtain some test results; the rest of the class/mod can be found here: https://github.com/Karel-Kroeze/RW_Blueprints/

using RimWorld;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using Verse;


namespace Blueprints
{
    [StaticConstructorOnStartup]
    public class Designator_CreateBlueprint : Designator
    {
        #region Public Constructors


        public Designator_CreateBlueprint()
        {
            Log.Error( "INSTANTIATING NOW:\n" + System.Environment.StackTrace );
            Log.Message( "Types with static constructors:" );
            foreach ( var type in GenTypes.AllTypesWithAttribute<StaticConstructorOnStartup>() )
            {
                Log.Message( "\t" + type.FullName );
            }


            LongEventHandler.ExecuteWhenFinished( delegate
            {
                Resources.Icon_AddBlueprint = ContentFinder<Texture2D>.Get( "Icons/AddBlueprint", true );
                Resources.Icon_Blueprint = ContentFinder<Texture2D>.Get( "Icons/Blueprint", true );
                Resources.Icon_Edit = ContentFinder<Texture2D>.Get( "Icons/Edit", true );


                icon = Resources.Icon_AddBlueprint;
            } );


            defaultLabel = "Fluffy.Blueprints.Create".Translate();
            defaultDesc = "Fluffy.Blueprints.CreateHelp".Translate();
            useMouseIcon = true;
        }


        #endregion Public Constructors


// more code.
}
}

Note that the LongEventHandler.ExecuteWhenFinished call does work, and circumvents the issue.


The attached output log highlights the issue. The game is clearly aware that this type (and a few others) should have a static constructor, yet the stack trace shows that it is still instantiated from a secondary thread.

[attachment deleted by admin - too old]
#18
Off-Topic / Shellfish Advertising!
February 23, 2016, 02:09:40 AM
clams! oysters! Get them here straight outta the sea!  Shrimp, lobster, crayfish, and crabs! Fresh as can be!
#19
Bugs / Float menu option dropped on multi column
February 16, 2016, 06:33:38 PM
When the float menu options get wrapped over multiple columns, there is one too many option rendered in each column, resulting in an option being drawn outside of the floatmenu rect, and thus dropped.

The following line in Verse.FloatMenu.DoWindowContents( Rect ) ;

if ((double) num1 > (double) this.ColumnMaxOptionCount)
Where num1 is the current y or row index (decompilation artifact) should instead read;
if ((double) num1 >= (double) this.ColumnMaxOptionCount)

Also, why are two ints geting cast to doubles for a comparison? That seems like a recipe for trouble in and of itself.

#20
Alpacas are missing the <litterSize> tag, and hence cannot reproduce.