├── .github └── workflows │ └── luacheck.yml ├── .gitignore ├── .imgs └── modROS.png ├── .luacheckrc ├── LICENSE ├── README.md ├── modDesc.xml ├── src ├── loader.lua ├── modROS.lua ├── mod_config.lua ├── msgs │ ├── geometry_msgs_transform_stamped.lua │ ├── nav_msgs_odometry.lua │ ├── rosgraph_msgs_clock.lua │ ├── sensor_msgs_imu.lua │ ├── sensor_msgs_laser_scan.lua │ └── tf2_msgs_tf_message.lua ├── ros │ ├── Publisher.lua │ └── WriteOnlyFileConnection.lua ├── utils │ ├── LaserScanner.lua │ ├── frames.lua │ ├── json.lua │ ├── ros.lua │ ├── shared_memory_segment.lua │ └── vehicle_util.lua └── vehicles │ └── RosVehicle.lua └── store.dds /.github/workflows/luacheck.yml: -------------------------------------------------------------------------------- 1 | name: luacheck 2 | 3 | on: 4 | push: 5 | pull_request: 6 | # allow manually starting this workflow 7 | workflow_dispatch: 8 | 9 | jobs: 10 | luacheck: 11 | name: Luacheck 12 | runs-on: ubuntu-20.04 13 | 14 | steps: 15 | - name: Fetch repository 16 | uses: actions/checkout@v2 17 | - name: Run luacheck 18 | uses: nebularg/actions-luacheck@v1 19 | with: 20 | files: src/ 21 | annotate: warning 22 | # ignore vehicle_utils.lua only in the CI config (not our main 23 | # luacheckrc). We ignore it until we fix it (bad), but get reminded 24 | # about it needing fixes on every local luacheck run. 25 | args: --exclude-files src/utils//vehicle_util.lua 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ignore symbolic link to named pipe ROS_messages 2 | ROS_messages 3 | -------------------------------------------------------------------------------- /.imgs/modROS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tud-cor/FS19_modROS/4356362b6e04060cfee5c103cd249b896ccba8ab/.imgs/modROS.png -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | 2 | std = "lua51+fs19_vars+fs19_other+fs19_funcs+modROS+ext_deps" 3 | 4 | -- don't complain about unused self args 5 | self = false 6 | 7 | ignore = { 8 | "631" -- line too long 9 | } 10 | 11 | -- don't complain about files not under our control 12 | exclude_files = {"src/utils/json.lua", "src/utils/shared_memory_segment.lua"} 13 | 14 | stds.modROS = { 15 | globals = { 16 | "ModROS", 17 | "g_modROSModDirectory", 18 | "g_modROSModName", 19 | "geometry_msgs_TransformStamped", 20 | "nav_msgs_Odometry", 21 | "ros", 22 | "rosgraph_msgs_Clock", 23 | "sensor_msgs_Imu", 24 | "sensor_msgs_LaserScan", 25 | "tf2_msgs_TFMessage", 26 | "vehicle_util", 27 | "mod_config", 28 | "frames", 29 | "Publisher", 30 | "WriteOnlyFileConnection", 31 | "LaserScanner", 32 | "RosVehicle", 33 | } 34 | } 35 | 36 | stds.ext_deps = { 37 | globals = { 38 | "json", 39 | "SharedMemorySegment" 40 | } 41 | } 42 | 43 | -- globals based on: https://github.com/scfmod/fs19_lua/blob/master/dump.lua 44 | stds.fs19_vars = { 45 | globals = { 46 | }, 47 | read_globals = { 48 | "coroutine", 49 | "deform", 50 | "g_achievementManager", 51 | "g_achievementsScreen", 52 | "g_addCheatCommands", 53 | "g_addTestCommands", 54 | "g_ambientSoundManager", 55 | "g_analogStickHTolerance", 56 | "g_analogStickVTolerance", 57 | "g_animalDialog", 58 | "g_animalFoodManager", 59 | "g_animalManager", 60 | "g_animalNameManager", 61 | "g_animalScreen", 62 | "g_animationManager", 63 | "g_animCache", 64 | "g_aspectScaleX", 65 | "g_aspectScaleY", 66 | "g_asyncManager", 67 | "g_autoSaveManager", 68 | "g_availableLanguageNamesTable", 69 | "g_availableLanguagesTable", 70 | "g_baleTypeManager", 71 | "g_baseHUDFilename", 72 | "g_baseUIFilename", 73 | "g_baseUIPostfix", 74 | "g_brandColorManager", 75 | "g_brandManager", 76 | "g_buildName", 77 | "g_buildTypeParam", 78 | "g_careerScreen", 79 | "g_characterSelectionScreen", 80 | "g_chatDialog", 81 | "g_client", 82 | "g_clientInterpDelay", 83 | "g_clientInterpDelayAdjustDown", 84 | "g_clientInterpDelayAdjustUp", 85 | "g_clientInterpDelayBufferMax", 86 | "g_clientInterpDelayBufferMin", 87 | "g_clientInterpDelayBufferOffset", 88 | "g_clientInterpDelayBufferScale", 89 | "g_clientInterpDelayMax", 90 | "g_clientInterpDelayMin", 91 | "g_colorBg", 92 | "g_colorBgUVs", 93 | "g_colorPickerDialog", 94 | "g_configurationManager", 95 | "g_connectionFailedDialog", 96 | "g_connectionHoseManager", 97 | "g_connectionManager", 98 | "g_connectToMasterServerScreen", 99 | "g_createGameScreen", 100 | "g_creditsScreen", 101 | "g_curNumLoadingBarStep", 102 | "g_currentDt", 103 | "g_currentMission", 104 | "g_currentModDirectory", -- not listed on https://github.com/scfmod/fs19_lua/blob/master/dump.lua 105 | "g_currentModName", -- not listed on https://github.com/scfmod/fs19_lua/blob/master/dump.lua 106 | "g_cutterEffectManager", 107 | "g_debugManager", 108 | "g_dedicatedServerMaxFrameLimit", 109 | "g_dedicatedServerMinFrameLimit", 110 | "g_defaultCamera", 111 | "g_deferredLoadingManager", 112 | "g_densityMapHeightManager", 113 | "g_densityMapRevision", 114 | "g_denyAcceptDialog", 115 | "g_depthOfFieldManager", 116 | "g_difficultyScreen", 117 | "g_directSellDialog", 118 | "g_dlcModNameHasPrefix", 119 | "g_dlcsDirectories", 120 | "g_drawGuiHelper", 121 | "g_effectManager", 122 | "g_farmlandManager", 123 | "g_farmManager", 124 | "g_fieldManager", 125 | "g_fillTypeManager", 126 | "g_flightAndNoHUDKeysEnabled", 127 | "g_forceDefaultPCButtons", 128 | "g_forceNeedsDlcsAndModsReload", 129 | "g_fovYDefault", 130 | "g_fovYMax", 131 | "g_fovYMin", 132 | "g_fruitTypeManager", 133 | "g_gameplayHintManager", 134 | "g_gameRevision", 135 | "g_gameSettings", 136 | "g_gameStateManager", 137 | "g_gameStatsXMLPathgameStats.xml',", 138 | "g_gameVersion", 139 | "g_gameVersionDisplay", 140 | "g_gameVersionDisplayExtra", 141 | "g_gameVersionNotification", 142 | "g_gamingStationManager", 143 | "g_groundTypeManager", 144 | "g_gui", 145 | "g_guiHelperSteps", 146 | "g_hasLicenseError", 147 | "g_helperManager", 148 | "g_helpLineManager", 149 | "g_i18n", 150 | "g_i3DManager", 151 | "g_infoDialog", 152 | "g_inputBinding", 153 | "g_inputDisplayManager", 154 | "g_isAppSuspended", 155 | "g_isConsoleSimulationActive", 156 | "g_isDevelopmentVersion", 157 | "g_isPresentationVersion", 158 | "g_isPresentationVersionAIDeactivated", 159 | "g_isPresentationVersionAllMapsEnabled", 160 | "g_isPresentationVersionDlcEnabled", 161 | "g_isPresentationVersionHideMenuButtons", 162 | "g_isPresentationVersionLogoEnabled", 163 | "g_isPresentationVersionShopEnabled", 164 | "g_isPresentationVersionSpecialStore", 165 | "g_isPresentationVersionSpecialStorePath", 166 | "g_isReloadingDlcs", 167 | "g_isServerStreamingVersion", 168 | "g_isSignedIn", 169 | "g_joinGameScreen", 170 | "g_language", 171 | "g_languageShort", 172 | "g_languageSuffix", 173 | "g_lastCheckDlcPaths", 174 | "g_lastMousePosX", 175 | "g_lastMousePosY", 176 | "g_lastTouchPosX", 177 | "g_lastTouchPosY", 178 | "g_logManager", 179 | "g_mainScreen", 180 | "g_manualGearShift", 181 | "g_mapManager", 182 | "g_mapSelectionScreen", 183 | "g_masterServerConnection", 184 | "g_materialManager", 185 | "g_maxModDescVersion", 186 | "g_maxNumLoadingBarSteps", 187 | "g_maxNumRealVehicleLights", 188 | "g_maxUploadRate", 189 | "g_maxUploadRatePerClient", 190 | "g_menuMusic", 191 | "g_menuMusicIsPlayingStarted", 192 | "g_messageCenter", 193 | "g_messageDialog", 194 | "g_minModDescVersion", 195 | "g_mission00StartPoint", 196 | "g_missionManager", 197 | "g_modEventListeners", 198 | "g_modHubScreen", 199 | "g_modIsLoaded", 200 | "g_modManager", 201 | "g_modNameToDirectory", 202 | "g_modsDirectory", 203 | "g_modSelectionScreen", 204 | "g_mpLoadingScreen", 205 | "g_multiplayerScreen", 206 | "g_networkDebug", 207 | "g_networkDebugPrints", 208 | "g_networkTime", 209 | "g_npcManager", 210 | "g_packetPhysicsNetworkTime", 211 | "g_particleSystemManager", 212 | "g_passwordDialog", 213 | "g_physicsDt", 214 | "g_physicsDtLastValidNonInterpolated", 215 | "g_physicsDtNonInterpolated", 216 | "g_physicsDtUnclamped", 217 | "g_physicsNetworkTime", 218 | "g_physicsTimeLooped", 219 | "g_placeableTypeManager", 220 | "g_placementCollisionRevision", 221 | "g_plattformPrefix", 222 | "g_playerColors", 223 | "g_playerModelManager", 224 | "g_preorderBonusManager", 225 | "g_presentedScreenAspectRatio", 226 | "g_prevNetworkTime", 227 | "g_referenceScreenHeight", 228 | "g_referenceScreenWidth", 229 | "g_registeredConsoleCommands", 230 | "g_safeFrameOffsetX", 231 | "g_safeFrameOffsetY", 232 | "g_savegamePath", 233 | "g_savegameXML", 234 | "g_screenAspectRatio", 235 | "g_screenHeight", 236 | "g_screenshotsDirectory", 237 | "g_screenWidth", 238 | "g_selectMasterServerScreen", 239 | "g_sellItemDialog", 240 | "g_server", 241 | "g_serverDetailScreen", 242 | "g_serverMaxCapacity", 243 | "g_serverMinCapacity", 244 | "g_settingsLanguageGUI", 245 | "g_settingsScreen", 246 | "g_shopConfigScreen", 247 | "g_showDeeplinkingFailedMessage", 248 | "g_showDevelopmentWarnings", 249 | "g_showSafeFrame", 250 | "g_showWatermark", 251 | "g_siloDialog", 252 | "g_sleepManager", 253 | "g_soundManager", 254 | "g_soundMixer", 255 | "g_soundPlayer", 256 | "g_specializationManager", 257 | "g_splitShapesRevision", 258 | "g_splitTypeManager", 259 | "g_sprayTypeManager", 260 | "g_startupScreen", 261 | "g_storeManager", 262 | "g_tensionBeltManager", 263 | "g_terrainDeformationQueue", 264 | "g_terrainLodTextureRevision", 265 | "g_textInputDialog", 266 | "g_time", 267 | "g_tipCollisionRevision", 268 | "g_toolTypeManager", 269 | "g_treePlantManager", 270 | "g_tutorialScreen", 271 | "g_uiDebugEnabled", 272 | "g_uniqueDlcNamePrefix", 273 | "g_updateLoopIndex", 274 | "g_updateNetworkTime", 275 | "g_vehicleColors", 276 | "g_vehicleTypeManager", 277 | "g_weatherTypeManager", 278 | "g_wildlifeSpawnerManager", 279 | "g_woodCuttingMarkerEnabled", 280 | "g_workAreaTypeManager", 281 | "g_yesNoDialog", 282 | "io", 283 | "math", 284 | "modOnCreate", 285 | "ssIcePlane", 286 | "ssSeasonAdmirer", 287 | "ssSnowAdmirer", 288 | "string", 289 | "table", 290 | } 291 | } 292 | 293 | stds.fs19_other = { 294 | globals = { 295 | "VehicleTypeManager", 296 | }, 297 | read_globals = { 298 | "_VERSION", 299 | "AbstractAnimalStrategy", 300 | "AbstractFieldMission", 301 | "AbstractManager", 302 | "AbstractMission", 303 | "AccessHandler", 304 | "AchievementManager", 305 | "AchievementMessage", 306 | "AchievementsScreen", 307 | "AIConveyorBelt", 308 | "AIConveyorBeltSetAngleEvent", 309 | "AIDriveStrategy", 310 | "AIDriveStrategyBaler", 311 | "AIDriveStrategyCollision", 312 | "AIDriveStrategyCombine", 313 | "AIDriveStrategyConveyor", 314 | "AIDriveStrategyStraight", 315 | "AIImplement", 316 | "AITurnStrategy", 317 | "AITurnStrategyBulb1", 318 | "AITurnStrategyBulb1Reverse", 319 | "AITurnStrategyBulb2", 320 | "AITurnStrategyBulb2Reverse", 321 | "AITurnStrategyBulb3", 322 | "AITurnStrategyBulb3Reverse", 323 | "AITurnStrategyDefault", 324 | "AITurnStrategyDefaultReverse", 325 | "AITurnStrategyHalfCircle", 326 | "AITurnStrategyHalfCircleReverse", 327 | "AIVehicle", 328 | "AIVehicleIsBlockedEvent", 329 | "AIVehicleSetStartedEvent", 330 | "AIVehicleUtil", 331 | "AmbientSoundManager", 332 | "AmbientSoundUtil", 333 | "Animal", 334 | "AnimalAddEvent", 335 | "AnimalCleanEvent", 336 | "AnimalController", 337 | "AnimalDealerEvent", 338 | "AnimalDialog", 339 | "AnimalFoodManager", 340 | "AnimalHusbandry", 341 | "AnimalHusbandryNoMorePalletSpaceEvent", 342 | "AnimalItem", 343 | "AnimalLoadingTrigger", 344 | "AnimalManager", 345 | "AnimalNameEvent", 346 | "AnimalNameManager", 347 | "AnimalRemoveEvent", 348 | "AnimalRidingEvent", 349 | "AnimalScreen", 350 | "AnimatedMapObject", 351 | "AnimatedObject", 352 | "AnimatedObjectEvent", 353 | "AnimatedVehicle", 354 | "AnimatedVehicleStartEvent", 355 | "AnimatedVehicleStopEvent", 356 | "Animation", 357 | "AnimationCache", 358 | "AnimationElement", 359 | "AnimationManager", 360 | "AnimCurve", 361 | "ArticulatedAxis", 362 | "AsyncManager", 363 | "Attachable", 364 | "AttacherJointControl", 365 | "AttacherJoints", 366 | "AudioGroup", 367 | "AutoSaveManager", 368 | "Bale", 369 | "BaleGrab", 370 | "BaleLoader", 371 | "BaleLoaderStateEvent", 372 | "BaleMission", 373 | "Baler", 374 | "BalerCreateBaleEvent", 375 | "BalerSetBaleTimeEvent", 376 | "BalerSetIsUnloadingBaleEvent", 377 | "BaleType", 378 | "BaleTypeManager", 379 | "BaleWrapper", 380 | "BaleWrapperStateEvent", 381 | "BanStorage", 382 | "Barrier", 383 | "BaseMaterial", 384 | "BaseMission", 385 | "BaseMissionFinishedLoadingEvent", 386 | "BaseMissionReadyEvent", 387 | "Basketball", 388 | "BasketTrigger", 389 | "BeehivePlaceable", 390 | "Bga", 391 | "BgaPlaceable", 392 | "BgaSellStation", 393 | "Binding", 394 | "BitmapElement", 395 | "BoxLayoutElement", 396 | "Brand", 397 | "BrandColorManager", 398 | "BrandManager", 399 | "BreadcrumbsElement", 400 | "BunkerSilo", 401 | "BunkerSiloActivatable", 402 | "BunkerSiloCloseEvent", 403 | "BunkerSiloCompacter", 404 | "BunkerSiloInteractor", 405 | "BunkerSiloOpenEvent", 406 | "BunkerSiloPlaceable", 407 | "Butterfly", 408 | "ButtonElement", 409 | "ButtonOverlay", 410 | "BuyableBale", 411 | "BuyHandToolEvent", 412 | "BuyingStation", 413 | "BuyingStationPlaceable", 414 | "BuyObjectEvent", 415 | "BuyPlaceableEvent", 416 | "BuyVehicleEvent", 417 | "CameraFlightManager", 418 | "CameraPath", 419 | "Can", 420 | "CareerScreen", 421 | "CCTDrivable", 422 | "Chainsaw", 423 | "ChainsawCutEvent", 424 | "ChainsawDelimbEvent", 425 | "ChainsawSoundStateActive", 426 | "ChainsawSoundStateCut", 427 | "ChainsawSoundStateIdle", 428 | "ChainsawSoundStateQuicktap", 429 | "ChainsawSoundStateStart", 430 | "ChainsawSoundStateStop", 431 | "ChainsawStateEvent", 432 | "ChainsawUtil", 433 | "ChangeLoanEvent", 434 | "ChangeVehicleConfigEvent", 435 | "CharacterCreationScreen", 436 | "ChatDialog", 437 | "ChatEvent", 438 | "ChatWindow", 439 | "CheatMoneyEvent", 440 | "CheckedOptionElement", 441 | "ChurchClock", 442 | "ClassIds", 443 | "ClassUtil", 444 | "Client", 445 | "ClientStartMissionEvent", 446 | "CloudUpdater", 447 | "Colorizer", 448 | "ColorPickerDialog", 449 | "Combine", 450 | "CombineStrawEnableEvent", 451 | "ConfigurationManager", 452 | "ConfigurationUtil", 453 | "Connection", 454 | "ConnectionFailedDialog", 455 | "ConnectionHoseManager", 456 | "ConnectionHoses", 457 | "ConnectionHoseType", 458 | "ConnectionManager", 459 | "ConnectionRequestAnswerEvent", 460 | "ConnectionRequestEvent", 461 | "ConnectToMasterServerScreen", 462 | "ContextActionDisplay", 463 | "ContractingStateEvent", 464 | "ControlsController", 465 | "ConveyorBelt", 466 | "ConveyorBeltEffect", 467 | "Cover", 468 | "CrabSteering", 469 | "Crawlers", 470 | "CreateGameScreen", 471 | "CreditsScreen", 472 | "CrowSoundStateBusy", 473 | "CrowSoundStateCalmAir", 474 | "CrowSoundStateCalmGround", 475 | "CrowSoundStateDefault", 476 | "CrowSoundStateTakeOff", 477 | "CrowStateDefault", 478 | "CrowStateFly", 479 | "CrowStateFlyGlide", 480 | "CrowStateIdleAttention", 481 | "CrowStateIdleEat", 482 | "CrowStateIdleWalk", 483 | "CrowStateLand", 484 | "CrowStateTakeOff", 485 | "CrowsWildlife", 486 | "CultivateMission", 487 | "Cultivator", 488 | "Cutter", 489 | "CutterEffect", 490 | "CutterEffectManager", 491 | "CutterEffectType", 492 | "Cylindered", 493 | "CylinderedEasyControlChangeEvent", 494 | "CylinderedFoldable", 495 | "DailySound", 496 | "Dashboard", 497 | "DataGrid", 498 | "DealerFarmStrategie", 499 | "DealerStrategie", 500 | "DealerTrailerStrategie", 501 | "DebugCube", 502 | "DebugGizmo", 503 | "DebugInfoTable", 504 | "DebugManager", 505 | "DebugRendering", 506 | "DebugText", 507 | "DebugUtil", 508 | "DeferredLoadingManager", 509 | "DensityMapFilter", 510 | "DensityMapHeightManager", 511 | "DensityMapHeightModifier", 512 | "DensityMapHeightUtil", 513 | "DensityMapModifier", 514 | "DenyAcceptDialog", 515 | "DepthOfFieldManager", 516 | "DialogElement", 517 | "DifficultyScreen", 518 | "DigitalDisplay", 519 | "DirectSellDialog", 520 | "Dischargeable", 521 | "DisplayActionBinding", 522 | "Dog", 523 | "DogBall", 524 | "DogFeedEvent", 525 | "DogFetchItemEvent", 526 | "DogFollowEvent", 527 | "Doghouse", 528 | "DogPetEvent", 529 | "Drivable", 530 | "DynamicallyLoadedParts", 531 | "DynamicMountAttacher", 532 | "DynamicMountUtil", 533 | "EconomyManager", 534 | "EditFarmDialog", 535 | "Effect", 536 | "EffectManager", 537 | "ElkTrigger", 538 | "Enterable", 539 | "Environment", 540 | "EnvironmentTimeEvent", 541 | "Event", 542 | "EventIds", 543 | "Farm", 544 | "FarmCreateUpdateEvent", 545 | "FarmDestroyEvent", 546 | "FarmhousePlaceable", 547 | "Farmland", 548 | "FarmlandInitialStateEvent", 549 | "FarmlandManager", 550 | "FarmlandStateEvent", 551 | "FarmManager", 552 | "FarmsInitialStateEvent", 553 | "FarmStats", 554 | "FarmTrailerEvent", 555 | "FertilizeMission", 556 | "FertilizingCultivator", 557 | "FertilizingSowingMachine", 558 | "Field", 559 | "FieldCropsQuery", 560 | "FieldCropsUpdaterConstructor", 561 | "FieldInfoDisplay", 562 | "FieldManager", 563 | "FieldUtil", 564 | "FileAccess", 565 | "Files", 566 | "FillActivatable", 567 | "FillLevelListener", 568 | "FillLevelsDisplay", 569 | "FillPlane", 570 | "FillTrigger", 571 | "FillTriggerPlaceable", 572 | "FillTriggerVehicle", 573 | "FillType", 574 | "FillTypeCategory", 575 | "FillTypeManager", 576 | "FillUnit", 577 | "FillUnitUnloadEvent", 578 | "FillVolume", 579 | "FinanceStats", 580 | "FinanceStatsEvent", 581 | "FlowLayoutElement", 582 | "FocusManager", 583 | "FogStateEvent", 584 | "FogUpdater", 585 | "Foldable", 586 | "FoldableSetFoldDirectionEvent", 587 | "FoliageBending", 588 | "FoliageBendingSystem", 589 | "FoliageTransformGroupConstructor", 590 | "FoliageXmlUtil", 591 | "FollowerSound", 592 | "ForageWagon", 593 | "FrameElement", 594 | "FrameReferenceElement", 595 | "FrontloaderAttacher", 596 | "FruitPreparer", 597 | "FruitType", 598 | "FruitTypeCategory", 599 | "FruitTypeConverter", 600 | "FruitTypeManager", 601 | "FSBaseMission", 602 | "FSCareerMissionInfo", 603 | "FSDensityMapModifier", 604 | "FSDensityMapUtil", 605 | "FSMissionInfo", 606 | "FSMUtil", 607 | "FSTutorialMissionInfo", 608 | "GameInfoDisplay", 609 | "GamepadCategories", 610 | "GamepadHelper", 611 | "GamepadSigninScreen", 612 | "GamePausedDisplay", 613 | "GamePauseEvent", 614 | "GameplayHintManager", 615 | "GameSettings", 616 | "GameState", 617 | "GameStateManager", 618 | "GamingStationManager", 619 | "GetAdminAnswerEvent", 620 | "GetAdminEvent", 621 | "GetBansEvent", 622 | "Graph", 623 | "GreatDemandsEvent", 624 | "GreatDemandSpecs", 625 | "GreenhousePlaceable", 626 | "GreenhousePlaceableWaterTankActivatable", 627 | "GreenhouseSetIsWaterTankFillingEvent", 628 | "GroundAdjustedNodes", 629 | "GroundReference", 630 | "GroundTypeManager", 631 | "GS_INPUT_HELP_MODE_AUTO", 632 | "GS_INPUT_HELP_MODE_GAMEPAD", 633 | "GS_INPUT_HELP_MODE_KEYBOARD", 634 | "GS_IS_CONSOLE_VERSION", 635 | "GS_IS_MAC_APP_STORE_VERSION", 636 | "GS_IS_STEAM_VERSION", 637 | "GS_MONEY_DOLLAR", 638 | "GS_MONEY_EURO", 639 | "GS_MONEY_POUND", 640 | "GS_PERFORMANCE_CLASS_PRESETS", 641 | "GS_PLATFORM_TYPE", 642 | "GS_PLATFORM_TYPE_ANDROID", 643 | "GS_PLATFORM_TYPE_IOS", 644 | "GS_PLATFORM_TYPE_PC", 645 | "GS_PLATFORM_TYPE_PS4", 646 | "GS_PLATFORM_TYPE_SWITCH", 647 | "GS_PLATFORM_TYPE_XBOXONE", 648 | "GS_PRIO_HIGH", 649 | "GS_PRIO_LOW", 650 | "GS_PRIO_NORMAL", 651 | "GS_PRIO_VERY_HIGH", 652 | "GS_PRIO_VERY_LOW", 653 | "GS_PRODUCT_ID", 654 | "GS_PROFILE_HIGH", 655 | "GS_PROFILE_LOW", 656 | "GS_PROFILE_MEDIUM", 657 | "GS_PROFILE_VERY_HIGH", 658 | "Gui", 659 | "GuiDataSource", 660 | "GuiElement", 661 | "GuiMixin", 662 | "GuiOverlay", 663 | "GuiProfile", 664 | "GuiSoundPlayer", 665 | "GuiTopDownCamera", 666 | "GuiUtils", 667 | "HandTool", 668 | "HarvestMission", 669 | "HeatingPlantPlaceable", 670 | "HelperManager", 671 | "HelpIcons", 672 | "HelpLineManager", 673 | "HighPressureWasher", 674 | "HighPressureWasherActivatable", 675 | "HighPressureWasherLance", 676 | "Honk", 677 | "HonkEvent", 678 | "HookLiftContainer", 679 | "HookLiftTrailer", 680 | "Horse", 681 | "HotspotTrigger", 682 | "HPWLanceStateEvent", 683 | "HPWPlaceableTurnOnEvent", 684 | "HTMLUtil", 685 | "HUD", 686 | "HUDDisplayElement", 687 | "HUDElement", 688 | "HUDFrameElement", 689 | "HUDPopupMessage", 690 | "HUDTextDisplay", 691 | "HusbandryModuleAnimal", 692 | "HusbandryModuleBase", 693 | "HusbandryModuleFood", 694 | "HusbandryModuleFoodSpillage", 695 | "HusbandryModuleLiquidManure", 696 | "HusbandryModuleManure", 697 | "HusbandryModuleMilk", 698 | "HusbandryModulePallets", 699 | "HusbandryModuleStraw", 700 | "HusbandryModuleWater", 701 | "I18N", 702 | "I3DManager", 703 | "I3DUtil", 704 | "IKChain", 705 | "IKChains", 706 | "IKUtil", 707 | "InAppPurchase", 708 | "IndexChangeSubjectMixin", 709 | "IndexStateElement", 710 | "InfoDialog", 711 | "InGameIcon", 712 | "IngameMap", 713 | "IngameMapElement", 714 | "InGameMenu", 715 | "InGameMenuAnimalsFrame", 716 | "InGameMenuContractsFrame", 717 | "InGameMenuFinancesFrame", 718 | "InGameMenuGameSettingsFrame", 719 | "InGameMenuGeneralSettingsFrame", 720 | "InGameMenuHelpFrame", 721 | "InGameMenuMapFrame", 722 | "InGameMenuMultiplayerFarmsFrame", 723 | "InGameMenuMultiplayerUsersFrame", 724 | "InGameMenuPricesFrame", 725 | "InGameMenuStatisticsFrame", 726 | "InGameMenuTutorialFrame", 727 | "InGameMenuVehiclesFrame", 728 | "Input", 729 | "InputAction", 730 | "InputBinding", 731 | "InputDevice", 732 | "InputDisplayManager", 733 | "InputEvent", 734 | "InputGlyphElement", 735 | "InputHelpDisplay", 736 | "InputHelpElement", 737 | "InsideBuildingTrigger", 738 | "InterpolationTime", 739 | "InterpolatorAngle", 740 | "InterpolatorPosition", 741 | "InterpolatorQuaternion", 742 | "InterpolatorValue", 743 | "JigglingParts", 744 | "JoinGameScreen", 745 | "JointConstructor", 746 | "JumpEvent", 747 | "KeyboardHelper", 748 | "KickBanEvent", 749 | "KickBanNotificationEvent", 750 | "Landscaping", 751 | "LandscapingScreen", 752 | "LandscapingScreenController", 753 | "LandscapingSculptEvent", 754 | "Leveler", 755 | "LevelerEffect", 756 | "Lighting", 757 | "Lights", 758 | "LightWildlife", 759 | "LightWildlifeAnimal", 760 | "LightWildlifeStateDefault", 761 | "ListElement", 762 | "ListItemElement", 763 | "ListUtil", 764 | "LivestockTrailer", 765 | "LoadingStation", 766 | "LoadTrigger", 767 | "LoadTriggerSetIsLoadingEvent", 768 | "LoanTrigger", 769 | "Locomotive", 770 | "LogGrab", 771 | "LogManager", 772 | "MainScreen", 773 | "ManureBarrel", 774 | "MapDataGrid", 775 | "MapHotspot", 776 | "MapManager", 777 | "MapOverlayGenerator", 778 | "MapPerformanceTestUtil", 779 | "MapSelectionScreen", 780 | "MasterServerConnection", 781 | "MaterialManager", 782 | "MaterialType", 783 | "MaterialUtil", 784 | "MathUtil", 785 | "MeshEvent", 786 | "MessageCenter", 787 | "MessageDialog", 788 | "MessageIds", 789 | "MessageType", 790 | "Mission00", 791 | "MissionCancelEvent", 792 | "MissionCollaborators", 793 | "MissionDismissEvent", 794 | "MissionDynamicInfoEvent", 795 | "MissionFinishedEvent", 796 | "MissionInfo", 797 | "MissionManager", 798 | "MissionPhysicsObject", 799 | "MissionStartedEvent", 800 | "MissionStartEvent", 801 | "MixerWagon", 802 | "MixerWagonBaleNotAcceptedEvent", 803 | "MixerWagonHUDExtension", 804 | "ModCategoryInfo", 805 | "ModHubCategoriesFrame", 806 | "ModHubController", 807 | "ModHubDetailsFrame", 808 | "ModHubItemsFrame", 809 | "ModHubLoadingFrame", 810 | "ModHubScreen", 811 | "ModInfo", 812 | "ModManager", 813 | "ModSelectionScreen", 814 | "MoneyChangeEvent", 815 | "MoneyType", 816 | "MorphPositionEffect", 817 | "Motorized", 818 | "Mountable", 819 | "MountableObject", 820 | "MouseHelper", 821 | "Mower", 822 | "MowerToggleWindrowDropEvent", 823 | "MPLoadingScreen", 824 | "MultiplayerAvailability", 825 | "MultiplayerScreen", 826 | "MultiTextOptionElement", 827 | "MultiValueTween", 828 | "NATType", 829 | "Network", 830 | "NetworkNode", 831 | "NetworkUtil", 832 | "NightGlower", 833 | "NightIllumination", 834 | "Nightlight", 835 | "Nightlight2", 836 | "NightlightFlicker", 837 | "NPCManager", 838 | "Object", 839 | "ObjectChangeUtil", 840 | "ObjectFarmChangeEvent", 841 | "ObjectIds", 842 | "ObjectSpawner", 843 | "OilPump", 844 | "OnCreateLoadedObjectEvent", 845 | "Overlay", 846 | "PagingElement", 847 | "PalletSellTrigger", 848 | "ParticleEffect", 849 | "ParticleSystemManager", 850 | "ParticleType", 851 | "ParticleUtil", 852 | "PedestrianSystem", 853 | "PhysicsObject", 854 | "Pickup", 855 | "PickupSetStateEvent", 856 | "Pipe", 857 | "PipeEffect", 858 | "Placeable", 859 | "PlaceableTypeManager", 860 | "Placeholders", 861 | "PlacementScreen", 862 | "PlacementScreenController", 863 | "PlacementUtil", 864 | "PlantLimitToFieldEvent", 865 | "PlatformPrivilegeUtil", 866 | "Player", 867 | "PlayerModelManager", 868 | "PlayerPermissionsEvent", 869 | "PlayerPickUpObjectEvent", 870 | "PlayerSetFarmAnswerEvent", 871 | "PlayerSetFarmEvent", 872 | "PlayerSetHandToolEvent", 873 | "PlayerStateActivateObject", 874 | "PlayerStateAnimalFeed", 875 | "PlayerStateAnimalInteract", 876 | "PlayerStateAnimalPet", 877 | "PlayerStateAnimalRide", 878 | "PlayerStateBase", 879 | "PlayerStateCrouch", 880 | "PlayerStateCycleHandtool", 881 | "PlayerStateDrop", 882 | "PlayerStateFall", 883 | "PlayerStateIdle", 884 | "PlayerStateJump", 885 | "PlayerStateMachine", 886 | "PlayerStatePickup", 887 | "PlayerStateRun", 888 | "PlayerStateSwim", 889 | "PlayerStateThrow", 890 | "PlayerStateUseLight", 891 | "PlayerStateWalk", 892 | "PlayerStyle", 893 | "PlayerSwitchedFarmEvent", 894 | "PlayerTeleportEvent", 895 | "PlayerThrowObjectEvent", 896 | "PlayerToggleLightEvent", 897 | "PlaySampleMixin", 898 | "Plow", 899 | "PlowLimitToFieldEvent", 900 | "PlowMission", 901 | "PlowRotationEvent", 902 | "PolygonChain", 903 | "PowerConsumer", 904 | "PowerTakeOffs", 905 | "PreorderBonusManager", 906 | "PresenceModes", 907 | "PricingDynamics", 908 | "RailroadCrossing", 909 | "RailroadVehicle", 910 | "RainDropFactorTrigger", 911 | "RandomlyMovingParts", 912 | "RandomSound", 913 | "RaycastUtil", 914 | "ReceivingHopper", 915 | "ReceivingHopperSetCreateBoxesEvent", 916 | "RemovePlayerFromFarmEvent", 917 | "RenderElement", 918 | "RenderText", 919 | "RequestMoneyChangeEvent", 920 | "ResetVehicleEvent", 921 | "RestartManager", 922 | "Reverb", 923 | "ReverseDriving", 924 | "ReverseDrivingSetStateEvent", 925 | "Rideable", 926 | "RideableAnimal", 927 | "RidgeMarker", 928 | "RidgeMarkerSetStateEvent", 929 | "Roller", 930 | "Ropes", 931 | "RotationAnimation", 932 | "Rotator", 933 | "RoundStatusBar", 934 | "SaveEvent", 935 | "Savegame", 936 | "SavegameController", 937 | "SaveGameResolvePolicy", 938 | "SavegameSettingsEvent", 939 | "SCFDebugTesting", 940 | "ScreenElement", 941 | "ScrollingAnimation", 942 | "SelectMasterServerScreen", 943 | "SellHandToolEvent", 944 | "SellingStation", 945 | "SellingStationPlaceable", 946 | "SellItemDialog", 947 | "SellPlaceableEvent", 948 | "SellVehicleEvent", 949 | "SemiTrailerFront", 950 | "SendLocomotiveToSplinePositionEvent", 951 | "Server", 952 | "ServerDetailScreen", 953 | "ServerSettingsDialog", 954 | "SetCoverStateEvent", 955 | "SetCrabSteeringEvent", 956 | "SetCruiseControlSpeedEvent", 957 | "SetCruiseControlStateEvent", 958 | "SetDensityMapEvent", 959 | "SetDischargeStateEvent", 960 | "SetFillUnitIsFillingEvent", 961 | "SetMotorTurnedOnEvent", 962 | "SetPipeStateEvent", 963 | "SetSeedIndexEvent", 964 | "SetSplitShapesEvent", 965 | "SettingsAdvancedFrame", 966 | "SettingsConsoleFrame", 967 | "SettingsControlsFrame", 968 | "SettingsDeviceFrame", 969 | "SettingsDisplayFrame", 970 | "SettingsGeneralFrame", 971 | "SettingsModel", 972 | "SettingsScreen", 973 | "SetTurnedOnEvent", 974 | "SetWorkModeEvent", 975 | "Shader", 976 | "ShaderPlaneEffect", 977 | "ShakeAnimation", 978 | "Ship", 979 | "ShopCategoriesFrame", 980 | "ShopConfigScreen", 981 | "ShopController", 982 | "ShopDisplayItem", 983 | "ShopItemsFrame", 984 | "ShopLandscapingFrame", 985 | "ShopMenu", 986 | "ShopTrigger", 987 | "Shovel", 988 | "ShutdownEvent", 989 | "SideNotification", 990 | "SiloDialog", 991 | "SiloExtensionPlaceable", 992 | "SiloPlaceable", 993 | "SimParticleSystem", 994 | "SimpleState", 995 | "SimpleStateMachine", 996 | "SleepDialog", 997 | "SleepManager", 998 | "SleepRequestEvent", 999 | "SleepResponseEvent", 1000 | "SlideDoorTrigger", 1001 | "SliderElement", 1002 | "SlopeCompensation", 1003 | "SlurrySideToSideEffect", 1004 | "SolarCollectorPlaceable", 1005 | "SoundManager", 1006 | "SoundMixer", 1007 | "SoundModifierType", 1008 | "SoundNode", 1009 | "SoundPlayer", 1010 | "SowingMachine", 1011 | "SowMission", 1012 | "SpeakerDisplay", 1013 | "SpecializationManager", 1014 | "SpecializationUtil", 1015 | "SpeedMeterDisplay", 1016 | "SpeedRotatingParts", 1017 | "SplineUtil", 1018 | "SplineVehicle", 1019 | "SplitTypeManager", 1020 | "Sprayer", 1021 | "SprayMission", 1022 | "SprayType", 1023 | "SprayTypeManager", 1024 | "StableListElement", 1025 | "StartMissionInfo", 1026 | "StartSleepStateEvent", 1027 | "StartupScreen", 1028 | "StatusBar", 1029 | "StopSleepStateEvent", 1030 | "Storage", 1031 | "Store", 1032 | "StoreItemUtil", 1033 | "StoreManager", 1034 | "StrawBlower", 1035 | "StringUtil", 1036 | "StumpCutter", 1037 | "SunAdmirer", 1038 | "Suspensions", 1039 | "TabbedMenu", 1040 | "TabbedMenuFrameElement", 1041 | "TabbedMenuWithDetails", 1042 | "TableElement", 1043 | "TableHeaderElement", 1044 | "Tedder", 1045 | "TemperatureUpdater", 1046 | "TensionBeltGeometryConstructor", 1047 | "TensionBeltManager", 1048 | "TensionBeltObject", 1049 | "TensionBelts", 1050 | "TensionBeltsActivatable", 1051 | "TensionBeltsEvent", 1052 | "TensionBeltsRefreshEvent", 1053 | "TerrainDeformation", 1054 | "TerrainDeformationQueue", 1055 | "TerrainDetailDistanceConstructor", 1056 | "TerrainLoadFlags", 1057 | "TextElement", 1058 | "TextInputDialog", 1059 | "TextInputElement", 1060 | "TextureArrayConstructor", 1061 | "TimedVisibility", 1062 | "TimerElement", 1063 | "TipEffect", 1064 | "TipOccluder", 1065 | "TireTrackSystem", 1066 | "ToggleButtonElement", 1067 | "ToolType", 1068 | "ToolTypeManager", 1069 | "TopNotification", 1070 | "TourIcons", 1071 | "TrafficSystem", 1072 | "Trailer", 1073 | "TrailerFarmStrategie", 1074 | "TrailerToggleTipSideEvent", 1075 | "TrainPlaceable", 1076 | "TransferMoneyDialog", 1077 | "TransferMoneyEvent", 1078 | "TransportMission", 1079 | "TransportMissionTrigger", 1080 | "TrashBag", 1081 | "TreeGrowEvent", 1082 | "TreePlaceable", 1083 | "TreePlanter", 1084 | "TreePlanterActivatable", 1085 | "TreePlanterLoadPalletEvent", 1086 | "TreePlantEvent", 1087 | "TreePlantManager", 1088 | "TreeSaw", 1089 | "TurnOnVehicle", 1090 | "Tutorial", 1091 | "TutorialScreen", 1092 | "Tween", 1093 | "TweenSequence", 1094 | "UnBanDialog", 1095 | "UnbanEvent", 1096 | "UnloadFeedingTrough", 1097 | "UnloadingStation", 1098 | "UnloadTrigger", 1099 | "UpdateSplitShapesEvent", 1100 | "UploadState", 1101 | "Upnp", 1102 | "User", 1103 | "UserDataEvent", 1104 | "UserEvent", 1105 | "UserManager", 1106 | "Utils", 1107 | "ValueBuffer", 1108 | "Vehicle", 1109 | "VehicleAttachEvent", 1110 | "VehicleBrokenEvent", 1111 | "VehicleBundleAttachEvent", 1112 | "VehicleCamera", 1113 | "VehicleCharacter", 1114 | "VehicleDebug", 1115 | "VehicleDetachEvent", 1116 | "VehicleEnterRequestEvent", 1117 | "VehicleEnterResponseEvent", 1118 | "VehicleHUDExtension", 1119 | "VehicleHudUtils", 1120 | "VehicleLeaveEvent", 1121 | "VehicleLowerImplementEvent", 1122 | "VehicleMotor", 1123 | "VehiclePlaceable", 1124 | "VehicleRemoveEvent", 1125 | "VehicleSchemaDisplay", 1126 | "VehicleSchemaOverlayData", 1127 | "VehicleSellingPoint", 1128 | "VehicleSetBeaconLightEvent", 1129 | "VehicleSetLightEvent", 1130 | "VehicleSetTurnLightEvent", 1131 | "VehicleShopBase", 1132 | "VendingMachine", 1133 | "VideoElement", 1134 | "VisualTrailer", 1135 | "VoteDialog", 1136 | "Washable", 1137 | "WaterLog", 1138 | "Watermill", 1139 | "WaterTower", 1140 | "WaterTrailer", 1141 | "WaterTrailerActivatable", 1142 | "WaterTrailerSetIsFillingEvent", 1143 | "Wearable", 1144 | "WearableRepairEvent", 1145 | "Weather", 1146 | "WeatherAddObjectEvent", 1147 | "WeatherFrontUpdater", 1148 | "WeatherInstance", 1149 | "WeatherObject", 1150 | "WeatherObjectRain", 1151 | "WeatherType", 1152 | "WeatherTypeManager", 1153 | "Weeder", 1154 | "WeedMission", 1155 | "WeighStation", 1156 | "Wheels", 1157 | "WheelsUtil", 1158 | "WildlifeSpawner", 1159 | "Windmill", 1160 | "WindObject", 1161 | "WindObjectChangedEvent", 1162 | "Windrower", 1163 | "WindrowerEffect", 1164 | "WindTurbinePlaceable", 1165 | "WindUpdater", 1166 | "Wipers", 1167 | "WoodCrusher", 1168 | "WoodCrusherPlaceable", 1169 | "WoodHarvester", 1170 | "WoodHarvesterCutTreeEvent", 1171 | "WoodHarvesterOnCutTreeEvent", 1172 | "WoodHarvesterOnDelimbTreeEvent", 1173 | "WoodSellEvent", 1174 | "WoodSellStationPlaceable", 1175 | "WorkArea", 1176 | "WorkAreaType", 1177 | "WorkAreaTypeManager", 1178 | "WorkMode", 1179 | "WorkParticles", 1180 | "Workshop", 1181 | "XMLUtil", 1182 | "YesNoDialog", 1183 | } 1184 | } 1185 | 1186 | stds.fs19_funcs = { 1187 | read_globals = { 1188 | "acceptedGameCreate", 1189 | "acceptedGameInvite", 1190 | "acceptedGameInvitePerformConnect", 1191 | "addConsoleCommand", 1192 | "addContactReport", 1193 | "addDensityMapHeightAtWorldLine", 1194 | "addDensityMapHeightAtWorldPos", 1195 | "addDensityMapHeightOcclusionArea", 1196 | "addDensityMapSyncerConnection", 1197 | "addDensityMapSyncerDensityMap", 1198 | "addDifferential", 1199 | "addFeedingPlace", 1200 | "addForce", 1201 | "addHusbandryAnimal", 1202 | "addImpulse", 1203 | "addJointBreakReport", 1204 | "addMilkingPlace", 1205 | "addModEventListener", 1206 | "addNotificationFilter", 1207 | "addParticleSystemSimulationTime", 1208 | "addReplacedCustomShader", 1209 | "addSplitShapeConnection", 1210 | "addSplitShapesShaderParameterOverwrite", 1211 | "addTerrainDeformationArea", 1212 | "addTerrainDeformationCircle", 1213 | "addTerrainUpdateConnection", 1214 | "addTimer", 1215 | "addToPhysics", 1216 | "addTorque", 1217 | "addTorqueImpulse", 1218 | "addTrackPoint", 1219 | "addTrafficSystemPlayer", 1220 | "addTrigger", 1221 | "addVehicleLink", 1222 | "addWakeUpReport", 1223 | "aimCamera", 1224 | "appIsSuspended", 1225 | "applyTerrainDeformation", 1226 | "areAchievementsAvailable", 1227 | "areStatsAvailable", 1228 | "asciiToUtf8", 1229 | "assert", 1230 | "assignAnimTrackClip", 1231 | "autoStartLocalSavegame", 1232 | "base64Decode", 1233 | "base64Encode", 1234 | "beginInputFuzzing", 1235 | "bitAND", 1236 | "bitHighestSet", 1237 | "bitNOT", 1238 | "bitOR", 1239 | "bitShiftLeft", 1240 | "bitShiftRight", 1241 | "bitXOR", 1242 | "buildNavMesh", 1243 | "buildNavPath", 1244 | "calcDistanceFrom", 1245 | "calcDistanceSquaredFrom", 1246 | "calculateFovY", 1247 | "cancelAllStreamedI3DFiles", 1248 | "cancelTerrainDeformation", 1249 | "catmullRomInterpolator1", 1250 | "catmullRomInterpolator3", 1251 | "centerHeadTracking", 1252 | "checkForNewDlcs", 1253 | "Class", 1254 | "cleanUpRenderingResources", 1255 | "clearAnimTrackClip", 1256 | "clearTerrainDeformationAreas", 1257 | "clone", 1258 | "cloneAnimCharacterSet", 1259 | "closeIntervalTimer", 1260 | "collectgarbage", 1261 | "companionDebugDraw", 1262 | "computeWheelShapeTireForces", 1263 | "conditionalAnimationDebugDraw", 1264 | "conditionalAnimationRegisterParameter", 1265 | "conditionalAnimationZeroiseTrackTimes", 1266 | "connectToServer", 1267 | "consoleCommandChangeLanguage", 1268 | "consoleCommandCleanI3DCache", 1269 | "consoleCommandDrawGuiHelper", 1270 | "consoleCommandDrawRawInput", 1271 | "consoleCommandFuzzInput", 1272 | "consoleCommandReloadCurrentGui", 1273 | "consoleCommandSetDebugRenderingMode", 1274 | "consoleCommandSetHighQuality", 1275 | "consoleCommandShowSafeFrame", 1276 | "consoleCommandSuspendApp", 1277 | "consoleCommandToggleUiDebug", 1278 | "consoleSetPowerConsumer", 1279 | "consoleSetWiperState", 1280 | "controlVehicle", 1281 | "copyFile", 1282 | "createAnimalCompanionManager", 1283 | "createAnimalHusbandry", 1284 | "createAudioSource", 1285 | "createBitVectorMap", 1286 | "createCamera", 1287 | "createCCT", 1288 | "createConditionalAnimation", 1289 | "createDensityMapHeightUpdater", 1290 | "createDensityMapSyncer", 1291 | "createDensityMapVisualizationOverlay", 1292 | "createFile", 1293 | "createFillPlaneShape", 1294 | "createFolder", 1295 | "createFoliageBendingRectangle", 1296 | "createFoliageBendingSystem", 1297 | "createImageOverlay", 1298 | "createImageOverlayWithTexture", 1299 | "createLightSource", 1300 | "createLowResCollisionHandler", 1301 | "createNavMesh", 1302 | "createNavPath", 1303 | "createPedestrianSystem", 1304 | "createRenderOverlay", 1305 | "createReverbEffect", 1306 | "createSample", 1307 | "createSoundPlayer", 1308 | "createStream", 1309 | "createStreamedSample", 1310 | "createTerrainDeformation", 1311 | "createTerrainDetailUpdater", 1312 | "createTerrainLayerTexture", 1313 | "createTrack", 1314 | "createTrafficSystem", 1315 | "createTransformGroup", 1316 | "createTyreTrackSystem", 1317 | "createVideoOverlay", 1318 | "createWebImageOverlay", 1319 | "createWheelShape", 1320 | "createXMLFile", 1321 | "cutTrack", 1322 | "delete", 1323 | "deleteFile", 1324 | "deleteFolder", 1325 | "destroyFoliageBendingObject", 1326 | "destroyLowResCollisionHandler", 1327 | "destroyTrack", 1328 | "disableAnimTrack", 1329 | "doExit", 1330 | "dofile", 1331 | "draw", 1332 | "drawDebugArrow", 1333 | "drawDebugLine", 1334 | "drawDebugPoint", 1335 | "drawDebugTriangle", 1336 | "enableAnimTrack", 1337 | "enableDevelopmentControls", 1338 | "enableTerrainDeformationMode", 1339 | "enableTerrainDeformationPaintingMode", 1340 | "enableTerrainDeformationSmoothingMode", 1341 | "endFrameRepeatMode", 1342 | "entityExists", 1343 | "eraseParallelogram", 1344 | "error", 1345 | "executeSettingsChange", 1346 | "exportScenegraphToGraphviz", 1347 | "exportScenegraphToGraphvizRec", 1348 | "extraUpdatePhysics", 1349 | "fileExists", 1350 | "fileWrite", 1351 | "fillPlaneAdd", 1352 | "filterText", 1353 | "findAndRemoveSplitShapeAttachments", 1354 | "findPolyline", 1355 | "findSplitShape", 1356 | "finishedUserProfileSync", 1357 | "finishWriteSplitShapesServerEvents", 1358 | "flushPhysicsCaches", 1359 | "flushWebCache", 1360 | "forceEndFrameRepeatMode", 1361 | "gcinfo", 1362 | "generateDensityMapVisualizationOverlay", 1363 | "get4kAvailable", 1364 | "getAchievement", 1365 | "getAdaptiveVsync", 1366 | "getAngularDamping", 1367 | "getAngularVelocity", 1368 | "getAnimalCompanionNeedNetworkUpdate", 1369 | "getAnimalFromCollisionNode", 1370 | "getAnimalPosition", 1371 | "getAnimalRotation", 1372 | "getAnimalShaderParameter", 1373 | "getAnimCharacterSet", 1374 | "getAnimClipDuration", 1375 | "getAnimClipIndex", 1376 | "getAnimNumOfClips", 1377 | "getAnimTrackAssignedClip", 1378 | "getAnimTrackBlendWeight", 1379 | "getAnimTrackTime", 1380 | "getAppBasePath", 1381 | "getAtmosphereCornettAsymetryFactor", 1382 | "getAtmosphereMieScale", 1383 | "getAudioSourceAutoPlay", 1384 | "getAudioSourceInnerRange", 1385 | "getAudioSourceRange", 1386 | "getAudioSourceSample", 1387 | "getAudioSourceTickInaudible", 1388 | "getAutoPerformanceClass", 1389 | "getBitVectorMapNumChannels", 1390 | "getBitVectorMapParallelogram", 1391 | "getBitVectorMapPoint", 1392 | "getBitVectorMapSize", 1393 | "getBloomMagnitude", 1394 | "getBloomMaskThreshold", 1395 | "getBloomQuality", 1396 | "getBrightness", 1397 | "getCamera", 1398 | "getCanRenderUnicode", 1399 | "getCCTCollisionFlags", 1400 | "getCenterOfMass", 1401 | "getChild", 1402 | "getChildAt", 1403 | "getChildIndex", 1404 | "getClipDistance", 1405 | "getClipDistancesWithLOD", 1406 | "getCloudQuality", 1407 | "getCollisionMask", 1408 | "getCompanionClosestDistance", 1409 | "getConditionalAnimationBoolValue", 1410 | "getConditionalAnimationFloatValue", 1411 | "getCorrectTextSize", 1412 | "getCropsGrowthNextState", 1413 | "getCropsGrowthStateTime", 1414 | "getCullOverride", 1415 | "getCurrentMasterVolume", 1416 | "getDate", 1417 | "getDateAt", 1418 | "getDateDiffSeconds", 1419 | "getDebugRenderingMode", 1420 | "getDensity", 1421 | "getDensityAtWorldPos", 1422 | "getDensityHeightAtWorldPos", 1423 | "getDensityMapCollisionHeightAtWorldPos", 1424 | "getDensityMapFilename", 1425 | "getDensityMapHeightFirstChannel", 1426 | "getDensityMapHeightNumChannels", 1427 | "getDensityMapHeightTypeAtWorldLine", 1428 | "getDensityMapHeightTypeAtWorldPos", 1429 | "getDensityMapMaxHeight", 1430 | "getDensityMapSize", 1431 | "getDensityNormalAtWorldPos", 1432 | "getDensityRegion", 1433 | "getDensityRegionWorld", 1434 | "getDiscretePerformanceSetting", 1435 | "getDlcPath", 1436 | "getDoFblendWeights", 1437 | "getDoFparams", 1438 | "getEffectiveClipDistancesWithLOD", 1439 | "getEffectiveVisibility", 1440 | "getEmitCountScale", 1441 | "getEmitStartTime", 1442 | "getEmitStopTime", 1443 | "getEmitterShape", 1444 | "getEmitterSurfaceSize", 1445 | "getEngineRevision", 1446 | "getExposureKeyValue", 1447 | "getExposureRange", 1448 | "getExposureTau", 1449 | "getFarClip", 1450 | "getfenv", 1451 | "getFileIdHasSplitShapes", 1452 | "getFileMD5", 1453 | "getFiles", 1454 | "getFillPlaneHeightAtLocalPos", 1455 | "getFilterAnisotropy", 1456 | "getFilterTrilinear", 1457 | "getFogPlaneHeight", 1458 | "getFogPlaneMieScale", 1459 | "getFoliageViewDistance", 1460 | "getFoliageViewDistanceCoeff", 1461 | "getFovY", 1462 | "getFullscreen", 1463 | "getGamepadAxisLabel", 1464 | "getGamepadAxisPhysicalName", 1465 | "getGamepadButtonLabel", 1466 | "getGamepadButtonPhysicalName", 1467 | "getGamepadCategory", 1468 | "getGamepadDefaultDeadzone", 1469 | "getGamepadEnabled", 1470 | "getGamepadId", 1471 | "getGamepadMappedUnknownAxis", 1472 | "getGamepadMappedUnknownButton", 1473 | "getGamepadName", 1474 | "getGamepadProductId", 1475 | "getGamepadVendorId", 1476 | "getGamepadVersionId", 1477 | "getGamepadVibrationEnabled", 1478 | "getGameRevisionExtraText", 1479 | "getGameTerritory", 1480 | "getGeometry", 1481 | "getGPUDriverVersion", 1482 | "getGPUName", 1483 | "getGPUVendor", 1484 | "getGravityDirection", 1485 | "getHasClassId", 1486 | "getHasGamepadAxis", 1487 | "getHasGamepadButton", 1488 | "getHasShaderParameter", 1489 | "getHasShadowFocusBox", 1490 | "getHasTerrainNormalMapping", 1491 | "getHaveAchievementsChanged", 1492 | "getHdrAvailable", 1493 | "getHeadTrackingRotation", 1494 | "getHeadTrackingTranslation", 1495 | "getHeadTrackingType", 1496 | "getHmdYaw", 1497 | "getInputAxis", 1498 | "getInputButton", 1499 | "getIsBadUserReputation", 1500 | "getIsCompound", 1501 | "getIsCompoundChild", 1502 | "getIsDensityMapVisualizationOverlayReady", 1503 | "getIsGamepadMappingReliable", 1504 | "getIsInCameraFrustum", 1505 | "getIsLanguageEnabled", 1506 | "getIsOrthographic", 1507 | "getIsPhysicsUpdateIndexSimulated", 1508 | "getIsSleeping", 1509 | "getIsSoundPlayerChannelStreamed", 1510 | "getIsSplitShapeSplit", 1511 | "getIsValidModDir", 1512 | "getKeyName", 1513 | "getLanguage", 1514 | "getLanguageCode", 1515 | "getLanguageName", 1516 | "getLevenshteinDistance", 1517 | "getLightColor", 1518 | "getLightRange", 1519 | "getLightScatteringDirection", 1520 | "getLinearDamping", 1521 | "getLinearVelocity", 1522 | "getLoadNamedInterpolatorCurve", 1523 | "getLocalLinearVelocity", 1524 | "getLODDistanceCoeff", 1525 | "getMass", 1526 | "getMasterVolume", 1527 | "getMaterial", 1528 | "getMaxNumOfParticles", 1529 | "getMaxNumShadowLights", 1530 | "getMD5", 1531 | "getmetatable", 1532 | "getMinClipDistance", 1533 | "getModCategoryName", 1534 | "getModDependency", 1535 | "getModDownloadAvailability", 1536 | "getModDownloadPath", 1537 | "getModFreeSpaceKb", 1538 | "getModHubRating", 1539 | "getModId", 1540 | "getModInstallPath", 1541 | "getModMetaAttributeBool", 1542 | "getModMetaAttributeInt", 1543 | "getModMetaAttributeString", 1544 | "getModNameAndBaseDirectory", 1545 | "getModNumDependencies", 1546 | "getModUseAvailability", 1547 | "getModUsedSpaceKb", 1548 | "getMoonBrightnessScale", 1549 | "getMoonSizeScale", 1550 | "getMotorRotationSpeed", 1551 | "getMotorTorque", 1552 | "getMouseButtonName", 1553 | "getMSAA", 1554 | "getMultiplayerAvailability", 1555 | "getName", 1556 | "getNATType", 1557 | "getNavMeshDistanceToWall", 1558 | "getNavPathDirection", 1559 | "getNavPathHasValidSlope", 1560 | "getNavPathIsValid", 1561 | "getNavPathLength", 1562 | "getNavPathNumOfWaypoints", 1563 | "getNavPathOrientation", 1564 | "getNavPathPosition", 1565 | "getNavPathWaypoint", 1566 | "getNearClip", 1567 | "getNeoMode", 1568 | "getNetworkError", 1569 | "getNormalizedScreenValues", 1570 | "getNormalizedUVs", 1571 | "getNormalizedValues", 1572 | "getNotification", 1573 | "getNumDlcPaths", 1574 | "getNumMaterials", 1575 | "getNumModCategories", 1576 | "getNumOfChildren", 1577 | "getNumOfContactReports", 1578 | "getNumOfGamepads", 1579 | "getNumOfLanguages", 1580 | "getNumOfMods", 1581 | "getNumOfNotifications", 1582 | "getNumOfParticlesToEmitPerMs", 1583 | "getNumOfProcessors", 1584 | "getNumOfScreenModes", 1585 | "getNumOfSplitShapes", 1586 | "getNumOfTriggers", 1587 | "getNumSoundPlayerChannels", 1588 | "getNumSoundPlayerItems", 1589 | "getObjectMask", 1590 | "getOrthographicHeight", 1591 | "getOSVersionName", 1592 | "getOverallVisibility", 1593 | "getP2PNodeId", 1594 | "getParent", 1595 | "getParticleSystemAverageSpeed", 1596 | "getParticleSystemLifespan", 1597 | "getParticleSystemNormalSpeed", 1598 | "getParticleSystemSpeed", 1599 | "getParticleSystemSpeedRandom", 1600 | "getParticleSystemSpriteScaleX", 1601 | "getParticleSystemSpriteScaleXGain", 1602 | "getParticleSystemSpriteScaleY", 1603 | "getParticleSystemSpriteScaleYGain", 1604 | "getParticleSystemTangentSpeed", 1605 | "getPedestrianSystemNightTimeRange", 1606 | "getPerformanceClass", 1607 | "getPerlinNoise2D", 1608 | "getPhysicsDt", 1609 | "getPhysicsDtNonInterpolated", 1610 | "getPhysicsDtUnclamped", 1611 | "getPhysicsUpdateIndex", 1612 | "getProcessorFrequency", 1613 | "getProcessorName", 1614 | "getProjectionOffset", 1615 | "getQuaternion", 1616 | "getRandomPlayerColor", 1617 | "getReflectionMapRatio", 1618 | "getRenderDriver", 1619 | "getResolutionScaling", 1620 | "getRigidBodyType", 1621 | "getRootNode", 1622 | "getRotation", 1623 | "getSampleDuration", 1624 | "getSamplePitch", 1625 | "getSamplePlayOffset", 1626 | "getSamplePlayTimeLeft", 1627 | "getSampleVelocity", 1628 | "getSampleVolume", 1629 | "getScale", 1630 | "getScreenAspectRatio", 1631 | "getScreenHdrOutput", 1632 | "getScreenMode", 1633 | "getScreenModeInfo", 1634 | "getShaderParameter", 1635 | "getShaderQuality", 1636 | "getShaderTimeSec", 1637 | "getShadowMapFilterSize", 1638 | "getShadowMapSize", 1639 | "getShadowQuality", 1640 | "getSoundPlayerChannelName", 1641 | "getSoundPlayerItemName", 1642 | "getSplineCV", 1643 | "getSplineDirection", 1644 | "getSplineLength", 1645 | "getSplineNumOfCV", 1646 | "getSplineOrientation", 1647 | "getSplinePosition", 1648 | "getSplitShapePlaneExtents", 1649 | "getSplitShapeStats", 1650 | "getSplitType", 1651 | "getSSAOIntensity", 1652 | "getSSAOQuality", 1653 | "getStartMode", 1654 | "getStartParameters", 1655 | "getStreamedSampleVolume", 1656 | "getSunBrightnessScale", 1657 | "getSunSizeScale", 1658 | "getSystemLanguage", 1659 | "getTerrainAttributesAtWorldPos", 1660 | "getTerrainDeformationBlockedAreaMapSize", 1661 | "getTerrainDetailByName", 1662 | "getTerrainDetailName", 1663 | "getTerrainDetailNumChannels", 1664 | "getTerrainDetailViewDistance", 1665 | "getTerrainHeightAtWorldPos", 1666 | "getTerrainHeightMapFilename", 1667 | "getTerrainLayerAtWorldPos", 1668 | "getTerrainLayerName", 1669 | "getTerrainLayerNumOfSubLayers", 1670 | "getTerrainLayerSubLayer", 1671 | "getTerrainLodBlendDistances", 1672 | "getTerrainLodBlendDynamicDistances", 1673 | "getTerrainLODDistanceCoeff", 1674 | "getTerrainLodNormalMapFilename", 1675 | "getTerrainLodTypeMapFilename", 1676 | "getTerrainNormalAtWorldPos", 1677 | "getTerrainNumOfLayers", 1678 | "getTerrainSize", 1679 | "getText3DHeight", 1680 | "getText3DLength", 1681 | "getText3DLineLength", 1682 | "getText3DWidth", 1683 | "getTextHeight", 1684 | "getTextLength", 1685 | "getTextLineLength", 1686 | "getTextureResolution", 1687 | "getTextWidth", 1688 | "getTime", 1689 | "getTimeSec", 1690 | "getTotalSystemMemory", 1691 | "getTrafficSystemNightTimeRange", 1692 | "getTranslation", 1693 | "getTyreTracksSegmentsCoeff", 1694 | "getUniqueUserId", 1695 | "getUseDoF", 1696 | "getUseLightScattering", 1697 | "getUserAttribute", 1698 | "getUserId", 1699 | "getUserName", 1700 | "getUserProfileAppPath", 1701 | "getVelocityAtLocalPos", 1702 | "getVelocityAtWorldPos", 1703 | "getVideoOverlayCurrentTime", 1704 | "getVideoOverlayDuration", 1705 | "getViewDistanceCoeff", 1706 | "getVisibility", 1707 | "getVolume", 1708 | "getVolumeMeshTessellationCoeff", 1709 | "getVsync", 1710 | "getWheelShapeAxleSpeed", 1711 | "getWheelShapeContactForce", 1712 | "getWheelShapeContactNormal", 1713 | "getWheelShapeContactObject", 1714 | "getWheelShapeContactPoint", 1715 | "getWheelShapePosition", 1716 | "getWheelShapeSlip", 1717 | "getWorldQuaternion", 1718 | "getWorldRotation", 1719 | "getWorldTranslation", 1720 | "getXMLBool", 1721 | "getXMLFloat", 1722 | "getXMLInt", 1723 | "getXMLRootName", 1724 | "getXMLString", 1725 | "hasNativeAchievementGUI", 1726 | "hasXMLProperty", 1727 | "haveModsChanged", 1728 | "hideAnimal", 1729 | "imeAbort", 1730 | "imeGetCursorPos", 1731 | "imeGetLastString", 1732 | "imeIsComplete", 1733 | "imeIsOpen", 1734 | "imeIsSupported", 1735 | "imeOpen", 1736 | "inAppFinishPendingPurchase", 1737 | "inAppFinishPurchase", 1738 | "inAppGetNumPendingPurchases", 1739 | "inAppGetPendingPurchaseProductId", 1740 | "inAppGetProductDescription", 1741 | "inAppGetProductPrice", 1742 | "inAppInit", 1743 | "inAppIsLoaded", 1744 | "inAppStartPurchase", 1745 | "init", 1746 | "initAchievements", 1747 | "InitClientOnce", 1748 | "initConditionalAnimation", 1749 | "initDensityMapHeightTypeProperties", 1750 | "InitEventClass", 1751 | "initModDownloadManager", 1752 | "InitObjectClass", 1753 | "InitStaticEventClass", 1754 | "InitStaticObjectClass", 1755 | "inspectTableAndPrint", 1756 | "installMod", 1757 | "ipairs", 1758 | "is4kVideoMode", 1759 | "isAbsolutPath", 1760 | "isAnimalVisible", 1761 | "isAnimTrackClipAssigned", 1762 | "isAnimTrackEnabled", 1763 | "isGameFullyInstalled", 1764 | "isGamepadSigninPending", 1765 | "isHeadTrackingAvailable", 1766 | "isHusbandryReady", 1767 | "isModUpdateRunning", 1768 | "isSamplePlaying", 1769 | "isSoundPlayerLoaded", 1770 | "isSoundPlayerPlaying", 1771 | "isUsingHmd", 1772 | "isVideoOverlayPlaying", 1773 | "keyEvent", 1774 | "linearInterpolator1", 1775 | "linearInterpolator2", 1776 | "linearInterpolator3", 1777 | "linearInterpolator4", 1778 | "linearInterpolatorN", 1779 | "linearInterpolatorTransRotScale", 1780 | "link", 1781 | "load", 1782 | "loadAmbientSound", 1783 | "loadBitVectorMapFromFile", 1784 | "loadBitVectorMapNew", 1785 | "loadCropsGrowthStateFromFile", 1786 | "loadDlcs", 1787 | "loadDlcsDirectories", 1788 | "loadDlcsFromDirectory", 1789 | "loadfile", 1790 | "loadI3DFile", 1791 | "loadInterpolator1Curve", 1792 | "loadInterpolator2Curve", 1793 | "loadInterpolator3Curve", 1794 | "loadInterpolator4Curve", 1795 | "loadLanguageSettings", 1796 | "loadMod", 1797 | "loadModDesc", 1798 | "loadMods", 1799 | "loadSample", 1800 | "loadServerSettings", 1801 | "loadSplitShapesFromFile", 1802 | "loadStreamedSample", 1803 | "loadstring", 1804 | "loadTerrainDetailUpdaterStateFromFile", 1805 | "loadUserSettings", 1806 | "loadXMLFile", 1807 | "loadXMLFileFromMemory", 1808 | "localDirectionToLocal", 1809 | "localDirectionToWorld", 1810 | "localRotationToLocal", 1811 | "localRotationToWorld", 1812 | "localToLocal", 1813 | "localToWorld", 1814 | "log", 1815 | "makeSplittable", 1816 | "masterServerAddAvailableMod", 1817 | "masterServerAddAvailableModEnd", 1818 | "masterServerAddAvailableModStart", 1819 | "masterServerAddDlc", 1820 | "masterServerAddDlcEnd", 1821 | "masterServerAddDlcStart", 1822 | "masterServerAddServer", 1823 | "masterServerAddServerMod", 1824 | "masterServerAddServerModEnd", 1825 | "masterServerAddServerModStart", 1826 | "masterServerDisconnect", 1827 | "masterServerInit", 1828 | "masterServerReconnect", 1829 | "masterServerRequestConnectionToServer", 1830 | "masterServerRequestFilteredServers", 1831 | "masterServerRequestServerDetails", 1832 | "masterServerSetCallbacks", 1833 | "masterServerSetNumPlayers", 1834 | "masterServerSetServerInfo", 1835 | "mathEulerRotateVector", 1836 | "mathEulerToQuaternion", 1837 | "mathQuaternionRotateVector", 1838 | "meshNetworkAddNode", 1839 | "meshNetworkBegin", 1840 | "meshNetworkBeginConfig", 1841 | "meshNetworkEnd", 1842 | "meshNetworkEndConfig", 1843 | "meshNetworkGetNodeStatusForApp", 1844 | "modDownloadManagerLoaded", 1845 | "modDownloadManagerUpdateSync", 1846 | "mouseEvent", 1847 | "moveCCT", 1848 | "navMeshRaycast", 1849 | "netCloseConnection", 1850 | "netGetAndResetConnectionSendStats", 1851 | "netGetBandwidthEstimate", 1852 | "netGetConnectionStats", 1853 | "netGetDefaultLocalIp", 1854 | "netGetHostByAddr", 1855 | "netGetTime", 1856 | "netSendStream", 1857 | "netSetIncomingPassword", 1858 | "netSetIsEventProcessingEnabled", 1859 | "netSetMaximumIncomingConnections", 1860 | "netShutdown", 1861 | "netStartup", 1862 | "new2DLayer", 1863 | "newproxy", 1864 | "next", 1865 | "nextMessageTypeId", 1866 | "notificationsLoaded", 1867 | "onBlockedListChanged", 1868 | "onDeepLinkingFailed", 1869 | "onFriendListChanged", 1870 | "OnInGameMenuMenu", 1871 | "OnLoadingScreen", 1872 | "onOkSigninAccept", 1873 | "onShowDeepLinkingErrorMsg", 1874 | "openIntervalTimer", 1875 | "openMpFriendInvitation", 1876 | "openNativeHelpMenu", 1877 | "openWebFile", 1878 | "overlapBox", 1879 | "overlapSphere", 1880 | "pairs", 1881 | "pauseSoundPlayer", 1882 | "pauseStreamedSample", 1883 | "pcall", 1884 | "playSample", 1885 | "playSoundPlayer", 1886 | "playStreamedSample", 1887 | "playVideoOverlay", 1888 | "prepareSaveBitVectorMapToFile", 1889 | "prepareSaveDensityMapToFile", 1890 | "prepareSaveSplitShapesToFile", 1891 | "prepareSaveTerrainHeightMap", 1892 | "prepareSaveTerrainLodTypeMap", 1893 | "prepareSplitShapesServerWriteUpdateStream", 1894 | "print", 1895 | "print_r", 1896 | "printCallstack", 1897 | "printf", 1898 | "printScenegraph", 1899 | "printScenegraphRec", 1900 | "printStatsOverlay", 1901 | "project", 1902 | "projectToCamera", 1903 | "promptUserConfirmScreenMode", 1904 | "quaternionInterpolator", 1905 | "quaternionInterpolator2", 1906 | "rawequal", 1907 | "rawget", 1908 | "rawset", 1909 | "raycastAll", 1910 | "raycastClosest", 1911 | "readAnimalCompanionManagerFromStream", 1912 | "readBitVectorMapFromStream", 1913 | "readDensityDataFromStream", 1914 | "readDensityMapSyncerServerUpdateFromStream", 1915 | "readIntervalTimerMs", 1916 | "readSplitShapeIdFromStream", 1917 | "readSplitShapesClientUpdateFromStream", 1918 | "readSplitShapesFromStream", 1919 | "readSplitShapesServerEventFromStream", 1920 | "readSplitShapesServerUpdateFromStream", 1921 | "readTerrainUpdateStream", 1922 | "readTrafficSystemFromStream", 1923 | "registerGlobalActionEvents", 1924 | "registerHandTool", 1925 | "registerObjectClassName", 1926 | "reloadDlcsAndMods", 1927 | "removeAllDifferentials", 1928 | "removeCCT", 1929 | "removeConsoleCommand", 1930 | "removeContactReport", 1931 | "removeDensityMapSyncerConnection", 1932 | "removeFromPhysics", 1933 | "removeHusbandryAnimal", 1934 | "removeJoint", 1935 | "removeJointBreakReport", 1936 | "removeModEventListener", 1937 | "removeSplitShapeAttachments", 1938 | "removeSplitShapeConnection", 1939 | "removeSplitShapesShaderParameterOverwrite", 1940 | "removeTerrainUpdateConnection", 1941 | "removeTimer", 1942 | "removeTrafficSystemPlayer", 1943 | "removeTrigger", 1944 | "removeWakeUpReport", 1945 | "removeXMLProperty", 1946 | "render360Screenshot", 1947 | "renderEnvProbe", 1948 | "renderOverlay", 1949 | "renderScreenshot", 1950 | "renderText", 1951 | "renderText3D", 1952 | "replaceUnrenderableCharacters", 1953 | "reportAnimalThreat", 1954 | "requestExit", 1955 | "requestGamepadSignin", 1956 | "resetAutoExposure", 1957 | "resetDensityMapVisualizationOverlay", 1958 | "resetEmitStartTimer", 1959 | "resetEmitStopTimer", 1960 | "resetModOnCreateFunctions", 1961 | "resetMultiplayerChecks", 1962 | "resetNumOfEmittedParticles", 1963 | "resetSplitShapes", 1964 | "resetTrafficSystem", 1965 | "restartApplication", 1966 | "resumeStreamedSample", 1967 | "rotate", 1968 | "rotateAboutLocalAxis", 1969 | "saveBitVectorMapToFile", 1970 | "saveCancelUpdateList", 1971 | "saveCropsGrowthStateToFile", 1972 | "saveDeleteSavegame", 1973 | "saveDensityMapToFile", 1974 | "saveGetHasSpaceForSaveGame", 1975 | "saveGetInfo", 1976 | "saveGetInfoById", 1977 | "saveGetNumOfSaveGames", 1978 | "saveGetUploadState", 1979 | "saveHardwareScalability", 1980 | "savePreparedBitVectorMapToFile", 1981 | "savePreparedDensityMapToFile", 1982 | "savePreparedSplitShapesToFile", 1983 | "savePreparedTerrainHeightMap", 1984 | "savePreparedTerrainLodTypeMap", 1985 | "saveReadSavegameCancel", 1986 | "saveReadSavegameFinish", 1987 | "saveReadSavegameGetProgress", 1988 | "saveReadSavegameHasProgress", 1989 | "saveReadSavegameStart", 1990 | "saveResetStorageDeviceSelection", 1991 | "saveResolveConflict", 1992 | "saveScreenshot", 1993 | "saveSetCloudErrorCallback", 1994 | "saveSplitShapesToFile", 1995 | "saveTerrainDetailUpdaterStateToFile", 1996 | "saveTerrainHeightMap", 1997 | "saveTerrainLodNormalMap", 1998 | "saveTerrainLodTypeMap", 1999 | "saveUpdateList", 2000 | "saveWriteSavegameFinish", 2001 | "saveWriteSavegameStart", 2002 | "saveXMLFile", 2003 | "saveXMLFileTo", 2004 | "saveXMLFileToMemory", 2005 | "searchText", 2006 | "select", 2007 | "setAdaptiveVsync", 2008 | "setAngularDamping", 2009 | "setAngularVelocity", 2010 | "setAnimalDaytime", 2011 | "setAnimalInteressNode", 2012 | "setAnimalShaderParameter", 2013 | "setAnimalTextureTile", 2014 | "setAnimTrackBlendWeight", 2015 | "setAnimTrackLoopState", 2016 | "setAnimTrackSpeedScale", 2017 | "setAnimTrackTime", 2018 | "setAtmosphereCornettAsymetryFactor", 2019 | "setAtmosphereMieScale", 2020 | "setAtmosphereSecondaryLightSource", 2021 | "setAudioCullingWorldProperties", 2022 | "setAudioGroupVolume", 2023 | "setAudioSourceAutoPlay", 2024 | "setAudioSourceInnerRange", 2025 | "setAudioSourceRange", 2026 | "setAudioSourceTickInaudible", 2027 | "setBitVectorMapParallelogram", 2028 | "setBloomMagnitude", 2029 | "setBloomMaskThreshold", 2030 | "setBloomQuality", 2031 | "setBrightness", 2032 | "setCamera", 2033 | "setCaption", 2034 | "setCCTPosition", 2035 | "setCenterOfMass", 2036 | "setClipDistance", 2037 | "setCloudFront", 2038 | "setCloudQuality", 2039 | "setCollisionMask", 2040 | "setColorGradingSettings", 2041 | "setCompanionArriveSteeringParameters", 2042 | "setCompanionBehaviorIdleStay", 2043 | "setCompanionBehaviorIdleWander", 2044 | "setCompanionBehaviorWanderParameters", 2045 | "setCompanionCommonSteeringParameters", 2046 | "setCompanionDaytime", 2047 | "setCompanionFeed", 2048 | "setCompanionFetch", 2049 | "setCompanionFollowEntity", 2050 | "setCompanionGotoEntity", 2051 | "setCompanionPet", 2052 | "setCompanionPosition", 2053 | "setCompanionsPhysicsUpdate", 2054 | "setCompanionSteeringTarget", 2055 | "setCompanionSteeringWeights", 2056 | "setCompanionsVisibility", 2057 | "setCompanionThreat", 2058 | "setCompanionTrigger", 2059 | "setCompanionWanderSteeringParameters", 2060 | "setCompanionWaterLevel", 2061 | "setConditionalAnimationBoolValue", 2062 | "setConditionalAnimationFloatValue", 2063 | "setConditionalAnimationSpecificParameterIds", 2064 | "setCropsEnableGrowth", 2065 | "setCropsGrowthMask", 2066 | "setCropsGrowthNextState", 2067 | "setCropsGrowthStateTime", 2068 | "setCropsIgnoreDensityChanges", 2069 | "setCropsMaxNumCellsPerFrame", 2070 | "setCropsNumGrowthStates", 2071 | "setCullOverride", 2072 | "setCurrentMasterVolume", 2073 | "setCurrentProcessPriority", 2074 | "setDebugRenderingMode", 2075 | "setDensityMapHeightCollisionMap", 2076 | "setDensityMapHeightTypeProperties", 2077 | "setDensityMapSyncerLostPacket", 2078 | "setDensityMapVisualizationOverlayGrowthStateColor", 2079 | "setDensityMapVisualizationOverlayStateBorderColor", 2080 | "setDensityMapVisualizationOverlayStateColor", 2081 | "setDensityMapVisualizationOverlayTypeColor", 2082 | "setDensityMapVisualizationOverlayTypedStateColor", 2083 | "setDensityMapVisualizationOverlayUpdateTimeLimit", 2084 | "setDirection", 2085 | "setDiscretePerformanceSetting", 2086 | "setDoFblendWeights", 2087 | "setDoFparams", 2088 | "setDropCountScale", 2089 | "setEmitCountScale", 2090 | "setEmitStartTime", 2091 | "setEmitStopTime", 2092 | "setEmitterShape", 2093 | "setEmittingState", 2094 | "setEnableAmbientSound", 2095 | "setEnableBetaMods", 2096 | "setEnvMap", 2097 | "setExposureKeyValue", 2098 | "setExposureRange", 2099 | "setExposureTau", 2100 | "setFarClip", 2101 | "setfenv", 2102 | "setFileLogPrefixTimestamp", 2103 | "setFillPlaneMaxPhysicalSurfaceAngle", 2104 | "setFilterAnisotropy", 2105 | "setFilterTrilinear", 2106 | "setFogPlaneHeight", 2107 | "setFogPlaneMieScale", 2108 | "setFoliageBendingSystem", 2109 | "setFoliageViewDistanceCoeff", 2110 | "setFovY", 2111 | "setFramerateLimiter", 2112 | "setFrictionVelocity", 2113 | "setFullscreen", 2114 | "setGamepadDeadzone", 2115 | "setGamepadDefaultDeadzone", 2116 | "setGamepadDigitalOutput", 2117 | "setGamepadEnabled", 2118 | "setGamepadVibration", 2119 | "setGamepadVibrationEnabled", 2120 | "setGlobalCloudState", 2121 | "setHasShadowFocusBox", 2122 | "setHasTerrainNormalMapping", 2123 | "setInvertStereoRendering", 2124 | "setIsCompound", 2125 | "setIsCompoundChild", 2126 | "setIsOrthographic", 2127 | "setJointDrive", 2128 | "setJointFrame", 2129 | "setJointPosition", 2130 | "setJointRotationLimit", 2131 | "setJointRotationLimitForceLimit", 2132 | "setJointRotationLimitSpring", 2133 | "setJointTranslationLimit", 2134 | "setJointTranslationLimitForceLimit", 2135 | "setJointTranslationLimitSpring", 2136 | "setLanguage", 2137 | "setLightColor", 2138 | "setLightCullingWorldProperties", 2139 | "setLightRange", 2140 | "setLightScatteringColor", 2141 | "setLightScatteringDirection", 2142 | "setLightShadowMap", 2143 | "setLinearDamping", 2144 | "setLinearVelocity", 2145 | "setLODDistanceCoeff", 2146 | "setLowResCollisionHandlerTerrainRootNode", 2147 | "setLuaErrorHandler", 2148 | "setMass", 2149 | "setMasterVolume", 2150 | "setMaterial", 2151 | "setMaterialDiffuseMap", 2152 | "setMaterialNormalMap", 2153 | "setMaxNumOfParticles", 2154 | "setMaxNumOfReflectionPlanes", 2155 | "setMaxNumShadowLights", 2156 | "setmetatable", 2157 | "setMilkingPlaceDoors", 2158 | "setMinClipDistance", 2159 | "setModDownloadManagerRecommenderParams", 2160 | "setModHubRating", 2161 | "setModInstalled", 2162 | "setMoonBrightnessScale", 2163 | "setMoonSizeScale", 2164 | "setMotorProperties", 2165 | "setMSAA", 2166 | "setName", 2167 | "setNearClip", 2168 | "setNumOfParticlesToEmitPerMs", 2169 | "setObjectMask", 2170 | "setOrthographicHeight", 2171 | "setOverlayColor", 2172 | "setOverlayLayer", 2173 | "setOverlayRotation", 2174 | "setOverlayUVs", 2175 | "setPairCollision", 2176 | "setParticleSystemLifespan", 2177 | "setParticleSystemNormalSpeed", 2178 | "setParticleSystemSpeed", 2179 | "setParticleSystemSpeedRandom", 2180 | "setParticleSystemSpriteScaleX", 2181 | "setParticleSystemSpriteScaleXGain", 2182 | "setParticleSystemSpriteScaleY", 2183 | "setParticleSystemSpriteScaleYGain", 2184 | "setParticleSystemTangentSpeed", 2185 | "setParticleSystemTimeScale", 2186 | "setPedestrianSystemDaytime", 2187 | "setPedestrianSystemEnabled", 2188 | "setPedestrianSystemNightTimeRange", 2189 | "setPerformanceClass", 2190 | "setPolylineTranslation", 2191 | "setPresenceMode", 2192 | "setProjectionOffset", 2193 | "setQuaternion", 2194 | "setReflectionMapObjectMasks", 2195 | "setReflectionMapRatio", 2196 | "setReflectionMapScaling", 2197 | "setRenderOverlayAspectRatio", 2198 | "setRenderOverlayCamera", 2199 | "setResolutionScaling", 2200 | "setRigidBodyType", 2201 | "setRootNode", 2202 | "setRotation", 2203 | "setSampleFrequencyFilter", 2204 | "setSampleGroup", 2205 | "setSamplePitch", 2206 | "setSampleVelocity", 2207 | "setSampleVolume", 2208 | "setScale", 2209 | "setSceneBrightness", 2210 | "setScreenHdrOutput", 2211 | "setScreenMode", 2212 | "setShaderParameter", 2213 | "setShaderQuality", 2214 | "setShadowFocusBox", 2215 | "setShadowMapFilterSize", 2216 | "setShadowMapSize", 2217 | "setShadowQuality", 2218 | "setShapeCullingWorldProperties", 2219 | "setSharedShaderParameter", 2220 | "setShowMouseCursor", 2221 | "setSolverIterationCount", 2222 | "setSoundPlayerChannel", 2223 | "setSoundPlayerItem", 2224 | "setSplitShapesFileIdMapping", 2225 | "setSplitShapesLoadingFileId", 2226 | "setSplitShapesNextFileId", 2227 | "setSplitShapesWorldCompressionParams", 2228 | "setSSAOIntensity", 2229 | "setSSAOQuality", 2230 | "setStartMode", 2231 | "setStereoRendering", 2232 | "setStreamedSampleGroup", 2233 | "setStreamedSampleVolume", 2234 | "setStreamLowPriorityI3DFiles", 2235 | "setSunBrightnessScale", 2236 | "setSunIsPrimary", 2237 | "setSunSizeScale", 2238 | "setTerrainDeformationBlockedAreaMap", 2239 | "setTerrainDeformationBlockedAreaMaxDisplacement", 2240 | "setTerrainDeformationDynamicObjectCollisionMask", 2241 | "setTerrainDeformationDynamicObjectMaxDisplacement", 2242 | "setTerrainDeformationOutsideAreaBrush", 2243 | "setTerrainDeformationOutsideAreaConstraints", 2244 | "setTerrainDeformationSmoothingAmount", 2245 | "setTerrainHeightAtWorldPos", 2246 | "setTerrainLayerAtWorldPos", 2247 | "setTerrainLoadDirectory", 2248 | "setTerrainLodBlendDistances", 2249 | "setTerrainLodBlendDynamicDistances", 2250 | "setTerrainLODDistanceCoeff", 2251 | "setTextAlignment", 2252 | "setTextBold", 2253 | "setTextColor", 2254 | "setTextDepthTestEnabled", 2255 | "setTextLineBounds", 2256 | "setTextLineHeightScale", 2257 | "setTextRenderOverlay", 2258 | "setTextureResolution", 2259 | "setTextVerticalAlignment", 2260 | "setTextWidthScale", 2261 | "setTextWrapWidth", 2262 | "setTimerTime", 2263 | "setTrafficSystemDaytime", 2264 | "setTrafficSystemEnabled", 2265 | "setTrafficSystemNightTimeRange", 2266 | "setTrafficSystemUseOutdoorAudioSetup", 2267 | "setTranslation", 2268 | "setTyreTracksSegementsCoeff", 2269 | "setUpdateCycleTime", 2270 | "setUpdateDeltaValue", 2271 | "setUpdateMask", 2272 | "setUpdateMaskFromInfoLayer", 2273 | "setUpdateMinMaxValue", 2274 | "setUseDoF", 2275 | "setUseKinematicSplitShapes", 2276 | "setUseLightScattering", 2277 | "setUserAttribute", 2278 | "setUserConfirmScreenMode", 2279 | "setVideoOverlayPosition", 2280 | "setVideoOverlayVolume", 2281 | "setViewDistanceCoeff", 2282 | "setViewport", 2283 | "setVisibility", 2284 | "setVolumeMeshTessellationCoeff", 2285 | "setVsync", 2286 | "setWheelShapeAutoHoldBrakeForce", 2287 | "setWheelShapeDirection", 2288 | "setWheelShapeForcePoint", 2289 | "setWheelShapeProps", 2290 | "setWheelShapeSteeringCenter", 2291 | "setWheelShapeTireFriction", 2292 | "setWheelShapeWidth", 2293 | "setWindowFocus", 2294 | "setWindVelocity", 2295 | "setWorldQuaternion", 2296 | "setWorldRotation", 2297 | "setWorldTranslation", 2298 | "setXMLBool", 2299 | "setXMLFloat", 2300 | "setXMLInt", 2301 | "setXMLString", 2302 | "showAnimal", 2303 | "showGameInstallProgress", 2304 | "showSigninScreen", 2305 | "showSoundPlayerContentRatingWarning", 2306 | "showUserProfile", 2307 | "simulateParticleSystems", 2308 | "simulatePhysics", 2309 | "simulatePhysicsTimeScale", 2310 | "smoothDensityMapHeightAtWorldPos", 2311 | "source", 2312 | "splitShape", 2313 | "startDevClient", 2314 | "startDevServer", 2315 | "startFrameRepeatMode", 2316 | "startServerGame", 2317 | "startUpdatePendingMods", 2318 | "startWriteSplitShapesServerEvents", 2319 | "statsGet", 2320 | "statsGetIndex", 2321 | "statsSet", 2322 | "stopSample", 2323 | "stopStreamedSample", 2324 | "stopVideoOverlay", 2325 | "storeAreDlcsCorrupted", 2326 | "storeBeginUserSignIn", 2327 | "storeGetBuyPageState", 2328 | "storeGetNumProducts", 2329 | "storeGetOnlineState", 2330 | "storeGetProductInfo", 2331 | "storeGetProductPrice", 2332 | "storeHasNativeGUI", 2333 | "storeHaveDlcsChanged", 2334 | "storeOpenBuyPage", 2335 | "storeRequestCloseBuyPage", 2336 | "streamAlignReadToByteBoundary", 2337 | "streamAlignWriteToByteBoundary", 2338 | "streamGetIpAndPort", 2339 | "streamGetNumOfUnreadBits", 2340 | "streamGetReadOffset", 2341 | "streamGetWriteOffset", 2342 | "streamI3DFile", 2343 | "streamReadBool", 2344 | "streamReadFloat32", 2345 | "streamReadInt16", 2346 | "streamReadInt32", 2347 | "streamReadInt8", 2348 | "streamReadIntN", 2349 | "streamReadManualTimestamp", 2350 | "streamReadString", 2351 | "streamReadUInt16", 2352 | "streamReadUInt8", 2353 | "streamReadUIntN", 2354 | "streamSetReadOffset", 2355 | "streamSetWriteOffset", 2356 | "streamWriteBool", 2357 | "streamWriteFloat32", 2358 | "streamWriteInt16", 2359 | "streamWriteInt32", 2360 | "streamWriteInt8", 2361 | "streamWriteIntN", 2362 | "streamWriteManualTimestamp", 2363 | "streamWriteStream", 2364 | "streamWriteString", 2365 | "streamWriteTimestamp", 2366 | "streamWriteUInt16", 2367 | "streamWriteUInt8", 2368 | "streamWriteUIntN", 2369 | "syncProfileFiles", 2370 | "testSplitShape", 2371 | "toggleShowFPS", 2372 | "toggleStatsOverlay", 2373 | "toggleVisibility", 2374 | "tonumber", 2375 | "tostring", 2376 | "touchEvent", 2377 | "traceOff", 2378 | "traceOn", 2379 | "translate", 2380 | "type", 2381 | "unicodeToUtf8", 2382 | "uninstallMod", 2383 | "unlink", 2384 | "unloadAmbientSound", 2385 | "unlockAchievement", 2386 | "unpack", 2387 | "unProject", 2388 | "unregisterObjectClassName", 2389 | "update", 2390 | "updateAmbientSound", 2391 | "updateAspectRatio", 2392 | "updateConditionalAnimation", 2393 | "updateDifferential", 2394 | "updateFeedingPlace", 2395 | "updateLoadingBar", 2396 | "updateLoadingBarProgress", 2397 | "updateMod", 2398 | "updatePlacementCollisionMap", 2399 | "updateRenderOverlay", 2400 | "updateTerrainCollisionMap", 2401 | "updateVideoOverlay", 2402 | "upnpAddPortMapping", 2403 | "upnpDiscover", 2404 | "upnpRemovePortMapping", 2405 | "usleep", 2406 | "utf8Strlen", 2407 | "utf8Substr", 2408 | "utf8ToLower", 2409 | "utf8ToUnicode", 2410 | "utf8ToUpper", 2411 | "verifyDlcs", 2412 | "watchTable", 2413 | "watchTableLive", 2414 | "worldDirectionToLocal", 2415 | "worldRotationToLocal", 2416 | "worldToLocal", 2417 | "wrapMousePosition", 2418 | "writeAnimalCompanionManagerToStream", 2419 | "writeBitVectorMapToStream", 2420 | "writeDensityDataToStream", 2421 | "writeDensityMapSyncerServerUpdateToStream", 2422 | "writeSplitShapeIdToStream", 2423 | "writeSplitShapesClientUpdateToStream", 2424 | "writeSplitShapesServerEventToStream", 2425 | "writeSplitShapesServerUpdateToStream", 2426 | "writeSplitShapesToStream", 2427 | "writeTerrainDeformationBlockedAreas", 2428 | "writeTerrainUpdateStream", 2429 | "writeTrafficSystemToStream", 2430 | "xpcall", 2431 | } 2432 | } 2433 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FS19_modROS 2 | 3 | ## Development status 4 | 5 | As of 2021-12-08, this mod is not under active development any more. 6 | 7 | It will most likely remain functional (as FarmSim19 is not expected to change significantly), but it's not feature complete (see the issue tracker for open issues). 8 | 9 | 10 | ## Overview 11 | 12 | This mod for Farming Simulator 2019 allows autonomous driving of FarmSim vehicles with the ROS navigation stack. 13 | 14 | The mod itself is hosted in this repository. 15 | [tud-cor/fs_mod_ros_windows](https://github.com/tud-cor/fs_mod_ros_windows) contains the companion Python scripts which implement a bridge between `modROS` and ROS 1 (using `rospy`). 16 | [tud-cor/fs_mod_ros](https://github.com/tud-cor/fs_mod_ros) contains two example ROS packages which show how to interact with FarmSim19 running `modROS`. 17 | 18 | 19 | ### ROS message support 20 | 21 | In its current state, `modROS` publishes four types of messages: 22 | 23 | - `rosgraph_msgs/Clock`: in-game simulated clock. This message stops being published when the game is paused/exited 24 | - `nav_msgs/Odometry`: ground-truth `Pose` and `Twist` of vehicles based on their in-game position and orientation 25 | - `sensor_msgs/LaserScan`: data from five virtual laser scanners (parallel planes) (but see [#10](https://github.com/tud-cor/FS19_modROS/issues/10)) 26 | - `sensor_msgs/Imu`: from a simulated IMU (but see [#6](https://github.com/tud-cor/FS19_modROS/issues/6)) 27 | 28 | In addition, there is preliminary support for input into Farming Simulator: 29 | 30 | - `geometry_msgs/Twist`: controls the currently active vehicle (used by the demos in [tud-cor/fs_mod_ros](https://github.com/tud-cor/fs_mod_ros)). Behaviour is similar to - but not identical to - a regular ROS `Twist` interface to a vehicle (velocity mapping is not 1-to-1 yet due to how FarmSim controls vehicles) 31 | 32 | Support for additional message types may be added in the future, but is limited by what the Farming Simulator Lua API exposes. 33 | 34 | 35 | ## ⚠️ Warning and disclaimer 36 | 37 | `modROS` uses memory modification techniques which *could* be considered harmful by anti-cheat systems which are often included in games with on-line gameplay. 38 | 39 | While the manifest clearly marks `modROS` as incompatible with multiplayer game sessions, and the authors have not experienced any problems so far, we feel we must warn users and strongly recommend against ever trying to enable the mod in multiplayer games, nor run any of the scripts in [tud-cor/fs_mod_ros_windows](https://github.com/tud-cor/fs_mod_ros_windows) while playing on-line. 40 | Users cannot hold the authors of `modROS` responsible for loss of (on-line or other) functionality in Farming Simulator 19, nor for any damages related to or as a consequence of such loss of functionality. 41 | 42 | 43 | ## Status 44 | 45 | Some parts are still under development. 46 | 47 | 48 | ## Requirements 49 | 50 | * Windows 10 51 | * Farming Simulator 19 52 | 53 | Both the Steam version of Farming Simulator and the version distributed as a stand-alone purchase have been tested. 54 | 55 | 56 | ## Building 57 | 58 | #### Installing the mod in Farming Simulator 19 59 | 60 | __Note: The following instructions assume the default paths to various system folders are used on your machine. If not, please update the paths in the relevant places.__ 61 | 62 | 1. Clone the mod or download the `.zip` at any location 63 | 64 | ```cmd 65 | git clone https://github.com/tud-cor/FS19_modROS modROS 66 | ``` 67 | 68 | 2. Moving mod files to the `mods` directory: 69 | In order for FarmSim to detect `modROS`, you either have to move the folder [modROS](https://github.com/tud-cor/FS19_modROS) to the `mods` directory (`%USERPROFILE%\Documents\My Games\FarmingSimulator2019\mods`) or create a symbolic link from the `modROS` folder and drop it in the `FarmingSimulator2019\mods` directory. 70 | 71 | The authors have used [hardlinkshellext/linkshellextension](https://schinagl.priv.at/nt/hardlinkshellext/linkshellextension.html) which makes this an easy process. 72 | 73 | 3. If you've sucessfully installed the mod, it should be listed on the *Installed* tab of the *Mods* section in FarmSim (`modROS` is shown with a red square): 74 | 75 | ![modROS](.imgs/modROS.png) 76 | 77 | More information on installing mods in Farming Simulator 2019 can be found [here](http://www.farmingsimulator19mods.com/how-to-install-farming-simulator-2019-19-mods/). 78 | 79 | 4. Enable the Developer Console in Farming Simulator. Tutorial can be found [here](https://www.youtube.com/watch?v=_hYbnu6nJsQ). 80 | 81 | 82 | #### ROS nodes in Windows 83 | To start transmitting messages between Farmsim and ROS, please first go to [fs_mod_ros_windows](https://github.com/tud-cor/fs_mod_ros_windows). 84 | 85 | #### Optional 86 | If you would like to have a simulated RGB camera (not required to run navigation stack in ROS) in Farsmsim using screen capture, please refer to [`d3dshot_screen_grabber`](https://github.com/tud-cor/d3dshot_screen_grabber) 87 | 88 | 89 | ## Running 90 | 91 | To publish data, you need to first run a ROS node-`all_in_one_publisher.py`. Please follow the instructions [here](https://github.com/tud-cor/fs_mod_ros_windows#publishing-data). 92 | 93 | **Note: Before proceeding to the next step, make sure you see *waiting for client from FarmSim19* in the cmd window** 94 | 95 | 96 | Open Farming Simulator 19 and switch the in-game console to command mode by pressing the tilde key (~) twice. More information on how to use console command in game can be found [here](https://wiki.nitrado.net/en/Admin_Commands_for_Farming_Simulator_19). 97 | 98 | 99 | To publish data, execute the following command in the FarmSim console: 100 | 101 | ``` 102 | rosPubMsg true 103 | ``` 104 | 105 | If you want to stop publishing data, simply execute: 106 | 107 | ``` 108 | rosPubMsg false 109 | ``` 110 | 111 | 112 | #### Subscribing data 113 | 114 | Please follow the instructions [here](https://github.com/tud-cor/fs_mod_ros_windows#subscribing-data) to run the ROS node- `cm_vel_subscriber.py` first. 115 | 116 | 117 | 118 | To give control of the manned vehicle to ROS, execute the following command in the FarmSim console: 119 | 120 | ``` 121 | rosControlVehicle true 122 | ``` 123 | 124 | If you want to stop subscribing and gain control back in FarmSim, so you can drive around the farm yourself: 125 | 126 | ``` 127 | rosControlVehicle false 128 | ``` 129 | 130 | #### Optional 131 | Force-center the camera if you use [`d3dshot_screen_grabber`](https://github.com/tud-cor/d3dshot_screen_grabber) to get a simulated RGB camera. 132 | 133 | This command is used to fix the camera view while capturing the screen. In FarmSim, the camera view is dynamic when one moves the cursor. In order to simulate the rgb sensor, the camera view should be fixed at one angle as it is mounted on the vehicle. 134 | 135 | To force-center the current camera, execute the following command in the FarmSim console: 136 | 137 | ``` 138 | forceCenteredCamera true 139 | ``` 140 | 141 | Stop forcing the camera: 142 | 143 | ``` 144 | forceCenteredCamera false 145 | ``` 146 | 147 | #### ROS Navigation stack 148 | Once you have all the required components, please refer to [fs_mod_ros](https://github.com/tud-cor/fs_mod_ros) to run ROS navigation stack on Linux. 149 | -------------------------------------------------------------------------------- /modDesc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <en>Mod ROS</en> 5 | 6 | 7 | 8 | 12 | 13 | 14 | tckarenchiang 15 | 0.0.3.0 16 | store.dds 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/loader.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Copyright (c) 2021, TU Delft 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | 18 | author: Ting-Chia Chiang, G.A. vd. Hoorn 19 | maintainer: Ting-Chia Chiang, G.A. vd. Hoorn 20 | 21 | --]] 22 | 23 | local directory = g_currentModDirectory 24 | local modName = g_currentModName 25 | 26 | g_modROSModDirectory = directory 27 | g_modROSModName = modName 28 | 29 | -- ROS 'messages' 30 | source(Utils.getFilename("src/msgs/geometry_msgs_transform_stamped.lua", directory)) 31 | source(Utils.getFilename("src/msgs/nav_msgs_odometry.lua", directory)) 32 | source(Utils.getFilename("src/msgs/rosgraph_msgs_clock.lua", directory)) 33 | source(Utils.getFilename("src/msgs/sensor_msgs_imu.lua", directory)) 34 | source(Utils.getFilename("src/msgs/sensor_msgs_laser_scan.lua", directory)) 35 | source(Utils.getFilename("src/msgs/tf2_msgs_tf_message.lua", directory)) 36 | 37 | -- third party utilities 38 | source(Utils.getFilename("src/utils/json.lua", directory)) 39 | source(Utils.getFilename("src/utils/shared_memory_segment.lua", directory)) 40 | source(Utils.getFilename("src/utils/vehicle_util.lua", directory)) 41 | 42 | -- our own utilities 43 | source(Utils.getFilename("src/utils/frames.lua", directory)) 44 | source(Utils.getFilename("src/utils/ros.lua", directory)) 45 | 46 | -- "ROS" 47 | source(Utils.getFilename("src/ros/WriteOnlyFileConnection.lua", directory)) 48 | source(Utils.getFilename("src/ros/Publisher.lua", directory)) 49 | 50 | -- main/default configuration 51 | -- TODO: add UI for all of this 52 | source(Utils.getFilename("src/mod_config.lua", directory)) 53 | 54 | -- main file 55 | source(Utils.getFilename("src/modROS.lua", directory)) 56 | 57 | -- LaserScanner class 58 | source(Utils.getFilename("src/utils/LaserScanner.lua", directory)) 59 | 60 | 61 | local function validateVehicleTypes() 62 | ModROS.installSpecializations(g_vehicleTypeManager, g_specializationManager, directory, modName) 63 | end 64 | 65 | local function init() 66 | VehicleTypeManager.validateVehicleTypes = Utils.prependedFunction(VehicleTypeManager.validateVehicleTypes, validateVehicleTypes) 67 | end 68 | 69 | init() 70 | -------------------------------------------------------------------------------- /src/modROS.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Copyright (c) 2021, TU Delft 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | 18 | name: modROS.lua 19 | version: 0.0.1 20 | description: 21 | This mod for Farming Simulator 2019 allows autonomous driving of FarmSim vehicles with the ROS navigation stack. 22 | There are three console commands in this mod for now: 23 | The first one is to publish data, the second one is to subscribe data and the last one is to force-center the camera 24 | ------------------------------------------------ 25 | ------------------------------------------------ 26 | 27 | A: Publishing data 28 | 1. sim time publisher - publish in-game simulated clock. This message stops being published when the game is paused/exited 29 | 2. odom publisher - publish ground-truth Pose and Twist of vehicles based on their in-game position and orientation 30 | 3. laser scan publisher - publish the laser scan data 31 | 4. imu publisher - publish the imu data (especially the acc info) 32 | 5. A command for writing all messages to a named pipe: "rosPubMsg true/false" 33 | 34 | ------------------------------------------------ 35 | ------------------------------------------------ 36 | 37 | B. Subscribing data 38 | 1. ros_cmd_teleop subscriber - give the vehicle control to ROS 39 | 2. A command for taking over control of a vehicle in the game : "rosControlVehicle true/false" 40 | 41 | ------------------------------------------------ 42 | ------------------------------------------------ 43 | 44 | C. Force-centering the camera 45 | 1. A command for force-centering the current camera: "forceCenteredCamera true/false" 46 | 47 | ------------------------------------------------ 48 | ------------------------------------------------ 49 | 50 | author: Ting-Chia Chiang, G.A. vd. Hoorn 51 | maintainer: Ting-Chia Chiang, G.A. vd. Hoorn 52 | 53 | 54 | --]] 55 | 56 | -- ModROS class is not local here 57 | -- it's now in the global scope so the installSpecializations(..) can be called in loader.lua 58 | ModROS = {} 59 | ModROS.MOD_DIR = g_modROSModDirectory 60 | ModROS.MOD_NAME = g_modROSModName 61 | ModROS.MOD_VERSION = g_modManager.nameToMod[ModROS.MOD_NAME]["version"] 62 | 63 | local function center_camera_func() 64 | local camIdx = g_currentMission.controlledVehicle.spec_enterable.camIndex 65 | local camera = g_currentMission.controlledVehicle.spec_enterable.cameras[camIdx] 66 | camera.rotX = camera.origRotX 67 | camera.rotY = camera.origRotY 68 | end 69 | 70 | function ModROS:loadMap() 71 | self.last_read = "" 72 | self.buf = SharedMemorySegment:init(64) 73 | self.sec = 0 74 | self.nsec = 0 75 | self.l_v_x_0 = 0 76 | self.l_v_y_0 = 0 77 | self.l_v_z_0 = 0 78 | 79 | -- initialise connection to the Python side (but do not connect it yet) 80 | self.path = "\\\\.\\pipe\\FS19_modROS_pipe" 81 | self._conx = WriteOnlyFileConnection.new(self.path) 82 | 83 | -- initialise no-namespace-specific publishers 84 | self._pub_tf = Publisher.new(self._conx, "tf", tf2_msgs_TFMessage) 85 | self._pub_clock = Publisher.new(self._conx, "clock", rosgraph_msgs_Clock) 86 | 87 | print("modROS (" .. ModROS.MOD_VERSION .. ") loaded") 88 | end 89 | 90 | function ModROS.installSpecializations(vehicleTypeManager, specializationManager, modDirectory, modName) 91 | specializationManager:addSpecialization("rosVehicle", "RosVehicle", Utils.getFilename("src/vehicles/RosVehicle.lua", modDirectory), nil) -- Nil is important here 92 | 93 | for typeName, typeEntry in pairs(vehicleTypeManager:getVehicleTypes()) do 94 | -- only add rosVehicle spec to vechile types thathave prerequiste drivable spec 95 | -- if there is no this condition, the will be added to all vehicle types regardless of having drivable spec as prerequisite 96 | -- there would be errors occur when running RosVehicle.prerequisitesPresent() 97 | -- hence, only if the prerequisites of specialization are fulfilled, specializations will be installed 98 | if SpecializationUtil.hasSpecialization(Drivable, typeEntry.specializations) then 99 | vehicleTypeManager:addSpecialization(typeName, modName .. ".rosVehicle") 100 | end 101 | end 102 | 103 | end 104 | 105 | function ModROS:update(dt) 106 | -- create TFMessage object 107 | self.tf_msg = tf2_msgs_TFMessage.new() 108 | 109 | if self.doPubMsg then 110 | -- avoid writing to the pipe if it isn't actually open 111 | if self._conx:is_connected() then 112 | self:publish_sim_time_func() 113 | self:publish_veh_odom_func() 114 | self:publish_laser_scan_func() 115 | self:publish_imu_func() 116 | self._pub_tf:publish(self.tf_msg) 117 | 118 | end 119 | end 120 | 121 | if self.doRosControl then 122 | self:subscribe_ROScontrol_func(dt) 123 | end 124 | if self.doCenterCamera then 125 | if g_currentMission.controlledVehicle == nil then 126 | print("You have left your vehicle! Stop force-centering camera") 127 | self.doCenterCamera = false 128 | else 129 | center_camera_func() 130 | end 131 | end 132 | end 133 | 134 | 135 | -- A.1 sim_time publisher: publish the farmsim time 136 | function ModROS:publish_sim_time_func() 137 | local msg = rosgraph_msgs_Clock.new() 138 | msg.clock = ros.Time.now() 139 | self._pub_clock:publish(msg) 140 | end 141 | 142 | 143 | -- A.2. odom publisher 144 | -- a function to publish ground-truth Pose and Twist of all vehicles (including non-drivable) based on their in-game position and orientation 145 | function ModROS:publish_veh_odom_func() 146 | -- FS time is "frozen" within a single call to update(..), so this 147 | -- will assign the same stamp to all Odometry messages 148 | local ros_time = ros.Time.now() 149 | for _, vehicle in pairs(g_currentMission.vehicles) do 150 | -- only if the vehicle is spec_rosVehicle, the pubOdom() can be called 151 | if vehicle.spec_rosVehicle then 152 | vehicle:pubOdom(ros_time, self.tf_msg) 153 | end 154 | end 155 | end 156 | 157 | 158 | -- A.3. laser scan publisher 159 | function ModROS:publish_laser_scan_func() 160 | -- FS time is "frozen" within a single call to update(..), so this 161 | -- will assign the same stamp to all LaserScan messages 162 | local ros_time = ros.Time.now() 163 | for _, vehicle in pairs(g_currentMission.vehicles) do 164 | -- only if the vehicle is spec_rosVehicle, the pubLaserScan() can be called 165 | if vehicle.spec_rosVehicle then 166 | vehicle:pubLaserScan(ros_time, self.tf_msg) 167 | end 168 | end 169 | end 170 | 171 | 172 | -- A.4. imu publisher 173 | -- a function to publish get the position and orientaion of unmanned or manned vehicle(s) get and write to the named pipe (symbolic link) 174 | function ModROS:publish_imu_func() 175 | 176 | local ros_time = ros.Time.now() 177 | for _, vehicle in pairs(g_currentMission.vehicles) do 178 | if vehicle.spec_rosVehicle then 179 | vehicle:pubImu(ros_time) 180 | end 181 | end 182 | end 183 | 184 | -- A.5. Console command allows to toggle publishers on/off: "rosPubMsg true/false" 185 | -- messages publisher console command 186 | addConsoleCommand("rosPubMsg", "write ros messages to named pipe", "rosPubMsg", ModROS) 187 | function ModROS:rosPubMsg(flag) 188 | if flag ~= nil and flag ~= "" and flag == "true" then 189 | 190 | if not self._conx:is_connected() then 191 | print("connecting to named pipe") 192 | local ret, err = self._conx:connect() 193 | if ret then 194 | print("Opened '" .. self._conx:get_uri() .. "'") 195 | else 196 | -- if not, print error to console and return 197 | print(("Could not connect: %s"):format(err)) 198 | print("Possible reasons:") 199 | print(" - symbolic link was not created") 200 | print(" - the 'all_in_one_publisher.py' script is not running") 201 | return 202 | end 203 | end 204 | -- initialisation was successful 205 | self.doPubMsg = true 206 | 207 | elseif flag == nil or flag == "" or flag == "false" then 208 | self.doPubMsg = false 209 | print("stop publishing data, set true, if you want to publish Pose") 210 | 211 | local ret, err = self._conx:disconnect() 212 | if not ret then 213 | print(("Could not disconnect: %s"):format(err)) 214 | else 215 | print("Disconnected") 216 | end 217 | end 218 | end 219 | 220 | 221 | -- B.1. ros_cmd_teleop subscriber 222 | -- a function to input the ROS geometry_msgs/Twist into the game to take over control of all vehicles 223 | function ModROS:subscribe_ROScontrol_func(dt) 224 | for _, vehicle in pairs(g_currentMission.vehicles) do 225 | if vehicle.spec_drivable then 226 | -- retrieve the first 32 chars from the buffer 227 | -- note: this does not remove them, it simply copies them 228 | local buf_read = self.buf:read(64) 229 | 230 | -- print to the game console if what we've found in the buffer is different 231 | -- from what was there the previous iteration 232 | -- the counter is just there to make sure we don't see the same line twice 233 | local allowedToDrive = false 234 | if buf_read ~= self.last_read and buf_read ~= "" then 235 | self.last_read = buf_read 236 | local read_str_list = {} 237 | -- loop over whitespace-separated components 238 | for read_str in string.gmatch(self.last_read, "%S+") do 239 | table.insert(read_str_list, read_str) 240 | end 241 | 242 | self.acc = tonumber(read_str_list[1]) 243 | self.rotatedTime_param = tonumber(read_str_list[2]) 244 | allowedToDrive = read_str_list[3] 245 | end 246 | 247 | if allowedToDrive == "true" then 248 | self.allowedToDrive = true 249 | elseif allowedToDrive == "false" then 250 | self.allowedToDrive = false 251 | end 252 | 253 | vehicle_util.ROSControl(vehicle, dt, self.acc, self.allowedToDrive, self.rotatedTime_param) 254 | end 255 | end 256 | end 257 | 258 | 259 | 260 | -- B.2. A command for taking over control of a vehicle in the game : "rosControlVehicle true/false" 261 | 262 | -- TODO Allow control of vehicles other than the 'active one'. (the console name has already been changed, but the implementation hasn't yet) 263 | 264 | -- console command to take over control of all vehicles in the game 265 | addConsoleCommand("rosControlVehicle", "let ROS control the current vehicle", "rosControlVehicle", ModROS) 266 | function ModROS:rosControlVehicle(flag) 267 | if flag ~= nil and flag ~= "" and flag == "true" then 268 | self.doRosControl = true 269 | print("start ROS teleoperation") 270 | elseif flag == nil or flag == "" or flag == "false" then 271 | self.doRosControl = false 272 | print("stop ROS teleoperation") 273 | end 274 | end 275 | 276 | 277 | -- C.1 A command for force-centering the current camera: "forceCenteredCamera true/false" 278 | -- centering the camera by setting the camera rotX, rotY to original angles 279 | addConsoleCommand("forceCenteredCamera", "force-center the current camera", "forceCenteredCamera", ModROS) 280 | function ModROS:forceCenteredCamera(flag) 281 | if flag ~= nil and flag ~= "" and flag == "true" then 282 | if g_currentMission.controlledVehicle ~= nil then 283 | print("start centering the camera") 284 | self.doCenterCamera = true 285 | else 286 | print("You have left your vehicle, come on! Please hop in one and type the command again!") 287 | end 288 | elseif flag == nil or flag == "" or flag == "false" then 289 | self.doCenterCamera = false 290 | print("stop centering the camera") 291 | end 292 | end 293 | 294 | addModEventListener(ModROS) 295 | -------------------------------------------------------------------------------- /src/mod_config.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | mod_config = 21 | { 22 | control_only_active_vehicle = false, 23 | vehicle = { 24 | case_ih_7210_pro = { 25 | laser_scan = { 26 | enabled = true, 27 | num_rays = 64, 28 | num_layers = 2, 29 | angle_min = -math.pi, 30 | angle_max = math.pi, 31 | range_min = 0.1, 32 | range_max = 30, 33 | ignore_terrain = true, 34 | inter_layer_distance = 0.1, 35 | -- apply a transform to first laser scan frame 36 | laser_transform = { 37 | translation = { 38 | x = 0.0, 39 | -- This lowers the origin of the scanner to be more in at an expected hight 40 | -- since the original attachment point is on the bonnet and it's too high to see important obstacles 41 | y = -1.5, 42 | z = 0.0 43 | }, 44 | rotation = { 45 | -- positive rotation over X rotates laser scanner down (ie: math.pi/6) 46 | x = 0.0, 47 | y = 0.0, 48 | z = 0.0 49 | } 50 | }, 51 | laser_attachments = "raycastNode(0)" 52 | }, 53 | -- the collision_mask for raycasting can be customized. Both 54 | -- decimal and hexadecimal notations are supported (ie: 9 and 0x9). 55 | -- if 'nil', the default mask will be used. 56 | -- TODO: describe what the "default mask" is exactly (which classes of objects are included / have their bit set to 1). 57 | raycast = { 58 | collision_mask = nil 59 | }, 60 | imu = { 61 | enabled = true 62 | } 63 | }, 64 | diesel_locomotive = { 65 | laser_scan = { 66 | enabled = false, 67 | num_rays = 64, 68 | num_layers = 2, 69 | angle_min = -math.pi, 70 | angle_max = math.pi, 71 | range_min = 0.1, 72 | range_max = 30, 73 | ignore_terrain = true, 74 | inter_layer_distance = 0.1, 75 | -- apply a transform to first laser scan frame 76 | laser_transform = { 77 | translation = { 78 | x = 0.0, 79 | -- This lowers the origin of the scanner to be more in at an expected hight 80 | -- since the original attachment point is on the bonnet and it's too high to see important obstacles 81 | y = -1.5, 82 | z = 0.0 83 | }, 84 | rotation = { 85 | -- positive rotation over X rotates laser scanner down (ie: math.pi/6) 86 | x = 0.0, 87 | y = 0.0, 88 | z = 0.0 89 | } 90 | }, 91 | laser_attachments = "raycastNode(0)" 92 | }, 93 | -- the collision_mask for raycasting can be customized. Both 94 | -- decimal and hexadecimal notations are supported (ie: 9 and 0x9). 95 | raycast = { 96 | collision_mask = nil 97 | }, 98 | imu = { 99 | enabled = false 100 | } 101 | }, 102 | fiat_1300dt = { 103 | laser_scan = { 104 | enabled = true, 105 | num_rays = 64, 106 | num_layers = 2, 107 | angle_min = -math.pi, 108 | angle_max = math.pi, 109 | range_min = 0.1, 110 | range_max = 30, 111 | ignore_terrain = true, 112 | inter_layer_distance = 0.1, 113 | -- apply a transform to first laser scan frame 114 | laser_transform = { 115 | translation = { 116 | x = 0.0, 117 | -- This lowers the origin of the scanner to be more in at an expected hight 118 | -- since the original attachment point is on the bonnet and it's too high to see important obstacles 119 | y = -1.5, 120 | z = 0.0 121 | }, 122 | rotation = { 123 | -- positive rotation over X rotates laser scanner down (ie: math.pi/6) 124 | x = 0.0, 125 | y = 0.0, 126 | z = 0.0 127 | } 128 | }, 129 | laser_attachments = "raycastNode(0)" 130 | }, 131 | -- the collision_mask for raycasting can be customized. Both 132 | -- decimal and hexadecimal notations are supported (ie: 9 and 0x9). 133 | raycast = { 134 | collision_mask = nil 135 | }, 136 | imu = { 137 | enabled = true 138 | } 139 | }, 140 | new_holland_tx_32 = { 141 | laser_scan = { 142 | enabled = true, 143 | num_rays = 64, 144 | num_layers = 2, 145 | angle_min = -math.pi, 146 | angle_max = math.pi, 147 | range_min = 0.1, 148 | range_max = 30, 149 | ignore_terrain = true, 150 | inter_layer_distance = 0.1, 151 | -- apply a transform to first laser scan frame 152 | laser_transform = { 153 | translation = { 154 | x = 0.0, 155 | -- This lowers the origin of the scanner to be more in at an expected hight 156 | -- since the original attachment point is on the bonnet and it's too high to see important obstacles 157 | y = -3, 158 | z = 0.0 159 | }, 160 | rotation = { 161 | -- positive rotation over X rotates laser scanner down (ie: math.pi/6) 162 | x = 0.0, 163 | y = 0.0, 164 | z = 0.0 165 | } 166 | }, 167 | laser_attachments = "raycastNode(0)" 168 | }, 169 | -- the collision_mask for raycasting can be customized. Both 170 | -- decimal and hexadecimal notations are supported (ie: 9 and 0x9). 171 | raycast = { 172 | collision_mask = nil 173 | }, 174 | imu = { 175 | enabled = true 176 | } 177 | }, 178 | default_vehicle = { 179 | laser_scan = { 180 | enabled = true, 181 | num_rays = 64, 182 | num_layers = 2, 183 | angle_min = -math.pi, 184 | angle_max = math.pi, 185 | range_min = 0.1, 186 | range_max = 30, 187 | ignore_terrain = true, 188 | inter_layer_distance = 0.1, 189 | -- apply a transform to first laser scan frame 190 | laser_transform = { 191 | translation = { 192 | x = 0.0, 193 | -- This lowers the origin of the scanner to be more in at an expected hight 194 | -- since the original attachment point is on the bonnet and it's too high to see important obstacles 195 | y = -1.5, 196 | z = 0.0 197 | }, 198 | rotation = { 199 | -- positive rotation over X rotates laser scanner down (ie: math.pi/6) 200 | x = 0.0, 201 | y = 0.0, 202 | z = 0.0 203 | } 204 | }, 205 | laser_attachments = "raycastNode(0)" 206 | }, 207 | -- the collision_mask for raycasting can be customized. Both 208 | -- decimal and hexadecimal notations are supported (ie: 9 and 0x9). 209 | raycast = { 210 | collision_mask = nil 211 | }, 212 | imu = { 213 | enabled = true 214 | } 215 | }, 216 | } 217 | } 218 | 219 | return mod_config 220 | -------------------------------------------------------------------------------- /src/msgs/geometry_msgs_transform_stamped.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | -- geometry_msgs_TransformStamped class 21 | geometry_msgs_TransformStamped = {} 22 | geometry_msgs_TransformStamped.ROS_MSG_NAME = "geometry_msgs/TransformStamped" 23 | 24 | local geometry_msgs_TransformStamped_mt = Class(geometry_msgs_TransformStamped) 25 | 26 | function geometry_msgs_TransformStamped.new() 27 | local self = {} 28 | setmetatable(self, geometry_msgs_TransformStamped_mt) 29 | 30 | -- fields as defined by geometry_msgs/TransformStamped 31 | self.header = { 32 | frame_id = "", 33 | stamp = { 34 | secs = 0, 35 | nsecs = 0 36 | } 37 | } 38 | self.child_frame_id = "" 39 | self.transform = { 40 | translation = { 41 | x = 0.0, 42 | y = 0.0, 43 | z = 0.0 44 | }, 45 | rotation = { 46 | x = 0.0, 47 | y = 0.0, 48 | z = 0.0, 49 | w = 0.0 50 | } 51 | } 52 | 53 | return self 54 | end 55 | 56 | function geometry_msgs_TransformStamped:delete() 57 | end 58 | 59 | function geometry_msgs_TransformStamped:set(frame_id, stamp, child_frame_id, tx, ty, tz, qx, qy, qz, qw) 60 | -- directly overwrite local fields 61 | self.header = { 62 | frame_id = frame_id, 63 | stamp = stamp 64 | } 65 | self.child_frame_id = child_frame_id 66 | self.transform = { 67 | translation = { 68 | x = tx, 69 | y = ty, 70 | z = tz 71 | }, 72 | rotation = { 73 | x = qx, 74 | y = qy, 75 | z = qz, 76 | w = qw 77 | } 78 | } 79 | end 80 | 81 | function geometry_msgs_TransformStamped:to_json() 82 | return json.stringify(self) 83 | end 84 | -------------------------------------------------------------------------------- /src/msgs/nav_msgs_odometry.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | nav_msgs_Odometry = {} 21 | nav_msgs_Odometry.ROS_MSG_NAME = "nav_msgs/Odometry" 22 | 23 | local nav_msgs_Odometry_mt = Class(nav_msgs_Odometry) 24 | 25 | function nav_msgs_Odometry.new() 26 | local self = {} 27 | setmetatable(self, nav_msgs_Odometry_mt) 28 | 29 | -- fields as defined by nav_msgs/Odometry 30 | self.header = { 31 | frame_id = "", 32 | stamp = {secs = 0, nsecs = 0} 33 | } 34 | self.child_frame_id = "" 35 | self.pose = { 36 | pose = { 37 | position = { 38 | x = 0.0, 39 | y = 0.0, 40 | z = 0.0 41 | }, 42 | orientation = { 43 | x = 0.0, 44 | y = 0.0, 45 | z = 0.0, 46 | w = 0.0 47 | } 48 | } 49 | } 50 | self.twist = { 51 | twist = { 52 | linear = { 53 | x = 0.0, 54 | y = 0.0, 55 | z = 0.0 56 | }, 57 | angular = { 58 | x = 0.0, 59 | y = 0.0, 60 | z = 0.0 61 | } 62 | } 63 | } 64 | 65 | return self 66 | end 67 | 68 | function nav_msgs_Odometry:delete() 69 | end 70 | 71 | function nav_msgs_Odometry:set(frame_id, stamp, child_frame_id, px, py, pz, qx, qy, qz, qw, tlx, tly, tlz, tax, tay, taz) 72 | -- directly overwrite local fields 73 | self.header = { 74 | frame_id = frame_id, 75 | stamp = stamp 76 | } 77 | self.child_frame_id = child_frame_id 78 | self.pose = { 79 | pose = { 80 | position = { 81 | x = pz, 82 | y = px, 83 | z = py 84 | }, 85 | orientation = { 86 | x = qx, 87 | y = qy, 88 | z = qz, 89 | w = qw 90 | } 91 | } 92 | } 93 | self.twist = { 94 | twist = { 95 | linear = { 96 | x = tlx, 97 | y = tly, 98 | z = tlz 99 | }, 100 | angular = { 101 | x = tax, 102 | y = tay, 103 | z = taz 104 | } 105 | } 106 | } 107 | end 108 | 109 | function nav_msgs_Odometry:to_json() 110 | return json.stringify(self) 111 | end 112 | -------------------------------------------------------------------------------- /src/msgs/rosgraph_msgs_clock.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | -- rosgraph_msgs_Clock class 21 | rosgraph_msgs_Clock = {} 22 | rosgraph_msgs_Clock.ROS_MSG_NAME = "rosgraph_msgs/Clock" 23 | 24 | local rosgraph_msgs_Clock_mt = Class(rosgraph_msgs_Clock) 25 | 26 | function rosgraph_msgs_Clock.new() 27 | local self = {} 28 | setmetatable(self, rosgraph_msgs_Clock_mt) 29 | 30 | -- fields as defined by rosgraph_msgs/Clock 31 | self.clock = {secs = 0, nsecs = 0} 32 | 33 | return self 34 | end 35 | 36 | function rosgraph_msgs_Clock:delete() 37 | end 38 | 39 | function rosgraph_msgs_Clock:set(clock) 40 | -- directly overwrite local fields 41 | self.clock = clock 42 | end 43 | 44 | function rosgraph_msgs_Clock:to_json() 45 | return json.stringify(self) 46 | end 47 | -------------------------------------------------------------------------------- /src/msgs/sensor_msgs_imu.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | -- sensor_msgs_Imu class 21 | sensor_msgs_Imu = {} 22 | sensor_msgs_Imu.ROS_MSG_NAME = "sensor_msgs/Imu" 23 | 24 | local sensor_msgs_Imu_mt = Class(sensor_msgs_Imu) 25 | 26 | function sensor_msgs_Imu.new() 27 | local self = {} 28 | setmetatable(self, sensor_msgs_Imu_mt) 29 | 30 | -- fields as defined by sensor_msgs/Imu 31 | self.header = { 32 | frame_id = "", 33 | stamp = {secs = 0, nsecs = 0} 34 | } 35 | self.orientation = { 36 | x = 0.0, 37 | y = 0.0, 38 | z = 0.0, 39 | w = 0.0 40 | } 41 | self.angular_velocity = { 42 | x = 0.0, 43 | y = 0.0, 44 | z = 0.0 45 | } 46 | self.linear_acceleration = { 47 | x = 0.0, 48 | y = 0.0, 49 | z = 0.0 50 | } 51 | 52 | return self 53 | end 54 | 55 | function sensor_msgs_Imu:delete() 56 | end 57 | 58 | function sensor_msgs_Imu:set(frame_id, stamp, qx, qy, qz, qw, avx, avy, avz, lax, lay, laz) 59 | -- directly overwrite local fields 60 | self.header = { 61 | frame_id = frame_id, 62 | stamp = stamp 63 | } 64 | self.orientation = { 65 | x = qx, 66 | y = qy, 67 | z = qz, 68 | w = qw 69 | } 70 | self.angular_velocity = { 71 | x = avx, 72 | y = avy, 73 | z = avz 74 | } 75 | self.linear_acceleration = { 76 | x = lax, 77 | y = lay, 78 | z = laz 79 | } 80 | end 81 | 82 | function sensor_msgs_Imu:to_json() 83 | return json.stringify(self) 84 | end 85 | -------------------------------------------------------------------------------- /src/msgs/sensor_msgs_laser_scan.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | -- sensor_msgs_LaserScan class 21 | sensor_msgs_LaserScan = {} 22 | sensor_msgs_LaserScan.ROS_MSG_NAME = "sensor_msgs/LaserScan" 23 | 24 | local sensor_msgs_LaserScan_mt = Class(sensor_msgs_LaserScan) 25 | 26 | function sensor_msgs_LaserScan.new() 27 | local self = {} 28 | setmetatable(self, sensor_msgs_LaserScan_mt) 29 | 30 | -- fields as defined by sensor_msgs/LaserScan 31 | self.header = { 32 | frame_id = "", 33 | stamp = {secs = 0, nsecs = 0} 34 | } 35 | self.angle_min = 0.0 36 | self.angle_max = 0.0 37 | self.angle_increment = 0.0 38 | self.time_increment = 0.0 39 | self.scan_time = 0.0 40 | self.range_min = 0.0 41 | self.range_max = 0.0 42 | self.ranges = {} 43 | self.intensities = {} 44 | 45 | return self 46 | end 47 | 48 | function sensor_msgs_LaserScan:delete() 49 | end 50 | 51 | function sensor_msgs_LaserScan:set( 52 | frame_id, 53 | stamp, 54 | angle_min, 55 | angle_max, 56 | angle_increment, 57 | time_increment, 58 | scan_time, 59 | range_min, 60 | range_max, 61 | ranges, 62 | intensities) 63 | -- directly overwrite local fields 64 | self.header = { 65 | frame_id = frame_id, 66 | stamp = stamp 67 | } 68 | self.angle_min = angle_min 69 | self.angle_max = angle_max 70 | self.angle_increment = angle_increment 71 | self.time_increment = time_increment 72 | self.scan_time = scan_time 73 | self.range_min = range_min 74 | self.range_max = range_max 75 | self.ranges = ranges 76 | self.intensities = intensities 77 | end 78 | 79 | function sensor_msgs_LaserScan:to_json() 80 | return json.stringify(self) 81 | end 82 | -------------------------------------------------------------------------------- /src/msgs/tf2_msgs_tf_message.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | -- tf2_msgs_TFMessage class 21 | tf2_msgs_TFMessage = {} 22 | tf2_msgs_TFMessage.ROS_MSG_NAME = "tf2_msgs/TFMessage" 23 | 24 | local tf2_msgs_TFMessage_mt = Class(tf2_msgs_TFMessage) 25 | 26 | function tf2_msgs_TFMessage.new() 27 | local self = {} 28 | setmetatable(self, tf2_msgs_TFMessage_mt) 29 | 30 | -- fields as defined by tf2_msgs/TFMessage 31 | self.transforms = {} 32 | 33 | return self 34 | end 35 | 36 | function tf2_msgs_TFMessage:delete() 37 | end 38 | 39 | function tf2_msgs_TFMessage:set(transforms) 40 | -- directly overwrite local fields 41 | self.transforms = transforms 42 | end 43 | 44 | function tf2_msgs_TFMessage:add_transform(transform) 45 | table.insert(self.transforms, transform) 46 | end 47 | 48 | function tf2_msgs_TFMessage:to_json() 49 | return json.stringify(self) 50 | end 51 | -------------------------------------------------------------------------------- /src/ros/Publisher.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Copyright (c) 2021, TU Delft 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | 18 | author: Ting-Chia Chiang, G.A. vd. Hoorn 19 | maintainer: Ting-Chia Chiang, G.A. vd. Hoorn 20 | 21 | --]] 22 | 23 | Publisher = {} 24 | 25 | local Publisher_mt = Class(Publisher) 26 | 27 | 28 | function Publisher.new(connection, topic_name, message_type) 29 | local self = {} 30 | setmetatable(self, Publisher_mt) 31 | 32 | if message_type['ROS_MSG_NAME'] == nil then 33 | -- TODO: implement proper logging 34 | print(("message_type must have ROS_MSG_NAME key, can't find it in '%s'"):format(message_type)) 35 | return nil, "ctor error: invalid message_type" 36 | end 37 | 38 | -- NOTE: there is no locking, so concurrent access to the connection is not 39 | -- guarded against. Serialisation of access is responsibility of owner of 40 | -- the Publisher object 41 | self._conx = connection 42 | 43 | -- "topic_name" could be with or without namespace 44 | -- with e.g. "/odom" 45 | -- wihtout e.g. "clock" 46 | self._topic_name = topic_name 47 | 48 | -- we need this to be able to tell the Python side what sort of message 49 | -- we're serialising 50 | self._message_type_name = message_type.ROS_MSG_NAME 51 | 52 | return self 53 | end 54 | 55 | function Publisher:delete() 56 | -- nothing to do. Connection object is not owned by this Publisher 57 | end 58 | 59 | function Publisher:publish(msg) 60 | if msg.ROS_MSG_NAME ~= self._message_type_name then 61 | return nil, ("Can't publish '%s' with publisher of type '%s'"):format(msg.ROS_MSG_NAME, self._message_type_name) 62 | end 63 | if not self._conx:is_connected() then 64 | return nil, "Can't write to nil fd" 65 | end 66 | 67 | -- try writing the serialised message to the connection 68 | local ret, err = self._conx:write(self._topic_name .. "\n" .. msg.ROS_MSG_NAME .. "\n" .. msg:to_json()) 69 | if not ret then 70 | return nil, "Error publishing message: '" .. err .. "'" 71 | end 72 | return ret 73 | end 74 | -------------------------------------------------------------------------------- /src/ros/WriteOnlyFileConnection.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | 3 | Copyright (c) 2021, TU Delft 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | 18 | author: Ting-Chia Chiang, G.A. vd. Hoorn 19 | maintainer: Ting-Chia Chiang, G.A. vd. Hoorn 20 | 21 | --]] 22 | 23 | WriteOnlyFileConnection = {} 24 | 25 | local WriteOnlyFileConnection_mt = Class(WriteOnlyFileConnection) 26 | 27 | 28 | function WriteOnlyFileConnection.new(uri) 29 | local self = {} 30 | setmetatable(self, WriteOnlyFileConnection_mt) 31 | 32 | self._uri = uri 33 | self._fd = nil 34 | 35 | return self 36 | end 37 | 38 | function WriteOnlyFileConnection:delete() 39 | self:close() 40 | end 41 | 42 | function WriteOnlyFileConnection:get_uri() 43 | return self._uri 44 | end 45 | 46 | function WriteOnlyFileConnection:_open() 47 | -- NOTE: this is not guarded in any way 48 | -- TODO: allow specifying flags 49 | self._fd = io.open(self._uri, "w") 50 | if not self._fd then 51 | return nil, "Could not open uri: unknown reason (FS Lua does not provide one)" 52 | end 53 | return true 54 | end 55 | 56 | function WriteOnlyFileConnection:_close() 57 | -- NOTE: this is not guarded in any way 58 | self._fd:close() 59 | self._fd = nil 60 | return true 61 | end 62 | 63 | function WriteOnlyFileConnection:connect() 64 | -- only connect if we're not already connected 65 | if self:is_connected() then 66 | return nil, "Already connected" 67 | end 68 | 69 | local ret, err = self:_open() 70 | if not ret then 71 | return nil, "Could not connect: '" .. err .. "'" 72 | end 73 | return ret 74 | end 75 | 76 | function WriteOnlyFileConnection:disconnect() 77 | -- only disconnect if we're actually connected 78 | if not self:is_connected() then 79 | return nil, "Not connected" 80 | end 81 | 82 | local ret, err = self:_close() 83 | if not ret then 84 | return nil, "Could not disconnect: '" .. err .. "'" 85 | end 86 | return ret 87 | end 88 | 89 | function WriteOnlyFileConnection:get_fd() 90 | return self._fd 91 | end 92 | 93 | function WriteOnlyFileConnection:is_connected() 94 | --TODO: find a better way to figure out whether a file is still open. 95 | -- io.type(..) does not appear to be supported :( 96 | return (self._fd ~= nil) 97 | end 98 | 99 | function WriteOnlyFileConnection:write(data) 100 | if not self:is_connected() then 101 | return nil, "Not connected" 102 | end 103 | -- does write() return anything? 104 | self._fd:write(data) 105 | return true 106 | end 107 | -------------------------------------------------------------------------------- /src/utils/LaserScanner.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | author: Ting-Chia Chiang 13 | author: G.A. vd. Hoorn 14 | --]] 15 | 16 | LaserScanner = {} 17 | 18 | local LaserScanner_mt = Class(LaserScanner) 19 | 20 | function LaserScanner.new(vehicle, vehicle_table) 21 | local self = {} 22 | setmetatable(self, LaserScanner_mt) 23 | 24 | -- store a reference to the table with settings for this scanner instance 25 | self.vehicle_table = vehicle_table 26 | -- store a reference to the vehicle this scanner is attached to 27 | self.vehicle = vehicle 28 | 29 | -- initial raycast distance 30 | self.INIT_RAY_DISTANCE = 1000 31 | -- set a raycast mask for a camera node which enables bits 5(unkown), 6(tractors), 7(combines), 8(trailers), 12(dynamic_objects) 32 | local RC_MASK_UNKNOWN5 = math.pow(2, 5) 33 | local RC_MASK_TRACTORS = math.pow(2, 6) 34 | local RC_MASK_COMBINES = math.pow(2, 7) 35 | local RC_MASK_TRAILERS = math.pow(2, 8) 36 | local RC_MASK_DYN_OBJS = math.pow(2, 12) 37 | 38 | -- if provided, use custom collision mask. If not, use default. 39 | if self.collision_mask then 40 | self.raycastMask = self.collision_mask 41 | -- print(("Using custom collision mask for laser scanner: 0x%08X"):format(self.raycastMask)) 42 | else 43 | self.raycastMask = RC_MASK_UNKNOWN5 + RC_MASK_TRACTORS + RC_MASK_COMBINES + RC_MASK_TRAILERS + RC_MASK_DYN_OBJS 44 | -- print(("Using default collision mask for laser scanner: 0x%08X"):format(self.raycastMask)) 45 | end 46 | 47 | self.cos = math.cos 48 | self.sin = math.sin 49 | self.radius = 0.2 50 | self.LS_FOV = self.vehicle_table.laser_scan.angle_max - self.vehicle_table.laser_scan.angle_min 51 | -- calculate nr of steps between rays 52 | self.delta_theta = self.LS_FOV / (self.vehicle_table.laser_scan.num_rays - 1) 53 | 54 | return self 55 | end 56 | 57 | 58 | function LaserScanner:getLaserData(laser_scan_array, x, y, z, dx_r, dy, dz_r) 59 | self.raycastDistance = self.INIT_RAY_DISTANCE 60 | raycastClosest(x, y, z, dx_r, dy, dz_r, "raycastCallback", self.vehicle_table.laser_scan.range_max, self, self.raycastMask) 61 | -- push back the self.raycastDistance to self.laser_scan_array table 62 | -- if self.raycastDistance is updated which mean there is object detected and raycastCallback is called 63 | -- otherwise, fill the range with self.INIT_RAY_DISTANCE (1000) (no object detected) 64 | -- if laser_scan.ignore_terrain is set true then ignore the terrain when detected 65 | 66 | if self.vehicle_table.laser_scan.ignore_terrain then 67 | -- this is a temporary method to filter out laser hits on the vehicle itself 68 | -- in FS, there are many vehicles composed of 2 components: the first component is the main part and the second component is mostly the axis object(s). 69 | -- however, some driveable vehicles do not have a 2nd component (e.g. diesel_locomotive). We need to exclude the condition of hitting 2nd component, if there exists no 2nd compoenent 70 | if not self.vehicle.components[2] then 71 | if self.raycastDistance ~= self.INIT_RAY_DISTANCE and self.raycastTransformId ~= g_currentMission.terrainRootNode and self.raycastTransformId ~= self.vehicle.components[1].node then 72 | table.insert(laser_scan_array, self.raycastDistance) 73 | else 74 | table.insert(laser_scan_array, self.INIT_RAY_DISTANCE) 75 | end 76 | else 77 | if self.raycastDistance ~= self.INIT_RAY_DISTANCE and self.raycastTransformId ~= g_currentMission.terrainRootNode and self.raycastTransformId ~= self.vehicle.components[1].node and self.raycastTransformId ~= self.vehicle.components[2].node then 78 | table.insert(laser_scan_array, self.raycastDistance) 79 | else 80 | table.insert(laser_scan_array, self.INIT_RAY_DISTANCE) 81 | end 82 | end 83 | else 84 | if self.raycastDistance ~= self.INIT_RAY_DISTANCE then 85 | table.insert(laser_scan_array, self.raycastDistance) 86 | else 87 | table.insert(laser_scan_array, self.INIT_RAY_DISTANCE) 88 | end 89 | end 90 | end 91 | 92 | 93 | function LaserScanner:raycastCallback(transformId, _, _, _, distance, _, _, _) 94 | self.raycastDistance = distance 95 | self.raycastTransformId = transformId 96 | -- for debugging 97 | -- self.object = g_currentMission:getNodeObject(self.raycastTransformId) 98 | -- print(string.format("hitted object is %s",getName(self.raycastTransformId))) 99 | -- print(string.format("hitted object id is %f",self.raycastTransformId)) 100 | -- print(string.format("self.raycastDistance is %f",self.raycastDistance)) 101 | -- print("v_id ",g_currentMission.controlledVehicle.components[1].node) 102 | end 103 | 104 | 105 | function LaserScanner:doScan(ros_time, tf_msg) 106 | local spec = self.vehicle.spec_rosVehicle 107 | 108 | for i = 0, spec.laser_scan_obj.vehicle_table.laser_scan.num_layers-1 do 109 | spec.laser_scan_array = {} 110 | -- get the (world) coordinate of each laser scanner's origin: (orig_x, orig_y, orig_z) 111 | -- "laser_dy" is added between the scanning planes, along +y direction (locally) from the lowest laser scan plane 112 | -- and all laser scan planes are parallel to each other 113 | local laser_dy = spec.laser_scan_obj.vehicle_table.laser_scan.inter_layer_distance * i 114 | local orig_x, orig_y, orig_z = localToWorld(spec.LaserFrameNode, 0, laser_dy, 0) 115 | 116 | for j = 0, (spec.laser_scan_obj.vehicle_table.laser_scan.num_rays - 1) do 117 | local seg_theta = j * spec.laser_scan_obj.delta_theta 118 | -- (i_laser_dx, 0 , i_laser_dz) is a local space direction to define the world space raycasting (scanning) direction 119 | local i_laser_dx = -spec.laser_scan_obj.sin(seg_theta) * spec.laser_scan_obj.radius 120 | local i_laser_dz = -spec.laser_scan_obj.cos(seg_theta) * spec.laser_scan_obj.radius 121 | local dx, dy, dz = localDirectionToWorld(spec.LaserFrameNode, i_laser_dx, 0 , i_laser_dz) 122 | spec.laser_scan_obj:getLaserData(spec.laser_scan_array, orig_x, orig_y, orig_z, dx, dy, dz) 123 | end 124 | 125 | -- create LaserScan instance 126 | local scan_msg = sensor_msgs_LaserScan.new() 127 | 128 | -- populate fields (not using LaserScan:set(..) here as this is much 129 | -- more readable than a long list of anonymous args) 130 | scan_msg.header.frame_id = spec.base_link_frame .."/laser_frame_" .. i 131 | scan_msg.header.stamp = ros_time 132 | -- with zero angle being forward along the x axis, scanning fov +-180 degrees 133 | scan_msg.angle_min = spec.laser_scan_obj.vehicle_table.laser_scan.angle_min 134 | scan_msg.angle_max = spec.laser_scan_obj.vehicle_table.laser_scan.angle_max 135 | scan_msg.angle_increment = spec.laser_scan_obj.LS_FOV / spec.laser_scan_obj.vehicle_table.laser_scan.num_rays 136 | -- assume sensor gives 50 scans per second 137 | scan_msg.time_increment = (1.0 / 50) / spec.laser_scan_obj.vehicle_table.laser_scan.num_rays 138 | --scan_msg.scan_time = 0.0 -- we don't set this field (TODO: should we?) 139 | scan_msg.range_min = spec.laser_scan_obj.vehicle_table.laser_scan.range_min 140 | scan_msg.range_max = spec.laser_scan_obj.vehicle_table.laser_scan.range_max 141 | scan_msg.ranges = spec.laser_scan_array 142 | --scan_msg.intensities = {} -- we don't set this field (TODO: should we?) 143 | 144 | -- publish the message 145 | spec.pub_scan:publish(scan_msg) 146 | 147 | -- convert to quaternion for ROS TF 148 | -- note the order of the axes here (see earlier comment about FS chirality) 149 | -- the rotation from base_link to raycastnode is the same as rotation from raycastnode to virtaul laser_frame_i as there is no rotation between base_link to raycastnode 150 | local q = ros.Transformations.quaternion_from_euler(spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.rotation.z, spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.rotation.x, spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.rotation.y) 151 | 152 | -- get the translation from base_link to laser_frame_i 153 | -- laser_dy is the offset from laser_frame_i to laser_frame_i+1 154 | local base_to_laser_x, base_to_laser_y, base_to_laser_z = localToLocal(spec.LaserFrameNode, self.vehicle.components[1].node, 0, laser_dy, 0) 155 | 156 | -- create single TransformStamped message 157 | local tf_base_link_laser_frame_i = geometry_msgs_TransformStamped.new() 158 | tf_base_link_laser_frame_i:set( 159 | spec.base_link_frame, 160 | ros_time, 161 | spec.base_link_frame .."/laser_frame_" .. i, 162 | -- note the order of the axes here (see earlier comment about FS chirality) 163 | base_to_laser_z, 164 | base_to_laser_x, 165 | base_to_laser_y, 166 | -- we don't need to swap the order of q, since the calculation of q is based on the ROS chirality 167 | q[1], 168 | q[2], 169 | q[3], 170 | q[4] 171 | ) 172 | spec:addTF(tf_msg, tf_base_link_laser_frame_i) 173 | end 174 | end 175 | -------------------------------------------------------------------------------- /src/utils/frames.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | frames = {} 21 | 22 | function frames.create_attached_node(parentNodeId, transformName, tran_x, tran_y, tran_z, rot_x, rot_y, rot_z) 23 | -- create a node 24 | local node = createTransformGroup(transformName) 25 | -- link the node to parentNodeId 26 | link(parentNodeId, node) 27 | -- apply a transfrom to the new node 28 | setTranslation(node, tran_x, tran_y, tran_z) 29 | setRotation(node, rot_x, rot_y, rot_z) 30 | return node 31 | end 32 | 33 | return frames 34 | 35 | -------------------------------------------------------------------------------- /src/utils/json.lua: -------------------------------------------------------------------------------- 1 | --[[ json.lua 2 | 3 | A compact pure-Lua JSON library. 4 | The main functions are: json.stringify, json.parse. 5 | 6 | ## json.stringify: 7 | 8 | This expects the following to be true of any tables being encoded: 9 | * They only have string or number keys. Number keys must be represented as 10 | strings in json; this is part of the json spec. 11 | * They are not recursive. Such a structure cannot be specified in json. 12 | 13 | A Lua table is considered to be an array if and only if its set of keys is a 14 | consecutive sequence of positive integers starting at 1. Arrays are encoded like 15 | so: `[2, 3, false, "hi"]`. Any other type of Lua table is encoded as a json 16 | object, encoded like so: `{"key1": 2, "key2": false}`. 17 | 18 | Because the Lua nil value cannot be a key, and as a table value is considerd 19 | equivalent to a missing key, there is no way to express the json "null" value in 20 | a Lua table. The only way this will output "null" is if your entire input obj is 21 | nil itself. 22 | 23 | An empty Lua table, {}, could be considered either a json object or array - 24 | it's an ambiguous edge case. We choose to treat this as an object as it is the 25 | more general type. 26 | 27 | To be clear, none of the above considerations is a limitation of this code. 28 | Rather, it is what we get when we completely observe the json specification for 29 | as arbitrary a Lua object as json is capable of expressing. 30 | 31 | ## json.parse: 32 | 33 | This function parses json, with the exception that it does not pay attention to 34 | \u-escaped unicode code points in strings. 35 | 36 | It is difficult for Lua to return null as a value. In order to prevent the loss 37 | of keys with a null value in a json string, this function uses the one-off 38 | table value json.null (which is just an empty table) to indicate null values. 39 | This way you can check if a value is null with the conditional 40 | `val == json.null`. 41 | 42 | If you have control over the data and are using Lua, I would recommend just 43 | avoiding null values in your data to begin with. 44 | 45 | --]] 46 | 47 | 48 | json = {} 49 | 50 | 51 | 52 | 53 | -- Internal functions. 54 | 55 | local function kind_of(obj) 56 | if type(obj) ~= 'table' then return type(obj) end 57 | local i = 1 58 | for _ in pairs(obj) do 59 | if obj[i] ~= nil then i = i + 1 else return 'table' end 60 | end 61 | if i == 1 then return 'table' else return 'array' end 62 | end 63 | 64 | local function escape_str(s) 65 | local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} 66 | local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} 67 | for i, c in ipairs(in_char) do 68 | s = s:gsub(c, '\\' .. out_char[i]) 69 | end 70 | return s 71 | end 72 | 73 | -- Returns pos, did_find; there are two cases: 74 | -- 1. Delimiter found: pos = pos after leading space + delim; did_find = true. 75 | -- 2. Delimiter not found: pos = pos after leading space; did_find = false. 76 | -- This throws an error if err_if_missing is true and the delim is not found. 77 | local function skip_delim(str, pos, delim, err_if_missing) 78 | pos = pos + #str:match('^%s*', pos) 79 | if str:sub(pos, pos) ~= delim then 80 | if err_if_missing then 81 | error('Expected ' .. delim .. ' near position ' .. pos) 82 | end 83 | return pos, false 84 | end 85 | return pos + 1, true 86 | end 87 | 88 | -- Expects the given pos to be the first character after the opening quote. 89 | -- Returns val, pos; the returned pos is after the closing quote character. 90 | local function parse_str_val(str, pos, val) 91 | val = val or '' 92 | local early_end_error = 'End of input found while parsing string.' 93 | if pos > #str then error(early_end_error) end 94 | local c = str:sub(pos, pos) 95 | if c == '"' then return val, pos + 1 end 96 | if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end 97 | -- We must have a \ character. 98 | local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'} 99 | local nextc = str:sub(pos + 1, pos + 1) 100 | if not nextc then error(early_end_error) end 101 | return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) 102 | end 103 | 104 | -- Returns val, pos; the returned pos is after the number's final character. 105 | local function parse_num_val(str, pos) 106 | local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) 107 | local val = tonumber(num_str) 108 | if not val then error('Error parsing number at position ' .. pos .. '.') end 109 | return val, pos + #num_str 110 | end 111 | 112 | 113 | -- Public values and functions. 114 | 115 | function json.stringify(obj, as_key) 116 | local s = {} -- We'll build the string as an array of strings to be concatenated. 117 | local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. 118 | if kind == 'array' then 119 | if as_key then error('Can\'t encode array as key.') end 120 | s[#s + 1] = '[' 121 | for i, val in ipairs(obj) do 122 | if i > 1 then s[#s + 1] = ', ' end 123 | s[#s + 1] = json.stringify(val) 124 | end 125 | s[#s + 1] = ']' 126 | elseif kind == 'table' then 127 | if as_key then error('Can\'t encode table as key.') end 128 | s[#s + 1] = '{' 129 | for k, v in pairs(obj) do 130 | if #s > 1 then s[#s + 1] = ', ' end 131 | s[#s + 1] = json.stringify(k, true) 132 | s[#s + 1] = ':' 133 | s[#s + 1] = json.stringify(v) 134 | end 135 | s[#s + 1] = '}' 136 | elseif kind == 'string' then 137 | return '"' .. escape_str(obj) .. '"' 138 | elseif kind == 'number' then 139 | if as_key then return '"' .. tostring(obj) .. '"' end 140 | return tostring(obj) 141 | elseif kind == 'boolean' then 142 | return tostring(obj) 143 | elseif kind == 'nil' then 144 | return 'null' 145 | else 146 | error('Unjsonifiable type: ' .. kind .. '.') 147 | end 148 | return table.concat(s) 149 | end 150 | 151 | json.null = {} -- This is a one-off table to represent the null value. 152 | 153 | function json.parse(str, pos, end_delim) 154 | pos = pos or 1 155 | if pos > #str then error('Reached unexpected end of input.') end 156 | local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. 157 | local first = str:sub(pos, pos) 158 | if first == '{' then -- Parse an object. 159 | local obj, key, delim_found = {}, true, true 160 | pos = pos + 1 161 | while true do 162 | key, pos = json.parse(str, pos, '}') 163 | if key == nil then return obj, pos end 164 | if not delim_found then error('Comma missing between object items.') end 165 | pos = skip_delim(str, pos, ':', true) -- true -> error if missing. 166 | obj[key], pos = json.parse(str, pos) 167 | pos, delim_found = skip_delim(str, pos, ',') 168 | end 169 | elseif first == '[' then -- Parse an array. 170 | local arr, val, delim_found = {}, true, true 171 | pos = pos + 1 172 | while true do 173 | val, pos = json.parse(str, pos, ']') 174 | if val == nil then return arr, pos end 175 | if not delim_found then error('Comma missing between array items.') end 176 | arr[#arr + 1] = val 177 | pos, delim_found = skip_delim(str, pos, ',') 178 | end 179 | elseif first == '"' then -- Parse a string. 180 | return parse_str_val(str, pos + 1) 181 | elseif first == '-' or first:match('%d') then -- Parse a number. 182 | return parse_num_val(str, pos) 183 | elseif first == end_delim then -- End of an object or array. 184 | return nil, pos + 1 185 | else -- Parse true, false, or null. 186 | local literals = {['true'] = true, ['false'] = false, ['null'] = json.null} 187 | for lit_str, lit_val in pairs(literals) do 188 | local lit_end = pos + #lit_str - 1 189 | if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end 190 | end 191 | local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) 192 | error('Invalid json syntax starting at ' .. pos_info_str) 193 | end 194 | end 195 | 196 | return json 197 | 198 | 199 | -------------------------------------------------------------------------------- /src/utils/ros.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: Ting-Chia Chiang 17 | author: G.A. vd. Hoorn 18 | --]] 19 | 20 | ros = {} 21 | 22 | ros.Names = {} 23 | ros.Transformations = {} 24 | ros.Time = {} 25 | 26 | 27 | -- function for legalizing a name for ROS resources 28 | function ros.Names.sanatize(veh_name) 29 | -- in order to meet the ROS naming conventions, we need to sanitize illegal names from FS by using 30 | -- 1. "%W" to replace every non-alphanumeric character with an underscore "_" 31 | -- 2. "+" modifier to get the longest sequence of non-alphanumeric character, i.e. "___" -> "_" (replace consecutive _ with single _) 32 | -- 3. :lower() to replace every uppercase letter with lowercase one 33 | local local_veh_name = veh_name:gsub("%W+", "_"):lower() 34 | 35 | -- make sure names do not start or end with underscores 36 | -- if it starts with an underscore, remove the first character 37 | -- if it ends with an underscore, remove the last character 38 | local_veh_name = local_veh_name:gsub("^_", "") 39 | local_veh_name = local_veh_name:gsub("_$", "") 40 | 41 | return local_veh_name 42 | end 43 | 44 | 45 | --- Construct a quaternion from the specified Euler angles. 46 | -- Function creates a table with four elements, representing a quaternion 47 | -- at the same angle as the result of the Euler angle rotations specified by 48 | -- the 'roll', 'pitch' and 'yaw' arguments. 49 | -- 50 | -- NOTE: this follows ROS' conventions for order of arguments (RPY), order of 51 | -- rotations and order of quaternion vector elements (ie: qx, qy, qz, qw). 52 | -- 53 | -- @param roll The roll angle 54 | -- @param pitch The pitch angle 55 | -- @param yaw The yaw angle 56 | -- @return a ROS compatible quaternion as a Lua table 57 | function ros.Transformations.quaternion_from_euler(roll, pitch, yaw) 58 | local ci = math.cos(roll / 2) 59 | local cj = math.cos(pitch / 2) 60 | local ck = math.cos(yaw / 2) 61 | local si = math.sin(roll / 2) 62 | local sj = math.sin(pitch / 2) 63 | local sk = math.sin(yaw / 2) 64 | 65 | local cc = ci * ck 66 | local cs = ci * sk 67 | local sc = si * ck 68 | local ss = si * sk 69 | 70 | return { 71 | cj * sc - sj * cs, 72 | cj * ss + sj * cc, 73 | cj * cs - sj * sc, 74 | cj * cc + sj * ss 75 | } 76 | end 77 | 78 | 79 | function ros.Time.now() 80 | -- precision: 48164266.436659 ms with 6 digits after decimal point which is in nanosecond 81 | 82 | local day_time = g_currentMission.environment.dayTime 83 | local floor = math.floor 84 | 85 | local secs_data = floor(day_time / 1000) 86 | local nsecs_data = floor((day_time - floor(day_time / 1000) * 1000) * 1e6) 87 | 88 | return {secs = secs_data, nsecs = nsecs_data} 89 | end 90 | -------------------------------------------------------------------------------- /src/utils/shared_memory_segment.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | 16 | author: G.A. vd. Hoorn 17 | --]] 18 | 19 | SharedMemorySegment = {} 20 | SharedMemorySegment.__index = SharedMemorySegment 21 | 22 | function SharedMemorySegment:init(size) 23 | local segment = {} 24 | setmetatable(segment, SharedMemorySegment) 25 | 26 | -- describe the buffer 27 | segment.len = size 28 | segment.marker_start = "fs_lua_memorp_buffer_0012" 29 | segment.marker_end = "fs_lua_memorp_buffer_end_0012" 30 | 31 | -- number of chars we use to encode buffer length 32 | segment.len_marker_len = 1 33 | 34 | -- index at which the bytes we're interested in actually start. 35 | -- add an extra 1 because Lua is 1-indexed 36 | segment.data_start = segment.marker_start:len() + segment.len_marker_len + 1 37 | 38 | -- construct the 'buffer string', give it a special contents: 39 | -- 40 | -- - first the start sentinel value 41 | -- - then the length of the actual buffer in bytes as a single character 42 | -- - then we make some space by adding 'len' spaces 43 | -- - finally the end sentinel value 44 | segment.segment_data = segment.marker_start .. string.char(segment.len) .. string.rep(" ", segment.len) .. segment.marker_end 45 | 46 | return segment 47 | end 48 | 49 | 50 | function SharedMemorySegment:read(len) 51 | -- if no length specified, return the entire buffer 52 | len = len or self.len 53 | 54 | -- TODO: is this -1 necessary? 55 | return self.segment_data:sub(self.data_start, self.data_start + len - 1) 56 | end 57 | 58 | 59 | function SharedMemorySegment:length() 60 | return self.len 61 | end 62 | 63 | -------------------------------------------------------------------------------- /src/utils/vehicle_util.lua: -------------------------------------------------------------------------------- 1 | vehicle_util = {} 2 | 3 | function vehicle_util.ROSControl(self, dt, acceleration, allowedToDrive, rotatedTime) 4 | if acceleration ~= nil and rotatedTime ~= nil and allowedToDrive ~= nil then 5 | self.rotatedTime = rotatedTime 6 | if self.rotatedTime > self.maxRotTime then 7 | self.rotatedTime = self.maxRotTime 8 | elseif self.rotatedTime < self.minRotTime then 9 | self.rotatedTime = self.minRotTime 10 | end 11 | 12 | -- if self.rotatedTime = 7 turn left 13 | -- if self.rotatedTime = -7 turn right 14 | 15 | if self.firstTimeRun then 16 | -- print(self.firstTimeRun) 17 | 18 | local acc = acceleration 19 | 20 | -- set speed limit 21 | local motor = self.spec_motorized.motor 22 | motor:setSpeedLimit(25) 23 | motor:setAccelerationLimit(5) 24 | -- motor:setMotorRotationAccelerationLimit(150) 25 | 26 | if not allowedToDrive then 27 | acc = 0 28 | end 29 | -- the last argument if set false, the acceleration needs to be 0 before a change of direction is allowed 30 | vehicle_util.upROSControlledWheels( 31 | self, 32 | dt, 33 | self.lastSpeedReal * self.movingDirection, 34 | acc, 35 | not allowedToDrive, 36 | true 37 | ) 38 | -- unit of lastSpeedReal m/ms 39 | end 40 | end 41 | end 42 | 43 | function vehicle_util.upROSControlledWheels(self, dt, currentSpeed, acceleration, doHandbrake, stopAndGoBraking) 44 | local acceleratorPedal = 0 45 | local brakePedal = 0 46 | local reverserDirection = 1 47 | if self.spec_drivable ~= nil then 48 | reverserDirection = self.spec_drivable.reverserDirection 49 | acceleration = acceleration * reverserDirection 50 | end 51 | 52 | local motor = self.spec_motorized.motor 53 | local absCurrentSpeed = math.abs(currentSpeed) 54 | local accSign = MathUtil.sign(acceleration) 55 | self.nextMovingDirection = Utils.getNoNil(self.nextMovingDirection, 0) 56 | 57 | local automaticBrake = false 58 | if math.abs(acceleration) < 0.001 then 59 | automaticBrake = true 60 | 61 | -- Non-stop&go only allows change of direction if the vehicle speed is smaller than 1km/h or the direction has already changed (e.g. because the brakes are not hard enough) 62 | if stopAndGoBraking or currentSpeed * self.nextMovingDirection < 0.0003 then 63 | self.nextMovingDirection = 0 64 | end 65 | else 66 | -- Disable the known moving direction if the vehicle is driving more than 5km/h (0.0014 * 3600 = 5.04km/h) in the opposite direction 67 | if self.nextMovingDirection * currentSpeed < -0.0014 then 68 | self.nextMovingDirection = 0 69 | end 70 | -- Continue accelerating if we want to go in the same direction 71 | -- or if the vehicle is only moving slowly in the wrong direction (0.0003 * 3600 = 1.08 km/h) and we are allowed to change direction 72 | if 73 | accSign == self.nextMovingDirection or 74 | (currentSpeed * accSign > -0.0003 and (stopAndGoBraking or self.nextMovingDirection == 0)) 75 | then 76 | acceleratorPedal = acceleration 77 | brakePedal = 0 78 | self.nextMovingDirection = accSign 79 | else 80 | acceleratorPedal = 0 81 | brakePedal = math.abs(acceleration) 82 | if stopAndGoBraking then 83 | self.nextMovingDirection = accSign 84 | end 85 | end 86 | end 87 | if automaticBrake then 88 | acceleratorPedal = 0 89 | end 90 | acceleratorPedal = motor:updateGear(acceleratorPedal, dt) 91 | 92 | if motor.gear == 0 and motor.targetGear ~= 0 then 93 | -- brake automatically if the vehicle is rolling backwards while shifting 94 | if currentSpeed * MathUtil.sign(motor.targetGear) < 0 then 95 | automaticBrake = true 96 | end 97 | end 98 | if automaticBrake then 99 | local isSlow = absCurrentSpeed < motor.lowBrakeForceSpeedLimit 100 | local isArticulatedSteering = 101 | self.spec_articulatedAxis ~= nil and self.spec_articulatedAxis.componentJoint ~= nil and 102 | math.abs(self.rotatedTime) > 0.01 103 | if (isSlow or doHandbrake) and not isArticulatedSteering then 104 | brakePedal = 1 105 | else 106 | -- interpolate between lowBrakeForce and 1 if speed is below 3.6 km/h 107 | local factor = math.min(absCurrentSpeed / 0.001, 1) 108 | brakePedal = MathUtil.lerp(1, motor.lowBrakeForceScale, factor) 109 | end 110 | end 111 | 112 | -- this getSmoothedAcceleratorAndBrakePedals doens't work properly, don't use! 113 | -- acceleratorPedal, brakePedal = WheelsUtil.getSmoothedAcceleratorAndBrakePedals(self, acceleratorPedal, brakePedal, dt) 114 | -- print(acceleratorPedal, brakePedal) 115 | 116 | local maxSpeed = motor:getMaximumForwardSpeed() * 3.6 117 | if self.movingDirection < 0 then 118 | maxSpeed = motor:getMaximumBackwardSpeed() * 3.6 119 | end 120 | --active braking if over the speed limit 121 | local overSpeedLimit = self:getLastSpeed() - math.min(motor:getSpeedLimit(), maxSpeed) 122 | if overSpeedLimit > 0 then 123 | brakePedal = math.max(math.min(math.pow(overSpeedLimit + 0.8, 2) - 1, 1), brakePedal) -- start to brake over 0.2km/h 124 | acceleratorPedal = 0.3 * math.max(1 - overSpeedLimit / 0.2, 0) * acceleratorPedal -- fadeout the accelerator pedal over 0.2km/h, but immediately reduce to 30% (don't set to 0 directly so that the physics engine can still compensate if the brakes are too hard) 125 | end 126 | if next(self.spec_motorized.differentials) ~= nil and self.spec_motorized.motorizedNode ~= nil then 127 | local absAcceleratorPedal = math.abs(acceleratorPedal) 128 | local minGearRatio, maxGearRatio = motor:getMinMaxGearRatio() 129 | local maxSpeed 130 | if maxGearRatio >= 0 then 131 | maxSpeed = motor:getMaximumForwardSpeed() 132 | else 133 | maxSpeed = motor:getMaximumBackwardSpeed() 134 | end 135 | local acceleratorPedalControlsSpeed = false 136 | if acceleratorPedalControlsSpeed then 137 | maxSpeed = maxSpeed * absAcceleratorPedal 138 | if absAcceleratorPedal > 0.001 then 139 | absAcceleratorPedal = 1 140 | end 141 | end 142 | maxSpeed = math.min(maxSpeed, motor:getSpeedLimit() / 3.6) 143 | local maxAcceleration = motor:getAccelerationLimit() 144 | local maxMotorRotAcceleration = motor:getMotorRotationAccelerationLimit() 145 | local minMotorRpm, maxMotorRpm = motor:getRequiredMotorRpmRange() 146 | local neededPtoTorque = PowerConsumer.getTotalConsumedPtoTorque(self) / motor:getPtoMotorRpmRatio() 147 | controlVehicle( 148 | self.spec_motorized.motorizedNode, 149 | absAcceleratorPedal, 150 | maxSpeed, 151 | maxAcceleration, 152 | minMotorRpm * math.pi / 30, 153 | maxMotorRpm * math.pi / 30, 154 | maxMotorRotAcceleration, 155 | minGearRatio, 156 | maxGearRatio, 157 | motor:getMaxClutchTorque(), 158 | neededPtoTorque 159 | ) 160 | end 161 | self:brake(brakePedal) 162 | end 163 | -------------------------------------------------------------------------------- /src/vehicles/RosVehicle.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Copyright (c) 2021, TU Delft 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | author: Ting-Chia Chiang 13 | author: G.A. vd. Hoorn 14 | --]] 15 | -- source(Utils.getFilename("src/modROS.lua", g_modROSModDirectory)) 16 | 17 | RosVehicle = {} 18 | 19 | -- RosVehicle.MOD_DIR = g_modROSModDirectory 20 | -- RosVehicle.MOD_NAME = g_modROSModName 21 | 22 | 23 | function RosVehicle.prerequisitesPresent(specializations) 24 | -- make spec as a prerequisite for rosVehicle since we only control vehicles which are drivable 25 | -- if a vehicle does not have drivable spec, an error will occur 26 | -- Not all prerequisites of specialization modROS.rosVehicle are fulfilled 27 | return SpecializationUtil.hasSpecialization(Drivable, specializations) 28 | end 29 | 30 | 31 | function RosVehicle.initSpecialization() 32 | end 33 | 34 | 35 | function RosVehicle.registerFunctions(vehicleType) 36 | SpecializationUtil.registerFunction(vehicleType, "addTF", RosVehicle.addTF) 37 | SpecializationUtil.registerFunction(vehicleType, "pubImu", RosVehicle.pubImu) 38 | SpecializationUtil.registerFunction(vehicleType, "pubLaserScan", RosVehicle.pubLaserScan) 39 | SpecializationUtil.registerFunction(vehicleType, "pubOdom", RosVehicle.pubOdom) 40 | end 41 | 42 | 43 | function RosVehicle.registerEventListeners(vehicleType) 44 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", RosVehicle) 45 | -- SpecializationUtil.registerEventListener(vehicleType, "onUpdate", RosVehicle) 46 | end 47 | 48 | 49 | -- -- rosVehicle spec own update 50 | -- function RosVehicle:onUpdate(dt) 51 | 52 | -- end 53 | 54 | 55 | -- this will be loaded for every rosVehicle vehicle before starting the game 56 | function RosVehicle:onLoad() 57 | -- rosVehicle namespace 58 | self.spec_rosVehicle = self["spec_" .. g_modROSModName .. ".rosVehicle"] 59 | local spec = self.spec_rosVehicle 60 | -- General rosVehicle variables 61 | 62 | -- there are two veh_name variables, one is with an id number and the other is without 63 | -- because there could be situations where the same vehicle model is spawned more than once in the FS world 64 | -- Hence, to create unique topic names for each vehicle, the name with id is necessary 65 | 66 | -- variables without id are used as keys to retrieve config settings/tables 67 | -- .id is initialized by FS 68 | spec.ros_veh_name_with_id = ros.Names.sanatize(self:getFullName() .. "_" .. self.id) 69 | spec.ros_veh_name = ros.Names.sanatize(self:getFullName()) 70 | spec.base_link_frame = spec.ros_veh_name_with_id .. "/base_link" 71 | spec.component_1_node = self.components[1].node 72 | if not spec.component_1_node then 73 | print(spec.ros_veh_name_with_id .. " does not have components[1].node") 74 | print("Can not publish odom, scan and imu messages for " .. spec.ros_veh_name_with_id) 75 | end 76 | -- Laser scanner initialization 77 | 78 | -- if there is no custom laser scanner setting for this vehicle, use the default settings to initialize an object of LaserScanner class 79 | -- note: a laser scanner is always mounted in the default settings 80 | if not mod_config.vehicle[spec.ros_veh_name] then 81 | spec.laser_scan_obj = LaserScanner.new(self, mod_config.vehicle["default_vehicle"]) 82 | -- if the custom laser scanner is mounted (parameter enabled = true), initialize an object of LaserScanner class 83 | elseif mod_config.vehicle[spec.ros_veh_name].laser_scan.enabled then 84 | spec.laser_scan_obj = LaserScanner.new(self, mod_config.vehicle[spec.ros_veh_name]) 85 | end 86 | 87 | -- only if the object of LaserScanner class was initialized (the laser scanner is enabled), initialize camera settings 88 | if spec.laser_scan_obj then 89 | -- store the individual vehicle config file in the specialization to avoid reloading in the loop 90 | spec.instance_veh = VehicleCamera:new(self, RosVehicle) 91 | spec.xml_path = spec.instance_veh.vehicle.configFileName 92 | spec.xmlFile = loadXMLFile("vehicle", spec.xml_path) 93 | -- get the cameraRaycast node 2(on top of ) which is 0 index .raycastNode(0) 94 | -- get the cameraRaycast node 3 (in the rear) which is 1 index .raycastNode(1) 95 | local cameraKey = string.format("vehicle.enterable.cameras.camera(%d).%s", 0, spec.laser_scan_obj.vehicle_table.laser_scan.laser_attachments) 96 | XMLUtil.checkDeprecatedXMLElements(spec.xmlFile, spec.xml_path, cameraKey .. "#index", "#node") -- FS17 to FS19 97 | local camIndexStr = getXMLString(spec.xmlFile, cameraKey .. "#node") 98 | spec.instance_veh.cameraNode = 99 | I3DUtil.indexToObject( 100 | spec.instance_veh.vehicle.components, 101 | camIndexStr, 102 | spec.instance_veh.vehicle.i3dMappings 103 | ) 104 | if spec.instance_veh.cameraNode == nil then 105 | print(spec.ros_veh_name_with_id .. " does not have cameraNode") 106 | print("Can not publish laser scan messages for " .. spec.ros_veh_name) 107 | end 108 | -- create laser_frame_1 attached to raycastNode (x left, y up, z into the page) 109 | -- and apply a transform to the self.laser_frame_1 110 | local tran_x, tran_y, tran_z = spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.translation.x, spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.translation.y, spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.translation.z 111 | local rot_x, rot_y, rot_z = spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.rotation.x, spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.rotation.y, spec.laser_scan_obj.vehicle_table.laser_scan.laser_transform.rotation.z 112 | local laser_frame_1 = frames.create_attached_node(spec.instance_veh.cameraNode, self:getFullName(), tran_x, tran_y, tran_z, rot_x, rot_y, rot_z) 113 | spec.LaserFrameNode = laser_frame_1 114 | 115 | -- Imu initialization 116 | 117 | -- initialize linear velocity and time(s) for Imu messages 118 | spec.l_v_x_0 = 0 119 | spec.l_v_y_0 = 0 120 | spec.l_v_z_0 = 0 121 | spec.sec = 0 122 | else 123 | print("An object of LaserScanner class for " .. spec.ros_veh_name_with_id .. "was not initialized") 124 | print("Can not publish laser scan messages for " .. spec.ros_veh_name_with_id) 125 | print("Possible reason:") 126 | print(" - there is no laser_scan.enabled configured in mod_config.lua") 127 | print(" - laser_scan.enabled is set false") 128 | end 129 | 130 | -- initialize publishers for Odometry, LaserScan and Imu messages for each rosVehicle 131 | spec.pub_odom = Publisher.new(ModROS._conx, spec.ros_veh_name_with_id .."/odom", nav_msgs_Odometry) 132 | spec.pub_scan = Publisher.new(ModROS._conx, spec.ros_veh_name_with_id .."/scan", sensor_msgs_LaserScan) 133 | spec.pub_imu = Publisher.new(ModROS._conx, spec.ros_veh_name_with_id .."/imu", sensor_msgs_Imu) 134 | end 135 | 136 | 137 | function RosVehicle:pubOdom(ros_time, tf_msg) 138 | 139 | local spec = self.spec_rosVehicle 140 | local vehicle_base_link = spec.base_link_frame 141 | 142 | -- retrieve the vehicle node we're interested in: 143 | -- A drivable vehicle is often composed of 2 components and the first component is the main part. 144 | -- The second component is mostly the axis object. Hence we take component1 as our vehicle 145 | -- The components can be checked/viewed in each vehicle's 3D model. 146 | 147 | -- if a vehicle somehow does not have self.components[1].node 148 | -- stop publishing odometry and return 149 | if not spec.component_1_node then return end 150 | 151 | local veh_node = spec.component_1_node 152 | 153 | -- retrieve global (ie: world) coordinates of this node 154 | local p_x, p_y, p_z = getWorldTranslation(veh_node) 155 | 156 | -- retrieve global (ie: world) quaternion of this node 157 | local q_x, q_y, q_z, q_w = getWorldQuaternion(veh_node) 158 | 159 | -- get twist data 160 | local l_v_x, l_v_y, l_v_z = getLocalLinearVelocity(veh_node) 161 | -- we don't use getAngularVelocity(veh_node) here as the return value is wrt the world frame not local frame 162 | 163 | 164 | -- convert y up world to z up world (farmsim coordinate system: x right, z towards me, y up; ROS: y right, x towards me, z up) 165 | -- https://stackoverflow.com/questions/16099979/can-i-switch-x-y-z-in-a-quaternion 166 | -- https://gamedev.stackexchange.com/questions/129204/switch-axes-and-handedness-of-a-quaternion 167 | -- https://stackoverflow.com/questions/18818102/convert-quaternion-representing-rotation-from-one-coordinate-system-to-another 168 | 169 | 170 | -- create nav_msgs/Odometry instance 171 | local odom_msg = nav_msgs_Odometry.new() 172 | 173 | -- populate fields (not using Odometry:set(..) here as this is much 174 | -- more readable than a long list of anonymous args) 175 | odom_msg.header.frame_id = "odom" 176 | odom_msg.header.stamp = ros_time 177 | odom_msg.child_frame_id = vehicle_base_link 178 | -- note the order of the axes here (see earlier comment about FS chirality) 179 | odom_msg.pose.pose.position.x = p_z 180 | odom_msg.pose.pose.position.y = p_x 181 | odom_msg.pose.pose.position.z = p_y 182 | -- note again the order of the axes 183 | odom_msg.pose.pose.orientation.x = q_z 184 | odom_msg.pose.pose.orientation.y = q_x 185 | odom_msg.pose.pose.orientation.z = q_y 186 | odom_msg.pose.pose.orientation.w = q_w 187 | -- since the train returns nil when passed to getLocalLinearVelocity, set 0 to prevent an error 188 | if l_v_x == nil then 189 | odom_msg.twist.twist.linear.x = 0 190 | odom_msg.twist.twist.linear.y = 0 191 | odom_msg.twist.twist.linear.z = 0 192 | else 193 | -- note again the order of the axes 194 | odom_msg.twist.twist.linear.x = l_v_z 195 | odom_msg.twist.twist.linear.y = l_v_x 196 | odom_msg.twist.twist.linear.z = l_v_y 197 | end 198 | -- TODO get AngularVelocity wrt local vehicle frame 199 | -- since the farmsim "getAngularVelocity()" can't get body-local angular velocity, we don't set odom_msg.twist.twist.angular for now 200 | -- publish the message 201 | spec.pub_odom:publish(odom_msg) 202 | 203 | -- get tf from odom to vehicles 204 | local tf_odom_vehicle_link = geometry_msgs_TransformStamped.new() 205 | tf_odom_vehicle_link:set("odom", ros_time, vehicle_base_link, p_z, p_x, p_y, q_z, q_x, q_y, q_w) 206 | -- update the transforms_array 207 | self:addTF(tf_msg, tf_odom_vehicle_link) 208 | 209 | end 210 | 211 | 212 | function RosVehicle:addTF(tf_msg, TransformStamped) 213 | tf_msg:add_transform(TransformStamped) 214 | end 215 | 216 | 217 | function RosVehicle:pubLaserScan(ros_time, tf_msg) 218 | local spec = self.spec_rosVehicle 219 | -- only if 220 | -- the object of LaserScanner class was initialized in onload() 221 | -- and the component 1 node exists 222 | -- and the cameraNode exists 223 | -- then publish the LaserScan message 224 | -- otherwise return 225 | if spec.laser_scan_obj and spec.component_1_node and spec.instance_veh.cameraNode then 226 | spec.laser_scan_obj:doScan(ros_time, tf_msg) 227 | else 228 | return 229 | end 230 | end 231 | 232 | 233 | function RosVehicle:pubImu(ros_time) 234 | 235 | local spec = self.spec_rosVehicle 236 | 237 | -- if a vehicle somehow does not have self.components[1].node 238 | -- stop publishing imu and return 239 | if not spec.component_1_node then return end 240 | 241 | -- if there are no custom settings for this vehicle, use the default settings 242 | if not mod_config.vehicle[spec.ros_veh_name] then 243 | spec.imu = mod_config.vehicle["default_vehicle"].imu.enabled 244 | else 245 | spec.imu = mod_config.vehicle[spec.ros_veh_name].imu.enabled 246 | end 247 | 248 | -- if imu of this vehicle is disabled, return 249 | if not spec.imu then return end 250 | 251 | -- retrieve the vehicle node we're interested in 252 | local veh_node = spec.component_1_node 253 | 254 | -- retrieve global (ie: world) coordinates of this node 255 | local q_x, q_y, q_z, q_w = getWorldQuaternion(veh_node) 256 | 257 | -- get twist data and calculate acc info 258 | 259 | -- check getVelocityAtWorldPos and getVelocityAtLocalPos 260 | -- local linear vel: Get velocity at local position of transform object; "getLinearVelocity" is the the velocity wrt world frame 261 | -- local l_v_z max is around 8(i guess the unit is m/s here) when reach 30km/hr(shown in speed indicator) 262 | local l_v_x, l_v_y, l_v_z = getLocalLinearVelocity(veh_node) 263 | -- we don't use getAngularVelocity(veh_node) here as the return value is wrt the world frame not local frame 264 | 265 | -- TODO add condition to filter out the vehicle: train because it does not have velocity info 266 | -- for now we'll just use 0.0 as a replacement value 267 | if not l_v_x then l_v_x = 0.0 end 268 | if not l_v_y then l_v_y = 0.0 end 269 | if not l_v_z then l_v_z = 0.0 end 270 | 271 | -- calculation of linear acceleration in x,y,z directions 272 | local acc_x = (l_v_x - spec.l_v_x_0) / (g_currentMission.environment.dayTime / 1000 - spec.sec) 273 | local acc_y = (l_v_y - spec.l_v_y_0) / (g_currentMission.environment.dayTime / 1000 - spec.sec) 274 | local acc_z = (l_v_z - spec.l_v_z_0) / (g_currentMission.environment.dayTime / 1000 - spec.sec) 275 | -- update the linear velocity and time 276 | spec.l_v_x_0 = l_v_x 277 | spec.l_v_y_0 = l_v_y 278 | spec.l_v_z_0 = l_v_z 279 | spec.sec = g_currentMission.environment.dayTime / 1000 280 | 281 | 282 | -- create sensor_msgs/Imu instance 283 | local imu_msg = sensor_msgs_Imu.new() 284 | -- populate fields (not using sensor_msgs_Imu:set(..) here as this is much 285 | -- more readable than a long list of anonymous args) 286 | imu_msg.header.frame_id = "base_link" 287 | imu_msg.header.stamp = ros_time 288 | -- note the order of the axes here (see earlier comment about FS chirality) 289 | imu_msg.orientation.x = q_z 290 | imu_msg.orientation.y = q_x 291 | imu_msg.orientation.z = q_y 292 | imu_msg.orientation.w = q_w 293 | -- TODO get AngularVelocity wrt local vehicle frame 294 | -- since the farmsim `getAngularVelocity()` can't get body-local angular velocity, we don't set imu_msg.angular_velocity for now 295 | 296 | -- note again the order of the axes 297 | imu_msg.linear_acceleration.x = acc_z 298 | imu_msg.linear_acceleration.y = acc_x 299 | imu_msg.linear_acceleration.z = acc_y 300 | 301 | -- publish the message 302 | spec.pub_imu:publish(imu_msg) 303 | 304 | end 305 | -------------------------------------------------------------------------------- /store.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tud-cor/FS19_modROS/4356362b6e04060cfee5c103cd249b896ccba8ab/store.dds --------------------------------------------------------------------------------