1. Do not share user accounts! Any account that is shared by another person will be blocked and closed. This means: we will close not only the account that is shared, but also the main account of the user who uses another person's account. We have the ability to detect account sharing, so please do not try to cheat the system. This action will take place on 04/18/2023. Read all forum rules.
    Dismiss Notice
  2. For downloading SimTools plugins you need a Download Package. Get it with virtual coins that you receive for forum activity or Buy Download Package - We have a zero Spam tolerance so read our forum rules first.

    Buy Now a Download Plan!
  3. Do not try to cheat our system and do not post an unnecessary amount of useless posts only to earn credits here. We have a zero spam tolerance policy and this will cause a ban of your user account. Otherwise we wish you a pleasant stay here! Read the forum rules
  4. We have a few rules which you need to read and accept before posting anything here! Following these rules will keep the forum clean and your stay pleasant. Do not follow these rules can lead to permanent exclusion from this website: Read the forum rules.
    Are you a company? Read our company rules

Tutorial How to write a Game Plugin for SimTools 2.0 - API documentation

Discussion in 'Tutorials and Tips by the Developer' started by yobuddy, Sep 23, 2016.

  1. Abt_Simulator

    Abt_Simulator New Member

    Joined:
    Feb 26, 2021
    Messages:
    4
    Balance:
    28Coins
    Ratings:
    +0 / 0 / -0
    My Motion Simulator:
    6DOF
    Hi, I am trying to write my own plugin for AC, as I require different signals than the standard plugin.
    I started my work off the SimBin example and removed parts I thought to be irrelevant, as I believe Memory Maps are the way to go for AC?

    My plugin is compiling fine and also recognised by SimTools and the game, but there is no motion.
    For starters I disabled all motions but Pitch and Roll.
    I chose the names to call values from the telemtry in the Private Struct according to some AC Shared Memory documentation I found.

    Can someone point me to the issue(s) in my code? I believe I am not picking up the data from the telemetry correctly when defining the struct...

    Code:
     Option Explicit On
    Option Strict On
    Imports Game_PluginAPI
    Imports System.IO
    Imports System.IO.MemoryMappedFiles
    Imports System.Math
    Imports System.Xml.Serialization
    Imports System.Runtime.InteropServices
    Public Class GamePlugin
        Implements IPlugin_Game
        '//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        '///                            SimTools Plugin - Edit the Setting below to provide support for your favorite game!                             ///
        '//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        '//////////////////////////////////////////////// 
        '/// Per Game Settings - Change for Each Game ///
        '////////////////////////////////////////////////
        Private Const _PluginAuthorsName As String = "ABT"
        Private Const _GameName As String = "Assetto Corsa" 'GameName (Must Be Unique!) - the displayed Name.
        Private Const _ProcessName As String = "acs" 'Process_Name without the (".exe") for this game
        Private Const _Port As String = "4123"  'Your Sending/Recieving UDP Port for this game
        Private Const _RequiresPatchingPath As Boolean = False 'do we need the game exe path for patching? (must be True if _RequiresSecondCheck = True)
        Private Const _RequiresSecondCheck As Boolean = False 'Used when games have the same _ProcessName. (all plugins with the same _ProcessName must use this!)
        Private Const _PluginOptions As String = "" 'Reserved For Future Use - No Change Needed 
        '////////////////////////////////////////////////
        '///           Memory Map Variables           ///
        '////////////////////////////////////////////////
        Private Const _Enable_MemoryMap As Boolean = True 'Is a MemoryMap file Required for this game?
        Private Const _MMF_Name As String = "$AC$" 'Set if using a Memory Map File - EXAMPLE("$gtr2$")
        '////////////////////////////////////////////////
        '///           MemoryHook Variables           ///
        '////////////////////////////////////////////////   
        Private Const _Enable_MemoryHook As Boolean = False 'Is a Memory Hook Required for this game? 
        Private Const _MemHook_Roll As UInteger = 0 'Not Used = 0
        Private Const _MemHook_Pitch As UInteger = 0
        Private Const _MemHook_Heave As UInteger = 0
        Private Const _MemHook_Yaw As UInteger = 0
        Private Const _MemHook_Sway As UInteger = 0
        Private Const _MemHook_Surge As UInteger = 0
        Private Const _MemHook_Extra1 As UInteger = 0
        Private Const _MemHook_Extra2 As UInteger = 0
        Private Const _MemHook_Extra3 As UInteger = 0
        '////////////////////////////////////////////////
        '///    DOFs Used for Output for this Game    ///
        '////////////////////////////////////////////////
        Private Const _DOF_Support_Roll As Boolean = True
        Private Const _DOF_Support_Pitch As Boolean = True
        Private Const _DOF_Support_Heave As Boolean = False
        Private Const _DOF_Support_Yaw As Boolean = False
        Private Const _DOF_Support_Sway As Boolean = False
        Private Const _DOF_Support_Surge As Boolean = False
        Private Const _DOF_Support_Extra1 As String = "" 'Blank = False
        Private Const _DOF_Support_Extra2 As String = "" '"" = Not Used
        Private Const _DOF_Support_Extra3 As String = "" 'ADD THE FORCE NAME HERE
        '/////////////////////////////////////////////////
        '///       GameDash - Dash Board Support       ///
        '/////////////////////////////////////////////////
        Private Const _Enable_DashBoard As Boolean = False  'Enable the DashBoard Output System?
        '/////////////////////////////////////////////////
        '///           GameVibe Support              ///
        '/////////////////////////////////////////////////
        Private Const _Enable_GameVibe As Boolean = False 'Enable the GameVibe Output System?
        '/////////////////////////////////////////////////
        'Used by GameManager when the Game Starts.
        Public Sub GameStart() Implements IPlugin_Game.GameStart
            'DO SOMETHING HERE AT GAME START!
        End Sub
        'Used by GameManager when the Game Stops.
        Public Sub GameStop() Implements IPlugin_Game.GameEnd
            'DO SOMETHING HERE AT GAME STOP!
        End Sub
        'Used by GameManager to Process a MemoryHook.
        Public Sub Process_MemoryHook() Implements IPlugin_Game.Process_MemoryHook
            'DO SOMETHING HERE AT GAME START!       
        End Sub
        'Used by GameManager to Process a MemoryMap.
        Public Sub Process_MemoryMap() Implements IPlugin_Game.Process_MemoryMap
             Dim RadToDeg As Double = 45.0 / Atan(1.0)
            Try
                Using file = MemoryMappedFile.OpenExisting(_MMF_Name)
                    Using reader = file.CreateViewAccessor(0, Marshal.SizeOf(MMFAC))
                        Dim bytes = New Byte(Marshal.SizeOf(MMFAC)) {}
                        reader.ReadArray(Of Byte)(0, bytes, 0, bytes.Length)
                        Dim ByteArray() As Byte = bytes
                        'Create Gchandle instance and pin variable required
                        Dim MyGC As GCHandle = GCHandle.Alloc(MMFAC, GCHandleType.Pinned)
                        'get address of variable in pointer variable
                        Dim AddofLongValue As IntPtr = MyGC.AddrOfPinnedObject()
                        'Copy the memory space to my GCHandle
                        Marshal.Copy(ByteArray, 0, AddofLongValue, ByteArray.Length)
                        'Direct Cast myGC to my Outsim Object
                        MMFAC = DirectCast(MyGC.Target, Struct_MMFAC)
                        'Free GChandle to avoid memory leaks
                        MyGC.Free()
                        'assign values - clip very small values
                        Roll_MemMap = MMFAC.roll * RadToDeg
                        Pitch_MemMap = -MMFAC.pitch * RadToDeg
                        Heave_MemMap = MMFAC.Heave
                        Yaw_MemMap = -MMFAC.heading * RadToDeg
                        Sway_MemMap = -MMFAC.Sway
                        Surge_MemMap = -MMFAC.Surge
                    End Using
                End Using
            Catch ex As Exception
            End Try
        End Sub
        'Used by GameEngine to Process Incoming UDP Packets.
        Public Sub Process_PacketRecieved(Text As String) Implements IPlugin_Game.Process_PacketRecieved
             'DO SOMETHING HERE TO RECIEVED UDP PACKETS
            Input_Data = CType(DeSerializeString(Text), GenericOutput)
            'Get Proper Data out of UDP Packet
            With Input_Data
                Roll_Output = (._Roll)
                Pitch_Output = (._Pitch)
                Heave_Output = (._Heave)
                Yaw_Output = (._Yaw)
                Sway_Output = (._Sway)
                Surge_Output = (._Surge)
            End With
        End Sub
        'Used by GameManager to Patch a Game.
        Public Function PatchGame(ByVal MyPath As String, ByVal MyIp As String) As Boolean Implements IPlugin_Game.PatchGame
            'Change as Needed
            MsgBox("Patch Installed!", MsgBoxStyle.OkOnly, "Patching info")
            Return True
        End Function
        'Used by GameManager to UnPatch a Game.
        Public Sub UnPatchGame(MyPath As String) Implements IPlugin_Game.UnPatchGame
            'Change as Needed
            UnPatch(MyPath)
            MsgBox("Patch Uninstalled!", MsgBoxStyle.OkOnly, "Patching info")
        End Sub
        'Used by GameManager to UnPatch a Game.
        Private Sub UnPatch(MyPath As String)
            'Change as Needed
        End Sub
        'Tells the User where to patch the game 
        Public Sub PatchPathInfo() Implements IPlugin_Game.PatchPathInfo
            'Tell the User where to patch the game 
            'Change as Needed
        End Sub
        'Used by GameManager to Validate a Path befors Patching.
        Public Function ValidatePatchPath(MyPath As String) As Boolean Implements IPlugin_Game.ValidatePatchPath
            'insert a simple validation of the patching path - let the user know he got it right
            'Change as Needed
        End Function
        '//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        '///                                                 PLACE EXTRA NEEDED CODE/FUNCTIONS HERE                                                     ///
        '//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    #Region "///// - EXTRA CODE/FUNCTIONS USED FOR THIS PLUGIN - /////"
        Private MMFAC As Struct_MMFAC
        Private Input_Data As New GenericOutput
        'Generic In/Output structure
        Public Structure GenericOutput
            Public _Roll As Double
            Public _Pitch As Double
            Public _Heave As Double
            Public _Yaw As Double
            Public _Sway As Double
            Public _Surge As Double
            Public _Extra1 As Double
            Public _Extra2 As Double
            Public _Extra3 As Double
        End Structure
        'DeSerialize
        Public Function DeSerializeString(InputString As String) As Object
            On Error Resume Next
            Dim xml_serializer As New XmlSerializer(GetType(GenericOutput))
            Dim string_reader As New StringReader(InputString)
            Dim DeserializedOutput As GenericOutput = DirectCast(xml_serializer.Deserialize(string_reader), GenericOutput)
            string_reader.Close()
            Return DeserializedOutput
        End Function
        'required for SimBin Games
        Private Structure Struct_MMFAC
            Public heading As Single  ' in GTR2 this actually is X_WC instead
            Public pitch As Single    ' in GTR2 this actually is Y_WC instead
            Public roll As Single   ' in GTR2 this actually is Z_WC instead
            Public Sway As Single ' lateral force left-right
            Public Heave As Single 'vertical force up-down
            Public Surge As Single 'longitudinal force faster, slower
        End Structure 

  2. yobuddy

    yobuddy Well-Known Member Staff Member Moderator SimAxe Beta Tester SimTools Developer Gold Contributor

    Joined:
    Feb 9, 2007
    Messages:
    5,133
    Occupation:
    Computer Technician
    Location:
    Portland, Oregon - USA
    Balance:
    47,902Coins
    Ratings:
    +5,027 / 16 / -0
    In the Process_MemoryMap() you need to actually create and send the 'GenericOutput' rather than assigning values.
    The data will then be cough by the Process_PacketRecieved and delivered into simtools itself.
    I can give you a hand tomorrow if your around.
    take care,
    yobuddy
    • Friendly Friendly x 1
  3. Abt_Simulator

    Abt_Simulator New Member

    Joined:
    Feb 26, 2021
    Messages:
    4
    Balance:
    28Coins
    Ratings:
    +0 / 0 / -0
    My Motion Simulator:
    6DOF
    I'd be glad to receive your assistance, thank you very much.
    I guess I roughly understand what you mean, but a helping hand would be mega! I'll drop by your inbox
  4. Gunni

    Gunni New Member

    Joined:
    Mar 28, 2021
    Messages:
    3
    Location:
    Austria
    Balance:
    69Coins
    Ratings:
    +1 / 0 / -0
    Hello I have a question?
    What do i need to install to create a plugin.
  5. yobuddy

    yobuddy Well-Known Member Staff Member Moderator SimAxe Beta Tester SimTools Developer Gold Contributor

    Joined:
    Feb 9, 2007
    Messages:
    5,133
    Occupation:
    Computer Technician
    Location:
    Portland, Oregon - USA
    Balance:
    47,902Coins
    Ratings:
    +5,027 / 16 / -0
    Visual studio community free edition.
    Most were built using version 2017 I believe, but anything later should work also.
    Take care,
    yobuddy
    • Like Like x 1
  6. Can Dizdaroglu

    Can Dizdaroglu New Member

    Joined:
    Jan 25, 2022
    Messages:
    3
    Balance:
    - 5Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, DC motor, Arduino, JRK, Motion platform
    Hello to all :)

    I build a 3d printed mini 2DOF test simulator to test my Unity game on it. I will also share all things about it soon. But i have one last problem, to use it with Unity.

    Here are the steps i followed:
    -I made the physical setup with PRO licence of Simtools.
    -I tested it with LFS and everything works great.
    -I build a game plugin using the same files on github/ddkclaudio/QuplaySimTools without any code change.
    -I dragged QuPlay_GamePlugin.dll file to the PluginUpdater and succesfully added "QuPlay" name on the game selection drop menu. Then i patched Unity build of QuPlay.
    -When i run QuPlay Unity build (without any code change), i can see the datas are coming over the UDP on port 4123, via the Tuning Center panel but physical simulator doesn't move.
    -After that, when i run LFS, i also see datas on the Tuning Center panel and simulator moves according to the cars movement.
    -Back to the QuPlay.exe, there is no movement again :(

    I think I forgot to make a very minor adjustment. Do you have an idea about the last step I will take to achieve success?
  7. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    20,461
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    144,596Coins
    Ratings:
    +10,741 / 52 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    If you have data in the Tuning Center that suggest things are working, but you may need to capture the Max/Min values in the Tuning Center so the rig has some suitable base values to act on, once it is moving the TC values can be tweaked further, as necessary.

    It would help if you post pictures of all of your settings.

    I am presuming you patch the Unity game for motion, but do want to check to be certain.
    Last edited: Jan 31, 2022
  8. Can Dizdaroglu

    Can Dizdaroglu New Member

    Joined:
    Jan 25, 2022
    Messages:
    3
    Balance:
    - 5Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, DC motor, Arduino, JRK, Motion platform
    Thanks for your fast reply.

    I also post a detailed video about the situation and my settings:



    Maybe, the video can show what am i doing wrong. I will be pleased with your help.

    Thank you again
  9. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    20,461
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    144,596Coins
    Ratings:
    +10,741 / 52 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK
    As I suggested in my previous post it was likely you needed to capture the Tuning Center Max/Min values and your video confirms that, as all values are set to zero.

    See here for quick details in capturing the TC Max/Min values: https://www.xsimulator.net/community/faq/set-base-tuning-motion-values-in-the-tuning-center.122/
  10. Can Dizdaroglu

    Can Dizdaroglu New Member

    Joined:
    Jan 25, 2022
    Messages:
    3
    Balance:
    - 5Coins
    Ratings:
    +2 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, DC motor, Arduino, JRK, Motion platform
    I got it working finally :) As you said, i captured Max/Min values in the Tuning Center, so it worked. Also, @yobuddy said the same thing at the same time with you on the PM, but at first, i couldn't get the logic behind the Tuning Center. Now i see why TC has these settings and what they mean :)

    I will prepare a video about all of these topics for the people who will have same problems, as a simple video guide. Also, i will publish my simulator built when i finished.

    I can't thank you @noorbeast and @yobuddy enough. Really thanks for everything. You are the best :)
    • Winner Winner x 1
    • Friendly Friendly x 1
  11. d4m

    d4m New Member

    Joined:
    Nov 23, 2021
    Messages:
    14
    Balance:
    51Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    AC motor, Arduino, 4DOF
    Guys, it turns out the Gran Turismo series on Playstation support UDP telemetry.
    I'm new to writing plugins and I'd like to give this one a try but it seems the data is not straightforward and requires some computation, especially for surge, sway, heave.
    The game presents the following:
    /// Position on the track. Track units are in meters.
    public Vector3 Position { get; set; }
    /// Velocity in track units (which are meters) for each axis.
    public Vector3 Velocity { get; set; }
    /// Rotation (Pitch/Yaw/Roll) from -1 to 1.
    public Vector3 Rotation { get; set; }
    /// Orientation to North. 1.0 is north, 0.0 is south.
    public float RelativeOrientationToNorth { get; set; }
    /// How fast the car turns around axes. (In radians/second, -1 to 1).
    public Vector3 AngularVelocity { get; set; }


    I’d need help understanding which of these could be used to compute these forces.
    Interestingly enough, a sway sensation seems present in the AngularVelocity vector but not the surge or heave (but for heave, the sensation is quite unclear).
    Any hints are greatly appreciated as the math for these seems difficult to come by.
    Thanks in advance.
  12. vthinsel

    vthinsel Well-Known Member

    Joined:
    Feb 20, 2015
    Messages:
    436
    Location:
    FRANCE
    Balance:
    5,961Coins
    Ratings:
    +563 / 2 / -0
    My Motion Simulator:
    Arduino, 4DOF
    Well. It is not that easy for GT as the data is encrypted using salsa20, and I couldnt find a native way to decode it in VB.
    You can check here and here
    You can get a pretty good heave/sway/surge based on velocity. Take delta velocity and delta time between two points and you get it.
    • Like Like x 2
  13. d4m

    d4m New Member

    Joined:
    Nov 23, 2021
    Messages:
    14
    Balance:
    51Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    AC motor, Arduino, 4DOF
    thanks @vthinsel for the pointers on delta time and velocity. why didn't I think about it, it is physics after all? :)
    I already have the data decoded in C and I wanted to have it transferred to the plugin itself as a 2nd step but you did that already.
  14. d4m

    d4m New Member

    Joined:
    Nov 23, 2021
    Messages:
    14
    Balance:
    51Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    AC motor, Arduino, 4DOF
    @vthinsel I have the issue of surge force (at least) changing sense during the race (sometimes it acts normal, sometimes the force is reversed). did you experience this? since I assume you did, is its sense linked to something else from the telemetry?
    Thanks in advance
  15. vthinsel

    vthinsel Well-Known Member

    Joined:
    Feb 20, 2015
    Messages:
    436
    Location:
    FRANCE
    Balance:
    5,961Coins
    Ratings:
    +563 / 2 / -0
    My Motion Simulator:
    Arduino, 4DOF
    Axis mouvment is a mix . Pitch could hide surge as they move the same axis. Weights define your priority. You can have only position, or forces, or both. Watch out for clipping in that case.
    • Informative Informative x 1
  16. d4m

    d4m New Member

    Joined:
    Nov 23, 2021
    Messages:
    14
    Balance:
    51Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    AC motor, Arduino, 4DOF
    Thanks @vthinsel , I am aware of the mix, that’s why I’m running one force/component at a time until I’m sure it behaves properly.
    For now I’m only focused on surge and that’s where I see the issue. You also mentioned in your post on gtplanet that you see the velocity positive and negative and I was thinking you had this behavior.
    Could it be the clock reference for the time delta? I’m using local clock on the PC receiving the UDP data.
    What is your clock reference for time delta? Are you using the local clock or some ingame clock from the UDP packet?
    Thanks again
  17. vthinsel

    vthinsel Well-Known Member

    Joined:
    Feb 20, 2015
    Messages:
    436
    Location:
    FRANCE
    Balance:
    5,961Coins
    Ratings:
    +563 / 2 / -0
    My Motion Simulator:
    Arduino, 4DOF
    I'm using local clock. It would be more accurate to use the ticks provided by the telemetry data, will be for next version :)
    You are probably right with the world/local velocity, which explains why I get positive and negative values when expecting only positive while driving a full lap. The good news is that acceleration being calculated with short delta, it should be pretty accurate no matter the car world position . The acceleration value stays coherent: not bouncing. I'll investigate more on this though, thanks for pointing it.
  18. DOF_Dex

    DOF_Dex New Member Gold Contributor

    Joined:
    Jan 29, 2024
    Messages:
    17
    Location:
    London
    Balance:
    19Coins
    Ratings:
    +3 / 0 / -0
    My Motion Simulator:
    2DOF, 3DOF, 6DOF
    Hi, I'm new to Simtools and keen to get started connecting Unreal 5.3 to Simtools 3.
    I noticed the documentation is focused on the older software. Is it best to stick with Simtools 2.6 and UE4.27.2 at the moment. I need as much help as I can get!

    If anyone is creating for Simtools 3 using UE5 it would be great to hear how different the process is compared to the older UE and Simtools version.

    Many thanks
  19. Jetsada

    Jetsada New Member Gold Contributor

    Joined:
    Jul 27, 2023
    Messages:
    2
    Occupation:
    engineering student
    Location:
    Thailand
    Balance:
    - 43Coins
    Ratings:
    +0 / 0 / -0
    My Motion Simulator:
    2DOF, DC motor, AC motor, Arduino
    Hi every one, now I'm studying to get data like row, pitch etc. from "Dirt rally 2" as a text file (or telemetry) and combine with Matlab to do simulation.
    I start to edit Dirt 2 - Example Game Plugin.zip (It's CodeMaster Games and UDP packet). As far as understand, I just edit "_GameName" , "_ProcessName" and "System.IO.File.Exists(MyPath & "\dirtrally2_game.exe")" at GameManager to Patch a Game.
    [​IMG]
    [​IMG]
    [​IMG]

    After build plugin and bring in to updater, I can Patch game. But when game's running, game manager still not show "game running" and nothing happened at tuning center.
    Where should I edit code further ? or any recomend ?
  20. noorbeast

    noorbeast VR Tassie Devil Staff Member Moderator Race Director

    Joined:
    Jul 13, 2014
    Messages:
    20,461
    Occupation:
    Innovative tech specialist for NGOs
    Location:
    St Helens, Tasmania, Australia
    Balance:
    144,596Coins
    Ratings:
    +10,741 / 52 / -2
    My Motion Simulator:
    3DOF, DC motor, JRK