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 - Razuhl

#1
RIMMSqol

Topics

In-Game modding, Pawn customization(skillpoints or unrestricted), Map search, QOL Settings, Food management, Pathfinding, Bug Fixes, Performance improvements.

Description:

Alter the settings of game objects

You will no longer be dependant on people balancing their mods or your specific mod combination. This mod allows you to change the settings of e.g. floors or power buildings via a graphical user interface in the mod menu.

Editable objects

  • floors and terrain
  • power buildings(power consumption/generation)
  • recipes
  • thoughts
  • apparel
  • plants
  • materials
  • food items
  • resource rocks
  • main buttons(reorder and hide/show)
  • architect buttons
  • buildings
  • hediffs
  • races
  • traits

QOL Settings/Bug Fixes/Performance


  • Turn off experience decay
  • Turn off tameness/training decay
  • Disable tracking of animal families
  • Leveling up/down displays an icon depicting the skill on the pawn
  • Level ups are tracked as thoughts for half a day
  • Fixes ingredient search to improve performance on recipes that limit the search range
  • Faster garbage collection for global pawns
  • Replace numeric inputs with bug free versions
  • Fixes ingredient consumption to prevent loss of material
  • Fixes movement speed on tiles above 100% movement speed
  • Icons for menues on architect buttons

Configurable Pathfinding

Pathfinding is split into 4 categories: Colonists, Tame Animals, Wild Animals and Other.
For each category a pathfinding algorithm can be selected and configured. Thus allowing the user to distribute his performance however it is desired.

Algorithms:
A*, accepts a number as configuration. Up until that distance the pathfinding will be precise(vanilla like setting would be 40), beyond that distance the pathfinding speeds up but no longer gurantees the best path. Unlike vanilla it accounts for transitional costs(moving from e.g. sandbag to sandbag is faster and moving from door to door is slower).

Restrict Movement

