demo: port all Widgets sections, ShowStyleEditor/ShowStyleSelector, menus; fix crashes found by click fuzzer (color/scalar default args, InputTextWithHint string hint, AddText overload, splitter reset, CollapsingHeader close button, callback data methods, SetKeyboardFocusHere & misc getters)
This commit is contained in:
@@ -1 +1 @@
|
||||
[[12, "imgui.lua"], [13676, "imgui_demo.lua"], [14613, "imgui_demo_2.lua"], [17688, "imgui_docking.lua"], [20816, "imgui_dragdrop.lua"], [21108, "imgui_draw.lua"], [26103, "imgui_h.lua"], [28257, "imgui_impl_roblox.lua"], [29022, "imgui_impl_roblox_fonts.lua"], [29800, "imgui_internal.lua"], [32956, "imgui_tables.lua"], [37303, "imgui_tabs.lua"], [38470, "imgui_widgets.lua"], [46945, "imstb_rectpack.lua"], [47391, "imstb_textedit.lua"], [48632, "imstb_truetype.lua"], [51100, "imstd_minstdio.lua"]]
|
||||
[[12, "imgui.lua"], [13756, "imgui_demo.lua"], [14689, "imgui_demo_2.lua"], [17764, "imgui_demo_widgets.lua"], [19688, "imgui_docking.lua"], [22816, "imgui_dragdrop.lua"], [23108, "imgui_draw.lua"], [28114, "imgui_h.lua"], [30324, "imgui_impl_roblox.lua"], [31089, "imgui_impl_roblox_fonts.lua"], [31867, "imgui_internal.lua"], [35023, "imgui_tables.lua"], [39370, "imgui_tabs.lua"], [40537, "imgui_widgets.lua"], [49061, "imstb_rectpack.lua"], [49507, "imstb_textedit.lua"], [50748, "imstb_truetype.lua"], [53216, "imstd_minstdio.lua"]]
|
||||
+2160
-11
File diff suppressed because it is too large
Load Diff
@@ -12930,6 +12930,86 @@ function ImGui.BeginTooltipHidden()
|
||||
return ret
|
||||
end
|
||||
|
||||
-- [SECTION] MISC GETTERS/SETTERS, FOCUS
|
||||
|
||||
function ImGui.NavMoveRequestResolveWithLastItem(result)
|
||||
local g = GImGui
|
||||
g.NavMoveScoringItems = false -- Ensure request doesn't need more processing
|
||||
ImGui.NavApplyItemToResult(result)
|
||||
ImGui.NavUpdateAnyRequestFlag()
|
||||
end
|
||||
|
||||
function ImGui.SetKeyboardFocusHere(offset)
|
||||
if offset == nil then offset = 0 end
|
||||
local g = GImGui
|
||||
local window = g.CurrentWindow
|
||||
IM_ASSERT(offset >= -1) -- -1 is allowed but not below
|
||||
|
||||
if g.DragDropActive or g.MovingWindow ~= nil then
|
||||
return
|
||||
end
|
||||
|
||||
ImGui.SetNavWindow(window)
|
||||
|
||||
local move_flags = bit32.bor(ImGuiNavMoveFlags.IsTabbing, ImGuiNavMoveFlags.Activate, ImGuiNavMoveFlags.FocusApi, ImGuiNavMoveFlags.NoSetNavCursorVisible)
|
||||
local scroll_flags = window.Appearing and bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.AlwaysCenterY) or bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.KeepVisibleEdgeY)
|
||||
ImGui.NavMoveRequestSubmit(ImGuiDir.None, (offset < 0) and ImGuiDir.Up or ImGuiDir.Down, move_flags, scroll_flags)
|
||||
if offset == -1 then
|
||||
ImGui.NavMoveRequestResolveWithLastItem(g.NavMoveResultLocal)
|
||||
else
|
||||
g.NavTabbingDir = 1
|
||||
g.NavTabbingCounter = offset + 1
|
||||
end
|
||||
end
|
||||
|
||||
function ImGui.FocusItem()
|
||||
local g = GImGui
|
||||
local window = g.CurrentWindow
|
||||
if g.DragDropActive or g.MovingWindow ~= nil then
|
||||
return
|
||||
end
|
||||
local move_flags = bit32.bor(ImGuiNavMoveFlags.IsTabbing, ImGuiNavMoveFlags.FocusApi, ImGuiNavMoveFlags.NoSetNavCursorVisible, ImGuiNavMoveFlags.NoSelect)
|
||||
local scroll_flags = window.Appearing and bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.AlwaysCenterY) or bit32.bor(ImGuiScrollFlags.KeepVisibleEdgeX, ImGuiScrollFlags.KeepVisibleEdgeY)
|
||||
ImGui.SetNavWindow(window)
|
||||
ImGui.NavMoveRequestSubmit(ImGuiDir.None, ImGuiDir.Up, move_flags, scroll_flags)
|
||||
ImGui.NavMoveRequestResolveWithLastItem(g.NavMoveResultLocal)
|
||||
end
|
||||
|
||||
function ImGui.ActivateItemByID(id)
|
||||
local g = GImGui
|
||||
g.NavNextActivateId = id
|
||||
g.NavNextActivateFlags = ImGuiActivateFlags.None
|
||||
end
|
||||
|
||||
function ImGui.SetNavCursorVisible(visible)
|
||||
local g = GImGui
|
||||
if g.NavWindow and bit32.band(g.NavWindow.Flags, ImGuiWindowFlags.NoNavInputs) ~= 0 then
|
||||
visible = false
|
||||
elseif g.IO.ConfigNavCursorVisibleAlways then
|
||||
visible = true
|
||||
end
|
||||
g.NavCursorVisible = visible
|
||||
end
|
||||
|
||||
function ImGui.GetFrameCount() return GImGui.FrameCount end
|
||||
function ImGui.GetStateStorage() return GImGui.CurrentWindow.DC.StateStorage end
|
||||
function ImGui.SetStateStorage(tree)
|
||||
local window = GImGui.CurrentWindow
|
||||
window.DC.StateStorage = tree or window.StateStorage
|
||||
end
|
||||
function ImGui.SetNextFrameWantCaptureKeyboard(want) GImGui.WantCaptureKeyboardNextFrame = want and 1 or 0 end
|
||||
function ImGui.SetNextFrameWantCaptureMouse(want) GImGui.WantCaptureMouseNextFrame = want and 1 or 0 end
|
||||
function ImGui.GetVersion() return IMGUI_VERSION end
|
||||
|
||||
local StyleColorNames = nil
|
||||
function ImGui.GetStyleColorName(idx)
|
||||
if StyleColorNames == nil then
|
||||
StyleColorNames = {}
|
||||
for k, v in pairs(ImGuiCol) do if k ~= "COUNT" then StyleColorNames[v] = k end end
|
||||
end
|
||||
return StyleColorNames[idx] or "Unknown"
|
||||
end
|
||||
|
||||
-- [SECTION] NAV END FRAME
|
||||
|
||||
local NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15
|
||||
|
||||
@@ -119,11 +119,7 @@ end
|
||||
|
||||
--- Closable header: CollapsingHeader(label, &p_open). Returns visible, open.
|
||||
function DemoCollapsingHeaderClosable(label, open)
|
||||
if not open then return false, open end
|
||||
local visible = ImGui.CollapsingHeader(label, open)
|
||||
-- ponytail: until CollapsingHeader(label, p_open) lands, a boolean 2nd arg is treated as flags=None by the library
|
||||
if type(visible) == "table" then visible = visible[1] end
|
||||
return visible, open
|
||||
return ImGui.CollapsingHeader(label, open)
|
||||
end
|
||||
|
||||
--- ImColor::HSV() as ImVec4
|
||||
|
||||
@@ -838,7 +838,7 @@ local function DemoWindowLayout_TextClipping()
|
||||
else
|
||||
local clip_rect = ImVec4(p0.x, p0.y, p1.x, p1.y)
|
||||
draw_list:AddRectFilled(p0, p1, IM_COL32(90, 90, 120, 255))
|
||||
draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, IM_COL32_WHITE, text_str, nil, 0.0, clip_rect)
|
||||
draw_list:AddText(ImGui.GetFont(), ImGui.GetFontSize(), text_pos, IM_COL32_WHITE, text_str, 1, #text_str + 1, 0.0, clip_rect)
|
||||
end
|
||||
until true end
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3129,6 +3129,12 @@ end
|
||||
|
||||
-- TODO:
|
||||
function MT.ImDrawList:_ResetForNewFrame()
|
||||
if self._Splitter._Count > 1 then
|
||||
self._Splitter:Merge(self)
|
||||
end
|
||||
self._Splitter._Current = 0 -- [Lua] recover from an error thrown mid-split
|
||||
self._Splitter._Count = 1
|
||||
|
||||
self.CmdBuffer:resize(0)
|
||||
self.IdxBuffer:resize(0)
|
||||
self.VtxBuffer:resize(0)
|
||||
@@ -4205,6 +4211,11 @@ end
|
||||
--- @param wrap_width float
|
||||
--- @param cpu_fine_clip_rect? ImVec4
|
||||
function MT.ImDrawList:AddText(font, font_size, pos, col, text, text_begin, text_end, wrap_width, cpu_fine_clip_rect)
|
||||
-- Overload: AddText(pos, col, text, text_end?)
|
||||
if type(font) == "table" and type(font[1]) == "number" then
|
||||
font, font_size, pos, col, text, text_begin, text_end, wrap_width, cpu_fine_clip_rect = nil, 0.0, font, font_size, pos, 1, col, 0.0, nil
|
||||
if text_end == nil then text_end = #text + 1 end
|
||||
end
|
||||
if text_begin == nil then text_begin = 1 end
|
||||
|
||||
if bit32.band(col, IM_COL32_A_MASK) == 0 then return end
|
||||
|
||||
+57
-1
@@ -67,6 +67,9 @@ function ImS32(val) return bitAnd(val, 0xFFFFFFFF) end
|
||||
|
||||
--- @alias ImDrawIdx unsigned_int
|
||||
|
||||
IMGUI_VERSION = "1.93.0 WIP"
|
||||
IMGUI_VERSION_NUM = 19298
|
||||
|
||||
IM_UNICODE_CODEPOINT_INVALID = 0xFFFD
|
||||
IM_UNICODE_CODEPOINT_MAX = 0xFFFF
|
||||
|
||||
@@ -1980,10 +1983,63 @@ ImGuiInputTextFlags = {
|
||||
--- @class ImGuiInputTextCallbackData
|
||||
|
||||
--- @return ImGuiInputTextCallbackData
|
||||
-- Buf is a 1-based zero-terminated byte table; positions (CursorPos, pos...) are 0-based byte offsets like upstream.
|
||||
MT.ImGuiInputTextCallbackData = {}
|
||||
MT.ImGuiInputTextCallbackData.__index = MT.ImGuiInputTextCallbackData
|
||||
function ImGuiInputTextCallbackData()
|
||||
return {}
|
||||
return setmetatable({}, MT.ImGuiInputTextCallbackData)
|
||||
end
|
||||
|
||||
function MT.ImGuiInputTextCallbackData:DeleteChars(pos, bytes_count)
|
||||
IM_ASSERT(pos + bytes_count <= self.BufTextLen)
|
||||
local buf = self.Buf
|
||||
local n = self.BufTextLen - bytes_count - pos + 1 -- includes zero terminator
|
||||
for i = 1, n do buf[pos + i] = buf[pos + bytes_count + i] end
|
||||
|
||||
if self.CursorPos >= pos + bytes_count then
|
||||
self.CursorPos = self.CursorPos - bytes_count
|
||||
elseif self.CursorPos >= pos then
|
||||
self.CursorPos = pos
|
||||
end
|
||||
self.SelectionStart = self.CursorPos; self.SelectionEnd = self.CursorPos
|
||||
self.BufDirty = true
|
||||
self.BufTextLen = self.BufTextLen - bytes_count
|
||||
end
|
||||
|
||||
--- @param new_text string
|
||||
function MT.ImGuiInputTextCallbackData:InsertChars(pos, new_text)
|
||||
local new_text_len = #new_text
|
||||
if new_text_len == 0 then return end
|
||||
local is_resizable = bit32.band(self.Flags, ImGuiInputTextFlags.CallbackResize) ~= 0
|
||||
-- We support partial insertion
|
||||
local avail = self.BufSize - 1 - self.BufTextLen
|
||||
if not is_resizable and new_text_len > avail then
|
||||
new_text_len = avail -- ponytail: truncates by bytes, not to the closest UTF-8 codepoint
|
||||
end
|
||||
if new_text_len <= 0 then return end
|
||||
-- ponytail: CallbackResize buffer growth not supported, text is truncated at BufSize instead
|
||||
if self.BufTextLen + new_text_len + 1 > self.BufSize then
|
||||
new_text_len = self.BufSize - 1 - self.BufTextLen
|
||||
if new_text_len <= 0 then return end
|
||||
end
|
||||
|
||||
local buf = self.Buf
|
||||
for i = self.BufTextLen, pos + 1, -1 do buf[i + new_text_len] = buf[i] end
|
||||
for i = 1, new_text_len do buf[pos + i] = string.byte(new_text, i) end
|
||||
buf[self.BufTextLen + new_text_len + 1] = 0
|
||||
|
||||
self.BufDirty = true
|
||||
self.BufTextLen = self.BufTextLen + new_text_len
|
||||
if self.CursorPos >= pos then
|
||||
self.CursorPos = self.CursorPos + new_text_len
|
||||
end
|
||||
self.SelectionStart = self.CursorPos; self.SelectionEnd = self.CursorPos
|
||||
end
|
||||
|
||||
function MT.ImGuiInputTextCallbackData:SelectAll() self.SelectionStart = 0; self.SelectionEnd = self.BufTextLen end
|
||||
function MT.ImGuiInputTextCallbackData:ClearSelection() self.SelectionStart = self.BufTextLen; self.SelectionEnd = self.BufTextLen end
|
||||
function MT.ImGuiInputTextCallbackData:HasSelection() return self.SelectionStart ~= self.SelectionEnd end
|
||||
|
||||
--- @alias ImGuiInputTextCallback fun(data: ImGuiInputTextCallbackData)
|
||||
|
||||
--- @alias ImGuiMemAllocFunc fun(T: function, start_idx: int, end_idx: int, userdata: any): table
|
||||
|
||||
+53
-4
@@ -2704,6 +2704,7 @@ end
|
||||
--- @param format? string
|
||||
--- @param flags? ImGuiInputTextFlags
|
||||
function ImGui.InputScalarN(label, data_type, data, components, step, step_fast, format, flags)
|
||||
if flags == nil then flags = 0 end
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return false
|
||||
@@ -3052,6 +3053,8 @@ end
|
||||
--- @param format string
|
||||
--- @param flags ImGuiSliderFlags
|
||||
function ImGui.DragScalar(label, data_type, data, v_speed, min, max, format, flags)
|
||||
if v_speed == nil then v_speed = 1.0 end
|
||||
if flags == nil then flags = 0 end
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return data, false
|
||||
@@ -3922,6 +3925,7 @@ end
|
||||
--- @param format? string
|
||||
--- @param flags? ImGuiSliderFlags
|
||||
function ImGui.VSliderScalar(label, size, data_type, data, min, max, format, flags)
|
||||
if flags == nil then flags = 0 end
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return data, false
|
||||
@@ -4776,7 +4780,20 @@ end
|
||||
--- @param flags ImGuiInputTextFlags
|
||||
--- @param callback? ImGuiInputTextCallback
|
||||
--- @param callback_user_data any
|
||||
local HintBufCache = setmetatable({}, { __mode = "k" })
|
||||
local function HintToBuf(hint)
|
||||
local t = HintBufCache[hint]
|
||||
if t == nil then
|
||||
t = {}
|
||||
for i = 1, #hint do t[i] = string.byte(hint, i) end
|
||||
t[#hint + 1] = 0
|
||||
HintBufCache[hint] = t
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
function ImGui.InputTextEx(label, hint, buf, buf_size, size_arg, flags, callback, callback_user_data)
|
||||
if type(hint) == "string" then hint = HintToBuf(hint) end
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return false
|
||||
@@ -5823,6 +5840,7 @@ local fmt_table_float = {
|
||||
--- @param col float[]
|
||||
--- @param flags ImGuiColorEditFlags
|
||||
function ImGui.ColorEdit4(label, col, flags)
|
||||
if flags == nil then flags = 0 end
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return false
|
||||
@@ -6074,12 +6092,14 @@ end
|
||||
--- @param flags? ImGuiColorEditFlags
|
||||
function ImGui.ColorEdit3(label, col, flags)
|
||||
if flags == nil then flags = 0 end
|
||||
if flags == nil then flags = 0 end
|
||||
|
||||
return ImGui.ColorEdit4(label, col, bit32.bor(flags, ImGuiColorEditFlags.NoAlpha))
|
||||
end
|
||||
|
||||
-- `col` mutated in place, returns value_changed
|
||||
function ImGui.ColorPicker3(label, col, flags)
|
||||
if flags == nil then flags = 0 end
|
||||
local col4 = { col[1], col[2], col[3], 1.0 }
|
||||
if not ImGui.ColorPicker4(label, col4, bit32.bor(flags or 0, ImGuiColorEditFlags.NoAlpha)) then
|
||||
return false
|
||||
@@ -6122,6 +6142,7 @@ local backup_initial_col = {0, 0, 0, 0}
|
||||
--- @param flags ImGuiColorEditFlags
|
||||
--- @param ref_col? float[]
|
||||
function ImGui.ColorPicker4(label, col, flags, ref_col)
|
||||
if flags == nil then flags = 0 end
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return false
|
||||
@@ -7356,17 +7377,45 @@ function ImGui.SetNextItemStorageID(storage_id)
|
||||
g.NextItemData.StorageId = storage_id
|
||||
end
|
||||
|
||||
-- Overloads: CollapsingHeader(label, flags?) -> is_open
|
||||
-- CollapsingHeader(label, p_visible: bool, flags?) -> is_open, p_visible
|
||||
--- @param label string
|
||||
--- @param flags? ImGuiTreeNodeFlags
|
||||
function ImGui.CollapsingHeader(label, flags)
|
||||
function ImGui.CollapsingHeader(label, a, b)
|
||||
local p_visible, flags
|
||||
if type(a) == "boolean" then p_visible, flags = a, b else flags = a end
|
||||
if flags == nil then flags = 0 end
|
||||
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
if window.SkipItems then
|
||||
return false
|
||||
return false, p_visible
|
||||
end
|
||||
|
||||
if p_visible == false then
|
||||
return false, p_visible
|
||||
end
|
||||
|
||||
local id = window:GetID(label)
|
||||
return ImGui.TreeNodeBehavior(id, bit32.bor(flags, ImGuiTreeNodeFlags.CollapsingHeader), label)
|
||||
flags = bit32.bor(flags, ImGuiTreeNodeFlags.CollapsingHeader)
|
||||
if p_visible ~= nil then
|
||||
flags = bit32.bor(flags, ImGuiTreeNodeFlags.AllowOverlap, ImGuiTreeNodeFlags.ClipLabelForTrailingButton)
|
||||
end
|
||||
local is_open = ImGui.TreeNodeBehavior(id, flags, label)
|
||||
if p_visible ~= nil then
|
||||
-- Create a small overlapping close button
|
||||
local g = GImGui
|
||||
local last_item_backup = ImGuiLastItemData()
|
||||
ImGuiLastItemData_Copy(last_item_backup, g.LastItemData)
|
||||
local button_size = g.FontSize
|
||||
local button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size)
|
||||
local button_y = g.LastItemData.Rect.Min.y + g.Style.FramePadding.y
|
||||
local close_button_id = ImGui.GetIDWithSeed("#CLOSE", nil, id)
|
||||
if ImGui.CloseButton(close_button_id, ImVec2(button_x, button_y)) then
|
||||
p_visible = false
|
||||
end
|
||||
ImGuiLastItemData_Copy(g.LastItemData, last_item_backup)
|
||||
end
|
||||
|
||||
return is_open, p_visible
|
||||
end
|
||||
|
||||
----------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
-- Click fuzzer for the demo: records every visible item rect (by wrapping ImGui.ItemAdd) and clicks/drags/scrolls/types on random ones.
|
||||
-- Usage: python3 tools/test/run.py --main tools/test/scripts/t_click_fuzz.luau --frames 3000 --quiet
|
||||
-- Change SEED to explore other paths.
|
||||
local SEED = tonumber(_G.FUZZ_SEED) or 1
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local RunService = game:GetService("RunService")
|
||||
local G = require(ReplicatedStorage:WaitForChild("ImGui"))
|
||||
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||
ImGui.CreateContext()
|
||||
local io = ImGui.GetIO()
|
||||
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.NavEnableKeyboard, G.ImGuiConfigFlags.DockingEnable)
|
||||
G.ImGui_ImplRoblox.Init()
|
||||
math.randomseed(SEED)
|
||||
|
||||
local items, prev_items = {}, {}
|
||||
local orig_ItemAdd = ImGui.ItemAdd
|
||||
ImGui.ItemAdd = function(bb, id, nav_bb, extra)
|
||||
local r = orig_ItemAdd(bb, id, nav_bb, extra)
|
||||
if r and id ~= 0 then
|
||||
local g = ImGui.GetCurrentContext()
|
||||
local w = g.CurrentWindow
|
||||
local c = w.ClipRect
|
||||
local x1, y1 = math.max(bb.Min.x, c.Min.x), math.max(bb.Min.y, c.Min.y)
|
||||
local x2, y2 = math.min(bb.Max.x, c.Max.x), math.min(bb.Max.y, c.Max.y)
|
||||
if x2 - x1 >= 2 and y2 - y1 >= 2 then
|
||||
items[#items + 1] = { x1, y1, x2, y2, w.Name }
|
||||
end
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
local log = {}
|
||||
local function note(s) log[#log + 1] = s; if #log > 12 then table.remove(log, 1) end end
|
||||
|
||||
-- action queue: list of {x, y, down, key, char, wheel}
|
||||
local queue = {}
|
||||
local mx, my, down = 500, 500, false
|
||||
local function plan()
|
||||
local list = prev_items
|
||||
if #list == 0 then queue = { { 500, 500, false } }; return end
|
||||
local it = list[math.random(#list)]
|
||||
local x = it[1] + math.random() * (it[3] - it[1])
|
||||
local y = it[2] + math.random() * (it[4] - it[2])
|
||||
local r = math.random()
|
||||
if r < 0.65 then
|
||||
note(string.format("click %.0f,%.0f in %s", x, y, it[5]))
|
||||
queue = { { x, y, false }, { x, y, true }, { x, y, false }, { x, y, false } }
|
||||
elseif r < 0.8 then
|
||||
local dx, dy = math.random(-150, 150), math.random(-80, 80)
|
||||
note(string.format("drag %.0f,%.0f by %d,%d in %s", x, y, dx, dy, it[5]))
|
||||
queue = { { x, y, false }, { x, y, true } }
|
||||
for i = 1, 6 do queue[#queue + 1] = { x + dx * i / 6, y + dy * i / 6, true } end
|
||||
queue[#queue + 1] = { x + dx, y + dy, false }
|
||||
elseif r < 0.9 then
|
||||
note(string.format("wheel %.0f,%.0f in %s", x, y, it[5]))
|
||||
queue = { { x, y, false, wheel = (math.random() < 0.5) and -3 or 3 } }
|
||||
elseif r < 0.95 then
|
||||
note(string.format("dblclick %.0f,%.0f in %s", x, y, it[5]))
|
||||
queue = { { x, y, false }, { x, y, true }, { x, y, false }, { x, y, true }, { x, y, false }, { x, y, false } }
|
||||
else
|
||||
local keys = { G.ImGuiKey.Enter, G.ImGuiKey.Escape, G.ImGuiKey.Tab, G.ImGuiKey.UpArrow, G.ImGuiKey.DownArrow, G.ImGuiKey.Backspace }
|
||||
local k = keys[math.random(#keys)]
|
||||
note("key " .. tostring(k) .. " + text")
|
||||
queue = { { mx, my, down, key = k }, { mx, my, down, char = "a1" } }
|
||||
end
|
||||
end
|
||||
|
||||
local frame = 0
|
||||
RunService.Stepped:Connect(function()
|
||||
frame += 1
|
||||
local ok, err = xpcall(function()
|
||||
G.ImGui_ImplRoblox.NewFrame()
|
||||
if #queue == 0 then plan() end
|
||||
local a = table.remove(queue, 1)
|
||||
mx, my = a[1], a[2]
|
||||
io:AddMousePosEvent(mx, my)
|
||||
if a[3] ~= down then down = a[3]; io:AddMouseButtonEvent(0, down) end
|
||||
if a.wheel then io:AddMouseWheelEvent(0, a.wheel) end
|
||||
if a.key then io:AddKeyEvent(a.key, true); io:AddKeyEvent(a.key, false) end
|
||||
if a.char then for i = 1, #a.char do io:AddInputCharacter(string.byte(a.char, i)) end end
|
||||
|
||||
prev_items = items
|
||||
items = {}
|
||||
ImGui.NewFrame()
|
||||
ImGui.DockSpaceOverViewport(0, nil, G.ImGuiDockNodeFlags.PassthruCentralNode)
|
||||
if frame % 400 == 1 then
|
||||
ImGui.SetNextWindowCollapsed(false)
|
||||
ImGui.SetNextWindowPos(ImVec2(650, 20))
|
||||
ImGui.SetNextWindowSize(ImVec2(700, 1000))
|
||||
end
|
||||
ImGui.ShowDemoWindow()
|
||||
ImGui.Render()
|
||||
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||
end, debug.traceback)
|
||||
if not ok then
|
||||
print("FUZZ FAIL at frame " .. frame .. " seed " .. SEED)
|
||||
for _, l in ipairs(log) do print(" " .. l) end
|
||||
error(err, 0)
|
||||
end
|
||||
if frame % 500 == 0 then print("frame", frame, "items", #prev_items) end
|
||||
end)
|
||||
Reference in New Issue
Block a user