Solution for Lua intellisense and auto-complete

This is the solution that I have found to provide add intellisense to my IDE (Rider and other Intellij-Based IDEs)
Install Emmy-Lua plugin: EmmyLua · GitHub
Create a lua file somewhere in project folder. Doesn’t have to be where you put your modules.
Then, use lua docs to create Nakama classes:

---@class Account
---@field public metadata table
---@field public username string
---@field public display_name string
---@field public timezone string
---@field public location string
---@field public language string
---@field public avatar_url string
local account = {}

---@class Nakama
local nk = {}

---Get all account information for a given user ID.
---@param id string User ID to fetch information for. Must be valid UUID.
---@return Account All account information including wallet, device IDs and more.
function nk.account_get_id(id)
end

This was an example. You need to add all functions of nakama in the file.

Then in your modules, you need to write this:

---@type Nakama
local nk = require("nakama")

And everything will be set. You now can use auto-complete features for Nakama.

1 Like

Thanks for sharing this one @xnnnk. Do you think you can add to this with some of the steps you ran to generate the Lua docs and we could start to package this file in a way that’s convenient for most developers?

I did not “generate” the lua doc. I wrote them manually because I didn’t want to spend 8 hours coding a generator to automate a 1 hour manual task. But it can be done.

I’m going to post what I wrote. I didn’t cover all of the API because I didn’t need them. The file name is “nakama.lua”. This way EmmyLua automatically detects it as a module.

Here is my folder structure:

Server
-- data
---- modules
------ game.lua
------ ...
-- nakama.lua
-- config.yml
-- start_server.bat (starts server with config file)

You need to open “Server” folder in your IDE. This way, both “nakama.lua” and your module files are included in IDE project.

Here is the nakama.lua file:

---@class Account
---@field public metadata table
---@field public wallet table
---@field public username string
---@field public display_name string
---@field public timezone string
---@field public location string
---@field public language string
---@field public avatar_url string
local account = {}

---@class CollectionObject
---@field public collection string
---@field public key string
---@field public user_id string
---@field public value table
---@field public version string
---@field public permission_read number
---@field public permission_write number
local collection_object = {}

---@class Context
---@field env table A table of key/value pairs which are defined in the YAML configuration of the server. This is useful to store API keys and other secrets which may be different between servers run in production and in development.
---@field execution_mode string The mode associated with the execution context. It's one of these values: "run_once", "rpc", "before", "after", "match", "matchmaker", "leaderboard_reset", "tournament_reset", "tournament_end".
---@field query_params table Query params that was passed through from HTTP request.
---@field session_id string The user session associated with the execution context.
---@field user_id string The user ID associated with the execution context.
---@field username string The username associated with the execution context.
---@field user_session_exp number The user session expiry in seconds associated with the execution context.
---@field client_ip string The IP address of the client making the request.
---@field client_port string The port number of the client making the request.
---@field match_id string The match ID that is currently being executed. Only applicable to server authoritative multiplayer.
---@field match_node string The node ID that the match is being executed on. Only applicable to server authoritative multiplayer.
---@field match_label string Labels associated with the match. Only applicable to server authoritative multiplayer.
---@field match_tick_rate number Tick rate defined for this match. Only applicable to server authoritative multiplayer.
local context = {}

---@class Presence
---@field user_id string
---@field session_id string
---@field username string
---@field node string
local presence = {}

---@class GameMessage
---@field sender Presence
---@field op_code number
---@field data string
local game_message = {}

---@class Dispatcher
local dispatcher = {}

---Send a message to one or more presences.
---This may be called at any point in the match loop to give match participants information about match state changes. May also be useful inside the match join callback to send initial state to the user on successful join.
---@param op_code number Numeric message op code.
---@param data string Data payload string, or nil.
---@param presences Presence[] List of presences (a subset of match participants) to use as message targets, or nil to send to the whole match.
---@param sender Presence A presence to tag on the message as the 'sender', or nil.
function dispatcher.broadcast_message(op_code, data, presences, sender)
end

---Removes participants from the match.
---Call at any point during the match loop to remove participants based on misbehaviour or other game-specific rules.
---@param presences Presence
function dispatcher.match_kick(presences)
end

---Sets a new label for the match.
---@param label string
function dispatcher.match_label_update(label)
end


---@class MessageNames
local message_names = {
    -- TODO
    ---Add friends by ID or username to a user's account.
    AddFriends = "AddFriends"
}

