Script v1_7_1_0
- AI
- Animals
- Collections
- Contracts
- Debug
- Economy
- Elements
- EnvironmentalScore
- Errors
- Events
- GUI
- Handtools
- Hud
- I3d
- Input
- Jobs
- Maps
- Materials
- Misc
- Objects
- Parameters
- Placeables
- Placement
- Player
- Shop
- Sounds
- Specialization
- Specializations
- AIConveyorBelt
- AIDrivable
- AIFieldWorker
- AIImplement
- AIJobVehicle
- AIVehicle
- AIVehicleObstacle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- AutoLoader
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BigBag
- BunkerSiloCompacter
- BunkerSiloInteractor
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- CropSensor
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- ExtendedAIVehicle
- ExtendedCombine
- ExtendedMotorized
- ExtendedMower
- ExtendedSowingMachine
- ExtendedSprayer
- ExtendedWearable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- HeadlandAnimation
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- InlineWrapper
- JigglingParts
- Leveler
- LicensePlates
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- ManureSensor
- MixerWagon
- Motorized
- Mountable
- Mower
- Mulcher
- MultipleItemPurchase
- Pallet
- Pickup
- Pipe
- PlaceableAI
- PlaceableAnimatedObjects
- PlaceableBeehive
- PlaceableBeehivePalletSpa...
- PlaceableBunkerSilo
- PlaceableBuyingStation
- PlaceableCartridgePlayer
- PlaceableChargingStation
- PlaceableClearAreas
- PlaceableColorable
- PlaceableDeletedNodes
- PlaceableDoghouse
- PlaceableDynamicallyLoade...
- PlaceableFarmhouse
- PlaceableFence
- PlaceableFoliageAreas
- PlaceableGreenhouse
- PlaceableHighPressureWash...
- PlaceableHotspots
- PlaceableHusbandry
- PlaceableHusbandryAnimals
- PlaceableHusbandryFeeding...
- PlaceableHusbandryFence
- PlaceableHusbandryFood
- PlaceableHusbandryLiquidM...
- PlaceableHusbandryMilk
- PlaceableHusbandryPallets
- PlaceableHusbandryStraw
- PlaceableHusbandryWater
- PlaceableIncomePerHour
- PlaceableIndoorAreas
- PlaceableInfoTrigger
- PlaceableLeveling
- PlaceableLights
- PlaceableManureHeap
- PlaceablePlacement
- PlaceableProductionPoint
- PlaceableSellingStation
- PlaceableSilo
- PlaceableSiloExtension
- PlaceableSolarPanels
- PlaceableTipOcclusionArea...
- PlaceableTrainSystem
- PlaceableTriggerMarkers
- PlaceableVine
- PlaceableWardrobe
- PlaceableWeatherStation
- PlaceableWeighingStation
- PlaceableWindTurbine
- PlaceableWorkshop
- Plow
- PlowPacker
- PowerConsumer
- PowerTakeOffs
- PrecisionFarmingStatistic
- PushHandTool
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- RTKStation
- SaltSpreader
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SoilSampler
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StonePicker
- StrawBlower
- StumpCutter
- SupportVehicle
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TestAreas
- TipOccluder
- Trailer
- TreePlanter
- TreeSaplingPallet
- TreeSaw
- TurnOnVehicle
- VariableWorkWidth
- VehicleSettings
- VineCutter
- VineDetector
- VinePrepruner
- Washable
- WaterTrailer
- Wearable
- Weeder
- WeedSpotSpray
- Wheels
- WindBending
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- StateMachine
- Statistics
- Tasks
- Triggers
- Utils
- Vehicles
Engine v1_7_1_0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- general
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- NoteNode
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- VoiceChat
- XML
Foundation Reference
ConnectionHoses
DescriptionSpecialization for connection hoses between vehicles and toolsFunctions
- addHoseTargetNodes
- addHoseToDelayedMountings
- connectCustomHoseNode
- connectCustomHosesToAttacherVehicle
- connectHose
- connectHosesToAttacherVehicle
- connectHoseToSkipNode
- disconnectCustomHoseNode
- disconnectHose
- getCenterPointAngle
- getCenterPointAngleRegulation
- getClonedSkipHoseNode
- getConnectionHoseConfigIndex
- getConnectionHosesByInputAttacherJoint
- getConnectionTarget
- getIsConnectionHoseUsed
- getIsConnectionTargetUsed
- getIsSkipNodeAvailable
- initSpecialization
- iterateConnectionTargets
- loadConnectionHosesFromXML
- loadCustomHosesFromXML
- loadExtraDependentParts
- loadHoseNode
- loadHoseSkipNode
- loadHoseTargetNode
- loadToolConnectorHoseNode
- onLoad
- onPostAttach
- onPostUpdate
- onPreDetach
- onPreLoad
- prerequisitesPresent
- registerConnectionHoseXMLPaths
- registerCustomHoseNodesXMLPaths
- registerEventListeners
- registerFunctions
- registerHoseNodesXMLPaths
- registerHoseTargetNodesXMLPaths
- registerOverwrittenFunctions
- retryHoseSkipNodeConnections
- updateAttachedConnectionHoses
- updateConnectionHose
- updateCustomHoseNode
- updateExtraDependentParts
- updateToolConnectionHose
addHoseTargetNodes
DescriptionDefinitionaddHoseTargetNodes()Code
639 | function ConnectionHoses:addHoseTargetNodes(xmlFile, key) |
640 | local spec = self.spec_connectionHoses |
641 | |
642 | local addedTarget = false |
643 | xmlFile:iterate(key, function(_, targetKey) |
644 | local entry = {} |
645 | if self:loadHoseTargetNode(xmlFile, targetKey, entry) then |
646 | table.insert(spec.targetNodes, entry) |
647 | entry.index = #spec.targetNodes |
648 | |
649 | if spec.targetNodesByType[entry.type] == nil then |
650 | spec.targetNodesByType[entry.type] = {} |
651 | end |
652 | |
653 | table.insert(spec.targetNodesByType[entry.type], entry) |
654 | addedTarget = true |
655 | end |
656 | end) |
657 | |
658 | -- return the index of the last added target |
659 | if addedTarget then |
660 | return #spec.targetNodes |
661 | end |
662 | end |
addHoseToDelayedMountings
DescriptionDefinitionaddHoseToDelayedMountings()Code
1351 | function ConnectionHoses:addHoseToDelayedMountings(sourceObject, sourceHose, targetObject, targetHose) |
1352 | local spec = self.spec_connectionHoses |
1353 | |
1354 | local toolConnectionHose = spec.targetNodeToToolConnection[targetHose.index] |
1355 | if toolConnectionHose ~= nil and (toolConnectionHose.delayedMounting == nil or sourceHose.typedIndex == toolConnectionHose.typedIndex) then |
1356 | local retry = toolConnectionHose.delayedMounting == nil |
1357 | toolConnectionHose.delayedMounting = {sourceObject=sourceObject, sourceHose=sourceHose, targetObject=targetObject, targetHose=targetHose} |
1358 | |
1359 | if retry then |
1360 | self.rootVehicle:retryHoseSkipNodeConnections(true, sourceObject) |
1361 | end |
1362 | end |
1363 | end |
connectCustomHoseNode
DescriptionDefinitionconnectCustomHoseNode()Code
1539 | function ConnectionHoses:connectCustomHoseNode(customHose, customTarget) |
1540 | self:updateCustomHoseNode(customHose, customTarget) |
1541 | |
1542 | customHose.isActive = true |
1543 | customTarget.isActive = true |
1544 | |
1545 | customHose.connectedTarget = customTarget |
1546 | customTarget.connectedHose = customHose |
1547 | |
1548 | ObjectChangeUtil.setObjectChanges(customHose.objectChanges, true) |
1549 | ObjectChangeUtil.setObjectChanges(customTarget.objectChanges, true) |
1550 | end |
connectCustomHosesToAttacherVehicle
DescriptionDefinitionconnectCustomHosesToAttacherVehicle()Code
1488 | function ConnectionHoses:connectCustomHosesToAttacherVehicle(attacherVehicle, inputJointDescIndex, jointDescIndex) |
1489 | local spec = self.spec_connectionHoses |
1490 | local customHoses = spec.customHosesByInputAttacher[inputJointDescIndex] |
1491 | if customHoses ~= nil then |
1492 | for i=1, #customHoses do |
1493 | local customHose = customHoses[i] |
1494 | if not customHose.isActive then |
1495 | if attacherVehicle.spec_connectionHoses ~= nil then |
1496 | local customTargets = attacherVehicle.spec_connectionHoses.customHoseTargetsByAttacher[jointDescIndex] |
1497 | if customTargets ~= nil then |
1498 | for j=1, #customTargets do |
1499 | local customTarget = customTargets[j] |
1500 | if not customTarget.isActive then |
1501 | if customHose.type == customTarget.type |
1502 | and customHose.specType == customTarget.specType then |
1503 | self:connectCustomHoseNode(customHose, customTarget) |
1504 | end |
1505 | end |
1506 | end |
1507 | end |
1508 | end |
1509 | end |
1510 | end |
1511 | end |
1512 | |
1513 | local customTargets = spec.customHoseTargetsByInputAttacher[inputJointDescIndex] |
1514 | if customTargets ~= nil then |
1515 | for i=1, #customTargets do |
1516 | local customTarget = customTargets[i] |
1517 | if not customTarget.isActive then |
1518 | if attacherVehicle.spec_connectionHoses ~= nil then |
1519 | customHoses = attacherVehicle.spec_connectionHoses.customHosesByAttacher[jointDescIndex] |
1520 | if customHoses ~= nil then |
1521 | for j=1, #customHoses do |
1522 | local customHose = customHoses[j] |
1523 | if not customHose.isActive then |
1524 | if customHose.type == customTarget.type |
1525 | and customHose.specType == customTarget.specType then |
1526 | self:connectCustomHoseNode(customHose, customTarget) |
1527 | end |
1528 | end |
1529 | end |
1530 | end |
1531 | end |
1532 | end |
1533 | end |
1534 | end |
1535 | end |
connectHose
DescriptionDefinitionconnectHose()Code
1110 | function ConnectionHoses:connectHose(sourceHose, targetObject, targetHose, updateToolConnections) |
1111 | local spec = self.spec_connectionHoses |
1112 | |
1113 | local doConnect = false |
1114 | if updateToolConnections ~= nil and not updateToolConnections then |
1115 | doConnect = true |
1116 | else |
1117 | if targetObject:updateToolConnectionHose(self, sourceHose, targetObject, targetHose, true) then |
1118 | doConnect = true |
1119 | else |
1120 | -- on tool connections we wait until both ends are connected to a tool and then we connect the hoses |
1121 | targetObject:addHoseToDelayedMountings(self, sourceHose, targetObject, targetHose) |
1122 | end |
1123 | end |
1124 | |
1125 | if doConnect then |
1126 | targetHose.connectedObject = self |
1127 | sourceHose.connectedObject = targetObject |
1128 | |
1129 | sourceHose.targetHose = targetHose |
1130 | |
1131 | local node, referenceNode |
1132 | if sourceHose.adapterName ~= nil then |
1133 | if sourceHose.adapterName ~= "NONE" then |
1134 | node, referenceNode = g_connectionHoseManager:getClonedAdapterNode(targetHose.type, sourceHose.adapterName, self.customEnvironment) |
1135 | end |
1136 | elseif targetHose.adapterName ~= "NONE" then |
1137 | node, referenceNode = g_connectionHoseManager:getClonedAdapterNode(targetHose.type, targetHose.adapterName, self.customEnvironment) |
1138 | end |
1139 | |
1140 | if node ~= nil then |
1141 | link(g_connectionHoseManager:getSocketTarget(targetHose.socket, targetHose.node), node) |
1142 | setTranslation(node, 0,0,0) |
1143 | setRotation(node, 0,0,0) |
1144 | targetObject:addAllSubWashableNodes(node) |
1145 | |
1146 | targetHose.adapter.node = node |
1147 | targetHose.adapter.refNode = referenceNode |
1148 | targetHose.adapter.isLinked = true |
1149 | end |
1150 | |
1151 | sourceHose.targetNode = targetHose.adapter.refNode |
1152 | |
1153 | setVisibility(sourceHose.visibilityNode, true) |
1154 | setShaderParameter(sourceHose.hoseNode, "cv0", 0, 0, -sourceHose.startStraightening, 1, false) |
1155 | sourceHose.endStraightening = sourceHose.endStraighteningBase * targetHose.straighteningFactor |
1156 | sourceHose.endStraighteningDirection = targetHose.straighteningDirection or sourceHose.endStraighteningDirectionBase |
1157 | |
1158 | ObjectChangeUtil.setObjectChanges(targetHose.objectChanges, true) |
1159 | ObjectChangeUtil.setObjectChanges(sourceHose.objectChanges, true) |
1160 | |
1161 | g_connectionHoseManager:openSocket(sourceHose.socket) |
1162 | g_connectionHoseManager:openSocket(targetHose.socket) |
1163 | |
1164 | self:updateConnectionHose(sourceHose, 0) |
1165 | |
1166 | table.insert(spec.updateableHoses, sourceHose) |
1167 | return true |
1168 | end |
1169 | |
1170 | return false |
1171 | end |
connectHosesToAttacherVehicle
DescriptionDefinitionconnectHosesToAttacherVehicle()Code
1441 | function ConnectionHoses:connectHosesToAttacherVehicle(attacherVehicle, inputJointDescIndex, jointDescIndex, updateToolConnections, excludeVehicle) |
1442 | if attacherVehicle.getConnectionTarget ~= nil then |
1443 | local hoses = self:getConnectionHosesByInputAttacherJoint(inputJointDescIndex) |
1444 | for _, hose in ipairs(hoses) do |
1445 | attacherVehicle:iterateConnectionTargets(function(target, isSkipNode) |
1446 | if not self:getIsConnectionHoseUsed(hose) then |
1447 | if not isSkipNode then |
1448 | if self:connectHose(hose, attacherVehicle, target, updateToolConnections) then |
1449 | return false |
1450 | end |
1451 | else |
1452 | if self:connectHoseToSkipNode(hose, attacherVehicle, target) then |
1453 | return false |
1454 | end |
1455 | end |
1456 | |
1457 | |
1458 | return true |
1459 | end |
1460 | |
1461 | return false |
1462 | end, jointDescIndex, hose.type, hose.specType) |
1463 | end |
1464 | |
1465 | --try to connect the hoses of attached implements, maybe the connection is now valid since we got another skip node |
1466 | self:retryHoseSkipNodeConnections(updateToolConnections, excludeVehicle) |
1467 | end |
1468 | end |
connectHoseToSkipNode
DescriptionDefinitionconnectHoseToSkipNode()Code
1367 | function ConnectionHoses:connectHoseToSkipNode(sourceHose, targetObject, skipNode, childHose, childVehicle) |
1368 | local spec = self.spec_connectionHoses |
1369 | |
1370 | skipNode.connectedObject = self |
1371 | sourceHose.connectedObject = targetObject |
1372 | |
1373 | sourceHose.targetHose = skipNode |
1374 | sourceHose.targetNode = skipNode.node |
1375 | |
1376 | setVisibility(sourceHose.visibilityNode, true) |
1377 | setShaderParameter(sourceHose.hoseNode, "cv0", 0, 0, -sourceHose.startStraightening, 1, false) |
1378 | |
1379 | ObjectChangeUtil.setObjectChanges(sourceHose.objectChanges, true) |
1380 | |
1381 | self:addAllSubWashableNodes(sourceHose.hoseNode) |
1382 | |
1383 | sourceHose.childVehicle = childVehicle |
1384 | sourceHose.childHose = childHose |
1385 | |
1386 | if self.getAttacherVehicle ~= nil then |
1387 | local attacherVehicle1 = self:getAttacherVehicle() |
1388 | if attacherVehicle1.getAttacherVehicle ~= nil then |
1389 | local attacherVehicle2 = attacherVehicle1:getAttacherVehicle() |
1390 | if attacherVehicle2 ~= nil then |
1391 | |
1392 | local attacherJointIndex = attacherVehicle2:getAttacherJointIndexFromObject(attacherVehicle1) |
1393 | local implement = attacherVehicle2:getImplementFromAttacherJointIndex(attacherJointIndex) |
1394 | |
1395 | if implement.inputJointDescIndex == skipNode.inputAttacherJointIndex then |
1396 | local firstValidTarget, isSkipNode = attacherVehicle2:getConnectionTarget(attacherJointIndex, skipNode.type, skipNode.specType) |
1397 | if firstValidTarget ~= nil then |
1398 | local hose = attacherVehicle1:getClonedSkipHoseNode(sourceHose, skipNode) |
1399 | if not isSkipNode then |
1400 | attacherVehicle1:connectHose(hose, attacherVehicle2, firstValidTarget) |
1401 | else |
1402 | attacherVehicle1:connectHoseToSkipNode(hose, attacherVehicle2, firstValidTarget, sourceHose, attacherVehicle1) |
1403 | end |
1404 | |
1405 | if skipNode.parentHose ~= nil then |
1406 | skipNode.parentVehicle:removeWashableNode(skipNode.parentHose.hoseNode) |
1407 | delete(skipNode.parentHose.hoseNode) |
1408 | table.removeElement(spec.updateableHoses, skipNode.parentHose.childHose) |
1409 | end |
1410 | skipNode.parentVehicle = attacherVehicle1 |
1411 | skipNode.parentHose = hose |
1412 | |
1413 | sourceHose.parentVehicle = attacherVehicle1 |
1414 | sourceHose.parentHose = hose |
1415 | |
1416 | hose.childVehicle = self |
1417 | hose.childHose = sourceHose |
1418 | |
1419 | attacherVehicle1:addAllSubWashableNodes(hose.hoseNode) |
1420 | else |
1421 | --same hose is still active, just update the relations |
1422 | if skipNode.parentHose ~= nil then |
1423 | sourceHose.parentVehicle = skipNode.parentVehicle |
1424 | sourceHose.parentHose = skipNode.parentHose |
1425 | |
1426 | sourceHose.parentHose.childVehicle = self |
1427 | sourceHose.parentHose.childHose = sourceHose |
1428 | end |
1429 | end |
1430 | end |
1431 | end |
1432 | end |
1433 | end |
1434 | |
1435 | table.insert(spec.updateableHoses, sourceHose) |
1436 | return true |
1437 | end |
disconnectCustomHoseNode
DescriptionDefinitiondisconnectCustomHoseNode()Code
1561 | function ConnectionHoses:disconnectCustomHoseNode(customHose, customTarget) |
1562 | setTranslation(customHose.node, unpack(customHose.startTranslation)) |
1563 | setRotation(customHose.node, unpack(customHose.startRotation)) |
1564 | |
1565 | customHose.isActive = false |
1566 | customTarget.isActive = false |
1567 | |
1568 | customHose.connectedTarget = nil |
1569 | customTarget.connectedHose = nil |
1570 | |
1571 | ObjectChangeUtil.setObjectChanges(customHose.objectChanges, false) |
1572 | ObjectChangeUtil.setObjectChanges(customTarget.objectChanges, false) |
1573 | end |
disconnectHose
DescriptionDefinitiondisconnectHose()Code
1175 | function ConnectionHoses:disconnectHose(hose) |
1176 | local spec = self.spec_connectionHoses |
1177 | local target = hose.targetHose |
1178 | if target ~= nil then |
1179 | hose.connectedObject:updateToolConnectionHose(self, hose, hose.connectedObject, target, false) |
1180 | |
1181 | local hoseHasSkipNodeTarget = target.isSkipNode ~= nil and target.isSkipNode |
1182 | local hoseIsFromSkipNodeTarget = hose.isClonedSkipNodeHose ~= nil and hose.isClonedSkipNodeHose |
1183 | if hoseHasSkipNodeTarget or hoseIsFromSkipNodeTarget then |
1184 | --remove all skip node connections recursively in both directions |
1185 | if hose.parentVehicle ~= nil and hose.parentHose ~= nil then |
1186 | hose.parentHose.childVehicle = nil |
1187 | hose.parentHose.childHose = nil |
1188 | hose.parentVehicle:disconnectHose(hose.parentHose) |
1189 | end |
1190 | |
1191 | if hose.childVehicle ~= nil and hose.childHose ~= nil then |
1192 | hose.childHose.parentVehicle = nil |
1193 | hose.childHose.parentHose = nil |
1194 | hose.childVehicle:disconnectHose(hose.childHose) |
1195 | end |
1196 | |
1197 | target.parentHose = nil |
1198 | end |
1199 | |
1200 | if target.adapter ~= nil and target.adapter.isLinked ~= nil and target.adapter.isLinked then |
1201 | hose.connectedObject:removeAllSubWashableNodes(target.adapter.node) |
1202 | delete(target.adapter.node) |
1203 | |
1204 | target.adapter.node = target.node |
1205 | target.adapter.refNode = target.node |
1206 | target.adapter.isLinked = false |
1207 | end |
1208 | |
1209 | setVisibility(hose.visibilityNode, false) |
1210 | ObjectChangeUtil.setObjectChanges(target.objectChanges, false) |
1211 | ObjectChangeUtil.setObjectChanges(hose.objectChanges, false) |
1212 | |
1213 | g_connectionHoseManager:closeSocket(hose.socket) |
1214 | g_connectionHoseManager:closeSocket(target.socket) |
1215 | |
1216 | target.connectedObject = nil |
1217 | hose.connectedObject = nil |
1218 | hose.targetHose = nil |
1219 | |
1220 | table.removeElement(spec.updateableHoses, hose) |
1221 | end |
1222 | end |
getCenterPointAngle
DescriptionDefinitiongetCenterPointAngle()Code
431 | function ConnectionHoses:getCenterPointAngle(node, cX, cY, cZ, eX, eY, eZ, useWorldSpace) |
432 | local lengthStartToCenter = MathUtil.vector3Length(cX, cY, cZ) |
433 | local lengthCenterToEnd = math.abs(MathUtil.vector3Length(cX-eX, cY-eY, cZ-eZ)) |
434 | |
435 | local _, sY, _ = getWorldTranslation(node) |
436 | if useWorldSpace then |
437 | _, cY, _ = localToWorld(node, cX, cY, cZ) |
438 | _, eY, _ = localToWorld(node, eX, eY, eZ) |
439 | else |
440 | sY = 0 |
441 | end |
442 | |
443 | local lengthStartToCenter2 = sY-cY |
444 | local lengthCenterToEnd2 = eY-cY |
445 | |
446 | local angle1 = math.acos(lengthStartToCenter2/lengthStartToCenter) |
447 | local angle2 = math.acos(lengthCenterToEnd2/lengthCenterToEnd) |
448 | |
449 | return angle1, angle2 |
450 | end |
getCenterPointAngleRegulation
DescriptionDefinitiongetCenterPointAngleRegulation()Code
454 | function ConnectionHoses:getCenterPointAngleRegulation(node, cX, cY, cZ, eX, eY, eZ, angle1, angle2, targetAngle, useWorldSpace) |
455 | local sX, sY, sZ = getWorldTranslation(node) |
456 | if useWorldSpace then |
457 | local _ |
458 | cX, _, cZ = localToWorld(node, cX, cY, cZ) |
459 | eX, _, eZ = localToWorld(node, eX, eY, eZ) |
460 | else |
461 | sX, sY, sZ = 0, 0, 0 |
462 | end |
463 | |
464 | local startCenterLength = MathUtil.vector2Length(sX-cX, sZ-cZ) |
465 | local centerEndLength = MathUtil.vector2Length(eX-cX, eZ-cZ) |
466 | |
467 | local pct = angle1/(angle1+angle2) |
468 | local alpha = math.pi * 0.5 - (pct * targetAngle) |
469 | |
470 | local newY1 = math.tan(alpha) * startCenterLength |
471 | local newY2 = math.tan(alpha) * centerEndLength |
472 | |
473 | local newY = (newY1 + newY2) / 2 |
474 | |
475 | if useWorldSpace then |
476 | return worldToLocal(node, cX, sY-newY, cZ) |
477 | else |
478 | return cX, sY-newY, cZ |
479 | end |
480 | end |
getClonedSkipHoseNode
DescriptionDefinitiongetClonedSkipHoseNode()Code
924 | function ConnectionHoses:getClonedSkipHoseNode(sourceHose, skipNode) |
925 | local clonedHose = {} |
926 | |
927 | clonedHose.isClonedSkipNodeHose = true |
928 | |
929 | clonedHose.type = sourceHose.type |
930 | clonedHose.specType = sourceHose.specType |
931 | clonedHose.hoseType = sourceHose.hoseType |
932 | clonedHose.node = skipNode.node |
933 | |
934 | clonedHose.component = self:getParentComponent(skipNode.node) |
935 | clonedHose.lastVelY = 0 |
936 | clonedHose.lastVelZ = 0 |
937 | clonedHose.dampingRange = 0.05 |
938 | clonedHose.dampingFactor = 50 |
939 | |
940 | clonedHose.minDeltaYComponent = self:getParentComponent(skipNode.node) |
941 | clonedHose.minDeltaY = math.huge |
942 | |
943 | clonedHose.length = skipNode.length or sourceHose.length |
944 | clonedHose.diameter = sourceHose.diameter |
945 | clonedHose.isTwoPointHose = skipNode.isTwoPointHose |
946 | |
947 | clonedHose.color = sourceHose.color |
948 | |
949 | local hose, startStraightening, endStraightening, minCenterPointAngle = g_connectionHoseManager:getClonedHoseNode(clonedHose.type, clonedHose.hoseType, clonedHose.length, clonedHose.diameter, clonedHose.color, self.customEnvironment) |
950 | |
951 | if hose ~= nil then |
952 | link(clonedHose.node, hose) |
953 | setTranslation(hose, 0, 0, 0) |
954 | setRotation(hose, 0, 0, 0) |
955 | |
956 | clonedHose.hoseNode = hose |
957 | clonedHose.visibilityNode = hose |
958 | clonedHose.startStraightening = startStraightening |
959 | clonedHose.endStraightening = endStraightening |
960 | clonedHose.endStraighteningBase = endStraightening |
961 | clonedHose.endStraighteningDirectionBase = {0, 0, 1} |
962 | clonedHose.endStraighteningDirection = clonedHose.endStraighteningDirectionBase |
963 | clonedHose.minCenterPointAngle = minCenterPointAngle |
964 | |
965 | setVisibility(clonedHose.visibilityNode, false) |
966 | else |
967 | Logging.xmlWarning(self.xmlFile, "Unable to find connection hose with length '%.2f' and diameter '%.2f' in '%s'", clonedHose.length, clonedHose.diameter, "skipHoseClone") |
968 | return false |
969 | end |
970 | |
971 | clonedHose.objectChanges = {} |
972 | |
973 | return clonedHose |
974 | end |
getConnectionHoseConfigIndex
DescriptionDefinitiongetConnectionHoseConfigIndex()Code
272 | function ConnectionHoses:getConnectionHoseConfigIndex() |
273 | return 1 |
274 | end |
getConnectionHosesByInputAttacherJoint
DescriptionDefinitiongetConnectionHosesByInputAttacherJoint()Code
1098 | function ConnectionHoses:getConnectionHosesByInputAttacherJoint(inputJointDescIndex) |
1099 | local spec = self.spec_connectionHoses |
1100 | |
1101 | if spec.hoseNodesByInputAttacher[inputJointDescIndex] ~= nil then |
1102 | return spec.hoseNodesByInputAttacher[inputJointDescIndex] |
1103 | end |
1104 | |
1105 | return {} |
1106 | end |
getConnectionTarget
DescriptionDefinitiongetConnectionTarget()Code
978 | function ConnectionHoses:getConnectionTarget(attacherJointIndex, type, specType, excludeToolConnections) |
979 | local spec = self.spec_connectionHoses |
980 | if #spec.targetNodes == 0 and #spec.hoseSkipNodes == 0 then |
981 | return nil |
982 | end |
983 | |
984 | local nodes = spec.targetNodesByType[type] |
985 | if nodes ~= nil then |
986 | for _, node in ipairs(nodes) do |
987 | if node.attacherJointIndices[attacherJointIndex] ~= nil then |
988 | if node.specType == specType then |
989 | if not self:getIsConnectionTargetUsed(node) then |
990 | local toolConnectionHose = spec.targetNodeToToolConnection[node.index] |
991 | if toolConnectionHose ~= nil and excludeToolConnections ~= nil and excludeToolConnections then |
992 | if toolConnectionHose.delayedMounting == nil then |
993 | return nil |
994 | end |
995 | end |
996 | |
997 | return node, false |
998 | end |
999 | end |
1000 | end |
1001 | end |
1002 | end |
1003 | |
1004 | nodes = spec.hoseSkipNodeByType[type] |
1005 | if nodes ~= nil then |
1006 | for _, node in ipairs(nodes) do |
1007 | if node.specType == specType then |
1008 | if self:getIsSkipNodeAvailable(node) then |
1009 | return node, true |
1010 | end |
1011 | end |
1012 | end |
1013 | end |
1014 | |
1015 | return nil |
1016 | end |
getIsConnectionHoseUsed
DescriptionDefinitiongetIsConnectionHoseUsed()Code
1072 | function ConnectionHoses:getIsConnectionHoseUsed(desc) |
1073 | return desc.connectedObject ~= nil |
1074 | end |
getIsConnectionTargetUsed
DescriptionDefinitiongetIsConnectionTargetUsed()Code
1066 | function ConnectionHoses:getIsConnectionTargetUsed(desc) |
1067 | return desc.connectedObject ~= nil |
1068 | end |
getIsSkipNodeAvailable
DescriptionDefinitiongetIsSkipNodeAvailable()Code
1078 | function ConnectionHoses:getIsSkipNodeAvailable(skipNode) |
1079 | if self.getAttacherVehicle == nil then |
1080 | return false |
1081 | end |
1082 | |
1083 | local attacherVehicle = self:getAttacherVehicle() |
1084 | if attacherVehicle ~= nil then |
1085 | local attacherJointIndex = attacherVehicle:getAttacherJointIndexFromObject(self) |
1086 | local implement = attacherVehicle:getImplementFromAttacherJointIndex(attacherJointIndex) |
1087 | |
1088 | if implement.inputJointDescIndex == skipNode.inputAttacherJointIndex then |
1089 | return attacherVehicle:getConnectionTarget(attacherJointIndex, skipNode.type, skipNode.specType, true) ~= nil and skipNode.parentHose == nil |
1090 | end |
1091 | end |
1092 | |
1093 | return false |
1094 | end |
initSpecialization
DescriptionDefinitioninitSpecialization()Code
23 | function ConnectionHoses.initSpecialization() |
24 | local schema = Vehicle.xmlSchema |
25 | schema:setXMLSpecializationType("ConnectionHoses") |
26 | |
27 | schema:register(XMLValueType.FLOAT, "vehicle.connectionHoses#maxUpdateDistance", "Max. distance to vehicle root to update connection hoses", ConnectionHoses.DEFAULT_MAX_UPDATE_DISTANCE) |
28 | |
29 | ConnectionHoses.registerConnectionHoseXMLPaths(schema, "vehicle.connectionHoses") |
30 | ConnectionHoses.registerConnectionHoseXMLPaths(schema, "vehicle.connectionHoses.connectionHoseConfigurations.connectionHoseConfiguration(?)") |
31 | |
32 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.connectionHoses.connectionHoseConfigurations.connectionHoseConfiguration(?)") |
33 | |
34 | schema:register(XMLValueType.VECTOR_N, Cylindered.MOVING_TOOL_XML_KEY .. ".connectionHoses#customHoseIndices", "Custom hoses to update") |
35 | schema:register(XMLValueType.VECTOR_N, Cylindered.MOVING_TOOL_XML_KEY .. ".connectionHoses#customTargetIndices", "Custom hose targets to update") |
36 | schema:register(XMLValueType.VECTOR_N, Cylindered.MOVING_PART_XML_KEY .. ".connectionHoses#customHoseIndices", "Custom hoses to update") |
37 | schema:register(XMLValueType.VECTOR_N, Cylindered.MOVING_PART_XML_KEY .. ".connectionHoses#customTargetIndices", "Custom hose targets to update") |
38 | |
39 | schema:setXMLSpecializationType() |
40 | end |
iterateConnectionTargets
DescriptionDefinitioniterateConnectionTargets()Code
1020 | function ConnectionHoses:iterateConnectionTargets(func, attacherJointIndex, type, specType, excludeToolConnections) |
1021 | local spec = self.spec_connectionHoses |
1022 | if #spec.targetNodes == 0 and #spec.hoseSkipNodes == 0 then |
1023 | return nil |
1024 | end |
1025 | |
1026 | local nodes = spec.targetNodesByType[type] |
1027 | if nodes ~= nil then |
1028 | for _, node in ipairs(nodes) do |
1029 | if node.attacherJointIndices[attacherJointIndex] ~= nil then |
1030 | if node.specType == specType then |
1031 | if not self:getIsConnectionTargetUsed(node) then |
1032 | local toolConnectionHose = spec.targetNodeToToolConnection[node.index] |
1033 | if toolConnectionHose ~= nil and excludeToolConnections ~= nil and excludeToolConnections then |
1034 | if toolConnectionHose.delayedMounting == nil then |
1035 | return nil |
1036 | end |
1037 | end |
1038 | |
1039 | if not func(node, false) then |
1040 | break |
1041 | end |
1042 | end |
1043 | end |
1044 | end |
1045 | end |
1046 | end |
1047 | |
1048 | nodes = spec.hoseSkipNodeByType[type] |
1049 | if nodes ~= nil then |
1050 | for _, node in ipairs(nodes) do |
1051 | if node.specType == specType then |
1052 | if self:getIsSkipNodeAvailable(node) then |
1053 | if not func(node, true) then |
1054 | break |
1055 | end |
1056 | end |
1057 | end |
1058 | end |
1059 | end |
1060 | |
1061 | return nil |
1062 | end |
loadConnectionHosesFromXML
DescriptionDefinitionloadConnectionHosesFromXML()Code
484 | function ConnectionHoses:loadConnectionHosesFromXML(xmlFile, key) |
485 | local spec = self.spec_connectionHoses |
486 | |
487 | xmlFile:iterate(key .. ".skipNode", function(_, hoseKey) |
488 | local entry = {} |
489 | if self:loadHoseSkipNode(xmlFile, hoseKey, entry) then |
490 | table.insert(spec.hoseSkipNodes, entry) |
491 | |
492 | if spec.hoseSkipNodeByType[entry.type] == nil then |
493 | spec.hoseSkipNodeByType[entry.type] = {} |
494 | end |
495 | |
496 | table.insert(spec.hoseSkipNodeByType[entry.type], entry) |
497 | end |
498 | end) |
499 | |
500 | self:addHoseTargetNodes(xmlFile, key .. ".target") |
501 | |
502 | xmlFile:iterate(key .. ".toolConnectorHose", function(_, hoseKey) |
503 | local entry = {} |
504 | if self:loadToolConnectorHoseNode(xmlFile, hoseKey, entry) then |
505 | table.insert(spec.toolConnectorHoses, entry) |
506 | |
507 | spec.targetNodeToToolConnection[entry.startTargetNodeIndex] = entry |
508 | spec.targetNodeToToolConnection[entry.endTargetNodeIndex] = entry |
509 | end |
510 | end) |
511 | |
512 | xmlFile:iterate(key .. ".hose", function(_, hoseKey) |
513 | local entry = {} |
514 | if self:loadHoseNode(xmlFile, hoseKey, entry, true) then |
515 | table.insert(spec.hoseNodes, entry) |
516 | entry.index = #spec.hoseNodes |
517 | |
518 | for _, index in pairs(entry.inputAttacherJointIndices) do |
519 | if spec.hoseNodesByInputAttacher[index] == nil then |
520 | spec.hoseNodesByInputAttacher[index] = {} |
521 | end |
522 | |
523 | table.insert(spec.hoseNodesByInputAttacher[index], entry) |
524 | end |
525 | end |
526 | end) |
527 | |
528 | xmlFile:iterate(key .. ".localHose", function(_, hoseKey) |
529 | local hose = {} |
530 | if self:loadHoseNode(xmlFile, hoseKey..".hose", hose, false) then |
531 | |
532 | local target = {} |
533 | if self:loadHoseTargetNode(xmlFile, hoseKey..".target", target) then |
534 | table.insert(spec.localHoseNodes, {hose=hose, target=target}) |
535 | end |
536 | end |
537 | end) |
538 | |
539 | self:loadCustomHosesFromXML(spec.customHoses, spec.customHosesByAttacher, spec.customHosesByInputAttacher, xmlFile, key .. ".customHose") |
540 | |
541 | self:loadCustomHosesFromXML(spec.customHoseTargets, spec.customHoseTargetsByAttacher, spec.customHoseTargetsByInputAttacher, xmlFile, key .. ".customTarget") |
542 | end |
loadCustomHosesFromXML
DescriptionDefinitionloadCustomHosesFromXML()Code
666 | function ConnectionHoses:loadCustomHosesFromXML(targetTable, attacherJointMapping, inputAttacherJointMapping, xmlFile, key) |
667 | xmlFile:iterate(key, function(_, customKey) |
668 | local entry = {} |
669 | entry.node = xmlFile:getValue(customKey .. "#node", nil, self.components, self.i3dMappings) |
670 | if entry.node ~= nil then |
671 | entry.type = xmlFile:getValue(customKey .. "#type") |
672 | if entry.type ~= nil then |
673 | entry.type = entry.type:upper() |
674 | |
675 | local attacherJointIndices = xmlFile:getValue(customKey .. "#attacherJointIndices", nil, true) |
676 | entry.attacherJointIndices = {} |
677 | for _, v in ipairs(attacherJointIndices) do |
678 | entry.attacherJointIndices[v] = v |
679 | |
680 | if attacherJointMapping[v] == nil then |
681 | attacherJointMapping[v] = {} |
682 | end |
683 | |
684 | table.insert(attacherJointMapping[v], entry) |
685 | end |
686 | |
687 | local inputAttacherJointIndices = xmlFile:getValue(customKey .. "#inputAttacherJointIndices", nil, true) |
688 | entry.inputAttacherJointIndices = {} |
689 | for _, v in ipairs(inputAttacherJointIndices) do |
690 | entry.inputAttacherJointIndices[v] = v |
691 | |
692 | if inputAttacherJointMapping[v] == nil then |
693 | inputAttacherJointMapping[v] = {} |
694 | end |
695 | |
696 | table.insert(inputAttacherJointMapping[v], entry) |
697 | end |
698 | |
699 | entry.objectChanges = {} |
700 | ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, customKey, entry.objectChanges, self.components, self) |
701 | ObjectChangeUtil.setObjectChanges(entry.objectChanges, false) |
702 | |
703 | entry.startTranslation = {getTranslation(entry.node)} |
704 | entry.startRotation = {getRotation(entry.node)} |
705 | |
706 | entry.isActive = false |
707 | |
708 | table.insert(targetTable, entry) |
709 | else |
710 | Logging.xmlWarning(xmlFile, "Missing type for custom hose '%s'", customKey) |
711 | end |
712 | else |
713 | Logging.xmlWarning(xmlFile, "Missing node for custom hose '%s'", customKey) |
714 | end |
715 | end) |
716 | end |
loadExtraDependentParts
DescriptionDefinitionloadExtraDependentParts()Code
1577 | function ConnectionHoses:loadExtraDependentParts(superFunc, xmlFile, baseName, entry) |
1578 | if not superFunc(self, xmlFile, baseName, entry) then |
1579 | return false |
1580 | end |
1581 | |
1582 | local customHoseIndices = xmlFile:getValue(baseName.. ".connectionHoses#customHoseIndices", nil, true) |
1583 | if #customHoseIndices > 0 then |
1584 | entry.customHoseIndices = customHoseIndices |
1585 | end |
1586 | |
1587 | local customTargetIndices = xmlFile:getValue(baseName.. ".connectionHoses#customTargetIndices", nil, true) |
1588 | if #customTargetIndices > 0 then |
1589 | entry.customTargetIndices = customTargetIndices |
1590 | end |
1591 | |
1592 | return true |
1593 | end |
loadHoseNode
DescriptionDefinitionloadHoseNode()Code
778 | function ConnectionHoses:loadHoseNode(xmlFile, hoseKey, entry, isBaseHose) |
779 | entry.inputAttacherJointIndices = {} |
780 | |
781 | local inputAttacherJointIndices = xmlFile:getValue(hoseKey .. "#inputAttacherJointIndices", nil, true) |
782 | for _, inputAttacherJointIndex in ipairs(inputAttacherJointIndices) do |
783 | entry.inputAttacherJointIndices[inputAttacherJointIndex] = inputAttacherJointIndex |
784 | end |
785 | |
786 | local inputAttacherJointNodes = xmlFile:getValue(hoseKey .. "#inputAttacherJointNodes", nil, self.components, self.i3dMappings, true) |
787 | for _, node in ipairs(inputAttacherJointNodes) do |
788 | local inputAttacherJointIndex = self:getInputAttacherJointIndexByNode(node) |
789 | if inputAttacherJointIndex ~= nil then |
790 | entry.inputAttacherJointIndices[inputAttacherJointIndex] = inputAttacherJointIndex |
791 | end |
792 | end |
793 | |
794 | entry.type = xmlFile:getValue(hoseKey .. "#type") |
795 | entry.specType = xmlFile:getValue(hoseKey .. "#specType") |
796 | if entry.type == nil then |
797 | Logging.xmlWarning(xmlFile, "Missing type attribute in '%s'", hoseKey) |
798 | return false |
799 | end |
800 | |
801 | entry.hoseType = xmlFile:getValue(hoseKey .. "#hoseType", "DEFAULT") |
802 | entry.node = xmlFile:getValue(hoseKey .. "#node", nil, self.components, self.i3dMappings) |
803 | if entry.node == nil then |
804 | Logging.xmlWarning(xmlFile, "Missing node for connection hose '%s'", hoseKey) |
805 | return false |
806 | end |
807 | |
808 | if isBaseHose then |
809 | local spec = self.spec_connectionHoses |
810 | local type = entry.type .. (entry.specType or "") |
811 | if spec.numHosesByType[type] == nil then |
812 | spec.numHosesByType[type] = 0 |
813 | end |
814 | spec.numHosesByType[type] = spec.numHosesByType[type] + 1 |
815 | entry.typedIndex = spec.numHosesByType[type] |
816 | end |
817 | |
818 | entry.isTwoPointHose = xmlFile:getValue(hoseKey .. "#isTwoPointHose", false) |
819 | entry.isWorldSpaceHose = xmlFile:getValue(hoseKey .. "#isWorldSpaceHose", true) |
820 | |
821 | entry.component = self:getParentComponent(entry.node) |
822 | entry.lastVelY = 0 |
823 | entry.lastVelZ = 0 |
824 | entry.dampingRange = xmlFile:getValue(hoseKey .. "#dampingRange", 0.05) |
825 | entry.dampingFactor = xmlFile:getValue(hoseKey .. "#dampingFactor", 50) |
826 | |
827 | entry.length = xmlFile:getValue(hoseKey .. "#length", 3) |
828 | entry.diameter = xmlFile:getValue(hoseKey .. "#diameter", 0.02) |
829 | entry.straighteningFactor = xmlFile:getValue(hoseKey .. "#straighteningFactor", 1) |
830 | entry.minCenterPointAngle = xmlFile:getValue(hoseKey .. "#minCenterPointAngle") |
831 | |
832 | entry.minCenterPointOffset = xmlFile:getValue(hoseKey .. "#minCenterPointOffset", nil, true) |
833 | entry.maxCenterPointOffset = xmlFile:getValue(hoseKey .. "#maxCenterPointOffset", nil, true) |
834 | |
835 | if entry.minCenterPointOffset ~= nil and entry.maxCenterPointOffset ~= nil then |
836 | for i=1, 3 do |
837 | if entry.minCenterPointOffset[i] == 0 then |
838 | entry.minCenterPointOffset[i] = -math.huge |
839 | end |
840 | |
841 | if entry.maxCenterPointOffset[i] == 0 then |
842 | entry.maxCenterPointOffset[i] = math.huge |
843 | end |
844 | end |
845 | end |
846 | |
847 | entry.minDeltaY = xmlFile:getValue(hoseKey .. "#minDeltaY", math.huge) |
848 | entry.minDeltaYComponent = xmlFile:getValue(hoseKey .. "#minDeltaYComponent", entry.component, self.components, self.i3dMappings) |
849 | |
850 | entry.color = xmlFile:getValue(hoseKey.."#color", nil, true) |
851 | |
852 | entry.adapterName = xmlFile:getValue(hoseKey .. "#adapterType") |
853 | entry.outgoingAdapter = xmlFile:getValue(hoseKey .. "#outgoingAdapter") |
854 | |
855 | entry.adapterNode = xmlFile:getValue(hoseKey .. "#adapterNode", nil, self.components, self.i3dMappings) |
856 | if entry.adapterNode ~= nil then |
857 | local node = g_connectionHoseManager:getClonedAdapterNode(entry.type, entry.adapterName or "DEFAULT", self.customEnvironment, true) |
858 | if node ~= nil then |
859 | link(entry.adapterNode, node) |
860 | else |
861 | Logging.xmlWarning(xmlFile, "Unable to find detached adapter for type '%s' in '%s'", entry.adapterName or "DEFAULT", hoseKey) |
862 | end |
863 | end |
864 | |
865 | local socketName = xmlFile:getValue(hoseKey .. "#socket") |
866 | if socketName ~= nil then |
867 | local socketColor = xmlFile:getValue(hoseKey .. "#socketColor", nil, true) |
868 | entry.socket = g_connectionHoseManager:linkSocketToNode(socketName, entry.node, self.customEnvironment, socketColor) |
869 | if entry.socket ~= nil then |
870 | setRotation(entry.socket.node, 0, math.pi, 0) |
871 | end |
872 | end |
873 | |
874 | local hose, startStraightening, endStraightening, minCenterPointAngle = g_connectionHoseManager:getClonedHoseNode(entry.type, entry.hoseType, entry.length, entry.diameter, entry.color, self.customEnvironment) |
875 | |
876 | if hose ~= nil then |
877 | local outgoingNode, visibilityNode = g_connectionHoseManager:getSocketTarget(entry.socket, entry.node), hose |
878 | local rx, ry, rz = 0, 0, 0 |
879 | if entry.outgoingAdapter ~= nil then |
880 | local node, referenceNode = g_connectionHoseManager:getClonedAdapterNode(entry.type, entry.outgoingAdapter, self.customEnvironment) |
881 | if node ~= nil then |
882 | link(outgoingNode, node) |
883 | outgoingNode = referenceNode |
884 | visibilityNode = node |
885 | ry = math.pi |
886 | |
887 | if entry.socket == nil then |
888 | setRotation(node, 0, ry, 0) |
889 | end |
890 | else |
891 | Logging.xmlWarning(xmlFile, "Unable to find adapter type '%s' in '%s'", entry.outgoingAdapter, hoseKey) |
892 | end |
893 | end |
894 | |
895 | link(outgoingNode, hose) |
896 | setTranslation(hose, 0, 0, 0) |
897 | setRotation(hose, rx, ry, rz) |
898 | |
899 | entry.hoseNode = hose |
900 | entry.visibilityNode = visibilityNode |
901 | entry.startStraightening = startStraightening * entry.straighteningFactor |
902 | entry.endStraightening = endStraightening |
903 | entry.endStraighteningBase = endStraightening |
904 | entry.endStraighteningDirectionBase = {0, 0, 1} |
905 | entry.endStraighteningDirection = entry.endStraighteningDirectionBase |
906 | entry.minCenterPointAngle = entry.minCenterPointAngle or minCenterPointAngle |
907 | |
908 | setVisibility(entry.visibilityNode, false) |
909 | else |
910 | Logging.xmlWarning(xmlFile, "Unable to find connection hose with length '%.2f' and diameter '%.2f' in '%s'", entry.length, entry.diameter, hoseKey) |
911 | return false |
912 | end |
913 | |
914 | entry.objectChanges = {} |
915 | ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, hoseKey, entry.objectChanges, self.components, self) |
916 | ObjectChangeUtil.setObjectChanges(entry.objectChanges, false) |
917 | |
918 | return true |
919 | end |
loadHoseSkipNode
DescriptionDefinitionloadHoseSkipNode()Code
546 | function ConnectionHoses:loadHoseSkipNode(xmlFile, targetKey, entry) |
547 | entry.node = xmlFile:getValue(targetKey .. "#node", nil, self.components, self.i3dMappings) |
548 | |
549 | if entry.node == nil then |
550 | Logging.xmlWarning(xmlFile, "Missing node for hose skip node '%s'", targetKey) |
551 | return false |
552 | end |
553 | |
554 | entry.inputAttacherJointIndex = xmlFile:getValue(targetKey .. "#inputAttacherJointIndex", 1) |
555 | entry.attacherJointIndex = xmlFile:getValue(targetKey .. "#attacherJointIndex", 1) |
556 | |
557 | entry.type = xmlFile:getValue(targetKey .. "#type") |
558 | entry.specType = xmlFile:getValue(targetKey .. "#specType") |
559 | |
560 | if entry.type == nil then |
561 | Logging.xmlWarning(xmlFile, "Missing type for hose skip node '%s'", targetKey) |
562 | return false |
563 | end |
564 | |
565 | entry.length = xmlFile:getValue(targetKey .. "#length") |
566 | entry.isTwoPointHose = xmlFile:getValue(targetKey .. "#isTwoPointHose", false) |
567 | |
568 | entry.isSkipNode = true |
569 | |
570 | return true |
571 | end |
loadHoseTargetNode
DescriptionDefinitionloadHoseTargetNode()Code
720 | function ConnectionHoses:loadHoseTargetNode(xmlFile, targetKey, entry) |
721 | entry.node = xmlFile:getValue(targetKey .. "#node", nil, self.components, self.i3dMappings) |
722 | |
723 | if entry.node == nil then |
724 | Logging.xmlWarning(xmlFile, "Missing node for connection hose target '%s'", targetKey) |
725 | return false |
726 | end |
727 | |
728 | entry.attacherJointIndices = {} |
729 | |
730 | local attacherJointIndices = xmlFile:getValue(targetKey .. "#attacherJointIndices", nil, true) |
731 | for _, attacherJointIndex in ipairs(attacherJointIndices) do |
732 | entry.attacherJointIndices[attacherJointIndex] = attacherJointIndex |
733 | end |
734 | |
735 | local attacherJointNodes = xmlFile:getValue(targetKey .. "#attacherJointNodes", nil, self.components, self.i3dMappings, true) |
736 | for _, node in ipairs(attacherJointNodes) do |
737 | local attacherJointIndex = self:getAttacherJointIndexByNode(node) |
738 | if attacherJointIndex ~= nil then |
739 | entry.attacherJointIndices[attacherJointIndex] = attacherJointIndex |
740 | end |
741 | end |
742 | |
743 | entry.type = xmlFile:getValue(targetKey .. "#type") |
744 | entry.specType = xmlFile:getValue(targetKey .. "#specType") |
745 | entry.straighteningFactor = xmlFile:getValue(targetKey .. "#straighteningFactor", 1) |
746 | entry.straighteningDirection = xmlFile:getValue(targetKey .. "#straighteningDirection", nil, true) |
747 | |
748 | local socketName = xmlFile:getValue(targetKey .. "#socket") |
749 | if socketName ~= nil then |
750 | local socketColor = xmlFile:getValue(targetKey .. "#socketColor", nil, true) |
751 | entry.socket = g_connectionHoseManager:linkSocketToNode(socketName, entry.node, self.customEnvironment, socketColor) |
752 | end |
753 | |
754 | if entry.type ~= nil then |
755 | entry.adapterName = xmlFile:getValue(targetKey .. "#adapterType", "DEFAULT") |
756 | |
757 | -- empty adapter with target node as reference |
758 | -- will be replaced with the real adapter on connecting |
759 | if entry.adapter == nil then |
760 | entry.adapter = {} |
761 | entry.adapter.node = entry.node |
762 | entry.adapter.refNode = entry.node |
763 | end |
764 | |
765 | entry.objectChanges = {} |
766 | ObjectChangeUtil.loadObjectChangeFromXML(xmlFile, targetKey, entry.objectChanges, self.components, self) |
767 | ObjectChangeUtil.setObjectChanges(entry.objectChanges, false) |
768 | else |
769 | Logging.xmlWarning(xmlFile, "Missing type for '%s'", targetKey) |
770 | return false |
771 | end |
772 | |
773 | return true |
774 | end |
loadToolConnectorHoseNode
DescriptionDefinitionloadToolConnectorHoseNode()Code
575 | function ConnectionHoses:loadToolConnectorHoseNode(xmlFile, targetKey, entry) |
576 | local spec = self.spec_connectionHoses |
577 | |
578 | local key = string.format("%s.startTarget", targetKey) |
579 | entry.startTargetNodeIndex = self:addHoseTargetNodes(xmlFile, key) |
580 | |
581 | if entry.startTargetNodeIndex == nil then |
582 | Logging.xmlWarning(xmlFile, "startTarget is missing for tool connection hose '%s'", targetKey) |
583 | return false |
584 | end |
585 | |
586 | key = string.format("%s.endTarget", targetKey) |
587 | entry.endTargetNodeIndex = self:addHoseTargetNodes(xmlFile, key) |
588 | |
589 | if entry.endTargetNodeIndex == nil then |
590 | Logging.xmlWarning(xmlFile, "endTarget is missing for tool connection hose '%s'", targetKey) |
591 | return false |
592 | end |
593 | |
594 | local startTarget = spec.targetNodes[entry.startTargetNodeIndex] |
595 | local endTarget = spec.targetNodes[entry.endTargetNodeIndex] |
596 | |
597 | for index, _ in pairs(startTarget.attacherJointIndices) do |
598 | if endTarget.attacherJointIndices[index] ~= nil then |
599 | Logging.xmlWarning(xmlFile, "Double usage of attacher joint index '%d' in '%s'", index, targetKey) |
600 | end |
601 | end |
602 | |
603 | entry.moveNodes = xmlFile:getValue(targetKey .. "#moveNodes", true) |
604 | entry.additionalHose = xmlFile:getValue(targetKey .. "#additionalHose", true) |
605 | |
606 | -- make sure the two nodes are pointing towards each other |
607 | if entry.moveNodes then |
608 | local x1, y1, z1 = getTranslation(startTarget.node) |
609 | local x2, y2, z2 = getTranslation(endTarget.node) |
610 | local dirX, dirY, dirZ = MathUtil.vector3Normalize(x1-x2, y1-y2, z1-z2) |
611 | local upX, upY, upZ = localDirectionToLocal(endTarget.node, getParent(endTarget.node), 0, 1, 0) |
612 | if (dirX ~= 0 or dirY ~= 0 or dirZ ~= 0) |
613 | and not MathUtil.isNan(dirX) and not MathUtil.isNan(dirY) and not MathUtil.isNan(dirZ) then |
614 | setDirection(startTarget.node, -dirX, -dirY, -dirZ, upX, upY, upZ) |
615 | setDirection(endTarget.node, dirX, dirY, dirZ, upX, upY, upZ) |
616 | end |
617 | end |
618 | |
619 | entry.mountingNode = xmlFile:getValue(targetKey .. "#mountingNode", nil, self.components, self.i3dMappings) |
620 | |
621 | if entry.mountingNode ~= nil then |
622 | setVisibility(entry.mountingNode, false) |
623 | end |
624 | |
625 | local type = spec.targetNodes[entry.startTargetNodeIndex].type .. (spec.targetNodes[entry.startTargetNodeIndex].specType or "") |
626 | if spec.numToolConnectionsByType[type] == nil then |
627 | spec.numToolConnectionsByType[type] = 0 |
628 | end |
629 | spec.numToolConnectionsByType[type] = spec.numToolConnectionsByType[type] + 1 |
630 | entry.typedIndex = spec.numToolConnectionsByType[type] |
631 | |
632 | entry.connected = false |
633 | |
634 | return true |
635 | end |
onLoad
DescriptionDefinitiononLoad()Code
190 | function ConnectionHoses:onLoad(savegame) |
191 | local spec = self.spec_connectionHoses |
192 | |
193 | local configKey = string.format("vehicle.connectionHoses.connectionHoseConfigurations.connectionHoseConfiguration(%d)", spec.configIndex - 1) |
194 | ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.connectionHoses.connectionHoseConfigurations.connectionHoseConfiguration", spec.configIndex, self.components, self) |
195 | |
196 | spec.numHosesByType = {} |
197 | spec.numToolConnectionsByType = {} |
198 | |
199 | spec.hoseSkipNodes = {} |
200 | spec.hoseSkipNodeByType = {} |
201 | |
202 | spec.targetNodes = {} |
203 | spec.targetNodesByType = {} |
204 | |
205 | spec.toolConnectorHoses = {} |
206 | spec.targetNodeToToolConnection = {} |
207 | |
208 | spec.hoseNodes = {} |
209 | spec.hoseNodesByInputAttacher = {} |
210 | |
211 | spec.localHoseNodes = {} |
212 | |
213 | spec.customHoses = {} |
214 | spec.customHosesByAttacher = {} |
215 | spec.customHosesByInputAttacher = {} |
216 | |
217 | spec.customHoseTargets = {} |
218 | spec.customHoseTargetsByAttacher = {} |
219 | spec.customHoseTargetsByInputAttacher = {} |
220 | |
221 | self:loadConnectionHosesFromXML(self.xmlFile, "vehicle.connectionHoses") |
222 | |
223 | if self.xmlFile:hasProperty(configKey) then |
224 | self:loadConnectionHosesFromXML(self.xmlFile, configKey) |
225 | end |
226 | |
227 | spec.maxUpdateDistance = self.xmlFile:getValue("vehicle.connectionHoses#maxUpdateDistance", ConnectionHoses.DEFAULT_MAX_UPDATE_DISTANCE) |
228 | |
229 | spec.targetNodesAvailable = #spec.targetNodes > 0 |
230 | spec.hoseNodesAvailable = #spec.hoseNodes > 0 |
231 | spec.localHosesAvailable = #spec.localHoseNodes > 0 |
232 | spec.skipNodesAvailable = #spec.hoseSkipNodes > 0 |
233 | |
234 | spec.updateableHoses = {} |
235 | |
236 | -- connection local hoses |
237 | for _, localHoseNode in ipairs(spec.localHoseNodes) do |
238 | self:connectHose(localHoseNode.hose, self, localHoseNode.target, false) |
239 | end |
240 | |
241 | if not self.isClient or (not spec.targetNodesAvailable and not spec.hoseNodesAvailable and not spec.localHosesAvailable and not spec.skipNodesAvailable) then |
242 | SpecializationUtil.removeEventListener(self, "onPostUpdate", ConnectionHoses) |
243 | end |
244 | end |
onPostAttach
DescriptionDefinitiononPostAttach()Code
1625 | function ConnectionHoses:onPostAttach(attacherVehicle, inputJointDescIndex, jointDescIndex) |
1626 | self:connectHosesToAttacherVehicle(attacherVehicle, inputJointDescIndex, jointDescIndex) |
1627 | self:connectCustomHosesToAttacherVehicle(attacherVehicle, inputJointDescIndex, jointDescIndex) |
1628 | end |
onPostUpdate
DescriptionDefinitiononPostUpdate()Code
248 | function ConnectionHoses:onPostUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
249 | local spec = self.spec_connectionHoses |
250 | if self.currentUpdateDistance < spec.maxUpdateDistance then |
251 | for i=1, #spec.updateableHoses do |
252 | local hose = spec.updateableHoses[i] |
253 | if self.updateLoopIndex == hose.connectedObject.updateLoopIndex then |
254 | self:updateConnectionHose(hose, i) |
255 | end |
256 | end |
257 | |
258 | if self.getAttachedImplements ~= nil then |
259 | local impements = self:getAttachedImplements() |
260 | for i=1, #impements do |
261 | local object = impements[i].object |
262 | if object.updateAttachedConnectionHoses ~= nil then |
263 | object:updateAttachedConnectionHoses(self) |
264 | end |
265 | end |
266 | end |
267 | end |
268 | end |
onPreDetach
DescriptionDefinitiononPreDetach()Code
1632 | function ConnectionHoses:onPreDetach(attacherVehicle, implement) |
1633 | local spec = self.spec_connectionHoses |
1634 | |
1635 | local inputJointDescIndex = self:getActiveInputAttacherJointDescIndex() |
1636 | |
1637 | local hoses = self:getConnectionHosesByInputAttacherJoint(inputJointDescIndex) |
1638 | for _, hose in ipairs(hoses) do |
1639 | self:disconnectHose(hose) |
1640 | end |
1641 | |
1642 | for i=#spec.updateableHoses, 1, -1 do |
1643 | local hose = spec.updateableHoses[i] |
1644 | if hose.connectedObject == attacherVehicle then |
1645 | self:disconnectHose(hose) |
1646 | end |
1647 | end |
1648 | |
1649 | -- remove delayed mounting if we detach the implement |
1650 | local attacherVehicleSpec = attacherVehicle.spec_connectionHoses |
1651 | if attacherVehicleSpec ~= nil then |
1652 | for _, toolConnector in pairs(attacherVehicleSpec.toolConnectorHoses) do |
1653 | if toolConnector.delayedMounting ~= nil then |
1654 | if toolConnector.delayedMounting.sourceObject == self then |
1655 | toolConnector.delayedMounting = nil |
1656 | end |
1657 | end |
1658 | end |
1659 | end |
1660 | |
1661 | local customHoses = spec.customHosesByInputAttacher[inputJointDescIndex] |
1662 | if customHoses ~= nil then |
1663 | for i=1, #customHoses do |
1664 | local customHose = customHoses[i] |
1665 | if customHose.isActive then |
1666 | self:disconnectCustomHoseNode(customHose, customHose.connectedTarget) |
1667 | end |
1668 | end |
1669 | end |
1670 | |
1671 | local customTargets = spec.customHoseTargetsByInputAttacher[inputJointDescIndex] |
1672 | if customTargets ~= nil then |
1673 | for i=1, #customTargets do |
1674 | local customTarget = customTargets[i] |
1675 | if customTarget.isActive then |
1676 | self:disconnectCustomHoseNode(customTarget.connectedHose, customTarget) |
1677 | end |
1678 | end |
1679 | end |
1680 | end |
onPreLoad
DescriptionDefinitiononPreLoad()Code
183 | function ConnectionHoses:onPreLoad(savegame) |
184 | local spec = self.spec_connectionHoses |
185 | spec.configIndex = self:getConnectionHoseConfigIndex() |
186 | end |
prerequisitesPresent
DescriptionDefinitionprerequisitesPresent()Code
17 | function ConnectionHoses.prerequisitesPresent(specializations) |
18 | return true |
19 | end |
registerConnectionHoseXMLPaths
DescriptionDefinitionregisterConnectionHoseXMLPaths()Code
44 | function ConnectionHoses.registerConnectionHoseXMLPaths(schema, basePath) |
45 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".skipNode(?)#node", "Skip node") |
46 | schema:register(XMLValueType.INT, basePath .. ".skipNode(?)#inputAttacherJointIndex", "Input attacher joint index", 1) |
47 | schema:register(XMLValueType.INT, basePath .. ".skipNode(?)#attacherJointIndex", "Attacher joint index", 1) |
48 | schema:register(XMLValueType.STRING, basePath .. ".skipNode(?)#type", "Connection hose type") |
49 | schema:register(XMLValueType.STRING, basePath .. ".skipNode(?)#specType", "Connection hose specialization type (if defined it needs to match the type of the other tool)") |
50 | schema:register(XMLValueType.FLOAT, basePath .. ".skipNode(?)#length", "Hose length") |
51 | schema:register(XMLValueType.BOOL, basePath .. ".skipNode(?)#isTwoPointHose", "Is two point hose without sagging", false) |
52 | |
53 | ConnectionHoses.registerHoseTargetNodesXMLPaths(schema, basePath .. ".target(?)") |
54 | |
55 | schema:register(XMLValueType.NODE_INDEX, basePath .. ".toolConnectorHose(?)#mountingNode", "Mounting node to toggle visibility") |
56 | schema:register(XMLValueType.BOOL, basePath .. ".toolConnectorHose(?)#moveNodes", "Defines if the start and end nodes are moved up depending on hose diameter", true) |
57 | schema:register(XMLValueType.BOOL, basePath .. ".toolConnectorHose(?)#additionalHose", "Defines if between start and end node a additional hose is created", true) |
58 | ConnectionHoses.registerHoseTargetNodesXMLPaths(schema, basePath .. ".toolConnectorHose(?).startTarget(?)") |
59 | ConnectionHoses.registerHoseTargetNodesXMLPaths(schema, basePath .. ".toolConnectorHose(?).endTarget(?)") |
60 | |
61 | ConnectionHoses.registerHoseNodesXMLPaths(schema, basePath .. ".hose(?)") |
62 | |
63 | ConnectionHoses.registerHoseNodesXMLPaths(schema, basePath .. ".localHose(?).hose") |
64 | ConnectionHoses.registerHoseTargetNodesXMLPaths(schema, basePath .. ".localHose(?).target") |
65 | |
66 | ConnectionHoses.registerCustomHoseNodesXMLPaths(schema, basePath .. ".customHose(?)") |
67 | ConnectionHoses.registerCustomHoseNodesXMLPaths(schema, basePath .. ".customTarget(?)") |
68 | end |
registerCustomHoseNodesXMLPaths
DescriptionDefinitionregisterCustomHoseNodesXMLPaths()Code
120 | function ConnectionHoses.registerCustomHoseNodesXMLPaths(schema, basePath) |
121 | schema:register(XMLValueType.NODE_INDEX, basePath .. "#node", "Target or source node") |
122 | schema:register(XMLValueType.STRING, basePath .. "#type", "Hose type which can be any string that needs to match between hose and target node") |
123 | schema:register(XMLValueType.VECTOR_N, basePath .. "#attacherJointIndices", "Attacher joint indices") |
124 | schema:register(XMLValueType.VECTOR_N, basePath .. "#inputAttacherJointIndices", "Input attacher joint indices") |
125 | |
126 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, basePath) |
127 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
173 | function ConnectionHoses.registerEventListeners(vehicleType) |
174 | SpecializationUtil.registerEventListener(vehicleType, "onPreLoad", ConnectionHoses) |
175 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", ConnectionHoses) |
176 | SpecializationUtil.registerEventListener(vehicleType, "onPostUpdate", ConnectionHoses) |
177 | SpecializationUtil.registerEventListener(vehicleType, "onPostAttach", ConnectionHoses) |
178 | SpecializationUtil.registerEventListener(vehicleType, "onPreDetach", ConnectionHoses) |
179 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
131 | function ConnectionHoses.registerFunctions(vehicleType) |
132 | SpecializationUtil.registerFunction(vehicleType, "getConnectionHoseConfigIndex", ConnectionHoses.getConnectionHoseConfigIndex) |
133 | SpecializationUtil.registerFunction(vehicleType, "updateAttachedConnectionHoses", ConnectionHoses.updateAttachedConnectionHoses) |
134 | SpecializationUtil.registerFunction(vehicleType, "updateConnectionHose", ConnectionHoses.updateConnectionHose) |
135 | SpecializationUtil.registerFunction(vehicleType, "getCenterPointAngle", ConnectionHoses.getCenterPointAngle) |
136 | SpecializationUtil.registerFunction(vehicleType, "getCenterPointAngleRegulation", ConnectionHoses.getCenterPointAngleRegulation) |
137 | SpecializationUtil.registerFunction(vehicleType, "loadConnectionHosesFromXML", ConnectionHoses.loadConnectionHosesFromXML) |
138 | SpecializationUtil.registerFunction(vehicleType, "loadHoseSkipNode", ConnectionHoses.loadHoseSkipNode) |
139 | SpecializationUtil.registerFunction(vehicleType, "loadToolConnectorHoseNode", ConnectionHoses.loadToolConnectorHoseNode) |
140 | SpecializationUtil.registerFunction(vehicleType, "addHoseTargetNodes", ConnectionHoses.addHoseTargetNodes) |
141 | SpecializationUtil.registerFunction(vehicleType, "loadCustomHosesFromXML", ConnectionHoses.loadCustomHosesFromXML) |
142 | SpecializationUtil.registerFunction(vehicleType, "loadHoseTargetNode", ConnectionHoses.loadHoseTargetNode) |
143 | SpecializationUtil.registerFunction(vehicleType, "loadHoseNode", ConnectionHoses.loadHoseNode) |
144 | SpecializationUtil.registerFunction(vehicleType, "getClonedSkipHoseNode", ConnectionHoses.getClonedSkipHoseNode) |
145 | SpecializationUtil.registerFunction(vehicleType, "getConnectionTarget", ConnectionHoses.getConnectionTarget) |
146 | SpecializationUtil.registerFunction(vehicleType, "iterateConnectionTargets", ConnectionHoses.iterateConnectionTargets) |
147 | SpecializationUtil.registerFunction(vehicleType, "getIsConnectionTargetUsed", ConnectionHoses.getIsConnectionTargetUsed) |
148 | SpecializationUtil.registerFunction(vehicleType, "getIsConnectionHoseUsed", ConnectionHoses.getIsConnectionHoseUsed) |
149 | SpecializationUtil.registerFunction(vehicleType, "getIsSkipNodeAvailable", ConnectionHoses.getIsSkipNodeAvailable) |
150 | SpecializationUtil.registerFunction(vehicleType, "getConnectionHosesByInputAttacherJoint", ConnectionHoses.getConnectionHosesByInputAttacherJoint) |
151 | SpecializationUtil.registerFunction(vehicleType, "connectHose", ConnectionHoses.connectHose) |
152 | SpecializationUtil.registerFunction(vehicleType, "disconnectHose", ConnectionHoses.disconnectHose) |
153 | SpecializationUtil.registerFunction(vehicleType, "updateToolConnectionHose", ConnectionHoses.updateToolConnectionHose) |
154 | SpecializationUtil.registerFunction(vehicleType, "addHoseToDelayedMountings", ConnectionHoses.addHoseToDelayedMountings) |
155 | SpecializationUtil.registerFunction(vehicleType, "connectHoseToSkipNode", ConnectionHoses.connectHoseToSkipNode) |
156 | SpecializationUtil.registerFunction(vehicleType, "connectHosesToAttacherVehicle", ConnectionHoses.connectHosesToAttacherVehicle) |
157 | SpecializationUtil.registerFunction(vehicleType, "retryHoseSkipNodeConnections", ConnectionHoses.retryHoseSkipNodeConnections) |
158 | SpecializationUtil.registerFunction(vehicleType, "connectCustomHosesToAttacherVehicle", ConnectionHoses.connectCustomHosesToAttacherVehicle) |
159 | SpecializationUtil.registerFunction(vehicleType, "connectCustomHoseNode", ConnectionHoses.connectCustomHoseNode) |
160 | SpecializationUtil.registerFunction(vehicleType, "updateCustomHoseNode", ConnectionHoses.updateCustomHoseNode) |
161 | SpecializationUtil.registerFunction(vehicleType, "disconnectCustomHoseNode", ConnectionHoses.disconnectCustomHoseNode) |
162 | end |
registerHoseNodesXMLPaths
DescriptionDefinitionregisterHoseNodesXMLPaths()Code
89 | function ConnectionHoses.registerHoseNodesXMLPaths(schema, basePath) |
90 | schema:register(XMLValueType.VECTOR_N, basePath .. "#inputAttacherJointIndices", "List of corresponding input attacher joint indices") |
91 | schema:register(XMLValueType.NODE_INDICES, basePath .. "#inputAttacherJointNodes", "List of corresponding input attacher joint nodes (i3dIdentifiers or paths separated by space)") |
92 | schema:register(XMLValueType.STRING, basePath .. "#type", "Hose type") |
93 | schema:register(XMLValueType.STRING, basePath .. "#specType", "Connection hose specialization type (if defined it needs to match the type of the other tool)") |
94 | schema:register(XMLValueType.STRING, basePath .. "#hoseType", "Hose material type", "DEFAULT") |
95 | schema:register(XMLValueType.NODE_INDEX, basePath .. "#node", "Hose output node") |
96 | schema:register(XMLValueType.BOOL, basePath .. "#isTwoPointHose", "Is two point hose without sagging", false) |
97 | schema:register(XMLValueType.BOOL, basePath .. "#isWorldSpaceHose", "Sagging is calculated in world space or local space of hose node", true) |
98 | schema:register(XMLValueType.STRING, basePath .. "#dampingRange", "Damping range in meters", 0.05) |
99 | schema:register(XMLValueType.FLOAT, basePath .. "#dampingFactor", "Damping factor", 50) |
100 | schema:register(XMLValueType.FLOAT, basePath .. "#length", "Hose length", 3) |
101 | schema:register(XMLValueType.FLOAT, basePath .. "#diameter", "Hose diameter", 0.02) |
102 | schema:register(XMLValueType.FLOAT, basePath .. "#straighteningFactor", "Straightening Factor", 1) |
103 | schema:register(XMLValueType.ANGLE, basePath .. "#minCenterPointAngle", "Min. angle of sagged curve", "Defined on connectionHose xml, default 90 degree") |
104 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. "#minCenterPointOffset", "Min. center point offset from hose node", "unlimited") |
105 | schema:register(XMLValueType.VECTOR_TRANS, basePath .. "#maxCenterPointOffset", "Max. center point offset from hose node", "unlimited") |
106 | schema:register(XMLValueType.FLOAT, basePath .. "#minDeltaY", "Min. delta Y from center point") |
107 | schema:register(XMLValueType.NODE_INDEX, basePath .. "#minDeltaYComponent", "Min. delta Y reference node") |
108 | schema:register(XMLValueType.COLOR, basePath .. "#color", "Hose color") |
109 | schema:register(XMLValueType.STRING, basePath .. "#adapterType", "Adapter type name") |
110 | schema:register(XMLValueType.NODE_INDEX, basePath .. "#adapterNode", "Link node for detached adapter") |
111 | schema:register(XMLValueType.STRING, basePath .. "#outgoingAdapter", "Adapter type that is used for outgoing connection hose") |
112 | schema:register(XMLValueType.STRING, basePath .. "#socket", "Outgoing socket name to load") |
113 | schema:register(XMLValueType.COLOR, basePath .. "#socketColor", "Socket custom color") |
114 | |
115 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, basePath) |
116 | end |
registerHoseTargetNodesXMLPaths
DescriptionDefinitionregisterHoseTargetNodesXMLPaths()Code
72 | function ConnectionHoses.registerHoseTargetNodesXMLPaths(schema, basePath) |
73 | schema:register(XMLValueType.NODE_INDEX, basePath .. "#node", "Target node") |
74 | schema:register(XMLValueType.VECTOR_N, basePath .. "#attacherJointIndices", "List of corresponding attacher joint indices") |
75 | schema:register(XMLValueType.NODE_INDICES, basePath .. "#attacherJointNodes", "List of corresponding attacher joint nodes (i3dIdentifiers or paths separated by space)") |
76 | schema:register(XMLValueType.STRING, basePath .. "#type", "Hose type") |
77 | schema:register(XMLValueType.STRING, basePath .. "#specType", "Connection hose specialization type (if defined it needs to match the type of the other tool)") |
78 | schema:register(XMLValueType.FLOAT, basePath .. "#straighteningFactor", "Straightening Factor", 1) |
79 | schema:register(XMLValueType.VECTOR_3, basePath .. "#straighteningDirection", "Straightening direction", "0 0 1") |
80 | schema:register(XMLValueType.STRING, basePath .. "#socket", "Socket name to load") |
81 | schema:register(XMLValueType.COLOR, basePath .. "#socketColor", "Socket custom color") |
82 | schema:register(XMLValueType.STRING, basePath .. "#adapterType", "Adapter type to use", "DEFAULT") |
83 | |
84 | ObjectChangeUtil.registerObjectChangeXMLPaths(schema, basePath) |
85 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
166 | function ConnectionHoses.registerOverwrittenFunctions(vehicleType) |
167 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadExtraDependentParts", ConnectionHoses.loadExtraDependentParts) |
168 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateExtraDependentParts", ConnectionHoses.updateExtraDependentParts) |
169 | end |
retryHoseSkipNodeConnections
DescriptionDefinitionretryHoseSkipNodeConnections()Code
1472 | function ConnectionHoses:retryHoseSkipNodeConnections(updateToolConnections, excludeVehicle) |
1473 | if self.getAttachedImplements ~= nil then |
1474 | local attachedImplements = self:getAttachedImplements() |
1475 | for _, implement in ipairs(attachedImplements) do |
1476 | local object = implement.object |
1477 | if object ~= excludeVehicle then |
1478 | if object.connectHosesToAttacherVehicle ~= nil then |
1479 | object:connectHosesToAttacherVehicle(self, implement.inputJointDescIndex, implement.jointDescIndex, updateToolConnections, excludeVehicle) |
1480 | end |
1481 | end |
1482 | end |
1483 | end |
1484 | end |
updateAttachedConnectionHoses
DescriptionDefinitionupdateAttachedConnectionHoses()Code
278 | function ConnectionHoses:updateAttachedConnectionHoses(attacherVehicle) |
279 | local spec = self.spec_connectionHoses |
280 | for i=1, #spec.updateableHoses do |
281 | local hose = spec.updateableHoses[i] |
282 | if hose.connectedObject == attacherVehicle then |
283 | if self.updateLoopIndex == hose.connectedObject.updateLoopIndex then |
284 | self:updateConnectionHose(hose, i) |
285 | end |
286 | end |
287 | end |
288 | end |
updateConnectionHose
DescriptionDefinitionupdateConnectionHose()Code
292 | function ConnectionHoses:updateConnectionHose(hose, index) |
293 | -- determine control points for spline |
294 | local p0x, p0y, p0z = 0, 0, -hose.startStraightening |
295 | local p3x, p3y, p3z = localToLocal(hose.targetNode, hose.hoseNode, 0, 0, 0) |
296 | local p4x, p4y, p4z = localToLocal(hose.targetNode, hose.hoseNode, hose.endStraighteningDirection[1] * hose.endStraightening, hose.endStraighteningDirection[2] * hose.endStraightening, hose.endStraighteningDirection[3] * hose.endStraightening) |
297 | |
298 | -- default position of middle node |
299 | local p2x, p2y, p2z |
300 | |
301 | if hose.isWorldSpaceHose then |
302 | local w1x, w1y, w1z = getWorldTranslation(hose.hoseNode) |
303 | local w2x, w2y, w2z = getWorldTranslation(hose.targetNode) |
304 | |
305 | p2x = (w1x + w2x) / 2 |
306 | p2y = (w1y + w2y) / 2 |
307 | p2z = (w1z + w2z) / 2 |
308 | else |
309 | p2x = p3x / 2 |
310 | p2y = p3y / 2 |
311 | p2z = p3z / 2 |
312 | end |
313 | |
314 | -- real distance between nodes |
315 | local d = MathUtil.vector3Length(p3x, p3y, p3z) |
316 | |
317 | -- simple calculation of the center point -> low precicision, high performance |
318 | local lengthDifference = math.max(hose.length - d, 0) |
319 | local p2yStart = p2y |
320 | if not hose.isWorldSpaceHose then |
321 | local _ |
322 | _, p2yStart, _ = localToWorld(hose.hoseNode, p2x, p2y, p2z) |
323 | end |
324 | |
325 | p2y = p2y - math.max(lengthDifference, 0.04 * d) |
326 | |
327 | if hose.isWorldSpaceHose then |
328 | if hose.minDeltaY ~= math.huge then |
329 | local x, y, z = worldToLocal(hose.minDeltaYComponent, p2x, p2y, p2z) |
330 | local _, yTarget, _ = localToLocal(hose.hoseNode, hose.minDeltaYComponent, 0, 0, 0) |
331 | p2x, p2y, p2z = localToWorld(hose.minDeltaYComponent, x, math.max(y, yTarget+hose.minDeltaY), z) |
332 | end |
333 | |
334 | p2x, p2y, p2z = worldToLocal(hose.hoseNode, p2x, p2y, p2z) |
335 | end |
336 | |
337 | local angle1, angle2 = self:getCenterPointAngle(hose.hoseNode, p2x, p2y, p2z, p3x, p3y, p3z, hose.isWorldSpaceHose) |
338 | local centerPointAngle = angle1+angle2 |
339 | if centerPointAngle < hose.minCenterPointAngle then |
340 | p2x, p2y, p2z = self:getCenterPointAngleRegulation(hose.hoseNode, p2x, p2y, p2z, p3x, p3y, p3z, angle1, angle2, hose.minCenterPointAngle, hose.isWorldSpaceHose) |
341 | end |
342 | |
343 | if hose.minCenterPointOffset ~= nil and hose.maxCenterPointOffset ~= nil then |
344 | p2x = MathUtil.clamp(p2x, hose.minCenterPointOffset[1], hose.maxCenterPointOffset[1]) |
345 | p2y = MathUtil.clamp(p2y, hose.minCenterPointOffset[2], hose.maxCenterPointOffset[2]) |
346 | p2z = MathUtil.clamp(p2z, hose.minCenterPointOffset[3], hose.maxCenterPointOffset[3]) |
347 | end |
348 | |
349 | -- manipulate by parent component Y and Z velocity |
350 | local newX, newY, newZ = getWorldTranslation(hose.component) |
351 | if hose.lastComponentPosition == nil or hose.lastComponentVelocity == nil then |
352 | hose.lastComponentPosition = {newX, newY, newZ} |
353 | hose.lastComponentVelocity = {newX, newY, newZ} |
354 | end |
355 | |
356 | local newVelX, newVelY, newVelZ = newX-hose.lastComponentPosition[1], newY-hose.lastComponentPosition[2], newZ-hose.lastComponentPosition[3] |
357 | hose.lastComponentPosition[1], hose.lastComponentPosition[2], hose.lastComponentPosition[3] = newX, newY, newZ |
358 | |
359 | local velX, velY, velZ = newVelX-hose.lastComponentVelocity[1], newVelY-hose.lastComponentVelocity[2], newVelZ-hose.lastComponentVelocity[3] |
360 | hose.lastComponentVelocity[1], hose.lastComponentVelocity[2], hose.lastComponentVelocity[3] = newVelX, newVelY, newVelZ |
361 | |
362 | local worldX, worldY, worldZ = getWorldTranslation(hose.hoseNode) |
363 | local _ |
364 | _, velY, velZ = worldToLocal(hose.hoseNode, worldX+velX, worldY+velY, worldZ+velZ) |
365 | |
366 | local _, wp2y, _ = localToWorld(hose.hoseNode, p2x, p2y, p2z) |
367 | local realLengthDifference = p2yStart - wp2y |
368 | velY = MathUtil.clamp(velY*-hose.dampingFactor, -hose.dampingRange, hose.dampingRange) * realLengthDifference |
369 | velZ = MathUtil.clamp(velZ*-hose.dampingFactor, -hose.dampingRange, hose.dampingRange) * realLengthDifference |
370 | |
371 | velY = velY * 0.1 + hose.lastVelY * 0.9 |
372 | velZ = velZ * 0.1 + hose.lastVelZ * 0.9 |
373 | |
374 | hose.lastVelY = velY |
375 | hose.lastVelZ = velZ |
376 | |
377 | p2x, p2y, p2z = p2x, p2y+velY, p2z+velZ |
378 | |
379 | -- on two point hoses we set the center point to 0 and the shader creates a two point catmull rom |
380 | if hose.isTwoPointHose then |
381 | p2x, p2y, p2z = 0, 0, 0 |
382 | end |
383 | |
384 | -- apply to shader |
385 | setShaderParameter(hose.hoseNode, "cv2", p2x, p2y, p2z, 0, false) -- center point |
386 | setShaderParameter(hose.hoseNode, "cv3", p3x, p3y, p3z, 0, false) -- target point |
387 | setShaderParameter(hose.hoseNode, "cv4", p4x, p4y, p4z, 1, false) -- straighter point |
388 | |
389 | if VehicleDebug.state == VehicleDebug.DEBUG_ATTACHER_JOINTS then |
390 | if self:getIsActiveForInput() then |
391 | local realLength = MathUtil.vector3Length(p2x, p2y, p2z) |
392 | realLength = realLength + MathUtil.vector3Length(p2x-p3x, p2y-p3y, p2z-p3z) |
393 | renderText(0.5, 0.9-index*0.02, 0.0175, string.format("hose %s:", getName(hose.node))) |
394 | renderText(0.62, 0.9-index*0.02, 0.0175, string.format("directLength: %.2f configLength: %.2f realLength: %.2f angle: %.2f minAngle: %.2f", d, hose.length, realLength, math.deg(centerPointAngle), math.deg(hose.minCenterPointAngle))) |
395 | |
396 | local x1,y1,z1 = localToWorld(hose.hoseNode, p0x, p0y, p0z) |
397 | local x2,y2,z2 = localToWorld(hose.hoseNode, 0, 0, 0) |
398 | drawDebugLine(x1,y1,z1, 1,0,0, x2,y2,z2, 0,1,0) |
399 | |
400 | x1,y1,z1 = localToWorld(hose.hoseNode, 0, 0, 0) |
401 | x2,y2,z2 = localToWorld(hose.hoseNode, p2x, p2y, p2z) |
402 | drawDebugLine(x1,y1,z1, 1,0,0, x2,y2,z2, 0,1,0) |
403 | |
404 | x1,y1,z1 = localToWorld(hose.hoseNode, p2x, p2y, p2z) |
405 | x2,y2,z2 = localToWorld(hose.hoseNode, p3x, p3y, p3z) |
406 | drawDebugLine(x1,y1,z1, 1,0,0, x2,y2,z2, 0,1,0) |
407 | |
408 | x1,y1,z1 = localToWorld(hose.hoseNode, p3x, p3y, p3z) |
409 | x2,y2,z2 = localToWorld(hose.hoseNode, p4x, p4y, p4z) |
410 | drawDebugLine(x1,y1,z1, 1,0,0, x2,y2,z2, 0,1,0) |
411 | |
412 | local x0,y0,z0 = localToWorld(hose.hoseNode, p0x, p0y, p0z) |
413 | x1,y1,z1 = localToWorld(hose.hoseNode, 0, 0, 0) |
414 | x2,y2,z2 = localToWorld(hose.hoseNode, p2x, p2y, p2z) |
415 | local x3,y3,z3 = localToWorld(hose.hoseNode, p3x, p3y, p3z) |
416 | local x4,y4,z4 = localToWorld(hose.hoseNode, p4x, p4y, p4z) |
417 | drawDebugPoint(x0,y0,z0, 1,0,0,1) |
418 | drawDebugPoint(x1,y1,z1, 1,0,0,1) |
419 | drawDebugPoint(x2,y2,z2, 1,0,0,1) |
420 | drawDebugPoint(x3,y3,z3, 1,0,0,1) |
421 | drawDebugPoint(x4,y4,z4, 1,0,0,1) |
422 | |
423 | DebugUtil.drawDebugNode(hose.hoseNode) |
424 | DebugUtil.drawDebugNode(hose.targetNode) |
425 | end |
426 | end |
427 | end |
updateCustomHoseNode
DescriptionDefinitionupdateCustomHoseNode()Code
1554 | function ConnectionHoses:updateCustomHoseNode(customHose, customTarget) |
1555 | setTranslation(customHose.node, localToLocal(customTarget.node, getParent(customHose.node), 0, 0, 0)) |
1556 | setRotation(customHose.node, localRotationToLocal(customTarget.node, getParent(customHose.node), 0, 0, 0)) |
1557 | end |
updateExtraDependentParts
DescriptionDefinitionupdateExtraDependentParts()Code
1597 | function ConnectionHoses:updateExtraDependentParts(superFunc, part, dt) |
1598 | superFunc(self, part, dt) |
1599 | |
1600 | if part.customHoseIndices ~= nil then |
1601 | local spec = self.spec_connectionHoses |
1602 | for i=1, #part.customHoseIndices do |
1603 | local customHoseIndex = part.customHoseIndices[i] |
1604 | local customHose = spec.customHoses[customHoseIndex] |
1605 | if customHose ~= nil and customHose.isActive then |
1606 | self:updateCustomHoseNode(customHose, customHose.connectedTarget) |
1607 | end |
1608 | end |
1609 | end |
1610 | |
1611 | if part.customTargetIndices ~= nil then |
1612 | local spec = self.spec_connectionHoses |
1613 | for i=1, #part.customTargetIndices do |
1614 | local customTargetIndex = part.customTargetIndices[i] |
1615 | local customTarget = spec.customHoseTargets[customTargetIndex] |
1616 | if customTarget ~= nil and customTarget.isActive then |
1617 | self:updateCustomHoseNode(customTarget.connectedHose, customTarget) |
1618 | end |
1619 | end |
1620 | end |
1621 | end |
updateToolConnectionHose
DescriptionDefinitionupdateToolConnectionHose()Code
1226 | function ConnectionHoses:updateToolConnectionHose(sourceObject, sourceHose, targetObject, targetHose, visibility) |
1227 | local spec = self.spec_connectionHoses |
1228 | |
1229 | local function setTargetNodeTranslation(hose) |
1230 | if hose.originalNodeTranslation == nil then |
1231 | hose.originalNodeTranslation = {getTranslation(hose.node)} |
1232 | else |
1233 | setTranslation(hose.node, unpack(hose.originalNodeTranslation)) |
1234 | end |
1235 | local wx, wy, wz = localToWorld(hose.node, 0, sourceHose.diameter*0.5, 0) |
1236 | local lx, ly, lz = worldToLocal(getParent(hose.node), wx, wy, wz) |
1237 | setTranslation(hose.node, lx, ly, lz) |
1238 | end |
1239 | |
1240 | local toolConnectionHose = spec.targetNodeToToolConnection[targetHose.index] |
1241 | if toolConnectionHose ~= nil then |
1242 | local opositTargetIndex = toolConnectionHose.startTargetNodeIndex |
1243 | if opositTargetIndex == targetHose.index then |
1244 | opositTargetIndex = toolConnectionHose.endTargetNodeIndex |
1245 | end |
1246 | local opositTarget = spec.targetNodes[opositTargetIndex] |
1247 | |
1248 | if opositTarget ~= nil then |
1249 | if visibility and toolConnectionHose.delayedMounting ~= nil and toolConnectionHose.delayedMounting.sourceHose.connectedObject == nil then |
1250 | local differentSource = toolConnectionHose.delayedMounting.sourceObject ~= sourceObject -- with the retryHoseSkipNodeConnections functionallity it can happen that the object is the same |
1251 | local sameType = toolConnectionHose.delayedMounting.sourceHose.type == sourceHose.type |
1252 | and toolConnectionHose.delayedMounting.sourceHose.specType == sourceHose.specType |
1253 | if differentSource and sameType then |
1254 | local x, y, z = localToLocal(targetHose.node, opositTarget.node, 0, 0, 0) |
1255 | local length = MathUtil.vector3Length(x, y, z) |
1256 | |
1257 | if toolConnectionHose.additionalHose then |
1258 | local hose, _, _, _ = g_connectionHoseManager:getClonedHoseNode(sourceHose.type, sourceHose.hoseType, length, sourceHose.diameter, sourceHose.color, self.customEnvironment) |
1259 | |
1260 | if hose ~= nil then |
1261 | link(targetHose.node, hose) |
1262 | setTranslation(hose, 0, 0, 0) |
1263 | |
1264 | local dirX, dirY, dirZ = localToLocal(hose, opositTarget.node, 0, 0, 0) |
1265 | if dirX ~= 0 or dirY ~= nil or dirZ ~= nil then |
1266 | setDirection(hose, dirX, dirY, dirZ, 0, 0, 1) |
1267 | |
1268 | setShaderParameter(hose, "cv0", 0, 0, -dirZ*0.5, 0, false) |
1269 | setShaderParameter(hose, "cv2", dirX*0.5+0.003, dirY*0.5, dirZ*0.5, 0, false) -- center point |
1270 | setShaderParameter(hose, "cv3", dirX-0.003, dirY, dirZ, 0, false) -- target point |
1271 | setShaderParameter(hose, "cv4", dirX-0.003, dirY, dirZ+dirZ*0.5, 0, false) -- end straightening point |
1272 | end |
1273 | |
1274 | if toolConnectionHose.moveNodes then |
1275 | setTargetNodeTranslation(targetHose) |
1276 | setTargetNodeTranslation(opositTarget) |
1277 | end |
1278 | |
1279 | sourceObject:addAllSubWashableNodes(hose) |
1280 | |
1281 | toolConnectionHose.hoseNode = hose |
1282 | toolConnectionHose.hoseNodeObject = sourceObject |
1283 | else |
1284 | return false |
1285 | end |
1286 | end |
1287 | |
1288 | toolConnectionHose.connected = true |
1289 | |
1290 | if toolConnectionHose.mountingNode ~= nil then |
1291 | setVisibility(toolConnectionHose.mountingNode, true) |
1292 | end |
1293 | |
1294 | -- connect the first attached hose to the tool connection |
1295 | if toolConnectionHose.delayedMounting ~= nil then |
1296 | toolConnectionHose.delayedUnmounting = {} |
1297 | table.insert(toolConnectionHose.delayedUnmounting, toolConnectionHose.delayedMounting) |
1298 | table.insert(toolConnectionHose.delayedUnmounting, {sourceObject=sourceObject, sourceHose=sourceHose, targetObject=targetObject, targetHose=targetHose}) |
1299 | |
1300 | local delayedHose = toolConnectionHose.delayedMounting |
1301 | toolConnectionHose.delayedMounting = nil |
1302 | delayedHose.sourceObject:connectHose(delayedHose.sourceHose, delayedHose.targetObject, delayedHose.targetHose, false) |
1303 | delayedHose.sourceObject:retryHoseSkipNodeConnections(false) |
1304 | end |
1305 | |
1306 | return true |
1307 | end |
1308 | else |
1309 | if toolConnectionHose.connected then |
1310 | toolConnectionHose.connected = false |
1311 | |
1312 | if toolConnectionHose.hoseNode ~= nil then |
1313 | toolConnectionHose.hoseNodeObject:removeAllSubWashableNodes(toolConnectionHose.hoseNode) |
1314 | |
1315 | delete(toolConnectionHose.hoseNode) |
1316 | toolConnectionHose.hoseNode = nil |
1317 | toolConnectionHose.hoseNodeObject = nil |
1318 | end |
1319 | |
1320 | if toolConnectionHose.mountingNode ~= nil then |
1321 | setVisibility(toolConnectionHose.mountingNode, false) |
1322 | end |
1323 | |
1324 | -- remove the second hose connection from the tool connection |
1325 | -- but keep it as delayed mounting |
1326 | -- if is hose from skip node, completly remove it (will be recreated depending on sub attached tool) |
1327 | if toolConnectionHose.delayedUnmounting ~= nil then |
1328 | for _, hose in ipairs(toolConnectionHose.delayedUnmounting) do |
1329 | if sourceHose ~= hose.sourceHose then |
1330 | hose.sourceObject:disconnectHose(hose.sourceHose) |
1331 | if hose.sourceHose.isClonedSkipNodeHose == nil or not hose.sourceHose.isClonedSkipNodeHose then |
1332 | toolConnectionHose.delayedMounting = hose |
1333 | end |
1334 | end |
1335 | end |
1336 | |
1337 | toolConnectionHose.delayedUnmounting = nil |
1338 | end |
1339 | end |
1340 | end |
1341 | end |
1342 | else |
1343 | return true |
1344 | end |
1345 | |
1346 | return false |
1347 | end |