Getting script to work on multiplayer

In this forum you will find and post information regarding the modding of Star Wars Battlefront 2. DO NOT POST MOD IDEAS/REQUESTS.

Moderator: Moderators

Post Reply
MileHighGuy
Jedi
Jedi
Posts: 1194
Joined: Fri Dec 19, 2008 7:58 pm

Getting script to work on multiplayer

Post by MileHighGuy »

Hello,

I made a grappling hook script that works on single player without issues. However in multiplayer, one person can use it fine, then the other person can use it, and then their "trajectories" get all messed up, and then it just stops working. Like one person will use the grappling hook and then get sent to where the other person launched it. I am looking for some ideas on things to try.

One thing I have tried was to add each function handle to a global table keeping track of all handlers and states per player index. That did not make a difference and it made the code quite uglier than it needed to be.

Here is the code. Bear with me, it is a bit long. You probably want to copy it into a text editor or IDE.

Code: Select all

-- local function to safely destroy the timer and release the timer elapse function
local safeEndTimerFunc = function(timer, timerHandle, timerElapseFuncHandle)

    if timer ~= nil then
        DestroyTimer(timer)
    --else
    --    print("timer was nil")
    end
    timerHandle = nil

    if timerElapseFuncHandle ~= nil then
        ReleaseTimerElapse(timerElapseFuncHandle)
    --else
    --    print("timer elapse handle was nil")
    end
    timerElapseFuncHandle = nil

end

-- This is a local (only visible in this file) function used in the function "enableGrapplingHook"
-- moves a character to an object with a speed in meters per second.
-- odfName is the ODF name of the deployed autoturret
local moveUnitToObjectAlongTrajectory = function(character, object, speed, trajectoryCoordTable)

    local unit = GetCharacterUnit(character)

    --check if unit is alive (will be nil if dead)
    if unit then
        --print("unit is alive, starting move")
        -- get start and end coordinates
        local xStart, yStart, zStart = GetWorldPosition(unit)
        --local xEnd, yEnd, zEnd = GetWorldPosition(object)
		
		-- variable to track the coordinate index
		local coordIndex = 1
		local xEnd = trajectoryCoordTable[coordIndex].x
		local yEnd = trajectoryCoordTable[coordIndex].y
		local zEnd = trajectoryCoordTable[coordIndex].z

        -- position deltas - create the vector
        local dX = xEnd - xStart
        local dY = yEnd - yStart
        local dZ = zEnd - zStart

        local distance = math.sqrt(dX * dX + dY * dY + dZ * dZ)

        local objLocation = GetEntityMatrix(object)
        -- move object a little bit temporarily so we can calc some rotations
        SetEntityMatrix(object, CreateMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.1, objLocation))
        local xTemp, yTemp, zTemp = GetWorldPosition(object)
        -- move it back to original position
        SetEntityMatrix(object, objLocation)

        --calculate angle (y-axis rotation)
        local adjacent = xTemp - xEnd
        local opposite = zTemp - zEnd
        local hypotenuse = math.sqrt(((xTemp - xEnd) * (xTemp - xEnd)) + ((zTemp - zEnd) * (zTemp - zEnd)))
        local phi = math.acos(adjacent / hypotenuse)

        --correct the angle
        -- this was a pain in the Diet Dr. Pepper
        if opposite < 0 then
            phi = phi + (math.pi) / 2
        else
            phi = -(phi - (math.pi) / 2)
        end

        local count = 0
        --every time interval move this distance. These two variables control speed
        -- units in meters per second
        local incrementDistance = speed / 100
        local timeInterval = 1/100 -- one hundredth of a second or 100 fps. Change this to control how "smooth" the unit moves
        local moveUnitTimer = CreateTimer("moveUnitTimer")
        SetTimerValue(moveUnitTimer, timeInterval) -- in seconds
		
		-- variable to track the coordinate index
		local coordIndex = 1

        local moveUnitTimerTracker = nil
        moveUnitTimerTracker = OnTimerElapse(function(timer)
            count = count + incrementDistance -- move 1 meter per time interval unit we hit distance
            --print("timer count is " .. tostring(count))

            ---- Tried to do this, but it crashed. Maybe you can figure it out
            ----draw the cable. DrawBeamBetween is the C function used in galactic conquest
            --DrawBeamBetween(
            --        GetEntityMatrix(unit),
            --        objLocation,
            --        "troop_icon", 1.0, 255, 255, 255, 255, 0, 1
            --)

            local factor = count / distance

            --check if unit is alive
            if GetCharacterUnit(character) then
                --print("unit is alive, moving")

                -- move character once every timer interval
                -- stop a little above the destination to avoid impact damage
                -- by making the last argument "nil" you can use absolute position/rotation
                SetEntityMatrix(unit, CreateMatrix(phi, 0.0, 1.0, 0.0, xStart + ((dX) * factor), yStart + ((dY + 0.5) * factor), zStart + ((dZ) * factor), nil))
            else
                --print(" unit is dead. stopping ")
                count = 0
				coordIndex = 1

                safeEndTimerFunc(timer, moveUnitTimer, moveUnitTimerTracker)
            end

            if count < distance then
                --print("continuing")
                --StopTimer(timer)
                SetTimerValue(timer, timeInterval)
                StartTimer(timer)
            else
			
				coordIndex = coordIndex + 1
				-- if there are more grapple coords
				if coordIndex < table.getn(trajectoryCoordTable) then
					--print("moving to next coord")
					
					count = 0
					
					xStart = trajectoryCoordTable[coordIndex-1].x
					yStart = trajectoryCoordTable[coordIndex-1].y
					zStart = trajectoryCoordTable[coordIndex-1].z
					
					-- recalculate the deltas
					dX = trajectoryCoordTable[coordIndex].x - xStart
					dY = trajectoryCoordTable[coordIndex].y - yStart
					dZ = trajectoryCoordTable[coordIndex].z - zStart

					distance = math.sqrt(dX * dX + dY * dY + dZ * dZ)
					
					--start timer again
					SetTimerValue(timer, timeInterval)
					StartTimer(timer)
			
				-- if we've reached the last grapple coord
				else
					count = 0
					coordIndex = 1

                    safeEndTimerFunc(timer, moveUnitTimer, moveUnitTimerTracker)
				end
            end
        end
        , moveUnitTimer)

        --print("starting move timer")
        StartTimer(moveUnitTimer)

    else
        --print("unit is dead, not moving")
    end

    --print("moving unit")

