In this tutorial, you're going to learn how to add ManureSystem support to your vehicle mod.
In the example folder you can find basic examples of placeables that are set up for the Manure System.
To successfully execute the required steps in this tutorial you will need the following programs:
- Text editor (Notepad++, Visual Studio Code or any proper IDE ...)
- GIANTS Editor 9.3.0 or 3D software that supports the GIANTS Exporter (Maya, blender ...)
- Internet connection for downloading sources from GitHub
For vehicles you also need an extra script in order to let the ManureSystem
detect your mod.
You will need to get a copy of the latest ManureSystemRegistry.lua
file which can be found in
the GitHub repository.
How to download the ManureSystemRegistry.lua
file:
- Go to the
docs
folder located in the root directory. - Click on the
ManureSystemRegistry.lua
file. - A window will open with the script file.
- Click on the button called
Raw
next to theBlame
button and it will open the file in RAW format. - Right click and click on
save as
(or hit ctrl - s on your keyboard) and save the file to the preferred location in your mod.
REMEMBER: Rename the file extension to
.lua
and don't save it as .txt!
In order to start with this step you need to have completed the part What do I need?.
INFO: If you don't plan to add additional specializations beyond the ManureSystemRegistry and your mod uses one of the following vehicle types:
manureTrailer
,sprayer
,selfPropelledSprayer
or already has theManureBarrel
specialization, then you don't need to necessarily add the ManureSystemRegistry.lua because the ManureSystem inserts the necessary specifications by default
Make sure you have read the information quote above, if so you can skip this section!
Open the modDesc.xml
file located in your mod directory.
In order to load the specialization you will need to add the specializations entry to the modDesc.
<specializations>
<specialization name="manureSystemRegistry" className="ManureSystemRegistry" filename="ManureSystemRegistry.lua"/>
</specializations>
The filename must be the exact location of the ManureSystemRegistry.lua
file you downloaded earlier. In this case it's
loaded from the root directory of the mod.
If a similar entry already exists you can just add the specialization entry to that.
<specialization name="manureSystemRegistry" className="ManureSystemRegistry" filename="ManureSystemRegistry.lua"/>
Now we need to add the newly loaded specification to the vehicle type.
In the example below we parent from the vanilla vehicle type manureBarrel
for our convenience. This can also be
something different depending on the vehicle you're adapting.
NOTE: Don't blindly copy and paste the
parent
in this case as this won't suit all cases but only manureBarrels in our example.
Here we add the newly registered spec name manureSystemVehicle
.
<vehicleTypes>
<type name="myNewBarrel" parent="manureBarrel" filename="$dataS/scripts/vehicles/Vehicle.lua">
<specialization name="manureSystemRegistry"/>
</type>
</vehicleTypes>
Copy the new vehicle type name (In our case myNewBarrel
) and close the modDesc file.
Open your vehicle's XML file and look for the XML element type="" which can be found on the second line of the file.
Which looks similar to this:
<vehicle type="manureBarrel">
We're going to rename the type manureBarrel
to our newly added vehicle type name we copied earlier in step 2:
<vehicle type="myNewBarrel">
Note: if your vehicle uses vehicleTypeConfigurations you also need to change the types there!
Awesome, we added the ManureSystemRegistry
specialization to your mod!
In order to tell the ManureSystem
what specializations to add you need to add the following entry to your vehicle XML.
<manureSystem/>
We have 4 options/attributes we can set here:
- hasConnectors:
true/false
if the mod has ManureSystem connectors (e.g. couplings, docking funnels) - hasPumpMotor:
true/false
if the mod has a ManureSystem pump motor - hasFillArm:
true/false
if the mod has a ManureSystem fill arm (e.g. normal fill arm or docking arm) - hasFillArmReceiver:
true/false
if the mod allows ManureSystem fill arms to fill from it's fillVolume (e.g. containers)
In this example we're going to add connectors, the pump motor and a fillarm. In order to tell that to the ManureSystem
mod we do the following:
<manureSystem hasConnectors="true" hasPumpMotor="true" hasFillArm="true"/>
If your mod also needs support for fillarm receiver just simply add the hasFillArmReceiver="true"
attribute.
In order todo this step you need to make sure you configured the
hasPumpMotor
entry from the
chapter Determine what to add.
For the pump motor we have a couple of configuration possibilities.
- litersPerSecond:
250
[OPTIONAL - default:100
] the liters per second the pump can handle at max efficiency. - toReachMaxEfficiencyTime:
1000
[OPTIONAL - default:1000
] the time in ms the pump needs to reach the max throughput. (This time is used as a starting point and will be influenced based on the manure thickness or hose length) - isStandalone:
true/false
[OPTIONAL - default:false
] determines if the pump functions as a standalone pump (so a pump without capacity on it's own) - useStandalonePumpText:
true/false
[OPTIONAL - default:false
] determines if the vehicle should use the standalone pump text, which is different than the standard pump text (left/right instead of in/out)
You also have the options to use a custom sound file for the pump. An example entry for a standalone pump will be:
<manureSystemPumpMotor isStandalone="true" litersPerSecond="250" toReachMaxEfficiencyTime="1000">
<sounds>
<pump template="SLURRY_02">
<pitch indoor="0.85" outdoor="0.75"/>
</pump>
</sounds>
</manureSystemPumpMotor>
Here we tell that it's a standalone pump with the isStandalone
attribute and with a pump throughput of 250 liters per
second and that it takes 1 second to reach that with the litersPerSecond
and toReachMaxEfficiencyTime
attributes. In
the example above you can also see the <sounds>
entry where we use a different template for our pump sound.
An example entry for a normal tanker pump will be, without the is isStandalone
attribute:
<manureSystemPumpMotor litersPerSecond="195" toReachMaxEfficiencyTime="1050"/>
As simple as that!
TIP: Through the entire mod you have the option to create a node with the
createNode
attribute or the option to refer to an existing node with thenode
attribute.
This option, for creating nodes, comes with the following settings:
- createNode:
true/false
[OPTIONAL - default:false
] - When createNode is set to
true
:- linkNode:
0>
[OPTIONAL - default:0>
] it's defaulted to the rootNode of your object, but allows setting a custom linkNode for our node to create. - position:
0 0 0
[OPTIONAL - default:0 0 0
] the xyz translations of the node to create. - rotation:
0 0 0
[OPTIONAL - default:0 0 0
] the xyz rotations of the node to create.
- linkNode:
- When createNode is set to
false
:- node:
0>
[REQUIRED] the index of the node it should use for the fill arm.
- node:
In order todo this step you need to make sure you configured the
hasFillArm
entry from the
chapter Determine what to add.
For the fill arm we have to following configuration possibilities:
- type:
string
e.g.dock
[OPTIONAL - default:OPTICAL
] the type of fillarm, e.g. if you want to prepare a docking arm make sure to set the correct type. - fillYOffset:
float
e.g.-0.5
[OPTIONAL - default:0
] the offset for the fill arm on fillable sources (in order to reach places easier). - fillUnitIndex:
int
e.g.1
[OPTIONAL - default:1
] the fillUnitIndex of which it should fill. - needsDockingCollision:
true/false
[OPTIONAL - default:false
] if the fill arm supports docking and needs to required collision for that.
For setting the fillArm node you have the option to create a transform group manually or let the script handle it for you.
Check section setting up a node for more details.
An example entry for creating a node through the XML would be:
<manureSystemFillArm createNode="true" linkNode="armLinkNode" position="-0.888 0.7 3.065" rotation="0 -90 0"/>
In the example above we let the ManureSystem
create a fill arm node and link it to the given armLinkNode
and give it
a custom position and rotation with the position
and rotation
attributes.
You don't have to use this option and have to freedom to choose if you want to refer to an existing node you placed yourself in the i3d file.
Personally I prefer using the createNode setting which allows for i3d avoidance.
An example entry without the option for creating a node would be:
<manureSystemFillArm node="armNode"/>
In this case the armNode
will be the node to use for the fill arm, instead of the node we created with the createNode
option from above.
When you set the needsDockingCollision
the ManureSystem
will load a docking collision on your fillArm.
This is needed in order to allow vehicles with funnels to detect the fill arm.
This collision might not always be on the correct positions as it by defaults takes the same locations as the fill arm
node you defined earlier.
If you want to offset the position or rotation of this docking collision you have to add the collision entry.
This will look like this:
<manureSystemFillArm type="DOCK" node="armNode" needsDockingCollision="true">
<collision position="0 0.1 0" rotation="90 0 0"/>
</manureSystemFillArm>
In most cases it's not needed to set the position or rotation on the collision.
You can verify that your fill arm is setup correctly in F5 mode (for physics) with the msToggleDebug
and msToggleConnectorNodes
commands in the developer console.
This will highlight the collisions and visualize the raycast line (red line)
- For dock arms make sure the collision cube is visible at the end of the fillarm. (Not required for normal fillarms)
- For all fillarms (including dock arms) make sure the raycast line is pointing away from your fillarm node, as shown on the image, to get the best results.
In order todo this step you need to make sure you configured the
hasFillArmReceiver
entry from the
chapter Determine what to add.
If you want to configure your vehicle to be able to allow sucking from the fill volume you will need
the FillArmReceiver
option.
For the fill arm receiver we have to following configuration possibilities:
- fillVolumeIndex:
int
e.g.1
[REQUIRED] The fillVolume index of where filarms can suck from. - fillUnitIndex:
int
e.g.1
[OPTIONAL - default:1
] The fillUnit index of where filarms can suck from. - fillArmOffset:
float
e.g.0.1
[OPTIONAL - default:0
] The offset for fillarms to be inrange (this might be used to allow for reaching hard to reach places).
<manureSystemFillArmReceiver fillVolumeIndex="1"/>
If you want fillarms to suck from a different fillunit you can simply define that with:
<manureSystemFillArmReceiver fillVolumeIndex="1" fillUnitIndex="2"/>
In order todo this step you need to make sure you configured the
hasConnectors
entry from the
chapter Determine what to add.
This paragraph is still W.I.P.
Connectors are needed to tell for example hoses or fillarms where to connect to. Simply said it bridges functions together.
Currently, the mod supports 4 types of connectors:
COUPLING
(manure hose coupling)COUPLINGFERTILIZER
(fertilizer hose coupling)DOCK
(funnel)OPTICAL
(as the name already suggests non-functional, just optical)
In our first example we're going to look at adding a COUPLING
connector type to our vehicle, this example also works
for the COUPLINGFERTILIZER
type.
Open the vehicle XML and add the <manureSystemConnectors
tag as child of the vehicle
tag.
Our step will result into this:
<manureSystemConnectors>
..
</manureSystemConnectors>
Replace the .. (dots) with a connector entry. For our first connector entry we're going to use an existing reference transform group from the i3d file. For that we open the i3d file and copy the index of the desired node.
Now that we found our node and copied the index we have to add a connector entry to the <manureSystemConnectors
tag.
The result will look something like this:
<manureSystemConnectors>
<connector type="COUPLING" node="0>1|1|2|1"/>
</manureSystemConnectors>
This tells the ManureSystem
mod that the node on index 0>1|1|2|1
is a COUPLING for manure hoses.
For vehicles you can also use the identifier defined in the i3dMappings
section which is highly recommended!
We can also use the option to tell the ManureSystem
to create a node (as mentioned in other tutorials).
TIP: Through the entire mod you have the option to create a node with the
createNode
attribute or the option to refer to an existing node with thenode
attribute.
Check section setting up a node for more details.
This will look something like this:
<manureSystemConnectors>
<connector type="COUPLING" linkNode="0>0|3" createNode="true" position="3.7 0.5 0.85" rotation="0 90 0"/>
</manureSystemConnectors>
This will create a COUPLING node linked to the node on the index 0>0|3
with the given position and rotation.
TIP: in order to verify that the node is on the correct position I suggest you to look ingame and use the console command
msToggleDebug
this will highlight all the connector nodes used.
For every connector type you will the following options available:
- inRangeDistance
float
e.g.1.8
This determines the distance till the hose can be connected (handy for increasing attach/detach possibilities on hard to reach places) - isParkPlace:
true/false
This flags is used to determine if the connector is used as a parking place (for hoses or just connectors that should behave as a parking place).
As mentioned above with the flag isParkPlace
the connector will act as a parking place.
- length (in meters)
float
e.g.3
[OPTIONAL - default:5
] This determines for which hose the place parameters should take effect upon. - direction
string
e.g.left
[OPTIONAL - default:right
] This the hose placement direction. - startTransOffset
vector 3 string
e.g.1 0 0
[OPTIONAL - default:0 0 0
] This determines the start translation of the hose on park position. - startRotOffset
vector 3 string
e.g.0 50 0
[OPTIONAL - default:0 0 0
] This determines the start rotation (in degrees) of the hose on park position. - endTransOffset
vector 3 string
e.g.0 1 0
[OPTIONAL - default:0 0 0
] This determines the end translation of the hose on park position. - endRotOffset
vector 3 string
e.g.20 0 0
[OPTIONAL - default:0 0 0
] This determines the end rotation (in degrees) of the hose on park position.
With the deformer you can offset the hose curve with a tranform node.
The deformer node can be created like any other node with either the createNode
flag or reference to an existing node
with the node
attribute.
Check section setting up a node for more details.
TIP: Through the entire mod you have the option to create a node with the
createNode
attribute or the option to refer to an existing node with thenode
attribute.
Below an example setup with support for an 3 and 5 meter hose.
<connector type="COUPLING" node="0>15|0" isParkPlace="true">
<parkPlaces>
<parkPlace length="3" startTransOffset="0 0 0" startRotOffset="0 0 0" endTransOffset="0.2 -0.45 0" endRotOffset="-25 0 0">
<deformer linkNode="0>15|0" createNode="true" position="0.005 -0.026 1.633"/>
</parkPlace>
<parkPlace length="5" startTransOffset="0 0 0" startRotOffset="0 0 0" endTransOffset="0.5 -1 0" endRotOffset="-15 0 0">
<deformer linkNode="0>15|0" createNode="true" position="0.012 -0.078 1.856"/>
</parkPlace>
</parkPlaces>
</connector>
NOTE: When using shared sets the animation is already done, so there's no need to add entries for shared set connectors!
The connector types COUPLING
and COUPLINGFERTILIZER
have animation support for locking the hose and opening the
manure flow.
This is done over the well known vehicle animations.
For the sake of the tutorial I assume you know how to add vehicle animations.
For vehicle animations the connector supports two entries:
- lockAnimationName:
string
e.g.myAnimationName
this is the animation name of theanimation
entry in the xml - manureFlowAnimationName:
string
e.g.myAnimationName
this is the animation name of theanimation
entry in the xml
Locking animation is an animation that triggers when the hose connects to the connector. Manure flow is the an animation that triggers when the player interacts with the connector in order to open the manure flow.
For the example connector entry I added an animation entry to my vehicle for the locking animation.
This looks like this (don't blindly copy this):
<animations>
<animation name="lockCoupling">
<part node="handleBack" startTime="0" endTime="0.5" startRot="-145 0 0" endRot="-15 0 0"/>
<part node="lockBack" startTime="0" endTime="0.5" startRot="-31 -90 0" endRot="-15 -90 0"/>
<part node="lockPartBack" startTime="0" endTime="0.5" startRot="-7.5 0 0" endRot="-15 0 0"/>
</animation>
</animations>
Above we see an animation entry with the name lockCoupling
, we have to remember that name because in order to tell
the ManureSystem
to play that animation when the player attaches/detaches the hose.
In order todo that we're going to set the lockAnimationName
attribute on our connector.
This will result in the following entry:
<manureSystemConnectors>
<connector type="COUPLING" node="refBack" lockAnimationName="lockCoupling"/>
</manureSystemConnectors>
In the example above the animation with the name lockCoupling
will be played for the locking animation of the hose.
The same can be done with the manure flow, that will require you to add the additional manureFlowAnimationName
attribute on the connector.
Like:
<manureSystemConnectors>
<connector type="COUPLING" node="refBack" lockAnimationName="lockCoupling" manureFlowAnimationName="flowCoupling"/>
</manureSystemConnectors>
The flowCoupling
will be another animation entry like the lockCoupling
.
NOTE:
lockAnimationName
works with and without themanureFlowAnimationName
butmanureFlowAnimationName
requires thelockAnimationName
!
With shared sets you can load preconfigured (model and animation) connectors for your vehicle and placeables.
Connector set ids:
- 1 (couplings for manure tankers)
- 2 (couplings for manure tankers)
- 3 (couplings for sprayers)
- 4 (funnels for docking)
Also, here counts the option to create nodes. Check section setting up a node for more details.
Extra attributes:
- placeholderNode:
0>
[OPTIONAL] the index of the node that should be blended out once the shared set is loaded.
Options set 1:
- connector
CONNECTOR_1
- handle
HANDLE_OLD
HANDLE_NEW
HYDRAULIC
PNEUMATIC
- valve
8INCH_BRASS
8INCH_CASTIRON
10INCH_MZ_CASTIRON
10INCH_BP_CASTIRON
Options set 2:
- connector
CONNECTOR_1
- handle
HANDLE_NEW
- valve
8INCH_BRASS
Options set 3:
- connector
CONNECTOR_1
CONNECTOR_2
CONNECTOR_3
CONNECTOR_4
Options set 4:
- connector
FUNNEL_8INCH
FUNNEL_10INCH
Examples:
<connector type="COUPLING">
<sharedSet createNode="true" linkNode="my_link_node" placeholderNode="my_placeholder_node" id="1">
<connector type="CONNECTOR_1"/>
<valve type="8INCH_BRASS"/>
<handle type="HANDLE_OLD"/>
</sharedSet>
</connector>
<connector type="COUPLING">
<sharedSet createNode="true" linkNode="my_link_node" placeholderNode="my_placeholder_node" id="2">
<connector type="CONNECTOR_1"/>
<valve type="8INCH_BRASS"/>
<handle type="HANDLE_NEW"/>
</sharedSet>
</connector>
<connector type="COUPLINGFERTILIZER">
<sharedSet createNode="true" linkNode="my_link_node" placeholderNode="my_placeholder_node" id="3">
<connector type="CONNECTOR_3"/>
</sharedSet>
</connector>
<connector type="DOCK">
<sharedSet node="my_node" id="4">
<connector type="FUNNEL_10INCH" color="SHARED_BLACK1"/>
</sharedSet>
<trigger position="0 0 0" roation="0 0 0" linkNode="my_node"/>
</connector>
Optional connectors that are non-functional
<connector type="OPTICAL">
<sharedSet node="connector_10inch_optical_node" id="1">
<valve type="10INCH_MZ_CASTIRON"/>
<handle type="PNEUMATIC"/>
</sharedSet>
</connector>
For the DOCK
connector type you will the following options available:
The funnel is the visual funnel that you can dock your fillarm in, this is however an optional entry and can be ignored if the funnel should be static.
In the <funnel></funnel>
attribute:
- node:
0>
[REQUIRED] the index of the node it should use for the funnel. - deformationYOffset:
float
[OPTIONAL - default:0.5
] The funnel deformation offset. - deformationYMaxPush:
float
[OPTIONAL - default:0.1
] The funnel deformation max push.
The trigger is needed for fillarms to detect the dock location.
In the <trigger></trigger>
attribute:
- linkNode:
0>
[OPTIONAL - default:0>
] it's defaulted to the rootNode of your object, but allows setting a custom linkNode for our node to create. - position:
0 0 0
[OPTIONAL - default:0 0 0
] the xyz translations of the node to create. - rotation:
0 0 0
[OPTIONAL - default:0 0 0
] the xyz rotations of the node to create.
Example entry:
<connector type="DOCK" node="funnelTopTrigger" inRangeDistance="0.2">
<funnel node="funnelTopDeformer" deformationYOffset="0.35" deformatioYMaxPush="0.09"/>
</connector>
With shared sets you can load preconfigured connectors for your vehicle.
The Manure System also supplies two types of funnels as standard for the dock connector in the shared set id 4
. These
funnels are loaded as an object including animation, making your modding experience as simple as possible.
Funnel options:
FUNNEL_8INCH
FUNNEL_10INCH
<connector type="DOCK">
<sharedSet node="funnel_node" id="4">
<connector type="FUNNEL_10INCH" color="SHARED_BLACK1"/>
</sharedSet>
<trigger position="0 0.4 0" roation="0 0 0" linkNode="funnel_node"/>
</connector>
Next to that you can configure visibilities of the pipe and change the flange visibilities.
<connector type="DOCK">
<sharedSet node="funnel_node" id="4">
<connector type="FUNNEL_8INCH" color="SHARED_BLACK1">
<pipe>true</pipe>
<flangeRound>false</flangeRound>
<flangeQuad>true</flangeQuad>
</connector>
</sharedSet>
<trigger position="0 0.4 0" roation="0 0 0" linkNode="funnel_node"/>
</connector>
If you want to tell that the source of the dock should come from a connected vehicle/placeable than you have to reference the stationary connector id and mark the connector stationary.
- stationaryConnectorId
int
[OPTIONAL - default:nil
] e.g.1
This indicates the id of the connector to references to. - isStationary:
true/false
[OPTIONAL - default:false
] This flags if the dock is used as stationary.
<connector type="DOCK" isStationary="true" stationaryConnectorId="1">
<sharedSet node="funnel_node" id="4">
<connector type="FUNNEL_10INCH" color="SHARED_BLACK1"/>
</sharedSet>
<trigger position="0 0.4 0" roation="0 0 0" linkNode="funnel_node"/>
</connector>
The transfer hose (e.g. with the Zunhammer FANT mod) setup is like any other connectionHose target entry. The Manure System introduces two new hose types:
- TRANSFER_HOSE (the actual hose)
- TRANSFER_HOSE_CABLE_BUNDLE (bundle of hydraulic lines)
In order to prepare your tanker to receive the transfer hose you will have to add the following entries at the end of the connectionHoses tag.
<connectionHoses>
<target attacherJointIndices="1" type="TRANSFER_HOSE" node="INDEX TO NODE" straighteningFactor="2" socket="TRANSFER_HOSE"/>
<target attacherJointIndices="1" type="TRANSFER_HOSE_CABLE_BUNDLE" node="INDEX TO NODE" straighteningFactor="2" socket="TRANSFER_HOSE_CABLE_BUNDLE"/>
</connectionHoses>
Replace the 'INDEX TO NODE' with an actual node (named) index.
With the ManureSystem it's also possible to create a node on the connectionHose target entries. Check section setting up a node for more details.
This will result in something similar to the following:
<connectionHoses>
<target attacherJointIndices="1" type="TRANSFER_HOSE" createNode="true" linknode="0>" position="0 1 1" rotation="0 180 0" straighteningFactor="2" socket="TRANSFER_HOSE"/>
<target attacherJointIndices="1" type="TRANSFER_HOSE_CABLE_BUNDLE" createNode="true" linknode="0>" position="0 1 1" rotation="0 180 0" straighteningFactor="2" socket="TRANSFER_HOSE_CABLE_BUNDLE"/>
</connectionHoses>