Coder Social home page Coder Social logo

lua-mumble's Introduction

lua-mumble

A lua module to connect to a mumble server and interact with it

Build requirements

sudo apt-get install libluajit-5.1-dev protobuf-c libprotobuf-c-dev libssl-dev libopus-dev libev-dev

Note: libluajit-5.1-dev can be substituted with liblua5.1-0-dev, liblua5.2-dev, or liblua5.3-dev depending on your needs.

Make usage

# Removes all object files, generated protobuf c/h files, dependency files, and mumble.so
make clean

# Makes everything
make all

# Make everything with debug flags for use with a debugger
make debug

# Makes only the protobuf c files in the ./proto folder
make proto

# Copies mumble.so in /usr/local/lib/lua/5.1/
make install

# Removes mumble.so in /usr/local/lib/lua/5.1/
make uninstall

Scripting documentation

mumble

-- The mumble library is returned by a require call
local mumble = require("mumble")

-- Connect to a mumble server
-- Returns client metatable object
-- Can return nil and an error string if something went wrong
mumble.client, [ String error ] = mumble.connect(String host, Number port, String certificate file path, String key file path)

-- Main event loop that handles all events, ping, and audio processing
-- This will block the script until disconnect or SIGINT, so call this *after* you create your hooks
mumble.loop()

-- The client's user
-- Is only available *after* "OnServerSync" is called
mumble.user = mumble.client.me
mumble.user = mumble.client:getMe()
mumble.user = mumble.client:getSelf()

-- A new timer object
-- The timer itself will do a best-effort at avoiding drift, that is, if you configure a timer to trigger every 10 seconds, then it will normally trigger at exactly 10 second intervals. If, however, your program cannot keep up with the timer (because it takes longer than those 10 seconds to do stuff) the timer will not fire more than once per event loop iteration.
mumble.timer = mumble.timer()

-- A new voicetarget object
mumble.voicetarget = mumble.voicetarget()

-- A new opus encoder object
-- Sample rate defaults to 48000
mumble.encoder = mumble.encoder(Number samplerate = 48000, Number channels)

-- A new opus decoder object
-- Sample rate defaults to 48000
mumble.decoder = mumble.decoder(Number samplerate = 48000, Number channels)

-- A timestamp in milliseconds
Number time = mumble.getTime()

-- A table of all currect clients
Table clients = mumble.getClients()

-- Structure
Table clients = {
	mumble.client,
	mumble.client,
	...
}

mumble.client

-- Authenticate as a user
mumble.client:auth(String username, String password, Table tokens)

-- Set the bots access tokens
mumble.client:setTokens(Table tokens)

-- Check if the client is connected
Boolean connected = mumble.client:isConnected()

-- Check if the client has fully synced all users and channels
Boolean synced = mumble.client:isSynced()

-- Request the registered ban list from the server
-- When server responds, it will call the 'OnBanList' hook
mumble.client:requestBanList()

-- Request the registered user list from the server
-- When server responds, it will call the 'OnUserList' hook
mumble.client:requestUserList()

-- Disconnect from a mumble server
mumble.client:disconnect()

-- Transmit a plugin data packet to a table of users
mumble.client:sendPluginData(String dataID, String plugindata, Table {mumble.user, ...})

-- Transmit a raw, encoded, opus packet
-- Set speaking to false at the end of a stream
mumble.client:transmit(Number codec, String encoded_audio_packet, Boolean speaking = true)

-- Play an ogg audio file
-- Changing the stream value will allow you to play multiple audio files at once
-- If audiostream = nil, it will pass along an error string as to why it couldn't play the file
mumble.audiostream audiostream, [ String error ] = mumble.client:play(String ogg file path, Number stream = 1, Number volume = 1.0)

-- Gets the audio stream object given the stream ID
mumble.audiostream audiostream = mumble.client:getAudioStream(Number stream = 1)

-- Gets a table of all currently active audio streams
Table audiostreams = mumble.client:getAudioStreams()

-- Structure
Table audiostreams = {
	[1]	= mumble.audiostream,
	[2]	= mumble.audiostream,
	...
}

-- Sets the duration of each audio packet played.
-- Higher quality = higher audio latency
-- Lower quality  = lower audio latency

Table mumble.quality = {
	["LOW"]		= 1,
	["MEDIUM"]	= 2,
	["HIGH"]	= 3,
}

mumble.client:setAudioQuality(Number quality = [LOW = 1, MEDIUM = 2, HIGH = 3])

-- Returns the current duration of each audio packet
-- Default: mumble.quality.HIGH = 3
Number size = mumble.client:getAudioQuality()

-- Checks if the client is currently playing an audio file on the specified audio stream
Boolean playing = mumble.client:isPlaying(Number stream = 1)

-- Stops playing the current audio on the specified audio stream
mumble.client:stopPlaying(Number stream = 1)

-- Sets the global volume level
-- Consider this the master volume level
mumble.client:setVolume(Number volume)

-- Gets the global volume level
Number volume = mumble.client:getVolume()

-- Returns if the client is tunneling UDP voice data through the TCP connection
-- This will be true until the first "OnPongUDP" call
Boolean tunneludp = mumble.client:isTunnelingUDP()

-- Attempts to change the bots comment
mumble.client:setComment(String comment)

-- Adds a callback for a specific event
-- If no unique name is passed, it will default to "hook"
mumble.client:hook(String hook, [ String unique name = "hook"], Function callback)

-- Gets all registered callbacks
Table hooks = mumble.client:getHooks()

-- Structure
Table hooks = {
	["OnServerSync"] = {
		["hook"] = function: 0xffffffff,
		["do stuff on connection"] = function: 0xffffffff,
	},
	["OnPingTCP"] = {
		["hook"] = function: 0xffffffff,
		["do stuff on ping"] = function: 0xffffffff,
	},
	...
}

-- Register a mumble.voicetarget to the server
-- Accepts multiple mumble.voicetarget objects that will all be assigned to the given ID
mumble.client:registerVoiceTarget(Number id, mumble.voicetarget ...)