---@module nakama
---@alias nk
local nk = {}

---Get all account information for a given user ID.
---@param id string User ID to fetch information for. Must be valid UUID.
---@return Account All account information including wallet, device IDs and more.
function nk.account_get_id(id)
end

---@param user_id string User ID for which the information is to be updated. Must be valid UUID.
---@param metadata table Metadata to update. Use nil if it is not being updated.
---@param username string Username to be set. Must be unique. Use "" (Go) or nil (Lua) if it is not being updated.
---@param display_name string Display name to be updated. Use "" (Go) or nil (Lua) if it is not being updated.
---@param timezone string Timezone to be updated. Use "" (Go) or nil (Lua) if it is not being updated.
---@param location string Location to be updated. Use "" (Go) or nil (Lua) if it is not being updated.
---@param language string Lang tag to be updated. Use "" (Go) or nil (Lua) if it is not being updated.
---@param avatar_url string User's avatar URL. Use "" (Go) or nil (Lua) if it is not being updated.
function nk.account_update_id(user_id, metadata, username,
                              display_name, timezone, location,
                              language, avatar_url)
end

---@param input string The string which has been aes128 encrypted.
---@param key string 16 bytes decryption key.
function nk.aes128_decrypt(input, key)
end

---@param input string The string which will be aes128 encrypted.
---@param key string 16 bytes encryption key.
function nk.nk.aes128_encrypt(input, key)
end

---@param id string Custom ID to use to authenticate the user. Must be between 6-128 characters.
---@param username string Optional username. If left empty, one is generated.
---@param create boolean Create user if one didn't exist previously. By default this is set to true.
---@return (string, string, boolean) The user's ID, username, and a boolean flag indicating if the account was just created (true) or already existed (false).
function nk.authenticate_custom(id, username, create)

end

---@param id string Device ID to use to authenticate the user. Must be between 6-128 characters.
---@param username string Optional username. If left empty, one is generated.
---@param create boolean Create user if one didn't exist previously. By default this is set to true.
---@return (string, string, boolean) The user's ID, username, and a boolean flag indicating if the account was just created (true) or already existed (false).
function nk.authenticate_device(id, username, create)

end

---@param email string Email address to use to authenticate the user. Must be between 10-255 characters.
---@param password string Password to set - must be longer than 8 characters.
---@param username string Optional username. If left empty, one is generated.
---@param create boolean Create user if one didn't exist previously. By default this is set to true.
---@return (string, string, boolean) The user's ID, username, and a boolean flag indicating if the account was just created (true) or already existed (false).
function nk.authenticate_device(email, password, username, create)

end

---@param token string Facebook OAuth access token.
---@param import boolean    Whether to import facebook friends after authenticated automatically. This is true by default.
---@param username string Optional username. If left empty, one is generated.
---@param create boolean Create user if one didn't exist previously. By default this is set to true.
---@return (string, string, boolean) The user's ID, username, and a boolean flag indicating if the account was just created (true) or already existed (false).
function nk.authenticate_facebook(token, import, username, create)

end

---@param token string
---@param username string
---@param create boolean Create user if one didn't exist previously. By default this is set to true.
---@return (string, string, boolean) The user's ID, username, and a boolean flag indicating if the account was just created (true) or already existed (false).
function nk.authenticate_google(token, username, create)
end

---Decode the JSON input as a Lua table.
---@param input string The JSON encoded input.
---@return table A Lua table with the decoded JSON.
function nk.json_decode(input)
end

---Encode the input as JSON.
---@param input table The input to encode as JSON.
---@return string The encoded JSON string.
function nk.json_encode(input)
end

---Setup a new dynamic leaderboard with the specified ID and various configuration settings. The leaderboard will be created if it doesn't already exist, otherwise its configuration will not be updated.
---@param id string The unique identifier for the new leaderboard. This is used by clients to submit scores.
---@param authoritative boolean Mark the leaderboard as authoritative which ensures updates can only be made via the Lua runtime. No client can submit a score directly. Optional in Lua. Default false.
---@param sort string The sort order for records in the leaderboard; possible values are "asc" or "desc". Optional in Lua. Default "desc".
---@param operator string The operator that determines how scores behave when submitted; possible values are "best", "set", or "incr". Optional in Lua. Default "best".
---@param reset string The cron format used to define the reset schedule for the leaderboard. This controls when a leaderboard is reset and can be used to power daily/weekly/monthly leaderboards. Optional in Lua.
---@param metadata table The metadata you want associated to the leaderboard. Some good examples are weather conditions for a racing game. Optional in Lua.
function nk.leaderboard_create(id, authoritative, sort, operator, reset, metadata)
end

