local xuyna = require('Direct3D9HookDll')
--[[ MIMGUI -> init.lua ]]--
local imgui = require 'mimgui.imgui'
local DX9 = require 'mimgui.dx9'
local ffi = require 'ffi'
local winmsg = require 'windows.message'
local memory = require 'memory'
local mimgui = {}
local renderer = nil
local subscriptionsInitialize = {}
local subscriptionsNewFrame = {}
local eventsRegistered = false
local active = false
local cursorActive = false
local playerLocked = false
local iniFilePath = nil
local defaultGlyphRanges = nil
setmetatable(mimgui, {__index = imgui, __newindex = function(t, k, v)
if imgui[k] then
print('[mimgui] Warning! Overwriting existing key "'..k..'"!')
end
rawset(t, k, v)
end})
-- background "Shift" triggering fix
memory.fill(0x00531155, 0x90, 5, true)
local function ShowCursor(show)
if show then
showCursor(true)
elseif cursorActive then
showCursor(false)
end
cursorActive = show
end
local function LockPlayer(lock)
if lock then
lockPlayerControl(true)
elseif playerLocked then
lockPlayerControl(false)
end
playerLocked = lock
end
-- MoonLoader v.027
if not isCursorActive then
isCursorActive = function() return cursorActive end
end
local function InitializeRenderer()
-- init renderer
local hwnd = ffi.cast('HWND', readMemory(0x00C8CF88, 4, false))
local d3ddevice = ffi.cast('LPDIRECT3DDEVICE9', getD3DDevicePtr())
renderer = assert(DX9.new(d3ddevice, hwnd))
renderer:SwitchContext()
-- configure imgui
imgui.GetIO().ImeWindowHandle = nil -- default causes crash. TODO: why?
imgui.GetIO().LogFilename = nil
local confdir = getWorkingDirectory() .. [[\config\mimgui\]]
if not doesDirectoryExist(confdir) then
createDirectory(confdir)
end
iniFilePath = ffi.new('char[260]', confdir .. script.this.filename .. '.ini')
imgui.GetIO().IniFilename = iniFilePath
-- change font
local fontFile = getFolderPath(0x14) .. '\\trebucbd.ttf'
assert(doesFileExist(fontFile), '[mimgui] Font "' .. fontFile .. '" doesn\'t exist!')
local builder = imgui.ImFontGlyphRangesBuilder()
builder:AddRanges(imgui.GetIO().Fonts:GetGlyphRangesCyrillic())
builder:AddText([[‚„…†‡€‰‹‘’“”•–—™›№]])
defaultGlyphRanges = imgui.ImVector_ImWchar()
builder:BuildRanges(defaultGlyphRanges)
imgui.GetIO().Fonts:AddFontFromFileTTF(fontFile, 14, nil, defaultGlyphRanges[0].Data)
-- invoke initializers
for _, cb in ipairs(subscriptionsInitialize) do
cb()
end
end
local function RegisterEvents()
function OnPresent()
if active then
if not renderer then
InitializeRenderer()
end
if renderer and not renderer.lost then
renderer:SwitchContext()
for _, sub in ipairs(subscriptionsNewFrame) do
if sub._render and sub._before then
sub:_before()
end
end
renderer:NewFrame()
local hideCursor = true
for _, sub in ipairs(subscriptionsNewFrame) do
if sub._render then
sub:_draw()
hideCursor = hideCursor and sub.HideCursor
end
end
if hideCursor and not isCursorActive() then
imgui.SetMouseCursor(imgui.lib.ImGuiMouseCursor_None)
end
renderer:EndFrame()
end
end
end
local keyState = {}
local WM_MOUSEHWHEEL = 0x020E
local mouseMsgs = {
[WM_MOUSEHWHEEL]=true,
[winmsg.WM_LBUTTONDOWN]=true,
[winmsg.WM_LBUTTONDBLCLK]=true,
[winmsg.WM_RBUTTONDOWN]=true,
[winmsg.WM_RBUTTONDBLCLK]=true,
[winmsg.WM_MBUTTONDOWN]=true,
[winmsg.WM_MBUTTONDBLCLK]=true,
[winmsg.WM_LBUTTONUP]=true,
[winmsg.WM_RBUTTONUP]=true,
[winmsg.WM_MBUTTONUP]=true,
[winmsg.WM_MOUSEWHEEL]=true,
[winmsg.WM_SETCURSOR]=true
}
local keyboardMsgs = {
[winmsg.WM_KEYDOWN]=true,
[winmsg.WM_SYSKEYDOWN]=true,
[winmsg.WM_KEYUP]=true,
[winmsg.WM_SYSKEYUP]=true,
[winmsg.WM_CHAR]=true
}
addEventHandler('onWindowMessage', function(msg, wparam, lparam)
if not renderer then
return
end
if not mimgui.DisableInput then
local keyboard = keyboardMsgs[msg]
local mouse = mouseMsgs[msg]
if active and (keyboard or mouse) then
renderer:SwitchContext()
local io = imgui.GetIO()
renderer:WindowMessage(msg, wparam, lparam)
if (keyboard and io.WantCaptureKeyboard) or (mouse and io.WantCaptureMouse) then
if msg == winmsg.WM_KEYDOWN or msg == winmsg.WM_SYSKEYDOWN then
keyState[wparam] = false
consumeWindowMessage(true, true, true)
elseif msg == winmsg.WM_KEYUP or msg == winmsg.WM_SYSKEYUP then
if not keyState[wparam] then
consumeWindowMessage(true, true, true)
end
else
consumeWindowMessage(true, true, true)
end
end
end
end
-- save key states to prevent key sticking
if msg == winmsg.WM_KILLFOCUS then
keyState = {}
elseif wparam < 256 then
if msg == winmsg.WM_KEYDOWN or msg == winmsg.WM_SYSKEYDOWN then
keyState[wparam] = true
elseif msg == winmsg.WM_KEYUP or msg == winmsg.WM_SYSKEYUP then
keyState[wparam] = false
end
end
end)
function OnReset()
if renderer and not renderer.lost then
renderer:InvalidateDeviceObjects()
renderer.lost = true
end
end
function OnLost()
if renderer then
renderer.lost = false
end
end
addEventHandler('onScriptTerminate', function(scr)
if scr == script.this then
xuyna.Uninitialize()
ShowCursor(false)
LockPlayer(false)
end
end)
local updaterThread = lua_thread.create(function()
while true do
wait(0)
local activate, hideCursor, lockPlayer = false, true, false
if #subscriptionsNewFrame > 0 then
for i, sub in ipairs(subscriptionsNewFrame) do
if type(sub.Condition) == 'function' then
sub._render = sub.Condition()
else
sub._render = sub.Condition and true
end
if sub._render then
hideCursor = hideCursor and sub.HideCursor
lockPlayer = lockPlayer or sub.LockPlayer
end
activate = activate or sub._render
end
end
active = activate
ShowCursor(active and not hideCursor)
LockPlayer(active and lockPlayer)
end
end)
updaterThread.work_in_pause = true
end
local function Unsubscribe(t, sub)
for i, v in ipairs(t) do
if v == sub then
table.remove(t, i)
return
end
end
end
local function ImGuiEnum(name)
return setmetatable({__name = name}, {__index = function(t, k)
return imgui.lib[t.__name .. k]
end})
end
--- API ---
mimgui._VERSION = '1.7.0'
mimgui.DisableInput = false
mimgui.ComboFlags = ImGuiEnum('ImGuiComboFlags_')
mimgui.Dir = ImGuiEnum('ImGuiDir_')
mimgui.ColorEditFlags = ImGuiEnum('ImGuiColorEditFlags_')
mimgui.Col = ImGuiEnum('ImGuiCol_')
mimgui.WindowFlags = ImGuiEnum('ImGuiWindowFlags_')
mimgui.NavInput = ImGuiEnum('ImGuiNavInput_')
mimgui.FocusedFlags = ImGuiEnum('ImGuiFocusedFlags_')
mimgui.Cond = ImGuiEnum('ImGuiCond_')
mimgui.BackendFlags = ImGuiEnum('ImGuiBackendFlags_')
mimgui.TreeNodeFlags = ImGuiEnum('ImGuiTreeNodeFlags_')
mimgui.StyleVar = ImGuiEnum('ImGuiStyleVar_')
mimgui.DrawCornerFlags = ImGuiEnum('ImDrawCornerFlags_')
mimgui.DragDropFlags = ImGuiEnum('ImGuiDragDropFlags_')
mimgui.SelectableFlags = ImGuiEnum('ImGuiSelectableFlags_')
mimgui.InputTextFlags = ImGuiEnum('ImGuiInputTextFlags_')
mimgui.MouseCursor = ImGuiEnum('ImGuiMouseCursor_')
mimgui.FontAtlasFlags = ImGuiEnum('ImFontAtlasFlags_')
mimgui.HoveredFlags = ImGuiEnum('ImGuiHoveredFlags_')
mimgui.ConfigFlags = ImGuiEnum('ImGuiConfigFlags_')
mimgui.DrawListFlags = ImGuiEnum('ImDrawListFlags_')
mimgui.DataType = ImGuiEnum('ImGuiDataType_')
mimgui.Key = ImGuiEnum('ImGuiKey_')
function mimgui.OnInitialize(cb)
assert(type(cb) == 'function')
table.insert(subscriptionsInitialize, cb)
return {Unsubscribe = function() Unsubscribe(subscriptionsInitialize, cb) end}
end
function mimgui.OnFrame(cond, cbBeforeFrame, cbDraw)
assert(type(cond) == 'function')
assert(type(cbBeforeFrame) == 'function')
if cbDraw then assert(type(cbDraw) == 'function') end
if not eventsRegistered then
RegisterEvents()
eventsRegistered = true
end
local sub = {
Condition = cond,
LockPlayer = false,
HideCursor = false,
_before = cbDraw and cbBeforeFrame or nil,
_draw = cbDraw or cbBeforeFrame,
_render = false,
}
function sub:Unsubscribe()
Unsubscribe(subscriptionsNewFrame, self)
end
function sub:IsActive()
return self._render
end
table.insert(subscriptionsNewFrame, sub)
return sub
end
function mimgui.SwitchContext()
return renderer:SwitchContext()
end
function mimgui.CreateTextureFromFile(path)
return renderer:CreateTextureFromFile(path)
end
function mimgui.CreateTextureFromFileInMemory(src, size)
return renderer:CreateTextureFromFileInMemory(src, size)
end
function mimgui.ReleaseTexture(tex)
return renderer:ReleaseTexture(tex)
end
function mimgui.CreateFontsTexture()
return renderer:CreateFontsTexture()
end
function mimgui.InvalidateFontsTexture()
return renderer:InvalidateFontsTexture()
end
function mimgui.GetRenderer()
return renderer
end
function mimgui.IsInitialized()
return renderer ~= nil
end
function mimgui.StrCopy(dst, src, len)
if len or tostring(ffi.typeof(dst)):find('*', 1, true) then
ffi.copy(dst, src, len)
else
len = math.min(ffi.sizeof(dst) - 1, #src)
ffi.copy(dst, src, len)
dst[len] = 0
end
end
local new = {}
setmetatable(new, {
__index = function(self, key)
local basetype = ffi.typeof(key)
local mt = {
__index = function(self, sz)
return setmetatable({type = ffi.typeof('$[$]', self.type, sz)}, getmetatable(self))
end,
__call = function(self, ...)
return self.type(...)
end
}
return setmetatable({type = ffi.typeof('$[1]', basetype), basetype = basetype}, {
__index = function(self, sz)
return setmetatable({type = ffi.typeof('$[$]', self.basetype, sz)}, mt)
end,
__call = mt.__call
})
end,
__call = function(self, t, ...)
return ffi.new(t, ...)
end
})
mimgui.new = new
--[[ MIMGUI -> init.lua ]]--
local newFrame = mimgui.OnFrame( --[[Сама функция создания фрейма, их может быть сколько вашей душе угодно.
Обратите внимание, что в mimgui рекомендуется создавать отдельный
фрейм для каждого окна, однако это не является обязательным.]]
function() return true end, -- Определяет, выполняется/отображается ли текущий фрейм.
function(player) --[[Сама область, в которой уже будем рисовать элементы.
В функцию в качестве первой переменной передаются список функций
для взаимодействия с локальным игроком и рядом нескольких возможностей.]]
imgui.Begin("Main Window") -- Создаём новое окно с заголовком 'Main Window'
imgui.Text("Hello") -- Добавляем туда текст 'Hello'
imgui.End() -- Объявляем конец данного окна
end
)
function main()
wait(-1)
end