-- Set the current voice target that mumble.client:play() will abide by
-- Defaults to 0, the default voice target
mumble.client:setVoiceTarget(Number id)

-- Get the current voice target
Number id = mumble.client:getVoiceTarget()

-- Get the encoder object that the internal audio system uses to play .ogg files
mumble.encoder encoder = mumble.client:getEncoder()

-- Get the average ping of the client
Number ping = mumble.client:getPing()

-- Get the uptime of the current client in seconds
Number time = mumble.client:getUpTime()

-- Returns a table of all mumble.users
Table users = mumble.client:getUsers()

-- Structure
-- Key:		index
-- Value:	mumble.user
Table users = {
	[1] = mumble.user,
	[2] = mumble.user,
	[3] = mumble.user,
	...
}

mumble.channel channel = mumble.client:getChannel(String path)

-- Returns a table of all mumble.channels
Table channels = mumble.client:getChannels()

-- Structure
-- Key:		channel id
-- Value:	mumble.channel
Table channels = {
	[id] = mumble.channel,
	[id] = mumble.channel,
	...
}

-- Request a users full texture data blob
-- Server will respond with a "OnUserState" with the requested data filled out
mumble.client:requestTextureBlob(Table {mumble.user, ...})

-- Request a users full comment data blob
-- Server will respond with a "OnUserState" with the requested data filled out
-- After the hook is called, mumble.user:getComment() will also return the full data
mumble.client:requestCommentBlob(Table {mumble.user, ...})

-- Request a channels full description data blob
-- Server will respond with a "OnChannelState" with the requested data filled out
-- After the hook is called, mumble.channel:getDescription() will also return the full data
mumble.client:requestDescriptionBlob(Table {mumble.user, ...})

-- Creates a channel
-- Will be parented to the root channel
mumble.client:createChannel(String name, String description = "", Number position = 0, Boolean temporary = false, Number max_users = 0)

mumble.user

-- Sends a text message to a user
mumble.user:message(String host)

-- Attempts to kick a user with an optional reason value
mumble.user:kick([ String reason ])

-- Attempts to ban a user with an optional reason value
mumble.user:ban([ String reason ])

-- Attempts to move a user to a different channel
mumble.user:move(mumble.channel channel)

-- Attempts to mute a user
-- If no boolean is passed, it will default to muting the user
mumble.user:setMuted([ Boolean mute = true ])

-- Attempts to deafen a user
-- If no boolean is passed, it will default to deafening the user
mumble.user:setDeaf([ Boolean deaf = true ])

-- Attempts to register the users name to the server
mumble.user:register()

-- Requests the users information statistics from the server
-- If no boolean is passed, it will default to requesting ALL statistics
mumble.user:requestStats([ Boolean statsonly = false ])

-- Gets the current mumble.client this user is a part of
mumble.client client = mumble.user:getClient()

-- Gets the current session number
Number session = mumble.user:getSession()

-- Gets the name of the user
String name = mumble.user:getName()

-- Gets the channel of the user
mumble.channel channel = mumble.user:getChannel()

-- Gets the registered ID of the user
-- Is 0 for unregistered users
Number userid = mumble.user:getID()

-- Returns if the user is muted or not
Boolean muted = mumble.user:isMuted()

-- Returns if the user is deaf or not
Boolean deaf = mumble.user:isDeaf()

-- Returns if the user is muted or not
Boolean muted = mumble.user:isSelfMute()

-- Returns if the user is deaf or not
Boolean deaf = mumble.user:isSelfDeaf()

-- Returns if the user is suppressed by the server
Boolean suppressed = mumble.user:isSuppressed()

-- Returns the comment string of the users comment
String comment = mumble.user:getComment()

-- Returns the comments SHA1 hash
String hash = mumble.user:getCommentHash()

-- Returns if the user is speaking or not
Boolean speaking = mumble.user:isSpeaking()

-- Returns if the user is recording or not
Boolean recording = mumble.user:isRecording()

-- Returns if the user is a priority speaker or not
Boolean priority = mumble.user:isPrioritySpeaker()

-- Returns the users avatar as a string of bytes
String texture = mumble.user:getTexture()

-- Returns the users avatar as a SHA1 hash
String hash = mumble.user:getTextureHash()

-- Returns the users username SHA1 hash
String hash = mumble.user:getHash()

-- Sets the users avatar image using a string of bytes
mumble.user:setTexure(String bytes)

-- Adds a channel to the list of channels the user is listening to
mumble.user:listen(mumble.channel ...)

-- Removes a channel from the list of channels the user is listening to
mumble.user:unlisten(mumble.channel ...)

-- Returns a table of all channels the user is currently listening to
Table listens = mumble.user:getListens()

-- Structure
-- Key:		channel id
-- Value:	mumble.channel
Table channels = {
	[id] = mumble.channel,
	[id] = mumble.channel,
	...
}

-- Transmit a plugin data packet to this user
mumble.user:sendPluginData(String dataID, String plugindata)

-- Request a users full texture data blob
-- Server will respond with a "OnUserState" with the requested data filled out
-- After the hook is called, mumble.user:getTexture() will also return the full data
mumble.user:requestTextureBlob()

-- Request a users full comment data blob
-- Server will respond with a "OnUserState" with the requested data filled out
-- After the hook is called, mumble.user:getComment() will also return the full data
mumble.user:requestCommentBlob()

mumble.channel

-- Gets a channel relative to the current
mumble.channel channel = mumble.channel(String path)

-- Sends a text message to the entire channel
mumble.channel:message(String message)

-- Attempts to set the channels description
mumble.channel:setDescription(String description)

-- Attempts to remove the channel
mumble.channel:remove()

-- Gets the current mumble.client this channel is a part of
mumble.client client = mumble.channel:getClient()

-- Gets the channels name
String name = mumble.channel:getName()

-- Gets the channel ID
Number id = mumble.channel:getID()

-- Gets the parent channel
-- Returns nil on root channel
mumble.channel channel = mumble.channel:getParent()

-- Returns the channels that are parented to the channel
Table children = mumble.channel:getChildren()

