# FFlag API

The fflag API gives scripts direct read and write access to Roblox's Fast Flag (FFlag) system. A background thread scans the game's memory for all registered FFlags and caches their names, addresses, and values. The Lua API reads and writes through that cache with no render-thread cost.

> All examples use `snake_case`. Every function is also accessible in `camelCase` and `PascalCase` — the engine accepts all three.

***

### How it works

The fflag system runs on a dedicated worker thread:

* **FFlags** are discovered by pattern scanning the Roblox binary for flag registration stubs. Each stub contains a pointer to the flag's DWORD value and a string pointer to its name.
* **Deduplication** removes flags that appear at multiple addresses, preferring the one inside the main module over heap copies.
* **A watch loop** polls flag values every 100ms and publishes updated snapshots via a lock-free shared pointer, so Lua reads are always safe and never block.

`fflag.is_scanned()` returns `false` while the initial scan is still running. All read functions return `nil` or empty tables until the scan completes.

***

### fflag.is\_scanned

```lua
local ready = fflag.is_scanned()
```

Returns `true` once the fflag cache has completed its initial pattern scan. Use this as a guard before accessing flags.

```lua
function on_frame()
    if not fflag.is_scanned() then
        draw.text(10, 10, "scanning fflags...", {1, 1, 0, 1})
        return
    end
    draw.text(10, 10, "flags loaded: " .. fflag.get_count(), {0, 1, 0, 1})
end
```

***

### fflag.get\_count

```lua
local count = fflag.get_count()
```

Returns the total number of FFlags currently cached. Typically around 6000–7000 depending on the Roblox version.

***

### fflag.get\_value

```lua
local value = fflag.get_value(flag_name)
```

Returns the current integer value of a flag by its exact name, or `nil` if the flag was not found.

Parameter: the full flag name as a string. Names are case-sensitive and must match exactly as they appear in Roblox's internal registry.

Returns `nil` if the flag does not exist or the cache is not yet scanned.

```lua
local fps_cap = fflag.get_value("TaskSchedulerTargetFps")
if fps_cap then
    print("current fps cap: " .. fps_cap)
end
```

***

### fflag.set\_value

```lua
local success = fflag.set_value(flag_name, value)
```

Writes a new integer value to a flag. Returns `true` if the flag was found and written, `false` otherwise.

The write goes directly to the flag's memory address in the Roblox process. The change takes effect immediately.

```lua
-- unlock fps
fflag.set_value("TaskSchedulerTargetFps", 9999)

-- enable debug fps display
fflag.set_value("DebugDisplayFPS", 1)
```

***

### fflag.reset\_value

```lua
local success = fflag.reset_value(flag_name)
```

Resets a single flag to its original value (the value it had when first scanned). Returns `true` if the flag was found and reset, `false` otherwise.

```lua
fflag.set_value("TaskSchedulerTargetFps", 9999)
-- later...
fflag.reset_value("TaskSchedulerTargetFps")
```

***

### fflag.reset\_all

```lua
fflag.reset_all()
```

Resets all modified flags back to their original values. Takes no arguments and returns nothing. Useful for cleanup when unloading a script.

***

### fflag.find

```lua
local results = fflag.find(pattern)
```

Searches all cached flags for names containing the given substring. The search is case-insensitive. Returns a table of matching flags, each with the following fields:

* `name` — the full flag name (string)
* `value` — current integer value (number)
* `original` — the value when first scanned (number)
* `changed` — whether the value differs from the original (boolean)
* `index` — the flag's position in the cache (number)

```lua
local physics_flags = fflag.find("physics")
for _, flag in ipairs(physics_flags) do
    local status = flag.changed and " [MODIFIED]" or ""
    print(flag.name .. " = " .. flag.value .. status)
end
```

***

### fflag.get\_all

```lua
local all = fflag.get_all()
```

Returns a table containing every cached flag. Each entry has the same fields as `fflag.find` plus an `address` field containing the flag's memory address. This can return a large table (6000+ entries). Prefer `fflag.find()` for targeted lookups.

```lua
local all = fflag.get_all()
local modified = 0
for _, flag in ipairs(all) do
    if flag.changed then
        modified = modified + 1
        print(flag.name .. ": " .. flag.original .. " -> " .. flag.value)
    end
end
print("total modified: " .. modified)
```