When using custom pathfinding each cell can be restricted so that it can only be traversed in specific directions. This allows building one way passages or direct the flow through the colony. Only colonist and tame animals respect these rules. Mustered colonists and colonists that perform specific jobs are unaffected(e.g. ,,BeatingFire" jobs). The jobs are configurable under "general settings".

The restrictions are defined using two designators. The ,,Smart Lines" designator is a linear drag operation. The direction of the drag determines the direction for cell movement that gets toggled on all but the last cell. This is a fast way to setup ,,highways" and offshoots. With the ,,Fill" designator selected restrictions can be pasted into a rectangle area, allowing full control but more micro intensive than ,,Smart Lines".

Careful with imprisoning pawns through cutting of all access. Thats the job of vanilla areas. Pawns will try to perform jobs that they can not reach since the decision of reachability does not inspect cells only rooms.

Customize ur Minions

Colonists gain personal growth points through their actions. Those points can be spent to alter backstories, traits and passions. The look and relations of a pawn can be changed for free.

Points are earned from the pawns records and the amount can be changed in the mod settings. By default each human kill is worth 1 point and each full year in the colony is worth 20 points. The pawns will have a "points spent" record which is worth -1 and is therefore reducing the number of points available. The base cost can be altered and the conversion factor for transferring points from a pawn to the pool. Turning a pawn into a remnant will put some points based on the colonists worth into the pool.

Changeable Features

  • Backstories
  • Traits
  • Passions
  • Hair
  • Head
  • Bodytype
  • Skincolor
  • Relations
  • Name
  • Gender
  • Age

If the goal is to use the edit feature unrestrained then set the base cost in the mod menu's general section to zero.

Where To Find

Search for stuff on the map(ore, items, animals, etc.) via its name. Cycle with left click through stacks or select up to 80 stacks with right click. Filter for forbidden items to quickly sort out the raid loot or hunt down that pesky beaver that you missed the first time around.

When using god mode a selection option to destroy all selected items is displayed.

Remnant Colonies(to be replaced)

Abandoned settlements become interactable settlements that are managed by the people left behind. They can be called via the comms console. If used with an old save a new comms console must be built.

Food and Restrictions

A preset ruleset determining who can do what with food and serve to manage the wide variety of food items. It can be used through an animated forbid/unforbid icon in the "assign" menu.


  • Restrict faction members from eating ingredients - This prevents your colonists and animals from eating raw food before you get a chance to refine it for more nutrition. Useful if the colony is on the brink of starvation.
  • Restrict non starving faction members from feeding or eating preserved food - With this you can stockpile preserved food for caravans without fearing it may be victimized at the next birthday party.
  • Restrict non starving colonists with mood above minor break threshold from eating meals better than simple - only use good food if necessary.
  • Restrict non starving colonists with ascetics trait from eating better than simple meals - just for roleplayers
  • Restrict non starving faction animals from eating meals - no more hens gorging themselfs on the good stuff.
  • Restrict non starving non colonist prisoners not marked for recruiting from eating meals better than simple - prison food the texan way.
  • Restrict non starving non colonist prisoners marked for recruiting with mood above 80% from eating meals better than simple - let them eat cake so you can put them to work sooner.

Customizable Menus

Main Menu

In the mod settings is a category for main buttons. There you can find the DDs which have a special property called buttons.
It's a list of other main buttons that will be displayed in a dropdown menu when clicking the button. By default the DDs are hidden and must be toggled visible.
Buttons that were added to a DD will not automatically be invisible. You have to hide them if you wan't them exclusively under the DD menu.

Architect Menu

In the mod settings is a category for architect buttons. There you can change the order and visibility of architect categories as well as which designators buttons appear in each category. The building buttons are defined
in the mod settings under the category buildings. Each building can define an "architect category" and an "architect category dropdown". The dropdown groups all buildings in the same category and dropdown together. Unlike
in vanilla buildings with material selection can be grouped as well. When using the button each click cycles between building selection and material selection.

Avoid Designator Refresh

In the mod menu settings under the general category is an option to avoid the refreshing of architect buttons. Some mods(e.g. AllowTool mods) use custom buttons that are not reloaded when vanilla buttons reload.
Those buttons will vanish, until a restart takes place, when changing anything in the mod menu. Once you are done with changing the architect buttons it is useful to activate this setting to avoid the problem.

Compatibility

The mod allows the user to activate/deactivate all code groups that might interfere with other mods. You can therefore decide to sacrifice a subset of funtionality to keep it compatible with any other mod. Think of it as deactivating a mod in a mod pack. The groups are deactivated in the general category of the mod settings under "forbidden patches".

Author

Razuhl

Download

Steam Workshop

License

Can modpack makers include your mod in their modpack? No.
Can other modders make derivative mods based on yours? No.
#2
When a pawn thinks about performing a recipe a search will be started that looks at the regions around the workbench(near to far). In the recipes configuration dialog the user can set a maximum distance at which ingredients are used. The search now moves through regions until it has found ingredients that are within the maximum distance or until the entire map has been explored(and in consequence every haulable item on the map). The region traversal completely ignores the fact that a region outside the maximum distance can not have relevant items.

This behaviour can be fixed by extending the region entry condition in WorkGiver_DoBill.TryFindBestBillIngredients with a test whether the region overlaps with the circle describing the allowed distance.


//set to maximum so no restriction
if ( Math.Abs(Bill.MaxIngredientSearchRadius - bill.ingredientSearchRadius) < 1f ) entryCondition = (Region from, Region r) => r.Allows(traverseParams, false);
else entryCondition = (Region from, Region r) => {
if ( !r.Allows(traverseParams, false) ) return false;
//check if the distance restriction touches the regions rect.
CellRect rect = r.extentsClose;
int DeltaX = Math.Abs(billGiver.Position.x - Math.Max(rect.minX, Math.Min(billGiver.Position.x, rect.maxX)));
if ( DeltaX > bill.ingredientSearchRadius ) return false;
int DeltaY = Math.Abs(billGiver.Position.z - Math.Max(rect.minZ, Math.Min(billGiver.Position.z, rect.maxZ)));
if ( DeltaY > bill.ingredientSearchRadius ) return false;
return (DeltaX * DeltaX + DeltaY * DeltaY) <= (bill.ingredientSearchRadius * bill.ingredientSearchRadius);
};


The behaviour can be observed by loading a game with a working colony(do not unpause). Then turning on the "Draw Region Traversal" option in the debug menu. Now a recipe is edited to have a distance limit in which no ingredients are found. Right clicking the corresponding workbench with a pawn that can do the recipe will light up the entire map. Alternatively if ingredients are found the search ends early but it doesn't end if all explored regions are past the distance limit.

With the fix in place only regions inside the limited area are searched even if no ingredients are found.
#3
Bugs / Wasteful memory allocations in PathFinder
April 12, 2018, 12:36:43 AM
The Verse.AI.PathFinder class is instanced for each map and each instance holds a variable calcGrid. This variable contains an entry for every cell on the map, containing a structure used in the pathfinding.

The data stored in the calcGrid is however independant from the map. By placing the sequences statusOpenValue and statusClosedValue and the calcGrid in a static context only one grid big enough for the largest map encountered is necessary instead of creating a seperate grid for each map.

A map with size 256x256 reserves slightly more than 1MB just for this.
#4
Bugs / A18 bugged save state for DefMaps
November 15, 2017, 09:13:52 PM
Add a new RecordDef, load a save where the definition did not exist yet, open the records page for a pawn. The page is not rendered since the defmap storing the records for a pawn runs into an index out of bounds error.
The same happens for WorkTypeDef and the "work" window.
Its untested but modding JoyKindDef and TrainableDef should also cause errors since DefMaps for those exist in IExposable objects.

Those out of bounds are however just one of the bugs that DefMaps are prone to. Changing the order of definitions inside an xml file moves the saved values to the wrong definition. So basically removing, adding or reordering cause the save state to fail.

The cause of the problem is that DefMaps only save values and not the corresponding keys. At the same time the assumption is made that the corresponding database(Defs) never change in order or quantity.

I fixed the issue with HarmonyPatches for my mod but I would be much easier to fix it in the main branch. Here is the code for reference.


static public class DefMapSaveStateFix
{
static public void Postfix<T,K>(DefMap<T, K> __instance) where T : Def, new() where K : new() {
if (Scribe.mode == LoadSaveMode.Saving) {
List<string> keys = new List<string>();
foreach ( T def in DefDatabase<T>.AllDefsListForReading.OrderBy(e=>e.index) ) {
keys.Add(def.defName);
}
Scribe_Collections.Look<string>(ref keys, "keys", LookMode.Undefined, new object[0]);
} else {
//grabbing the values via reflection. The llokup can be cached per load for performance.
System.Reflection.FieldInfo fi = __instance.GetType().GetField("values", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
List<K> values = (List<K>)fi.GetValue(__instance);
List<string> keys = new List<string>();
Scribe_Collections.Look<string>(ref keys, "keys", LookMode.Undefined, new object[0]);
//we only need to save and calculate the keys once per save. To keep the patch simple we save it multiple times
List<int> valueMapping = new List<int>(values.Count);
if ( keys.NullOrEmpty() ) { //old save without keys, we must assume the order is matching the database ordering
for ( int index = 0; index < values.Count; index++ ) {
valueMapping.Add(index);
}
} else {
foreach ( string defName in keys ) {
T def = DefDatabase<T>.GetNamed(defName, false);
if ( def == null ) {
//we no longer use the value specified at this index.
valueMapping.Add(-1);
} else {
valueMapping.Add(def.index);
}
}
}

List<K> oldValues = new List<K>(values.Count);
oldValues.AddRange(values);
values.Clear();
//fill the list until it has enough entries
foreach ( T def in DefDatabase<T>.AllDefsListForReading.OrderBy(e=>e.index) ) {
values.Add(default(K));
}
//assign the saved values to the right spot
for ( int index = 0; index < valueMapping.Count; index++ ) {
if ( valueMapping[index] >= 0 ) {
values[valueMapping[index]] = oldValues[index];
}
}
}
}
}

[HarmonyPatch(typeof(DefMap<RecordDef, float>))]
[HarmonyPatch("ExposeData")]
static public class DefMapSaveStateFixRecordDef
{
static void Postfix(DefMap<RecordDef, float> __instance) {
DefMapSaveStateFix.Postfix<RecordDef,float>(__instance);
}
}

[HarmonyPatch(typeof(DefMap<WorkTypeDef, int>))]
[HarmonyPatch("ExposeData")]
static public class DefMapSaveStateFixWorkTypeDef
{
static void Postfix(DefMap<WorkTypeDef, int> __instance) {
DefMapSaveStateFix.Postfix<WorkTypeDef,int>(__instance);
}
}
#5
In the class ThoughtDef the getter method for Label is missing a negation in an if check regarding the thoughts stages. Currently the thoughts stages get accessed if they are null or empty instead of only being accessed if they are not.

      public string Label {
         get {
            if (!this.label.NullOrEmpty()) {
               return this.label;
            }
            if (this.stages.NullOrEmpty<ThoughtStage>()) {
               if (!this.stages[0].label.NullOrEmpty()) {
                  return this.stages[0].label;
               }
               if (!this.stages[0].labelSocial.NullOrEmpty()) {
                  return this.stages[0].labelSocial;
               }
            }
            Log.Error("Cannot get good label for ThoughtDef " + this.defName);
            return this.defName;
         }
      }

The line in red should read:
if (!this.stages.NullOrEmpty<ThoughtStage>()) {