-- Returns the users that are currently within the channel
Table users = mumble.channel:getUsers()

-- Structure
-- Key:		index
-- Value:	mumble.user
Table users = {
	[1] = mumble.user,
	[2] = mumble.user,
	[3] = mumble.user,
	...
}

-- Gets the channels description
String description = mumble.channel:getDescription()

-- Gets the channels description SHA1 hash
String hash = mumble.channel:getDescriptionHash()

-- Returns if the channel is temporary or not
Boolean temporary = mumble.channel:isTemporary()

-- Returns the channels position
Number position = mumble.channel:getPosition()

-- Gets the max number of users allowed in this channel
Number max = mumble.channel:getMaxUsers()

-- Returns a table of all linked channels
Number linked = mumble.channel:getLinked()

-- Attempts to link channel(s)
mumble.channel:link(mumble.channel ...)

-- Attempts to unlink channel(s)
mumble.channel:unlink(mumble.channel ...)

-- Returns if the client is restricted from entering the channel
-- NOTE: *Will only work in mumble version 1.4+*
Boolean restricted = mumble.channel:isEnterRestricted()

-- Returns if the client is able to enter the channel
-- NOTE: *Will only work in mumble version 1.4+*
Boolean enter = mumble.channel:canEnter()

-- Request ACL config for the channel
-- When server responds, it will call the 'OnACL' hook
mumble.channel:requestACL()

-- Request permissions for the channel
-- When server responds, it will call the 'OnPermissionQuery' hook
mumble.channel:requestPermissions()

-- Gets the permissions value for the channel
Number permissions = mumble.channel:getPermissions()

-- Gets the permissions value for the channel
Boolean permission = mumble.channel:hasPermission(mumble.acl flag)

-- Request a users full texture data blob
-- Server will respond with a "OnChannelState" with the requested data filled out
-- After the hook is called, mumble.channel:getDescription() will also return the full data
mumble.channel:requestTextureBlob()

-- Creates a channel
-- Will be parented to the channel that this method was called from
mumble.channel:create(String name, String description = "", Number position = 0, Boolean temporary = false, Number max_users = 0)

mumble.timer

-- Configure the timer to trigger after after seconds (fractional and negative values are supported).
-- If repeat is 0, then it will automatically be stopped once the timeout is reached.
-- If it is positive, then the timer will automatically be configured to trigger again repeat seconds later, again, and again, until stopped manually.
mumble.timer:start(Function callback, Number after, Number repeat = 0)

-- Configure the timer to trigger after after seconds (fractional and negative values are supported).
-- If repeat is 0., then it will automatically be stopped once the timeout is reached.
-- If it is positive, then the timer will automatically be configured to trigger again repeat seconds later, again, and again, until stopped manually.
mumble.timer:set(Number after, Number repeat = 0)

-- This will act as if the timer timed out, and restarts it again if it is repeating. It basically works like calling mumble.timer.stop, updating the timeout to the repeat value and calling mumble.timer.start.
-- The exact semantics are as in the following rules, all of which will be applied to the watcher:
-- If the timer is pending, the pending status is always cleared.
-- If the timer is started but non-repeating, stop it (as if it timed out, without invoking it).
-- If the timer is repeating, make the repeat value the new timeout and start the timer, if necessary.
mumble.timer:again()

-- Stops the timer
mumble.timer:stop()

mumble.voicetarget

-- Add a user to whisper to
mumble.voicetarget:addUser(mumble.user user)

-- Return a table of all the users currently in the voicetarget
Table users = mumble.voicetarget:getUsers()

-- Structure
-- Key:		index
-- Value:	Number session
Table channels = {
	Number session,
	Number session,
	...
}

-- Sets the channel that is be shouted to
mumble.voicetarget:setChannel(mumble.channel channel)

-- Gets the channel that is shouted to
mumble.voicetarget:getChannel()

-- Sets the specific user group to whisper to
mumble.voicetarget:setGroup(String group)

-- Gets the group name we are whispering to
String group = mumble.voicetarget:getGroup()

-- Shout to the linked channels of the set channel
mumble.voicetarget:setLinks(Boolean followlinks)

-- Returns if we are currently shouting to linked channels of the set channel
Boolean links = mumble.voicetarget:getLinks()

-- Shout to the children of the set channel
mumble.voicetarget:setChildren(Boolean followchildren)

-- Returns if we are currently shouting to children of the set channel
Boolean children = mumble.voicetarget:getChildren()

mumble.encoder

-- Equivalent to OPUS_RESET_STATE
mumble.encoder:reset()

-- Equivalent to OPUS_GET_FINAL_RANGE
Number range = mumble.encoder:getFinalRange()

-- Equivalent to OPUS_GET_BANDWIDTH
Number bandwidth = mumble.encoder:getBandwidth()

-- Equivalent to OPUS_GET_SAMPLE_RATE
Number samplerate = mumble.encoder:getSamplerate()

-- Set the bitrate that the encoder will use
mumble.encoder:setBitRate(Number bitrate)

-- Get the bitrate that the encoder is using
Number bitrate = mumble.encoder:getBitRate()

-- Encode X number of pcm frames into an opus audio packet
String encoded = mumble.encoder:encode(Number frames, String pcm)

-- Encode X number of pcm float frames into an opus audio packet
String encoded = mumble.encoder:encode_float(Number frames, String pcm)

mumble.decoder

-- Equivalent to OPUS_RESET_STATE
mumble.decoder:reset()

-- Equivalent to OPUS_GET_FINAL_RANGE
Number range = mumble.decoder:getFinalRange()

-- Equivalent to OPUS_GET_BANDWIDTH
Number bandwidth = mumble.decoder:getBandwidth()

-- Equivalent to OPUS_GET_SAMPLE_RATE
Number samplerate = mumble.decoder:getSamplerate()

-- Set the bitrate that the decoder will use
mumble.decoder:setBitRate(Number bitrate)

-- Get the bitrate that the decoder is using
Number bitrate = mumble.decoder:getBitRate()

-- Decode an opus audio packet into raw PCM data
String decoded = mumble.decoder:decode(String encoded)

