Go Back   Codemasters Forums > Action, RPG and Strategy Games > Operation Flashpoint: Dragon Rising > English > Operation Flashpoint: Dragon Rising - Mission Editing and Modding Chat Zone
Sign In
Register on CodeM

Operation Flashpoint: Dragon Rising - Mission Editing and Modding Chat Zone A little area for all you mission editors and modders to chat and discuss ideas.

Reply
 
LinkBack Thread Tools Display Modes
Old 25-11-2009, 02:11 AM   #1 (permalink)
Senior Member
 
Join Date: Oct 2009
Location: New York
Posts: 536
Default [LUA] Timer library script

I've been meaning to post this code for awhile, but I've just figured out a few things that make it easier to use and thought now was as good a time as any. Particularily since it seems that more and more issues are turning up with OFP timers.

This is a timer object (for lack of a better term, it's not an object in the C++/Java sense) that can be used to schedule arbitrary functions to be executed at some time in the future. You can download the code here. I've also included a two sample mssn files that that show how to use the timer. The first randomly spawns a number of enemy echelons around your position and respawns them 10 to 20 seconds after they have been killed. The second mission calls in three JDAM airstrikes five seconds apart.


INSTALLATION
  1. Unzip the above archive.
  2. Copy the Autocomplete.xml and LuaSyntax.xml files to your Mission Editor\Database\LuaEditor folder (be sure to make backup copies of the files first).
  3. Create a secondary script in your mission and paste the contents of the attached timer.lua script into your secondary script. You can use any "Script Name" in the mission editor that you like, but for our purposes I will assume you have used the script name "timer".


USAGE

To use the timer in your own scripts your level.lua script must contain a onMissionStart function. You do not need to import the secondary script or start the timer or do anything else. Just have an onMissionStart function (even an empty one). This is required so the Timer can inject itself into your code.


SCHEDULING

There are three functions that can be used to schedule events.
  1. Timer:Schedule(event, delay) -- executes the event in 'delay' seconds
  2. Timer:Repeating(event, delay) -- executes the event every 'delay' seconds
  3. Timer:RepeatIf(event, delay) -- executes the event every 'delay' seconds for as long as the event returns true.

And five functions for timer control (these are mostly untested)
  1. Timer:Pause() -- Pauses the timer. This will save a few CPU cycles if the timer is not in use.
  2. Timer:Resume() -- Resumes a paused timer. Any pending events in the timer's queue will be executed when you call Timer:Resume.
  3. Timer:Clear() -- Removes all pending events from the timer's queue.
  4. Timer:Destroy() -- Removes all pending event and releases the OFP timer used.
  5. Timer:Create() -- Can be used to re-create a timer after it has been destroyed.

Note that all times are given in seconds and not milliseconds like the OFP timers. Use floating point numbers to specify fractions of a second, i.e 1.5, 0.25 (although see the caveats below before going to crazy).


EVENTS

The 'event' used can either be the name a function or a table that contains a function named 'run'. Any Lua function can be called by the Timer and you do not need to define any onTimer_XXX functions unless you start your own OFP timers.

EXAMPLES

Code:
function onMissionStart()
    Timer:Schedule(once, 5)      -- runs 'once'  in five seconds
    Timer:Repeating(always, 30)  -- runs 'always' every 30 seconds.
    Timer:RepeatIf(maybe, 2)     -- runs 'maybe' every two seconds, maybe.
end

function once()
    OFP:displaySystemMessage("Timer called once")
end

function always()
    OFP:displaySystemMessage("Timer called always")
end

maybe = {
    count = 3
    run = function(self)
        OFP:displaySystemMessage("Count down " .. self.count)
        self.count = self.count - 1
        return self.count > 0
    end
end
When using a table as an 'event' the first parameter to the run function should always be a parameter named "self" (or "this" if you prefer). The "self" parameter can be used to access the other fields in the table, that is, the "self" parameter will refer to the table that contains the run function. If you do not need to refer to any of the other fields in the table then you do not need to include the self parameter.


PROS
  1. The Timer object only uses one OFP timer regardless of how many events are scheduled.
  2. No need to remember to remove timers when you are done with them, or reset timers for events you want to repeat.
  3. Allows you to create the function to be scheduled "on the fly"
Code:
function onDeath(victim, unit)
    local echelon = OFP:getEchelon(victim)
    if not OFP:isAlive(echelon) then
        local setID = ... -- get the entity set ID for the echelon
        local setName = ... -- get the name of the entity set to spawn
        local respawn = function()
            OFP:destroyEntitySet(setId)
            OFP:activateEntitySet(setName)
        end
        -- respawn between 10 and 20 seconds from now
        local time = math.random(10, 20)
        Timer:Schedule(respawn, time)
    end
end
CONS
  1. Does alot of "busy work" if you are only scheduling one or two events. Use the OFP timer functions in that case.
  2. The timer only checks the queue for pending events a few times per second so it is not suited if you need fine grained control. You can change how often the timer will check its queue for pending events by setting Timer.DELAY (this value is in milliseconds), but setting it lower than 250 (the default) likely isn't going to buy you much. Setting Timer.DELAY higher will save CPU cycles.
TROUBLESHOOTING
  1. If the timer doesn't work double check that you are using the 'colon' syntax when calling the Timer functions. Timer:Create() works, Timer.Create() will fail, Timer:Schedule works, Timer.Schedule will fail.

Hopefully others will find this useful. I use it all the time, but that is because I wrote it ;)
__________________
In theory there is no difference between theory and practice. But in practice there is.
Intro to LUA, Fun with tables, Undocumented Functions, Saving Game State
Timer library, Sector Control Framework
Finite State Machines (part 1)

Last edited by Haywood Slap; 30-11-2009 at 02:42 AM. Reason: Updated for latest version (1.0b3)
Haywood Slap is offline   Reply With Quote
Old 25-11-2009, 02:25 AM   #2 (permalink)
Senior Member
 
TemplarGFX's Avatar
 
Join Date: Oct 2009
Posts: 2,497
Default

whoa, awesome stuff. I sure hope CM work out a way to import user scripts for Patch 2 so adding these types of things is alot easier
__________________
Island War - Free Roam Download Release Candidate here
The ENTIRE Island is at your feet! Explore, conquer, have fun! COOP with up to 3 friends!
----------------------------------------
Templar's Completely Awesome Entity Database
Real Muzzle Velocity, Rate Of Fire, Effective Range, Recoil. Better Aimed Position. No zooming on sights!
----------------------------------------
PAYPAL DONATE
TemplarGFX is offline   Reply With Quote
Old 25-11-2009, 05:51 AM   #3 (permalink)
Senior Member
 
Dru1d's Avatar
 
Join Date: Sep 2009
Posts: 226
Default

Nice scripting Haywood, I'll certainly use it, thanks.
Dru1d is offline   Reply With Quote
Old 25-11-2009, 03:10 PM   #4 (permalink)
Senior Member
 
Join Date: Oct 2009
Posts: 130
Default

good job, allready linked in the working with LUA thread. Hmmm... ive missed such thingy during the creation of "first day on skira". The mission has way to many timers.
gannebamm is offline   Reply With Quote
Old 26-11-2009, 12:45 AM   #5 (permalink)
Senior Member
 
Join Date: Oct 2009
Location: New York
Posts: 536
Default

Well I've already found and fixed one bug (I should know better than to add code moments before releasing it... sigh). You can download the fixed version, or if you already have downloaded the code you can apply the fix yourself.

On line 180, in the Timer:Resume function is the line
Code:
if not paused then return end
this should be
Code:
if not self.paused then return end
Quote:
I sure hope CM work out a way to import user scripts for Patch 2 so adding these types of things is alot easier
I'll second that! I've struggled for days to find a way to add library scripts to OFP. Using secondary scripts is workable, but every time I find and fix a bug I have to take the new timer script and paste it into all the missions that use it.

It would also be nice if CM came up with a way to install library scripts that allowed the script authors to provide the XML needed to update the Autocomplete.xml and LuaSyntax.xml files so that the editor would provide online help, autocompletion and syntax coloring. For example, if you want the Timer script to look really official go to the "Mission Editor/Database/LuaEditor" folder and open the Autocomplete.xml file. Go to the bottom of the file and just above the "</AutoList"> line add the following XML so the end of the file looks like:
Code:
  <word text="connectToWaypoint" />
  <word text="disconnectFromWaypoint" />
  <!-- Timer functions added here -->
  <word text="Timer:Create" insert="+()" desc="Initializes the timer object.  Must be called before a timer can be used."/>
  <word text="Timer:Schedule" insert="+()" desc="Schedules an event to be executed once.">
    <input>
      <argument name="event" type="function" desc="The name of a function or table with a run function defined."/>
      <argument name="delay" type="number" desc="The delay (in seconds) until the event is executed."/>
    </input>
  </word>
  <word text="Timer:Repeating" insert="+()" desc="Schedules an event to be executed repeatedly.">
    <input>
      <argument name="event" type="function" desc="The name of a function or table with a run function defined."/>
      <argument name="delay" type="number" desc="The delay (in seconds) until the event is executed."/>
    </input>
  </word>
  <word text="Timer:RepeatIf" insert="+()" desc="Schedules an event to be executed repeated for as long as the event returns true.">
    <input>
      <argument name="event" type="function" desc="The name of a function or table with a run function defined."/>
      <argument name="delay" type="number" desc="The delay (in seconds) until the event is executed."/>
    </input>
  </word>
  <word text="Timer:Pause" insert="+() " desc="Pauses the timer. No events will be executed while the timer is paused."/>
  <word text="Timer:Resume" insert="+() " desc="Resumes a paused timer. Any pending events in the timer's queue will be executed."/>
  <word text="Timer:Clear" insert="+() " desc="Removes all pending events from the Timer's queue"/>
  <word text="Timer:Destroy" insert="+() " desc="Releases the OFP timer and removes all pending events from the timer's queue."></word>
</AutoList>
And while you have the file open look up a few lines and change the line of OFP:displaySystemMessage to the following:
Code:
  <word text="OFP:displaySystemMessage" insert="+()" desc="This will allows to send a message to the chat buffer to be displayed on screen. " >
This removes the two garbage characters the OFP inserts between the parentheses.

Then open the LuaSyntax.xml file and find the end of the <Patterns> section (around line 287) and add the following:
Code:
          Timer
          Timer:Create
          Timer:Schedule
          Timer:RepeatIf
          Timer:Repeating
          Timer:Clear
          Timer:Pause
          Timer:Resume
          Timer:Destroy
        </Patterns>  <!-- don't add this line, it's just to show you where to paste the above -->
Save the files, and et voila, inline help, auto code completion, and syntax coloring!

I was thinking of including the modified Autocomplete.xml and LuaSyntax.xml files in the zip, but that would overwrite any other changes people may have made to the files.
__________________
In theory there is no difference between theory and practice. But in practice there is.
Intro to LUA, Fun with tables, Undocumented Functions, Saving Game State
Timer library, Sector Control Framework
Finite State Machines (part 1)
Haywood Slap is offline   Reply With Quote
Old 27-11-2009, 04:36 PM   #6 (permalink)
Senior Member
 
Join Date: Oct 2009
Location: New York
Posts: 536
Default

I've updated the first post with a link to the modified Autocomplete.xml and LuaSyntax.xml files need to enable inline help, autocompletion, and syntax coloring in the editor.
__________________
In theory there is no difference between theory and practice. But in practice there is.
Intro to LUA, Fun with tables, Undocumented Functions, Saving Game State
Timer library, Sector Control Framework
Finite State Machines (part 1)
Haywood Slap is offline   Reply With Quote
Old 30-11-2009, 02:47 AM   #7 (permalink)
Senior Member
 
Join Date: Oct 2009
Location: New York
Posts: 536
Default

I've updated the first post with a link to a newest version (1.0b3)

The newest version makes it easier to use the Timer object: simply paste the timer.lua script into a secondary script. There is no need to "import" it, start it, or do any other bookkeeping. You can just start scheduling events. The new version also includes updated Autocomplete.xml and LuaSyntax.xml files (including all the changes for the undocumented functions) that you can copy to you LuaEditor folder.

Let me know if anyone has any questions, finds any bugs, or can't get it to work.
__________________
In theory there is no difference between theory and practice. But in practice there is.
Intro to LUA, Fun with tables, Undocumented Functions, Saving Game State
Timer library, Sector Control Framework
Finite State Machines (part 1)

Last edited by Haywood Slap; 30-11-2009 at 02:50 AM.
Haywood Slap is offline   Reply With Quote
Old 07-01-2010, 07:03 AM   #8 (permalink)
Junior Member
 
Join Date: Jan 2010
Posts: 1
Default Great!

I like this approach to handling timer events. I'm a dev for Bitfighter (bitfighter.org), and I was just sitting down to write something like this, but I'm going to borrow parts of your code instead.

I'll be sure to attribute the code to you.
Watusimoto is offline   Reply With Quote
Old 08-01-2010, 04:21 AM   #9 (permalink)
Senior Member
 
Dru1d's Avatar
 
Join Date: Sep 2009
Posts: 226
Default

We could do with a sticky for your secondary script and a kind soul to manage the latest update to it.

I have 2 functions that I have created and use in a secondary script in which I have Haywoods. It would be easier if every now and then I could click on the sticky and download the latest version that contains everyones.

Might prove unmanageable but I like the idea of a library that easier to access that searching through the forums all of the time.
__________________
"The most rewarding things you do in life are often the ones that look like they cannot be done." Arnold Palmer
Despawner function - despawns units/echelons/groups from 1 simple function
getTracking function - tracks entities returning intercept spawn coordinates
Op Intel_igent Core - intel entry .mssn file
shooting range - need the practice?
Dru1d is offline   Reply With Quote
Old 09-01-2010, 05:35 PM   #10 (permalink)
Senior Member
 
Join Date: Oct 2009
Location: New York
Posts: 536
Default

Thanks! It is all open source (Apache 2.0 license) so you are free to use code. That is why I posted it

I have been hoping that the mythical second patch will introduce some features to make using and sharing secondary and library scripts much easier. It is a bit of a pain at the moment.
__________________
In theory there is no difference between theory and practice. But in practice there is.
Intro to LUA, Fun with tables, Undocumented Functions, Saving Game State
Timer library, Sector Control Framework
Finite State Machines (part 1)
Haywood Slap is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



All times are GMT. The time now is 03:32 PM.


Powered by vBulletin®
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.