---Delete a leaderboard and all scores that belong to it.
---@param id string The unique identifier for the leaderboard to delete. Mandatory field.
function nk.leaderboard_delete(id)
end

---Use the preconfigured operator for the given leaderboard to submit a score for a particular user.
---@param id string The unique identifier for the leaderboard to submit to. Mandatory field.
---@param owner string The owner of this score submission. Mandatory field.
---@param username string The owner username of this score submission, if it's a user. Optional in Lua.
---@param score number    The score to submit. Optional in Lua. Default 0.
---@param subscore number A secondary subscore parameter for the submission. Optional in Lua. Default 0.
---@param metadata table The metadata you want associated to this submission. Some good examples are weather conditions for a racing game. Optional in Lua.
function nk.leaderboard_record_write(id, owner, username, score, subscore, metadata)
end

---@param message string
function nk.logger_error(message)
end

---@param message string
function nk.logger_info(message)
end

---@param message string
function nk.logger_warn(message)
end

---Create a new authoritative realtime multiplayer match running on the given runtime module name. The given params are passed to the match's init hook.
---@param module string The name of an available runtime module that will be responsible for the match. In Go, this was registered in InitModule. In Lua, this was provided as an independent match handler module.
---@param params table Any value to pass to the match's init hook. Optional in Lua.
---@return string The match ID of the newly created match. Clients can immediately use this ID to join the match.
function nk.match_create(module, params)
end

---List currently running realtime multiplayer matches and optionally filter them by authoritative mode, label, and current participant count.
---@param limit number The maximum number of matches to list. Optional in Lua. Default 1.
---@param authoritative boolean Boolean true if listing should only return authoritative matches, false to only return relayed matches, nil to return both. Optional in Lua. Default false (Go) or nil (Lua).
---@param label string A label to filter authoritative matches by. Optional in Lua. Default "" (Go) or nil (Lua) meaning any label matches.
---@param min_size number Inclusive lower limit of current match participants. Optional in Lua.
---@param max_size number Inclusive upper limit of current match participants. Optional in Lua.
---@param query string Additional query parameters to shortlist matches
function nk.match_list(limit, authoritative, label, min_size, max_size, query)

end

---Registers a function that will be called when matchmaking finds opponents.
---@param func function A function reference which will be executed on each matchmake completion.
function nk.register_matchmaker_matched(func)

end

---Register a function with the server which will be executed after every non-realtime message 
---as specified while registering the function. 
---This can be used to apply custom logic to standard features in the server. It will not block the execution pipeline. 
---The logic will be executed in parallel to any response message sent back to a client.
---@param func function
---@param message_name string
function nk.register_req_after(func, message_name)
end

---Register a function with the server which will be executed before any non-realtime message with the specified message name. 
---This can be used to apply custom conditions to standard features in the server. The function should pass the payload 
---input back as a return argument so the pipeline can continue to execute the standard logic. 
---If you return nil, the server will stop processing that message. Any other return argument will result in an error.
---@param func function
---@param message_name string
function nk.register_req_before(func, message_name)
end

---Registers a function for use with client RPC to the server. 
---The ID can be any string identifier and is sent by the client. 
---The ID is used to map the client RPC message to the specific function to execute. 
---This function can also be used to register a HTTP endpoint within the server.
---@param func function A function reference which will be executed on each RPC message.
---@param id string The unique identifier used to register the func function for RPC.
function nk.register_rpc(func, id)
end

---The runtime environment allows you to run code that must only be executed only once. 
---This is useful if you have custom SQL queries that you need to perform (like creating a new table) 
---or to register with third party services.
---@param func function A function reference which will be executed only once.
function nk.run_once(func)
end

---Fetch one or more records by their bucket/collection/keyname and optional user.
---@param object_ids CollectionObject[] A table / array of object identifiers to be fetched.
---@return CollectionObject[]
function nk.storage_read(object_ids)
end

---You can list records in a collection and page through results. 
---The records returned can be filtered to those owned by the user or "" for public records which aren't owned by a user.
---@param user_id string User ID or "" (empty string) for public records.
---@param collection string Collection to list data from.
---@param limit number Limit number of records retrieved. Min 10, Max 100.
---@param cursor string Pagination cursor from previous result. If none available set to nil or "" (empty string).
---@return table
function nk.storage_list(user_id, collection, limit, cursor)

