Skip to content

Documentation

Discookie edited this page Oct 18, 2017 · 1 revision

DOCUMENTATION

This is the page that will have function descriptions. 'Bigger' examples and tutorials are going onto separate pages.

Base

This section will describe the core modules. These provide basic functionality, useful APIs, and a majority of other modules use these as a dependency.

Logger

Description

Provides a basic interface for logging. Uses either absolute time, or frame-based timestamps, and uses named logging components for better debugging.

  Format:
Time [LEVEL] <Name>: Message

  Examples:
133.37 [ERROR] <Global>: LOGGER TEST - IGNORE ME
133.37 [INFO] <Global>: Global log level is 3

Constructor and name change

Creates a named Logger instance. It will print output_log entries with its given name.

-- Params: name (string)
local myLogger = Logger("myModule") -- makes a new unique Logger instance

myLogger:changeName("newModule") -- changes the name of an already existing instance

Log functions

Using log4j log levels, more on them here

Log levels in decreasing order, with their expected output, and log level after them:

local myLogger = Logger("myModule")

-- Log level 0: OFF

myLogger:exc("desc")
myLogger:exception("desc")
myLogger:fatal("desc")
-- 1.23 [FATAL] <Global>: Log level 1

myLogger:err("desc")
myLogger:error("desc")
-- 1.23 [ERROR] <Global>: Log level 2

myLogger:warn("desc")
myLogger:warning("desc")
-- 1.23 [WARN] <Global>: Log level 3

myLogger:log("desc")
myLogger:info("desc")
-- 1.23 [INFO] <Global>: Log level 4

myLogger:dbg("desc")
myLogger:debug("desc")
-- 1.23 [DEBUG] <Global>: Log level 5

myLogger:trace("desc", level)
-- 1.23 [TRACE] <Global>: Log level 7
-- If a level is specified, then log level '5+level'

Enable/disable

You can disable logging of each instance separately.

local myLogger = new Logger("myModule")
myLogger:log("Enabed by default - you can see this")

myLogger:disable()
myLogger:log("You cannot see this")

myLogger:enable()
myLogger:log("You can see this again")

myLogger:toggle() -- Toggles on/off
myLogger:log("Off again")

myLogger:error("Log levels ERROR and above ignore the enabled state")

Events

Description

The events module is the core of the framework. All the game's events are routed through here, with the possibility of custom events included.

The module has 2 main sections: the Event and the EventHandler.

An Event is made up of 2 parts: the id of the event, and the data of the event. While the ID is stored in the central Events table, the data is entirely event-specific, and can range from nil to a raw Track table.

Callbacks can be added to the EventHandler - whenever the specified type of event is thrown, the callback will be called. (note: you can bind classes to your callbacks)

Each callback added has an unique callbackID - with that ID, it can be changed, disabled, or even removed.

This module does NOT use multithreading - every callback is executed in the order they were added in, even if they were disabled beforehand. Disabled callbacks are skipped.

Any extra EventHandlers, apart from EventHandler.instance, will have their original events (from Events.INIT to Events.SCORE) forwarded from EventHandler.instance. This is because there is no other way to capture those events.

Constructor

A global EventHandler.instance is provided, the default events are all routed through this one central instance. You have the option to create your own EventHandler instance.

local myEventHandler = EventHandler()

(note: I will use EventHandler.instance from now on, instead of a separate instance)

You can reset to default your EventHandler, deleting every event and re-registering gameplay event forwardings.

EventHandler.instance:reset()

Adding/Removing callbacks

Callbacks can be added in 2 ways: as a standalone function, and with a class to bind to. The callback function needs to take only one parameter - the Event object of the event.

Event IDs can be found in the Events table.

-- Standalone function
local function myCallback(event)
    Logger.Global:log(dump(ev))
end

local callbackID = EventHandler.instance:on(Events.INIT, myCallback)

Callbacks can also be bound to classes, if you wish to use object-oriented modules.

-- Create a function inside our class
function MyClass:onEvent(event)
    self.logger:log(event.id)
end

-- Create an instance of our class
local myInstance = MyClass()

-- Bind our instance to our function
local callbackID2 = EventHandler.instance:on(Events.ALL, MyClass.onEvent, myInstance)

To remove a callback, you need its unique callbackID. Only with this value can the event be removed.

EventHandler.instance:remove(callbackID)

EventHandler.instance:del(callbackID2) -- alias

Enabling/Disabling callbacks

Disabling an event only disables the callbacks - it does not remove the event itself, making it possible to re-enable each event.