-- Decode an opus audio packet into raw PCM float data
String decoded = mumble.decoder:decode_float(String encoded)

mumble.audiostream

-- Returns if this audio stream is currently playing or not
Boolean isplaying = mumble.audiostream:isPlaying()

-- Sets the volume of the audio stream
mumble.audiostream:setVolume(Number volume)

-- Gets the volume of the audio stream
Number volume = mumble.audiostream:getVolume()

-- Gets the stream number of this audio stream
Number stream = mumble.audiostream:getVolume()

-- Pause the audio
mumble.audiostream:pause()

-- Resume playing the audio
mumble.audiostream:play()

-- Pauses the audio AND resets playback from the beginning
mumble.audiostream:stop()

-- Will attempt to seek to a given position via sample numbers
-- Returns the offset that it has seeked to
Number samples = mumble.audiostream:seek(String whence ["start", "cur", "end"], Number offset = 0)

-- Returns the duration of the stream given the unit type
Number samples/seconds = mumble.audiostream:getLength(String units ["seconds", "samples"])

Table info = mumble.audiostream:getInfo()

Table comments = mumble.audiostream:getComment()

-- Stops the audio stream from playing.
-- Calls "OnAudioFinished" hook
-- Is lastly removed from the mumble.client:getAudioStreams() table
mumble.audiostream:close()

mumble.acl

Table mumble.acl = {
	NONE = 0x0,
	WRITE = 0x1,
	TRAVERSE = 0x2,
	ENTER = 0x4,
	SPEAK = 0x8,
	MUTE_DEAFEN = 0x10,
	MOVE = 0x20,
	MAKE_CHANNEL = 0x40,
	LINK_CHANNEL = 0x80,
	WHISPER = 0x100,
	TEXT_MESSAGE = 0x200,
	MAKE_TEMP_CHANNEL = 0x400,
	LISTEN = 0x800,

	-- Root channel only
	KICK = 0x10000,
	BAN = 0x20000,
	REGISTER = 0x40000,
	SELF_REGISTER = 0x80000,
	RESET_USER_CONTENT = 0x100000,

	CACHED = 0x8000000,
	ALL = WRITE + TRAVERSE + ENTER + SPEAK + MUTE_DEAFEN + MOVE
			+ MAKE_CHANNEL + LINK_CHANNEL + WHISPER + TEXT_MESSAGE + MAKE_TEMP_CHANNEL + LISTEN
			+ KICK + BAN + REGISTER + SELF_REGISTER + RESET_USER_CONTENT,
}

mumble.reject

Table mumble.reject = {
	[0] = "None",
	[1] = "WrongVersion",
	[2] = "InvalidUsername",
	[3] = "WrongUserPW",
	[4] = "WrongServerPW",
	[5] = "UsernameInUse",
	[6] = "ServerFull",
	[7] = "NoCertificate",
	[8] = "AuthenticatorFail",
}

mumble.deny

Table mumble.deny = {
	[0]  = "Text",
	[1]  = "Permission",
	[2]  = "SuperUser",
	[3]  = "ChannelName",
	[4]  = "TextTooLong",
	[5]  = "H9K",
	[6]  = "TemporaryChannel",
	[7]  = "MissingCertificate",
	[8]  = "UserName",
	[9]  = "ChannelFull",
	[10] = "NestingLimit",
	[11] = "ChannelCountLimit",
}

hooks

OnServerVersion (mumble.client client, Table event)

Called when the server version information is recieved.

Table event = {
	["version"]		= Number version,
	["release"]		= String release,
	["os"]			= String os,
	["os_version"]	= String os_version,
}

OnPongTCP (mumble.client client, Table event)

Called when the server sends a responce to a TCP ping request.

Table event = {
	["ping"]			= Number ping,
	["timestamp"]		= Number timestamp,
	["good"]			= Number good,
	["late"]			= Number late,
	["lost"]			= Number lost,
	["resync"]			= Number resync,
	["udp_packets"]		= Number udp_packets,
	["tcp_packets"]		= Number tcp_packets,
	["udp_ping_avg"]	= Number udp_ping_avg,
	["udp_ping_var"]	= Number udp_ping_var,
	["tcp_ping_avg"]	= Number tcp_ping_avg,
	["tcp_ping_var"]	= Number tcp_ping_var,
}

OnPongUDP (mumble.client client, Table event)

Called when the server sends a responce to a UDP ping request.

Table event = {
	["ping"]			= Number ping,
	["timestamp"]		= Number timestamp,
}

OnServerReject (mumble.client client, Table event)

Called when you are rejected from connecting to the server.

Table event = {
	["type"]	= mumble.reject type,
	["reason"]	= String reason,
}

OnServerSync (mumble.client client, Table event)

Called after the bot has recieved all the mumble.user and mumble.channel states.

Table event = {
	["user"]			= mumble.user user,
	["max_bandwidth"]	= Number max_bandwidth,
	["welcome_text"]	= String welcome_text,
	["permissions"]		= Number permissions,
}

OnChannelRemove (mumble.client client, mumble.channel channel)

Called when a mumble.channel is removed.


OnChannelState (mumble.client client, Table event)

Called when a mumble.channel state has changed.. Like updating the name, description, position, comment, etc.. Not every value will always be set. Only the fields that are currently changing will be set!

Table event = {
	["channel"]				= mumble.channel channel,
	["parent"]				= mumble.channel parent,
	["channel_id"]			= Number channel_id,
	["position"]			= Number position,
	["max_users"]			= Number max_users,
	["name"]				= String name,
	["description"]			= String description,
	["description_hash"]	= String description_hash,
	["temporary"]			= Boolean temporary,
	["is_enter_restricted"]	= Boolean is_enter_restricted,
	["can_enter"]			= Boolean can_enter,
	["links"]				= {
		[1] = mumble.channel channel,
		...
	},
	["links_add"]			= {
		[1] = mumble.channel channel,
		...
	},
	["links_remove"]		= {
		[1] = mumble.channel channel,
		...
	}
}

OnUserChannel (mumble.client client, Table event)