***

### Examples

FPS unlocker — set the task scheduler target every frame in case the game resets it:

```lua
function on_frame()
    if not fflag.is_scanned() then return end

    local current = fflag.get_value("TaskSchedulerTargetFps")
    if current and current ~= 9999 then
        fflag.set_value("TaskSchedulerTargetFps", 9999)
        print("fps unlocked")
    end
end
```

Search and display flags on screen:

```lua
function on_frame()
    if not fflag.is_scanned() then return end

    local render_flags = fflag.find("render")
    local y = 30

    draw.text(10, 10, "Render Flags: " .. #render_flags, {1, 1, 1, 1})

    for i, flag in ipairs(render_flags) do
        if i > 15 then break end
        local color = flag.changed and {1, 0.5, 0, 1} or {0.7, 0.7, 0.7, 1}
        draw.text(10, y, flag.name .. " = " .. flag.value, color)
        y = y + 16
    end
end
```

Bulk modification with cleanup on script unload:

```lua
local modified_flags = {}

function apply_tweaks()
    local tweaks = {
        {"TaskSchedulerTargetFps", 9999},
        {"DebugDisplayFPS", 1},
    }

    for _, tweak in ipairs(tweaks) do
        local name, value = tweak[1], tweak[2]
        local old = fflag.get_value(name)
        if old then
            fflag.set_value(name, value)
            table.insert(modified_flags, name)
            print("set " .. name .. ": " .. old .. " -> " .. value)
        end
    end
end

function cleanup()
    for _, name in ipairs(modified_flags) do
        fflag.reset_value(name)
    end
    modified_flags = {}
    print("all tweaks reverted")
end

function on_frame()
    if not fflag.is_scanned() then return end
    if #modified_flags == 0 then
        apply_tweaks()
    end
end
```

Monitor all modified flags in real time:

```lua
local last_check = 0

function on_frame()
    if not fflag.is_scanned() then return end

    local now = utility.get_time()
    if now - last_check < 1.0 then return end
    last_check = now

    local all = fflag.get_all()
    local changed = {}
    for _, flag in ipairs(all) do
        if flag.changed then
            table.insert(changed, flag)
        end
    end

    if #changed > 0 then
        draw.text(10, 10, "Modified Flags: " .. #changed, {1, 0.5, 0, 1})
        local y = 30
        for _, flag in ipairs(changed) do
            draw.text(10, y, flag.name .. ": " .. flag.original .. " -> " .. flag.value, {1, 0.8, 0.3, 1})
            y = y + 16
        end
    end
end
```

***

### Performance notes

* All read functions (`get_value`, `find`, `get_all`) read from an atomic shared pointer snapshot. They never block the render thread or the fflag worker thread.
* `set_value` and `reset_value` perform a single memory write to the Roblox process per call. They are safe to call every frame but there is no benefit to doing so since the value persists until changed.
* The watch loop detects external changes to flag values every 100ms. If the game resets a flag you modified, you will see the change reflected in the next snapshot.
* Flag values are 32-bit integers (DWORD). Flags that appear as booleans in Roblox use `0` for false and `1` for true.
* The flag cache rebuilds when the game teleports to a new place. Modified values are not preserved across teleports.
* `get_all` returns a large table. Avoid calling it every frame. Use `find` for targeted lookups or cache results in a local variable.

***

### API Reference

| Function                       | Description                                 |
| ------------------------------ | ------------------------------------------- |
| `fflag.is_scanned()`           | Returns `true` when the flag cache is ready |
| `fflag.get_count()`            | Returns total number of cached flags        |
| `fflag.get_value(name)`        | Read a flag's current value by name         |
| `fflag.set_value(name, value)` | Write a new integer value to a flag         |
| `fflag.reset_value(name)`      | Reset a flag to its original value          |
| `fflag.reset_all()`            | Reset all flags to original values          |
| `fflag.find(pattern)`          | Case-insensitive substring search           |
| `fflag.get_all()`              | Get all flags as a table                    |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://project-vector-1.gitbook.io/vector-lua-engine/api/fflag-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