EventHandler.instance:enable(id)
Eventhandler.instance:disable(id)
Eventhandler.instance:toggle(id)

You can also disable an event from inside the calback function by returning a non-falsey value (usually true).

function callback(ev)
	return true -- This event will not run again until re-enabled.
end

Throwing events

Events can be thrown using the Event object. Each callback gets a separate copy of the same object.

-- Params: 
local myEvent = Event(Events.INIT, {})

EventHandler.instance:throw(myEvent)

Tick

The tick module is used to track our current position in the song as well as to provide accurate timing, taking into account pauses.

It contains two sub-modules: GameStates and Tick.

GameStates

The former, GameStates is used to track bigger sections of the loading and the game process - it tracks pauses, load segments, and pre- and post-song sections. This class is static - meaning there is only one global game state (because there is only one song playing currently).

It indicates that the song is currently in progress, by giving a 0x10 flag to the current GameState. All the possible game states are stored in GameStates, along with the current state.

-- Returns the current game state, can be cross-checked with GameStates
local currentGameState = GameStates.current

if currentGameState == GameStates.PRE_START then
    Logger.Global:log("The song is about to start!")
end

-- Short-hand for checking for the paused flag.
local gameIsPaused = GameStates.isPaused()

Tick

The latter, Tick, serves more precise timing purposes. It is recommended to use this module when syncing special effects and visuals with the song.

Tick has two separate timers: RelativeTime and AbsoluteTime.

FRAME events, when passed back by the game, have an 'elapsed time' parameter. RelativeTime uses the sum of this 'elapsed time' parameter, while AbsoluteTime gets its timing value from the number of elapsed frames. (AbsoluteTime runs based on the 90Hz refresh rate of the HTC VIVE.) On computers with more frequent frame-drops (or more reprojected frames), this will cause significant discrepancy between the two times. For static render updates, using AbsoluteTime is recommended, while RelativeTime is better for song-synchronized and timecoded visualizations.

Tick, however accurate data it gets from current frames, is still very inaccurate. For more accurate timing, use the game's built-in GetMillisecondsSinceStartup() function.

local myTick = Tick()

Instances of Tick can be reset, just like any other non-static class.

myTick:reset()

You can get current times by these two functions:

local currentRelativeTime = Tick.instance:getRelativeTime() -- based on elapsed time

local currentAbsoluteTime = Tick.instance:getAbsoluteTime() -- based on frame count

Intervals

Description

The intervals module is used mainly to run timed events and intervals. Its timing is entirely gameplay-based - meaning that if you pause the game, your timers will stop, unlike the Events.FRAME event.

To help timing functions, this module takes the two Tick module timings.

Just like EventHandler, callbacks are added to Intervals the same way - once every timeout seconds, your callback will be called. The callback can be bound to a class for object-oriented purposes.

Each interval has a unique callbackID - using this ID, the interval can be removed. Callbacks can also remove themselves by returning a non-falsey value (typically true). Timers can be created this way, only running once, and returning true.

Intervals cannot temporarily be disabled, and they cannot use a timer other than Tick - do not run high precision tasks with Intervals, run them with GetMillisecondsSinceStartup() and coroutines instead!

Constructor

A global Intervals.instance is provided. However, you can make your own if you wish.

local myIntervals = Intervals()

Adding timers/intervals

addInterval takes 3 parameters:

  • timeout to indicate their interval duration in seconds,
  • isRelativeTime to indicate the timing method, true for relative, false for absolute (default true),
  • the callback function.
  • (optional) A 4th, class parameter is also provided to make function binding easier.

Callbacks are given no parameters, they are just called - to give them an extra parameter, use the bindFunc utility.

local myTimeout = 3.5 -- seconds, not necessarily integers
local useRelativeTime = true
local function myCallback()
    Logger.Global:log("My interval is called!")
end

local callbackID = Intervals.instance:addInterval(myTimeout, useRelativeTime, myCallback) -- a 4th parameter

Removing timers/intervals

Removing intervals can be done the same way as removing events - by passing the callback ID returned from adding the interval.

Intervals.instance:delInterval(callbackID)
Intervals.instance:del(callbackID2) -- alias
Intervals.instance:remove(callbackID3) -- alias

Intervals can also delete themselves by returning true.

-- This interval would only run once - it will be removed as soon as it returns true.
-- This method is useful for creating timeouts.
local function myCallback()
    return true
end

Random

TODO.


Back to top

Gameplay

TODO.


Back to top

VR

TODO.


Back to top