Called when a mumble.user changes their channel

Table event = {
	["user"]	= mumble.user user,
	["actor"]	= mumble.user actor,
	["from"]	= mumble.channel from,
	["to"]		= mumble.channel to,
}

OnUserRemove (mumble.client client, Table event)

Called when a mumble.user disconnects or is kicked from the server

Table event = {
	["user"]	= mumble.user user,
	["actor"]	= mumble.user actor,
	["reason"]	= String reason,
	["ban"]		= Boolean ban,
}

OnUserConnected (mumble.client client, Table event)

Called when a mumble.user has connected to the server

Table event = {
	["user"]	= mumble.user user,
	...
}

OnUserState (mumble.client client, Table event)

Called when a mumble.user state has changed.. Like updating their comment, moving channels, muted, deafened, etc.. Not every value will always be set. Only the fields that are currently changing will be set!

Table event = {
	["user_id"]				= Number user_id,
	["session"]				= Number session,
	["actor"]				= mumble.user actor,
	["user"]				= mumble.user user,
	["channel"]				= mumble.channel channel,
	["mute"]				= Boolean mute,
	["deaf"]				= Boolean deaf,
	["self_mute"]			= Boolean self_mute,
	["self_deaf"]			= Boolean self_deaf,
	["suppress"]			= Boolean suppress,
	["recording"]			= Boolean recording,
	["priority_speaker"]	= Boolean priority_speaker,
	["name"]				= String name,
	["comment"]				= String comment,
	["texture"]				= String texture,
	["hash"]				= String hash,
	["comment_hash"]		= String comment_hash,
	["texture_hash"]		= String texture_hash,
}

OnUserStartSpeaking (mumble.client client, mumble.user)

Called when a user starts to transmit voice data.


OnUserStopSpeaking (mumble.client client, mumble.user)

Called when a user stops transmitting voice data.


OnUserSpeak (mumble.client client, Table event)

Called when a user starts to transmit voice data.

Table event = {
	["user"]			= mumble.user user,
	["codec"]			= Number codec,
	["target"]			= Number target,
	["sequence"]		= Number sequence,
	["data"]			= String encoded_opus_packet,
	["frame_header"]	= Number frame_header, // The frame header usually contains a length and terminator bit
	["speaking"]		= Boolean speaking,
}

OnBanList (mumble.client client, Table banlist)

Called on response to a mumble.client:requestBanList() call

Table banlist = {
	[1] = {
		["address"] = {
			["string"]	= String ipaddress,
			["ipv4"]	= Boolean isipv4,
			["ipv6"]	= Boolean isipv6,
			["data"]	= Table raw,
		},
		["mask"]		= Number ip_mask,
		["name"]		= String name,
		["hash"]		= String hash,
		["reason"]		= String reason,
		["start"]		= String start,
		["duration"]	= Number duration
	},
	...
}

OnMessage (mumble.client client, Table event)

Called when the bot receives a text message

Table event = {
	["actor"]		= mumble.user actor,
	["message"]		= String message,
	["users"]		= Table users,
	["channels"]	= Table channels -- will be nil when receiving a direct message
}

OnPermissionDenied (mumble.client client, Table event)

Called when an action is performed that you don't have permission to do

Table event = {
	["type"]		= Number type,
	["permission"]	= Number permission,
	["channel"]		= mumble.channel channel,
	["user"]		= mumble.user user,
	["reason"]		= String reason,
	["name"]		= String name,
}

OnACL (mumble.client client, Table acl)

Called when ACL data is received from a mumble.channel:requestACL() request

Table acl = {
	["channel"]      = mumble.channel channel,
	["inherit_acls"] = Boolean inherit_acls,
	["groups"]       = {
		[1] = {
			["name"]        = String group_name,
			["inherited"]   = Boolean inherited,
			["inheritable"] = Boolean inheritable,
			["add"] = {
				[1] = Number user_id,
				...
			},
			["remove"] = {
				[1] = Number user_id,
				...
			},
			["inherited_members"] = {
				[1] = Number user_id,
				...
			}
		},
		...
	},
	["acls"]       = {
		[1] = {
			["apply_here"]  = Boolean apply_here,
			["apply_subs"]  = Boolean apply_subs,
			["inherited"]   = Boolean inherited,
			["user_id"]     = Number user_id,
			["group"]       = String group,
			["grant"]       = Number grant, -- This number is a flag that determines what this group is allowed to do
			["deny"]        = Number deny,  -- This number is a flag that determines what this group is NOT allowed to do
		},
		...
	},
}

OnCryptSetup (mumble.client client, Table event)

Called when the server sends UDP encryption keys to the client.

Table event = {
	["valid"]			= Boolean valid,
	["key"]				= String key,
	["client_nonce"]	= String client_nonce,
	["server_nonce"]	= String server_nonce,
}

OnUserList (mumble.client client, Table userlist)

Called on response to a mumble.client:requestUsers() call

Table userlist = {
	[1] = {
		["user_id"]			= Number user_id,
		["name"]			= String name,
		["last_seen"]		= String last_seen,
		["last_channel"]	= mumble.channel last_channel,
	},
	...
}

OnPermissionQuery (mumble.client client, Table event)

Called when the bot recieves permissions for a channel.

Table event = {
	["channel"]			= mumble.channel channel,
	["permissions"]		= Number permissions,
	["flush"]			= Boolean flush,
}

OnCodecVersion (mumble.client client, Table event)

Called when the bot recieves the codec info from the server.

Table event = {
	["alpha"]			= Number alpha,
	["beta"]			= Number beta,
	["prefer_alpha"]	= Boolean prefer_alpha,
	["opus"]			= Boolean opus,
}

OnUserStats (mumble.client client, Table event)

Called when the mumble.user's detailed statistics are received from the server. Only sent if mumble.user:requestStats() is called.

