Violet

Login

On this page

Use core.login from on_tick(stage) while stage == core.stage.LOGIN to inspect the login flow and manage characters from the character-selection screen.

Character actions are live

Reordering, deletion, and restoration affect the account's character list. A true result means the action was submitted, not that it has completed. Re-read the character list before sending another action.

Login Steps

StepMeaning
1World and channel selection
2Character selection
3New-character setup
4New-character name entry

Other values may appear during transitions.

Character Structure

get_characters() returns one record per created character:

PropertyTypeDescription
idnumberStable character ID
indexnumberZero-based display position
namestringCharacter name
levelnumberCharacter level
jobnumberJob ID
ghostbooleanWhether deletion is pending
delete_deadlinenumberDeletion eligibility time as a Unix timestamp, or 0
deletion_readybooleanWhether permanent deletion is currently eligible

Character actions accept a returned character record, a character ID, or a zero-based display index. Prefer passing the complete record; numeric values are resolved as IDs first and then as indices.

Functions

core.login.get_step() -> number | nil

Available on GMS and CW

Returns the current login step, or nil when the login interface is unavailable.


core.login.get_char_count() -> number | nil

Available on GMS and CW

Returns the number of created characters during character selection.


core.login.get_total_slot_count() -> number | nil

Available on GMS and CW

Returns the account's total available character slots during character selection.


core.login.get_empty_slot_count() -> number | nil

Available on GMS and CW

Returns the number of unoccupied character slots during character selection.


core.login.get_characters() -> table<login_character> | nil

Available on GMS and CW

Returns the current character list during character selection.


core.login.move_character_to_front(character: login_character | number) -> boolean

Available on GMS and CW

Moves the selected character to the front of the displayed character order.


core.login.soft_delete_character(character: login_character | number) -> boolean

Available on GMS

Starts the deletion waiting period for an active character that is not already pending deletion.


core.login.hard_delete_character(character: login_character | number) -> boolean

Available on GMS and CW

Permanently deletes a character whose deletion waiting period has completed.


core.login.restore_character(character: login_character | number) -> boolean

Available on GMS and CW

Restores a character that is pending deletion.

lua
function on_tick(stage)
    if stage ~= core.stage.LOGIN then return end

    if core.login.get_step() ~= 2 then
        return
    end

    for _, character in ipairs(core.login.get_characters() or {}) do
        if character.ghost and not character.deletion_ready then
            core.login.restore_character(character)
            break
        end
    end
end

core.login.get_hold() -> table | nil

Available on GMS and CW

Returns why Auto Login is currently parked, or nil when nothing is holding it back. Usable from any stage — a hold armed in the field is visible before the logout lands.

PropertyTypeDescription
reasonstring"gm_evade" after Evade Potential GM fires, or "stay_logged_out" during the Stay Logged Out wait
remaining_secnumberSeconds until the hold expires on its own

core.login.clear_hold() -> boolean

Available on GMS and CW

Releases every Auto Login hold so the next login tick logs back in — the same effect as re-ticking Auto Login in the menu. Returns false only when the autos module is unavailable.

The GM hold follows the character

Evade Potential GM is per character, not per account: the 6-hour hold keeps the character that triggered it offline. Logging into a different character is fine — switch profile first, then release the hold, as in the example below. Releasing it without switching logs the same character straight back in.

Example: rotate characters after a GM evade

Each saved profile points Auto Login at a different character slot. When Evade Potential GM fires, switch to the next profile, wait for it to become active, then release the hold so Auto Login logs into that profile's character instead of waiting six hours.

lua
plugin = {
    name        = "GM Rotate",
    version     = "1.0.0",
    author      = "you",
    description = "Switch profile and log into the next character after a GM evade",
    load        = true,
}

-- Profiles that differ only in autos.auto_login.char_index
local ROTATION = { "Farm A", "Farm B", "Farm C" }
local pending  -- profile we are waiting on before releasing the hold

local function next_profile()
    local active = core.profiles.get_active()
    for i, name in ipairs(ROTATION) do
        if active and active.name == name then
            return ROTATION[i % #ROTATION + 1]
        end
    end
    return ROTATION[1]
end

function on_gm_evasion()
    pending = next_profile()
    if core.profiles.switch(pending) then
        core.log_warning("GM evade: switching to " .. pending)
    else
        core.log_error("GM evade: could not switch to " .. pending .. ", staying logged out")
        pending = nil
    end
end

function on_tick(stage)
    if not pending then return end

    -- Profile switches apply asynchronously; release the hold only once the
    -- new profile (and its Auto Login slot) is actually live.
    local active = core.profiles.get_active()
    if active and active.name == pending then
        core.login.clear_hold()
        core.log_warning("GM evade: " .. pending .. " is active, Auto Login released")
        pending = nil
    end
end