├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report_0high.md │ ├── bug_report_1med.md │ ├── bug_report_2low.md │ ├── bug_report_3lowest.md │ └── reproducible-community-modpack-bug-report--medium-priority-.md ├── .gitignore ├── LICENSE ├── README.md ├── RimThreaded ├── 1.3 │ └── Assemblies │ │ ├── RimThreaded.dll │ │ ├── RimThreaded.pdb │ │ ├── ThreadSafeLinkedList.dll │ │ ├── ThreadSafeLinkedListRW.dll │ │ ├── Unity.Newtonsoft.Json.dll │ │ └── replacements_1.3.json └── About │ ├── About.xml │ ├── Preview.png │ └── PublishedFileId.txt ├── Source ├── AssemblyCache.cs ├── CustomTickList.cs ├── HaulingCache.cs ├── JumboCell.cs ├── JumboCell_Cache.cs ├── MethodLocker.cs ├── Mod_Patches │ ├── AlienRace_Patch.cs │ ├── AndroidTiers_Patch.cs │ ├── AwesomeInventory_Patch.cs │ ├── Better_Message_Placement_Patch.cs │ ├── CE_Utility_Transpile.cs │ ├── Children_Patch.cs │ ├── CombatExteneded_Patch.cs │ ├── CompUtility_Transpile.cs │ ├── DubsBadHygiene.cs │ ├── DubsSkylight_getPatch_Transpile.cs │ ├── Dubs_Skylight_Patch.cs │ ├── Fluffy_Breakdowns_Patch.cs │ ├── GeneratePawns_Patch_Transpile.cs │ ├── GiddyUpCore_Patch.cs │ ├── Hospitality_Patch.cs │ ├── JobDriver_Mounted_Transpile.cs │ ├── JobGiver_FindItemByRadius_Transpile.cs │ ├── JobsOfOppurtunity_Patch.cs │ ├── MapReroll_Patch.cs │ ├── PawnComponentsUtility_Patch.cs │ ├── PawnRules_Patch.cs │ ├── ProjectileCE_Transpile.cs │ ├── RimWar_Patch.cs │ ├── SOS2_Patch.cs │ ├── SpeakUp_Patch.cs │ ├── TD_Enhancement_Patch.cs │ ├── TextureUtility_Transpile.cs │ ├── TurnItOnAndOff_Patch.cs │ ├── VEE_Patch.cs │ ├── Verb_LaunchProjectileCE_Transpile.cs │ ├── Verb_MeleeAttackCE_Transpile.cs │ ├── WorkGiver_ConstructDeliverResources_Transpile.cs │ ├── ZombieLand_Patch.cs │ └── childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch_Transpile.cs ├── OneTickPool.cs ├── Patch_TryOpportunisticJob.cs ├── PlantHarvest_Cache.cs ├── PlantSowing_Cache.cs ├── PulsePool.cs ├── RW_Patches │ ├── Alert_ColonistLeftUnburied_Patch.cs │ ├── Alert_MinorBreakRisk_Patch.cs │ ├── AlertsReadout_Patch.cs │ ├── ApparelGraphicRecordGetter_Patch.cs │ ├── Archive_Patch.cs │ ├── Area_Patch.cs │ ├── AttackTargetReservationManager_Patch.cs │ ├── AttackTargetsCache_Patch.cs │ ├── AudioSourceMaker_Patch.cs │ ├── AudioSource_Patch.cs │ ├── BattleLog_Transpile.cs │ ├── Battle_Patch.cs │ ├── BeautyUtility_Patch.cs │ ├── BiomeDef_Patch.cs │ ├── BodyDef_Patch.cs │ ├── Building_Bed_Patch.cs │ ├── Building_Door_Patch.cs │ ├── Building_PlantGrower_Patch.cs │ ├── Camera_Patch.cs │ ├── CellFinder_Patch.cs │ ├── ColoredText_Patch.cs │ ├── CompCauseGameCondition_Patch.cs │ ├── CompForbiddable_Patch.cs │ ├── CompSpawnSubplant_Transpile.cs │ ├── Component_Patch.cs │ ├── ContentFinder_Texture2D_Patch.cs │ ├── Corpse_Patch.cs │ ├── DateNotifier_Patch.cs │ ├── DesignationManager_Patch.cs │ ├── Designator_Haul_Patch.cs │ ├── Dijkstra_Patch.cs │ ├── District_Patch.cs │ ├── DrugAIUtility_Patch.cs │ ├── DynamicDrawManager_Patch.cs │ ├── FactionManager_Patch.cs │ ├── FilthMaker_Patch.cs │ ├── FireUtility_Patch.cs │ ├── FleckStatic_Patch.cs │ ├── FleckSystemBase_Patch.cs │ ├── FloodFiller_Patch.cs │ ├── FoodUtility_Patch.cs │ ├── FullPool_Patch.cs │ ├── GUIStyle_Patch.cs │ ├── GameObject_Patch.cs │ ├── GenClosest_Patch.cs │ ├── GenCollection_Patch.cs │ ├── GenDraw_Patch.cs │ ├── GenGrid_Patch.cs │ ├── GenPlace_Patch.cs │ ├── GenSpawn_Patch.cs │ ├── GenTemperature_Patch.cs │ ├── GenTypes_Patch.cs │ ├── GlobalControlsUtility_Patch.cs │ ├── GoodwillSituationManager_Patch.cs │ ├── GoodwillSituationWorker_MemeCompatibility_Patch.cs │ ├── GrammarResolver_Patch.cs │ ├── GraphicDatabaseHeadRecords_Patch.cs │ ├── GraphicDatabase_Patch.cs │ ├── GraphicsFormatUtility_Patch.cs │ ├── Graphics_Patch.cs │ ├── GridsUtility_Patch.cs │ ├── Hauling_Transpile.cs │ ├── HediffGiver_Heat_Patch.cs │ ├── HediffGiver_Hypothermia_Patch.cs │ ├── HediffGiver_Hypothermia_Transpile.cs │ ├── HediffSet_Patch.cs │ ├── HistoryEventsManager_Patch.cs │ ├── IdeoManager_Patch.cs │ ├── ImmunityHandler_Patch.cs │ ├── JobDriver_TendPatient_Patch.cs │ ├── JobGiver_ExitMap_Patch.cs │ ├── JobGiver_WanderNearDutyLocation_Patch.cs │ ├── JobGiver_Work_Patch.cs │ ├── JobMaker_Patch.cs │ ├── JobQueue_Patch.cs │ ├── LightningBoltMeshMaker_Patch.cs │ ├── ListerBuildingsRepairable_Patch.cs │ ├── ListerThings_Patch.cs │ ├── ListerThings_Transpile.cs │ ├── LongEventHandler_Patch.cs │ ├── LordManager_Patch.cs │ ├── LordToil_Siege_Patch.cs │ ├── Lord_Patch.cs │ ├── MapGenerator_Patch.cs │ ├── MapPawns_Patch.cs │ ├── MapPawns_Transpile.cs │ ├── Map_Patch.cs │ ├── Map_Transpile.cs │ ├── MaterialPool_Patch.cs │ ├── Material_Patch.cs │ ├── MeditationFocusTypeAvailabilityCache_Patch.cs │ ├── MemoryThoughtHandler_Patch.cs │ ├── MemoryUtility_Patch.cs │ ├── MeshMakerPlanes_Patch.cs │ ├── MeshMakerShadows_Patch.cs │ ├── Mesh_Transpile.cs │ ├── Messages_Patch.cs │ ├── MoteBubble_Patch.cs │ ├── OverlayDrawer_Patch.cs │ ├── Patch_TryOpportunisticJob_Transpile.cs │ ├── PathFinder_Patch.cs │ ├── PawnCapacitiesHandler_Patch.cs │ ├── PawnCapacityUtility_Patch.cs │ ├── PawnCollisionTweenerUtility_Patch.cs │ ├── PawnDestinationReservationManager_Patch.cs │ ├── PawnPathPool_Patch.cs │ ├── PawnPath_Patch.cs │ ├── PawnTextureAtlas_Patch.cs │ ├── PawnUtility_Patch.cs │ ├── Pawn_ApparelTracker_Patch.cs │ ├── Pawn_HealthTracker_Patch.cs │ ├── Pawn_JobTracker_DetermineNextJob_Transpile.cs │ ├── Pawn_JobTracker_Patch.cs │ ├── Pawn_MindState_Patch.cs │ ├── Pawn_Patch.cs │ ├── Pawn_PathFollower_Patch.cs │ ├── Pawn_PlayerSettings_Patch.cs │ ├── Pawn_RelationsTracker_Patch.cs │ ├── Pawn_RotationTracker_Patch.cs │ ├── PhysicalInteractionReservationManager_Patch.cs │ ├── Plant_Patch.cs │ ├── PlayLog_Patch.cs │ ├── PortraitsCache_Patch.cs │ ├── Rand_Patch.cs │ ├── ReachabilityCache_Patch.cs │ ├── Reachability_Patch.cs │ ├── RealtimeMoteList_Patch.cs │ ├── RecipeWorkerCounter_Patch.cs │ ├── RecordWorker_TimeGettingJoy_Patch.cs │ ├── RegionAndRoomQuery_Patch.cs │ ├── RegionAndRoomUpdater_Patch.cs │ ├── RegionDirtyer_Patch.cs │ ├── RegionGrid_Patch.cs │ ├── RegionLinkDatabase_Patch.cs │ ├── RegionLink_Patch.cs │ ├── RegionMaker_Patch.cs │ ├── RegionTraverser_Patch.cs │ ├── Region_Patch.cs │ ├── RenderTexture_Patch.cs │ ├── ReservationManager_Patch.cs │ ├── ResourceCounter_Patch.cs │ ├── Resources_Patch.cs │ ├── RestUtility_Patch.cs │ ├── RimWorld_Pawn_GuestTracker_SetGuestStatus_Transpile.cs │ ├── RitualObligationTargetWorker_AnyEmptyGrave_Patch.cs │ ├── RitualObligationTargetWorker_GraveWithTarget_Patch.cs │ ├── RoofGrid_Patch.cs │ ├── Room_Patch.cs │ ├── RulePackDef_Patch.cs │ ├── SampleSustainer_Patch.cs │ ├── SeasonUtility_Patch.cs │ ├── SectionLayer_Patch.cs │ ├── ShootLeanUtility_Patch.cs │ ├── SimplePool_Patch.cs │ ├── SituationalThoughtHandler_Patch.cs │ ├── SlateRef_Patch.cs │ ├── SoundSizeAggregator_Patch.cs │ ├── SoundStarter_Patch.cs │ ├── StatWorker_Patch.cs │ ├── SteadyEnvironmentEffects_Patch.cs │ ├── StoreUtility_Patch.cs │ ├── StoryState_Patch.cs │ ├── SubSoundDef_Patch.cs │ ├── SustainerManager_Patch.cs │ ├── Sustainer_Patch.cs │ ├── TaleManager_Patch.cs │ ├── Text_Patch.cs │ ├── Texture2D_Patch.cs │ ├── Texture_Patch.cs │ ├── ThingGrid_Patch.cs │ ├── ThingOwnerThing_Patch.cs │ ├── ThingOwnerUtility_Patch.cs │ ├── Thing_Patch.cs │ ├── ThinkNode_ForbidOutsideFlagRadius_Patch.cs │ ├── ThinkNode_JoinVoluntarilyJoinableLord_Patch.cs │ ├── ThinkNode_SubtreesByTag_Patch.cs │ ├── TickList_Patch.cs │ ├── TickManager_Patch.cs │ ├── TileTemperaturesComp_Patch.cs │ ├── TileTemperaturesComp_Transpile.cs │ ├── TimeControls_Patch.cs │ ├── Time_Patch.cs │ ├── Toils_Ingest_Patch.cs │ ├── TradeShip_Patch.cs │ ├── Transform_Patch.cs │ ├── TransportShipManager_Patch.cs │ ├── UniqueIDsManager_Patch.cs │ ├── UnityEngine_Object_Patch.cs │ ├── Verb_Patch.cs │ ├── WealthWatcher_Patch.cs │ ├── WildPlantSpawner_Patch.cs │ ├── WindManager_Patch.cs │ ├── WorkGiver_DoBill_Patch.cs │ ├── WorkGiver_DoBill_RegionProcessor.cs │ ├── WorkGiver_DoBill_Transpile.cs │ ├── WorkGiver_GrowerHarvest_Patch.cs │ ├── WorkGiver_GrowerSow_Patch.cs │ ├── WorkGiver_Grower_Patch.cs │ ├── WorkGiver_Scanner_Patch.cs │ ├── WorldComponentUtility_Patch.cs │ ├── WorldObjectsHolder_Patch.cs │ ├── WorldPawns_Patch.cs │ ├── World_Patch.cs │ ├── ZoneManager_Patch.cs │ ├── Zone_Growing_Patch.cs │ └── Zone_Patch.cs ├── RimThreaded.cs ├── RimThreaded.csproj ├── RimThreaded.sln ├── RimThreadedHarmony.cs ├── RimThreadedMod.cs ├── RimThreadedSettings.cs ├── packages.config └── replacements_1.4.json ├── configure.cmd └── configure.ps1 /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: #users 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: rimthreaded 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_0high.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Reproducible Vanilla Bug Report (High Priority) 3 | about: Submit a bug report that occurs in RimWorld running only RimThreaded and DLCs 4 | that can be reproduced fairly consistantly. 5 | title: '' 6 | labels: Bug, Reproducible, Vanilla RT 7 | assignees: '' 8 | 9 | --- 10 | 17 | 18 | 19 | ### Developer To Do Notes: 20 | - [ ] 21 | - [ ] 22 | - [ ] 23 | 24 | 25 | # **Vanilla Bug Report** 26 | 27 | ### **Describe the bug** 28 | ❗❗❗ bug description here ❗❗❗ 29 | 30 | ### **Steps to reproduce the behavior (VERY IMPORTANT)** 31 | 1. ❗❗❗ step 1 here ❗❗❗ 32 | 2. ❗❗❗ step 2 here ❗❗❗ 33 | 3. ❗❗❗ step 3 here ❗❗❗ 34 | 4. ❗❗❗ step 4 here ❗❗❗ 35 | 36 | ### **Error Logs** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#what-logs-should-my-bug-report-include) 37 | ```cs 38 | !!! You can copy paste an error here !!! 39 | ``` 40 | 41 | #### **HugsLib log** 42 | ❗❗❗ Link to HugsLib log. (MUST BE LINK) ❗❗❗ 43 | 44 | #### **Player.log (Optional)** 45 | ❗❗❗ Link to contents of Player.log or Error.log (MUST BE LINK) ❗❗❗ 46 | 47 | ### **Save file** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#how-do-i-attach-the-save-file-to-the-report) 48 | ❗❗❗ Please add a save file where the issue occurs to speed up testing and fixing of the issue ❗❗❗ 49 | 50 | ### **Screenshots (Optional)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#how-do-i-attach-a-screenshot-to-the-report) 51 | ❗❗❗ Add screenshots to help explain your problem here ❗❗❗ 52 | 53 | ### **Mod list (For vanilla report, it has to be same as below list.)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#what-mod-organizer-should-i-use) 54 | ``` 55 | [Mod list length: 6] 56 | Harmony [https://steamcommunity.com/sharedfiles/filedetails/?id=2009463077] 57 | Core [https:// no link (local mod)] 58 | Royalty [Official DLC] [https:// no link (local mod)] 59 | Ideology [Official DLC] [https:// no link (local mod)] 60 | HugsLib [https://steamcommunity.com/sharedfiles/filedetails/?id=818773962] 61 | RimThreaded [https://steamcommunity.com/sharedfiles/filedetails/?id=2222907981] 62 | ``` 63 | * Harmony 64 | * Core 65 | * Royalty (Optional) 66 | * Ideology (Optional) 67 | * HugsLib 68 | * RimThreaded 69 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_1med.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Reproducible Non-Vanilla Bug Report (Medium Priority) 3 | about: Submit a bug report that occurs in modded RimWorld that can be reproduced fairly 4 | consistantly. 5 | title: '' 6 | labels: Bug, Reproducible 7 | assignees: '' 8 | 9 | --- 10 | 17 | 18 | 19 | ### Developer To Do Notes: 20 | - [ ] 21 | - [ ] 22 | - [ ] 23 | 24 | 25 | # **Non-Vanilla Bug Report** 26 | 27 | ### **Describe the bug** 28 | ❗❗❗ bug description here ❗❗❗ 29 | 30 | ### **Steps to reproduce the behavior (VERY IMPORTANT)** 31 | 1. ❗❗❗ step 1 here ❗❗❗ 32 | 2. ❗❗❗ step 2 here ❗❗❗ 33 | 3. ❗❗❗ step 3 here ❗❗❗ 34 | 4. ❗❗❗ step 4 here ❗❗❗ 35 | 36 | ### **Error Logs** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#what-logs-should-my-bug-report-include) 37 | ```cs 38 | !!! You can copy paste an error here !!! 39 | ``` 40 | 41 | #### **HugsLib log** 42 | ❗❗❗ Link to HugsLib log. (MUST BE LINK) ❗❗❗ 43 | 44 | #### **Player.log (Optional)** 45 | ❗❗❗ Link to contents of Player.log or Error.log (MUST BE LINK) ❗❗❗ 46 | 47 | ### **Save file** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#how-do-i-attach-the-save-file-to-the-report) 48 | ❗❗❗ Please add a save file where the issue occurs to speed up testing and fixing of the issue ❗❗❗ 49 | 50 | ### **Screenshots (Optional)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#how-do-i-attach-a-screenshot-to-the-report) 51 | ❗❗❗ Add screenshots to help explain your problem here ❗❗❗ 52 | 53 | ### **Mod list (Preferably a RimPy compatible list.)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#what-mod-organizer-should-i-use) 54 | ``` 55 | ❗❗❗ Add RimPy mod list here ❗❗❗ 56 | ``` 57 | * Harmony 58 | * Core 59 | * Royalty (Optional) 60 | * Ideology (Optional) 61 | * HugsLib 62 | * 63 | * 64 | * 65 | * RimThreaded 66 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_2low.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Non-Reproducible Vanilla Bug Report (Low Priority) 3 | about: Submit a bug report that occurs in RimWorld running only RimThreaded and DLCs 4 | that cannot be reproduced fairly consistantly. 5 | title: '' 6 | labels: Bug, Vanilla RT 7 | assignees: '' 8 | 9 | --- 10 | 17 | 18 | 19 | ### Developer To Do Notes: 20 | - [ ] 21 | - [ ] 22 | - [ ] 23 | 24 | 25 | # **Vanilla Bug Report** 26 | 27 | ### **Describe the bug** 28 | ❗❗❗ bug description here ❗❗❗ 29 | 30 | ### **Steps to reproduce the behavior (VERY IMPORTANT)** 31 | 1. ❗❗❗ step 1 here ❗❗❗ 32 | 2. ❗❗❗ step 2 here ❗❗❗ 33 | 3. ❗❗❗ step 3 here ❗❗❗ 34 | 4. ❗❗❗ step 4 here ❗❗❗ 35 | 36 | ### **Error Logs** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#what-logs-should-my-bug-report-include) 37 | ```cs 38 | !!! You can copy paste an error here !!! 39 | ``` 40 | 41 | #### **HugsLib log** 42 | ❗❗❗ Link to HugsLib log. (MUST BE LINK) ❗❗❗ 43 | 44 | #### **Player.log (Optional)** 45 | ❗❗❗ Link to contents of Player.log or Error.log (MUST BE LINK) ❗❗❗ 46 | 47 | ### **Save file** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#how-do-i-attach-the-save-file-to-the-report) 48 | ❗❗❗ Please add a save file where the issue occurs to speed up testing and fixing of the issue ❗❗❗ 49 | 50 | ### **Screenshots (Optional)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#how-do-i-attach-a-screenshot-to-the-report) 51 | ❗❗❗ Add screenshots to help explain your problem here ❗❗❗ 52 | 53 | ### **Mod list (For vanilla report, it has to be same as below list.)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#what-mod-organizer-should-i-use) 54 | ``` 55 | [Mod list length: 6] 56 | Harmony [https://steamcommunity.com/sharedfiles/filedetails/?id=2009463077] 57 | Core [https:// no link (local mod)] 58 | Royalty [Official DLC] [https:// no link (local mod)] 59 | Ideology [Official DLC] [https:// no link (local mod)] 60 | HugsLib [https://steamcommunity.com/sharedfiles/filedetails/?id=818773962] 61 | RimThreaded [https://steamcommunity.com/sharedfiles/filedetails/?id=2222907981] 62 | ``` 63 | * Harmony 64 | * Core 65 | * Royalty (Optional) 66 | * Ideology (Optional) 67 | * HugsLib 68 | * RimThreaded 69 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report_3lowest.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Non-Reproducible Non-Vanilla Bug Report (Lowest Priority) 3 | about: Submit a bug report that occurs in modded RimWorld that cannot be reproduced 4 | fairly consistantly. 5 | title: '' 6 | labels: Bug 7 | assignees: '' 8 | 9 | --- 10 | 17 | 18 | 19 | ### Developer To Do Notes: 20 | - [ ] 21 | - [ ] 22 | - [ ] 23 | 24 | 25 | # **Non-Vanilla Bug Report** 26 | 27 | ### **Describe the bug** 28 | ❗❗❗ bug description here ❗❗❗ 29 | 30 | ### **Steps to reproduce the behavior (VERY IMPORTANT)** 31 | 1. ❗❗❗ step 1 here ❗❗❗ 32 | 2. ❗❗❗ step 2 here ❗❗❗ 33 | 3. ❗❗❗ step 3 here ❗❗❗ 34 | 4. ❗❗❗ step 4 here ❗❗❗ 35 | 36 | ### **Error Logs** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#what-logs-should-my-bug-report-include) 37 | ```cs 38 | !!! You can copy paste an error here !!! 39 | ``` 40 | 41 | #### **HugsLib log** 42 | ❗❗❗ Link to HugsLib log. (MUST BE LINK) ❗❗❗ 43 | 44 | #### **Player.log (Optional)** 45 | ❗❗❗ Link to contents of Player.log or Error.log (MUST BE LINK) ❗❗❗ 46 | 47 | ### **Save file** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q&A#how-do-i-attach-the-save-file-to-the-report) 48 | ❗❗❗ Please add a save file where the issue occurs to speed up testing and fixing of the issue ❗❗❗ 49 | 50 | ### **Screenshots (Optional)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#how-do-i-attach-a-screenshot-to-the-report) 51 | ❗❗❗ Add screenshots to help explain your problem here ❗❗❗ 52 | 53 | ### **Mod list (Preferably a RimPy compatible list.)** [?](https://github.com/cseelhoff/RimThreaded/wiki/Q%26A#what-mod-organizer-should-i-use) 54 | ``` 55 | ❗❗❗ Add RimPy mod list here ❗❗❗ 56 | ``` 57 | * Harmony 58 | * Core 59 | * Royalty (Optional) 60 | * Ideology (Optional) 61 | * HugsLib 62 | * 63 | * 64 | * 65 | * RimThreaded 66 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/reproducible-community-modpack-bug-report--medium-priority-.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Reproducible Community Modpack Bug Report (Medium Priority) 3 | about: Submit a bug report that occurs in the Community Modpack that can be reproduced 4 | fairly consistantly. 5 | title: '' 6 | labels: Bug, Community Modpack, Reproducible 7 | assignees: pastorismylord 8 | 9 | --- 10 | 11 | ## **IMPORTANT:** 12 | **Please first search existing bugs to ensure you are not creating a duplicate bug report!** 13 | **Make sure you have the latest version of Rimworld!** 14 | 15 | ### **Describe the bug** 16 | !!! bug description here !!! 17 | 18 | ### **Steps to reproduce the behavior (VERY IMPORTANT)** 19 | 1. Go to '...' 20 | 2. Click on '....' 21 | 3. Scroll down to '....' 22 | 4. See error 23 | 24 | ### **Error Logs** 25 | #### **Player.log** 26 | !!! Link to contents of Player.log or Error.log (MUST BE LINK) !!! 27 | #### **HugsLib log** 28 | !!! Link to HugsLib log. (MUST BE LINK) !!! 29 | 30 | ### **Save file** 31 | !!! Please add a save file where the issue occurs to speed up testing and fixing of the issue !!! 32 | 33 | ### **Screenshots** 34 | !!! Add screenshots to help explain your problem here !!! 35 | 36 | ### **Modpack Version** 37 | !!! Version of the Community Modpack (V1 preview 2. for example) !!! 38 | 39 | ### **Have you done any changes to the community mod list?** 40 | !!! YES / NO !!! 41 | !!! List of Changes !!! 42 | 43 | 44 | ### **Mod list (Preferably a RimPy compatible list.)** 45 | * Harmony 46 | * Core 47 | * Royalty (Optional) 48 | * Ideology (Optional) 49 | * HugsLib 50 | * 51 | * 52 | * 53 | * RimThreaded 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Caleb Seelhoff 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /RimThreaded/1.3/Assemblies/RimThreaded.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cseelhoff/RimThreaded/c4e491805bd247ec8e38522157f876ad4ef73417/RimThreaded/1.3/Assemblies/RimThreaded.dll -------------------------------------------------------------------------------- /RimThreaded/1.3/Assemblies/RimThreaded.pdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cseelhoff/RimThreaded/c4e491805bd247ec8e38522157f876ad4ef73417/RimThreaded/1.3/Assemblies/RimThreaded.pdb -------------------------------------------------------------------------------- /RimThreaded/1.3/Assemblies/ThreadSafeLinkedList.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cseelhoff/RimThreaded/c4e491805bd247ec8e38522157f876ad4ef73417/RimThreaded/1.3/Assemblies/ThreadSafeLinkedList.dll -------------------------------------------------------------------------------- /RimThreaded/1.3/Assemblies/ThreadSafeLinkedListRW.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cseelhoff/RimThreaded/c4e491805bd247ec8e38522157f876ad4ef73417/RimThreaded/1.3/Assemblies/ThreadSafeLinkedListRW.dll -------------------------------------------------------------------------------- /RimThreaded/1.3/Assemblies/Unity.Newtonsoft.Json.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cseelhoff/RimThreaded/c4e491805bd247ec8e38522157f876ad4ef73417/RimThreaded/1.3/Assemblies/Unity.Newtonsoft.Json.dll -------------------------------------------------------------------------------- /RimThreaded/About/Preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cseelhoff/RimThreaded/c4e491805bd247ec8e38522157f876ad4ef73417/RimThreaded/About/Preview.png -------------------------------------------------------------------------------- /RimThreaded/About/PublishedFileId.txt: -------------------------------------------------------------------------------- 1 | 2222907981 -------------------------------------------------------------------------------- /Source/CustomTickList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace RimThreaded 5 | { 6 | public class ThreadedTickList 7 | { 8 | public Action prepareAction; 9 | public Action tickAction; 10 | public int preparing = -1; 11 | public int threadCount = -1; 12 | public bool readyToTick = false; 13 | public EventWaitHandle prepEventWaitStart = new ManualResetEvent(false); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/JumboCell_Cache.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Verse; 3 | 4 | namespace RimThreaded 5 | { 6 | public abstract class JumboCell_Cache 7 | { 8 | public Dictionary[]>> positionsAwaitingAction = new Dictionary[]>>(); 9 | 10 | public abstract bool IsActionableObject(Map map, IntVec3 location); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Source/Mod_Patches/AlienRace_Patch.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection.Emit; 5 | using Verse; 6 | using HarmonyLib; 7 | using static HarmonyLib.AccessTools; 8 | using static RimThreaded.RimThreadedHarmony; 9 | using RimThreaded.RW_Patches; 10 | 11 | namespace RimThreaded.Mod_Patches 12 | { 13 | class AlienRace_Patch 14 | { 15 | 16 | public static void Patch() 17 | { 18 | Type ARHarmonyPatches = TypeByName("AlienRace.HarmonyPatches"); 19 | if (ARHarmonyPatches != null) 20 | { 21 | 22 | string methodName = nameof(HediffSet_Patch.AddDirect); 23 | Log.Message("RimThreaded is patching " + typeof(HediffSet_Patch).FullName + " " + methodName); 24 | Transpile(typeof(HediffSet_Patch), typeof(AlienRace_Patch), methodName); 25 | 26 | 27 | methodName = nameof(HediffSet_Patch.CacheMissingPartsCommonAncestors); 28 | Log.Message("RimThreaded is patching " + typeof(HediffSet_Patch).FullName + " " + methodName); 29 | Transpile(typeof(HediffSet_Patch), typeof(AlienRace_Patch), methodName); 30 | 31 | } 32 | } 33 | 34 | 35 | public static IEnumerable AddDirect(IEnumerable instructions, ILGenerator iLGenerator) 36 | { 37 | 38 | Type ARHarmonyPatches = TypeByName("AlienRace.HarmonyPatches"); 39 | return (IEnumerable)ARHarmonyPatches.GetMethod("BodyReferenceTranspiler").Invoke(null, new object[] { instructions }); 40 | } 41 | public static IEnumerable CacheMissingPartsCommonAncestors(IEnumerable instructions, ILGenerator iLGenerator) 42 | { 43 | 44 | Type ARHarmonyPatches = TypeByName("AlienRace.HarmonyPatches"); 45 | return (IEnumerable)ARHarmonyPatches.GetMethod("BodyReferenceTranspiler").Invoke(null, new object[] { instructions }); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/Mod_Patches/AndroidTiers_Patch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Reflection; 4 | using Verse; 5 | using System.Collections.Generic; 6 | using System.Reflection.Emit; 7 | using static HarmonyLib.AccessTools; 8 | using static RimThreaded.RimThreadedHarmony; 9 | 10 | namespace RimThreaded.Mod_Patches 11 | { 12 | class AndroidTiers_Patch 13 | { 14 | public static Type androidTiers_GeneratePawns_Patch1; 15 | public static Type androidTiers_GeneratePawns_Patch; 16 | public static void Patch() 17 | { 18 | 19 | androidTiers_GeneratePawns_Patch1 = TypeByName("MOARANDROIDS.PawnGroupMakerUtility_Patch"); 20 | if (androidTiers_GeneratePawns_Patch1 != null) 21 | { 22 | androidTiers_GeneratePawns_Patch = androidTiers_GeneratePawns_Patch1.GetNestedType("GeneratePawns_Patch"); 23 | } 24 | Type patched; 25 | if (androidTiers_GeneratePawns_Patch != null) 26 | { 27 | string methodName = "Listener"; 28 | patched = typeof(GeneratePawns_Patch_Transpile); 29 | Log.Message("RimThreaded is patching " + androidTiers_GeneratePawns_Patch.FullName + " " + methodName); 30 | Log.Message("Utility_Patch::Listener != null: " + (Method(androidTiers_GeneratePawns_Patch, "Listener") != null)); 31 | Log.Message("Utility_Patch_Transpile::Listener != null: " + (Method(patched, "Listener") != null)); 32 | Transpile(androidTiers_GeneratePawns_Patch, patched, methodName); 33 | } 34 | Type androidTiers_Utils = TypeByName("MOARANDROIDS.Utils"); 35 | if (androidTiers_Utils != null) 36 | { 37 | string methodName = nameof(getCachedCSM); 38 | Log.Message("RimThreaded is patching " + androidTiers_Utils.FullName + " " + methodName); 39 | Transpile(androidTiers_Utils, typeof(AndroidTiers_Patch), methodName); 40 | } 41 | } 42 | public static void set_Item(Dictionary CSM, Thing t, object j) 43 | { 44 | lock (CSM) 45 | { 46 | CSM[t] = j; 47 | } 48 | } 49 | public static IEnumerable getCachedCSM(IEnumerable instructions, ILGenerator iLGenerator) 50 | { 51 | Type ThingToCompSkyMind = typeof(Dictionary<,>).MakeGenericType(new[] { typeof(Thing), TypeByName("MOARANDROIDS.CompSkyMind") }); 52 | foreach (CodeInstruction i in instructions) 53 | { 54 | if (i.opcode == OpCodes.Callvirt) 55 | {//CompSkyMind 56 | if ((MethodInfo)i.operand == Method(ThingToCompSkyMind, "set_Item")) 57 | { 58 | i.operand = Method(typeof(AndroidTiers_Patch), nameof(set_Item)); 59 | } 60 | } 61 | yield return i; 62 | } 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/Mod_Patches/AwesomeInventory_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using static RimThreaded.RimThreadedHarmony; 5 | 6 | namespace RimThreaded.Mod_Patches 7 | { 8 | class AwesomeInventory_Patch 9 | { 10 | public static Type awesomeInventoryJobsJobGiver_FindItemByRadius; 11 | public static Type awesomeInventoryJobsJobGiver_FindItemByRadiusSub; 12 | public static Type jobGiver_AwesomeInventory_TakeArm; 13 | public static Type awesomeInventoryErrorMessage; 14 | public static void Patch() 15 | { 16 | awesomeInventoryJobsJobGiver_FindItemByRadius = TypeByName("AwesomeInventory.Jobs.JobGiver_FindItemByRadius"); 17 | awesomeInventoryJobsJobGiver_FindItemByRadiusSub = TypeByName("AwesomeInventory.Jobs.JobGiver_FindItemByRadius+<>c__DisplayClass17_0"); 18 | awesomeInventoryErrorMessage = TypeByName("AwesomeInventory.ErrorMessage"); 19 | jobGiver_AwesomeInventory_TakeArm = TypeByName("AwesomeInventory.Jobs.JobGiver_AwesomeInventory_TakeArm"); 20 | 21 | Type patched; 22 | if (awesomeInventoryJobsJobGiver_FindItemByRadius != null) 23 | { 24 | string methodName = "Reset"; 25 | Log.Message("RimThreaded is patching " + awesomeInventoryJobsJobGiver_FindItemByRadius.FullName + " " + methodName); 26 | patched = typeof(JobGiver_FindItemByRadius_Transpile); 27 | Transpile(awesomeInventoryJobsJobGiver_FindItemByRadius, patched, methodName); 28 | methodName = "FindItem"; 29 | Log.Message("RimThreaded is patching " + awesomeInventoryJobsJobGiver_FindItemByRadius.FullName + " " + methodName); 30 | Transpile(awesomeInventoryJobsJobGiver_FindItemByRadius, patched, methodName); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/Mod_Patches/Better_Message_Placement_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using static RimThreaded.RimThreadedHarmony; 5 | using RimThreaded.RW_Patches; 6 | 7 | namespace RimThreaded.Mod_Patches 8 | { 9 | class Better_Message_Placement_Patch 10 | { 11 | 12 | public static void Patch() 13 | { 14 | Type Messages_MessagesDoGUI_Patch = TypeByName("Better_Message_Placement.Messages_MessagesDoGUI_Patch"); 15 | if (Messages_MessagesDoGUI_Patch != null) 16 | { 17 | 18 | string methodName = "MessagesDoGUI"; 19 | Log.Message("RimThreaded is patching " + typeof(Messages_Patch).FullName + " " + methodName); 20 | Transpile(typeof(Messages_Patch), Messages_MessagesDoGUI_Patch, methodName, patchMethod: "Transpiler"); 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /Source/Mod_Patches/Children_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using static RimThreaded.RimThreadedHarmony; 5 | 6 | namespace RimThreaded.Mod_Patches 7 | { 8 | class Children_Patch 9 | { 10 | public static Type childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch; 11 | public static void Patch() 12 | { 13 | childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch = TypeByName("Children.ChildrenHarmony+HediffComp_Discoverable_CheckDiscovered_Patch"); 14 | Type patched; 15 | if (childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch != null) 16 | { 17 | string methodName = "CheckDiscovered_Pre"; 18 | patched = typeof(childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch_Transpile); 19 | Log.Message("RimThreaded is patching " + childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch.FullName + " " + methodName); 20 | Transpile(childrenHarmonyHediffComp_Discoverable_CheckDiscovered_Patch, patched, methodName); 21 | PawnComponentsUtility_Patch.RunDestructivePatches(); 22 | } 23 | 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Mod_Patches/DubsBadHygiene.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Reflection.Emit; 7 | using Verse; 8 | using static HarmonyLib.AccessTools; 9 | 10 | namespace RimThreaded.Mod_Patches 11 | { 12 | class DubsBadHygiene_Patch 13 | { 14 | public static void Patch() 15 | { 16 | Type DubsBadHygiene_JobDriver_UseToilet = TypeByName("DubsBadHygiene.JobDriver_UseToilet"); 17 | if (DubsBadHygiene_JobDriver_UseToilet != null) 18 | { 19 | string methodName = "b__1_2"; 20 | Log.Message("RimThreaded is patching " + DubsBadHygiene_JobDriver_UseToilet.FullName + " " + methodName); 21 | RimThreadedHarmony.Transpile(DubsBadHygiene_JobDriver_UseToilet, typeof(DubsBadHygiene_Patch), methodName, nameof(MakeNewToils_b__1_2)); 22 | } 23 | } 24 | 25 | public static IEnumerable MakeNewToils_b__1_2(IEnumerable instructions, ILGenerator iLGenerator) 26 | { 27 | List instructionsList = instructions.ToList(); 28 | for (int i = 0; i < instructionsList.Count; i++) 29 | { 30 | CodeInstruction ci = instructionsList[i]; 31 | if (ci.opcode == OpCodes.Ldfld && (FieldInfo)ci.operand == Field(typeof(Room), nameof(Room.uniqueContainedThings))) 32 | { 33 | ci.opcode = OpCodes.Call; 34 | ci.operand = Method(typeof(Room), "get_ContainedAndAdjacentThings"); 35 | } 36 | yield return ci; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/Mod_Patches/Dubs_Skylight_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using static RimThreaded.RimThreadedHarmony; 5 | 6 | namespace RimThreaded.Mod_Patches 7 | { 8 | class Dubs_Skylight_Patch 9 | { 10 | public static Type dubsSkylight_Patch_GetRoof; 11 | public static void Patch() 12 | { 13 | dubsSkylight_Patch_GetRoof = TypeByName("Dubs_Skylight.Patch_GetRoof"); 14 | Type patched; 15 | if (dubsSkylight_Patch_GetRoof != null) 16 | { 17 | string methodName = "Postfix"; 18 | patched = typeof(DubsSkylight_getPatch_Transpile); 19 | Log.Message("RimThreaded is patching " + dubsSkylight_Patch_GetRoof.FullName + " " + methodName); 20 | Transpile(dubsSkylight_Patch_GetRoof, patched, methodName); 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Source/Mod_Patches/Fluffy_Breakdowns_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using RimWorld; 5 | 6 | namespace RimThreaded.Mod_Patches 7 | { 8 | class Fluffy_Breakdowns_Patch 9 | { 10 | public static void Patch() 11 | { 12 | Type MapComponent_Durability = TypeByName("Fluffy_Breakdowns.MapComponent_Durability");//Fluffy_Breakdowns.MapComponent_Durability.GetDurability 13 | if (MapComponent_Durability != null) 14 | { 15 | string methodName = "GetDurability"; 16 | Log.Message("RimThreaded is patching " + MapComponent_Durability.FullName + " " + methodName); 17 | MethodLocker.LockMethodOnInstance(MapComponent_Durability, methodName, LockFlag.WriterLock, OTypes: new Type[] { typeof(CompBreakdownable) }); 18 | methodName = "ExposeData"; 19 | Log.Message("RimThreaded is patching " + MapComponent_Durability.FullName + " " + methodName); 20 | MethodLocker.LockMethodOnInstance(MapComponent_Durability, methodName, LockFlag.WriterLock); 21 | methodName = "MapComponentTick"; 22 | Log.Message("RimThreaded is patching " + MapComponent_Durability.FullName + " " + methodName); 23 | MethodLocker.LockMethodOnInstance(MapComponent_Durability, methodName, LockFlag.WriterLock); 24 | methodName = "SetDurability"; 25 | Log.Message("RimThreaded is patching " + MapComponent_Durability.FullName + " " + methodName); 26 | MethodLocker.LockMethodOnInstance(MapComponent_Durability, methodName, LockFlag.WriterLock, OTypes: new Type[] { typeof(CompBreakdownable), typeof(float) }); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/Mod_Patches/GeneratePawns_Patch_Transpile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Reflection.Emit; 6 | using HarmonyLib; 7 | using RimThreaded.RW_Patches; 8 | using UnityEngine; 9 | using Verse; 10 | 11 | namespace RimThreaded.Mod_Patches 12 | { 13 | public class GeneratePawns_Patch_Transpile 14 | { 15 | public static IEnumerable Listener(IEnumerable instructions, ILGenerator iLGenerator) 16 | { 17 | List l = instructions.ToList(); 18 | bool match = false; 19 | 20 | 21 | //Replacement Instructions 22 | CodeInstruction loadToken = new CodeInstruction(OpCodes.Ldtoken, typeof(Texture2D).GetTypeInfo()); 23 | CodeInstruction resolveToken = new CodeInstruction(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); 24 | 25 | 26 | for (int x = 0; x < l.Count; x++) 27 | { 28 | CodeInstruction i = l[x]; 29 | 30 | if (i.opcode == OpCodes.Call 31 | && (MethodInfo)i.operand == TargetMethodHelper()) 32 | { 33 | match = true; 34 | 35 | i.operand = typeof(Resources_Patch).GetMethod("Load"); 36 | 37 | l.Insert(x, resolveToken); 38 | l.Insert(x, loadToken); 39 | 40 | 41 | } 42 | yield return l[x]; 43 | } 44 | if (!match) 45 | { 46 | Log.Error("No IL Instruction found for PawnGroupMakerUtility_Patch."); 47 | } 48 | } 49 | 50 | public static MethodBase TargetMethodHelper() 51 | { 52 | MethodInfo i = typeof(Resources).GetMethods().Single( 53 | m => 54 | m.Name == "Load" && 55 | m.GetGenericArguments().Length == 1 && 56 | m.GetParameters().Length == 1 && 57 | m.GetParameters()[0].ParameterType == typeof(String) 58 | ); 59 | 60 | 61 | return i.MakeGenericMethod(typeof(Texture2D)); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/Mod_Patches/Hospitality_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using static RimThreaded.RimThreadedHarmony; 5 | 6 | namespace RimThreaded.Mod_Patches 7 | { 8 | class Hospitality_Patch 9 | { 10 | public static Type hospitalityCompUtility; 11 | public static Type hospitalityCompGuest; 12 | public static void Patch() 13 | { 14 | hospitalityCompUtility = TypeByName("Hospitality.CompUtility"); 15 | hospitalityCompGuest = TypeByName("Hospitality.CompGuest"); 16 | 17 | Type patched; 18 | if (hospitalityCompUtility != null) 19 | { 20 | string methodName = "CompGuest"; 21 | Log.Message("RimThreaded is patching " + hospitalityCompUtility.FullName + " " + methodName); 22 | patched = typeof(CompUtility_Transpile); 23 | Transpile(hospitalityCompUtility, patched, methodName); 24 | methodName = "OnPawnRemoved"; 25 | Log.Message("RimThreaded is patching " + hospitalityCompUtility.FullName + " " + methodName); 26 | Transpile(hospitalityCompUtility, patched, methodName); 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/Mod_Patches/JobsOfOppurtunity_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimThreaded.RW_Patches; 3 | using Verse; 4 | using static HarmonyLib.AccessTools; 5 | using static RimThreaded.RimThreadedHarmony; 6 | 7 | namespace RimThreaded.Mod_Patches 8 | { 9 | class JobsOfOppurtunity_Patch 10 | { 11 | 12 | public static Type jobsOfOpportunityJobsOfOpportunity_Hauling; 13 | public static Type jobsOfOpportunityJobsOfOpportunity_Patch_TryOpportunisticJob; 14 | 15 | public static void Patch() 16 | { 17 | jobsOfOpportunityJobsOfOpportunity_Hauling = TypeByName("JobsOfOpportunity.JobsOfOpportunity+Hauling"); 18 | jobsOfOpportunityJobsOfOpportunity_Patch_TryOpportunisticJob = TypeByName("JobsOfOpportunity.JobsOfOpportunity+Patch_TryOpportunisticJob"); 19 | 20 | Type patched; 21 | //if (jobsOfOpportunityJobsOfOpportunity_Hauling != null) 22 | //{ 23 | // cachedStoreCell = Field(jobsOfOpportunityJobsOfOpportunity_Hauling, "cachedStoreCell"); 24 | // string methodName = "CanHaul"; 25 | // patched = typeof(Hauling_Transpile); 26 | // Log.Message("RimThreaded is patching " + jobsOfOpportunityJobsOfOpportunity_Hauling.FullName + " " + methodName); 27 | // Transpile(jobsOfOpportunityJobsOfOpportunity_Hauling, patched, methodName); 28 | //} 29 | 30 | if (jobsOfOpportunityJobsOfOpportunity_Patch_TryOpportunisticJob != null) 31 | { 32 | string methodName = "TryOpportunisticJob"; 33 | patched = typeof(Patch_TryOpportunisticJob_Transpile); 34 | Log.Message("RimThreaded is patching " + jobsOfOpportunityJobsOfOpportunity_Patch_TryOpportunisticJob.FullName + " " + methodName); 35 | Transpile(jobsOfOpportunityJobsOfOpportunity_Patch_TryOpportunisticJob, patched, methodName); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/Mod_Patches/MapReroll_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimThreaded.RW_Patches; 2 | using RimWorld.Planet; 3 | using System; 4 | using System.Collections.Generic; 5 | using Verse; 6 | using static HarmonyLib.AccessTools; 7 | using static RimThreaded.RimThreadedHarmony; 8 | 9 | namespace RimThreaded.Mod_Patches 10 | { 11 | class MapReroll_Patch 12 | { 13 | public static Type MapReroll; 14 | public static void Patch() 15 | { 16 | MapReroll = TypeByName("MapReroll.MapPreviewGenerator"); 17 | if (MapReroll != null) 18 | { 19 | Log.Message("RimThreaded is patching methods for compatibility with MapReroll"); 20 | Type original = typeof(World); 21 | Type patched = typeof(MapReroll_Patch); 22 | Prefix(original, patched, nameof(NaturalRockTypesIn)); 23 | Prefix(original, patched, nameof(CoastDirectionAt)); 24 | } 25 | } 26 | 27 | public static bool NaturalRockTypesIn(World __instance, ref IEnumerable __result, int tile) 28 | { 29 | if (World_Patch.tmpNaturalRockDefs == null) 30 | { 31 | World_Patch.tmpNaturalRockDefs = new List(); 32 | } 33 | return true; 34 | } 35 | public static bool CoastDirectionAt(World __instance, ref Rot4 __result, int tileID) 36 | { 37 | if (World_Patch.tmpOceanDirs == null) 38 | { 39 | World_Patch.tmpOceanDirs = new List(); 40 | } 41 | if (World_Patch.tmpNeighbors == null) 42 | { 43 | World_Patch.tmpNeighbors = new List(); 44 | } 45 | return true; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/Mod_Patches/PawnRules_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimThreaded.RW_Patches; 2 | using System; 3 | using Verse; 4 | using static HarmonyLib.AccessTools; 5 | using static RimThreaded.RimThreadedHarmony; 6 | 7 | namespace RimThreaded.Mod_Patches 8 | { 9 | class PawnRules_Patch 10 | { 11 | public static Type pawnRulesPatchRimWorld_Pawn_GuestTracker_SetGuestStatus; 12 | public static void Patch() 13 | { 14 | 15 | pawnRulesPatchRimWorld_Pawn_GuestTracker_SetGuestStatus = TypeByName("PawnRules.Patch.RimWorld_Pawn_GuestTracker_SetGuestStatus"); 16 | Type patched; 17 | if (pawnRulesPatchRimWorld_Pawn_GuestTracker_SetGuestStatus != null) 18 | { 19 | string methodName = "Prefix"; 20 | Log.Message("RimThreaded is patching " + pawnRulesPatchRimWorld_Pawn_GuestTracker_SetGuestStatus.FullName + " " + methodName); 21 | patched = typeof(RimWorld_Pawn_GuestTracker_SetGuestStatus_Transpile); 22 | Transpile(pawnRulesPatchRimWorld_Pawn_GuestTracker_SetGuestStatus, patched, methodName); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Mod_Patches/RimWar_Patch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Reflection; 4 | using Verse; 5 | using System.Collections.Generic; 6 | using System.Reflection.Emit; 7 | using static HarmonyLib.AccessTools; 8 | using static RimThreaded.RimThreadedHarmony; 9 | using System.Linq; 10 | 11 | namespace RimThreaded.Mod_Patches 12 | { 13 | class RimWar_Patch 14 | { 15 | public static Type RimWar_Planet_WorldUtility; 16 | public static void Patch() 17 | { 18 | RimWar_Planet_WorldUtility = TypeByName("RimWar.Planet.WorldUtility"); 19 | if (RimWar_Planet_WorldUtility != null) 20 | { 21 | string methodName = nameof(GetWorldObjectsInRange); 22 | Log.Message("RimThreaded is patching " + RimWar_Planet_WorldUtility.FullName + " " + methodName); 23 | Transpile(RimWar_Planet_WorldUtility, typeof(RimWar_Patch), methodName); 24 | } 25 | } 26 | 27 | public static IEnumerable GetWorldObjectsInRange(IEnumerable instructions, ILGenerator iLGenerator) 28 | { 29 | List instructionsList = instructions.ToList(); 30 | for(int i = 0; i < instructionsList.Count; i++) 31 | { 32 | CodeInstruction codeInstruction = instructionsList[i]; 33 | if (codeInstruction.opcode == OpCodes.Callvirt && 34 | (MethodInfo)codeInstruction.operand == Method(typeof(RimWorld.Planet.WorldObject), "get_Tile")) 35 | { 36 | LocalBuilder worldObject = iLGenerator.DeclareLocal(typeof(RimWorld.Planet.WorldObject)); 37 | yield return new CodeInstruction(OpCodes.Stloc, worldObject); 38 | yield return new CodeInstruction(OpCodes.Ldloc, worldObject); 39 | //yield return new CodeInstruction(OpCodes.Ldnull); 40 | //yield return new CodeInstruction(OpCodes.Ceq); 41 | Label label = (Label)instructionsList[i + 10].operand; 42 | //yield return new CodeInstruction(OpCodes.Brtrue, label); 43 | yield return new CodeInstruction(OpCodes.Brfalse, label); 44 | yield return new CodeInstruction(OpCodes.Ldloc, worldObject); 45 | } 46 | yield return codeInstruction; 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Mod_Patches/SpeakUp_Patch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection.Emit; 5 | using static HarmonyLib.AccessTools; 6 | using System.Linq; 7 | using Verse; 8 | 9 | namespace RimThreaded.Mod_Patches 10 | { 11 | class SpeakUp_Patch 12 | { 13 | public static Type GrammarResolver_RandomPossiblyResolvableEntry; 14 | 15 | public static void Patch() 16 | { 17 | GrammarResolver_RandomPossiblyResolvableEntry = TypeByName("SpeakUp.GrammarResolver_RandomPossiblyResolvableEntry"); 18 | if (GrammarResolver_RandomPossiblyResolvableEntry != null) 19 | { 20 | string methodName = nameof(Prefix); 21 | Log.Message("RimThreaded is patching " + GrammarResolver_RandomPossiblyResolvableEntry.FullName + " " + methodName); 22 | RimThreadedHarmony.Transpile(GrammarResolver_RandomPossiblyResolvableEntry, typeof(SpeakUp_Patch), methodName); 23 | } 24 | } 25 | 26 | public static IEnumerable Prefix(IEnumerable instructions, ILGenerator iLGenerator) 27 | { 28 | List instructionsList = instructions.ToList(); 29 | for (int i = 0; i < instructionsList.Count; i++) 30 | { 31 | CodeInstruction ci = instructionsList[i]; 32 | if (ci.opcode == OpCodes.Ldarg_S) //&& (ArgumentInfo)ci.operand == Argument(GrammarResolver_RandomPossiblyResolvableEntry, "___rules") 33 | { 34 | ci.opcode = OpCodes.Ldsfld; 35 | ci.operand = Field(TypeByName("GrammarResolver_Replacement"), "rules"); 36 | } 37 | yield return ci; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/Mod_Patches/TD_Enhancement_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static HarmonyLib.AccessTools; 4 | using System.Threading; 5 | 6 | namespace RimThreaded.Mod_Patches 7 | { 8 | class TD_Enhancement_Patch 9 | { 10 | public static ReaderWriterLockSlim learnedInfo_Lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); 11 | public static void Patch() 12 | { 13 | Type TD_Enhancement_Pack_Learn_Patch = TypeByName("TD_Enhancement_Pack.Learn_Patch"); 14 | if (TD_Enhancement_Pack_Learn_Patch != null) 15 | { 16 | string methodName = "Postfix"; 17 | Log.Message("RimThreaded is patching " + TD_Enhancement_Pack_Learn_Patch.FullName + " " + methodName); 18 | RimThreadedHarmony.Prefix(TD_Enhancement_Pack_Learn_Patch, typeof(TD_Enhancement_Patch), methodName, destructive: false, PatchMethod: nameof(WriterPrefix), finalizer: nameof(WriterFinalizer)); 19 | } 20 | Type LearnedGameComponent = TypeByName("TD_Enhancement_Pack.LearnedGameComponent"); 21 | if (LearnedGameComponent != null) 22 | { 23 | string methodName = "GameComponentTick"; 24 | Log.Message("RimThreaded is patching " + LearnedGameComponent.FullName + " " + methodName); 25 | RimThreadedHarmony.Prefix(LearnedGameComponent, typeof(TD_Enhancement_Patch), methodName, destructive: false, PatchMethod: nameof(WriterPrefix), finalizer: nameof(WriterFinalizer)); 26 | } 27 | 28 | } 29 | public static void WriterPrefix() 30 | { 31 | learnedInfo_Lock.EnterWriteLock(); 32 | } 33 | public static void WriterFinalizer() 34 | { 35 | learnedInfo_Lock.ExitWriteLock(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/Mod_Patches/ZombieLand_Patch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using System.Reflection.Emit; 6 | using static HarmonyLib.AccessTools; 7 | 8 | namespace RimThreaded.Mod_Patches 9 | { 10 | class ZombieLand_Patch 11 | { 12 | public static void Patch() 13 | { 14 | Type type = TypeByName("ZombieLand.ZombieStateHandler"); 15 | if (type != null) 16 | { 17 | foreach (MethodInfo method in type.GetMethods()) 18 | { 19 | if (method.IsDeclaredMember()) 20 | { 21 | try 22 | { 23 | IEnumerable> f = PatchProcessor.ReadMethodBody(method); 24 | foreach (KeyValuePair e in f) 25 | { 26 | if (e.Value is FieldInfo fieldInfo && RimThreadedHarmony.replaceFields.ContainsKey(fieldInfo)) 27 | { 28 | RimThreadedHarmony.TranspileFieldReplacements(method); 29 | break; 30 | } 31 | if (e.Value is MethodInfo methodInfo && RimThreadedHarmony.replaceFields.ContainsKey(methodInfo)) 32 | { 33 | RimThreadedHarmony.TranspileFieldReplacements(method); 34 | break; 35 | } 36 | } 37 | } 38 | catch (NotSupportedException) { } 39 | } 40 | } 41 | } 42 | 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/OneTickPool.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading; 3 | 4 | namespace RimThreaded 5 | { 6 | /// 7 | /// Use this class only when you can demonstrate an object dies after 1 tick and you can't track its life. 8 | /// If you can track its life use the SimplePool instead. 9 | /// 10 | public static class OneTickPool where T : new() 11 | { 12 | private static readonly List ObjectsList = new List(); 13 | 14 | private static T reservedItem; 15 | public static int ObjectsCount => ObjectsList.Count; 16 | 17 | private static int Pivot = -1;// everything to the left is being used, everything to the right is free. 18 | 19 | /// 20 | /// REMEMBER OBJECTS RETURNED FROM THIS MUST BE CLEARED 21 | /// 22 | public static T Get() 23 | { 24 | T freeItem2; 25 | do 26 | { 27 | int index = Interlocked.Increment(ref Pivot); 28 | 29 | if (index >= ObjectsCount) 30 | { 31 | lock (ObjectsList) 32 | { 33 | while (index >= ObjectsCount) 34 | { 35 | ObjectsList.Add(new T()); 36 | } 37 | } 38 | } 39 | freeItem2 = ObjectsList[index]; 40 | } 41 | while (freeItem2.Equals(reservedItem)); 42 | return freeItem2; 43 | } 44 | public static void Tick(T reserved) 45 | { 46 | Pivot = -1; 47 | reservedItem = reserved; 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /Source/Patch_TryOpportunisticJob.cs: -------------------------------------------------------------------------------- 1 | using Verse; 2 | using Verse.AI; 3 | 4 | namespace RimThreaded 5 | { 6 | class Patch_TryOpportunisticJob 7 | { 8 | public static Pawn getPawn(Pawn_JobTracker jobTracker) 9 | { 10 | return jobTracker.pawn; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Source/PlantHarvest_Cache.cs: -------------------------------------------------------------------------------- 1 | using RimThreaded.RW_Patches; 2 | using RimWorld; 3 | using Verse; 4 | 5 | namespace RimThreaded 6 | { 7 | public class PlantHarvest_Cache : JumboCell_Cache 8 | { 9 | public override bool IsActionableObject(Map map, IntVec3 location) 10 | { 11 | //---START--- For plant Harvest 12 | //WorkGiver_GrowerHarvest.HasJobOnCell 13 | Plant plant = location.GetPlant(map); 14 | bool hasJobOnCell = plant != null && !plant.IsForbidden(Faction.OfPlayer) && (plant.HarvestableNow && plant.LifeStage == PlantLifeStage.Mature) && (plant.CanYieldNow()); 15 | if (!hasJobOnCell) 16 | { 17 | return false; 18 | } 19 | bool canReserve = ReservationManager_Patch.IsUnreserved(map.reservationManager, plant); 20 | if (!canReserve) 21 | return false; 22 | //---END-- 23 | return true; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Source/PlantSowing_Cache.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded 6 | { 7 | public class PlantSowing_Cache : JumboCell_Cache 8 | { 9 | public override bool IsActionableObject(Map map, IntVec3 location) 10 | { 11 | //---START--- For plant sowing 12 | ThingDef localWantedPlantDef = WorkGiver_Grower.CalculateWantedPlantDef(location, map); 13 | if (localWantedPlantDef == null) 14 | { 15 | return false; 16 | } 17 | List thingList = location.GetThingList(map); 18 | for (int i = 0; i < thingList.Count; i++) 19 | { 20 | Thing thing = thingList[i]; 21 | if (thing.def == localWantedPlantDef) 22 | { 23 | return false; 24 | } 25 | } 26 | if (map.physicalInteractionReservationManager.IsReserved(location)) 27 | { 28 | return false; 29 | } 30 | Thing thing2 = PlantUtility.AdjacentSowBlocker(localWantedPlantDef, location, map); 31 | if (thing2 != null) 32 | { 33 | if (thing2 is Plant plant2 && !plant2.IsForbidden(Faction.OfPlayer)) 34 | { 35 | IPlantToGrowSettable plantToGrowSettable = plant2.Position.GetPlantToGrowSettable(plant2.Map); 36 | if (plantToGrowSettable != null && plantToGrowSettable.GetPlantDefToGrow() == plant2.def) 37 | { 38 | return false; 39 | } 40 | } 41 | } 42 | 43 | for (int j = 0; j < thingList.Count; j++) 44 | { 45 | Thing thing3 = thingList[j]; 46 | if (!thing3.def.BlocksPlanting()) 47 | { 48 | continue; 49 | } 50 | 51 | if (thing3.def.category == ThingCategory.Plant) 52 | { 53 | if (!thing3.IsForbidden(Faction.OfPlayer)) 54 | { 55 | break; // JobMaker.MakeJob(JobDefOf.CutPlant, thing3); 56 | } 57 | Log.Warning("Plant IsForbidden"); 58 | return false; 59 | } 60 | 61 | if (thing3.def.EverHaulable) 62 | { 63 | break; //HaulAIUtility.HaulAsideJobFor(pawn, thing3); 64 | } 65 | return false; 66 | } 67 | 68 | //TODO fix null check? find root cause. Or maybe it was just from a bad save? 69 | //if (localWantedPlantDef != null &&!localWantedPlantDef.CanEverPlantAt_NewTemp(location, map, true)) 70 | // this change helps with boulders blocking growing zones. likely at a small performance cost 71 | if (localWantedPlantDef != null && (!location.InBounds(map) || (double)map.fertilityGrid.FertilityAt(location) < localWantedPlantDef.plant.fertilityMin)) 72 | { 73 | return false; 74 | } 75 | //---END-- 76 | return true; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Source/PulsePool.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace RimThreaded 6 | { 7 | public static class PulsePool where T : new() 8 | { 9 | private static readonly ConcurrentQueue FreeItems = new ConcurrentQueue(); 10 | 11 | public static int FreeItemsCount => FreeItems.Count; 12 | public static T Pulse(T o) 13 | { 14 | lock (FreeItems) 15 | { 16 | if (!FreeItems.Contains(o)) 17 | { 18 | FreeItems.Enqueue(o); 19 | } 20 | FreeItems.TryDequeue(out T freeItem); 21 | if (freeItem.Equals(o)) 22 | { 23 | ExpandPulsePool(); 24 | FreeItems.Enqueue(o); 25 | return new T(); 26 | } 27 | return freeItem; 28 | } 29 | } 30 | internal static void ExpandPulsePool() 31 | { 32 | for (int i = 0; i != 20; i++) 33 | { 34 | FreeItems.Enqueue(new T()); 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/RW_Patches/Alert_ColonistLeftUnburied_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class Alert_ColonistLeftUnburied_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(Alert_ColonistLeftUnburied); 12 | Type patched = typeof(Alert_ColonistLeftUnburied_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(IsCorpseOfColonist)); 14 | } 15 | 16 | public static bool IsCorpseOfColonist(ref bool __result, Corpse corpse) 17 | { 18 | if (corpse == null) 19 | { 20 | __result = false; 21 | return false; 22 | } 23 | Pawn InnerPawn = corpse.InnerPawn; 24 | if (InnerPawn == null) 25 | { 26 | __result = false; 27 | return false; 28 | } 29 | ThingDef def = InnerPawn.def; 30 | if (def == null) 31 | { 32 | __result = false; 33 | return false; 34 | } 35 | RaceProperties race = def.race; 36 | if (race == null) 37 | { 38 | __result = false; 39 | return false; 40 | } 41 | __result = InnerPawn.Faction == Faction.OfPlayer && race.Humanlike && !InnerPawn.IsQuestLodger() && !InnerPawn.IsSlave && !corpse.IsInAnyStorage(); 42 | return false; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/RW_Patches/Alert_MinorBreakRisk_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RimWorld; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class Alert_MinorBreakRisk_Patch 9 | { 10 | public static void RunDestructivePatches() 11 | { 12 | Type original = typeof(Alert_MinorBreakRisk); 13 | Type patched = typeof(Alert_MinorBreakRisk_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(GetReport)); 15 | } 16 | public static bool GetReport(Alert_MinorBreakRisk __instance, ref AlertReport __result) 17 | { 18 | List pawnsAtRiskMinorResult = new List(); 19 | List pawnList = PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_FreeColonists_NoCryptosleep; 20 | for (int i = 0; i < pawnList.Count; i++) 21 | { 22 | Pawn item = pawnList[i]; 23 | if (item.Downed || item.MentalStateDef != null) continue; 24 | float curMood = item.mindState.mentalBreaker.CurMood; 25 | if (curMood < item.mindState.mentalBreaker.BreakThresholdMajor) 26 | { 27 | return false; 28 | } 29 | if (curMood < item.mindState.mentalBreaker.BreakThresholdMinor) 30 | { 31 | pawnsAtRiskMinorResult.Add(item); 32 | } 33 | } 34 | __result = AlertReport.CulpritsAre(pawnsAtRiskMinorResult); 35 | return false; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/RW_Patches/AlertsReadout_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class AlertsReadout_Patch 8 | { 9 | public static void RunNonDestructivesPatches() 10 | { 11 | Type original = typeof(AlertsReadout); 12 | Type patched = typeof(AlertsReadout_Patch); 13 | //RimThreadedHarmony.Prefix(original, patched, nameof(AlertsReadoutUpdate), Type.EmptyTypes, false); 14 | } 15 | 16 | public static bool AlertsReadoutUpdate(AlertsReadout __instance) 17 | { 18 | //this will disable alert checks on ultrafast speed for an added speed boost 19 | return !(Find.TickManager.curTimeSpeed == TimeSpeed.Ultrafast && RimThreadedMod.Settings.disablesomealerts); 20 | } 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/RW_Patches/Area_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class Area_Patch 9 | { 10 | public static Dictionary corners = new Dictionary(); 11 | 12 | public struct Range2D 13 | { 14 | public int minX; 15 | public int minZ; 16 | public int maxX; 17 | public int maxZ; 18 | 19 | public Range2D(int x1, int z1, int x2, int z2) 20 | { 21 | minX = x1; 22 | minZ = z1; 23 | maxX = x2; 24 | maxZ = z2; 25 | } 26 | } 27 | 28 | internal static void RunNonDestructivePatches() 29 | { 30 | Type original = typeof(Area); 31 | Type patched = typeof(Area_Patch); 32 | RimThreadedHarmony.Postfix(original, patched, nameof(Set)); //TODO need code to check on shrinking of area 33 | } 34 | 35 | public static void Set(Area __instance, IntVec3 c, bool val) 36 | { 37 | if (!val) return; 38 | Range2D range = GetCorners(__instance); 39 | range.minX = Math.Min(range.minX, c.x); 40 | range.minZ = Math.Min(range.minZ, c.z); 41 | range.maxX = Math.Max(range.maxX, c.x); 42 | range.maxZ = Math.Max(range.maxZ, c.z); 43 | } 44 | 45 | public static Range2D GetCorners(Area __instance) 46 | { 47 | if (__instance == null) 48 | { 49 | return new Range2D(0, 0, 99999, 99999); 50 | } 51 | 52 | if (corners.TryGetValue(__instance, out Range2D range)) return range; 53 | IntVec3[] iv3 = __instance.ActiveCells.ToArray(); 54 | bool initialized = false; 55 | foreach (IntVec3 intVec3 in iv3) 56 | { 57 | if (!initialized) 58 | { 59 | range = new Range2D(intVec3.x, intVec3.z, intVec3.x, intVec3.z); 60 | initialized = true; 61 | } 62 | range.minX = Math.Min(range.minX, intVec3.x); 63 | range.minZ = Math.Min(range.minZ, intVec3.z); 64 | range.maxX = Math.Max(range.maxX, intVec3.x); 65 | range.maxZ = Math.Max(range.maxZ, intVec3.z); 66 | } 67 | corners[__instance] = range; 68 | return range; 69 | } 70 | 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Source/RW_Patches/AudioSourceMaker_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Verse.Sound; 4 | using static System.Threading.Thread; 5 | using static RimThreaded.RimThreaded; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class AudioSourceMaker_Patch 11 | { 12 | static readonly Func safeFunction = parameters => 13 | AudioSourceMaker.NewAudioSourceOn((GameObject)parameters[0]); 14 | 15 | public static void RunDestructivePatches() 16 | { 17 | Type original = typeof(AudioSourceMaker); 18 | Type patched = typeof(AudioSourceMaker_Patch); 19 | RimThreadedHarmony.Prefix(original, patched, nameof(NewAudioSourceOn)); 20 | } 21 | 22 | public static bool NewAudioSourceOn(ref AudioSource __result, GameObject go) 23 | { 24 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 25 | return true; 26 | threadInfo.safeFunctionRequest = new object[] { safeFunction, new object[] { go } }; 27 | mainThreadWaitHandle.Set(); 28 | threadInfo.eventWaitStart.WaitOne(); 29 | __result = (AudioSource)threadInfo.safeFunctionResult; 30 | return false; 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/RW_Patches/BattleLog_Transpile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection.Emit; 5 | using HarmonyLib; 6 | using Verse; 7 | using static HarmonyLib.AccessTools; 8 | 9 | namespace RimThreaded.RW_Patches 10 | { 11 | public class BattleLog_Transpile 12 | { 13 | internal static void RunNonDestructivePatches() 14 | { 15 | Type original = typeof(BattleLog); 16 | Type patched = typeof(BattleLog_Transpile); 17 | RimThreadedHarmony.Transpile(original, patched, nameof(Add)); 18 | } 19 | 20 | public static object addLogEntryLock = new object(); 21 | public static IEnumerable Add(IEnumerable instructions, ILGenerator iLGenerator) 22 | { 23 | List instructionsList = instructions.ToList(); 24 | int i = 0; 25 | Type lockObjectType = typeof(object); 26 | List loadLockObjectInstructions = new List 27 | { 28 | new CodeInstruction(OpCodes.Ldsfld, Field(typeof(BattleLog_Transpile), "addLogEntryLock")), 29 | }; 30 | LocalBuilder lockObject = iLGenerator.DeclareLocal(lockObjectType); 31 | LocalBuilder lockTaken = iLGenerator.DeclareLocal(typeof(bool)); 32 | foreach (CodeInstruction ci in RimThreadedHarmony.EnterLock( 33 | lockObject, lockTaken, loadLockObjectInstructions, instructionsList[i])) 34 | yield return ci; 35 | 36 | while (i < instructionsList.Count - 1) 37 | { 38 | yield return instructionsList[i++]; 39 | } 40 | foreach (CodeInstruction ci in RimThreadedHarmony.ExitLock( 41 | iLGenerator, lockObject, lockTaken, instructionsList[i])) 42 | yield return ci; 43 | 44 | while (i < instructionsList.Count) 45 | { 46 | yield return instructionsList[i++]; 47 | } 48 | } 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/RW_Patches/Battle_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using UnityEngine; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class Battle_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(Battle); 13 | Type patched = typeof(Battle_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(Absorb)); 15 | } 16 | public static bool Absorb(Battle __instance, Battle battle) 17 | { 18 | lock (__instance) 19 | { 20 | __instance.creationTimestamp = Mathf.Min(__instance.creationTimestamp, battle.creationTimestamp); 21 | __instance.entries.AddRange(battle.entries); 22 | __instance.concerns.AddRange(battle.concerns); 23 | __instance.entries = __instance.entries.OrderBy(e => e.Age).ToList(); 24 | } 25 | battle.entries.Clear(); 26 | battle.concerns.Clear(); 27 | battle.absorbedBy = __instance; 28 | __instance.battleName = null; 29 | return false; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/RW_Patches/BiomeDef_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using RimWorld; 5 | using Verse; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class BiomeDef_Patch 11 | { 12 | internal static void RunDestructivePatches() 13 | { 14 | Type original = typeof(BiomeDef); 15 | Type patched = typeof(BiomeDef_Patch); 16 | RimThreadedHarmony.Prefix(original, patched, "CachePlantCommonalitiesIfShould"); 17 | } 18 | public static bool CachePlantCommonalitiesIfShould(BiomeDef __instance) 19 | { 20 | if (__instance.cachedPlantCommonalities != null) 21 | { 22 | return false; 23 | } 24 | if (__instance.cachedPlantCommonalities != null) 25 | { 26 | return false; 27 | } 28 | lock (__instance) //TODO more efficient lock 29 | { 30 | Dictionary localCachedPlantCommonalities = new Dictionary(); 31 | for (int i = 0; i < __instance.wildPlants.Count; i++) 32 | { 33 | BiomePlantRecord wildPlant = __instance.wildPlants[i]; 34 | ThingDef plant = wildPlant.plant; 35 | if (plant != null) 36 | { 37 | localCachedPlantCommonalities[plant] = wildPlant.commonality; 38 | } 39 | } 40 | 41 | foreach (ThingDef allDef in DefDatabase.AllDefs) 42 | { 43 | if (allDef.plant == null || allDef.plant.wildBiomes == null) continue; 44 | for (int j = 0; j < allDef.plant.wildBiomes.Count; j++) 45 | { 46 | if (allDef.plant.wildBiomes[j].biome == __instance) 47 | { 48 | localCachedPlantCommonalities.Add(allDef, allDef.plant.wildBiomes[j].commonality); 49 | } 50 | } 51 | } 52 | __instance.cachedPlantCommonalitiesSum = localCachedPlantCommonalities.Sum(x => x.Value); 53 | __instance.cachedPlantCommonalities = localCachedPlantCommonalities; 54 | 55 | } 56 | return false; 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Source/RW_Patches/BodyDef_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimThreaded.RW_Patches; 2 | using RimThreaded; 3 | using System; 4 | using Verse; 5 | using System.Collections.Generic; 6 | 7 | public class BodyDef_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(BodyDef); 12 | Type patched = typeof(BodyDef_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(GetPartsWithTag)); 14 | } 15 | 16 | public static bool GetPartsWithTag(BodyDef __instance, ref List __result, BodyPartTagDef tag) 17 | { 18 | Dictionary> cachedPartsByTag = __instance.cachedPartsByTag; 19 | 20 | if (cachedPartsByTag.TryGetValue(tag, out __result)) 21 | return false; 22 | 23 | lock (cachedPartsByTag) 24 | { 25 | if (cachedPartsByTag.TryGetValue(tag, out __result)) 26 | return false; 27 | List AllParts = __instance.AllParts; 28 | __result = new List(); 29 | for (int i = 0; i < AllParts.Count; i++) 30 | { 31 | BodyPartRecord bodyPartRecord = AllParts[i]; 32 | if (bodyPartRecord.def.tags.Contains(tag)) 33 | { 34 | __result.Add(bodyPartRecord); 35 | } 36 | } 37 | cachedPartsByTag[tag] = __result; 38 | } 39 | return false; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Source/RW_Patches/Building_Door_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | 7 | public class Building_Door_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(Building_Door); 12 | Type patched = typeof(Building_Door_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, "get_DoorPowerOn"); 14 | } 15 | 16 | public static bool get_DoorPowerOn(Building_Door __instance, ref bool __result) 17 | { 18 | CompPowerTrader pc = __instance.powerComp; 19 | bool poweron = false; 20 | if (pc != null) 21 | { 22 | try 23 | { 24 | poweron = pc.PowerOn; 25 | } 26 | catch (NullReferenceException) { } 27 | } 28 | __result = poweron; 29 | return false; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/RW_Patches/Building_PlantGrower_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class Building_PlantGrower_Patch 8 | { 9 | internal static void RunNonDestructivePatches() 10 | { 11 | Type original = typeof(Building_PlantGrower); 12 | Type patched = typeof(Building_PlantGrower_Patch); 13 | RimThreadedHarmony.Postfix(original, patched, nameof(SetPlantDefToGrow)); 14 | } 15 | 16 | public static void SetPlantDefToGrow(Building_PlantGrower __instance, ThingDef plantDef) 17 | { 18 | if (Current.ProgramState == ProgramState.Playing) 19 | { 20 | foreach (IntVec3 c in __instance.OccupiedRect()) 21 | { 22 | JumboCell.ReregisterObject(__instance.Map, c, RimThreaded.plantSowing_Cache); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/RW_Patches/Camera_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using UnityEngine; 4 | using static HarmonyLib.AccessTools; 5 | using static RimThreaded.RimThreaded; 6 | using static System.Threading.Thread; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | public class Camera_Patch 11 | { 12 | static readonly MethodInfo MethodSetTargetTexture = 13 | Method(typeof(Camera), "set_targetTexture", new Type[] { typeof(RenderTexture) }); 14 | 15 | static readonly Action ActionSetTargetTexture = 16 | (Action)Delegate.CreateDelegate 17 | (typeof(Action), MethodSetTargetTexture); 18 | 19 | static readonly Action SafeActionSetTargetTexture = parameters => 20 | ActionSetTargetTexture( 21 | (Camera)parameters[0], 22 | (RenderTexture)parameters[1]); 23 | 24 | public static bool set_targetTexture(Camera __instance, RenderTexture value) 25 | { 26 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 27 | return true; 28 | threadInfo.safeFunctionRequest = new object[] { 29 | SafeActionSetTargetTexture, new object[] { __instance, value } }; 30 | mainThreadWaitHandle.Set(); 31 | threadInfo.eventWaitStart.WaitOne(); 32 | return false; 33 | } 34 | 35 | static readonly MethodInfo MethodRender = 36 | Method(typeof(Camera), "Render", new Type[] { }); 37 | 38 | static readonly Action ActionRender = 39 | (Action)Delegate.CreateDelegate 40 | (typeof(Action), MethodRender); 41 | 42 | static readonly Action SafeActionRender = p => 43 | ActionRender((Camera)p[0]); 44 | public static bool Render(Camera __instance) 45 | { 46 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 47 | return true; 48 | threadInfo.safeFunctionRequest = new object[] { SafeActionRender, new object[] { __instance } }; 49 | mainThreadWaitHandle.Set(); 50 | threadInfo.eventWaitStart.WaitOne(); 51 | return false; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Source/RW_Patches/CellFinder_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class CellFinder_Patch 8 | { 9 | [ThreadStatic] public static List[] mapSingleEdgeCells; 10 | 11 | internal static void InitializeThreadStatics() 12 | { 13 | mapSingleEdgeCells = new List[4]; 14 | } 15 | 16 | internal static void RunNonDestructivePatches() 17 | { 18 | Type original = typeof(CellFinder); 19 | Type patched = typeof(CellFinder_Patch); 20 | RimThreadedHarmony.Prefix(original, patched, nameof(TryFindRandomCellNear), null, false); 21 | } 22 | public static bool TryFindRandomCellNear(ref bool __result, IntVec3 root, 23 | Map map, 24 | int squareRadius, 25 | Predicate validator, 26 | ref IntVec3 result, 27 | int maxTries = -1 28 | ) 29 | { 30 | if (map == null) 31 | { 32 | __result = false; 33 | return false; 34 | } 35 | return true; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/RW_Patches/ColoredText_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class ColoredText_Patch 8 | { 9 | [ThreadStatic] public static Regex ColonistCountRegex; 10 | 11 | public static void InitializeThreadStatics() 12 | { 13 | ColonistCountRegex = new Regex("\\d+\\.?\\d* " + "(" + FactionDefOf.PlayerColony.pawnsPlural + "|" + FactionDefOf.PlayerColony.pawnSingular + ")"); 14 | } 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Source/RW_Patches/CompForbiddable_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class CompForbiddable_Patch 7 | { 8 | private static readonly Type Original = typeof(CompForbiddable); 9 | private static readonly Type Patched = typeof(CompForbiddable_Patch); 10 | public static void RunNonDestructivePatches() 11 | { 12 | RimThreadedHarmony.Postfix(Original, Patched, nameof(set_Forbidden)); 13 | } 14 | 15 | public static void set_Forbidden(CompForbiddable __instance, bool value) 16 | { 17 | if (__instance.parent.Map != null) 18 | { 19 | HaulingCache.ReregisterHaulableItem(__instance.parent); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/RW_Patches/Component_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using static RimThreaded.RimThreaded; 4 | using static System.Threading.Thread; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class Component_Patch 9 | { 10 | //private static readonly MethodInfo MethodComponentTransform = Method(typeof(Component), "get_transform"); 11 | //private static readonly MethodInfo MethodComponent_PatchTransform = Method(typeof(Component_Patch), "get_transform"); 12 | 13 | public static Transform get_transform(Component __instance) 14 | { 15 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 16 | return __instance.transform; 17 | Func FuncTransform = parameters => __instance.transform; 18 | threadInfo.safeFunctionRequest = new object[] { FuncTransform, new object[] { } }; 19 | mainThreadWaitHandle.Set(); 20 | threadInfo.eventWaitStart.WaitOne(); 21 | return (Transform)threadInfo.safeFunctionResult; 22 | } 23 | 24 | public static GameObject get_gameObject(Component __instance) 25 | { 26 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 27 | return __instance.gameObject; 28 | Func FuncGameObject = parameters => __instance.gameObject; 29 | threadInfo.safeFunctionRequest = new object[] { FuncGameObject, new object[] { } }; 30 | mainThreadWaitHandle.Set(); 31 | threadInfo.eventWaitStart.WaitOne(); 32 | return (GameObject)threadInfo.safeFunctionResult; 33 | } 34 | 35 | //public static IEnumerable TranspileComponentTransform(IEnumerable instructions, ILGenerator iLGenerator) 36 | //{ 37 | // foreach (CodeInstruction codeInstruction in instructions) 38 | // { 39 | // if (codeInstruction.operand is MethodInfo methodInfo) 40 | // { 41 | // if (methodInfo == MethodComponentTransform) 42 | // { 43 | // //Log.Message("RimThreaded is replacing method call: "); 44 | // codeInstruction.operand = MethodComponent_PatchTransform; 45 | // } 46 | // } 47 | // yield return codeInstruction; 48 | // } 49 | //} 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/RW_Patches/ContentFinder_Texture2D_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Verse; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | public class ContentFinder_Texture2D_Patch 10 | { 11 | static readonly Func FuncContentFinder = parameters => 12 | ContentFinder.Get( 13 | (string)parameters[0], 14 | (bool)parameters[1]); 15 | 16 | public static void RunDestructivePatches() 17 | { 18 | Type original = typeof(ContentFinder); 19 | Type patched = typeof(ContentFinder_Texture2D_Patch); 20 | RimThreadedHarmony.Prefix(original, patched, "Get"); 21 | } 22 | public static bool Get(ref Texture2D __result, string itemPath, bool reportFailure = true) 23 | { 24 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 25 | return true; 26 | threadInfo.safeFunctionRequest = new object[] { FuncContentFinder, new object[] { itemPath, reportFailure } }; 27 | mainThreadWaitHandle.Set(); 28 | threadInfo.eventWaitStart.WaitOne(); 29 | __result = (Texture2D)threadInfo.safeFunctionResult; 30 | return false; 31 | } 32 | 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Source/RW_Patches/Corpse_Patch.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Reflection.Emit; 7 | using UnityEngine; 8 | using Verse; 9 | using static HarmonyLib.AccessTools; 10 | 11 | namespace RimThreaded.RW_Patches 12 | { 13 | class Corpse_Patch 14 | { 15 | internal static void RunNonDestructivePatches() 16 | { 17 | Type original = typeof(Corpse); 18 | Type patched = typeof(Corpse_Patch); 19 | RimThreadedHarmony.Transpile(original, patched, nameof(SpawnSetup)); 20 | } 21 | internal static void RunDestructivePatches() 22 | { 23 | Type original = typeof(Corpse); 24 | Type patched = typeof(Corpse_Patch); 25 | RimThreadedHarmony.Prefix(original, patched, nameof(DrawAt)); 26 | } 27 | public static IEnumerable SpawnSetup(IEnumerable instructions, ILGenerator iLGenerator) 28 | { 29 | List instructionsList = instructions.ToList(); 30 | for (int i = 0; i < instructionsList.Count; i++) 31 | { 32 | CodeInstruction ci = instructionsList[i]; 33 | if (ci.opcode == OpCodes.Call && (MethodInfo)ci.operand == Method(typeof(Corpse), "get_InnerPawn")) 34 | { 35 | ci.operand = Method(typeof(Corpse_Patch), nameof(SetRotationSouth)); 36 | yield return ci; 37 | i++; //call valuetype Verse.Rot4 Verse.Rot4::get_South() 38 | i++; //callvirt instance void Verse.Thing::set_Rotation(valuetype Verse.Rot4) 39 | i++; //ldarg.0 40 | i++; //NotifyColonistBar(); 41 | continue; 42 | } 43 | yield return ci; 44 | } 45 | } 46 | 47 | public static void SetRotationSouth(Corpse __instance) 48 | { 49 | Pawn InnerPawn = __instance.InnerPawn; 50 | if (InnerPawn == null) 51 | return; 52 | InnerPawn.Rotation = Rot4.South; 53 | __instance.NotifyColonistBar(); 54 | } 55 | public static bool DrawAt(Corpse __instance, Vector3 drawLoc, bool flip = false) 56 | { 57 | Pawn InnerPawn = __instance.InnerPawn; 58 | if (InnerPawn == null) 59 | return false; 60 | InnerPawn.Drawer.renderer.RenderPawnAt(drawLoc); 61 | return false; 62 | } 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/RW_Patches/DateNotifier_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RimWorld; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class DateNotifier_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(DateNotifier); 14 | Type patched = typeof(DateNotifier_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "FindPlayerHomeWithMinTimezone"); 16 | } 17 | 18 | public static bool FindPlayerHomeWithMinTimezone(DateNotifier __instance, ref Map __result) 19 | { 20 | List maps = Find.Maps; 21 | Map map = maps[0]; 22 | int num = -1; 23 | if (maps.Count > 1) 24 | { 25 | for (int i = 0; i < maps.Count; i++) 26 | { 27 | if (!maps[i].IsPlayerHome) continue; 28 | int num2 = GenDate.TimeZoneAt(Find.WorldGrid.LongLatOf(maps[i].Tile).x); 29 | if (map != null && num2 >= num) continue; 30 | map = maps[i]; 31 | num = num2; 32 | } 33 | } 34 | __result = map; 35 | return false; 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/RW_Patches/Designator_Haul_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class Designator_Haul_Patch 8 | { 9 | private static readonly Type Original = typeof(Designator_Haul); 10 | private static readonly Type Patched = typeof(Designator_Haul_Patch); 11 | public static void RunNonDestructivePatches() 12 | { 13 | RimThreadedHarmony.Postfix(Original, Patched, "DesignateThing"); 14 | } 15 | 16 | public static void DesignateThing(Designator_Haul __instance, Thing t) 17 | { 18 | HaulingCache.ReregisterHaulableItem(t); 19 | } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Source/RW_Patches/DrugAIUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RimWorld; 4 | using UnityEngine; 5 | using Verse; 6 | using Verse.AI; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | class DrugAIUtility_Patch 11 | { 12 | 13 | public static void RunDestructivePatches() 14 | { 15 | //DrugAIUtility - vanilla bug? 16 | Type original = typeof(DrugAIUtility); 17 | Type patched = typeof(DrugAIUtility_Patch); 18 | RimThreadedHarmony.Prefix(original, patched, "IngestAndTakeToInventoryJob"); 19 | } 20 | 21 | public static bool IngestAndTakeToInventoryJob(ref Job __result, Thing drug, Pawn pawn, int maxNumToCarry = 9999) 22 | { 23 | Job job = JobMaker.MakeJob(JobDefOf.Ingest, drug); 24 | job.count = Mathf.Min(drug.stackCount, drug.def.ingestible.maxNumToIngestAtOnce, maxNumToCarry); 25 | if (pawn.drugs != null && drugPolicyExists(pawn.drugs.CurrentPolicy.entriesInt, drug.def)) 26 | { 27 | DrugPolicyEntry drugPolicyEntry = pawn.drugs.CurrentPolicy[drug.def]; 28 | int num = pawn.inventory.innerContainer.TotalStackCountOfDef(drug.def) - job.count; 29 | if (drugPolicyEntry.allowScheduled && num <= 0) 30 | { 31 | job.takeExtraIngestibles = drugPolicyEntry.takeToInventory; 32 | } 33 | } 34 | 35 | __result = job; 36 | return false; 37 | } 38 | 39 | private static bool drugPolicyExists(List entriesInt, ThingDef def) 40 | { 41 | for (int index = 0; index < entriesInt.Count; index++) 42 | { 43 | if (entriesInt[index].drug == def) 44 | { 45 | return true; 46 | } 47 | } 48 | return false; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Source/RW_Patches/DynamicDrawManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | 8 | public class DynamicDrawManager_Patch 9 | { 10 | public static void RunDestructivePatches() 11 | { 12 | Type original = typeof(DynamicDrawManager); 13 | Type patched = typeof(DynamicDrawManager_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "RegisterDrawable"); 15 | RimThreadedHarmony.Prefix(original, patched, "DeRegisterDrawable"); 16 | } 17 | 18 | public static bool RegisterDrawable(DynamicDrawManager __instance, Thing t) 19 | { 20 | if (t.def.drawerType == DrawerType.None) return false; 21 | if (__instance.drawingNow) 22 | Log.Warning("Cannot register drawable " + t + " while drawing is in progress. Things shouldn't be spawned in Draw methods."); 23 | lock (__instance) 24 | { 25 | __instance.drawThings.Add(t); 26 | } 27 | return false; 28 | } 29 | 30 | public static bool DeRegisterDrawable(DynamicDrawManager __instance, Thing t) 31 | { 32 | if (t.def.drawerType == DrawerType.None) return false; 33 | if (__instance.drawingNow) 34 | Log.Warning("Cannot deregister drawable " + t + " while drawing is in progress. Things shouldn't be despawned in Draw methods."); 35 | lock (__instance) 36 | { 37 | HashSet newDrawThings = new HashSet(__instance.drawThings); 38 | newDrawThings.Remove(t); 39 | __instance.drawThings = newDrawThings; 40 | } 41 | return false; 42 | } 43 | 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Source/RW_Patches/FactionManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using RimWorld; 5 | using RimWorld.Planet; 6 | using Verse; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | 11 | public class FactionManager_Patch 12 | { 13 | internal static void RunDestructivePatches() 14 | { 15 | Type original = typeof(FactionManager); 16 | Type patched = typeof(FactionManager_Patch); 17 | RimThreadedHarmony.Prefix(original, patched, nameof(FactionManagerTick)); 18 | } 19 | 20 | public static bool FactionManagerTick(FactionManager __instance) 21 | { 22 | SettlementProximityGoodwillUtility.CheckSettlementProximityGoodwillChange(); 23 | 24 | lock (__instance) 25 | { 26 | List newList = __instance.toRemove; 27 | for (int num = newList.Count - 1; num >= 0; num--) 28 | { 29 | Faction faction = newList[num]; 30 | newList.Remove(faction); 31 | __instance.toRemove = newList; 32 | __instance.Remove(faction); 33 | } 34 | } 35 | allFactionsTickList = __instance.allFactions; 36 | allFactionsTicks = allFactionsTickList.Count; 37 | return false; 38 | } 39 | public static List allFactionsTickList; 40 | public static int allFactionsTicks; 41 | 42 | public static void FactionsPrepare() 43 | { 44 | try 45 | { 46 | World world = Find.World; 47 | world.factionManager.FactionManagerTick(); 48 | } 49 | catch (Exception ex3) 50 | { 51 | Log.Error(ex3.ToString()); 52 | } 53 | } 54 | 55 | public static void FactionsListTick() 56 | { 57 | while (true) 58 | { 59 | int index = Interlocked.Decrement(ref allFactionsTicks); 60 | if (index < 0) return; 61 | Faction faction = allFactionsTickList[index]; 62 | try 63 | { 64 | faction.FactionTick(); 65 | } 66 | catch (Exception ex) 67 | { 68 | Log.Error("Exception ticking faction: " + faction.ToStringSafe() + ": " + ex); 69 | } 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Source/RW_Patches/FilthMaker_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class FilthMaker_Patch 9 | { 10 | public static readonly Type original = typeof(FilthMaker); 11 | public static readonly Type patched = typeof(FilthMaker_Patch); 12 | 13 | public static void RunDestructivePatches() 14 | { 15 | RimThreadedHarmony.Prefix(original, patched, nameof(TryMakeFilth), new Type[] { typeof(IntVec3), typeof(Map), typeof(ThingDef), typeof(IEnumerable), typeof(bool), typeof(FilthSourceFlags) }, false); 16 | } 17 | 18 | public static bool TryMakeFilth(ref bool __result, IntVec3 c, Map map, ThingDef filthDef, IEnumerable sources, bool shouldPropagate, FilthSourceFlags additionalFlags = FilthSourceFlags.None) 19 | { 20 | __result = false; 21 | if (map == null) 22 | return false; 23 | return true; 24 | } 25 | 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /Source/RW_Patches/FireUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class FireUtility_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(FireUtility); 12 | Type patched = typeof(FireUtility_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(TryAttachFire)); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(ChanceToStartFireIn), null, false); 15 | } 16 | 17 | public static bool TryAttachFire(Thing t, float fireSize) 18 | { 19 | if (!t.CanEverAttachFire() || t.HasAttachment(ThingDefOf.Fire)) 20 | return false; 21 | Fire fire = (Fire)ThingMaker.MakeThing(ThingDefOf.Fire); 22 | fire.fireSize = fireSize; 23 | fire.AttachTo(t); 24 | GenSpawn.Spawn(fire, t.Position, t.Map, Rot4.North); 25 | if (!(t is Pawn pawn)) 26 | return false; 27 | Verse.AI.Pawn_JobTracker jobs = pawn.jobs; 28 | if (jobs != null) 29 | jobs.StopAll(); 30 | pawn.records.Increment(RecordDefOf.TimesOnFire); 31 | return false; 32 | } 33 | public static bool ChanceToStartFireIn(ref float __result, IntVec3 c, Map map) 34 | { 35 | if (map == null) 36 | { 37 | __result = 0f; 38 | return false; 39 | } 40 | return true; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/RW_Patches/FleckStatic_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class FleckStatic_Patch 7 | { 8 | public static void RunDestructivePatches() 9 | { 10 | Type original = typeof(FleckStatic); 11 | Type patched = typeof(FleckStatic_Patch); 12 | RimThreadedHarmony.Prefix(original, patched, nameof(get_EndOfLife)); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(Draw), new Type[] { typeof(DrawBatch) }); 14 | } 15 | 16 | public static bool get_EndOfLife(FleckStatic __instance, ref bool __result) 17 | { 18 | FleckDef def = __instance.def; 19 | if (def == null) 20 | { 21 | __result = true; 22 | return false; 23 | } 24 | __result = __instance.ageSecs >= def.Lifespan; 25 | return false; 26 | } 27 | public static bool Draw(FleckStatic __instance, DrawBatch batch) 28 | { 29 | FleckDef def = __instance.def; 30 | if (def == null) 31 | return false; 32 | __instance.Draw(def.altitudeLayer.AltitudeFor(def.altitudeLayerIncOffset), batch); 33 | return false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/RW_Patches/FoodUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class FoodUtility_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(FoodUtility); 12 | Type patched = typeof(FoodUtility_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(GetMeatSourceCategory)); 14 | } 15 | 16 | public static bool GetMeatSourceCategory(ref MeatSourceCategory __result, ThingDef source) 17 | { 18 | IngestibleProperties ingestible = source.ingestible; 19 | if (ingestible == null) 20 | { 21 | __result = MeatSourceCategory.Undefined; 22 | return false; 23 | } 24 | if ((ingestible.foodType & FoodTypeFlags.Meat) != FoodTypeFlags.Meat) 25 | { 26 | __result = MeatSourceCategory.NotMeat; 27 | return false; 28 | } 29 | if (ingestible.sourceDef != null && ingestible.sourceDef.race != null && ingestible.sourceDef.race.Humanlike) 30 | { 31 | __result = MeatSourceCategory.Humanlike; 32 | return false; 33 | } 34 | __result = ingestible.sourceDef != null && ingestible.sourceDef.race.FleshType != null && ingestible.sourceDef.race.FleshType == FleshTypeDefOf.Insectoid ? MeatSourceCategory.Insect : MeatSourceCategory.Undefined; 35 | return false; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/RW_Patches/FullPool_Patch.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | public static class FullPool_Patch where T : IFullPoolable, new() 7 | { 8 | private static readonly ConcurrentStack FreeItems = new ConcurrentStack(); 9 | 10 | public static T Get() 11 | { 12 | return !FreeItems.TryPop(out T freeItem) ? new T() : freeItem; 13 | } 14 | 15 | public static void Return(T item) 16 | { 17 | item.Reset(); 18 | FreeItems.Push(item); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/RW_Patches/GenDraw_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Verse; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class GenDraw_Patch 10 | { 11 | 12 | internal static void RunDestructivePatches() 13 | { 14 | Type original = typeof(GenDraw); 15 | Type patched = typeof(GenDraw_Patch); 16 | 17 | 18 | RimThreadedHarmony.Prefix(original, patched, "DrawMeshNowOrLater", new Type[] { typeof(Mesh), typeof(Vector3), typeof(Quaternion), typeof(Material), typeof(bool) }); 19 | } 20 | 21 | private static readonly Action ActionDrawMeshNowOrLater = p => 22 | GenDraw.DrawMeshNowOrLater((Mesh)p[0], (Vector3)p[1], (Quaternion)p[2], (Material)p[3], (bool)p[4]); 23 | 24 | 25 | 26 | 27 | public static bool DrawMeshNowOrLater(Mesh mesh, Vector3 loc, Quaternion quat, Material mat, bool drawNow) 28 | { 29 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 30 | return true; 31 | 32 | threadInfo.safeFunctionRequest = new object[] { ActionDrawMeshNowOrLater, new object[] { mesh, loc, quat, mat, drawNow } }; 33 | mainThreadWaitHandle.Set(); 34 | threadInfo.eventWaitStart.WaitOne(); 35 | return false; 36 | } 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/RW_Patches/GenGrid_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class GenGrid_Patch 7 | { 8 | internal static void RunNonDestructivePatches() 9 | { 10 | Type original = typeof(GenGrid); 11 | Type patched = typeof(GenGrid_Patch); 12 | RimThreadedHarmony.Prefix(original, patched, nameof(InBounds), new Type[] { typeof(IntVec3), typeof(Map) }, false); 13 | } 14 | public static bool InBounds(ref bool __result, IntVec3 c, Map map) 15 | { 16 | if (map == null) 17 | { 18 | __result = false; 19 | return false; 20 | } 21 | return true; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Source/RW_Patches/GenSpawn_Patch.cs: -------------------------------------------------------------------------------- 1 |  2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Verse; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class GenSpawn_Patch 10 | { 11 | private static readonly Type Original = typeof(GenSpawn); 12 | private static readonly Type Patched = typeof(GenSpawn_Patch); 13 | 14 | public static void RunDestructivePatches() 15 | { 16 | RimThreadedHarmony.Prefix(Original, Patched, "WipeExistingThings"); 17 | } 18 | 19 | public static bool WipeExistingThings(IntVec3 thingPos, Rot4 thingRot, BuildableDef thingDef, Map map, DestroyMode mode) 20 | { 21 | foreach (IntVec3 item in GenAdj.CellsOccupiedBy(thingPos, thingRot, thingDef.Size)) 22 | { 23 | List list = map.thingGrid.ThingsAt(item).ToList(); 24 | for (int index = 0; index < list.Count; index++) 25 | { 26 | Thing item2 = list[index]; 27 | if (item2 == null) continue; 28 | if (GenSpawn.SpawningWipes(thingDef, item2.def)) 29 | { 30 | item2.Destroy(mode); 31 | } 32 | } 33 | } 34 | 35 | return false; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/RW_Patches/GenTypes_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | public class GenTypes_Patch 9 | { 10 | private static readonly Type Original = typeof(GenTypes); 11 | private static readonly Type Patched = typeof(GenTypes_Patch); 12 | 13 | public static void RunDestructivePatches() 14 | { 15 | RimThreadedHarmony.Prefix(Original, Patched, "AllSubclassesNonAbstract"); 16 | } 17 | public static bool AllSubclassesNonAbstract(Type baseType, ref List __result) 18 | { 19 | if (GenTypes.cachedSubclassesNonAbstract.TryGetValue(baseType, out List typeList)) 20 | { 21 | __result = typeList; 22 | return false; 23 | } 24 | lock (GenTypes.cachedSubclassesNonAbstract) 25 | { 26 | if (!GenTypes.cachedSubclassesNonAbstract.TryGetValue(baseType, out List typeList2)) 27 | { 28 | typeList = GenTypes.AllTypes.Where((x) => x.IsSubclassOf(baseType) && !x.IsAbstract).ToList(); 29 | GenTypes.cachedSubclassesNonAbstract.Add(baseType, typeList); 30 | } 31 | else 32 | { 33 | typeList = typeList2; 34 | } 35 | __result = typeList; 36 | return false; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/RW_Patches/GlobalControlsUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using UnityEngine; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class GlobalControlsUtility_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(GlobalControlsUtility); 14 | Type patched = typeof(GlobalControlsUtility_Patch); 15 | RimThreadedHarmony.Postfix(original, patched, "DoTimespeedControls"); 16 | } 17 | 18 | public static void DoTimespeedControls(float leftX, float width, ref float curBaseY) 19 | { 20 | DateTime now = DateTime.Now; 21 | if (now.Second != RimThreaded.lastTicksCheck.Second) 22 | { 23 | RimThreaded.lastTicksCheck = now; 24 | RimThreaded.ticksPerSecond = GenTicks.TicksAbs - RimThreaded.lastTicksAbs; 25 | RimThreaded.lastTicksAbs = GenTicks.TicksAbs; 26 | } 27 | 28 | Rect rect = new Rect(leftX - 20f, curBaseY - 26f, (float)(width + 20.0 - 7.0), 26f); 29 | Text.Anchor = TextAnchor.MiddleRight; 30 | string label = "TPS: " + RimThreaded.ticksPerSecond + "(" + (int)(Find.TickManager.TickRateMultiplier * 60f) + ")"; 31 | Widgets.Label(rect, label); 32 | Text.Anchor = TextAnchor.UpperLeft; 33 | curBaseY -= 26f; 34 | } 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/RW_Patches/GoodwillSituationManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class GoodwillSituationManager_Patch 8 | { 9 | 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(GoodwillSituationManager); 13 | Type patched = typeof(GoodwillSituationManager_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(Recalculate), new Type[] { typeof(Faction), typeof(bool) }); 15 | } 16 | 17 | public static bool Recalculate(GoodwillSituationManager __instance, Faction other, bool canSendHostilityChangedLetter) 18 | { 19 | List outSituations1; 20 | if (__instance.cachedData.TryGetValue(other, out outSituations1)) 21 | { 22 | __instance.Recalculate(other, outSituations1); 23 | } 24 | else 25 | { 26 | List outSituations2 = new List(); 27 | __instance.Recalculate(other, outSituations2); 28 | lock (__instance.cachedData) 29 | { 30 | __instance.cachedData.Add(other, outSituations2); 31 | } 32 | } 33 | __instance.CheckHostilityChanged(other, canSendHostilityChangedLetter); 34 | return false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/RW_Patches/GoodwillSituationWorker_MemeCompatibility_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class GoodwillSituationWorker_MemeCompatibility_Patch 7 | { 8 | public static void RunDestructivePatches() 9 | { 10 | Type original = typeof(GoodwillSituationWorker_MemeCompatibility); 11 | Type patched = typeof(GoodwillSituationWorker_MemeCompatibility_Patch); 12 | RimThreadedHarmony.Prefix(original, patched, nameof(Applies), new Type[] { typeof(Faction), typeof(Faction) }); 13 | } 14 | 15 | public static bool Applies(GoodwillSituationWorker_MemeCompatibility __instance, ref bool __result, Faction a, Faction b) 16 | { 17 | Ideo primaryIdeo1 = a.ideos.PrimaryIdeo; 18 | if (primaryIdeo1 == null) 19 | return false; 20 | GoodwillSituationDef def = __instance.def; 21 | if (def == null) 22 | { 23 | __result = false; 24 | return false; 25 | } 26 | if (def.versusAll) 27 | return primaryIdeo1.memes.Contains(def.meme); 28 | Ideo primaryIdeo2 = b.ideos.PrimaryIdeo; 29 | return primaryIdeo2 != null && primaryIdeo1.memes.Contains(def.meme) && primaryIdeo2.memes.Contains(def.otherMeme); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/RW_Patches/GraphicDatabaseHeadRecords_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using static RimThreaded.RimThreaded; 4 | using static System.Threading.Thread; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class GraphicDatabaseHeadRecords_Patch 10 | { 11 | 12 | internal static void RunDestructivePatches() 13 | { 14 | //Type original = typeof(GraphicDatabaseHeadRecords); 15 | //Type patched = typeof(GraphicDatabaseHeadRecords_Patch); 16 | //RimThreadedHarmony.Prefix(original, patched, nameof(BuildDatabaseIfNecessary)); 17 | } 18 | 19 | /* 20 | private static readonly Action SafeFunction = parameters => 21 | GraphicDatabaseHeadRecords.BuildDatabaseIfNecessary(); 22 | 23 | public static bool BuildDatabaseIfNecessary() 24 | { 25 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 26 | return true; 27 | threadInfo.safeFunctionRequest = new object[] { SafeFunction, new object[] { } }; 28 | mainThreadWaitHandle.Set(); 29 | threadInfo.eventWaitStart.WaitOne(); 30 | return false; 31 | } 32 | */ 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/RW_Patches/GraphicsFormatUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using HarmonyLib; 4 | using UnityEngine; 5 | using static HarmonyLib.AccessTools; 6 | using static RimThreaded.RimThreaded; 7 | using static System.Threading.Thread; 8 | using UnityEngine.Experimental.Rendering; 9 | 10 | namespace RimThreaded.RW_Patches 11 | { 12 | class GraphicsFormatUtility_Patch 13 | { 14 | private static readonly Type original = typeof(GraphicsFormatUtility); 15 | private static readonly Type patched = typeof(GraphicsFormatUtility_Patch); 16 | 17 | private static readonly MethodInfo methodGetGraphicsFormat = 18 | Method(original, "GetGraphicsFormat", new Type[] { typeof(RenderTextureFormat), typeof(RenderTextureReadWrite) }); 19 | 20 | private static readonly Func funcGetGraphicsFormat = 21 | (Func)Delegate.CreateDelegate( 22 | typeof(Func), methodGetGraphicsFormat); 23 | 24 | private static readonly Func funcGetGraphicsFormat2 = parameters => 25 | funcGetGraphicsFormat((RenderTextureFormat)parameters[0], (RenderTextureReadWrite)parameters[1]); 26 | 27 | internal static void RunDestructivePatches() 28 | { 29 | RimThreadedHarmony.harmony.Patch(methodGetGraphicsFormat, 30 | prefix: new HarmonyMethod(Method(patched, nameof(GetGraphicsFormat)))); 31 | } 32 | 33 | public static bool GetGraphicsFormat(ref GraphicsFormat __result, RenderTextureFormat format, RenderTextureReadWrite readWrite) 34 | { 35 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 36 | return true; 37 | threadInfo.safeFunctionRequest = new object[] { funcGetGraphicsFormat2, new object[] { format, readWrite } }; 38 | mainThreadWaitHandle.Set(); 39 | threadInfo.eventWaitStart.WaitOne(); 40 | __result = (GraphicsFormat)threadInfo.safeFunctionResult; 41 | return false; 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/RW_Patches/IdeoManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using RimWorld; 5 | using Verse; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class IdeoManager_Patch 10 | { 11 | internal static void RunNonDestructivePatches()//there may be the need for locks in the IdeoManager 12 | { 13 | Type original = typeof(IdeoManager); 14 | } 15 | public static List Ideos; 16 | public static int IdeosCount; 17 | 18 | public static void IdeosPrepare() 19 | { 20 | Ideos = Current.Game.World.ideoManager.ideos; 21 | IdeosCount = Ideos.Count; 22 | } 23 | public static void IdeosTick() 24 | { 25 | while (true) 26 | { 27 | int index = Interlocked.Decrement(ref IdeosCount); 28 | if (index < 0) return; 29 | try 30 | { 31 | Ideos[index].IdeoTick(); 32 | } 33 | catch (Exception e) 34 | { 35 | Log.Error("Exception ticking Ideo: " + Ideos[index].ToString() + ": " + e); 36 | } 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Source/RW_Patches/ImmunityHandler_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | using static Verse.ImmunityHandler; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class ImmunityHandler_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(ImmunityHandler); 14 | Type patched = typeof(ImmunityHandler_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "ImmunityHandlerTick"); 16 | } 17 | 18 | public static bool ImmunityHandlerTick(ImmunityHandler __instance) 19 | { 20 | List list = __instance.NeededImmunitiesNow(); 21 | for (int i = 0; i < list.Count; i++) 22 | { 23 | __instance.TryAddImmunityRecord(list[i].immunity, list[i].source); 24 | } 25 | lock (__instance) 26 | { 27 | List newImmunityList = new List(__instance.immunityList); 28 | for (int j = 0; j < __instance.immunityList.Count; j++) 29 | { 30 | ImmunityRecord immunityRecord = newImmunityList[j]; 31 | Hediff firstHediffOfDef = __instance.pawn.health.hediffSet.GetFirstHediffOfDef(immunityRecord.hediffDef); 32 | immunityRecord.ImmunityTick(__instance.pawn, firstHediffOfDef != null, firstHediffOfDef); 33 | } 34 | for (int num = newImmunityList.Count - 1; num >= 0; num--) 35 | { 36 | if (newImmunityList[num].immunity <= 0f) 37 | { 38 | bool flag = false; 39 | for (int k = 0; k < list.Count; k++) 40 | { 41 | if (list[k].immunity == newImmunityList[num].hediffDef) 42 | { 43 | flag = true; 44 | break; 45 | } 46 | } 47 | 48 | if (!flag) 49 | { 50 | newImmunityList.RemoveAt(num); 51 | } 52 | } 53 | } 54 | __instance.immunityList = newImmunityList; 55 | } 56 | return false; 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Source/RW_Patches/JobDriver_TendPatient_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class JobDriver_TendPatient_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(JobDriver_TendPatient); 12 | Type patched = typeof(JobDriver_TendPatient_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(get_Deliveree)); 14 | } 15 | public static bool get_Deliveree(JobDriver_TendPatient __instance, ref Pawn __result) 16 | { 17 | __result = (Pawn)__instance?.job?.targetA.Thing; 18 | return false; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/RW_Patches/JobGiver_WanderNearDutyLocation_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using Verse.AI; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class JobGiver_WanderNearDutyLocation_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(JobGiver_WanderNearDutyLocation); 12 | Type patched = typeof(JobGiver_WanderNearDutyLocation_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(GetWanderRoot)); 14 | } 15 | public static bool GetWanderRoot(JobGiver_WanderNearDutyLocation __instance, ref IntVec3 __result, Pawn pawn) 16 | { 17 | __result = IntVec3.Invalid; 18 | PawnDuty duty = pawn.mindState.duty; 19 | if (duty != null) 20 | { 21 | __result = WanderUtility.BestCloseWanderRoot(duty.focus.Cell, pawn); 22 | } 23 | return false; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/RW_Patches/JobMaker_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using Verse; 4 | using Verse.AI; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public static class JobMaker_Patch 10 | { 11 | public static ConcurrentStack jobStack = new ConcurrentStack(); 12 | 13 | public static void RunDestructivePatches() 14 | { 15 | Type original = typeof(JobMaker); 16 | Type patched = typeof(JobMaker_Patch); 17 | RimThreadedHarmony.Prefix(original, patched, "MakeJob", new Type[] { }); 18 | RimThreadedHarmony.Prefix(original, patched, "ReturnToPool"); 19 | } 20 | 21 | public static bool MakeJob(ref Job __result) 22 | { 23 | if (!jobStack.TryPop(out Job job)) 24 | { 25 | job = new Job(); 26 | } 27 | job.loadID = Find.UniqueIDsManager.GetNextJobID(); 28 | __result = job; 29 | return false; 30 | } 31 | 32 | public static bool ReturnToPool(Job job) 33 | { 34 | if (job == null || jobStack.Count >= 1000) 35 | return false; 36 | job.Clear(); 37 | jobStack.Push(job); 38 | return false; 39 | } 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Source/RW_Patches/LightningBoltMeshMaker_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using UnityEngine; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class LightningBoltMeshMaker_Patch 11 | { 12 | static readonly Func FuncLightningBoltMeshMaker = parameters => 13 | LightningBoltMeshMaker.NewBoltMesh(); 14 | 15 | internal static void RunDestructivePatches() 16 | { 17 | Type original = typeof(LightningBoltMeshMaker); 18 | Type patched = typeof(LightningBoltMeshMaker_Patch); 19 | RimThreadedHarmony.Prefix(original, patched, "NewBoltMesh"); 20 | } 21 | 22 | public static bool NewBoltMesh(ref Mesh __result) 23 | { 24 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 25 | return true; 26 | threadInfo.safeFunctionRequest = new object[] { FuncLightningBoltMeshMaker, new object[] { } }; 27 | mainThreadWaitHandle.Set(); 28 | threadInfo.eventWaitStart.WaitOne(); 29 | __result = (Mesh)threadInfo.safeFunctionResult; 30 | return false; 31 | } 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/RW_Patches/ListerBuildingsRepairable_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class ListerBuildingsRepairable_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(ListerBuildingsRepairable); 13 | Type patched = typeof(ListerBuildingsRepairable_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(UpdateBuilding)); 15 | RimThreadedHarmony.Prefix(original, patched, nameof(Notify_BuildingDeSpawned)); 16 | } 17 | public static bool Notify_BuildingDeSpawned(ListerBuildingsRepairable __instance, Building b) 18 | { 19 | if (b.Faction != null) 20 | { 21 | lock (__instance) 22 | { 23 | __instance.ListFor(b.Faction).Remove(b); 24 | __instance.HashSetFor(b.Faction).Remove(b); 25 | } 26 | } 27 | return false; 28 | } 29 | public static bool UpdateBuilding(ListerBuildingsRepairable __instance, Building b) 30 | { 31 | Faction faction = b.Faction; 32 | if (faction == null || !b.def.building.repairable) 33 | return false; 34 | lock (__instance) 35 | { 36 | List thingList = __instance.ListFor(faction); 37 | HashSet thingSet = __instance.HashSetFor(faction); 38 | if (b.HitPoints < b.MaxHitPoints) 39 | { 40 | if (!thingList.Contains(b)) 41 | thingList.Add(b); 42 | thingSet.Add(b); 43 | } 44 | else 45 | { 46 | List newthingList = new List(thingList); 47 | newthingList.Remove(b); 48 | __instance.repairables[faction] = newthingList; 49 | HashSet newthingSet = new HashSet(thingSet); 50 | newthingSet.Remove(b); 51 | __instance.repairablesSet[faction] = newthingSet; 52 | } 53 | } 54 | return false; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Source/RW_Patches/LongEventHandler_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using System.Collections.Concurrent; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | 8 | public class LongEventHandler_Patch 9 | { 10 | 11 | public static ConcurrentQueue toExecuteWhenFinished2 = new ConcurrentQueue(); 12 | 13 | internal static void RunDestructivePatches() 14 | { 15 | Type original = typeof(LongEventHandler); 16 | Type patched = typeof(LongEventHandler_Patch); 17 | RimThreadedHarmony.Prefix(original, patched, "ExecuteToExecuteWhenFinished"); 18 | RimThreadedHarmony.Prefix(original, patched, "ExecuteWhenFinished"); 19 | } 20 | public static void RunNonDestructivePatches() 21 | { 22 | Type original = typeof(LongEventHandler); 23 | Type patched = typeof(LongEventHandler_Patch); 24 | RimThreadedHarmony.Prefix(original, patched, "RunEventFromAnotherThread", null, false); 25 | } 26 | 27 | public static bool ExecuteToExecuteWhenFinished() 28 | { 29 | if (toExecuteWhenFinished2.Count > 0) 30 | { 31 | DeepProfiler.Start("ExecuteToExecuteWhenFinished()"); 32 | } 33 | while (toExecuteWhenFinished2.TryDequeue(out Action action)) 34 | { 35 | DeepProfiler.Start(action.Method.DeclaringType + " -> " + action.Method); 36 | try 37 | { 38 | action(); 39 | } 40 | catch (Exception arg) 41 | { 42 | Log.Error("Could not execute post-long-event action. Exception: " + arg); 43 | } 44 | finally 45 | { 46 | DeepProfiler.End(); 47 | } 48 | } 49 | 50 | if (toExecuteWhenFinished2.Count > 0) 51 | { 52 | DeepProfiler.End(); 53 | } 54 | 55 | LongEventHandler.toExecuteWhenFinished.Clear(); 56 | return false; 57 | } 58 | public static bool ExecuteWhenFinished(Action action) 59 | { 60 | toExecuteWhenFinished2.Enqueue(action); 61 | return true; 62 | } 63 | 64 | public static bool RunEventFromAnotherThread(Action action) 65 | { 66 | RimThreaded.InitializeAllThreadStatics(); 67 | return true; 68 | } 69 | 70 | } 71 | 72 | 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Source/RW_Patches/LordManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using Verse.AI.Group; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class LordManager_Patch 8 | { 9 | 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(LordManager); 13 | Type patched = typeof(LordManager_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "LordOf", new Type[] { typeof(Pawn) }); 15 | RimThreadedHarmony.Prefix(original, patched, "RemoveLord"); 16 | } 17 | 18 | public static bool LordOf(LordManager __instance, ref Lord __result, Pawn p) 19 | { 20 | Lord lordResult = null; 21 | if (p != null) 22 | { 23 | if (!Lord_Patch.pawnsLord.TryGetValue(p, out lordResult)) 24 | { 25 | for (int i = 0; i < __instance.lords.Count; i++) 26 | { 27 | Lord lord = __instance.lords[i]; 28 | for (int j = 0; j < lord.ownedPawns.Count; j++) 29 | { 30 | if (lord.ownedPawns[j] == p) 31 | { 32 | lock (Lord_Patch.pawnsLord) 33 | { 34 | Lord_Patch.pawnsLord.SetOrAdd(p, lord); 35 | } 36 | __result = lord; 37 | return false; 38 | } 39 | } 40 | } 41 | lock (Lord_Patch.pawnsLord) 42 | { 43 | Lord_Patch.pawnsLord.SetOrAdd(p, null); 44 | } 45 | } 46 | } 47 | __result = lordResult; 48 | return false; 49 | } 50 | public static bool RemoveLord(LordManager __instance, Lord oldLord) 51 | { 52 | for (int j = 0; j < oldLord.ownedPawns.Count; j++) 53 | { 54 | lock (Lord_Patch.pawnsLord) 55 | { 56 | Lord_Patch.pawnsLord.SetOrAdd(oldLord.ownedPawns[j], null); 57 | } 58 | } 59 | __instance.lords.Remove(oldLord); 60 | Find.SignalManager.DeregisterReceiver(oldLord); 61 | oldLord.Cleanup(); 62 | return false; 63 | } 64 | 65 | } 66 | } -------------------------------------------------------------------------------- /Source/RW_Patches/MapGenerator_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | using RimWorld.Planet; 5 | using static RimThreaded.RimThreaded; 6 | using static System.Threading.Thread; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | 11 | public class MapGenerator_Patch 12 | { 13 | static readonly Func FuncGenerateMap = parameters => 14 | MapGenerator.GenerateMap( 15 | (IntVec3)parameters[0], 16 | (MapParent)parameters[1], 17 | (MapGeneratorDef)parameters[2], 18 | (IEnumerable)parameters[3], 19 | (Action)parameters[4]); 20 | 21 | 22 | internal static void RunDestructivePatches() 23 | { 24 | Type original = typeof(MapGenerator); 25 | Type patched = typeof(MapGenerator_Patch); 26 | RimThreadedHarmony.Prefix(original, patched, "GenerateMap"); 27 | } 28 | 29 | public static bool GenerateMap(ref Map __result, IntVec3 mapSize, MapParent parent, MapGeneratorDef mapGenerator, IEnumerable extraGenStepDefs = null, Action extraInitBeforeContentGen = null) 30 | { 31 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 32 | return true; 33 | threadInfo.timeoutExempt = 60000; 34 | threadInfo.safeFunctionRequest = new object[] { FuncGenerateMap, new object[] { 35 | mapSize, parent, mapGenerator, extraGenStepDefs, extraInitBeforeContentGen } }; 36 | mainThreadWaitHandle.Set(); 37 | threadInfo.eventWaitStart.WaitOne(); 38 | threadInfo.timeoutExempt = 0; 39 | __result = (Map)threadInfo.safeFunctionResult; 40 | return false; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/RW_Patches/Map_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class Map_Patch 9 | { 10 | 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(Map); 14 | Type patched = typeof(Map_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "get_IsPlayerHome"); 16 | } 17 | 18 | public static bool get_IsPlayerHome(Map __instance, ref bool __result) 19 | { 20 | if (__instance.info != null && __instance.info.parent != null && __instance.info.parent.def != null && __instance.info.parent.def.canBePlayerHome) 21 | { 22 | __result = __instance.info.parent.Faction == Faction.OfPlayer; 23 | return false; 24 | } 25 | __result = false; 26 | return false; 27 | 28 | } 29 | 30 | public static void MapsPostTickPrepare() 31 | { 32 | SteadyEnvironmentEffects_Patch.totalSteadyEnvironmentEffectsTicks = 0; 33 | SteadyEnvironmentEffects_Patch.steadyEnvironmentEffectsTicksCompleted = 0; 34 | SteadyEnvironmentEffects_Patch.steadyEnvironmentEffectsCount = 0; 35 | WildPlantSpawner_Patch.wildPlantSpawnerCount = 0; 36 | WildPlantSpawner_Patch.wildPlantSpawnerTicksCount = 0; 37 | WildPlantSpawner_Patch.wildPlantSpawnerTicksCompleted = 0; 38 | TradeShip_Patch.totalTradeShipTicks = 0; 39 | TradeShip_Patch.totalTradeShipTicksCompleted = 0; 40 | TradeShip_Patch.totalTradeShipsCount = 0; 41 | try 42 | { 43 | List maps = Find.Maps; 44 | for (int j = 0; j < maps.Count; j++) 45 | { 46 | Map map = maps[j]; 47 | map.MapPostTick(); 48 | } 49 | } 50 | catch (Exception ex3) 51 | { 52 | Log.Error(ex3.ToString()); 53 | } 54 | 55 | } 56 | 57 | public static void MapPostListTick() 58 | { 59 | SteadyEnvironmentEffects_Patch.SteadyEffectTick(); 60 | WildPlantSpawner_Patch.WildPlantSpawnerListTick(); 61 | TradeShip_Patch.PassingShipListTick(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/RW_Patches/MaterialPool_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Verse; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | public class MaterialPool_Patch 10 | { 11 | static readonly Func FuncMatFrom = parameters => 12 | MaterialPool.MatFrom((MaterialRequest)parameters[0]); 13 | 14 | public static void RunDestructivePatches() 15 | { 16 | Type original = typeof(MaterialPool); 17 | Type patched = typeof(MaterialPool_Patch); 18 | RimThreadedHarmony.Prefix(original, patched, "MatFrom", new Type[] { typeof(MaterialRequest) }); 19 | } 20 | 21 | public static bool MatFrom(ref Material __result, MaterialRequest req) 22 | { 23 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 24 | return true; 25 | threadInfo.safeFunctionRequest = new object[] { FuncMatFrom, new object[] { req } }; 26 | mainThreadWaitHandle.Set(); 27 | threadInfo.eventWaitStart.WaitOne(); 28 | __result = (Material)threadInfo.safeFunctionResult; 29 | return false; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Source/RW_Patches/MemoryUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse.Profile; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class MemoryUtility_Patch 7 | { 8 | private static readonly Type Original = typeof(MemoryUtility); 9 | private static readonly Type Patched = typeof(MemoryUtility_Patch); 10 | 11 | public static void RunNonDestructivePatches() 12 | { 13 | RimThreadedHarmony.Postfix(Original, Patched, "ClearAllMapsAndWorld"); 14 | } 15 | 16 | public static void ClearAllMapsAndWorld() 17 | { 18 | //GenTemperature_Patch.SeasonalShiftAmplitudeCache.Clear(); 19 | RimThreaded.billFreeColonistsSpawned.Clear(); 20 | RimThreaded.plantHarvest_Cache.positionsAwaitingAction.Clear(); 21 | RimThreaded.plantSowing_Cache.positionsAwaitingAction.Clear(); 22 | HaulingCache.waitingForZoneBetterThanMapDict.Clear(); 23 | HaulingCache.awaitingHaulingMapDict.Clear(); 24 | ListerThings_Patch.mapToGroupToZoomsToGridToThings.Clear(); 25 | WorkGiver_Grower_Patch.awaitingPlantCellsMapDict.Clear(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/RW_Patches/MeshMakerPlanes_Patch.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using Verse; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | using static HarmonyLib.AccessTools; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | 11 | public class MeshMakerPlanes_Patch 12 | { 13 | internal static void RunDestructivePatches() 14 | { 15 | Type original = typeof(MeshMakerPlanes); 16 | Type patched = typeof(MeshMakerPlanes_Patch); 17 | //RimThreadedHarmony.Prefix(original, patched, "NewPlaneMesh", new Type[] { typeof(Vector2), typeof(bool), typeof(bool), typeof(bool) }); 18 | } 19 | 20 | static readonly Func FuncNewPlaneMesh = p => 21 | MeshMakerPlanes.NewPlaneMesh((Vector2)p[0], (bool)p[1], (bool)p[2], (bool)p[3]); 22 | 23 | 24 | 25 | private static readonly Func FuncNewPlaneMesh1 = 26 | (Func)Delegate.CreateDelegate( 27 | typeof(Func), 28 | Method(typeof(MeshMakerPlanes), "NewPlaneMesh", new Type[] { typeof(Vector2), typeof(bool), typeof(bool), typeof(bool) })); 29 | 30 | private static readonly Func FuncNewPlaneMesh2 = parameters => 31 | FuncNewPlaneMesh1((Vector2)parameters[0], (bool)parameters[1], (bool)parameters[2], (bool)parameters[3]); 32 | 33 | 34 | public static Mesh NewPlaneMesh(Vector2 size, bool flipped, bool backLift, bool twist) 35 | { 36 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 37 | return MeshMakerPlanes.NewPlaneMesh(size, flipped, backLift, twist); 38 | threadInfo.safeFunctionRequest = new object[] { FuncNewPlaneMesh2, new object[] { size, flipped, backLift, twist } }; 39 | mainThreadWaitHandle.Set(); 40 | threadInfo.eventWaitStart.WaitOne(); 41 | return (Mesh)threadInfo.safeFunctionResult; 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/RW_Patches/MeshMakerShadows_Patch.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using System; 3 | using Verse; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | public class MeshMakerShadows_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(MeshMakerShadows); 14 | Type patched = typeof(MeshMakerShadows_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "NewShadowMesh", new Type[] { typeof(float), typeof(float), typeof(float) }); 16 | } 17 | 18 | static readonly Func FuncNewShadowMesh = parameters => 19 | MeshMakerShadows.NewShadowMesh( 20 | (float)parameters[0], 21 | (float)parameters[1], 22 | (float)parameters[2]); 23 | 24 | public static bool NewShadowMesh(ref Mesh __result, float baseWidth, float baseHeight, float tallness) 25 | { 26 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 27 | return true; 28 | threadInfo.safeFunctionRequest = new object[] { FuncNewShadowMesh, new object[] { baseWidth, baseHeight, tallness } }; 29 | mainThreadWaitHandle.Set(); 30 | threadInfo.eventWaitStart.WaitOne(); 31 | __result = (Mesh)threadInfo.safeFunctionResult; 32 | return false; 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/RW_Patches/Mesh_Transpile.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using UnityEngine; 5 | using System.Reflection.Emit; 6 | using System.Linq; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | public class Mesh_Transpile 11 | { 12 | public static IEnumerable Mesh(IEnumerable instructions, ILGenerator iLGenerator) 13 | { 14 | 15 | List instructionsList = instructions.ToList(); 16 | int i = 0; 17 | while (i < instructionsList.Count) 18 | { 19 | if ( 20 | instructionsList[i].opcode == OpCodes.Call && 21 | (MethodInfo)instructionsList[i].operand == AccessTools.Method(typeof(Mesh), "InternalCreate") 22 | ) 23 | { 24 | } 25 | else 26 | { 27 | yield return instructionsList[i]; 28 | i++; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/RW_Patches/MoteBubble_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Threading; 4 | using UnityEngine; 5 | using Verse; 6 | using static RimThreaded.RimThreaded; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | class MoteBubble_Patch 11 | { 12 | internal static void RunDestructivePatches() 13 | { 14 | Type original = typeof(MoteBubble); 15 | Type patched = typeof(MoteBubble_Patch); 16 | RimThreadedHarmony.Prefix(original, patched, nameof(SetupMoteBubble)); 17 | } 18 | public static bool SetupMoteBubble(MoteBubble __instance, Texture2D icon, Pawn target, Color? iconColor = null) 19 | { 20 | __instance.iconMat = MaterialPool.MatFrom(icon, ShaderDatabase.TransparentPostLight, Color.white); 21 | //__instance.iconMatPropertyBlock = new MaterialPropertyBlock(); 22 | if (!allWorkerThreads.TryGetValue(Thread.CurrentThread, out ThreadInfo threadInfo)) 23 | { 24 | __instance.iconMatPropertyBlock = new MaterialPropertyBlock(); 25 | } 26 | else 27 | { 28 | Func FuncMaterialPropertyBlock = parameters => new MaterialPropertyBlock(); 29 | threadInfo.safeFunctionRequest = new object[] { FuncMaterialPropertyBlock, new object[] { } }; 30 | mainThreadWaitHandle.Set(); 31 | threadInfo.eventWaitStart.WaitOne(); 32 | __instance.iconMatPropertyBlock = (MaterialPropertyBlock)threadInfo.safeFunctionResult; 33 | } 34 | 35 | __instance.arrowTarget = target; 36 | if (!iconColor.HasValue) 37 | return false; 38 | __instance.iconMatPropertyBlock.SetColor("_Color", iconColor.Value); 39 | return false; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Source/RW_Patches/OverlayDrawer_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class OverlayDrawer_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(OverlayDrawer); 12 | Type patched = typeof(OverlayDrawer_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(GetOverlaysHandle)); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(DisposeHandle)); 15 | } 16 | 17 | public static bool GetOverlaysHandle(OverlayDrawer __instance, ref ThingOverlaysHandle __result, Thing thing) 18 | { 19 | if (!thing.Spawned) 20 | { 21 | __result = null; 22 | return false; 23 | } 24 | ThingOverlaysHandle thingOverlaysHandle; 25 | lock (__instance) //added 26 | { 27 | if (!__instance.overlayHandles.TryGetValue(thing, out thingOverlaysHandle)) 28 | { 29 | thingOverlaysHandle = new ThingOverlaysHandle(__instance, thing); 30 | __instance.overlayHandles.Add(thing, thingOverlaysHandle); 31 | } 32 | } 33 | __result = thingOverlaysHandle; 34 | return false; 35 | } 36 | public static bool DisposeHandle(OverlayDrawer __instance, Thing thing) 37 | { 38 | ThingOverlaysHandle thingOverlaysHandle; 39 | lock (__instance) //added 40 | { 41 | if (__instance.overlayHandles.TryGetValue(thing, out thingOverlaysHandle)) 42 | { 43 | thingOverlaysHandle.Dispose(); 44 | __instance.overlayHandles.Remove(thing); 45 | } 46 | } 47 | return false; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/RW_Patches/Patch_TryOpportunisticJob_Transpile.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection.Emit; 5 | using Verse; 6 | using static HarmonyLib.AccessTools; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | class Patch_TryOpportunisticJob_Transpile 11 | { 12 | public static IEnumerable TryOpportunisticJob(IEnumerable instructions, ILGenerator iLGenerator) 13 | { 14 | int[] matchesFound = new int[1]; 15 | List instructionsList = instructions.ToList(); 16 | int i = 0; 17 | while (i < instructionsList.Count) 18 | { 19 | int matchIndex = 0; 20 | if ( 21 | i + 3 < instructionsList.Count && 22 | instructionsList[i + 3].opcode == OpCodes.Callvirt && 23 | instructionsList[i + 3].operand.ToString().Contains("GetValue") 24 | ) 25 | { 26 | matchesFound[matchIndex]++; 27 | instructionsList[i].opcode = OpCodes.Call; 28 | instructionsList[i].operand = Method(typeof(Patch_TryOpportunisticJob), "getPawn"); 29 | yield return instructionsList[i++]; 30 | i += 3; 31 | } 32 | yield return instructionsList[i++]; 33 | } 34 | for (int mIndex = 0; mIndex < matchesFound.Length; mIndex++) 35 | { 36 | if (matchesFound[mIndex] < 1) 37 | Log.Error("IL code instruction set " + mIndex + " not found"); 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/RW_Patches/PawnCapacityUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Verse; 7 | using static Verse.PawnCapacityUtility; 8 | 9 | namespace RimThreaded.RW_Patches 10 | { 11 | public class PawnCapacityUtility_Patch 12 | { 13 | internal static void RunNonDestructivePatches() 14 | { 15 | Type original = typeof(PawnCapacityUtility); 16 | Type patched = typeof(PawnCapacityUtility_Patch); 17 | RimThreadedHarmony.Prefix(original, patched, nameof(CalculatePartEfficiency), null, false); 18 | } 19 | 20 | public static bool CalculatePartEfficiency(ref float __result, HediffSet diffSet, BodyPartRecord part, bool ignoreAddedParts = false, List impactors = null) 21 | { 22 | if(part == null) 23 | { 24 | __result = 0f; 25 | return false; 26 | } 27 | return true; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/RW_Patches/PawnPathPool_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse.AI; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class PawnPathPool_Patch 8 | { 9 | [ThreadStatic] public static List threadStaticPaths; 10 | 11 | internal static void InitializeThreadStatics() 12 | { 13 | threadStaticPaths = new List(64); 14 | } 15 | public static void RunDestructivePatches() 16 | { 17 | Type original = typeof(PawnPathPool); 18 | Type patched = typeof(PawnPathPool_Patch); 19 | RimThreadedHarmony.Prefix(original, patched, "GetEmptyPawnPath"); 20 | } 21 | 22 | public static bool GetEmptyPawnPath(PawnPathPool __instance, ref PawnPath __result) 23 | { 24 | for (int index = 0; index < threadStaticPaths.Count; ++index) 25 | { 26 | if (!threadStaticPaths[index].inUse) 27 | { 28 | threadStaticPaths[index].inUse = true; 29 | __result = threadStaticPaths[index]; 30 | return false; 31 | } 32 | } 33 | //if (threadStaticPaths.Count > this.map.mapPawns.AllPawnsSpawnedCount + 2) 34 | //{ 35 | // Log.ErrorOnce("PawnPathPool leak: more paths than spawned pawns. Force-recovering.", 664788); 36 | // this.paths.Clear(); 37 | //} 38 | PawnPath pawnPath = new PawnPath(); 39 | threadStaticPaths.Add(pawnPath); 40 | pawnPath.inUse = true; 41 | __result = pawnPath; 42 | return false; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Source/RW_Patches/PawnPath_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | using Verse.AI; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class PawnPath_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(PawnPath); 14 | Type patched = typeof(PawnPath_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "AddNode"); 16 | RimThreadedHarmony.Prefix(original, patched, "ReleaseToPool"); 17 | } 18 | public static bool AddNode(PawnPath __instance, IntVec3 nodePosition) 19 | { 20 | lock (__instance) 21 | { 22 | __instance.nodes.Add(nodePosition); 23 | } 24 | return false; 25 | } 26 | public static bool ReleaseToPool(PawnPath __instance) 27 | { 28 | if (__instance == PawnPath.NotFound) return false; 29 | __instance.totalCostInt = 0f; 30 | __instance.usedRegionHeuristics = false; 31 | lock (__instance) 32 | { 33 | __instance.nodes = new List(); 34 | } 35 | __instance.inUse = false; 36 | return false; 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/RW_Patches/Pawn_JobTracker_DetermineNextJob_Transpile.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Verse; 5 | using System.Reflection.Emit; 6 | using Verse.AI; 7 | using static HarmonyLib.AccessTools; 8 | 9 | namespace RimThreaded.RW_Patches 10 | { 11 | public class Pawn_JobTracker_DetermineNextJob_Transpile 12 | { 13 | public static FieldRef jobTrackerPawn = FieldRefAccess("pawn"); 14 | public static IEnumerable Postfix(IEnumerable instructions, ILGenerator iLGenerator) 15 | { 16 | List instructionsList = instructions.ToList(); 17 | int i = 0; 18 | bool matchFound = false; 19 | while (i < instructionsList.Count) 20 | { 21 | if (i + 5 < instructionsList.Count && 22 | instructionsList[i + 5].opcode == OpCodes.Stloc_0) 23 | { 24 | matchFound = true; 25 | instructionsList[i].opcode = OpCodes.Ldsfld; 26 | instructionsList[i].operand = Field(typeof(Pawn_JobTracker_DetermineNextJob_Transpile), "jobTrackerPawn"); 27 | yield return instructionsList[i]; 28 | i++; 29 | instructionsList[i].opcode = OpCodes.Ldarg_0; 30 | instructionsList[i].operand = null; 31 | yield return instructionsList[i]; 32 | i++; 33 | instructionsList[i].opcode = OpCodes.Callvirt; 34 | instructionsList[i].operand = Method(typeof(FieldRef), "Invoke"); 35 | yield return instructionsList[i]; 36 | i++; 37 | instructionsList[i].opcode = OpCodes.Ldind_Ref; 38 | instructionsList[i].operand = null; 39 | yield return instructionsList[i]; 40 | i += 2; 41 | } 42 | else 43 | { 44 | yield return instructionsList[i]; 45 | i++; 46 | } 47 | } 48 | if (!matchFound) 49 | { 50 | Log.Error("IL code instructions not found"); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Source/RW_Patches/Pawn_RotationTracker_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class Pawn_RotationTracker_Patch 7 | { 8 | public static void RunDestructivePatches() 9 | { 10 | Type original = typeof(Pawn_RotationTracker); 11 | Type patched = typeof(Pawn_RotationTracker_Patch); 12 | RimThreadedHarmony.Prefix(original, patched, nameof(UpdateRotation)); 13 | } 14 | 15 | public static bool UpdateRotation(Pawn_RotationTracker __instance) 16 | { 17 | if (__instance.pawn.Destroyed || __instance.pawn.jobs.HandlingFacing) 18 | { 19 | return false; 20 | } 21 | Stance_Busy stance_Busy = __instance.pawn.stances.curStance as Stance_Busy; 22 | if (stance_Busy != null && stance_Busy.focusTarg.IsValid) 23 | { 24 | if (stance_Busy.focusTarg.HasThing) 25 | { 26 | __instance.Face(stance_Busy.focusTarg.Thing.DrawPos); 27 | } 28 | else 29 | { 30 | __instance.FaceCell(stance_Busy.focusTarg.Cell); 31 | } 32 | return false; 33 | } 34 | if (__instance.pawn.pather.Moving) 35 | { 36 | if (__instance.pawn.pather.curPath != null && __instance.pawn.pather.curPath.NodesLeftCount >= 1) 37 | { 38 | __instance.FaceAdjacentCell(__instance.pawn.pather.nextCell); 39 | } 40 | return false; 41 | } 42 | Verse.AI.Job curJob = __instance.pawn.CurJob; 43 | Verse.AI.JobDriver curDriver = __instance.pawn.jobs.curDriver; 44 | if (curJob != null && curDriver != null && __instance.pawn.jobs.curJob != null) 45 | { 46 | LocalTargetInfo target = curJob.GetTarget(curDriver.rotateToFace); 47 | __instance.FaceTarget(target); 48 | } 49 | if (__instance.pawn.Drafted) 50 | { 51 | __instance.pawn.Rotation = Rot4.South; 52 | } 53 | return false; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/RW_Patches/PlayLog_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | 8 | public class PlayLog_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(PlayLog); 13 | Type patched = typeof(PlayLog_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "Add"); 15 | RimThreadedHarmony.Prefix(original, patched, "RemoveEntry"); 16 | //RimThreadedHarmony.Prefix(original, patched, "AnyEntryConcerns"); 17 | } 18 | 19 | public static bool Add(PlayLog __instance, LogEntry entry) 20 | { 21 | lock (__instance) 22 | { 23 | List newEntries = new List(__instance.entries); 24 | newEntries.Insert(0, entry); 25 | while (newEntries.Count > 150) 26 | { 27 | newEntries.RemoveAt(newEntries.Count - 1); 28 | } 29 | __instance.entries = newEntries; 30 | } 31 | return false; 32 | } 33 | 34 | public static bool RemoveEntry(PlayLog __instance, LogEntry entry) 35 | { 36 | lock (__instance) 37 | { 38 | List newEntries = new List(__instance.entries); 39 | newEntries.Remove(entry); 40 | __instance.entries = newEntries; 41 | } 42 | return false; 43 | } 44 | /* 45 | public static bool AnyEntryConcerns(PlayLog __instance, Pawn p, ref bool __result) 46 | { 47 | List snapshotEntries = __instance.entries; 48 | for (int i = 0; i < snapshotEntries.Count; i++) 49 | { 50 | if (snapshotEntries[i].Concerns(p)) 51 | { 52 | __result = true; 53 | return false; 54 | } 55 | } 56 | __result = false; 57 | return false; 58 | } 59 | */ 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/RW_Patches/PortraitsCache_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RimWorld; 4 | using Verse; 5 | using UnityEngine; 6 | using static RimWorld.PortraitsCache; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | public class PortraitsCache_Patch 11 | { 12 | internal static void RunDestructivePatches() 13 | { 14 | Type original = typeof(PortraitsCache); 15 | Type patched = typeof(PortraitsCache_Patch); 16 | /* 17 | RimThreadedHarmony.Prefix(original, patched, nameof(Clear)); 18 | RimThreadedHarmony.Prefix(original, patched, nameof(GetOrCreateCachedPortraitsWithParams)); 19 | RimThreadedHarmony.Prefix(original, patched, nameof(NewRenderTexture)); 20 | RimThreadedHarmony.Prefix(original, patched, nameof(RemoveExpiredCachedPortraits)); 21 | RimThreadedHarmony.Prefix(original, patched, nameof(Get)); 22 | RimThreadedHarmony.Prefix(original, patched, nameof(SetAnimatedPortraitsDirty)); 23 | RimThreadedHarmony.Prefix(original, patched, nameof(SetDirty)); 24 | */ 25 | } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Source/RW_Patches/Rand_Patch.cs: -------------------------------------------------------------------------------- 1 | using Verse; 2 | using System; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | 7 | public static class Rand_Patch 8 | { 9 | public static object lockObject = new object(); 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(Rand); 13 | Type patched = typeof(Rand_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "PushState", Type.EmptyTypes); 15 | RimThreadedHarmony.Prefix(original, patched, "PopState"); 16 | } 17 | 18 | public static bool PushState() 19 | { 20 | lock (lockObject) 21 | { 22 | Rand.stateStack.Push(Rand.StateCompressed); 23 | } 24 | return false; 25 | } 26 | public static bool PopState() 27 | { 28 | lock (lockObject) 29 | { 30 | Rand.StateCompressed = Rand.stateStack.Pop(); 31 | } 32 | return false; 33 | } 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /Source/RW_Patches/RealtimeMoteList_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | 8 | public class RealtimeMoteList_Patch 9 | { 10 | public static void RunDestructivePatches() 11 | { 12 | Type original = typeof(RealtimeMoteList); 13 | Type patched = typeof(RealtimeMoteList_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "Clear"); 15 | RimThreadedHarmony.Prefix(original, patched, "MoteSpawned"); 16 | RimThreadedHarmony.Prefix(original, patched, "MoteDespawned"); 17 | } 18 | 19 | public static bool Clear(RealtimeMoteList __instance) 20 | { 21 | lock (__instance) 22 | { 23 | __instance.allMotes = new List(); 24 | } 25 | return false; 26 | } 27 | 28 | public static bool MoteSpawned(RealtimeMoteList __instance, Mote newMote) 29 | { 30 | lock (__instance) 31 | { 32 | __instance.allMotes.Add(newMote); 33 | } 34 | return false; 35 | } 36 | 37 | public static bool MoteDespawned(RealtimeMoteList __instance, Mote oldMote) 38 | { 39 | lock (__instance) 40 | { 41 | List newMotes = new List(__instance.allMotes); 42 | newMotes.Remove(oldMote); 43 | __instance.allMotes = newMotes; 44 | } 45 | return false; 46 | } 47 | 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Source/RW_Patches/RecipeWorkerCounter_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | public class RecipeWorkerCounter_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(RecipeWorkerCounter); 13 | Type patched = typeof(RecipeWorkerCounter_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "GetCarriedCount"); 15 | } 16 | 17 | public static bool GetCarriedCount(RecipeWorkerCounter __instance, ref int __result, Bill_Production bill, ThingDef prodDef) 18 | { 19 | int num = 0; 20 | //foreach (Pawn item in bill.Map.mapPawns.FreeColonistsSpawned) 21 | if (!RimThreaded.billFreeColonistsSpawned.TryGetValue(bill, out List freeColonistsSpawned)) 22 | { 23 | freeColonistsSpawned = bill.Map.mapPawns.FreeColonistsSpawned; 24 | RimThreaded.billFreeColonistsSpawned[bill] = freeColonistsSpawned; 25 | } 26 | for (int i = 0; i < freeColonistsSpawned.Count; i++) 27 | { 28 | Thing carriedThing = freeColonistsSpawned[i]?.carryTracker?.CarriedThing; 29 | if (carriedThing == null) continue; 30 | int stackCount = carriedThing.stackCount; 31 | carriedThing = carriedThing.GetInnerIfMinified(); 32 | if (__instance.CountValidThing(carriedThing, bill, prodDef)) 33 | { 34 | num += stackCount; 35 | } 36 | } 37 | 38 | __result = num; 39 | return false; 40 | } 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/RW_Patches/RecordWorker_TimeGettingJoy_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class RecordWorker_TimeGettingJoy_Patch 8 | { 9 | public static void RunDestructivePatches() 10 | { 11 | Type original = typeof(RecordWorker_TimeGettingJoy); 12 | Type patched = typeof(RecordWorker_TimeGettingJoy_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(ShouldMeasureTimeNow)); 14 | } 15 | public static bool ShouldMeasureTimeNow(RecordWorker_TimeGettingJoy __instance, ref bool __result, Pawn pawn) 16 | { 17 | __result = pawn?.CurJob?.def?.joyKind != null; 18 | return false; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/RW_Patches/RegionAndRoomQuery_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | 7 | public class RegionAndRoomQuery_Patch 8 | { 9 | 10 | static readonly Type original = typeof(RegionAndRoomQuery); 11 | static readonly Type patched = typeof(RegionAndRoomQuery_Patch); 12 | 13 | internal static void RunNonDestructivePatches() 14 | { 15 | RimThreadedHarmony.Postfix(original, patched, nameof(RoomAt)); 16 | } 17 | 18 | public static void RoomAt(ref Room __result, IntVec3 c, Map map, RegionType allowedRegionTypes = RegionType.Set_All) 19 | { 20 | if (__result == null) 21 | lock (map.regionAndRoomUpdater) 22 | { 23 | __result = RegionAndRoomQuery.DistrictAt(c, map, allowedRegionTypes)?.Room; 24 | } 25 | } 26 | 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /Source/RW_Patches/RegionLinkDatabase_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class RegionLinkDatabase_Patch 8 | { 9 | public static void RunDestructivePatches() 10 | { 11 | Type original = typeof(RegionLinkDatabase); 12 | Type patched = typeof(RegionLinkDatabase_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(LinkFrom)); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(Notify_LinkHasNoRegions)); 15 | } 16 | 17 | public static bool LinkFrom(RegionLinkDatabase __instance, ref RegionLink __result, EdgeSpan span) 18 | { 19 | ulong key = span.UniqueHashCode(); 20 | RegionLink value; 21 | Dictionary links = __instance.links; 22 | lock (links) 23 | { 24 | if (!links.TryGetValue(key, out value)) 25 | { 26 | value = new RegionLink(); 27 | value.span = span; 28 | links.Add(key, value); 29 | } 30 | } 31 | __result = value; 32 | return false; 33 | } 34 | public static bool Notify_LinkHasNoRegions(RegionLinkDatabase __instance, RegionLink link) 35 | { 36 | Dictionary links = __instance.links; 37 | lock (links) 38 | { 39 | links.Remove(link.UniqueHashCode()); 40 | } 41 | return false; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Source/RW_Patches/RegionLink_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class RegionLink_Patch 7 | { 8 | 9 | static readonly Type original = typeof(RegionLink); 10 | static readonly Type patched = typeof(RegionLink_Patch); 11 | 12 | internal static void RunDestructivePatches() 13 | { 14 | RimThreadedHarmony.Prefix(original, patched, nameof(Register)); 15 | } 16 | 17 | public static bool Register(RegionLink __instance, Region reg) 18 | { 19 | Region regionA = __instance.RegionA; 20 | Region regionB = __instance.RegionB; 21 | if (__instance.regions[0] == reg || __instance.regions[1] == reg) 22 | Log.Error("Tried to double-register region " + reg.ToString() + " in " + __instance); 23 | else if (regionA == null || !regionA.valid) 24 | __instance.RegionA = reg; 25 | else if (regionB == null || !regionB.valid) 26 | __instance.RegionB = reg; 27 | else 28 | { 29 | Log.Warning("Could not register region " + reg.ToString() + " in link " + __instance + 30 | ": > 2 regions on link!\nRegionA: " + __instance.RegionA.DebugString + "\nRegionB: " + 31 | __instance.RegionB.DebugString); 32 | 33 | //TODO find root cause 34 | //RegionAndRoomUpdater_Patch.regionsToReDirty.Add(regionA); 35 | //RegionAndRoomUpdater_Patch.regionsToReDirty.Add(regionB); 36 | //RegionAndRoomUpdater_Patch.regionsToReDirty.Add(reg); 37 | //RegionDirtyer_Patch.SetRegionDirty(reg.Map.regionDirtyer, regionA); 38 | //RegionDirtyer_Patch.SetRegionDirty(reg.Map.regionDirtyer, regionB); 39 | /* 40 | foreach (IntVec3 cell in reg.Cells) 41 | { 42 | if (regionA.Cells.Contains(cell)) 43 | { 44 | __instance.RegionA = reg; 45 | RegionDirtyer_Patch.SetRegionDirty(reg.Map.regionDirtyer, regionA); 46 | break; 47 | } 48 | if (regionB.Cells.Contains(cell)) 49 | { 50 | __instance.RegionB = reg; 51 | RegionDirtyer_Patch.SetRegionDirty(reg.Map.regionDirtyer, regionB); 52 | break; 53 | } 54 | } 55 | */ 56 | } 57 | 58 | return false; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/RW_Patches/Resources_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using static RimThreaded.RimThreaded; 4 | using static System.Threading.Thread; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class Resources_Patch 9 | { 10 | public static Func safeFunction = parameters => 11 | Resources.Load( 12 | (string)parameters[0], 13 | (Type)parameters[1]); 14 | 15 | public static UnityEngine.Object Load(string path, Type type) 16 | { 17 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 18 | return Resources.Load(path, type); 19 | threadInfo.safeFunctionRequest = new object[] { safeFunction, new object[] { path, type } }; 20 | mainThreadWaitHandle.Set(); 21 | threadInfo.eventWaitStart.WaitOne(); 22 | return (UnityEngine.Object)threadInfo.safeFunctionResult; 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Source/RW_Patches/RimWorld_Pawn_GuestTracker_SetGuestStatus_Transpile.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using RimWorld; 5 | using Verse; 6 | using System.Reflection.Emit; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | public class RimWorld_Pawn_GuestTracker_SetGuestStatus_Transpile 11 | { 12 | public static AccessTools.FieldRef pawn = AccessTools.FieldRefAccess("pawn"); 13 | public static IEnumerable Prefix(IEnumerable instructions, ILGenerator iLGenerator) 14 | { 15 | List instructionsList = instructions.ToList(); 16 | int currentInstructionIndex = 0; 17 | int matchFound = 0; 18 | while (currentInstructionIndex < instructionsList.Count) 19 | { 20 | if (currentInstructionIndex + 2 < instructionsList.Count && 21 | instructionsList[currentInstructionIndex + 2].opcode == OpCodes.Ldstr) 22 | { 23 | matchFound++; 24 | instructionsList[currentInstructionIndex].opcode = OpCodes.Ldsfld; 25 | instructionsList[currentInstructionIndex].operand = AccessTools.Field(typeof(RimWorld_Pawn_GuestTracker_SetGuestStatus_Transpile), "pawn"); 26 | yield return instructionsList[currentInstructionIndex]; 27 | yield return new CodeInstruction(OpCodes.Ldarg_0); 28 | yield return new CodeInstruction(OpCodes.Callvirt, AccessTools.Method(typeof(AccessTools.FieldRef), "Invoke")); 29 | yield return new CodeInstruction(OpCodes.Ldind_Ref); 30 | currentInstructionIndex += 5; 31 | } 32 | else 33 | { 34 | yield return instructionsList[currentInstructionIndex]; 35 | currentInstructionIndex++; 36 | } 37 | } 38 | if (matchFound < 1) 39 | { 40 | Log.Error("IL code instructions not found"); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Source/RW_Patches/RitualObligationTargetWorker_AnyEmptyGrave_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class RitualObligationTargetWorker_AnyEmptyGrave_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(RitualObligationTargetWorker_AnyEmptyGrave); 12 | Type patched = typeof(RitualObligationTargetWorker_AnyEmptyGrave_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(LabelExtraPart), new Type[] { typeof(RitualObligation) }); 14 | } 15 | public static bool LabelExtraPart(RitualObligationTargetWorker_AnyEmptyGrave __instance, ref string __result, RitualObligation obligation) 16 | { 17 | __result = string.Empty; 18 | if (obligation == null || obligation.targetA == null || (Pawn)obligation.targetA.Thing == null) 19 | { 20 | return false; 21 | } 22 | __result = ((Pawn)obligation.targetA.Thing).LabelShort; 23 | return false; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/RW_Patches/RoofGrid_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | class RoofGrid_Patch 7 | { 8 | internal static void RunDestructivePatches() 9 | { 10 | Type original = typeof(RoofGrid); 11 | Type patched = typeof(RoofGrid_Patch); 12 | 13 | RimThreadedHarmony.Prefix(original, patched, nameof(SetRoof)); 14 | } 15 | public static bool SetRoof(RoofGrid __instance, IntVec3 c, RoofDef def) 16 | { 17 | Map map = __instance.map; 18 | int mcc = map.cellIndices.CellToIndex(c); 19 | if (__instance.roofGrid[mcc] != def) 20 | { 21 | __instance.roofGrid[mcc] = def; 22 | map.glowGrid.MarkGlowGridDirty(c); 23 | //Comment the 3 following lines and uncomment the 4th to fix the roof notification -Sernior 24 | Room room = map.regionGrid.GetValidRegionAt_NoRebuild(c)?.Room; 25 | if (room != null) 26 | room.Notify_RoofChanged(); 27 | //map.regionGrid.GetValidRegionAt_NoRebuild(c)?.District.Notify_RoofChanged(); This fixes the roofs notification instead of the 3 previous lines -Sernior 28 | if (__instance.drawerInt != null) 29 | { 30 | __instance.drawerInt.SetDirty(); 31 | } 32 | 33 | map.mapDrawer.MapMeshDirty(c, MapMeshFlag.Roofs); 34 | } 35 | return false; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Source/RW_Patches/RulePackDef_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | using Verse.Grammar; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class RulePackDef_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(RulePackDef); 13 | Type patched = typeof(RulePackDef_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(get_RulesPlusIncludes)); 15 | } 16 | public static bool get_RulesPlusIncludes(RulePackDef __instance, ref List __result) 17 | { 18 | if (__instance.cachedRules == null) 19 | { 20 | lock (__instance) 21 | { 22 | List tmpCachedRules = new List(); //changed 23 | if (__instance.rulePack != null) 24 | tmpCachedRules.AddRange(__instance.rulePack.Rules); //changed 25 | if (__instance.include != null) 26 | { 27 | for (int index = 0; index < __instance.include.Count; ++index) 28 | tmpCachedRules.AddRange(__instance.include[index].RulesPlusIncludes); //changed 29 | } 30 | __instance.cachedRules = tmpCachedRules; //changed 31 | } 32 | } 33 | __result = __instance.cachedRules; 34 | return false; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/RW_Patches/SampleSustainer_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Verse.Sound; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class SampleSustainer_Patch 11 | { 12 | 13 | static readonly Func safeFunction = parameters => 14 | SampleSustainer.TryMakeAndPlay( 15 | (SubSustainer)parameters[0], 16 | (AudioClip)parameters[1], 17 | (float)parameters[2]); 18 | 19 | public static void RunDestructivePatches() 20 | { 21 | Type original = typeof(SampleSustainer); 22 | Type patched = typeof(SampleSustainer_Patch); 23 | RimThreadedHarmony.Prefix(original, patched, "TryMakeAndPlay"); 24 | } 25 | 26 | public static bool TryMakeAndPlay(ref SampleSustainer __result, SubSustainer subSus, AudioClip clip, float scheduledEndTime) 27 | { 28 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 29 | return true; 30 | threadInfo.safeFunctionRequest = new object[] { safeFunction, new object[] { subSus, clip, scheduledEndTime } }; 31 | mainThreadWaitHandle.Set(); 32 | threadInfo.eventWaitStart.WaitOne(); 33 | __result = (SampleSustainer)threadInfo.safeFunctionResult; 34 | return false; 35 | } 36 | 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Source/RW_Patches/SeasonUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RimWorld; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class SeasonUtility_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(SeasonUtility); 14 | Type patched = typeof(SeasonUtility_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "GetReportedSeason"); 16 | } 17 | 18 | public static Dictionary> yearLatitudeSeason = new Dictionary>(); 19 | public static bool GetReportedSeason(ref Season __result, float yearPct, float latitude) 20 | { 21 | int year1000 = (int)(yearPct * 1000f); 22 | if (!yearLatitudeSeason.TryGetValue(year1000, out Dictionary latitudeSeason)) 23 | { 24 | latitudeSeason = new Dictionary(); 25 | yearLatitudeSeason.Add(year1000, latitudeSeason); 26 | } 27 | if (!latitudeSeason.TryGetValue(latitude, out Season season)) 28 | { 29 | SeasonUtility.GetSeason(yearPct, latitude, out float spring, out float summer, out float fall, out float winter, out float permanentSummer, out float permanentWinter); 30 | if (permanentSummer == 1f) 31 | { 32 | season = Season.PermanentSummer; 33 | } 34 | 35 | if (permanentWinter == 1f) 36 | { 37 | season = Season.PermanentWinter; 38 | } 39 | if (permanentSummer != 1f && permanentWinter != 1f) 40 | { 41 | season = GenMath.MaxBy(Season.Spring, spring, Season.Summer, summer, Season.Fall, fall, Season.Winter, winter); 42 | } 43 | latitudeSeason.Add(latitude, season); 44 | } 45 | __result = season; 46 | return false; 47 | } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/RW_Patches/SectionLayer_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using UnityEngine; 4 | using static System.Threading.Thread; 5 | using static RimThreaded.RimThreaded; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class SectionLayer_Patch 11 | { 12 | internal static void RunDestructivePatches() 13 | { 14 | Type original = typeof(SectionLayer); 15 | Type patched = typeof(SectionLayer_Patch); 16 | RimThreadedHarmony.Prefix(original, patched, "GetSubMesh"); 17 | } 18 | 19 | public static bool GetSubMesh(SectionLayer __instance, ref LayerSubMesh __result, Material material) 20 | { 21 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 22 | return true; 23 | Func safeFunction = parameters => __instance.GetSubMesh((Material)parameters[0]); 24 | threadInfo.safeFunctionRequest = new object[] { safeFunction, new object[] { material } }; 25 | mainThreadWaitHandle.Set(); 26 | threadInfo.eventWaitStart.WaitOne(); 27 | __result = (LayerSubMesh)threadInfo.safeFunctionResult; 28 | return false; 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/RW_Patches/SimplePool_Patch.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace RimThreaded.RW_Patches 4 | { 5 | public static class SimplePool_Patch where T : new() 6 | { 7 | private static readonly ConcurrentStack FreeItems = new ConcurrentStack(); 8 | 9 | public static int FreeItemsCount => FreeItems.Count; 10 | 11 | public static T Get() => FreeItems.TryPop(out T freeItem) ? freeItem : new T(); 12 | 13 | public static void Return(T item) => FreeItems.Push(item);//as a precaution this might require a check for duplicates. 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/RW_Patches/SlateRef_Patch.cs: -------------------------------------------------------------------------------- 1 | namespace RimThreaded.RW_Patches 2 | { 3 | class SlateRef_Patch 4 | { 5 | 6 | //{ 7 | // "ClassName": "RimWorld.QuestGen.SlateRef`1", 8 | // "ThreadStatics": [ 9 | // { 10 | // "FieldName": "tmpCurSlate" 11 | // } 12 | // ] 13 | //}, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Source/RW_Patches/SoundSizeAggregator_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse.Sound; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | 8 | public class SoundSizeAggregator_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(SoundSizeAggregator); 13 | Type patched = typeof(SoundSizeAggregator_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(RegisterReporter)); 15 | RimThreadedHarmony.Prefix(original, patched, nameof(RemoveReporter)); 16 | RimThreadedHarmony.Prefix(original, patched, nameof(get_AggregateSize)); 17 | } 18 | 19 | public static bool RegisterReporter(SoundSizeAggregator __instance, ISizeReporter newRep) 20 | { 21 | lock (__instance.reporters) //added lock 22 | { 23 | __instance.reporters.Add(newRep); 24 | } 25 | return false; 26 | } 27 | 28 | public static bool RemoveReporter(SoundSizeAggregator __instance, ISizeReporter oldRep) 29 | { 30 | lock (__instance.reporters) 31 | { 32 | List newReporters = new List(__instance.reporters); //safe copy remove 33 | newReporters.Remove(oldRep); 34 | __instance.reporters = newReporters; 35 | } 36 | return false; 37 | } 38 | public static bool get_AggregateSize(SoundSizeAggregator __instance, ref float __result) 39 | { 40 | if (__instance.reporters.Count == 0) 41 | { 42 | __result = __instance.testSize; 43 | return false; 44 | } 45 | float num = 0f; 46 | foreach (ISizeReporter reporter in __instance.reporters) 47 | if (reporter != null) // added check for null 48 | num += reporter.CurrentSize(); 49 | __result = num; 50 | return false; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Source/RW_Patches/SoundStarter_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Verse; 3 | using Verse.Sound; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class SoundStarter_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(SoundStarter); 14 | Type patched = typeof(SoundStarter_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "PlayOneShot"); 16 | RimThreadedHarmony.Prefix(original, patched, "PlayOneShotOnCamera"); 17 | } 18 | 19 | static readonly Action ActionPlayOneShot = parameters => 20 | ((SoundDef)parameters[0]).PlayOneShot( 21 | (SoundInfo)parameters[1]); 22 | 23 | public static bool PlayOneShot(SoundDef soundDef, SoundInfo info) 24 | { 25 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 26 | return true; 27 | threadInfo.safeFunctionRequest = new object[] { ActionPlayOneShot, new object[] { soundDef, info } }; 28 | mainThreadWaitHandle.Set(); 29 | threadInfo.eventWaitStart.WaitOne(); 30 | return false; 31 | } 32 | static readonly Action ActionPlayOneShotOnCamera = parameters => 33 | ((SoundDef)parameters[0]).PlayOneShotOnCamera( 34 | (Map)parameters[1]); 35 | 36 | public static bool PlayOneShotOnCamera(SoundDef soundDef, Map onlyThisMap) 37 | { 38 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 39 | return true; 40 | threadInfo.safeFunctionRequest = new object[] { ActionPlayOneShotOnCamera, new object[] { soundDef, onlyThisMap } }; 41 | mainThreadWaitHandle.Set(); 42 | threadInfo.eventWaitStart.WaitOne(); 43 | return false; 44 | } 45 | 46 | 47 | } 48 | } -------------------------------------------------------------------------------- /Source/RW_Patches/StoreUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class StoreUtility_Patch 8 | { 9 | internal static void RunDestructivePatches() 10 | { 11 | Type original = typeof(StoreUtility); 12 | Type patched = typeof(StoreUtility_Patch); 13 | RimThreadedHarmony.Prefix(original, patched, nameof(CurrentHaulDestinationOf), new Type[] { typeof(Thing) }); 14 | } 15 | public static bool CurrentHaulDestinationOf(ref IHaulDestination __result, Thing t) 16 | { 17 | __result = null; 18 | if (t == null) 19 | return false; 20 | if (!t.Spawned) 21 | { 22 | __result = t.ParentHolder as IHaulDestination; 23 | return false; 24 | } 25 | Map map = t.Map; 26 | if (map == null) 27 | return false; 28 | HaulDestinationManager haulDestinationManager = map.haulDestinationManager; 29 | if (haulDestinationManager == null) 30 | return false; 31 | __result = haulDestinationManager.SlotGroupParentAt(t.Position); 32 | return false; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Source/RW_Patches/StoryState_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | 8 | public class StoryState_Patch 9 | { 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(StoryState); 13 | Type patched = typeof(StoryState_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, "RecordPopulationIncrease"); 15 | } 16 | public static bool RecordPopulationIncrease(StoryState __instance) 17 | { 18 | int count = PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_FreeColonists.Count; 19 | lock (__instance.colonistCountTicks) 20 | { 21 | if (!__instance.colonistCountTicks.ContainsKey(count)) 22 | { 23 | __instance.colonistCountTicks.Add(count, Find.TickManager.TicksGame); 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/RW_Patches/TaleManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | class TaleManager_Patch 9 | { 10 | 11 | public static void RunDestructivePatches() 12 | { 13 | Type original = typeof(TaleManager); 14 | Type patched = typeof(TaleManager_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, "Add"); 16 | RimThreadedHarmony.Prefix(original, patched, "RemoveTale"); 17 | } 18 | 19 | public static bool Add(TaleManager __instance, Tale tale) 20 | { 21 | lock (__instance) 22 | { 23 | __instance.tales.Add(tale); 24 | } 25 | __instance.CheckCullTales(tale); 26 | return false; 27 | } 28 | public static bool RemoveTale(TaleManager __instance, Tale tale) 29 | { 30 | if (!tale.Unused) 31 | { 32 | Log.Warning("Tried to remove used tale " + tale); 33 | } 34 | else 35 | { 36 | lock (__instance) 37 | { 38 | List newTales = new List(__instance.tales); 39 | newTales.Remove(tale); 40 | __instance.tales = newTales; 41 | } 42 | } 43 | return false; 44 | } 45 | 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/RW_Patches/Text_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using Verse; 4 | using static RimThreaded.RimThreaded; 5 | using static System.Threading.Thread; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class Text_Patch 10 | { 11 | 12 | private static readonly Type Original = typeof(Text); 13 | private static readonly Type Patched = typeof(Text_Patch); 14 | 15 | public static void RunDestructivePatches() 16 | { 17 | RimThreadedHarmony.Prefix(Original, Patched, "get_CurFontStyle"); 18 | } 19 | 20 | public static Func safeFunction = parameters => { return Text.CurFontStyle; }; 21 | public static bool get_CurFontStyle(ref GUIStyle __result) 22 | { 23 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 24 | return true; 25 | threadInfo.safeFunctionRequest = new object[] { safeFunction, new object[] { } }; 26 | mainThreadWaitHandle.Set(); 27 | threadInfo.eventWaitStart.WaitOne(); 28 | __result = (GUIStyle)threadInfo.safeFunctionResult; 29 | return false; 30 | 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/RW_Patches/Thing_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Reflection.Emit; 6 | using HarmonyLib; 7 | using Verse; 8 | using static HarmonyLib.AccessTools; 9 | 10 | namespace RimThreaded.RW_Patches 11 | { 12 | class Thing_Patch 13 | { 14 | internal static void RunDestructivePatches() 15 | { 16 | Type original = typeof(Thing); 17 | Type patched = typeof(Thing_Patch); 18 | RimThreadedHarmony.Prefix(original, patched, nameof(get_Map)); 19 | RimThreadedHarmony.Transpile(original, patched, nameof(TakeDamage)); 20 | } 21 | 22 | public static IEnumerable TakeDamage(IEnumerable instructions, 23 | ILGenerator iLGenerator) 24 | { 25 | List instructionsList = instructions.ToList(); 26 | for (int i = 0; i < instructionsList.Count; i++) 27 | { 28 | CodeInstruction ci = instructionsList[i]; 29 | if (ci.opcode == OpCodes.Call && (MethodInfo)ci.operand == Method(typeof(Map), "get_MapHeld")) 30 | { 31 | yield return instructionsList[i++]; 32 | yield return instructionsList[i]; 33 | yield return new CodeInstruction(OpCodes.Ldloc_2); 34 | Label label = (Label)instructionsList[i + 13].operand; 35 | yield return new CodeInstruction(OpCodes.Brfalse, label); 36 | } 37 | else 38 | { 39 | yield return ci; 40 | } 41 | } 42 | } 43 | 44 | public static bool get_Map(Thing __instance, ref Map __result) 45 | { 46 | __result = null; 47 | int mapIndexOrState = __instance.mapIndexOrState; 48 | if (mapIndexOrState >= 0) 49 | __result = Find.Maps[mapIndexOrState]; 50 | //else 51 | //{ 52 | // lock (lastMapIndex) 53 | // { 54 | // if (lastMapIndex.TryGetValue(__instance, out sbyte lastIndex)) 55 | // { 56 | // __result = Find.Maps[lastIndex]; 57 | // } 58 | // } 59 | //} 60 | return false; 61 | } 62 | 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/RW_Patches/ThinkNode_JoinVoluntarilyJoinableLord_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using System.Collections.Generic; 4 | using Verse; 5 | using Verse.AI.Group; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class ThinkNode_JoinVoluntarilyJoinableLord_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(ThinkNode_JoinVoluntarilyJoinableLord); 14 | Type patched = typeof(ThinkNode_JoinVoluntarilyJoinableLord_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, nameof(JoinVoluntarilyJoinableLord)); 16 | } 17 | 18 | public static bool JoinVoluntarilyJoinableLord(ThinkNode_JoinVoluntarilyJoinableLord __instance, Pawn pawn) 19 | { 20 | Lord lord1 = pawn.GetLord(); 21 | Lord lord2 = null; 22 | float num1 = 0.0f; 23 | if (lord1 != null) 24 | { 25 | if (!(lord1.LordJob is LordJob_VoluntarilyJoinable lordJob2)) 26 | return false; 27 | lord2 = lord1; 28 | num1 = lordJob2.VoluntaryJoinPriorityFor(pawn); 29 | } 30 | Map map = pawn.Map; //changed 31 | if (map != null) //changed 32 | { 33 | List lords = map.lordManager.lords;//changed 34 | for (int index = 0; index < lords.Count; ++index) 35 | { 36 | if (lords[index].LordJob is LordJob_VoluntarilyJoinable lordJob4 && lords[index].CurLordToil.VoluntaryJoinDutyHookFor(pawn) == __instance.dutyHook) 37 | { 38 | float num2 = lordJob4.VoluntaryJoinPriorityFor(pawn); 39 | if ((double)num2 > 0.0 && (lord2 == null || (double)num2 > (double)num1)) 40 | { 41 | lord2 = lords[index]; 42 | num1 = num2; 43 | } 44 | } 45 | } 46 | } 47 | if (lord2 == null || lord1 == lord2) 48 | return false; 49 | lord1?.Notify_PawnLost(pawn, PawnLostCondition.LeftVoluntarily); 50 | lord2.AddPawn(pawn); 51 | return false; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Source/RW_Patches/ThinkNode_SubtreesByTag_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Verse; 5 | using Verse.AI; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class ThinkNode_SubtreesByTag_Patch 11 | { 12 | internal static void RunDestructivePatches() 13 | { 14 | Type original = typeof(ThinkNode_SubtreesByTag); 15 | Type patched = typeof(ThinkNode_SubtreesByTag_Patch); 16 | RimThreadedHarmony.Prefix(original, patched, "TryIssueJobPackage"); 17 | } 18 | 19 | public static bool TryIssueJobPackage(ThinkNode_SubtreesByTag __instance, ref ThinkResult __result, Pawn pawn, JobIssueParams jobParams) 20 | { 21 | List matchedTrees = new List(); 22 | foreach (ThinkTreeDef allDef in DefDatabase.AllDefs) 23 | { 24 | if (allDef.insertTag == __instance.insertTag) 25 | { 26 | matchedTrees.Add(allDef); 27 | } 28 | } 29 | matchedTrees = matchedTrees.OrderByDescending((tDef) => tDef.insertPriority).ToList(); 30 | 31 | ThinkTreeDef thinkTreeDef; 32 | for (int i = 0; i < matchedTrees.Count; i++) 33 | { 34 | thinkTreeDef = matchedTrees[i]; 35 | ThinkResult result = thinkTreeDef.thinkRoot.TryIssueJobPackage(pawn, jobParams); 36 | if (result.IsValid) 37 | { 38 | __result = result; 39 | return false; 40 | } 41 | } 42 | 43 | __result = ThinkResult.NoJob; 44 | return false; 45 | } 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Source/RW_Patches/TileTemperaturesComp_Transpile.cs: -------------------------------------------------------------------------------- 1 | using HarmonyLib; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection.Emit; 5 | using static HarmonyLib.AccessTools; 6 | using static RimThreaded.RimThreadedHarmony; 7 | 8 | namespace RimThreaded.RW_Patches 9 | { 10 | public class TileTemperaturesComp_Transpile 11 | { 12 | public static IEnumerable WorldComponentTick(IEnumerable instructions, ILGenerator iLGenerator) 13 | { 14 | List instructionsList = instructions.ToList(); 15 | int i = 0; 16 | List loadLockObjectInstructions = new List 17 | { 18 | new CodeInstruction(OpCodes.Ldsfld, Field(typeof(TileTemperaturesComp_Patch), "worldComponentTickLock")) 19 | }; 20 | LocalBuilder lockObject = iLGenerator.DeclareLocal(typeof(object)); 21 | LocalBuilder lockTaken = iLGenerator.DeclareLocal(typeof(bool)); 22 | foreach (CodeInstruction ci in EnterLock( 23 | lockObject, lockTaken, loadLockObjectInstructions, instructionsList[i])) 24 | yield return ci; 25 | while (i < instructionsList.Count - 1) 26 | { 27 | yield return instructionsList[i++]; 28 | } 29 | foreach (CodeInstruction ci in ExitLock( 30 | iLGenerator, lockObject, lockTaken, instructionsList[i])) 31 | yield return ci; 32 | yield return instructionsList[i++]; 33 | 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/RW_Patches/TimeControls_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using Verse; 3 | using Verse.Sound; 4 | using UnityEngine; 5 | using System; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class TimeControls_Patch 11 | { 12 | public static bool lastTickForcedSlow; 13 | public static bool overrideForcedSlow; 14 | 15 | 16 | internal static void RunNonDestructivePatches() 17 | { 18 | Type original = typeof(TimeControls); 19 | Type patched = typeof(TimeControls_Patch); 20 | RimThreadedHarmony.Prefix(original, patched, "DoTimeControlsGUI", new[] { typeof(Rect) }, false); 21 | } 22 | 23 | public static bool DoTimeControlsGUI(Rect timerRect) 24 | { 25 | if (Event.current.type != EventType.KeyDown) 26 | { 27 | return true; 28 | } 29 | 30 | if (!Find.WindowStack.WindowsForcePause) 31 | { 32 | if (KeyBindingDefOf.TimeSpeed_Fast.KeyDownEvent || 33 | KeyBindingDefOf.TimeSpeed_Superfast.KeyDownEvent || 34 | KeyBindingDefOf.TimeSpeed_Ultrafast.KeyDownEvent 35 | ) 36 | { 37 | if (lastTickForcedSlow) 38 | { 39 | overrideForcedSlow = true; 40 | } 41 | } 42 | } 43 | 44 | //allow speed 4 even if not dev mode 45 | if (Prefs.DevMode) 46 | return true; 47 | TickManager tickManager = Find.TickManager; 48 | if (KeyBindingDefOf.TimeSpeed_Ultrafast.KeyDownEvent) 49 | { 50 | tickManager.CurTimeSpeed = TimeSpeed.Ultrafast; 51 | TimeControls.PlaySoundOf(tickManager.CurTimeSpeed); 52 | Event.current.Use(); 53 | } 54 | if (!KeyBindingDefOf.Dev_TickOnce.KeyDownEvent || tickManager.CurTimeSpeed != TimeSpeed.Paused) 55 | return true; 56 | tickManager.DoSingleTick(); 57 | SoundDefOf.Clock_Stop.PlayOneShotOnCamera(); 58 | 59 | return true; 60 | } 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Source/RW_Patches/Toils_Ingest_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Verse; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | public class Toils_Ingest_Patch 9 | { 10 | [ThreadStatic] public static List cardinals; 11 | [ThreadStatic] public static List diagonals; 12 | 13 | internal static void InitializeThreadStatics() 14 | { 15 | cardinals = GenAdj.CardinalDirections.ToList(); 16 | diagonals = GenAdj.DiagonalDirections.ToList(); 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Source/RW_Patches/TransportShipManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using RimWorld; 5 | using Verse; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | class TransportShipManager_Patch 10 | { 11 | internal static void RunNonDestructivePatches() 12 | { 13 | Type original = typeof(TransportShipManager); 14 | //Type patched = typeof(TransportShipManager_Patch); 15 | RimThreadedHarmony.TranspileMethodLock(original, "RegisterShipObject"); 16 | RimThreadedHarmony.TranspileMethodLock(original, "DeregisterShipObject"); 17 | } 18 | public static List AllTransportShips; 19 | public static int AllTransportShipsCount; 20 | 21 | public static void ShipObjectsPrepare() 22 | { 23 | AllTransportShips = Current.Game.transportShipManager.ships; 24 | AllTransportShipsCount = AllTransportShips.Count; 25 | } 26 | public static void ShipObjectsTick() 27 | { 28 | while (true) 29 | { 30 | int index = Interlocked.Decrement(ref AllTransportShipsCount); 31 | if (index < 0) return; 32 | try 33 | { 34 | AllTransportShips[index].Tick(); 35 | } 36 | catch (Exception e) 37 | { 38 | Log.Error("Exception ticking TransportShip: " + AllTransportShips[index].ToString() + ": " + e); 39 | } 40 | /* 41 | int index = Interlocked.Decrement(ref allFactionsTicks); 42 | if (index < 0) return; 43 | Faction faction = allFactionsTickList[index]; 44 | try 45 | { 46 | faction.FactionTick(); 47 | } 48 | catch (Exception ex) 49 | { 50 | Log.Error("Exception ticking faction: " + faction.ToStringSafe() + ": " + ex); 51 | } 52 | }*/ 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/RW_Patches/UniqueIDsManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using RimWorld; 3 | using Verse; 4 | using System.Threading; 5 | 6 | namespace RimThreaded.RW_Patches 7 | { 8 | 9 | public class UniqueIDsManager_Patch 10 | { 11 | internal static void RunDestructivePatches() 12 | { 13 | Type original = typeof(UniqueIDsManager); 14 | Type patched = typeof(UniqueIDsManager_Patch); 15 | RimThreadedHarmony.Prefix(original, patched, nameof(GetNextID)); 16 | } 17 | public static bool GetNextID(ref int __result, ref int nextID) 18 | { 19 | if (Scribe.mode == LoadSaveMode.LoadingVars && !Find.UniqueIDsManager.wasLoaded) 20 | { 21 | Log.Warning("Getting next unique ID during LoadingVars before UniqueIDsManager was loaded. Assigning a random value."); 22 | __result = Rand.Int; 23 | return false; 24 | } 25 | 26 | if (Scribe.mode == LoadSaveMode.Saving) 27 | { 28 | Log.Warning("Getting next unique ID during saving This may cause bugs."); 29 | } 30 | 31 | //int result = nextID; 32 | int result = Interlocked.Increment(ref nextID) - 1; 33 | if (nextID == int.MaxValue) 34 | { 35 | Log.Warning("Next ID is at max value. Resetting to 0. This may cause bugs."); 36 | nextID = 0; 37 | } 38 | 39 | __result = result; 40 | return false; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/RW_Patches/UnityEngine_Object_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static System.Threading.Thread; 3 | using static RimThreaded.RimThreaded; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class UnityEngine_Object_Patch 8 | { 9 | 10 | internal static void RunDestructivePatches() 11 | { 12 | Type original = typeof(UnityEngine.Object); 13 | Type patched = typeof(UnityEngine_Object_Patch); 14 | RimThreadedHarmony.Prefix(original, patched, nameof(ToString), new Type[] { }); 15 | RimThreadedHarmony.Prefix(original, patched, nameof(Destroy), new Type[] { typeof(UnityEngine.Object) }); 16 | } 17 | 18 | public static bool ToString(UnityEngine.Object __instance, ref string __result) 19 | { 20 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 21 | { 22 | return true; 23 | } 24 | Func safeFunction = parameters => __instance.ToString(); 25 | threadInfo.safeFunctionRequest = new object[] { safeFunction, new object[] { } }; 26 | mainThreadWaitHandle.Set(); 27 | threadInfo.eventWaitStart.WaitOne(); 28 | __result = (string)threadInfo.safeFunctionResult; 29 | return false; 30 | } 31 | public static bool Destroy(UnityEngine.Object __instance) 32 | { 33 | if (!CurrentThread.IsBackground || !allWorkerThreads.TryGetValue(CurrentThread, out ThreadInfo threadInfo)) 34 | { 35 | return true; 36 | } 37 | Action safeActionDestroy = parameters => UnityEngine.Object.Destroy(__instance); 38 | threadInfo.safeFunctionRequest = new object[] { safeActionDestroy, new object[] { } }; 39 | mainThreadWaitHandle.Set(); 40 | threadInfo.eventWaitStart.WaitOne(); 41 | return false; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Source/RW_Patches/Verb_Patch.cs: -------------------------------------------------------------------------------- 1 | using Verse; 2 | using System; 3 | 4 | namespace RimThreaded.RW_Patches 5 | { 6 | public class Verb_Patch 7 | { 8 | 9 | static readonly Type original = typeof(Verb); 10 | static readonly Type patched = typeof(Verb_Patch); 11 | 12 | internal static void RunDestructivePatches() 13 | { 14 | RimThreadedHarmony.Prefix(original, patched, "get_DirectOwner"); 15 | } 16 | 17 | public static bool get_DirectOwner(Verb __instance, ref IVerbOwner __result) 18 | { 19 | if (__instance.verbTracker == null) 20 | { 21 | __result = null; 22 | } 23 | else 24 | { 25 | return true; 26 | } 27 | return false; 28 | } 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/RW_Patches/WealthWatcher_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using RimWorld; 4 | using Verse; 5 | using UnityEngine; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class WealthWatcher_Patch 11 | { 12 | 13 | static Type original = typeof(WealthWatcher); 14 | static Type patched = typeof(WealthWatcher_Patch); 15 | 16 | public static void RunDestructivePatches() 17 | { 18 | RimThreadedHarmony.Prefix(original, patched, "ResetStaticData"); 19 | } 20 | 21 | public static bool ResetStaticData(WealthWatcher __instance) 22 | { 23 | int num = -1; 24 | List allDefsListForReading = DefDatabase.AllDefsListForReading; 25 | for (int i = 0; i < allDefsListForReading.Count; i++) 26 | { 27 | num = Mathf.Max(num, allDefsListForReading[i].index); 28 | } 29 | 30 | float[] newCachedTerrainMarketValue = new float[num + 1]; 31 | for (int j = 0; j < allDefsListForReading.Count; j++) 32 | { 33 | newCachedTerrainMarketValue[allDefsListForReading[j].index] = allDefsListForReading[j].GetStatValueAbstract(StatDefOf.MarketValue); 34 | } 35 | WealthWatcher.cachedTerrainMarketValue = newCachedTerrainMarketValue; 36 | return false; 37 | } 38 | 39 | 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Source/RW_Patches/WorkGiver_DoBill_RegionProcessor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using RimWorld; 5 | using Verse; 6 | using Verse.AI; 7 | using UnityEngine; 8 | 9 | namespace RimThreaded.RW_Patches 10 | { 11 | public class WorkGiver_DoBill_RegionProcessor 12 | { 13 | public List newRelevantThings = new List(); 14 | public List ingredientsOrdered = new List(); 15 | public List relevantThings = new List(); 16 | public HashSet processedThings = new HashSet(); 17 | public Bill bill; 18 | public Pawn pawn; 19 | public Predicate baseValidator; 20 | public bool billGiverIsPawn; 21 | public int adjacentRegionsAvailable; 22 | public IntVec3 rootCell; 23 | public List chosen; 24 | public int regionsProcessed = 0; 25 | public bool foundAll = false; 26 | 27 | public WorkGiver_DoBill_RegionProcessor() 28 | { 29 | } 30 | 31 | public bool Get_RegionProcessor(Region r) 32 | { 33 | List thingList = r.ListerThings.ThingsMatching(ThingRequest.ForGroup(ThingRequestGroup.HaulableEver)); 34 | for (int index = 0; index < thingList.Count; ++index) 35 | { 36 | Thing thing = thingList[index]; 37 | if (!processedThings.Contains(thing) && ReachabilityWithinRegion.ThingFromRegionListerReachable( 38 | thing, r, PathEndMode.ClosestTouch, pawn) && baseValidator(thing) && !(thing.def.IsMedicine & billGiverIsPawn)) 39 | { 40 | newRelevantThings.Add(thing); 41 | processedThings.Add(thing); 42 | } 43 | } 44 | ++regionsProcessed; 45 | if (newRelevantThings.Count > 0 && regionsProcessed > adjacentRegionsAvailable) 46 | { 47 | relevantThings.AddRange(newRelevantThings); 48 | newRelevantThings.Clear(); 49 | if (WorkGiver_DoBill_Patch.TryFindBestBillIngredientsInSet2(relevantThings, bill, chosen, rootCell, billGiverIsPawn, ingredientsOrdered)) 50 | { 51 | foundAll = true; 52 | return true; 53 | } 54 | } 55 | return false; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Source/RW_Patches/WorldComponentUtility_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld.Planet; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Threading; 5 | using Verse; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | //Class was largely overhauled to allow multithreaded ticking for WorldPawns.Tick() 10 | public class WorldComponentUtility_Patch 11 | { 12 | public static bool WorldComponentTick(World world) 13 | { 14 | worldComponents = world.components; 15 | worldComponentTicks = worldComponents.Count; 16 | return false; 17 | } 18 | 19 | internal static void RunDestructivePatches() 20 | { 21 | Type original = typeof(WorldComponentUtility); 22 | Type patched = typeof(WorldComponentUtility_Patch); 23 | RimThreadedHarmony.Prefix(original, patched, "WorldComponentTick"); 24 | } 25 | 26 | public static List worldComponents; 27 | public static int worldComponentTicks; 28 | 29 | public static void WorldComponentPrepare() 30 | { 31 | try 32 | { 33 | World world = Find.World; 34 | world.debugDrawer.WorldDebugDrawerTick(); 35 | world.pathGrid.WorldPathGridTick(); 36 | WorldComponentUtility.WorldComponentTick(world); 37 | } 38 | catch (Exception ex3) 39 | { 40 | Log.Error(ex3.ToString()); 41 | } 42 | } 43 | 44 | public static void WorldComponentListTick() 45 | { 46 | while (true) 47 | { 48 | int index = Interlocked.Decrement(ref worldComponentTicks); 49 | if (index < 0) return; 50 | WorldComponent worldComponent = worldComponents[index]; 51 | if (null != worldComponent) //TODO: is null-check and lock necessary? 52 | { 53 | try 54 | { 55 | worldComponent.WorldComponentTick(); 56 | } 57 | catch (Exception ex) 58 | { 59 | Log.Error("Exception ticking World Component: " + worldComponent.ToStringSafe() + ex); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Source/RW_Patches/WorldObjectsHolder_Patch.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using RimWorld.Planet; 3 | using System; 4 | using System.Threading; 5 | using Verse; 6 | 7 | namespace RimThreaded.RW_Patches 8 | { 9 | 10 | public class WorldObjectsHolder_Patch 11 | { 12 | //Class was largely overhauled to allow multithreaded ticking for WorldPawns.Tick() 13 | internal static void RunDestructivePatches() 14 | { 15 | Type original = typeof(WorldObjectsHolder); 16 | Type patched = typeof(WorldObjectsHolder_Patch); 17 | RimThreadedHarmony.Prefix(original, patched, "WorldObjectsHolderTick"); 18 | } 19 | 20 | public static bool WorldObjectsHolderTick(WorldObjectsHolder __instance) 21 | { 22 | worldObjectsTickList = __instance.worldObjects; 23 | worldObjectsTicks = __instance.worldObjects.Count; 24 | return false; 25 | } 26 | 27 | public static List worldObjectsTickList; 28 | public static int worldObjectsTicks; 29 | 30 | public static void WorldObjectsPrepare() 31 | { 32 | try 33 | { 34 | World world = Find.World; 35 | world.worldObjects.WorldObjectsHolderTick(); 36 | } 37 | catch (Exception ex3) 38 | { 39 | Log.Error(ex3.ToString()); 40 | } 41 | } 42 | 43 | public static void WorldObjectsListTick() 44 | { 45 | while (true) 46 | { 47 | int index = Interlocked.Decrement(ref worldObjectsTicks); 48 | if (index < 0) return; 49 | WorldObject worldObject = worldObjectsTickList[index]; 50 | try 51 | { 52 | worldObject.Tick(); 53 | } 54 | catch (Exception ex) 55 | { 56 | Log.Error("Exception ticking world object: " + worldObject.ToStringSafe() + ": " + ex); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/RW_Patches/World_Patch.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class World_Patch 8 | { 9 | [ThreadStatic] public static List tmpNaturalRockDefs = new List(); 10 | [ThreadStatic] public static List tmpNeighbors = new List(); 11 | [ThreadStatic] public static List tmpOceanDirs = new List(); 12 | 13 | internal static void InitializeThreadStatics() 14 | { 15 | tmpNaturalRockDefs = new List(); 16 | tmpNeighbors = new List(); 17 | tmpOceanDirs = new List(); 18 | } 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/RW_Patches/ZoneManager_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class ZoneManager_Patch 8 | { 9 | internal static void RunNonDestructivePatches() 10 | { 11 | Type original = typeof(ZoneManager); 12 | Type patched = typeof(ZoneManager_Patch); 13 | RimThreadedHarmony.Postfix(original, patched, "AddZoneGridCell"); 14 | } 15 | 16 | public static void AddZoneGridCell(ZoneManager __instance, Zone zone, IntVec3 c) 17 | { 18 | if (Current.ProgramState == ProgramState.Playing) 19 | { 20 | if (zone is Zone_Growing) 21 | { 22 | //Log.Message("Adding growing zone cell to awaiting plant cells"); 23 | JumboCell.ReregisterObject(zone.Map, c, RimThreaded.plantSowing_Cache); 24 | } 25 | } 26 | } 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Source/RW_Patches/Zone_Growing_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class Zone_Growing_Patch 8 | { 9 | internal static void RunNonDestructivePatches() 10 | { 11 | Type original = typeof(Zone_Growing); 12 | Type patched = typeof(Zone_Growing_Patch); 13 | RimThreadedHarmony.Postfix(original, patched, nameof(SetPlantDefToGrow)); 14 | } 15 | 16 | public static void SetPlantDefToGrow(Zone_Growing __instance, ThingDef plantDef) 17 | { 18 | if (Current.ProgramState == ProgramState.Playing) 19 | { 20 | foreach (IntVec3 c in __instance.cells) 21 | { 22 | JumboCell.ReregisterObject(__instance.Map, c, RimThreaded.plantSowing_Cache); 23 | } 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/RW_Patches/Zone_Patch.cs: -------------------------------------------------------------------------------- 1 | using RimWorld; 2 | using System; 3 | using Verse; 4 | 5 | namespace RimThreaded.RW_Patches 6 | { 7 | class Zone_Patch 8 | { 9 | internal static void RunNonDestructivePatches() 10 | { 11 | Type original = typeof(Zone); 12 | Type patched = typeof(Zone_Patch); 13 | RimThreadedHarmony.Postfix(original, patched, "CheckAddHaulDestination"); 14 | } 15 | 16 | public static void CheckAddHaulDestination(Zone __instance) 17 | { 18 | if (Current.ProgramState == ProgramState.Playing) 19 | { 20 | if (__instance is Zone_Growing zone) 21 | { 22 | //Log.Message("Adding growing zone cell to awaiting plant cells"); 23 | foreach (IntVec3 c in zone.cells) 24 | { 25 | JumboCell.ReregisterObject(zone.Map, c, RimThreaded.plantSowing_Cache); 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Source/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /configure.cmd: -------------------------------------------------------------------------------- 1 | powershell -ExecutionPolicy ByPass -File .\configure.ps1 --------------------------------------------------------------------------------