Table event = {
	["user"]				= mumble.user actor,
	["stats_only"]			= Boolean stats_only,
	["certificates"]		= Table certificates,
	["from_client"]			= {
		["good"]	= Number good,
		["late"]	= Number late,
		["lost"]	= Number lost,
		["resync"]	= Number resync,
	},
	["from_server"]			= {
		["good"]	= Number good,
		["late"]	= Number late,
		["lost"]	= Number lost,
		["resync"]	= Number resync,
	},
	["udp_packets"]			= Number udp_packets,
	["tcp_packets"]			= Number tcp_packets,
	["udp_ping_avg"]		= Number udp_ping_avg,
	["udp_ping_var"]		= Number udp_ping_var,
	["tcp_ping_avg"]		= Number tcp_ping_avg,
	["tcp_ping_var"]		= Number tcp_ping_var,
	["version"]				= Number version,
	["release"]				= String release,
	["os"]					= String os,
	["os_version"]			= String os_version,
	["certificates"]		= Table celt_versions,
	["address"]				= {
		["string"]	= String ipaddress,
		["ipv4"]	= Boolean isipv4,
		["ipv6"]	= Boolean isipv6,
		["data"]	= Table raw,
	},
	["bandwidth"]			= Number bandwidth,
	["onlinesecs"]			= Number onlinesecs,
	["idlesecs"]			= Number idlesecs,
	["strong_certificate"]	= Boolean strong_certificate,
	["opus"]				= Boolean opus,
}

OnServerConfig (mumble.client client, Table event)

Called when the servers settings are received. Usually called after OnServerSync

Table event = {
	["max_bandwidth"]			= Number max_bandwidth,
	["welcome_text"]			= String welcome_text,
	["allow_html"]				= Boolean allow_html,
	["message_length"]			= Number message_length,
	["image_message_length"]	= Number image_message_length,
	["max_users"]				= Number max_users,
}

OnSuggestConfig (mumble.client client, Table event)

Called when the servers suggest the client to use specific settings.

Table event = {
	["version"]					= Number version,
	["positional"]				= Boolean positional,
	["push_to_talk"]			= Boolean push_to_talk,
}

OnPluginData (mumble.client client, Table event)

Called when the client receives plugin data from the server.

Table event = {
	["sender"] = mumble.user sender, -- Who sent this data packet
	["id"]     = Number id,          -- The data ID of this packet
	["data"]   = String data,        -- The data sent (can be binary data)
	["receivers"]				= {  -- A table of who is receiving this data
		[1] = mumble.user,
		...
	},
}

OnError (mumble.client client, String error)

Called when an error occurs inside a hook. WARNING: Erroring within this hook will cause an error on the line where mumble.loop() is called, causing the script to exit


OnPingTCP (mumble.client client, Table event)

Called just before a TCP ping is sent to the server. This updates the users statistics found on their information panel. The mumble.client will automatically ping the server every 30 seconds within mumble.loop()

Table event = {
	["timestamp"]		= Number timestamp,
	["good"]			= Number good,
	["late"]			= Number late,
	["lost"]			= Number lost,
	["resync"]			= Number resync,
	["udp_packets"]		= Number udp_packets,
	["tcp_packets"]		= Number tcp_packets,
	["udp_ping_avg"]	= Number udp_ping_avg,
	["udp_ping_var"]	= Number udp_ping_var,
	["tcp_ping_avg"]	= Number tcp_ping_avg,
	["tcp_ping_var"]	= Number tcp_ping_var,
}

OnPingUDP (mumble.client client, Table event)

Called just before a UDP ping is sent to the server. The mumble.client will automatically ping the server every 30 seconds within mumble.loop()

Table event = {
	["timestamp"]		= Number timestamp,
}

OnAudioStreamEnd (mumble.client client, mumble.audiostream stream)

Called when a sound file has finished playing. Passes the number of the audio stream that finished.

lua-mumble's People

Contributors

asdfjkluiop avatar bkacjios avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

lua-mumble's Issues

client:play() arguments?

So I know you don't support this anymore really, and it seems like you're making Lumble, to be better and whatnot, but I stumbled on this and wanted to use it. I got most of it down, but your documentation for client:play seems to be wrong unfortunately. mumble.client:play(String ogg file path) is the string you document, but giving it a direct path to the .ogg doesn't work, as it expects a number for arg #2.

uninitialized error variable in client_play()

Hi,