end

---Remove one or more objects by their collection/keyname and optional user.
---@param object_ids CollectionObject[] A table / array of object identifiers to delete
function nk.storage_delete(object_ids)
end

---Write one or more objects by their collection/keyname and optional user.
---@param object_ids CollectionObject[] A table / array of object identifiers to be written.
---@return CollectionObject[]
function nk.storage_write(object_ids)
end

---Execute an arbitrary SQL query and return the number of rows affected. Typically an INSERT, DELETE, or UPDATE statement with no return columns.
---@param query string A SQL query to execute.
---@param parameters table Arbitrary parameters to pass to placeholders in the query.
---@return number A single number indicating the number of rows affected by the query.
function nk.sql_exec(query, parameters)
end

---Execute an arbitrary SQL query that is expected to return row data. Typically a SELECT
---@param query string A SQL query to execute.
---@param parameters table Arbitrary parameters to pass to placeholders in the query.
---@return table[] A Lua table containing the result rows in the format: { {column1 = "value1", column2 = "value2", ...}, {column1 = "value1", column2 = "value2", ...},  ...}
function nk.sql_query(query, parameters)
end

---Update a user's wallet with the given changeset.
---@param user_id string The ID of the user to update the wallet for.
---@param changeset table The set of wallet operations to apply.
---@param metadata table Additional metadata to tag the wallet update with. Optional in Lua.
---@param update_ledger boolean Whether to record this update in the ledger. Default true. Optional in Lua.
function nk.wallet_update(user_id, changeset, metadata, update_ledger)
end
2 Likes

Im aiming to use this thing, but some of the lines have errors or shows errors on this.

Does the plugin has been changed or something? Did someone else used this?

Hey @KittySkin what errors are you getting in your IDE?

The errors are on the file, it shows errors with @module like its wrongly declared, from what I readed its because lua server containing lua doc inside of it.
Im using visual studio code for this.

Do you think its possible complete this documentation and add it as part of the lua setup steps?

Im completing it right now so once I have added all nakama functionalities ill upload it here again, If I miss something, please let me know.

@KittySkin you are welcome to submit a PR with any type annotations and the steps required to use them in VS Code. You can upload them here too. We don’t provide out-of-the-box type support for Lua in your IDE but would love your help in adding it.

Alternatively, if generated the type annotations is a problem, you can always use Typescript or Go.

Here is the full code, ill fill the PR later. Important to notice is that this is not exclusive to VS Code, if EmmyLua its available for an IDE, then this works.

How to use this? Place nakama.lua on the folder project. Make 100% sure that said file NEVER ends up on the server since that could lead to server failures.
Use EmmyLua plugin for your desired IDE and it should now work as expected, returning full intellisense for Nakama specific functions and other stuff.

nakama.lua (73.7 KB)

Sorry to upload the file, but its WAY larger than the max characters admited by the forums. If you or someone can actually make the commit instead, Ill be glad since im full hands on with my work haha

Thank you @KittySkin for this fantastic contribution!

1 Like

Hey, im with time to do the PR now. The thing is, where exactly do I place it? The nakama.lua file would break the nakama server if uploaded into the modules folder, so its an absolute no there.
Do you guys have a place to submit documentation changes? The added steps should be placed here

Hey @KittySkin we’ll discuss the best approach internally. Thank you.

1 Like

Yeay! Thx for letting me know @lugehorsam ! glad to help, ping me once this is ready so I can contribute there future intellisense updates.

Im adding now information on expected param format for stuff like storage_write or read that uses tables as input data.

Once that its ready and if you guys have it available at github, ill be more than happy to PR improvements :slight_smile:

1 Like

Hello, quick update. I added optional parameters handling and some template code for storage write and read options.
Feel free to use this new version, its built upon Lua Server EmmyLua implementation and its also compatible with any EmmyLua version for any IDE too.
nakama.lua (74.0 KB)

1 Like

Started a new topic mainly to keep this updated and to being able to edit the OP in order to keep it better updated and tracked.

Nakama Lua Intellisense Implementation - Heroic Labs

Also last versiion fix a parameter handling error. Feel free to use that one :slight_smile:

Thanks @KittySkin - closing this topic in favor of your new one.