Skip to main content

Api Test

Download the complete project ZIP. Preserve the directory structure, including any helper modules. These examples require the live Traceless client; they are not standalone Lua programs.

Individual source downloads:

main.lua​

local traceless = require("traceless")
local helper = require("traceless_api_test.helper")
local ffi = require("ffi")
local bit = require("bit")

local results = {}
local order = {}
local callbacks = {
paint = 0,
paint_ui = 0,
setup = 0,
predict_command = 0,
prediction = 0,
override_view = 0,
player_hurt = 0,
round_start = 0,
aim_fire = 0,
aim_hit = 0,
aim_miss = 0,
timer = 0,
console_input = 0,
ui = 0
}

local render_resources = {
checked = false,
font = nil,
rgba = nil,
png = nil,
jpg = nil
}

local function detail(value)
local text = tostring(value or "ok"):gsub("[\r\n]+", " ")
return #text > 140 and text:sub(1, 137) .. "..." or text
end

local function record(name, passed, message)
if results[name] == nil then
order[#order + 1] = name
end
results[name] = {
passed = passed,
message = detail(message)
}
if not passed then
traceless.console.error("[API test] " .. name .. ": " .. results[name].message)
end
end

local function test(name, callback)
local ok, passed, message = pcall(callback)
if not ok then
record(name, false, passed)
else
record(name, passed == true, message or (passed and "ok" or "failed"))
end
end

local function surface(name, object, functions)
test("surface." .. name, function()
if type(object) ~= "table" and type(object) ~= "function" then
return false, "got " .. type(object)
end
if type(object) == "function" then
return true, "constructor"
end
for index = 1, #functions do
if type(object[functions[index]]) ~= "function" then
return false, "missing " .. functions[index]
end
end
return true, #functions .. " functions"
end)
end

surface("console", traceless.console, {"info", "color", "error", "execute"})
surface("notify", traceless.notify, {"info", "color", "error"})
surface("events", traceless.events, {"on", "off"})
surface("timer", traceless.timer, {"after"})
surface("engine", traceless.engine, {
"camera_angles", "camera_position", "eye_position", "latency", "screen_size",
"timestamp", "system_time", "unix_time", "random_int", "random_float",
"reload_scripts", "absolute_frame_time", "current_time", "frame_count",
"frame_time", "max_players", "real_time", "tick_count", "tick_interval"
})
surface("input", traceless.input, {"key_down"})
surface("cvars", traceless.cvars, {})
surface("players", traceless.players, {"local_controller", "local_pawn", "from_userid", "all"})
surface("entities", traceless.entities, {"from_index", "from_handle", "all"})
surface("schema", traceless.schema, {"read"})
surface("prediction", traceless.prediction, {"local_state", "ticks"})
surface("trace", traceless.trace, {"line", "hull", "visibility", "penetration"})
surface("weapons", traceless.weapons, {"active"})
surface("render", traceless.render, {
"circle", "circle_outline", "gradient", "indicator", "line", "load_jpg", "load_png",
"load_rgba", "measure_text", "create_font", "font_text", "font_measure_text",
"rectangle", "text", "texture", "triangle", "world_to_screen"
})
surface("materials", traceless.materials, {
"find_material", "find_materials"
})
surface("panorama", traceless.panorama, {"loadstring", "open"})
surface("ui", traceless.ui, {
"get", "get_raw", "set", "set_callback", "set_visible", "update", "reference",
"new_button", "new_checkbox", "new_color_picker", "new_combobox", "new_hotkey",
"new_label", "new_listbox", "new_multiselect", "new_slider", "new_string",
"new_textbox", "is_menu_open", "menu_position", "menu_size", "mouse_position", "name"
})
surface("storage", traceless.storage, {"read", "write"})
surface("json", traceless.json, {
"decode_invalid_numbers", "decode_max_depth", "encode_invalid_numbers",
"encode_keep_buffer", "encode_max_depth", "encode_number_precision",
"encode_sparse_array", "parse", "stringify"
})
surface("unsafe", traceless.unsafe, {"create_interface", "find_signature", "schema_write"})
surface("vector", traceless.vector, {})
surface("angle", traceless.angle, {})
surface("ffi", ffi, {"cdef", "cast", "typeof", "new"})
surface("bit", bit, {"band", "bor", "bxor", "bnot", "lshift", "rshift"})

test("require.traceless.identity", function()
return require("traceless") == traceless
end)

test("require.project_module", function()
local packed = helper.pack("one", nil, "three")
return packed.n == 3 and packed[1] == "one" and packed[2] == nil and packed[3] == "three"
end)

test("ffi.runtime", function()
local value = ffi.new("int", 7)
local cast = ffi.cast("int", value)
return tonumber(cast) == 7 and tostring(ffi.typeof("int")):find("int") ~= nil
end)

test("bit.operations", function()
return bit.band(0xF0, 0x0F) == 0
and bit.bor(0x10, 0x01) == 0x11
and bit.bxor(0xFF, 0x0F) == 0xF0
end)

test("vector.operations", function()
local first = traceless.vector(1, 2, 3)
local second = traceless.vector(3, 2, 1)
local sum = first + second
local normalized = first:normalized()
local right, up = normalized:vectors()
return sum.x == 4 and sum.y == 4 and sum.z == 4
and helper.approx(first:length(), math.sqrt(14))
and helper.approx(normalized:length(), 1)
and right ~= nil and up ~= nil
and first:dist(second) > 0
end)

test("json.round_trip", function()
local encoded = traceless.json.stringify({value = 7, enabled = true})
local decoded = traceless.json.parse(encoded)
return decoded.value == 7 and decoded.enabled == true
end)

test("json.null", function()
return traceless.json.parse("null") == traceless.json.null
end)

test("engine.values", function()
local width, height = traceless.engine.screen_size()
return type(width) == "number" and type(height) == "number"
and traceless.engine.random_int(4, 4) == 4
and traceless.engine.random_float(1, 1) == 1
and traceless.engine.tick_interval() >= 0
end)

test("storage.round_trip", function()
traceless.storage.write("api_test", {version = 1, value = "local"})
local value = traceless.storage.read("api_test")
return value ~= nil and value.version == 1 and value.value == "local"
end)

local controls = {}
controls.show = traceless.ui.new_checkbox("LUA", "API test", "Show report", true)
controls.mode = traceless.ui.new_combobox(
"LUA", "API test", "Mode", "first", "second")
controls.multi = traceless.ui.new_multiselect(
"LUA", "API test", "Options", "one", "two", "three")
controls.list = traceless.ui.new_listbox(
"LUA", "API test", "List", {"zero", "one", "two"})
controls.slider = traceless.ui.new_slider("LUA", "API test", "Value", 0, 10, 4)
controls.hotkey = traceless.ui.new_hotkey("LUA", "API test", "Hotkey", false, -1)
controls.color = traceless.ui.new_color_picker("LUA", "API test", "Color", 80, 180, 255, 255)
controls.textbox = traceless.ui.new_textbox("LUA", "API test", "Text", "initial")
controls.hidden = traceless.ui.new_string("api_test_hidden", "initial")
controls.label = traceless.ui.new_label("LUA", "API test", "UI controls are ready")

local ui_callback_registered = pcall(function()
traceless.ui.set_callback(controls.textbox, function()
callbacks.ui = (callbacks.ui or 0) + 1
end)
end)

controls.run_penetration = traceless.ui.new_button("LUA", "API test", "Run trace and penetration", function()
local pawn = traceless.players.local_pawn()
if pawn == nil then
record("trace.penetration.state", false, "local pawn unavailable")
return
end
local eye = pawn:eye_position()
if eye == nil then
record("trace.penetration.state", false, "eye position unavailable")
return
end
local destination = eye + traceless.vector(256, 0, 0)
local line = traceless.trace.line({from = eye, to = destination, skip = pawn})
local hull = traceless.trace.hull({
from = eye,
to = destination,
mins = traceless.vector(-2, -2, -2),
maxs = traceless.vector(2, 2, 2),
skip = pawn
})
local visible, visibility = traceless.trace.visibility({from = eye, to = destination, skip = pawn})
local penetration = traceless.trace.penetration({
from = eye,
to = destination,
shooter = pawn,
ignore_penetration = false
})
record("trace.line.state", line ~= nil and line.fraction ~= nil)
record("trace.hull.state", hull ~= nil and hull.fraction ~= nil)
record("trace.visibility.state", visibility ~= nil and type(visible) == "boolean")
record("trace.penetration.state", penetration ~= nil and penetration.damage ~= nil)
end)

controls.run_schema = traceless.ui.new_button("LUA", "API test", "Run entity checks", function()
local controller = traceless.players.local_controller()
local pawn = traceless.players.local_pawn()
record("players.local_controller", controller ~= nil)
record("players.local_pawn", pawn ~= nil)
if pawn ~= nil then
local health = traceless.schema.read(pawn, "m_iHealth", "int32")
local origin = pawn:origin()
local hitbox = pawn:hitbox("head")
record("schema.typed_read", health ~= nil)
record("entity.valid", pawn:is_valid())
record("entity.classname", pawn:classname() ~= nil)
record("entity.health", pawn:health() ~= nil)
record("entity.team", pawn:team() ~= nil)
record("entity.alive", pawn:is_alive() ~= nil)
record("entity.dormant", pawn:is_dormant() ~= nil)
record("entity.origin", origin ~= nil)
record("entity.hitbox", hitbox ~= nil)
local weapon = pawn:weapon()
if weapon ~= nil then
local data = weapon:data()
record("weapon.data", data ~= nil and data.damage ~= nil)
record("weapon.accuracy", weapon:inaccuracy() ~= nil and weapon:spread() ~= nil)
record("weapon.secondary_accuracy",
weapon:inaccuracy(true) ~= nil and weapon:spread(true) ~= nil)
record("weapon.recoil_index", weapon:recoil_index() ~= nil)
record("weapon.clip", weapon:clip() ~= nil)
end
end
if controller ~= nil then
record("controller.pawn_conversion", controller:pawn() ~= nil)
record("controller.name", controller:name() ~= nil)
record("controller.steam_id", controller:steam_id() ~= nil)
record("controller.tick_base", controller:tick_base() ~= nil)
record("controller.is_local", controller:is_local() == true)
end
if pawn ~= nil then
record("pawn.controller", pawn:controller() ~= nil)
record("pawn.velocity", pawn:velocity() ~= nil)
record("pawn.recoil", pawn:recoil() ~= nil)
record("entity.handle_round_trip", traceless.entities.from_handle(pawn:handle()) ~= nil)
record("entity.index_round_trip", traceless.entities.from_index(pawn:index()) ~= nil)
record("entity.scene_node", pawn:scene_node() ~= nil)
record("entity.model", pawn:model() ~= nil)
record("entity.bone", pawn:bone(0) ~= nil)
end
record("players.all", type(traceless.players.all()) == "table")
record("players.enemies", type(traceless.players.all(true)) == "table")
record("entities.all", type(traceless.entities.all()) == "table")
end)

controls.run_ui = traceless.ui.new_button("LUA", "API test", "Run UI checks", function()
local label_name = traceless.ui.name(controls.label)
traceless.ui.update(controls.mode, {"first", "second", "third"})
traceless.ui.set(controls.mode, "second")
traceless.ui.set(controls.multi, {"one", "three"})
traceless.ui.set(controls.list, 1)
traceless.ui.set(controls.slider, 7)
traceless.ui.set(controls.color, 40, 120, 220, 255)
traceless.ui.set(controls.textbox, "updated")
traceless.ui.set(controls.hidden, "stored")
traceless.ui.set(controls.label, "UI controls verified")
traceless.ui.set_visible(controls.label, false)
traceless.ui.set_visible(controls.label, true)
local red, green, blue, alpha = traceless.ui.get(controls.color)
local selected = traceless.ui.get(controls.multi)
record("ui.checkbox", type(traceless.ui.get(controls.show)) == "boolean")
record("ui.combobox", traceless.ui.get(controls.mode) == "second")
record("ui.multiselect", helper.contains(selected, "one") and helper.contains(selected, "three"))
record("ui.listbox", traceless.ui.get(controls.list) == 1)
record("ui.slider", traceless.ui.get(controls.slider) == 7)
record("ui.color_picker", red == 40 and green == 120 and blue == 220 and alpha == 255)
record("ui.textbox", traceless.ui.get(controls.textbox) == "updated")
record("ui.string", traceless.ui.get(controls.hidden) == "stored")
record("ui.name", label_name == "UI controls are ready")
record("ui.set_callback", ui_callback_registered)
end)

local report_page = traceless.ui.new_slider("LUA", "API test", "Report page", 1, 32, 1)

local function check_render_resources()
if render_resources.checked then
return
end
render_resources.checked = true
test("render.font", function()
render_resources.font = traceless.render.create_font(
"Tahoma",
14,
400,
traceless.render.font_flags.outline)
return render_resources.font ~= nil
end)
test("render.font_measure_text", function()
if render_resources.font == nil then
return false, "font unavailable"
end
local width, height = traceless.render.font_measure_text(
render_resources.font,
"api test")
return width > 0 and height > 0
end)
test("render.measure_text", function()
local width, height = traceless.render.measure_text("", "api test")
return width > 0 and height > 0
end)
test("render.world_to_screen", function()
local ok, screen_x, screen_y = pcall(
traceless.render.world_to_screen,
0,
0,
0)
return ok and (screen_x == nil
or (type(screen_x) == "number" and type(screen_y) == "number"))
end)
test("render.load_rgba", function()
render_resources.rgba = traceless.render.load_rgba(helper.rgba, 1, 1)
return render_resources.rgba ~= nil
end)
test("render.load_png", function()
render_resources.png = traceless.render.load_png(helper.png, 1, 1)
return render_resources.png ~= nil
end)
test("render.load_jpg", function()
render_resources.jpg = traceless.render.load_jpg(helper.jpg, 1, 1)
return render_resources.jpg ~= nil
end)
end

traceless.events.on("paint", function()
callbacks.paint = callbacks.paint + 1
check_render_resources()
end)

traceless.events.on("paint_ui", function()
callbacks.paint_ui = callbacks.paint_ui + 1
local menu_x, menu_y = traceless.ui.menu_position()
local menu_width, menu_height = traceless.ui.menu_size()
local mouse_x, mouse_y = traceless.ui.mouse_position()
record("ui.menu_helpers", menu_x ~= nil and menu_y ~= nil
and menu_width ~= nil and menu_height ~= nil
and mouse_x ~= nil and mouse_y ~= nil
and type(traceless.ui.is_menu_open()) == "boolean")
if not traceless.ui.get(controls.show) then
return
end
local width, height = traceless.engine.screen_size()
local x = math.max(10, width - 430)
local y = 60
traceless.render.rectangle(x, y, 410, 330, 18, 22, 30, 235)
if render_resources.font ~= nil then
traceless.render.font_text(
render_resources.font,
x + 12,
y + 12,
255,
255,
255,
255,
traceless.render.font_alignment.left,
"Traceless Lua API test")
else
traceless.render.text(x + 12, y + 12, 255, 255, 255, 255, "", 0,
"Traceless Lua API test")
end
traceless.render.line(x + 12, y + 50, x + 398, y + 50, 80, 180, 255, 220)
traceless.render.gradient(x + 12, y + 55, 130, 8, 80, 180, 255, 220,
180, 80, 255, 220, true)
traceless.render.triangle(x + 155, y + 51, x + 165, y + 63, x + 175, y + 51,
180, 80, 255, 220)
traceless.render.circle(x + 195, y + 59, 80, 180, 255, 220, 6, 0, 1)
traceless.render.circle_outline(x + 215, y + 59, 180, 80, 255, 220, 6, 0, 1, 1)
local indicator_y = traceless.render.indicator(80, 180, 255, 220, "API test")
record("render.indicator", type(indicator_y) == "number")
traceless.render.text(x + 12, y + 32, 180, 190, 205, 255, "", 0,
string.format("paint %d | ui %d | setup %d | predict %d",
callbacks.paint, callbacks.paint_ui, callbacks.setup, callbacks.predict_command))
traceless.render.text(x + 12, y + 46, 180, 190, 205, 255, "", 0,
string.format("prediction %d | view %d | ui callback %d",
callbacks.prediction, callbacks.override_view, callbacks.ui))
if render_resources.rgba ~= nil then
traceless.render.texture(render_resources.rgba, x + 360, y + 10, 24, 24,
255, 255, 255, 255)
end
if render_resources.png ~= nil then
traceless.render.texture(render_resources.png, x + 330, y + 10, 24, 24,
255, 255, 255, 255)
end
if render_resources.jpg ~= nil then
traceless.render.texture(render_resources.jpg, x + 300, y + 10, 24, 24,
255, 255, 255, 255)
end
local page = traceless.ui.get(report_page) or 1
local start = (page - 1) * 10 + 1
local line = 0
for index = start, math.min(#order, start + 9) do
local name = order[index]
local result = results[name]
local red, green = result.passed and 130 or 255, result.passed and 235 or 100
traceless.render.text(x + 12, y + 78 + line * 22, red, green, 150, 255, "", 0,
string.format("%s: %s", result.passed and "PASS" or "FAIL", name))
line = line + 1
end
end)

traceless.events.on("command.setup", function(command)
callbacks.setup = callbacks.setup + 1
local angles = command.view_angles
if angles ~= nil then
command.view_angles = angles
end
local button = command:button("attack")
local subticks = command:subticks()
local history = command:history()
if callbacks.setup == 1 then
record("command.view_angles", angles ~= nil)
record("command.button", button ~= nil and type(button.held) == "boolean")
record("command.subticks", type(subticks) == "function")
record("command.history", type(history) == "function")
end
local forward_move = command.forward_move
if forward_move ~= nil then
command.forward_move = forward_move
end
end)

traceless.events.on("predict_command", function(command)
callbacks.predict_command = callbacks.predict_command + 1
if callbacks.predict_command == 1 then
record("predict_command.fields", command.command_number ~= nil
and command.tick_count ~= nil
and command.view_angles ~= nil)
end
end)

traceless.events.on("prediction_update", function()
callbacks.prediction = callbacks.prediction + 1
if callbacks.prediction == 1 then
local state_ok = pcall(traceless.prediction.local_state)
local ticks_ok = pcall(traceless.prediction.ticks)
record("prediction.snapshots", state_ok and ticks_ok)
end
end)

traceless.events.on("override_view", function(view)
callbacks.override_view = callbacks.override_view + 1
if callbacks.override_view == 1 then
record("override_view.fields", view ~= nil and view.fov ~= nil
and view.pitch ~= nil and view.yaw ~= nil)
end
end)

traceless.events.on("player_hurt", function(event)
callbacks.player_hurt = callbacks.player_hurt + 1
if event ~= nil then
record("game_event.object", event.name == "player_hurt")
end
end)

traceless.events.on("round_start", function(event)
callbacks.round_start = callbacks.round_start + 1
if event ~= nil then
record("game_event.round_start", event.name == "round_start")
end
end)

traceless.events.on("aim_fire", function(shot)
callbacks.aim_fire = callbacks.aim_fire + 1
if callbacks.aim_fire == 1 then
record("shot.aim_fire", shot ~= nil and shot.id ~= nil)
end
end)

traceless.events.on("aim_hit", function(shot)
callbacks.aim_hit = callbacks.aim_hit + 1
if callbacks.aim_hit == 1 then
record("shot.aim_hit", shot ~= nil and shot.id ~= nil)
end
end)

traceless.events.on("aim_miss", function(shot)
callbacks.aim_miss = callbacks.aim_miss + 1
if callbacks.aim_miss == 1 then
record("shot.aim_miss", shot ~= nil and shot.id ~= nil)
end
end)

traceless.events.on("console_input", function(text)
local command = text:match("^%s*(.-)%s*$")
if command == "traceless_api_test" then
callbacks.console_input = callbacks.console_input + 1
traceless.console.info("[API test] console_input callback received")
traceless.notify.info("Lua API test console callback received")
return true
end
return false
end)

traceless.timer.after(1, function(label)
callbacks.timer = callbacks.timer + 1
record("timer.after", callbacks.timer == 1 and label == "api_test")
end, "api_test")

traceless.events.on("shutdown", function()
traceless.console.info("Traceless Lua API test unloaded")
end)

traceless.notify.info("Traceless Lua API test loaded")