It seems that error variable in client_play() (client.c) is not initialized and stb_vorbis_open_filename() in case of success does not change its value so that following error checking if statement works only by chance (on my setup it didn't work).

Simple solution:

-	int error;
+	int error = VORBIS__no_error;

Additionally I think there is possible memory leak in case of error in stb_vorbis_open_filename() - function returns without freeing the sound pointer.

Hook:OnMessage

I just tried to implement a chat interface, based on received messages: https://github.com/bkacjios/lua-mumble#onmessage-mumbleclient-client-table-event

However, it seems that just the message gets set into the event table. users is always an empty table and actor nil:

client:hook("OnMessage", function(client, event)
    -- ["actor"]		= mumble.user actor,
    -- ["message"]		= String message,
    -- ["users"]		= Table users,
    -- ["channels"]	= Table channels
    print("OnMessage:client", client)
    pprint(client)
    print("OnMessage:event", event)
    pprint(event)
end)

Sending "test" in direct chat prints:

OnMessage:client        mumble.client: 0x41d3a428

OnMessage:event table: 0x41d39c08
{ 
  message = 'TEST',
  users = {} 
}

Audio playback stutter

Thanks for making lua-mumble!

Same as #5, audio playback via

local stream, err = client:play("music.ogg", 1, 1.0)

stutters from time to time (every 10~20 seconds), tested with a 48000Hz 2ch ogg file.

Played samples not audible after some time (client:transmit)

Hello,
i have a playback bot (https://github.com/hbeni/fgcom-mumble/blob/master/server/fgcom-radio-playback.bot.lua) that plays back samples previously recorded.

This works fine. Until it doesn't. My log at the terminal still shows samples that are processed and put into the client:transmit function. From the mumble client perspective it looks like the bot is not speaking.

What i can see is, when activating the debug output of the sample data, that the printed binary blob changes at the moment when the transmission stops working.
The samples to be played are fetched from a lua buffer variable, that gets filled if its empty.

It somehow looks like the content of the buffer is overwritten with "garbage/random not-sample-data" at a random point in time - possible memory corruption?

Compilation error from duplicate packet_handler definitions

Clean make all leads to:

/usr/bin/ld: channel.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: channel.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: client.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: client.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: encoder.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: encoder.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: mumble.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: mumble.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: packet.o:(.data.rel.ro+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: packet.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: target.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: target.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: timer.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: timer.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: user.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: user.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
/usr/bin/ld: util.o:(.rodata+0x0): multiple definition of `packet_handler'; audio.o:(.rodata+0x0): first defined here
/usr/bin/ld: util.o:(.bss+0x0): multiple definition of `MUMBLE_CONNECTIONS'; audio.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

which leads to rg packet_handler showing:

mumble.h:338:27:const Packet_Handler_Func packet_handler[NUM_PACKETS];
packet.c:1051:27:const Packet_Handler_Func packet_handler[27] = {

And looking at the git blame, it seems like the one in packet.c was very very recently added in
72c83f239c8307a59a322abd6bb5f0c9688c76b9

Which I would assume is the cause of the duplication?

Private message event

OnMessage event don't react on incoming private text message. How I can catch it? Thanks.

Add sample speed informatin to OnUserSpeak() hook

Currently we have no samplespeed information in the event table passed to the hook OnUserSpeak.
Thus we need to guess it currently (0.02 secs spacing between samples for 48kHz samples).

As the speed can vary depending on the codec used and some other circumstances, this should be passed from mumble to the lua hook.

How to compile?

I know you probably don't have notifications for this and this is a stupid question but if i'm being honest, I have no idea how to compile this. I'm a Lua programmer, not a C programmer, gosh darnit.
I compiled protoc as necessary, moved the headers into the folder as needed, and then i just kept re running make and downloading any headers I needed after that it started throwing errors in the mumble.c and it said a bunch of packages were not found in the pkg-config-path environment variable.
Any chance you have some binaries for Windows or Linux on hand?

Ok, I've successfully compiled. I still think official binaries or comp instructions would be helpful, but I'm going to leave my process below in case anyone else wants to build this but doesn't know how. (instructions for Linux)
Clone the repository, and then use the command make or make -f makefile inside of the directory. It will start to tell you you're missing certain packages like protobuf-c or openssl or vorbis. Whenever it does that, do sudo apt-get install lib[package]-dev where [package] is what you were missing, so the first thing you'll probably run into is no protobuf-c/protobuf-c.h file. So you would do sudo apt-get install libprotobuf-c-dev . Just keep installing those packages and then makeing until it doesnt fail any more. Then you'll be able to require Mumble in Lua.

Add plugin packets

Hello,
mumble-voip/mumble#3743 will introduce a new plugin framework and with that comes a new packet type in the protocol that allows plugins to communicate to each other.
It would be nice if this packet would be supported in the lua client lib.
Plugins can use the method to send arbitary data to each other via the server.
A hook call when such data is incoming would be good, as well as an function to send such data to other clients (via the server).

The protobuf definition is here:

message PluginDataTransmission {
	// The session ID of the client this message was sent from
	optional uint32 senderSession = 1;
	// The session IDs of the clients that should receive this message
	repeated uint32 receiverSessions = 2 [packed = true];
	// The data that is sent
	optional bytes data = 3;
	// The ID of the sent data. This will be used by plugins to check whether they will
	// process it or not
	optional string dataID = 4;
}

client.me object absent

local mumble = require("mumble")
local client = assert(mumble.connect("some.host", 64738, "bot.pem", "bot.key"))
client:auth("Test-Bot")
local user = client.me
print(user)

Result: nil value

(bot has connected to server and works)
How to get own client user object???

Stuttery Audio playback

I have the project working well, the chatbot features we need are fine, however we want a new music bot and i've gotten the functionality working, however the audio sometimes stutters, and it makes it a little awkward. Both while connecting to the server over a network, and while connecting internally.

timer.c realloc(): invalid next size

Hi there,
thanks to your fabolous library, i was able to implement the server side bots for fgcom-mumble.

Now I wanted to implement some fake clients (code see here) that connect to mumble and perform average stuff so I can test load of the server given my plugin infrastructure.
Unfortunately, the bots abort at a random time, especially if load/bot count increases.

I spawn the bots with a shell script, and the limit seems to be about 10 bots, then they start dropping out, printing "realloc(): invalid next size" as their last words.

It looks like some memory corruption, at least what i have found on the internet (but i have no knowledge of such things).

I was able to capture one of such aborts using gdb, and it pointed me to timer.c, line 19 and mumble.c, line 341.

realloc(): invalid next size

Program received signal SIGABRT, Aborted.
0x00007ffff7c77781 in raise () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) 
(gdb) 
(gdb) where
#0  0x00007ffff7c77781 in raise () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff7c6155b in abort () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff7cba038 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007ffff7cc13da in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x00007ffff7cc548c in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#5  0x00007ffff7cc6426 in realloc () from /lib/x86_64-linux-gnu/libc.so.6
#6  0x000055555556130e in ?? ()
#7  0x000055555555e499 in ?? ()
#8  0x000055555555ee80 in ?? ()
#9  0x000055555555f0a4 in ?? ()
#10 0x000055555555e41e in ?? ()
#11 0x000055555555f26d in ?? ()
#12 0x000055555555c9a8 in lua_pcall ()
#13 0x00007ffff7bf3bd7 in mumble_lua_timer (loop=0x7ffff7854720, w_=0x555555600ce8, revents=256) at timer.c:19
#14 0x00007ffff7848633 in ev_invoke_pending () from /usr/lib/x86_64-linux-gnu/libev.so.4
#15 0x00007ffff784be71 in ev_run () from /usr/lib/x86_64-linux-gnu/libev.so.4
#16 0x00007ffff7bf22b3 in mumble_loop (l=0x5555555832a0) at mumble.c:341
#17 0x000055555555eb59 in ?? ()
#18 0x000055555556850d in ?? ()
#19 0x000055555555f0d5 in ?? ()
#20 0x000055555555e41e in ?? ()
#21 0x000055555555f26d in ?? ()
#22 0x000055555555c9a8 in lua_pcall ()
#23 0x000055555555aa3e in ?? ()
#24 0x000055555555b506 in ?? ()
#25 0x000055555555eb59 in ?? ()
#26 0x000055555555f0a4 in ?? ()
#27 0x000055555555e41e in ?? ()
#28 0x000055555555f26d in ?? ()
#29 0x000055555555ca37 in lua_cpcall ()
#30 0x000055555555a6c6 in ?? ()
#31 0x00007ffff7c62e0b in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#32 0x000055555555a74a in ?? ()

Implement pluginData sending function

With the hook OnPluginData we are capable of receiving plugins information.
I need to broadcast such plugin data from a bot of mine, so my plugin can make itself aware to the plugin and beeing handled properly.
Something along the lines of mumble.client:send(String dataID, String message, [Array tgtusers]) where tgtusers is optional and defaults to all clients connected to the server.

MumbleAPI.h defines this as following, if that helps:

/// Sends the provided data to the provided client(s). This kind of data can only be received by another plugin active
/// on that client. The sent data can be seen by any active plugin on the receiving client. Therefore the sent data
/// must not contain sensitive information or anything else that shouldn't be known by others.
///
/// @param callerID The ID of the plugin calling this function
/// @param connection The ID of the server-connection to send the data through (the server the given users are on)
/// @param users An array of user IDs to send the data to
/// @param userCount The size of the provided user-array
/// @param data The data that shall be sent as a String
/// @param dataLength The length of the data-string
/// @param dataID The ID of the sent data. This has to be used by the receiving plugin(s) to figure out what to do with
/// 	the data
/// @returns The error code. If everything went well, STATUS_OK will be returned.
mumble_error_t (PLUGIN_CALLING_CONVENTION *sendData)(plugin_id_t callerID, mumble_connection_t connection, mumble_userid_t *users, size_t userCount, const char *data, size_t dataLength, const char *dataID);

Crash in timer.lua example script

With adding "mumble:loop()" at the end of "timer.lua" example and running, it crashes after first iteration after 15 seconds. Is it normal?

1
2
3
Stopping timer..
free(): invalid pointer

With empty "OnServerSync" hook the same:

local mumble = require("mumble")
local client = assert(mumble.connect("druha.su", 64738, "bot.pem", "bot.key"))
client:auth("Mumble-Bot")
client:hook("OnServerSync", function(event)
  print("tick")
end)
mumble.loop()

Question: How to capture incoming audio stream?

Hello,
i'm not sure if i understand the API correctly, but it seems there is currently no way to capture audio streams form other users?

I want to build some recording bot that stores incoming audio to a file on disk, suitable for later playback trough lua-mumble (background is fgcom-mumble, i need this for the ATIS recording feature).
How can i do that?

It is impotant to somehow beeing able to distinguish between sending users, because there might be several users recording ATIS messages in parallel.

hook onUserChannel() not called?

Hi,
i try to use the following hook from the readme to detect users joining my channel:

client:hook("OnUserChannel", function(event)
	--["user"]	= mumble.user user,
	--["actor"]	= mumble.user actor,
	--["from"]	= mumble.channel from,
	--["to"]	= mumble.channel to,
    print("OnUserChannel(): client joined channel: ", event.user.getName())
end)

However it never seems to fire?

I was curious and looked in the hooks example code, there the hook is missing.
Is it not implemented yet?

sendPluginData with list broken? `bad argument #3 to 'sendPluginData' (mumble.user expected, got table)`

Hi, i noticed the following issue: bad argument #3 to 'sendPluginData' (mumble.user expected, got table)

  • I have code that updates a global playback_targets variable. It builds a table containing mumble.user objects:
    updateAllChannelUsersforSend = function(cl)
      print("udpate channelusers")
      local ch = cl:getChannel(fgcom.channel)
      local users = ch:getUsers()
      playback_targets = {}
      print("ok: "..ch:getName())
      for k,v in pairs(users) do
          print("  k="..tostring(k).."v="..tostring(v))
          table.insert(playback_targets, v)
      end
    end
  • I have a function defined to send specific plugin data to that list:
    notifyUserdata = function(tgts)
      local msg = "CALLSIGN="..fgcom.callsign
      fgcom.dbg("Bot sets userdata: "..msg)
      client:sendPluginData("FGCOM:UPD_USR:0", msg, tgts)
    end

When invoking it, I get the error.
When inspecting using inspect module after the call to updateAllChannelUsersforSend , it prints indeed the populated table:

    updateAllChannelUsersforSend(client)
local inspect = require('inspect')
print(inspect(playback_targets));
    notifyUserdata(playback_targets)
udpate channelusers
ok: fgcom-mumble
  k=73v=mumble.user [73][D-EBHX]
  k=75v=mumble.user [75][FGCOM-Recorder]
  k=74v=mumble.user [74][FGCOM-Status]
{ <userdata 1>, <userdata 2>, <userdata 3> }
test/fgcom-fakepilot.bot.lua:194: bad argument #3 to 'sendPluginData' (mumble.user expected, got table)

Question: timers and access to shared variable - lock needed?

Hi, I have a question regarding threads safety in lua-mumble timers.

โ“ What happens, if at the same time the hook adds/reads data, and the timer nils that table?
Will this work (because the reference to the table inside the timer is still valid), or do I need some sort of locking (if so, what exactly?)

Given I have a complex sharedTable table:

sharedTable = {
  1 = {
    name:"somename",
    lastUpdate:12345
  },
  2 = {...},
  ...
}

In the hook OnPluginData I add and manipulate entries to that table.

I want to regularly clean out entries not updated for a prolonged time and maintain the lastUpdate timestamp for that.
I also have a mumble.timer iterating over that table each 60 seconds. It will set stale entries to sharedTable[userID] = nil so they are deleted from the table.

Timer counter

After removing mumble.sleep and client:update functions how can I now make timer event to build some needed stuff? Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.