end

--  example: "rep_bldg_inf_autoturret", 100
-- odfName, a string which is the name of the deployed autoturret ODF
-- speed, a number, the speed to travel the grappling hook in meters per second
enableGrapplingHookFollowTrajectory = function(odfName, speed)

    -- grappling hook code
    grappleLaunchArc = OnCharacterDispenseControllable(
            (function(player, controllable)
                --print("dispensed entity")

                if GetEntityClass(controllable) == FindEntityClass(odfName) then
                    --print("dispensed autoturret")


                    -- this timer will track the grapple's position over time.
                    -- If it detects that the grapple is stopped, it will pull the unit towards it.
                    -- If the grapple dies or never stops, the timer stops and nothing happens.
                    local hookIsAlive = true
                    local grappleCoordTable = {}
                    local loopCount = 0
                    local grappleTimeInterval = 1/60 --record the path of the grappling hook at 60 fps so it looks nice! Can lower if desired
                    local moveGrappleTimer = CreateTimer("moveGrappleTimer")
                    SetTimerValue(moveGrappleTimer, grappleTimeInterval) -- in seconds
                    local moveGrappleTimerTracker = nil
                    moveGrappleTimerTracker = OnTimerElapse(function(timer)
                        loopCount = loopCount + 1
                        --print("timer count is " .. tostring(loopCount))

                        if hookIsAlive == true then


                            --print("hook still alive, continuing")
                            local xGrap, yGrap, zGrap = GetWorldPosition(controllable)
                            table.insert(grappleCoordTable, { x = xGrap, y = yGrap, z = zGrap })

                            -- check if there is more than 1 entry in the table and if the last and second to last are equal
                            -- probably should clean out all but the last 2 of the table....
                            if table.getn(grappleCoordTable) > 1
                                    and grappleCoordTable[table.getn(grappleCoordTable)].x == grappleCoordTable[table.getn(grappleCoordTable) - 1].x
                                    and grappleCoordTable[table.getn(grappleCoordTable)].y == grappleCoordTable[table.getn(grappleCoordTable) - 1].y
                                    and grappleCoordTable[table.getn(grappleCoordTable)].z == grappleCoordTable[table.getn(grappleCoordTable) - 1].z
                            then
                                --print("grapple is stationary")

                                -- call the function that does the actual moving of our unit
                                moveUnitToObjectAlongTrajectory(player, controllable, speed, grappleCoordTable)

                                --exit the timer, clean up
                                loopCount = 0
                                grappleCoordTable = {}
                                hookIsAlive = true
                                --StopTimer(timer) -- timer should already be stopped if we are in this function?

                                safeEndTimerFunc(timer, moveGrappleTimer,moveGrappleTimerTracker)

                                --print("exiting")
                                --exit the callback function
                                return
                            end

                            --StopTimer(moveUnitTimer)
                            SetTimerValue(timer, grappleTimeInterval)
                            StartTimer(timer)
                        elseif hookIsAlive == false then
                            --print("hook is dead, stopping")

                            -- clean up
                            loopCount = 0
                            grappleCoordTable = {}
                            hookIsAlive = true

                            safeEndTimerFunc(timer, moveGrappleTimer,moveGrappleTimerTracker)
                        else
                            --print("Grapple code: something else happened!")
                        end
                    end
                    , moveGrappleTimer)

                    -- this event listener simply sets alive to false.
                    -- I tried to use IsObjectAlive but that crashed when it was dead. Lol
                    -- Could potentially run into some synchronization issues, but that hasn't happened during testing
                    -- If there are glitches with the weapon then consider using the "LifeTime" value in the autoturret odf ...
                    -- ... instead of this event. make the timer only go until a the LifeTime of the autoturret
                    local hookArcDeath = nil
                    hookArcDeath = OnObjectKill(function(object, killer)
                        --print("object died")
                        if object == controllable then
                            --print(" hook died")
                            hookIsAlive = false
                            --print("alive is " .. tostring(alive))

                            if hookArcDeath ~= nil then
                                ReleaseObjectKill(hookArcDeath)
                            end
                            hookArcDeath = nil
                        end
                    end)

                    --print("starting grapple timer")
                    -- kick off the timer to track the grapple's position over time
                    StartTimer(moveGrappleTimer)
                end
            end
			))

end
also here is the download for the grappling hook:
https://www.moddb.com/games/star-wars-b ... pling-hook

Thanks
Post Reply