diff --git a/.gitignore b/.gitignore
index f652b45..5bf56e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -297,3 +297,4 @@ __pycache__/
*.btm.cs
*.odx.cs
*.xsd.cs
+/Assemblies/0Harmony.xml
diff --git a/Assemblies/0Harmony.dll b/1.0/Assemblies/0Harmony.dll
similarity index 100%
rename from Assemblies/0Harmony.dll
rename to 1.0/Assemblies/0Harmony.dll
diff --git a/Assemblies/IHoldMultipleThings.dll b/1.0/Assemblies/IHoldMultipleThings.dll
similarity index 100%
rename from Assemblies/IHoldMultipleThings.dll
rename to 1.0/Assemblies/IHoldMultipleThings.dll
diff --git a/Assemblies/PickUpAndHaul.dll b/1.0/Assemblies/PickUpAndHaul.dll
similarity index 100%
rename from Assemblies/PickUpAndHaul.dll
rename to 1.0/Assemblies/PickUpAndHaul.dll
diff --git a/1.0/Assemblies/THIS IS FOR v1.0 ONLY.txt b/1.0/Assemblies/THIS IS FOR v1.0 ONLY.txt
new file mode 100644
index 0000000..e69de29
diff --git a/1.1/Assemblies/0Harmony.dll b/1.1/Assemblies/0Harmony.dll
new file mode 100644
index 0000000..106a81a
Binary files /dev/null and b/1.1/Assemblies/0Harmony.dll differ
diff --git a/1.1/Assemblies/0Harmony.xml b/1.1/Assemblies/0Harmony.xml
new file mode 100644
index 0000000..a17cc8f
--- /dev/null
+++ b/1.1/Assemblies/0Harmony.xml
@@ -0,0 +1,2476 @@
+
+
+
+ 0Harmony
+
+
+
+ A factory to create delegate types
+
+
+ Default constructor
+
+
+ Creates a delegate type for a method
+ The method
+ The new delegate type
+
+
+
+ A getter delegate type
+ Type that getter gets field/property value from
+ Type of the value that getter gets
+ The instance get getter uses
+ An delegate
+
+
+
+ A setter delegate type
+ Type that setter sets field/property value for
+ Type of the value that setter sets
+ The instance the setter uses
+ The value the setter uses
+ An delegate
+
+
+
+ A constructor delegate type
+ Type that constructor creates
+ An delegate
+
+
+
+ A helper class for fast access to getters and setters
+
+
+ Creates an instantiation delegate
+ Type that constructor creates
+ The new instantiation delegate
+
+
+
+ Creates an getter delegate for a property
+ Type that getter reads property from
+ Type of the property that gets accessed
+ The property
+ The new getter delegate
+
+
+
+ Creates an getter delegate for a field
+ Type that getter reads field from
+ Type of the field that gets accessed
+ The field
+ The new getter delegate
+
+
+
+ Creates an getter delegate for a field (with a list of possible field names)
+ Type that getter reads field/property from
+ Type of the field/property that gets accessed
+ A list of possible field names
+ The new getter delegate
+
+
+
+ Creates an setter delegate
+ Type that setter assigns property value to
+ Type of the property that gets assigned
+ The property
+ The new setter delegate
+
+
+
+ Creates an setter delegate for a field
+ Type that setter assigns field value to
+ Type of the field that gets assigned
+ The field
+ The new getter delegate
+
+
+
+ A delegate to invoke a method
+ The instance
+ The method parameters
+ The method result
+
+
+ A helper class to invoke method with delegates
+
+
+ Creates a fast invocation handler from a method
+ The method to invoke
+ Controls if boxed value object is accessed/updated directly
+ The
+
+
+ The directBoxValueAccess option controls how value types passed by reference (e.g. ref int, out my_struct) are handled in the arguments array
+ passed to the fast invocation handler.
+ Since the arguments array is an object array, any value types contained within it are actually references to a boxed value object.
+ Like any other object, there can be other references to such boxed value objects, other than the reference within the arguments array.
+ For example,
+
+ var val = 5;
+ var box = (object)val;
+ var arr = new object[] { box };
+ handler(arr); // for a method with parameter signature: ref/out/in int
+
+
+
+
+ If directBoxValueAccess is true, the boxed value object is accessed (and potentially updated) directly when the handler is called,
+ such that all references to the boxed object reflect the potentially updated value.
+ In the above example, if the method associated with the handler updates the passed (boxed) value to 10, both box and arr[0]
+ now reflect the value 10. Note that the original val is not updated, since boxing always copies the value into the new boxed value object.
+
+
+ If directBoxValueAccess is false (default), the boxed value object in the arguments array is replaced with a "reboxed" value object,
+ such that potential updates to the value are reflected only in the arguments array.
+ In the above example, if the method associated with the handler updates the passed (boxed) value to 10, only arr[0] now reflects the value 10.
+
+
+
+
+ A low level memory helper
+
+
+ Mark method for no inlining (currently only works on Mono)
+ The method/constructor to change
+
+
+ Detours a method
+ The original method/constructor
+ The replacement method/constructor
+ An error string
+
+
+
+ Writes a jump to memory
+ The memory address
+ Jump destination
+ An error string
+
+
+
+ Gets the start of a method in memory
+ The method/constructor
+ [out] Details of the exception
+ The method start address
+
+
+
+ special parameter names that can be used in prefix and postfix methods
+
+
+ Patch function helpers
+
+
+ Adds a prefix
+ The patch info
+ The owner (Harmony ID)
+ The annotation info
+
+
+
+ Removes a prefix
+ The patch info
+ The owner (Harmony ID)
+
+
+
+ Adds a postfix
+ The patch info
+ The owner (Harmony ID)
+ The annotation info
+
+
+
+ Removes a postfix
+ The patch info
+ The owner (Harmony ID)
+
+
+
+ Adds a transpiler
+ The patch info
+ The owner (Harmony ID)
+ The annotation info
+
+
+
+ Removes a transpiler
+ The patch info
+ The owner (Harmony ID)
+
+
+
+ Adds a finalizer
+ The patch info
+ The owner (Harmony ID)
+ The annotation info
+
+
+
+ Removes a finalizer
+ The patch info
+ The owner (Harmony ID)
+
+
+
+ Removes a patch method
+ The patch info
+ The patch method
+
+
+
+ Gets sorted patch methods
+ The original method
+ Patches to sort
+ Use debug mode
+ The sorted patch methods
+
+
+
+ Creates new replacement method with the latest patches and detours the original method
+ The original method
+ Information describing the patches
+ The newly created replacement method
+
+
+
+ Creates a patch sorter
+ Array of patches that will be sorted
+ Use debugging
+
+
+ Sorts internal PatchSortingWrapper collection and caches the results.
+ After first run the result is provided from the cache.
+ The original method
+ The sorted patch methods
+
+
+ Checks if the sorter was created with the same patch list and as a result can be reused to
+ get the sorted order of the patches.
+ List of patches to check against
+ true if equal
+
+
+ Removes one unresolved dependency from the least important patch.
+
+
+ Outputs all unblocked patches from the waiting list to results list
+
+
+ Adds patch to both results list and handled patches set
+ Patch to add
+
+
+ Wrapper used over the Patch object to allow faster dependency access and
+ dependency removal in case of cyclic dependencies
+
+
+ Create patch wrapper object used for sorting
+ Patch to wrap
+
+
+ Determines how patches sort
+ The other patch
+ integer to define sort order (-1, 0, 1)
+
+
+ Determines whether patches are equal
+ The other patch
+ true if equal
+
+
+ Hash function
+ A hash code
+
+
+ Bidirectionally registers Patches as after dependencies
+ List of dependencies to register
+
+
+ Bidirectionally registers Patches as before dependencies
+ List of dependencies to register
+
+
+ Bidirectionally removes Patch from after dependencies
+ Patch to remove
+
+
+ Bidirectionally removes Patch from before dependencies
+ Patch to remove
+
+
+ Specifies the type of method
+
+
+
+ This is a normal method
+
+
+ This is a getter
+
+
+ This is a setter
+
+
+ This is a constructor
+
+
+ This is a static constructor
+
+
+ Specifies the type of argument
+
+
+
+ This is a normal argument
+
+
+ This is a reference argument (ref)
+
+
+ This is an out argument (out)
+
+
+ This is a pointer argument (&)
+
+
+ Specifies the type of patch
+
+
+
+ Any patch
+
+
+ A prefix patch
+
+
+ A postfix patch
+
+
+ A transpiler
+
+
+ A finalizer
+
+
+ A reverse patch
+
+
+ Specifies the type of reverse patch
+
+
+
+ Use the unmodified original method (directly from IL)
+
+
+ Use the original as it is right now including previous patches but excluding future ones
+
+
+ The base class for all Harmony annotations (not meant to be used directly)
+
+
+
+ The common information for all attributes
+
+
+ Annotation to define your Harmony patch methods
+
+
+
+ An empty annotation can be used together with TargetMethod(s)
+
+
+
+ An annotation that specifies a class to patch
+ The declaring class/type
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The argument types of the method or constructor to patch
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The name of the method, property or constructor to patch
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The name of the method, property or constructor to patch
+ An array of argument types to target overloads
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The name of the method, property or constructor to patch
+ An array of argument types to target overloads
+ Array of
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The
+ An array of argument types to target overloads
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The
+ An array of argument types to target overloads
+ Array of
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The declaring class/type
+ The name of the method, property or constructor to patch
+ The
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The name of the method, property or constructor to patch
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The name of the method, property or constructor to patch
+ An array of argument types to target overloads
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The name of the method, property or constructor to patch
+ An array of argument types to target overloads
+ An array of
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The name of the method, property or constructor to patch
+ The
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The
+ An array of argument types to target overloads
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ The
+ An array of argument types to target overloads
+ An array of
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ An array of argument types to target overloads
+
+
+
+ An annotation that specifies a method, property or constructor to patch
+ An array of argument types to target overloads
+ An array of
+
+
+
+ Annotation to define your standin methods for reverse patching
+
+
+
+ An annotation that specifies the type of reverse patching
+ The of the reverse patch
+
+
+
+ A Harmony annotation to define that all methods in a class are to be patched
+
+
+
+ A Harmony annotation
+
+
+
+ A Harmony annotation to define patch priority
+ The priority
+
+
+
+ A Harmony annotation
+
+
+
+ A Harmony annotation to define that a patch comes before another patch
+ The array of harmony IDs of the other patches
+
+
+
+ A Harmony annotation
+
+
+ A Harmony annotation to define that a patch comes after another patch
+ The array of harmony IDs of the other patches
+
+
+
+ A Harmony annotation
+
+
+ A Harmony annotation to debug a patch (output uses to log to your Desktop)
+
+
+
+ Specifies the Prepare function in a patch class
+
+
+
+ Specifies the Cleanup function in a patch class
+
+
+
+ Specifies the TargetMethod function in a patch class
+
+
+
+ Specifies the TargetMethods function in a patch class
+
+
+
+ Specifies the Prefix function in a patch class
+
+
+
+ Specifies the Postfix function in a patch class
+
+
+
+ Specifies the Transpiler function in a patch class
+
+
+
+ Specifies the Finalizer function in a patch class
+
+
+
+ A Harmony annotation
+
+
+
+ The name of the original argument
+
+
+
+ The index of the original argument
+
+
+
+ The new name of the original argument
+
+
+
+ An annotation to declare injected arguments by name
+
+
+
+ An annotation to declare injected arguments by index
+ Zero-based index
+
+
+
+ An annotation to declare injected arguments by renaming them
+ Name of the original argument
+ New name
+
+
+
+ An annotation to declare injected arguments by index and renaming them
+ Zero-based index
+ New name
+
+
+
+ An abstract wrapper around OpCode and their operands. Used by transpilers
+
+
+
+ The opcode
+
+
+
+ The operand
+
+
+
+ All labels defined on this instruction
+
+
+
+ All exception block boundaries defined on this instruction
+
+
+
+ Creates a new CodeInstruction with a given opcode and optional operand
+ The opcode
+ The operand
+
+
+
+ Create a full copy (including labels and exception blocks) of a CodeInstruction
+ The to copy
+
+
+
+ Clones a CodeInstruction and resets its labels and exception blocks
+ A lightweight copy of this code instruction
+
+
+
+ Clones a CodeInstruction, resets labels and exception blocks and sets its opcode
+ The opcode
+ A copy of this CodeInstruction with a new opcode
+
+
+
+ Clones a CodeInstruction, resets labels and exception blocks and sets its operand
+ The operand
+ A copy of this CodeInstruction with a new operand
+
+
+
+ Returns a string representation of the code instruction
+ A string representation of the code instruction
+
+
+
+ Exception block types
+
+
+
+ The beginning of an exception block
+
+
+
+ The beginning of a catch block
+
+
+
+ The beginning of an except filter block
+
+
+
+ The beginning of a fault block
+
+
+
+ The beginning of a finally block
+
+
+
+ The end of an exception block
+
+
+
+ An exception block
+
+
+
+ Block type
+
+
+
+ Catch type
+
+
+
+ Creates an exception block
+ The
+ The catch type
+
+
+
+ The Harmony instance is the main entry to Harmony. After creating one with an unique identifier, it is used to patch and query the current application domain
+
+
+
+ The unique identifier
+
+
+
+ Set to true before instantiating Harmony to debug Harmony or use an environment variable to set HARMONY_DEBUG to '1' like this: cmd /C "set HARMONY_DEBUG=1 && game.exe"
+ This is for full debugging. To debug only specific patches, use the attribute
+
+
+
+ Creates a new Harmony instance
+ A unique identifier (you choose your own)
+ A Harmony instance
+
+
+
+ Searches the current assembly for Harmony annotations and uses them to create patches
+
+
+
+ Creates a empty patch processor for an original method
+ The original method/constructor
+ A new instance
+
+
+
+ Creates a patch class processor from an annotated class
+ The class/type
+ A new instance
+
+
+
+ Creates a reverse patcher for one of your stub methods
+ The original method/constructor
+ The stand-in stub method as
+ A new instance
+
+
+
+ Searches an assembly for Harmony annotations and uses them to create patches
+ The assembly
+
+
+
+ Creates patches by manually specifying the methods
+ The original method/constructor
+ An optional prefix method wrapped in a object
+ An optional postfix method wrapped in a object
+ An optional transpiler method wrapped in a object
+ An optional finalizer method wrapped in a object
+ The replacement method that was created to patch the original method
+
+
+
+ Patches a foreign method onto a stub method of yours and optionally applies transpilers during the process
+ The original method/constructor you want to duplicate
+ Your stub method as that will become the original. Needs to have the correct signature (either original or whatever your transpilers generates)
+ An optional transpiler as method that will be applied during the process
+ The replacement method that was created to patch the stub method
+
+
+
+ Unpatches methods
+ The optional Harmony ID to restrict unpatching to a specific instance
+ This method could be static if it wasn't for the fact that unpatching creates a new replacement method that contains your harmony ID
+
+
+
+ Unpatches a method
+ The original method/constructor
+ The
+ The optional Harmony ID to restrict unpatching to a specific instance
+
+
+
+ Unpatches a method
+ The original method/constructor
+ The patch method as method to remove
+
+
+
+ Test for patches from a specific Harmony ID
+ The Harmony ID
+ True if patches for this ID exist
+
+
+
+ Gets patch information for a given original method
+ The original method/constructor
+ The patch information as
+
+
+
+ Gets the methods this instance has patched
+ An enumeration of original methods/constructors
+
+
+
+ Gets all patched original methods in the appdomain
+ An enumeration of patched original methods/constructors
+
+
+
+ Gets Harmony version for all active Harmony instances
+ [out] The current Harmony version
+ A dictionary containing assembly versions keyed by Harmony IDs
+
+
+
+ Under Mono, HarmonyException wraps IL compile errors with detailed information about the failure
+
+
+
+ Default serialization constructor (not implemented)
+ The info
+ The context
+
+
+
+ Get a list of IL instructions in pairs of offset+code
+ A list of key/value pairs which represent an offset and the code at that offset
+
+
+
+ Get a list of IL instructions without offsets
+ A list of
+
+
+
+ Get the error offset of the errornous IL instruction
+ The offset
+
+
+
+ Get the index of the errornous IL instruction
+ The index into the list of instructions or -1 if not found
+
+
+
+ A wrapper around a method to use it as a patch (for example a Prefix)
+
+
+
+ The original method
+
+
+
+ Class/type declaring this patch
+
+
+
+ Patch method name
+
+
+
+ Optional patch
+
+
+
+ Array of argument types of the patch method
+
+
+
+ of the patch
+
+
+
+ Install this patch before patches with these Harmony IDs
+
+
+
+ Install this patch after patches with these Harmony IDs
+
+
+
+ Reverse patch type, see
+
+
+
+ Create debug output for this patch
+
+
+
+ Default constructor
+
+
+
+ Creates a patch from a given method
+ The original method
+
+
+
+ Creates a patch from a given method
+ The original method
+ The patch
+ A list of harmony IDs that should come after this patch
+ A list of harmony IDs that should come before this patch
+ Set to true to generate debug output
+
+
+
+ Creates a patch from a given method
+ The patch class/type
+ The patch method name
+ The optional argument types of the patch method (for overloaded methods)
+
+
+
+ Gets the names of all internal patch info fields
+ A list of field names
+
+
+
+ Merges annotations
+ The list of to merge
+ The merged
+
+
+
+ Returns a string that represents the annotation
+ A string representation
+
+
+
+ Annotation extensions
+
+
+
+ Copies annotation information
+ The source
+ The destination
+
+
+
+ Clones an annotation
+ The to clone
+ A copied
+
+
+
+ Merges annotations
+ The master
+ The detail
+ A new, merged
+
+
+
+ Gets all annotations on a class/type
+ The class/type
+ A list of all
+
+
+
+ Gets merged annotations on a class/type
+ The class/type
+ The merged
+
+
+
+ Gets all annotations on a method
+ The method/constructor
+ A list of
+
+
+
+ Gets merged annotations on a method
+ The method/constructor
+ The merged
+
+
+
+
+ A mutable representation of an inline signature, similar to Mono.Cecil's CallSite.
+ Used by the calli instruction, can be used by transpilers
+
+
+
+
+ See
+
+
+
+ See
+
+
+
+ See
+
+
+
+ The list of all parameter types or function pointer signatures received by the call site
+
+
+
+ The return type or function pointer signature returned by the call site
+
+
+
+ Returns a string representation of the inline signature
+ A string representation of the inline signature
+
+
+
+
+ A mutable representation of a parameter type with an attached type modifier,
+ similar to Mono.Cecil's OptionalModifierType / RequiredModifierType and C#'s modopt / modreq
+
+
+
+
+ Whether this is a modopt (optional modifier type) or a modreq (required modifier type)
+
+
+
+ The modifier type attached to the parameter type
+
+
+
+ The modified parameter type
+
+
+
+ Returns a string representation of the modifier type
+ A string representation of the modifier type
+
+
+
+ Patch serialization
+
+
+
+ Control the binding of a serialized object to a type
+ Specifies the assembly name of the serialized object
+ Specifies the type name of the serialized object
+ The type of the object the formatter creates a new instance of
+
+
+
+ Serializes a patch info
+ The
+ The serialized data
+
+
+
+ Deserialize a patch info
+ The serialized data
+ A
+
+
+
+ Compare function to sort patch priorities
+ The patch
+ Zero-based index
+ The priority
+ A standard sort integer (-1, 0, 1)
+
+
+
+ Serializable patch information
+
+
+
+ Prefixes as an array of
+
+
+
+ Postfixes as an array of
+
+
+
+ Transpilers as an array of
+
+
+
+ Finalizers as an array of
+
+
+
+ Default constructor
+
+
+
+ Returns if any of the patches wants debugging turned on
+
+
+
+ Adds a prefix
+
+ The prefix method
+ An owner (Harmony ID)
+ The priority, see
+ A list of Harmony IDs for prefixes that should run after this prefix
+ A list of Harmony IDs for prefixes that should run before this prefix
+ A flag that will log the replacement method via every time this prefix is used to build the replacement, even in the future
+
+
+
+ Removes prefixes
+ The owner of the prefix or * for any prefix
+
+
+
+ Adds a postfix
+ The postfix method
+ An owner (Harmony ID)
+ The priority, see
+ A list of Harmony IDs for postfixes that should run after this postfix
+ A list of Harmony IDs for postfixes that should run before this postfix
+ A flag that will log the replacement method via every time this postfix is used to build the replacement, even in the future
+
+
+
+ Removes postfixes
+ The owner of the postfix or * for any postfix
+
+
+
+ Adds a transpiler
+ The transpiler method
+ An owner (Harmony ID)
+ The priority, see
+ A list of Harmony IDs for transpilers that should run after this transpiler
+ A list of Harmony IDs for transpilers that should run before this transpiler
+ A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future
+
+
+
+ Removes transpilers
+ The owner of the transpiler or * for any transpiler
+
+
+
+ Adds a finalizer
+ The finalizer method
+ An owner (Harmony ID)
+ The priority, see
+ A list of Harmony IDs for finalizers that should run after this finalizer
+ A list of Harmony IDs for finalizers that should run before this finalizer
+ A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future
+
+
+
+ Removes finalizers
+ The owner of the finalizer or * for any finalizer
+
+
+
+ Removes a patch using its method
+ The method of the patch to remove
+
+
+
+ A serializable patch
+
+
+
+ Zero-based index
+
+
+
+ The owner (Harmony ID)
+
+
+
+ The priority, see
+
+
+
+ Keep this patch before the patches indicated in the list of Harmony IDs
+
+
+
+ Keep this patch after the patches indicated in the list of Harmony IDs
+
+
+
+ A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future
+
+
+
+ The method of the static patch method
+
+
+
+ Creates a patch
+ The method of the patch
+ Zero-based index
+ An owner (Harmony ID)
+ The priority, see
+ A list of Harmony IDs for patches that should run after this patch
+ A list of Harmony IDs for patches that should run before this patch
+ A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future
+
+
+
+ Get the patch method or a DynamicMethod if original patch method is a patch factory
+ The original method/constructor
+ The method of the patch
+
+
+
+ Determines whether patches are equal
+ The other patch
+ true if equal
+
+
+
+ Determines how patches sort
+ The other patch
+ integer to define sort order (-1, 0, 1)
+
+
+
+ Hash function
+ A hash code
+
+
+
+ A PatchClassProcessor used to turn on a class/type into patches
+
+
+
+ Creates an empty patch class processor
+ The Harmony instance
+ The class to process
+
+
+
+ Applies the patches
+ A list of all created replacement methods or null if patch class is not annotated
+
+
+
+ A group of patches
+
+
+
+ A collection of prefix
+
+
+
+ A collection of postfix
+
+
+
+ A collection of transpiler
+
+
+
+ A collection of finalizer
+
+
+
+ Gets all owners (Harmony IDs) or all known patches
+ The patch owners
+
+
+
+ Creates a group of patches
+ An array of prefixes as
+ An array of postfixes as
+ An array of transpileres as
+ An array of finalizeres as
+
+
+
+ A PatchProcessor handles patches on a method/constructor
+
+
+
+ Creates an empty patch processor
+ The Harmony instance
+ The original method/constructor
+
+
+
+ Adds a prefix
+ The prefix as a
+ A for chaining calls
+
+
+
+ Adds a prefix
+ The prefix method
+ A for chaining calls
+
+
+
+ Adds a postfix
+ The postfix as a
+ A for chaining calls
+
+
+
+ Adds a postfix
+ The postfix method
+ A for chaining calls
+
+
+
+ Adds a transpiler
+ The transpiler as a
+ A for chaining calls
+
+
+
+ Adds a transpiler
+ The transpiler method
+ A for chaining calls
+
+
+
+ Adds a finalizer
+ The finalizer as a
+ A for chaining calls
+
+
+
+ Adds a finalizer
+ The finalizer method
+ A for chaining calls
+
+
+
+ Gets all patched original methods in the appdomain
+ An enumeration of patched method/constructor
+
+
+
+ Applies all registered patches
+ The generated replacement method
+
+
+
+ Unpatches patches of a given type and/or Harmony ID
+ The patch type
+ Harmony ID or * for any
+ A for chaining calls
+
+
+
+ Unpatches a specific patch
+ The method of the patch
+ A for chaining calls
+
+
+
+ Gets patch information on an original
+ The original method/constructor
+ The patch information as
+
+
+
+ Gets Harmony version for all active Harmony instances
+ [out] The current Harmony version
+ A dictionary containing assembly version keyed by Harmony ID
+
+
+
+ Returns the methods unmodified list of code instructions
+ The original method/constructor
+ Optionally an existing generator that will be used to create all local variables and labels contained in the result (if not specified, an internal generator is used)
+ A list containing all the original
+
+
+
+ Returns the methods unmodified list of code instructions
+ The original method/constructor
+ A new generator that now contains all local variables and labels contained in the result
+ A list containing all the original
+
+
+
+ A low level way to read the body of a method. Used for quick searching in methods
+ The original method
+ All instructions as opcode/operand pairs
+
+
+
+ A patch priority
+
+
+
+ Patch last
+
+
+
+ Patch with very low priority
+
+
+
+ Patch with low priority
+
+
+
+ Patch with lower than normal priority
+
+
+
+ Patch with normal priority
+
+
+
+ Patch with higher than normal priority
+
+
+
+ Patch with high priority
+
+
+
+ Patch with very high priority
+
+
+
+ Patch first
+
+
+
+ A reverse patcher
+
+
+
+ Creates a reverse patcher
+ The Harmony instance
+ The original method/constructor
+ Your stand-in stub method as
+
+
+
+ Applies the patch
+ The type of patch, see
+ The generated replacement method
+
+
+
+ A collection of commonly used transpilers
+
+
+
+ A transpiler that replaces all occurrences of a given method with another one
+ The enumeration of to act on
+ Method or constructor to search for
+ Method or constructor to replace with
+ Modified enumeration of
+
+
+
+ A transpiler that alters instructions that match a predicate by calling an action
+ The enumeration of to act on
+ A predicate selecting the instructions to change
+ An action to apply to matching instructions
+ Modified enumeration of
+
+
+
+ A transpiler that logs a text at the beginning of the method
+ The instructions to act on
+ The log text
+ Modified enumeration of
+
+
+
+ A helper class for reflection related functions
+
+
+
+ Shortcut for to simplify the use of reflections and make it work for any access level
+
+
+
+ Shortcut for to simplify the use of reflections and make it work for any access level but only within the current type
+
+
+
+ Gets a type by name. Prefers a full name with namespace but falls back to the first type matching the name otherwise
+ The name
+ A type or null if not found
+
+
+
+ Gets all type by name from a given assembly. This is a wrapper that respects different .NET versions
+ The assembly
+ An array of types
+
+
+
+ Applies a function going up the type hierarchy and stops at the first non null result
+ Result type of func()
+ The class/type to start with
+ The evaluation function returning T
+ Returns the first non null result or default(T) when reaching the top level type object
+
+
+
+ Applies a function going into inner types and stops at the first non null result
+ Generic type parameter
+ The class/type to start with
+ The evaluation function returning T
+ Returns the first non null result or null with no match
+
+
+
+ Gets the reflection information for a directly declared field
+ The class/type where the field is defined
+ The name of the field
+ A field or null when type/name is null or when the field cannot be found
+
+
+
+ Gets the reflection information for a field by searching the type and all its super types
+ The class/type where the field is defined
+ The name of the field (case sensitive)
+ A field or null when type/name is null or when the field cannot be found
+
+
+
+ Gets the reflection information for a field
+ The class/type where the field is declared
+ The zero-based index of the field inside the class definition
+ A field or null when type is null or when the field cannot be found
+
+
+
+ Gets the reflection information for a directly declared property
+ The class/type where the property is declared
+ The name of the property (case sensitive)
+ A property or null when type/name is null or when the property cannot be found
+
+
+
+ Gets the reflection information for the getter method of a directly declared property
+ The class/type where the property is declared
+ The name of the property (case sensitive)
+ A method or null when type/name is null or when the property cannot be found
+
+
+
+ Gets the reflection information for the setter method of a directly declared property
+ The class/type where the property is declared
+ The name of the property (case sensitive)
+ A method or null when type/name is null or when the property cannot be found
+
+
+
+ Gets the reflection information for a property by searching the type and all its super types
+ The class/type
+ The name
+ A property or null when type/name is null or when the property cannot be found
+
+
+
+ Gets the reflection information for the getter method of a property by searching the type and all its super types
+ The class/type
+ The name
+ A method or null when type/name is null or when the property cannot be found
+
+
+
+ Gets the reflection information for the setter method of a property by searching the type and all its super types
+ The class/type
+ The name
+ A method or null when type/name is null or when the property cannot be found
+
+
+
+ Gets the reflection information for a directly declared method
+ The class/type where the method is declared
+ The name of the method (case sensitive)
+ Optional parameters to target a specific overload of the method
+ Optional list of types that define the generic version of the method
+ A method or null when type/name is null or when the method cannot be found
+
+
+
+ Gets the reflection information for a method by searching the type and all its super types
+ The class/type where the method is declared
+ The name of the method (case sensitive)
+ Optional parameters to target a specific overload of the method
+ Optional list of types that define the generic version of the method
+ A method or null when type/name is null or when the method cannot be found
+
+
+
+ Gets the reflection information for a method by searching the type and all its super types
+ The full name like Namespace.Type1.Type2:MethodName of the type where the method is declared
+ Optional parameters to target a specific overload of the method
+ Optional list of types that define the generic version of the method
+ A method or null when type/name is null or when the method cannot be found
+
+
+
+ Gets the names of all method that are declared in a type
+ The declaring class/type
+ A list of method names
+
+
+
+ Gets the names of all method that are declared in the type of the instance
+ An instance of the type to search in
+ A list of method names
+
+
+
+ Gets the names of all fields that are declared in a type
+ The declaring class/type
+ A list of field names
+
+
+
+ Gets the names of all fields that are declared in the type of the instance
+ An instance of the type to search in
+ A list of field names
+
+
+
+ Gets the names of all properties that are declared in a type
+ The declaring class/type
+ A list of property names
+
+
+
+ Gets the names of all properties that are declared in the type of the instance
+ An instance of the type to search in
+ A list of property names
+
+
+
+ Gets the type of any class member of
+ A member
+ The class/type of this member
+
+
+
+ Test if a class member is actually an concrete implementation
+ A member
+ True if the member is a declared
+
+
+
+ Gets the real implementation of a class member
+ A member
+ The member itself if its declared. Otherwise the member that is actually implemented in some base type
+
+
+
+ Gets the reflection information for a directly declared constructor
+ The class/type where the constructor is declared
+ Optional parameters to target a specific overload of the constructor
+ Optional parameters to only consider static constructors
+ A constructor info or null when type is null or when the constructor cannot be found
+
+
+
+ Gets the reflection information for a constructor by searching the type and all its super types
+ The class/type where the constructor is declared
+ Optional parameters to target a specific overload of the method
+ Optional parameters to only consider static constructors
+ A constructor info or null when type is null or when the method cannot be found
+
+
+
+ Gets reflection information for all declared constructors
+ The class/type where the constructors are declared
+ Optional parameters to only consider static constructors
+ A list of constructor infos
+
+
+
+ Gets reflection information for all declared methods
+ The class/type where the methods are declared
+ A list of methods
+
+
+
+ Gets reflection information for all declared properties
+ The class/type where the properties are declared
+ A list of properties
+
+
+
+ Gets reflection information for all declared fields
+ The class/type where the fields are declared
+ A list of fields
+
+
+
+ Gets the return type of a method or constructor
+ The method/constructor
+ The return type
+
+
+
+ Given a type, returns the first inner type matching a recursive search by name
+ The class/type to start searching at
+ The name of the inner type (case sensitive)
+ The inner type or null if type/name is null or if a type with that name cannot be found
+
+
+
+ Given a type, returns the first inner type matching a recursive search with a predicate
+ The class/type to start searching at
+ The predicate to search with
+ The inner type or null if type/predicate is null or if a type with that name cannot be found
+
+
+
+ Given a type, returns the first method matching a predicate
+ The class/type to start searching at
+ The predicate to search with
+ The method or null if type/predicate is null or if a type with that name cannot be found
+
+
+
+ Given a type, returns the first constructor matching a predicate
+ The class/type to start searching at
+ The predicate to search with
+ The constructor info or null if type/predicate is null or if a type with that name cannot be found
+
+
+
+ Given a type, returns the first property matching a predicate
+ The class/type to start searching at
+ The predicate to search with
+ The property or null if type/predicate is null or if a type with that name cannot be found
+
+
+
+ Returns an array containing the type of each object in the given array
+ An array of objects
+ An array of types or an empty array if parameters is null (if an object is null, the type for it will be object)
+
+
+
+ Creates an array of input parameters for a given method and a given set of potential inputs
+ The method/constructor you are planing to call
+ The possible input parameters in any order
+ An object array matching the method signature
+
+
+
+ A read/writable reference to an instance field
+ The class the field is defined in or "object" if type cannot be accessed at compile time
+ The type of the field
+ The runtime instance to access the field (leave empty for static fields)
+ An readable/assignable object representing the field
+
+
+
+ Creates an instance field reference
+ The class the field is defined in or "object" if type cannot be accessed at compile time
+ The type of the field
+ The name of the field
+ A read and writable field reference delegate
+
+
+
+ Creates an instance field reference for a specific instance
+ The class the field is defined in or "object" if type cannot be accessed at compile time
+ The type of the field
+ The instance
+ The name of the field
+ An readable/assignable object representing the field
+
+
+
+ Creates an instance field reference delegate
+ The class the field is defined in or "object" if type cannot be accessed at compile time
+ The type of the field
+ The field of the field
+ A read and writable delegate
+
+
+
+ A read/writable reference delegate to a static field
+ The type of the field
+ An readable/assignable object representing the static field
+
+
+
+ Creates a static field reference
+ The class the field is defined in or "object" if type cannot be accessed at compile time
+ The type of the field
+ The name of the field
+ An readable/assignable object representing the static field
+
+
+
+ Creates a static field reference delegate
+ The type of the field
+ The field
+ A read and writable delegate
+
+
+
+ Returns who called the current method
+ The calling method/constructor (excluding the caller)
+
+
+
+ Rethrows an exception while preserving its stack trace (throw statement typically clobbers existing stack traces)
+ The exception to rethrow
+
+
+
+ Tells you if the current runtime is based on Mono
+ True if we are running under Mono, false otherwise (.NET)
+
+
+
+ Throws a missing member runtime exception
+ The type that is involved
+ A list of names
+
+
+
+ Gets default value for a specific type
+ The class/type
+ The default value
+
+
+
+ Creates an (possibly uninitialized) instance of a given type
+ The class/type
+ The new instance
+
+
+
+ Makes a deep copy of any object
+ The type of the instance that should be created
+ The original object
+ A copy of the original object but of type T
+
+
+
+ Makes a deep copy of any object
+ The type of the instance that should be created
+ The original object
+ [out] The copy of the original object
+ Optional value transformation function (taking a field name and src/dst instances)
+ The optional path root to start with
+
+
+
+ Makes a deep copy of any object
+ The original object
+ The type of the instance that should be created
+ Optional value transformation function (taking a field name and src/dst instances)
+ The optional path root to start with
+ The copy of the original object
+
+
+
+ Tests if a type is a struct
+ The type
+ True if the type is a struct
+
+
+
+ Tests if a type is a class
+ The type
+ True if the type is a class
+
+
+
+ Tests if a type is a value type
+ The type
+ True if the type is a value type
+
+
+
+ Tests if a type is an integer type
+ The type
+ True if the type represents some integer
+
+
+
+ Tests if a type is a floating point type
+ The type
+ True if the type represents some floating point
+
+
+
+ Tests if a type is a numerical type
+ The type
+ True if the type represents some number
+
+
+
+ Tests if a type is void
+ The type
+ True if the type is void
+
+
+
+ Test whether an instance is of a nullable type
+ Type of instance
+ An instance to test
+ True if instance is of nullable type, false if not
+
+
+
+ Calculates a combined hash code for an enumeration of objects
+ The objects
+ The hash code
+
+
+
+ General extensions for common cases
+
+
+
+ Joins an enumeration with a value converter and a delimiter to a string
+ The inner type of the enumeration
+ The enumeration
+ An optional value converter (from T to string)
+ An optional delimiter
+ The values joined into a string
+
+
+
+ Converts an array of types (for example methods arguments) into a human readable form
+ The array of types
+ A human readable description including brackets
+
+
+
+ A full description of a type
+ The type
+ A human readable description
+
+
+
+ A a full description of a method or a constructor without assembly details but with generics
+ The method/constructor
+ A human readable description
+
+
+
+ A helper converting parameter infos to types
+ The array of parameter infos
+ An array of types
+
+
+
+ A helper to access a value via key from a dictionary
+ The key type
+ The value type
+ The dictionary
+ The key
+ The value for the key or the default value (of T) if that key does not exist
+
+
+
+ A helper to access a value via key from a dictionary with extra casting
+ The value type
+ The dictionary
+ The key
+ The value for the key or the default value (of T) if that key does not exist or cannot be cast to T
+
+
+
+ Escapes Unicode and ASCII non printable characters
+ The string to convert
+ The string to convert
+ A string literal surrounded by
+
+
+
+ Extensions for
+
+
+
+ Shortcut for testing whether the operand is equal to a non-null value
+ The
+ The value
+ True if the operand has the same type and is equal to the value
+
+
+
+ Shortcut for testing whether the operand is equal to a non-null value
+ The
+ The value
+ True if the operand is equal to the value
+ This is an optimized version of for
+
+
+
+ Shortcut for code.opcode == opcode && code.OperandIs(operand)
+ The
+ The
+ The operand value
+ True if the opcode is equal to the given opcode and the operand has the same type and is equal to the given operand
+
+
+
+ Shortcut for code.opcode == opcode && code.OperandIs(operand)
+ The
+ The
+ The operand value
+ True if the opcode is equal to the given opcode and the operand is equal to the given operand
+ This is an optimized version of for
+
+
+
+ Tests for any form of Ldarg*
+ The
+ The (optional) index
+ True if it matches one of the variations
+
+
+
+ Tests for Ldarga/Ldarga_S
+ The
+ The (optional) index
+ True if it matches one of the variations
+
+
+
+ Tests for Starg/Starg_S
+ The
+ The (optional) index
+ True if it matches one of the variations
+
+
+
+ Tests for any form of Ldloc*
+ The
+ The optional local variable
+ True if it matches one of the variations
+
+
+
+ Tests for any form of Stloc*
+ The
+ The optional local variable
+ True if it matches one of the variations
+
+
+
+ Tests if the code instruction branches
+ The
+ The label if the instruction is a branch operation or if not
+ True if the instruction branches
+
+
+
+ Tests if the code instruction calls the method/constructor
+ The
+ The method
+ True if the instruction calls the method or constructor
+
+
+
+ Tests if the code instruction loads a constant
+ The
+ True if the instruction loads a constant
+
+
+
+ Tests if the code instruction loads an integer constant
+ The
+ The integer constant
+ True if the instruction loads the constant
+
+
+
+ Tests if the code instruction loads a floating point constant
+ The
+ The floating point constant
+ True if the instruction loads the constant
+
+
+
+ Tests if the code instruction loads an enum constant
+ The
+ The enum
+ True if the instruction loads the constant
+
+
+
+ Tests if the code instruction loads a field
+ The
+ The field
+ Set to true if the address of the field is loaded
+ True if the instruction loads the field
+
+
+
+ Tests if the code instruction stores a field
+ The
+ The field
+ True if the instruction stores this field
+
+
+
+ General extensions for collections
+
+
+
+ A simple way to execute code for every element in a collection
+ The inner type of the collection
+ The collection
+ The action to execute
+
+
+
+ A simple way to execute code for elements in a collection matching a condition
+ The inner type of the collection
+ The collection
+ The predicate
+ The action to execute
+
+
+
+ A helper to add an item to a collection
+ The inner type of the collection
+ The collection
+ The item to add
+ The collection containing the item
+
+
+
+ A helper to add an item to an array
+ The inner type of the collection
+ The array
+ The item to add
+ The array containing the item
+
+
+
+ A helper to add items to an array
+ The inner type of the collection
+ The array
+ The items to add
+ The array containing the items
+
+
+
+ A file log for debugging
+
+
+
+ Full pathname of the log file, defaults to a file called harmony.log.txt on your Desktop
+
+
+
+ The indent character. The default is tab
+
+
+
+ The current indent level
+
+
+
+ Changes the indentation level
+ The value to add to the indentation level
+
+
+
+ Log a string in a buffered way. Use this method only if you are sure that FlushBuffer will be called
+ or else logging information is incomplete in case of a crash
+ The string to log
+
+
+
+ Logs a list of string in a buffered way. Use this method only if you are sure that FlushBuffer will be called
+ or else logging information is incomplete in case of a crash
+ A list of strings to log (they will not be re-indented)
+
+
+
+ Returns the log buffer and optionally empties it
+ True to empty the buffer
+ The buffer.
+
+
+
+ Replaces the buffer with new lines
+ The lines to store
+
+
+
+ Flushes the log buffer to disk (use in combination with LogBuffered)
+
+
+
+ Log a string directly to disk. Slower method that prevents missing information in case of a crash
+ The string to log.
+
+
+
+ Resets and deletes the log
+
+
+
+ Logs some bytes as hex values
+ The pointer to some memory
+ The length of bytes to log
+
+
+
+ A helper class to retrieve reflection info for non-private methods
+
+
+
+ Given a lambda expression that calls a method, returns the method info
+ The lambda expression using the method
+ The method in the lambda expression
+
+
+
+ Given a lambda expression that calls a method, returns the method info
+ The generic type
+ The lambda expression using the method
+ The method in the lambda expression
+
+
+
+ Given a lambda expression that calls a method, returns the method info
+ The generic type
+ The generic result type
+ The lambda expression using the method
+ The method in the lambda expression
+
+
+
+ Given a lambda expression that calls a method, returns the method info
+ The lambda expression using the method
+ The method in the lambda expression
+
+
+
+ A reflection helper to read and write private elements
+ The result type defined by GetValue()
+
+
+
+ Creates a traverse instance from an existing instance
+ The existing instance
+
+
+
+ Gets/Sets the current value
+ The value to read or write
+
+
+
+ A reflection helper to read and write private elements
+
+
+
+ Creates a new traverse instance from a class/type
+ The class/type
+ A instance
+
+
+
+ Creates a new traverse instance from a class T
+ The class
+ A instance
+
+
+
+ Creates a new traverse instance from an instance
+ The object
+ A instance
+
+
+
+ Creates a new traverse instance from a named type
+ The type name, for format see
+ A instance
+
+
+
+ Creates a new and empty traverse instance
+
+
+
+ Creates a new traverse instance from a class/type
+ The class/type
+
+
+
+ Creates a new traverse instance from an instance
+ The object
+
+
+
+ Gets the current value
+ The value
+
+
+
+ Gets the current value
+ The type of the value
+ The value
+
+
+
+ Invokes the current method with arguments and returns the result
+ The method arguments
+ The value returned by the method
+
+
+
+ Invokes the current method with arguments and returns the result
+ The type of the value
+ The method arguments
+ The value returned by the method
+
+
+
+ Sets a value of the current field or property
+ The value
+ The same traverse instance
+
+
+
+ Gets the type of the current field or property
+ The type
+
+
+
+ Moves the current traverse instance to a inner type
+ The type name
+ A traverse instance
+
+
+
+ Moves the current traverse instance to a field
+ The type name
+ A traverse instance
+
+
+
+ Moves the current traverse instance to a field
+ The type of the field
+ The type name
+ A traverse instance
+
+
+
+ Gets all fields of the current type
+ A list of field names
+
+
+
+ Moves the current traverse instance to a property
+ The type name
+ Optional property index
+ A traverse instance
+
+
+
+ Moves the current traverse instance to a field
+ The type of the property
+ The type name
+ Optional property index
+ A traverse instance
+
+
+
+ Gets all properties of the current type
+ A list of property names
+
+
+
+ Moves the current traverse instance to a method
+ The name of the method
+ The arguments defining the argument types of the method overload
+ A traverse instance
+
+
+
+ Moves the current traverse instance to a method
+ The name of the method
+ The argument types of the method
+ The arguments for the method
+ A traverse instance
+
+
+
+ Gets all methods of the current type
+ A list of method names
+
+
+
+ Checks if the current traverse instance is for a field
+ True if its a field
+
+
+
+ Checks if the current traverse instance is for a property
+ True if its a property
+
+
+
+ Checks if the current traverse instance is for a method
+ True if its a method
+
+
+
+ Checks if the current traverse instance is for a type
+ True if its a type
+
+
+
+ Iterates over all fields of the current type and executes a traverse action
+ Original object
+ The action receiving a instance for each field
+
+
+
+ Iterates over all fields of the current type and executes a traverse action
+ Original object
+ Target object
+ The action receiving a pair of instances for each field pair
+
+
+
+ Iterates over all fields of the current type and executes a traverse action
+ Original object
+ Target object
+ The action receiving a dot path representing the field pair and the instances
+
+
+
+ Iterates over all properties of the current type and executes a traverse action
+ Original object
+ The action receiving a instance for each property
+
+
+
+ Iterates over all properties of the current type and executes a traverse action
+ Original object
+ Target object
+ The action receiving a pair of instances for each property pair
+
+
+
+ Iterates over all properties of the current type and executes a traverse action
+ Original object
+ Target object
+ The action receiving a dot path representing the property pair and the instances
+
+
+
+ A default field action that copies fields to fields
+
+
+
+ Returns a string that represents the current traverse
+ A string representation
+
+
+
+
diff --git a/1.1/Assemblies/IHoldMultipleThings.dll b/1.1/Assemblies/IHoldMultipleThings.dll
new file mode 100644
index 0000000..bccd46a
Binary files /dev/null and b/1.1/Assemblies/IHoldMultipleThings.dll differ
diff --git a/1.1/Assemblies/PickUpAndHaul.dll b/1.1/Assemblies/PickUpAndHaul.dll
new file mode 100644
index 0000000..40b7765
Binary files /dev/null and b/1.1/Assemblies/PickUpAndHaul.dll differ
diff --git a/About/About.xml b/About/About.xml
index 063797b..f5de76d 100644
--- a/About/About.xml
+++ b/About/About.xml
@@ -4,19 +4,31 @@
Mehni
1.0
+ 1.1
+ Mehni.PickUpAndHaul
+
+
+
+ brrainz.harmony
+ Harmony
+ steam://url/CommunityFilePage/2009463077
+ https://github.com/pardeike/HarmonyRimWorld/releases/latest
+
+
+
https://ludeon.com/forums/index.php?topic=35832
"Greatest hauling mod ever" - Chicken Plucker
- v.1.0.5
-
+ v1.1.0⅓
+
Colonists will gather stuff in their inventory, then haul it all to a stockpile.
This hauling mod will greatly increase hauling efficiency, because pawns can now carry more than one gun or t-shirt. Those smart and intelligent colonists can use their inventory!
-Works well in combination with Combat Extended, AllowTool's Haul Urgently, etc. No known conflicts.
+Safe to add to existing games.
-Safe to add to existing games. <size=20>Credits and thanks:</size>
+<size=20>Credits and thanks:</size>
- AlexTD, for his direct contributions
- erdelf, Zorba, Why_is_that and Dingo for code and advice (yet again!)
- Chicken Plucker, for the preview image
diff --git a/Source/IHoldMultipleThings/IHoldMultipleThings.csproj b/Source/IHoldMultipleThings/IHoldMultipleThings.csproj
index a9b4eb5..a3f2c6a 100644
--- a/Source/IHoldMultipleThings/IHoldMultipleThings.csproj
+++ b/Source/IHoldMultipleThings/IHoldMultipleThings.csproj
@@ -9,25 +9,28 @@
Properties
IHoldMultipleThings
IHoldMultipleThings
- v3.5
+ v4.7.2
512
+
false
none
true
- ..\..\Assemblies\
+ ..\..\v1.1\Assemblies\
TRACE
prompt
4
+ false
none
true
- ..\..\Assemblies\
+ ..\..\1.1\Assemblies\
TRACE
prompt
4
+ false
diff --git a/Source/IHoldMultipleThingsv1.0/IHoldMultipleThings.cs b/Source/IHoldMultipleThingsv1.0/IHoldMultipleThings.cs
new file mode 100644
index 0000000..7adc3c4
--- /dev/null
+++ b/Source/IHoldMultipleThingsv1.0/IHoldMultipleThings.cs
@@ -0,0 +1,11 @@
+using Verse;
+
+namespace IHoldMultipleThings
+{
+ public interface IHoldMultipleThings
+ {
+ bool CapacityAt(Thing thing, IntVec3 storeCell, Map map, out int capacity);
+
+ bool StackableAt(Thing thing, IntVec3 storeCell, Map map);
+ }
+}
diff --git a/Source/IHoldMultipleThingsv1.0/IHoldMultipleThingsv10.csproj b/Source/IHoldMultipleThingsv1.0/IHoldMultipleThingsv10.csproj
new file mode 100644
index 0000000..265887c
--- /dev/null
+++ b/Source/IHoldMultipleThingsv1.0/IHoldMultipleThingsv10.csproj
@@ -0,0 +1,53 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {0F7BA6C3-BF3C-42D5-9268-593B4AF8FC12}
+ Library
+ Properties
+ IHoldMultipleThings
+ IHoldMultipleThings
+ v3.5
+ 512
+
+
+ false
+ none
+ true
+ ..\..\Assemblies\
+ TRACE
+ prompt
+ 4
+
+
+ none
+ true
+ ..\..\Assemblies\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/IHoldMultipleThingsv1.0/Properties/AssemblyInfo.cs b/Source/IHoldMultipleThingsv1.0/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..77b3e84
--- /dev/null
+++ b/Source/IHoldMultipleThingsv1.0/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("IHoldMultipleThings")]
+[assembly: AssemblyDescription("Pick Up and Haul interface for multi-stack solutions")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("IHoldMultipleThings")]
+[assembly: AssemblyCopyright("Copyright © Mehni 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e1536a54-d289-41fa-9d0b-8a2f6812c7fa")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.1.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Source/PickUpAndHaul.sln b/Source/PickUpAndHaul.sln
index 4bf388e..1eef94f 100644
--- a/Source/PickUpAndHaul.sln
+++ b/Source/PickUpAndHaul.sln
@@ -1,12 +1,16 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2020
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29025.244
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PickUpAndHaul", "PickUpAndHaul\PickUpAndHaul.csproj", "{CCF8350B-E3FD-4693-9209-681E9C089097}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IHoldMultipleThings", "IHoldMultipleThings\IHoldMultipleThings.csproj", "{E1536A54-D289-41FA-9D0B-8A2F6812C7FA}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PickUpAndHaulv10", "PickUpAndHaulv1.0\PickUpAndHaulv10.csproj", "{2480F13E-E9ED-44EC-A5DE-C821676904E7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IHoldMultipleThingsv10", "IHoldMultipleThingsv1.0\IHoldMultipleThingsv10.csproj", "{0F7BA6C3-BF3C-42D5-9268-593B4AF8FC12}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -21,6 +25,10 @@ Global
{E1536A54-D289-41FA-9D0B-8A2F6812C7FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1536A54-D289-41FA-9D0B-8A2F6812C7FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1536A54-D289-41FA-9D0B-8A2F6812C7FA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2480F13E-E9ED-44EC-A5DE-C821676904E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2480F13E-E9ED-44EC-A5DE-C821676904E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0F7BA6C3-BF3C-42D5-9268-593B4AF8FC12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0F7BA6C3-BF3C-42D5-9268-593B4AF8FC12}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Source/PickUpAndHaul/DebugLog.cs b/Source/PickUpAndHaul/DebugLog.cs
index 2744706..fb56ddf 100644
--- a/Source/PickUpAndHaul/DebugLog.cs
+++ b/Source/PickUpAndHaul/DebugLog.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace PickUpAndHaul
+namespace PickUpAndHaul
{
static class Log
{
diff --git a/Source/PickUpAndHaul/HarmonyPatches.cs b/Source/PickUpAndHaul/HarmonyPatches.cs
index 63e0170..ed7fb91 100644
--- a/Source/PickUpAndHaul/HarmonyPatches.cs
+++ b/Source/PickUpAndHaul/HarmonyPatches.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using RimWorld;
using Verse;
using UnityEngine;
-using Harmony;
+using HarmonyLib;
using System.Reflection.Emit;
using System.Reflection;
using Verse.AI;
@@ -17,7 +16,10 @@ static class HarmonyPatches
{
static HarmonyPatches()
{
- HarmonyInstance harmony = HarmonyInstance.Create(id: "mehni.rimworld.pickupandhaul.main");
+ var harmony = new Harmony("mehni.rimworld.pickupandhaul.main");
+#if DEBUG
+ Harmony.DEBUG = true;
+#endif
harmony.Patch(original: AccessTools.Method(typeof(FloatMenuMakerMap), "AddHumanlikeOrders"),
transpiler: new HarmonyMethod(typeof(HarmonyPatches), nameof(FloatMenuMakerMad_AddHumanlikeOrders_Transpiler)));
@@ -40,7 +42,7 @@ static HarmonyPatches()
harmony.Patch(original: AccessTools.Method(typeof(ITab_Pawn_Gear), "DrawThingRow"),
transpiler: new HarmonyMethod(typeof(HarmonyPatches), nameof(GearTabHighlightTranspiler)));
- Verse.Log.Message("PickUpAndHaul v0.1.0.5¼ welcomes you to RimWorld with pointless logspam.", true);
+ Verse.Log.Message("PickUpAndHaul v0.1.1.0⅓ welcomes you to RimWorld with pointless logspam.", true);
}
private static bool Drop_Prefix(Pawn pawn, Thing thing)
@@ -101,7 +103,6 @@ public static void DropUnusedInventory_PostFix(Pawn pawn)
public static IEnumerable FloatMenuMakerMad_AddHumanlikeOrders_Transpiler(IEnumerable instructions)
{
-
MethodInfo playerHome = AccessTools.Property(typeof(Map), nameof(Map.IsPlayerHome)).GetGetMethod();
List instructionList = instructions.ToList();
@@ -109,7 +110,7 @@ public static IEnumerable FloatMenuMakerMad_AddHumanlikeOrders_
foreach (CodeInstruction instruction in instructionList)
{
- if (!patched && instruction.operand == playerHome && !ModCompatibilityCheck.CombatExtendedIsActive)
+ if (!patched && instruction.Calls(playerHome) && !ModCompatibilityCheck.CombatExtendedIsActive)
{
instruction.opcode = OpCodes.Ldc_I4_0;
instruction.operand = null;
@@ -122,26 +123,24 @@ public static IEnumerable FloatMenuMakerMad_AddHumanlikeOrders_
//ITab_Pawn_Gear
//private void DrawThingRow(ref float y, float width, Thing thing, bool inventory = false)
- public static IEnumerable GearTabHighlightTranspiler(IEnumerable instructions, ILGenerator il, MethodBase mb)
+ public static IEnumerable GearTabHighlightTranspiler(IEnumerable instructions)
{
- MethodInfo WidgetsButtonImageInfo = AccessTools.Method(typeof(Widgets), "ButtonImage", new Type[] { typeof(Rect), typeof(Texture2D) });
- MethodInfo WidgetsButtonImageColorInfo = AccessTools.Method(typeof(Widgets), "ButtonImage", new Type[] { typeof(Rect), typeof(Texture2D), typeof(Color) });
-
MethodInfo SelPawnForGearInfo = AccessTools.Property(typeof(ITab_Pawn_Gear), "SelPawnForGear").GetGetMethod(true);
MethodInfo GetColorForHauledInfo = AccessTools.Method(typeof(HarmonyPatches), nameof(GetColorForHauled));
+ MethodInfo ColorWhite = AccessTools.Property(typeof(Color), nameof(Color.white)).GetGetMethod();
+
bool done = false;
foreach (CodeInstruction i in instructions)
{
- //if (Widgets.ButtonImage(rect2, TexButton.Drop))
- if (!done && i.opcode == OpCodes.Call && i.operand == WidgetsButtonImageInfo)
+ //// Color color = flag ? Color.grey : Color.white;
+ if (!done && i.Calls(ColorWhite))
{
yield return new CodeInstruction(OpCodes.Ldarg_0); //this
yield return new CodeInstruction(OpCodes.Call, SelPawnForGearInfo); //this.SelPawnForGearInfo
yield return new CodeInstruction(OpCodes.Ldarg_3); //thing
yield return new CodeInstruction(OpCodes.Call, GetColorForHauledInfo); //GetColorForHauledInfo(Pawn, Thing)
- yield return new CodeInstruction(OpCodes.Call, WidgetsButtonImageColorInfo); //ButtonImage(rect, texture, color)
done = true;
}
else
diff --git a/Source/PickUpAndHaul/JobDriver_HaulToInventory.cs b/Source/PickUpAndHaul/JobDriver_HaulToInventory.cs
index 1cad9b6..80fe3cb 100644
--- a/Source/PickUpAndHaul/JobDriver_HaulToInventory.cs
+++ b/Source/PickUpAndHaul/JobDriver_HaulToInventory.cs
@@ -145,7 +145,7 @@ protected override IEnumerable MakeNewToils()
Job curJob = actor.jobs.curJob;
LocalTargetInfo storeCell = curJob.targetB;
- Job unloadJob = new Job(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, storeCell);
+ Job unloadJob = JobMaker.MakeJob(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, storeCell);
if (unloadJob.TryMakePreToilReservations(actor, false))
{
actor.jobs.jobQueue.EnqueueFirst(unloadJob, JobTag.Misc);
diff --git a/Source/PickUpAndHaul/JobDriver_UnloadYourHauledInventory.cs b/Source/PickUpAndHaul/JobDriver_UnloadYourHauledInventory.cs
index 309c2e6..0539126 100644
--- a/Source/PickUpAndHaul/JobDriver_UnloadYourHauledInventory.cs
+++ b/Source/PickUpAndHaul/JobDriver_UnloadYourHauledInventory.cs
@@ -158,7 +158,7 @@ from straggler in pawn.inventory.innerContainer
}
return new ThingCount(thing, thing.stackCount);
}
- return default(ThingCount);
+ return default;
}
}
}
\ No newline at end of file
diff --git a/Source/PickUpAndHaul/PawnUnloadChecker.cs b/Source/PickUpAndHaul/PawnUnloadChecker.cs
index 47ef7f2..519dacd 100644
--- a/Source/PickUpAndHaul/PawnUnloadChecker.cs
+++ b/Source/PickUpAndHaul/PawnUnloadChecker.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using System.Collections.Generic;
using RimWorld;
using Verse;
using Verse.AI;
@@ -12,7 +9,7 @@ public class PawnUnloadChecker
{
public static void CheckIfPawnShouldUnloadInventory(Pawn pawn, bool forced = false)
{
- Job job = new Job(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, pawn);
+ Job job = JobMaker.MakeJob(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, pawn);
CompHauledToInventory itemsTakenToInventory = pawn.TryGetComp();
if (itemsTakenToInventory == null)
diff --git a/Source/PickUpAndHaul/PickUpAndHaul.csproj b/Source/PickUpAndHaul/PickUpAndHaul.csproj
index 35b6458..2e47ac0 100644
--- a/Source/PickUpAndHaul/PickUpAndHaul.csproj
+++ b/Source/PickUpAndHaul/PickUpAndHaul.csproj
@@ -9,45 +9,44 @@
Properties
PickUpAndHaul
PickUpAndHaul
- v3.5
+ v4.7.2
512
+
false
none
true
- ..\..\Assemblies\
+ ..\..\v1.1\Assemblies\
DEBUG;TRACE
prompt
4
+ false
none
true
- ..\..\Assemblies\
+ ..\..\1.1\Assemblies\
TRACE
prompt
4
+ false
-
- False
- ..\..\..\..\..\..\..\..\..\..\Users\Maniak\Documents\RimWorld Mods\0Harmony.dll
+
+ ..\..\..\..\..\..\workshop\content\294100\2009463077\Assemblies\0Harmony.dll
..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll
False
-
- ..\..\..\..\..\..\workshop\content\294100\731732064\Assemblies\ExtendedStorage.dll
- False
-
False
..\..\Assemblies\IHoldMultipleThings.dll
+
@@ -56,13 +55,15 @@
..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll
False
+
+ ..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.CoreModule.dll
+ False
+
-
-
diff --git a/Source/PickUpAndHaul/Properties/AssemblyInfo.cs b/Source/PickUpAndHaul/Properties/AssemblyInfo.cs
index 7dab455..a040188 100644
--- a/Source/PickUpAndHaul/Properties/AssemblyInfo.cs
+++ b/Source/PickUpAndHaul/Properties/AssemblyInfo.cs
@@ -33,4 +33,4 @@
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.1.0.5")]
-[assembly: AssemblyFileVersion("0.1.0.853")]
+[assembly: AssemblyFileVersion("0.1.1.0")]
diff --git a/Source/PickUpAndHaul/WorkGiver_HaulToInventory.cs b/Source/PickUpAndHaul/WorkGiver_HaulToInventory.cs
index 18979d0..479eb85 100644
--- a/Source/PickUpAndHaul/WorkGiver_HaulToInventory.cs
+++ b/Source/PickUpAndHaul/WorkGiver_HaulToInventory.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using RimWorld;
using Verse;
using Verse.AI;
@@ -91,7 +90,7 @@ public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false)
if (capacityStoreCell == 0) return HaulAIUtility.HaulToStorageJob(pawn, thing);
- Job job = new Job(PickUpAndHaulJobDefOf.HaulToInventory, null, storeCell); //Things will be in queues
+ Job job = JobMaker.MakeJob(PickUpAndHaulJobDefOf.HaulToInventory, null, storeCell); //Things will be in queues
Log.Message($"-------------------------------------------------------------------");
Log.Message($"------------------------------------------------------------------");//different size so the log doesn't count it 2x
Log.Message($"{pawn} job found to haul: {thing} to {storeCell}:{capacityStoreCell}, looking for more now");
@@ -99,7 +98,7 @@ public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false)
//Find extra things than can be hauled to inventory, queue to reserve them
bool isUrgent = ModCompatibilityCheck.AllowToolIsActive && pawn.Map.designationManager.DesignationOn(thing)?.def == haulUrgentlyDesignation;
- Func validatorExtra = (Thing t) =>
+ bool validatorExtra(Thing t) =>
(!isUrgent || pawn.Map.designationManager.DesignationOn(t)?.def == haulUrgentlyDesignation) &&
GoodThingToHaul(t, pawn) && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t, false);//forced is false, may differ from first thing
@@ -221,19 +220,13 @@ public CellAllocation(Thing a, int c)
public static int CapacityAt(Thing thing, IntVec3 storeCell, Map map)
{
- int capacity;
- if (HoldMultipleThings_Support.CapacityAt(thing, storeCell, map, out capacity))
+ if (HoldMultipleThings_Support.CapacityAt(thing, storeCell, map, out int capacity))
{
Log.Message($"Found external capacity of {capacity}");
return capacity;
}
- if (ExtendedStorage_Support.CapacityAt(thing, storeCell, map, out capacity))
- {
- return capacity;
- }
-
capacity = thing.def.stackLimit;
Thing preExistingThing = map.thingGrid.ThingAt(storeCell, thing.def);
@@ -246,8 +239,7 @@ public static int CapacityAt(Thing thing, IntVec3 storeCell, Map map)
public static bool Stackable(Thing nextThing, KeyValuePair allocation)
=> nextThing == allocation.Value.allocated
|| allocation.Value.allocated.CanStackWith(nextThing)
- || HoldMultipleThings_Support.StackableAt(nextThing, allocation.Key, nextThing.Map)
- || ExtendedStorage_Support.StackableAt(nextThing.def, allocation.Key, nextThing.Map);
+ || HoldMultipleThings_Support.StackableAt(nextThing, allocation.Key, nextThing.Map);
public static bool AllocateThingAtCell(Dictionary storeCellCapacity, Pawn pawn, Thing nextThing, Job job)
{
@@ -258,7 +250,7 @@ public static bool AllocateThingAtCell(Dictionary store
IntVec3 storeCell = allocation.Key;
//Can't stack with allocated cells, find a new cell:
- if (storeCell == default(IntVec3))
+ if (storeCell == default)
{
StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(nextThing);
if (TryFindBestBetterStoreCellFor(nextThing, pawn, map, currentPriority, pawn.Faction, out IntVec3 nextStoreCell))
@@ -326,7 +318,7 @@ public static bool TryFindBestBetterStoreCellFor(Thing thing, Pawn carrier, Map
.Where(s => s.Settings.Priority > currentPriority && s.parent.Accepts(thing)))
{
if (slotGroup.CellsList.Except(skipCells).FirstOrDefault(c => StoreUtility.IsGoodStoreCell(c, map, thing, carrier, faction)) is IntVec3 cell
- && cell != default(IntVec3))
+ && cell != default)
{
foundCell = cell;
diff --git a/Source/PickUpAndHaulv1.0/CompHauledToInventory.cs b/Source/PickUpAndHaulv1.0/CompHauledToInventory.cs
new file mode 100644
index 0000000..8a75a28
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/CompHauledToInventory.cs
@@ -0,0 +1,27 @@
+namespace PickUpAndHaul
+{
+ using System.Collections.Generic;
+ using Verse;
+
+ public class CompHauledToInventory : ThingComp
+ {
+ private HashSet takenToInventory = new HashSet();
+
+ public HashSet GetHashSet()
+ {
+ takenToInventory.RemoveWhere(x => x == null);
+ return takenToInventory;
+ }
+
+ public void RegisterHauledItem(Thing thing)
+ {
+ this.takenToInventory.Add(thing);
+ }
+
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+ Scribe_Collections.Look(ref takenToInventory, "ThingsHauledToInventory", LookMode.Reference);
+ }
+ }
+}
diff --git a/Source/PickUpAndHaulv1.0/DebugLog.cs b/Source/PickUpAndHaulv1.0/DebugLog.cs
new file mode 100644
index 0000000..2744706
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/DebugLog.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace PickUpAndHaul
+{
+ static class Log
+ {
+ [System.Diagnostics.Conditional("DEBUG")]
+ public static void Message(string x)
+ {
+ Verse.Log.Message(x, true);
+ }
+ }
+}
diff --git a/Source/PickUpAndHaul/ExtendedStorage_Support.cs b/Source/PickUpAndHaulv1.0/ExtendedStorage_Support.cs
similarity index 100%
rename from Source/PickUpAndHaul/ExtendedStorage_Support.cs
rename to Source/PickUpAndHaulv1.0/ExtendedStorage_Support.cs
diff --git a/Source/PickUpAndHaulv1.0/HarmonyPatches.cs b/Source/PickUpAndHaulv1.0/HarmonyPatches.cs
new file mode 100644
index 0000000..63e0170
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/HarmonyPatches.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using UnityEngine;
+using Harmony;
+using System.Reflection.Emit;
+using System.Reflection;
+using Verse.AI;
+
+namespace PickUpAndHaul
+{
+ [StaticConstructorOnStartup]
+ static class HarmonyPatches
+ {
+ static HarmonyPatches()
+ {
+ HarmonyInstance harmony = HarmonyInstance.Create(id: "mehni.rimworld.pickupandhaul.main");
+
+ harmony.Patch(original: AccessTools.Method(typeof(FloatMenuMakerMap), "AddHumanlikeOrders"),
+ transpiler: new HarmonyMethod(typeof(HarmonyPatches), nameof(FloatMenuMakerMad_AddHumanlikeOrders_Transpiler)));
+
+ harmony.Patch(original: AccessTools.Method(typeof(JobGiver_DropUnusedInventory), "TryGiveJob"),
+ postfix: new HarmonyMethod(typeof(HarmonyPatches), nameof(DropUnusedInventory_PostFix)));
+
+ harmony.Patch(original: AccessTools.Method(typeof(JobDriver_HaulToCell), "MakeNewToils"),
+ postfix: new HarmonyMethod(typeof(HarmonyPatches), nameof(JobDriver_HaulToCell_PostFix)));
+
+ harmony.Patch(original: AccessTools.Method(typeof(Pawn_InventoryTracker), "Notify_ItemRemoved"),
+ postfix: new HarmonyMethod(typeof(HarmonyPatches), nameof(Pawn_InventoryTracker_PostFix)));
+
+ harmony.Patch(original: AccessTools.Method(typeof(JobGiver_DropUnusedInventory), "Drop"),
+ prefix: new HarmonyMethod(typeof(HarmonyPatches), nameof(Drop_Prefix)));
+
+ harmony.Patch(original: AccessTools.Method(typeof(JobGiver_Idle), "TryGiveJob"),
+ postfix: new HarmonyMethod(typeof(HarmonyPatches), nameof(IdleJoy_Postfix)));
+
+ harmony.Patch(original: AccessTools.Method(typeof(ITab_Pawn_Gear), "DrawThingRow"),
+ transpiler: new HarmonyMethod(typeof(HarmonyPatches), nameof(GearTabHighlightTranspiler)));
+
+ Verse.Log.Message("PickUpAndHaul v0.1.0.5¼ welcomes you to RimWorld with pointless logspam.", true);
+ }
+
+ private static bool Drop_Prefix(Pawn pawn, Thing thing)
+ {
+ CompHauledToInventory takenToInventory = pawn.TryGetComp();
+ if (takenToInventory == null)
+ return true;
+
+ HashSet carriedThing = takenToInventory.GetHashSet();
+
+ return !carriedThing.Contains(thing);
+ }
+
+ private static void Pawn_InventoryTracker_PostFix(Pawn_InventoryTracker __instance, Thing item)
+ {
+ CompHauledToInventory takenToInventory = __instance.pawn.TryGetComp();
+ if (takenToInventory == null)
+ return;
+
+ HashSet carriedThing = takenToInventory.GetHashSet();
+ if (carriedThing?.Count > 0)
+ {
+ if (carriedThing.Contains(item))
+ {
+ carriedThing.Remove(item);
+ }
+ }
+ }
+
+ private static void JobDriver_HaulToCell_PostFix(JobDriver_HaulToCell __instance)
+ {
+ CompHauledToInventory takenToInventory = __instance.pawn.TryGetComp();
+ if (takenToInventory == null)
+ return;
+
+ HashSet carriedThing = takenToInventory.GetHashSet();
+
+ if (__instance.job.haulMode == HaulMode.ToCellStorage
+ && __instance.pawn.Faction == Faction.OfPlayer
+ && __instance.pawn.RaceProps.Humanlike
+ && __instance.pawn.carryTracker.CarriedThing is Corpse == false
+ && carriedThing != null
+ && carriedThing.Count != 0) //deliberate hauling job. Should unload.
+ {
+ PawnUnloadChecker.CheckIfPawnShouldUnloadInventory(__instance.pawn, true);
+ }
+ }
+
+ public static void IdleJoy_Postfix(Pawn pawn)
+ {
+ PawnUnloadChecker.CheckIfPawnShouldUnloadInventory(pawn, true);
+ }
+
+ public static void DropUnusedInventory_PostFix(Pawn pawn)
+ {
+ PawnUnloadChecker.CheckIfPawnShouldUnloadInventory(pawn);
+ }
+
+ public static IEnumerable FloatMenuMakerMad_AddHumanlikeOrders_Transpiler(IEnumerable instructions)
+ {
+
+ MethodInfo playerHome = AccessTools.Property(typeof(Map), nameof(Map.IsPlayerHome)).GetGetMethod();
+ List instructionList = instructions.ToList();
+
+ bool patched = false;
+
+ foreach (CodeInstruction instruction in instructionList)
+ {
+ if (!patched && instruction.operand == playerHome && !ModCompatibilityCheck.CombatExtendedIsActive)
+ {
+ instruction.opcode = OpCodes.Ldc_I4_0;
+ instruction.operand = null;
+ yield return instruction;
+ patched = true;
+ }
+ yield return instruction;
+ }
+ }
+
+ //ITab_Pawn_Gear
+ //private void DrawThingRow(ref float y, float width, Thing thing, bool inventory = false)
+ public static IEnumerable GearTabHighlightTranspiler(IEnumerable instructions, ILGenerator il, MethodBase mb)
+ {
+ MethodInfo WidgetsButtonImageInfo = AccessTools.Method(typeof(Widgets), "ButtonImage", new Type[] { typeof(Rect), typeof(Texture2D) });
+ MethodInfo WidgetsButtonImageColorInfo = AccessTools.Method(typeof(Widgets), "ButtonImage", new Type[] { typeof(Rect), typeof(Texture2D), typeof(Color) });
+
+ MethodInfo SelPawnForGearInfo = AccessTools.Property(typeof(ITab_Pawn_Gear), "SelPawnForGear").GetGetMethod(true);
+
+ MethodInfo GetColorForHauledInfo = AccessTools.Method(typeof(HarmonyPatches), nameof(GetColorForHauled));
+
+ bool done = false;
+ foreach (CodeInstruction i in instructions)
+ {
+ //if (Widgets.ButtonImage(rect2, TexButton.Drop))
+ if (!done && i.opcode == OpCodes.Call && i.operand == WidgetsButtonImageInfo)
+ {
+ yield return new CodeInstruction(OpCodes.Ldarg_0); //this
+ yield return new CodeInstruction(OpCodes.Call, SelPawnForGearInfo); //this.SelPawnForGearInfo
+ yield return new CodeInstruction(OpCodes.Ldarg_3); //thing
+ yield return new CodeInstruction(OpCodes.Call, GetColorForHauledInfo); //GetColorForHauledInfo(Pawn, Thing)
+ yield return new CodeInstruction(OpCodes.Call, WidgetsButtonImageColorInfo); //ButtonImage(rect, texture, color)
+ done = true;
+ }
+ else
+ yield return i;
+ }
+ }
+
+ private static Color GetColorForHauled(Pawn pawn, Thing thing)
+ {
+ if (pawn.GetComp()?.GetHashSet().Contains(thing) ?? false)
+ return Color.Lerp(Color.grey, Color.red, 0.5f);
+ return Color.white;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/PickUpAndHaulv1.0/IHoldMultipleThings_Support.cs b/Source/PickUpAndHaulv1.0/IHoldMultipleThings_Support.cs
new file mode 100644
index 0000000..016682c
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/IHoldMultipleThings_Support.cs
@@ -0,0 +1,42 @@
+using Verse;
+
+namespace PickUpAndHaul
+{
+ using System.Linq;
+
+ public class HoldMultipleThings_Support
+ {
+ // ReSharper disable SuspiciousTypeConversion.Global
+ public static bool CapacityAt(Thing thing, IntVec3 storeCell, Map map, out int capacity)
+ {
+ capacity = 0;
+
+ var compOfHolding = (map.haulDestinationManager.SlotGroupParentAt(storeCell) as ThingWithComps)?
+ .AllComps.FirstOrDefault(x => x is IHoldMultipleThings.IHoldMultipleThings);
+
+ if (compOfHolding is IHoldMultipleThings.IHoldMultipleThings holderOfThings)
+ return holderOfThings.CapacityAt(thing, storeCell, map, out capacity);
+
+ foreach (Thing t in storeCell.GetThingList(map))
+ if (t is IHoldMultipleThings.IHoldMultipleThings holderOfMultipleThings)
+ return holderOfMultipleThings.CapacityAt(thing, storeCell, map, out capacity);
+
+ return false;
+ }
+
+ public static bool StackableAt(Thing thing, IntVec3 storeCell, Map map)
+ {
+ var compOfHolding = (map.haulDestinationManager.SlotGroupParentAt(storeCell) as ThingWithComps)?
+ .AllComps.FirstOrDefault(x => x is IHoldMultipleThings.IHoldMultipleThings);
+
+ if (compOfHolding is IHoldMultipleThings.IHoldMultipleThings holderOfThings)
+ return holderOfThings.StackableAt(thing, storeCell, map);
+
+ foreach (Thing t in storeCell.GetThingList(map))
+ if (t is IHoldMultipleThings.IHoldMultipleThings holderOfMultipleThings)
+ return holderOfMultipleThings.StackableAt(thing, storeCell, map);
+
+ return false;
+ }
+ }
+}
diff --git a/Source/PickUpAndHaulv1.0/JobDriver_HaulToInventory.cs b/Source/PickUpAndHaulv1.0/JobDriver_HaulToInventory.cs
new file mode 100644
index 0000000..1cad9b6
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/JobDriver_HaulToInventory.cs
@@ -0,0 +1,201 @@
+namespace PickUpAndHaul
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using RimWorld;
+ using UnityEngine;
+ using Verse;
+ using Verse.AI;
+
+ public class JobDriver_HaulToInventory : JobDriver
+ {
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ Log.Message($"{pawn} starting HaulToInventory job: {job.targetQueueA.ToStringSafeEnumerable()}:{job.countQueue.ToStringSafeEnumerable()}");
+ pawn.ReserveAsManyAsPossible(job.targetQueueA, job);
+ pawn.ReserveAsManyAsPossible(job.targetQueueB, job);
+ return pawn.Reserve(job.targetQueueA[0], job) && pawn.Reserve(job.targetB, job);
+ }
+
+ //get next, goto, take, check for more. Branches off to "all over the place"
+ protected override IEnumerable MakeNewToils()
+ {
+ CompHauledToInventory takenToInventory = pawn.TryGetComp();
+
+ Toil wait = Toils_General.Wait(2);
+
+ Toil nextTarget = Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A); //also does count
+ yield return nextTarget;
+
+ //honestly the workgiver checks for encumbered, so until CE checks are in this is unnecessary
+ //yield return CheckForOverencumbered();//Probably redundant without CE checks
+
+ Toil gotoThing = new Toil
+ {
+ initAction = () =>
+ {
+ pawn.pather.StartPath(TargetThingA, PathEndMode.ClosestTouch);
+ },
+ defaultCompleteMode = ToilCompleteMode.PatherArrival
+ };
+ gotoThing.FailOnDespawnedNullOrForbidden(TargetIndex.A);
+ yield return gotoThing;
+
+ Toil takeThing = new Toil
+ {
+ initAction = () =>
+ {
+ Pawn actor = pawn;
+ Thing thing = actor.CurJob.GetTarget(TargetIndex.A).Thing;
+ Toils_Haul.ErrorCheckForCarry(actor, thing);
+
+ //get max we can pick up
+ int countToPickUp = Mathf.Min(job.count, MassUtility.CountToPickUpUntilOverEncumbered(actor, thing));
+ Log.Message($"{actor} is hauling to inventory {thing}:{countToPickUp}");
+
+ // yo dawg, I heard you like delegates so I put delegates in your delegate, so you can delegate your delegates.
+ // because compilers don't respect IF statements in delegates and toils are fully iterated over as soon as the job starts.
+ try
+ {
+ ((Action)(() =>
+ {
+ if (ModCompatibilityCheck.CombatExtendedIsActive)
+ {
+ //CombatExtended.CompInventory ceCompInventory = actor.GetComp();
+ //ceCompInventory.CanFitInInventory(thing, out countToPickUp);
+ }
+ }))();
+ }
+ catch (TypeLoadException) { }
+
+ if (countToPickUp > 0)
+ {
+ Thing splitThing = thing.SplitOff(countToPickUp);
+ bool shouldMerge = takenToInventory.GetHashSet().Any(x => x.def == thing.def);
+ actor.inventory.GetDirectlyHeldThings().TryAdd(splitThing, shouldMerge);
+ takenToInventory.RegisterHauledItem(splitThing);
+
+ try
+ {
+ ((Action)(() =>
+ {
+ if (ModCompatibilityCheck.CombatExtendedIsActive)
+ {
+ //CombatExtended.CompInventory ceCompInventory = actor.GetComp();
+ //ceCompInventory.UpdateInventory();
+ }
+ }))();
+ }
+ catch (TypeLoadException)
+ {
+ }
+ }
+
+ //thing still remains, so queue up hauling if we can + end the current job (smooth/instant transition)
+ //This will technically release the reservations in the queue, but what can you do
+ if (thing.Spawned)
+ {
+ Job haul = HaulAIUtility.HaulToStorageJob(actor, thing);
+ if (haul?.TryMakePreToilReservations(actor, false) ?? false)
+ {
+ actor.jobs.jobQueue.EnqueueFirst(haul, JobTag.Misc);
+ }
+ actor.jobs.curDriver.JumpToToil(wait);
+ }
+ }
+ };
+ yield return takeThing;
+ yield return Toils_Jump.JumpIf(nextTarget, () => !job.targetQueueA.NullOrEmpty());
+
+ //Find more to haul, in case things spawned while this was in progess
+ yield return new Toil
+ {
+ initAction = () =>
+ {
+ List haulables = pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling();
+ WorkGiver_HaulToInventory haulMoreWork = DefDatabase.AllDefsListForReading.First(wg => wg.Worker is WorkGiver_HaulToInventory).Worker as WorkGiver_HaulToInventory;
+ Thing haulMoreThing = GenClosest.ClosestThing_Global(pawn.Position, haulables, 12, t => haulMoreWork.HasJobOnThing(pawn, t));
+
+ //WorkGiver_HaulToInventory found more work nearby
+ if (haulMoreThing != null)
+ {
+ Log.Message($"{pawn} hauling again : {haulMoreThing}");
+ Job haulMoreJob = haulMoreWork.JobOnThing(pawn, haulMoreThing);
+
+ if (haulMoreJob.TryMakePreToilReservations(pawn, false))
+ {
+ pawn.jobs.jobQueue.EnqueueFirst(haulMoreJob, JobTag.Misc);
+ EndJobWith(JobCondition.Succeeded);
+ }
+ }
+ }
+ };
+
+ //maintain cell reservations on the trip back
+ //TODO: do that when we carry things
+ //I guess that means TODO: implement carrying the rest of the items in this job instead of falling back on HaulToStorageJob
+ yield return Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.ClosestTouch);
+
+ yield return new Toil //Queue next job
+ {
+ initAction = () =>
+ {
+ Pawn actor = pawn;
+ Job curJob = actor.jobs.curJob;
+ LocalTargetInfo storeCell = curJob.targetB;
+
+ Job unloadJob = new Job(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, storeCell);
+ if (unloadJob.TryMakePreToilReservations(actor, false))
+ {
+ actor.jobs.jobQueue.EnqueueFirst(unloadJob, JobTag.Misc);
+ EndJobWith(JobCondition.Succeeded);
+ //This will technically release the cell reservations in the queue, but what can you do
+ }
+ }
+ };
+ yield return wait;
+ }
+
+ public Toil CheckForOverencumbered()
+ {
+ Toil toil = new Toil();
+ toil.initAction = delegate
+ {
+ Pawn actor = toil.actor;
+ Job curJob = actor.jobs.curJob;
+ Thing nextThing = curJob.targetA.Thing;
+
+ //float usedBulkByPct = 1f;
+ //float usedWeightByPct = 1f;
+
+ //try
+ //{
+ // ((Action)(() =>
+ // {
+ // if (ModCompatibilityCheck.CombatExtendedIsActive)
+ // {
+ // CompInventory ceCompInventory = actor.GetComp();
+ // usedWeightByPct = ceCompInventory.currentWeight / ceCompInventory.capacityWeight;
+ // usedBulkByPct = ceCompInventory.currentBulk / ceCompInventory.capacityBulk;
+ // }
+ // }))();
+ //}
+ //catch (TypeLoadException) { }
+
+
+ if (!(MassUtility.EncumbrancePercent(actor) <= 0.9f /*|| usedBulkByPct >= 0.7f || usedWeightByPct >= 0.8f*/))
+ {
+ Job haul = HaulAIUtility.HaulToStorageJob(actor, nextThing);
+ if (haul?.TryMakePreToilReservations(actor, false) ?? false)
+ {
+ //note that HaulToStorageJob etc doesn't do opportunistic duplicate hauling for items in valid storage. REEEE
+ actor.jobs.jobQueue.EnqueueFirst(haul, JobTag.Misc);
+ EndJobWith(JobCondition.Succeeded);
+ }
+ }
+ };
+ return toil;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/PickUpAndHaulv1.0/JobDriver_UnloadYourHauledInventory.cs b/Source/PickUpAndHaulv1.0/JobDriver_UnloadYourHauledInventory.cs
new file mode 100644
index 0000000..309c2e6
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/JobDriver_UnloadYourHauledInventory.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+using RimWorld;
+using System.Linq;
+
+namespace PickUpAndHaul
+{
+ public class JobDriver_UnloadYourHauledInventory : JobDriver
+ {
+ private int countToDrop = -1;
+ private int unloadDuration = 3;
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref countToDrop, "countToDrop", -1);
+ }
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ => true;
+
+ ///
+ /// Find spot, reserve spot, pull thing out of inventory, go to spot, drop stuff, repeat.
+ ///
+ ///
+ protected override IEnumerable MakeNewToils()
+ {
+ CompHauledToInventory takenToInventory = pawn.TryGetComp();
+ HashSet carriedThing = takenToInventory.GetHashSet();
+
+ if (ModCompatibilityCheck.ExtendedStorageIsActive)
+ unloadDuration = 20;
+
+ Toil wait = Toils_General.Wait(unloadDuration);
+ Toil celebrate = Toils_General.Wait(unloadDuration);
+
+ yield return wait;
+ Toil findSpot = new Toil
+ {
+ initAction = () =>
+ {
+ ThingCount unloadableThing = FirstUnloadableThing(pawn);
+
+ if (unloadableThing.Count == 0 && carriedThing.Count == 0)
+ EndJobWith(JobCondition.Succeeded);
+
+ if (unloadableThing.Count != 0)
+ {
+ //StoragePriority currentPriority = StoreUtility.StoragePriorityAtFor(pawn.Position, unloadableThing.Thing);
+ if (!StoreUtility.TryFindStoreCellNearColonyDesperate(unloadableThing.Thing, pawn, out IntVec3 c))
+ {
+ pawn.inventory.innerContainer.TryDrop(unloadableThing.Thing, ThingPlaceMode.Near, unloadableThing.Thing.stackCount, out Thing _);
+ EndJobWith(JobCondition.Succeeded);
+ }
+ else
+ {
+ job.SetTarget(TargetIndex.A, unloadableThing.Thing);
+ job.SetTarget(TargetIndex.B, c);
+ countToDrop = unloadableThing.Thing.stackCount;
+ }
+ }
+ }
+ };
+ yield return findSpot;
+
+ yield return Toils_Reserve.Reserve(TargetIndex.B);
+
+ yield return new Toil
+ {
+ initAction = delegate
+ {
+ Thing thing = job.GetTarget(TargetIndex.A).Thing;
+ if (thing == null || !pawn.inventory.innerContainer.Contains(thing))
+ {
+ carriedThing.Remove(thing);
+ pawn.jobs.curDriver.JumpToToil(wait);
+ return;
+ }
+ if (!pawn.health.capacities.CapableOf(PawnCapacityDefOf.Manipulation) || !thing.def.EverStorable(false))
+ {
+ pawn.inventory.innerContainer.TryDrop(thing, ThingPlaceMode.Near, countToDrop, out thing);
+ EndJobWith(JobCondition.Succeeded);
+ carriedThing.Remove(thing);
+ }
+ else
+ {
+ pawn.inventory.innerContainer.TryTransferToContainer(thing, pawn.carryTracker.innerContainer, countToDrop, out thing);
+ job.count = countToDrop;
+ job.SetTarget(TargetIndex.A, thing);
+ carriedThing.Remove(thing);
+ }
+ try
+ {
+ ((Action)(() =>
+ {
+ if (ModCompatibilityCheck.CombatExtendedIsActive)
+ {
+ //CombatExtended.CompInventory ceCompInventory = pawn.GetComp();
+ //ceCompInventory.UpdateInventory();
+ }
+ }))();
+ }
+ catch (TypeLoadException) { }
+ thing.SetForbidden(false, false);
+ }
+ };
+
+ Toil carryToCell = Toils_Haul.CarryHauledThingToCell(TargetIndex.B);
+ yield return Toils_Goto.GotoCell(TargetIndex.B, PathEndMode.Touch);
+ yield return carryToCell;
+ yield return Toils_Haul.PlaceHauledThingInCell(TargetIndex.B, carryToCell, true);
+
+ //If the original cell is full, PlaceHauledThingInCell will set a different TargetIndex resulting in errors on yield return Toils_Reserve.Release.
+ //We still gotta release though, mostly because of Extended Storage.
+ Toil releaseReservation = new Toil
+ {
+ initAction = () =>
+ {
+ if (pawn.Map.reservationManager.ReservedBy(job.targetB, pawn, pawn.CurJob)
+ && !ModCompatibilityCheck.HCSKIsActive)
+ pawn.Map.reservationManager.Release(job.targetB, pawn, pawn.CurJob);
+ }
+ };
+ yield return releaseReservation;
+ yield return Toils_Jump.Jump(wait);
+ yield return celebrate;
+ }
+
+ private static ThingCount FirstUnloadableThing(Pawn pawn)
+ {
+ CompHauledToInventory itemsTakenToInventory = pawn.TryGetComp();
+ HashSet carriedThings = itemsTakenToInventory.GetHashSet();
+
+ //find the overlap.
+ IEnumerable potentialThingsToUnload =
+ from t in pawn.inventory.innerContainer
+ where carriedThings.Contains(t)
+ select t;
+
+ foreach (Thing thing in carriedThings.OrderBy(t => t.def.FirstThingCategory?.index))
+ {
+ //merged partially picked up stacks get a different thingID in inventory
+ if (!potentialThingsToUnload.Contains(thing))
+ {
+ ThingDef stragglerDef = thing.def;
+ //we have no method of grabbing the newly generated thingID. This is the solution to that.
+ IEnumerable dirtyStragglers =
+ from straggler in pawn.inventory.innerContainer
+ where straggler.def == stragglerDef
+ select straggler;
+
+ carriedThings.Remove(thing);
+
+ foreach (Thing dirtyStraggler in dirtyStragglers)
+ return new ThingCount(dirtyStraggler, dirtyStraggler.stackCount);
+ }
+ return new ThingCount(thing, thing.stackCount);
+ }
+ return default(ThingCount);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/PickUpAndHaulv1.0/ModCompatibilityCheck.cs b/Source/PickUpAndHaulv1.0/ModCompatibilityCheck.cs
new file mode 100644
index 0000000..c640ce6
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/ModCompatibilityCheck.cs
@@ -0,0 +1,22 @@
+using System.Linq;
+using Verse;
+
+namespace PickUpAndHaul
+{
+ public static class ModCompatibilityCheck
+ {
+ public static bool CombatExtendedIsActive
+ => ModsConfig.ActiveModsInLoadOrder.Any(m => m.Name == "Combat Extended");
+
+ public static bool AllowToolIsActive
+ => ModsConfig.ActiveModsInLoadOrder.Any(m => m.Name == "Allow Tool");
+
+ public static bool ExtendedStorageIsActive
+ => ModsConfig.ActiveModsInLoadOrder.Any(m => m.Name == "ExtendedStorageFluffyHarmonised")
+ || ModsConfig.ActiveModsInLoadOrder.Any(m => m.Name == "Extended Storage")
+ || ModsConfig.ActiveModsInLoadOrder.Any(m => m.Name == "Core SK");
+
+ public static bool HCSKIsActive
+ => ModsConfig.ActiveModsInLoadOrder.Any(m => m.Name == "Core SK");
+ }
+}
diff --git a/Source/PickUpAndHaulv1.0/PawnUnloadChecker.cs b/Source/PickUpAndHaulv1.0/PawnUnloadChecker.cs
new file mode 100644
index 0000000..47ef7f2
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/PawnUnloadChecker.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace PickUpAndHaul
+{
+ public class PawnUnloadChecker
+ {
+ public static void CheckIfPawnShouldUnloadInventory(Pawn pawn, bool forced = false)
+ {
+ Job job = new Job(PickUpAndHaulJobDefOf.UnloadYourHauledInventory, pawn);
+ CompHauledToInventory itemsTakenToInventory = pawn.TryGetComp();
+
+ if (itemsTakenToInventory == null)
+ return;
+
+ HashSet carriedThing = itemsTakenToInventory.GetHashSet();
+
+ if (pawn.Faction != Faction.OfPlayer || !pawn.RaceProps.Humanlike)
+ return;
+ if (carriedThing == null || carriedThing.Count == 0 || pawn.inventory.innerContainer.Count == 0)
+ return;
+
+ if (forced)
+ {
+ if (job.TryMakePreToilReservations(pawn, false))
+ {
+ pawn.jobs.jobQueue.EnqueueFirst(job, JobTag.Misc);
+ return;
+ }
+ }
+
+ if (MassUtility.EncumbrancePercent(pawn) >= 0.90f || carriedThing.Count >= 1)
+ {
+ if (job.TryMakePreToilReservations(pawn, false))
+ {
+ pawn.jobs.jobQueue.EnqueueFirst(job, JobTag.Misc);
+ return;
+ }
+ }
+
+ if (pawn.inventory.innerContainer?.Count >= 1)
+ {
+ foreach (Thing rottable in pawn.inventory.innerContainer)
+ {
+ CompRottable compRottable = rottable.TryGetComp();
+
+ if (compRottable?.TicksUntilRotAtCurrentTemp < 30000)
+ {
+ pawn.jobs.jobQueue.EnqueueFirst(job, JobTag.Misc);
+ return;
+ }
+ }
+ }
+
+ if (Find.TickManager.TicksGame % 50 == 0 && pawn.inventory.innerContainer.Count < carriedThing.Count)
+ {
+ Verse.Log.Warning("[PickUpAndHaul] " + pawn + " inventory was found out of sync with haul index. Pawn will drop their inventory.");
+ carriedThing.Clear();
+ pawn.inventory.UnloadEverything = true;
+ }
+ }
+ }
+
+ [DefOf]
+ public static class PickUpAndHaulJobDefOf
+ {
+ public static JobDef UnloadYourHauledInventory;
+ public static JobDef HaulToInventory;
+ }
+}
\ No newline at end of file
diff --git a/Source/PickUpAndHaulv1.0/PickUpAndHaulv10.csproj b/Source/PickUpAndHaulv1.0/PickUpAndHaulv10.csproj
new file mode 100644
index 0000000..747532d
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/PickUpAndHaulv10.csproj
@@ -0,0 +1,74 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {2480F13E-E9ED-44EC-A5DE-C821676904E7}
+ Library
+ Properties
+ PickUpAndHaul
+ PickUpAndHaul
+ v3.5
+ 512
+
+
+ false
+ none
+ true
+ ..\..\Assemblies\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ none
+ true
+ ..\..\Assemblies\
+ TRACE
+ prompt
+ 4
+
+
+
+ False
+ ..\..\..\..\..\..\..\..\..\..\Users\Maniak\Documents\RimWorld Mods\0Harmony.dll
+
+
+ ..\..\..\..\RimWorldWin64_Data\Managed\Assembly-CSharp.dll
+ False
+
+
+ ..\..\..\..\..\..\workshop\content\294100\731732064\Assemblies\ExtendedStorage.dll
+ False
+
+
+ False
+ ..\..\Assemblies\IHoldMultipleThings.dll
+
+
+
+
+
+
+
+
+ ..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.dll
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Source/PickUpAndHaulv1.0/Properties/AssemblyInfo.cs b/Source/PickUpAndHaulv1.0/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..7dab455
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("PickUpAndHaul")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("PickUpAndHaul")]
+[assembly: AssemblyCopyright("Copyright © Mehni 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ccf8350b-e3fd-4693-9209-681e9c089097")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.1.0.5")]
+[assembly: AssemblyFileVersion("0.1.0.853")]
diff --git a/Source/PickUpAndHaulv1.0/WorkGiver_HaulToInventory.cs b/Source/PickUpAndHaulv1.0/WorkGiver_HaulToInventory.cs
new file mode 100644
index 0000000..18979d0
--- /dev/null
+++ b/Source/PickUpAndHaulv1.0/WorkGiver_HaulToInventory.cs
@@ -0,0 +1,348 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace PickUpAndHaul
+{
+ public class WorkGiver_HaulToInventory : WorkGiver_HaulGeneral
+ {
+ //Thanks to AlexTD for the more dynamic search range
+ //And queueing
+ //And optimizing
+ private const float SEARCH_FOR_OTHERS_RANGE_FRACTION = 0.5f;
+
+ public override bool ShouldSkip(Pawn pawn, bool forced = false) => base.ShouldSkip(pawn, forced)
+ || pawn.Faction != Faction.OfPlayer
+ || !pawn.RaceProps.Humanlike
+ || pawn.TryGetComp() == null;
+
+ public static bool GoodThingToHaul(Thing t, Pawn pawn) => t.Spawned
+ && !t.IsInValidBestStorage()
+ && !t.IsForbidden(pawn)
+ && !(t is Corpse)
+ && pawn.CanReserve(t);
+
+ public override bool HasJobOnThing(Pawn pawn, Thing thing, bool forced = false)
+ {
+ //bulky gear (power armor + minigun) so don't bother.
+ if (MassUtility.GearMass(pawn) / MassUtility.Capacity(pawn) >= 0.8f)
+ return false;
+
+ if (!GoodThingToHaul(thing, pawn) || !HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced))
+ return false;
+
+ StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(thing);
+ return StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out IntVec3 _);
+ }
+
+ //pick up stuff until you can't anymore,
+ //while you're up and about, pick up something and haul it
+ //before you go out, empty your pockets
+
+ public override Job JobOnThing(Pawn pawn, Thing thing, bool forced = false)
+ {
+ //bulky gear (power armor + minigun) so don't bother.
+ if (MassUtility.GearMass(pawn) / MassUtility.Capacity(pawn) >= 0.8f)
+ return null;
+
+ DesignationDef haulUrgentlyDesignation = DefDatabase.GetNamed("HaulUrgentlyDesignation", false);
+
+ //This WorkGiver gets hijacked by AllowTool and expects us to urgently haul corpses.
+ if (ModCompatibilityCheck.AllowToolIsActive && thing is Corpse
+ && pawn.Map.designationManager.DesignationOn(thing)?.def == haulUrgentlyDesignation && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced))
+ return HaulAIUtility.HaulToStorageJob(pawn, thing);
+
+ if (!GoodThingToHaul(thing, pawn) || !HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, thing, forced))
+ return null;
+
+ StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(thing);
+ if (StoreUtility.TryFindBestBetterStoreCellFor(thing, pawn, pawn.Map, currentPriority, pawn.Faction, out IntVec3 storeCell, true))
+ {
+ //since we've gone through all the effort of getting the loc, might as well use it.
+ //Don't multi-haul food to hoppers.
+ if (thing.def.IsNutritionGivingIngestible)
+ {
+ if (thing.def.ingestible.preferability == FoodPreferability.RawBad || thing.def.ingestible.preferability == FoodPreferability.RawTasty)
+ {
+ List thingList = storeCell.GetThingList(thing.Map);
+
+ foreach (Thing t in thingList)
+ if (t.def == ThingDefOf.Hopper)
+ return HaulAIUtility.HaulToStorageJob(pawn, thing);
+ }
+ }
+ }
+ else
+ {
+ JobFailReason.Is("NoEmptyPlaceLower".Translate());
+ return null;
+ }
+
+ //https://github.com/Mehni/PickUpAndHaul/pull/18
+ if (MassUtility.WillBeOverEncumberedAfterPickingUp(pawn, thing, 1))
+ return HaulAIUtility.HaulToStorageJob(pawn, thing);
+
+ //credit to Dingo
+ int capacityStoreCell = CapacityAt(thing, storeCell, pawn.Map);
+
+ if (capacityStoreCell == 0) return HaulAIUtility.HaulToStorageJob(pawn, thing);
+
+ Job job = new Job(PickUpAndHaulJobDefOf.HaulToInventory, null, storeCell); //Things will be in queues
+ Log.Message($"-------------------------------------------------------------------");
+ Log.Message($"------------------------------------------------------------------");//different size so the log doesn't count it 2x
+ Log.Message($"{pawn} job found to haul: {thing} to {storeCell}:{capacityStoreCell}, looking for more now");
+
+ //Find extra things than can be hauled to inventory, queue to reserve them
+ bool isUrgent = ModCompatibilityCheck.AllowToolIsActive && pawn.Map.designationManager.DesignationOn(thing)?.def == haulUrgentlyDesignation;
+
+ Func validatorExtra = (Thing t) =>
+ (!isUrgent || pawn.Map.designationManager.DesignationOn(t)?.def == haulUrgentlyDesignation) &&
+ GoodThingToHaul(t, pawn) && HaulAIUtility.PawnCanAutomaticallyHaulFast(pawn, t, false);//forced is false, may differ from first thing
+
+
+ //Find what fits in inventory, set nextThingLeftOverCount to be
+ int nextThingLeftOverCount = 0;
+ float encumberance = MassUtility.EncumbrancePercent(pawn);
+ job.targetQueueA = new List(); //more things
+ job.targetQueueB = new List(); //more storage; keep in mind the job doesn't use it, but reserve it so you don't over-haul
+ job.countQueue = new List();//thing counts
+
+
+ //TODO check CE along with encumberance
+ //float usedBulkByPct = 1f;
+ //float usedWeightByPct = 1f;
+
+ //try
+ //{
+ // ((Action)(() =>
+ // {
+ // if (ModCompatibilityCheck.CombatExtendedIsActive)
+ // {
+ // CombatExtended.CompInventory ceCompInventory = pawn.GetComp();
+ // usedWeightByPct = ceCompInventory.currentWeight / ceCompInventory.capacityWeight;
+ // usedBulkByPct = ceCompInventory.currentBulk / ceCompInventory.capacityBulk;
+ // }
+ // }))();
+ //}
+ //catch (TypeLoadException) { }
+
+ float distanceToHaul = (storeCell - thing.Position).LengthHorizontal * SEARCH_FOR_OTHERS_RANGE_FRACTION;
+ float distanceToSearchMore = Math.Max(12f, distanceToHaul);
+
+ List haulables = pawn.Map.listerHaulables.ThingsPotentiallyNeedingHauling()
+ .Where(validatorExtra).ToList();
+
+ Thing nextThing = thing;
+ Thing lastThing = thing;
+
+ Dictionary storeCellCapacity = new Dictionary
+ {
+ [storeCell] = new CellAllocation(nextThing, capacityStoreCell)
+ };
+ skipCells = new HashSet() { storeCell };
+
+ do
+ {
+ haulables.Remove(nextThing);
+ if (AllocateThingAtCell(storeCellCapacity, pawn, nextThing, job))
+ {
+ lastThing = nextThing;
+ encumberance += AddedEnumberance(pawn, nextThing);
+
+ if (encumberance > 1)// || usedBulkByPct >= 0.7f || usedWeightByPct >= 0.8f))//TODO: CE also
+ {
+ //can't CountToPickUpUntilOverEncumbered here, pawn doesn't actually hold these things yet
+ nextThingLeftOverCount = CountPastCapacity(pawn, nextThing, encumberance);
+ Log.Message($"Inventory allocated, will carry {nextThing}:{nextThingLeftOverCount}");
+ break;
+ }
+ }
+ }
+ while ((nextThing = GenClosest.ClosestThingReachable(lastThing.Position, thing.Map, ThingRequest.ForUndefined(),
+ PathEndMode.ClosestTouch, TraverseParms.For(pawn), distanceToSearchMore, null, haulables))
+ is Thing);
+
+ if (nextThing == null)
+ {
+ skipCells = null;
+ return job;
+ }
+
+ //Find what can be carried
+ //this doesn't actually get pickupandhauled, but will hold the reservation so others don't grab what this pawn can carry
+ haulables.RemoveAll(t => !t.CanStackWith(nextThing));
+
+ int carryCapacity = pawn.carryTracker.MaxStackSpaceEver(nextThing.def) - nextThingLeftOverCount;
+ if (carryCapacity == 0)
+ {
+ Log.Message("Can't carry more, nevermind!");
+ skipCells = null;
+ return job;
+ }
+ Log.Message($"Looking for more like {nextThing}");
+
+ while ((nextThing = GenClosest.ClosestThingReachable(nextThing.Position, thing.Map, ThingRequest.ForUndefined(),
+ PathEndMode.ClosestTouch, TraverseParms.For(pawn), 8f, null, haulables)) != null)
+ {
+ haulables.Remove(nextThing);
+ carryCapacity -= nextThing.stackCount;
+
+ if (AllocateThingAtCell(storeCellCapacity, pawn, nextThing, job))
+ break;
+
+ if (carryCapacity <= 0)
+ {
+ int lastCount = job.countQueue.Pop() + carryCapacity;
+ job.countQueue.Add(lastCount);
+ Log.Message($"Nevermind, last count is {lastCount}");
+ break;
+ }
+ }
+
+ skipCells = null;
+ return job;
+ }
+
+ public class CellAllocation
+ {
+ public Thing allocated;
+ public int capacity;
+
+ public CellAllocation(Thing a, int c)
+ {
+ allocated = a;
+ capacity = c;
+ }
+ }
+
+ public static int CapacityAt(Thing thing, IntVec3 storeCell, Map map)
+ {
+ int capacity;
+
+ if (HoldMultipleThings_Support.CapacityAt(thing, storeCell, map, out capacity))
+ {
+ Log.Message($"Found external capacity of {capacity}");
+ return capacity;
+ }
+
+ if (ExtendedStorage_Support.CapacityAt(thing, storeCell, map, out capacity))
+ {
+ return capacity;
+ }
+
+ capacity = thing.def.stackLimit;
+
+ Thing preExistingThing = map.thingGrid.ThingAt(storeCell, thing.def);
+ if (preExistingThing != null)
+ capacity = thing.def.stackLimit - preExistingThing.stackCount;
+
+ return capacity;
+ }
+
+ public static bool Stackable(Thing nextThing, KeyValuePair allocation)
+ => nextThing == allocation.Value.allocated
+ || allocation.Value.allocated.CanStackWith(nextThing)
+ || HoldMultipleThings_Support.StackableAt(nextThing, allocation.Key, nextThing.Map)
+ || ExtendedStorage_Support.StackableAt(nextThing.def, allocation.Key, nextThing.Map);
+
+ public static bool AllocateThingAtCell(Dictionary storeCellCapacity, Pawn pawn, Thing nextThing, Job job)
+ {
+ Map map = pawn.Map;
+ KeyValuePair allocation = storeCellCapacity.FirstOrDefault(kvp =>
+ kvp.Key.GetSlotGroup(map).parent.Accepts(nextThing) &&
+ Stackable(nextThing, kvp));
+ IntVec3 storeCell = allocation.Key;
+
+ //Can't stack with allocated cells, find a new cell:
+ if (storeCell == default(IntVec3))
+ {
+ StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(nextThing);
+ if (TryFindBestBetterStoreCellFor(nextThing, pawn, map, currentPriority, pawn.Faction, out IntVec3 nextStoreCell))
+ {
+ storeCell = nextStoreCell;
+ job.targetQueueB.Add(storeCell);
+
+ storeCellCapacity[storeCell] = new CellAllocation(nextThing, CapacityAt(nextThing, storeCell, map));
+
+ Log.Message($"New cell for unstackable {nextThing} = {nextStoreCell}");
+ }
+ else
+ {
+ Log.Message($"{nextThing} can't stack with allocated cells");
+
+ if (job.targetQueueA.NullOrEmpty())
+ job.targetQueueA.Add(nextThing);
+ return false;
+ }
+ }
+
+ job.targetQueueA.Add(nextThing);
+ int count = nextThing.stackCount;
+ storeCellCapacity[storeCell].capacity -= count;
+ Log.Message($"{pawn} allocating {nextThing}:{count}, now {storeCell}:{storeCellCapacity[storeCell].capacity}");
+
+ while (storeCellCapacity[storeCell].capacity <= 0)
+ {
+ int capacityOver = -storeCellCapacity[storeCell].capacity;
+ storeCellCapacity.Remove(storeCell);
+
+ Log.Message($"{pawn} overdone {storeCell} by {capacityOver}");
+
+ if (capacityOver == 0)
+ break; //don't find new cell, might not have more of this thing to haul
+
+ StoragePriority currentPriority = StoreUtility.CurrentStoragePriorityOf(nextThing);
+ if (TryFindBestBetterStoreCellFor(nextThing, pawn, map, currentPriority, pawn.Faction, out IntVec3 nextStoreCell))
+ {
+ storeCell = nextStoreCell;
+ job.targetQueueB.Add(storeCell);
+
+ int capacity = CapacityAt(nextThing, storeCell, map) - capacityOver;
+ storeCellCapacity[storeCell] = new CellAllocation(nextThing, capacity);
+
+ Log.Message($"New cell {storeCell}:{capacity}, allocated extra {capacityOver}");
+ }
+ else
+ {
+ count -= capacityOver;
+ job.countQueue.Add(count);
+ Log.Message($"Nowhere else to store, allocated {nextThing}:{count}");
+ return false;
+ }
+ }
+ job.countQueue.Add(count);
+ Log.Message($"{nextThing}:{count} allocated");
+ return true;
+ }
+
+ public static HashSet skipCells;
+ public static bool TryFindBestBetterStoreCellFor(Thing thing, Pawn carrier, Map map, StoragePriority currentPriority, Faction faction, out IntVec3 foundCell)
+ {
+ foreach (SlotGroup slotGroup in map.haulDestinationManager.AllGroupsListInPriorityOrder
+ .Where(s => s.Settings.Priority > currentPriority && s.parent.Accepts(thing)))
+ {
+ if (slotGroup.CellsList.Except(skipCells).FirstOrDefault(c => StoreUtility.IsGoodStoreCell(c, map, thing, carrier, faction)) is IntVec3 cell
+ && cell != default(IntVec3))
+ {
+ foundCell = cell;
+
+ skipCells.Add(cell);
+
+ return true;
+ }
+ }
+ foundCell = IntVec3.Invalid;
+ return false;
+ }
+
+ public static float AddedEnumberance(Pawn pawn, Thing thing)
+ => thing.stackCount * thing.GetStatValue(StatDefOf.Mass) / MassUtility.Capacity(pawn);
+
+ public static int CountPastCapacity(Pawn pawn, Thing thing, float encumberance)
+ => (int)Math.Ceiling((encumberance - 1) * MassUtility.Capacity(pawn) / thing.GetStatValue(StatDefOf.Mass));
+ }
+}