Welcome to Open Carnage

A resource for Halo Custom Edition and MCC modding, with unique means of rewarding content creation and support. Have a wander to see why we're worth the time!

EST. 14th of February, 2012

Sign in to follow this  
Followers 0
Nickster5000

Event Table

Posted (edited)

Preface:

If you're comfortable with Lua's MetaTable system, and are comfortable with Lua's prototype inheritance chain, then feel free to scroll down to the bottom of this post for the full implementation.

 

For those who haven't worked with Lua's prototype system, metatables allow you to expand the functionality of an object by defining metamethods. Normally, if you try accessing a value in an object, and it does not exist, then it will return nil. That's not entirely true: It will first check the __index metamethod to see if it can find the value in there. If it can't find the value in __index, THEN it will return nil. This allows you to create multiple unique objects that conform to a class schema.

 

Motivation

Let's say you needed to have some stuff occur concurrently in the background for your project. For instance, you want to implement a class system (I.E, DPS, Tank, Healer, Etc.) and you want to give them all "abilities" that last x amount of seconds, and have to cool down for y seconds. You could probably use something like 

w8 x

to allow the ability to run, and do the same for 

w8 y

to execute the cooldown. 

 

There's two problems to this though:

1. It blocks the function that it is called in.

2. What if you want to do stuff during these times? Like tell the user that their ability has 5 seconds left, or that their cooldown for an ability ends in another 10 seconds? That simply will not work. 

 

So, I've taken a bit of inspiration from JavaScript, and I implemented a pseudo-EventQueue system for SAPP. 

 

EventItem Class

If you've already peeked at the implementation, you'll notice that EventItem has three methods you can call. Let's go over them and see how they work:

 

EventItem:new()

function EventItem.new(self) ... end

This returns a new object with the __index metamethod being set to EventItem. Basically, you can use all of the operations and values from EventItem on this new object.

 

EventItem:set()

function EventItem.set(self, props, eachTickCb, completedCb, time) ... end

This allows you to set some values for your EventItem. Let me explain what each parameter does:

time - The amount of time you want this event to last, in ticks. If you want this event to last for 30 seconds, then time should be 900 (30 * 30). If you set the time to be -1, this is a conditional event, and will only terminate once eachTickCb returns true.

props - place any values in here that you want this EventItem to have access to.

completedCb - Did you know that lua functions are first class citizens in lua? That allows you to treat them like a value. Simply define a function and reference it, or define the callback function directly in this parameter spot. This function is called when the event is completed. The props parameter is automatically passed into it when it is called.

eachTickCb -  This function is executed on every tick. This function is called with two parameters: props and time. This will execute on every tick, and allows you to do stuff while the event is counting down (I.E, display that status message from earlier).

 

EventItem:isTimedOut()

function EventItem.isTimedOut(self) ... end

This function has no parameters, but it is important that you understand what it does:

If you set the event with a finite time, then it decrements that time by 1 for every tick, and executes the eachTickCb until time is zero. When time is zero, the completedCb is executed.

If you set the event for -1 time, then it will execute the eachTickCb until it returns true, in which it will then execute the completedCb. This allows you to queue events that are related to different things other than time.

 

Full Implementation

EVENT_TABLE = {}

EventItem = {
    time=nil,
    completedCb=nil,
    eachTickCb=nil,
    props=nil
}


function EventItem.isTimedOut(self)
    if self.time == -1 then --conditional event
        if self.eachTickCb == nil and self.eachTickCb(self.props, self.time) 
            self.completedCb(self.props)
            return true 
        end
        return false
    elseif self.time == 0 then -- timed event expires
        self.completedCb(self.props)
        return true
    else --timed event has not expired
        self.time = self.time - 1
        if self.eachTickCb ~= nil then self.eachTickCb(self.props, self.time) end
        return false
    end
end

function EventItem.set(self, props, eachTickCb, completedCb, time)
    self.time = time
    self.props = props
    self.completedCb = completedCb
    self.eachTickCb = eachTickCb 
end

function EventItem.new(self)
    local newEventTableInstance = {}
    setmetatable(newEventTableInstance, self)
    self.__index = self
    return newEventTableInstance
end

function OnScriptLoad()
	... other callback definitions
	register_callback(cb['EVENT_TICK'], "handleTick")
end

function handleTick()
    for key,_ in pairs(EVENT_TABLE) do
        if EVENT_TABLE[key]:isTimedOut() == true then
            EVENT_TABLE[key] = nil 
        end
    end

end

 

I know it's a lot to take in, but I have found this VERY USEFUL for the stuff I am working on, and I love sharing these cool solutions for the interesting problems they solve. Please let me know if you have any questions about anything pertaining to this EventItem class or lua itself, and I'll be happy to help!

 

 

 

Edited by Nickster5000
Enclusion and Tucker933 like this

Share this post


Link to post
Share on other sites

Tiddy-bits:

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0
  • Recently Browsing   0 members

    No registered users viewing this page.