-- ============================================================ -- 赛事服清梦工具 v1.4(防闪退版) -- 作者: 春秋大梦 -- QQ: 3013991146 -- QQ群: 784551820 -- 电报:@cqdm_anqusifu -- ============================================================ -- ========== 配置 ========== local CONFIG = { DEFAULT_KNIFE = 702011302, ADDR_FILE = gg.EXT_FILES_DIR .. "/knife_addrs.txt", FAV_FILE = gg.EXT_FILES_DIR .. "/knife_favorites.txt", ITEM_FILE = "/storage/emulated/0/物品ID大全.txt", ITEM_CACHE_FILE = gg.EXT_FILES_DIR .. "/item_cache.txt", ITEM_FAV_FILE = gg.EXT_FILES_DIR .. "/item_favorites.txt", CONFIG_FILE = gg.EXT_FILES_DIR .. "/script_config.txt", KNIFE_FAV_FILE = "/storage/emulated/0/春秋大梦_刀皮收藏.txt", ITEM_FAV_FILE_NEW = "/storage/emulated/0/春秋大梦_物品收藏.txt", PAGE_SIZE = 30, BATCH_SIZE = 200, TELEGRAM = "@cqdm_anqusifu", VERSION = "v1.4", RETRY_COUNT = 3, } -- ========== 运行时状态 ========== local state = { cachedAddrs = nil, addrCacheValid = false, itemCache = nil, searchCache = {}, itemFavorites = {}, knifeFavorites = {}, initialized = false, } -- ========== 工具函数 ========== local function fileExists(path) local f = io.open(path, "r") if f then f:close(); return true end return false end local function readFile(path) local f = io.open(path, "r") if not f then return nil end local content = {} for line in f:lines() do table.insert(content, line) end f:close() return #content > 0 and content or nil end local function writeFile(path, data) local f = io.open(path, "w") if not f then return false end for _, line in ipairs(data) do f:write(line .. "\n") end f:close() return true end local function safeGetValues(checkTbl) local success, result = pcall(gg.getValues, checkTbl) if success and result then return result end return nil end local function safeSetValues(setTbl) local success, result = pcall(gg.setValues, setTbl) return success and result or false end -- ========== 拼音转换(精简映射) ========== local pyMap = { ["a"]="a",["b"]="b",["c"]="c",["d"]="d",["e"]="e",["f"]="f", ["g"]="g",["h"]="h",["j"]="j",["k"]="k",["l"]="l",["m"]="m", ["n"]="n",["o"]="o",["p"]="p",["q"]="q",["r"]="r",["s"]="s", ["t"]="t",["w"]="w",["x"]="x",["y"]="y",["z"]="z", ["金"]="j",["狮"]="s",["宝"]="b",["石"]="s",["项"]="x",["链"]="l", ["盛"]="s",["宴"]="y",["雕"]="d",["塑"]="s",["花"]="h",["瓶"]="p", ["唱"]="c",["片"]="p",["座"]="z",["钟"]="z",["集"]="j",["邮"]="y", ["册"]="c",["块"]="k",["杯"]="b",["魔"]="m",["方"]="f",["条"]="t", ["箱"]="x",["暗"]="a",["区"]="q",["兔"]="t",["黄"]="h",["战"]="z", ["盔"]="k",["白"]="b",["银"]="y",["水"]="s",["枪"]="q",["月"]="y", ["饼"]="b",["汤"]="t",["匙"]="c",["矿"]="k",["镐"]="g",["猛"]="m", ["攻"]="g",["审"]="s",["判"]="p",["眼"]="y",["塔"]="t",["奇"]="q", ["克"]="k",["马"]="m",["钥"]="y",["打"]="d",["火"]="h",["黑"]="h", ["牌"]="p",["铭"]="m",["手"]="s",["表"]="b",["芯"]="x",["柯"]="k", ["恩"]="e",["币"]="b",["模"]="m",["型"]="x",["试"]="s",["剂"]="j", ["盒"]="h",["机"]="j",["密"]="m",["文"]="w",["件"]="j",["理"]="l", ["想"]="x",["国"]="g",["中"]="z",["雕"]="d",["像"]="x", } local function toPinyin(str) local result = "" for i = 1, #str do local char = str:sub(i, i) result = result .. (pyMap[char] or char) end return result end -- ========== 物品收藏 ========== local function loadItemFavorites() local data = readFile(CONFIG.ITEM_FAV_FILE_NEW) if not data then state.itemFavorites = {} return end state.itemFavorites = {} for _, line in ipairs(data) do local id = tonumber(line) if id and id > 0 then table.insert(state.itemFavorites, id) end end end local function saveItemFavorites() local data = {} for _, id in ipairs(state.itemFavorites) do table.insert(data, tostring(id)) end writeFile(CONFIG.ITEM_FAV_FILE_NEW, data) end local function toggleItemFavorite(id) for i, v in ipairs(state.itemFavorites) do if v == id then table.remove(state.itemFavorites, i) saveItemFavorites() return false end end table.insert(state.itemFavorites, id) saveItemFavorites() return true end local function isItemFavorite(id) for _, v in ipairs(state.itemFavorites) do if v == id then return true end end return false end -- ========== 加载物品 ========== local function loadItems() if state.itemCache then return state.itemCache end local data = readFile(CONFIG.ITEM_CACHE_FILE) if data then local items = {} for _, line in ipairs(data) do local name, id, pinyin, lower = line:match("^(.-)%t(%d+)%t(.-)%t(.*)$") if name and id then table.insert(items, { name = name, id = tonumber(id), pinyin = pinyin, lower = lower }) end end if #items > 0 then state.itemCache = items return items end end local f = io.open(CONFIG.ITEM_FILE, "r") if not f then return loadDefaultItems() end local items = {} for line in f:lines() do local name, id = line:match("^(.-)%s*%[ItemID:%s*(%d+)%]") if name and id then name = name:match("^%s*(.-)%s*$") if name then local idNum = tonumber(id) if idNum and idNum > 0 then table.insert(items, { name = name, id = idNum, pinyin = toPinyin(name), lower = name:lower() }) end end end end f:close() if #items == 0 then return loadDefaultItems() end local cacheLines = {} for _, item in ipairs(items) do table.insert(cacheLines, item.name .. "\t" .. item.id .. "\t" .. item.pinyin .. "\t" .. item.lower) end writeFile(CONFIG.ITEM_CACHE_FILE, cacheLines) state.itemCache = items return items end -- ========== 内置精简版物品 ========== local function loadDefaultItems() local raw = { {"机密文件",408080027},{"理想国试剂盒",408080040},{"金狮雕像",408080008}, {"宝石项链",408080029},{"盛宴雕塑",408080039},{"花瓶",408080003}, {"唱片机",408080019},{"座钟",408080009},{"金块",408080024}, {"金杯",408080030},{"金魔方",408080028},{"金条箱",408990008}, {"暗区金兔",408990045},{"黄金战盔",408990065},{"白银战盔",408990066}, {"黄金水枪",408990156},{"黄金月饼",408990178},{"金汤匙",408990119}, {"金矿镐",408990241},{"金矿箱",408990164},{"猛攻雕像",408203030}, {"审判之眼雕像",408203032},{"塔奇克马雕像",408204023}, {"黄金密钥U盘",408208001},{"金色打火机",408980010}, {"黑金身份牌",408110011},{"金铭牌",408110002},{"手工制金币",408130004}, {"手表芯片",408990009},{"金色芯片",408990060},{"柯恩币模型",408990228}, } local items = {} for _, v in ipairs(raw) do table.insert(items, {name=v[1], id=v[2], pinyin=toPinyin(v[1]), lower=v[1]:lower()}) end state.itemCache = items return items end -- ========== 搜索物品 ========== local function searchItems(keyword) if not keyword or keyword == "" then return {} end if state.searchCache[keyword] then return state.searchCache[keyword] end local items = loadItems() local kw = keyword:lower() local kwPy = toPinyin(keyword) local matches = {} local exact, prefix, contain, pinyinMatch = {}, {}, {}, {} for _, item in ipairs(items) do if item.lower == kw then table.insert(exact, item) elseif item.lower:find("^" .. kw) then table.insert(prefix, item) elseif item.lower:find(kw) then table.insert(contain, item) elseif item.pinyin:find(kwPy) or item.pinyin:find(kw) then table.insert(pinyinMatch, item) end end for _, list in ipairs({exact, prefix, contain, pinyinMatch}) do for _, item in ipairs(list) do if #matches < 200 then table.insert(matches, item) end end end state.searchCache[keyword] = matches return matches end -- ========== 刀皮数据 ========== local knives = { {"空蝉回响",702011350},{"瑞兔折刀",702011316},{"瀚星斩铁",702011342}, {"急袭弯刀",702011322},{"开山刀",702011303},{"撬棍",702011304}, {"登山镐",702011305},{"工兵铲",702011306},{"军用弯刀",702011307}, {"突击匕首",702011308},{"伸缩棍",702011309},{"丛林猎刃",702011310}, {"查普曼铲",702011311},{"鲨鱼刀",702011312},{"勇士战斧",702011313}, {"冰海战斧",702011314},{"野战折刀",702011315},{"精英指虎",702011318}, {"霜狼生存刀",702011320},{"战术特遣·蝴蝶折叠刀",702011323}, {"烈焰战镰",702011324},{"裁决手杖剑",702011325},{"冬日冰镐",702011326}, {"恐惧战镰",702011327},{"龙魂·双截棍",702011328},{"明刀·绣春",702011329}, {"胜利军刀",702011331},{"涂鸦利刃",702011332},{"贝利亚黄昏",702011333}, {"下弦月",702011334},{"旧日主宰",702011335},{"寒牙手刺",702011336}, {"旧日主宰海外",702011337},{"盛冬利刃",702011338}, {"盘牙·彻甲短刃",702011339},{"三尺万仞·战术剑",702011340}, {"不屈烈怒",702011341},{"热能武器·补牢",702011343},{"赢家匕首",702011344}, {"S-07折刀",702011345},{"收割者",702011346},{"苍穹利爪",702011347}, {"空腔战术",702011348},{"棒球棍",702011349},{"百炼恒常",702011351}, {"幽燕钛玄",702011352},{"赤火炉心",702011353},{"赤火炉心2",702011354}, {"机动防卫·伸缩棍",702011355},{"资源产出中",702011356}, {"掠影·马来剑",702011357},{"惩戒·战术爪",702011358},{"碳鳞",702011359}, {"考古工具",702011360},{"原初之蛇",702011361},{"蛇涏",702011362}, {"曼陀罗",702011363},{"熔火",702011364},{"灰烬",702011365}, {"糖果陷阱",702011366},{"终焉",702011367},{"荒坂特战利刃",702011368}, {"收割者2",702011396},{"精神攻击",702011397},{"特制行军斧",702011398}, {"战术手斧",702011301}, } local knifeIdMap = {} for _, v in ipairs(knives) do knifeIdMap[v[2]] = v[1] end -- ========== 刀皮收藏 ========== local function loadKnifeFavorites() local data = readFile(CONFIG.KNIFE_FAV_FILE) if not data then state.knifeFavorites = {} return end state.knifeFavorites = {} for _, line in ipairs(data) do local id = tonumber(line) if id and knifeIdMap[id] then table.insert(state.knifeFavorites, id) end end end local function saveKnifeFavorites() local data = {} for _, id in ipairs(state.knifeFavorites) do table.insert(data, tostring(id)) end writeFile(CONFIG.KNIFE_FAV_FILE, data) end local function toggleKnifeFavorite(id) for i, v in ipairs(state.knifeFavorites) do if v == id then table.remove(state.knifeFavorites, i) saveKnifeFavorites() return false end end table.insert(state.knifeFavorites, id) saveKnifeFavorites() return true end local function isKnifeFavorite(id) for _, v in ipairs(state.knifeFavorites) do if v == id then return true end end return false end -- ============================================================ -- 核心功能:初始化地址(多级指针解析) -- ============================================================ -- ========== 获取内存区间 ========== local function getRanges() local ranges = {} local t = gg.getRangesList('^/data/*.so*$') for i, v in pairs(t) do if v.type:sub(2, 2) == 'w' then table.insert(ranges, v) end end return ranges end -- ========== 多级指针解析 ========== local function resolvePointer(soName, offsets, use64Bit) local ti = gg.getTargetInfo() local ranges = getRanges() local bitSize = use64Bit and 32 or 4 local targetRange = nil for i, v in pairs(ranges) do local name = v.internalName:gsub('^.*/', '') if soName[1] == name and soName[2] == v.state then targetRange = v break end end if not targetRange then return nil end local currentAddrs = {{address = targetRange.start + offsets[1], flags = bitSize}} for i = 2, #offsets do local values = safeGetValues(currentAddrs) if not values then return nil end currentAddrs = {} for _, v in ipairs(values) do if v and v.value then local addr = v.value if not ti.x64 then addr = addr & 0xFFFFFFFF end if addr > 0 then table.insert(currentAddrs, { address = addr + offsets[i], flags = bitSize }) end end end if #currentAddrs == 0 then return nil end end return currentAddrs[1].address end -- ========== 去重偏移组合 ========== local function deduplicateOffsets(offsetsList) local seen = {} local result = {} for _, offsets in ipairs(offsetsList) do local key = table.concat(offsets, ",") if not seen[key] then seen[key] = true table.insert(result, offsets) end end return result end -- ========== 从搜索列表加载地址 ========== local function loadAddressesFromSearch() local count = gg.getResultsCount() if not count or count == 0 then return nil end local fetchCount = math.min(count, 100) local results = gg.getResults(fetchCount) if not results or #results == 0 then return nil end local addrs = {} for _, r in ipairs(results) do if r and r.address then table.insert(addrs, r.address) end end if #addrs == 0 then return nil end return addrs end -- ========== 检测搜索列表是否有地址 ========== local function hasSearchResults() local count = gg.getResultsCount() return count and count > 0 end -- ========== 初始化刀皮地址 ========== local function initAddresses() -- 检测搜索列表是否已有地址 if hasSearchResults() then local addrs = loadAddressesFromSearch() if addrs and #addrs > 0 then -- 验证是否有有效地址 local checkCount = math.min(5, #addrs) local checkTbl = {} for i = 1, checkCount do table.insert(checkTbl, {address = addrs[i], flags = gg.TYPE_DWORD}) end local values = safeGetValues(checkTbl) local validCount = 0 if values then for _, v in ipairs(values) do if v and v.value and tonumber(v.value) == CONFIG.DEFAULT_KNIFE then validCount = validCount + 1 end end end if validCount > 0 then state.cachedAddrs = addrs state.addrCacheValid = true state.initialized = true gg.toast("搜索列表中已有 " .. #addrs .. " 个有效地址") return true end end end gg.toast("正在初始化刀皮地址...") -- 所有偏移组合 local allOffsets = { {0x2A15A8, 0x118, 0x1A0}, {0x2A15B0, 0x118, 0x1A0}, {0x2A2F60, 0x118, 0x30}, {0x2A2F68, 0x118, 0x30}, {0x299ED8, 0x30, 0x1F0, 0xE8, 0x1A0}, {0x299EE0, 0x30, 0x1F0, 0xE8, 0x1A0}, {0x299F00, 0x30, 0x1D0, 0xE8, 0x1A0}, {0x299F08, 0x30, 0x1D0, 0xE8, 0x1A0}, {0x299F70, 0x30, 0x1B0, 0xE8, 0x1A0}, {0x299F78, 0x30, 0x1B0, 0xE8, 0x1A0}, {0x29DCC8, 0x30, 0x90, 0xE8, 0x1A0}, {0x29DCC8, 0x30, 0x138, 0xE8, 0x30}, {0x29DCD0, 0x30, 0x90, 0xE8, 0x1A0}, {0x29DCD0, 0x30, 0x138, 0xE8, 0x30}, {0x2A0198, 0x30, 0x30, 0xE8, 0x1A0}, {0x2A0198, 0x30, 0xD8, 0xE8, 0x30}, {0x2A01A0, 0x30, 0x30, 0xE8, 0x1A0}, {0x2A01A0, 0x30, 0xD8, 0xE8, 0x30}, {0x2A15A8, 0x30, 0x10, 0xE8, 0x1A0}, {0x2A15A8, 0x30, 0xB8, 0xE8, 0x30}, {0x2A15A8, 0x118, 0x10, 0x118, 0x1A0}, {0x2A15B0, 0x30, 0x10, 0xE8, 0x1A0}, {0x2A15B0, 0x30, 0xB8, 0xE8, 0x30}, {0x2A15B0, 0x118, 0x10, 0x118, 0x1A0}, {0x2A15B8, 0x30, 0x98, 0xE8, 0x30}, {0x2A15C0, 0x30, 0x98, 0xE8, 0x30}, {0x2A15E0, 0x30, 0x78, 0xE8, 0x30}, {0x2A15E8, 0x30, 0x78, 0xE8, 0x30}, {0x2A2EF0, 0x30, 0x38, 0xE8, 0x30}, {0x2A2EF8, 0x30, 0x38, 0xE8, 0x30}, {0x2A2F60, 0x30, 0x18, 0xE8, 0x30}, {0x2A2F60, 0x118, 0x10, 0x118, 0x30}, {0x2A2F68, 0x30, 0x18, 0xE8, 0x30}, {0x2A2F68, 0x118, 0x10, 0x118, 0x30}, {0x73EAE0, 0x8, 0x58, 0x118, 0x30}, {0x79C4D8, 0x18, 0x10, 0x50, 0x30}, {0x7DC240, 0x30, 0xD0, 0xE8, 0x1A0}, {0x7DC240, 0x30, 0x178, 0xE8, 0x30}, {0x7DC248, 0x30, 0xD0, 0xE8, 0x1A0}, {0x7DC248, 0x30, 0x178, 0xE8, 0x30}, } local uniqueOffsets = deduplicateOffsets(allOffsets) local addresses = {} local failed = 0 for i, offsets in ipairs(uniqueOffsets) do local addr = nil for attempt = 1, CONFIG.RETRY_COUNT do addr = resolvePointer({"libUE4.so:bss", "Cb"}, offsets, true) if addr and addr > 0 then break end gg.sleep(50) end if addr and addr > 0 then table.insert(addresses, addr) else failed = failed + 1 end end if #addresses == 0 then gg.toast("初始化失败!请确保在游戏地图中") state.addrCacheValid = false state.initialized = false return false end -- 验证地址是否有效(读取值是否为M9 ID) local checkCount = math.min(10, #addresses) local checkTbl = {} for i = 1, checkCount do table.insert(checkTbl, {address = addresses[i], flags = gg.TYPE_DWORD}) end local values = safeGetValues(checkTbl) local validCount = 0 if values then for _, v in ipairs(values) do if v and v.value and tonumber(v.value) == CONFIG.DEFAULT_KNIFE then validCount = validCount + 1 end end end if validCount == 0 then gg.toast("初始化失败!地址验证不通过,请确保持有M9军刀") state.addrCacheValid = false state.initialized = false return false end -- 保存到缓存 state.cachedAddrs = addresses state.addrCacheValid = true state.initialized = true -- 保存到文件 local lines = {} for _, a in ipairs(addresses) do table.insert(lines, a) end writeFile(CONFIG.ADDR_FILE, lines) -- 添加到GG搜索列表 gg.clearResults() local searchResults = {} for _, addr in ipairs(addresses) do table.insert(searchResults, { address = addr, flags = gg.TYPE_DWORD, }) end gg.loadResults(searchResults) gg.toast(string.format("✅ 初始化成功!已缓存 %d 个地址", #addresses)) return true end -- ========== 获取地址(统一入口) ========== local function getAddresses() if state.addrCacheValid and state.cachedAddrs and #state.cachedAddrs > 0 then return state.cachedAddrs end -- 尝试从搜索列表加载 local addrs = loadAddressesFromSearch() if addrs and #addrs > 0 then state.cachedAddrs = addrs state.addrCacheValid = true state.initialized = true return addrs end -- 尝试从文件加载 addrs = readFile(CONFIG.ADDR_FILE) if addrs and #addrs > 0 then state.cachedAddrs = addrs state.addrCacheValid = true state.initialized = true return addrs end return nil end -- ========== 检查是否已初始化 ========== local function checkInitialized() if not state.initialized or not state.addrCacheValid or not state.cachedAddrs or #state.cachedAddrs == 0 then -- 尝试从搜索列表加载 local addrs = loadAddressesFromSearch() if addrs and #addrs > 0 then state.cachedAddrs = addrs state.addrCacheValid = true state.initialized = true return true end -- 尝试从文件加载 addrs = readFile(CONFIG.ADDR_FILE) if addrs and #addrs > 0 then state.cachedAddrs = addrs state.addrCacheValid = true state.initialized = true return true end gg.toast("请先执行「初始化」获取地址") return false end return true end -- ========== 修改值 ========== local function setKnifeValue(targetID, targetName) if not targetID or targetID <= 0 then gg.toast("无效的ID") return false end local addrs = getAddresses() if not addrs or #addrs == 0 then gg.toast("没有有效地址,请先执行初始化") return false end local total = #addrs local batchSize = CONFIG.BATCH_SIZE for startIdx = 1, total, batchSize do local endIdx = math.min(startIdx + batchSize - 1, total) local setTbl = {} for i = startIdx, endIdx do table.insert(setTbl, { address = addrs[i], flags = gg.TYPE_DWORD, value = targetID }) end if not safeSetValues(setTbl) then gg.toast("修改失败,请重试") return false end end local checkCount = math.min(20, total) local checkTbl = {} local indices = {} for i = 1, total do indices[i] = i end for i = #indices, 2, -1 do local j = math.random(i) indices[i], indices[j] = indices[j], indices[i] end for i = 1, checkCount do table.insert(checkTbl, {address = addrs[indices[i]], flags = gg.TYPE_DWORD}) end local after = safeGetValues(checkTbl) local successCount = 0 if after then for _, v in ipairs(after) do if v and v.value and tonumber(v.value) == targetID then successCount = successCount + 1 end end end gg.toast("改为 -> " .. targetName .. " (" .. successCount .. "/" .. checkCount .. " 成功)") return true end -- ========== 随机刀皮 ========== local function randomKnife() local k = knives[math.random(1, #knives)] setKnifeValue(k[2], k[1]) end -- ========== 分页显示 ========== local function showPaginatedWithFavorite(items, title) if #items == 0 then gg.toast("没有匹配的物品"); return end local total = #items local pageSize = CONFIG.PAGE_SIZE local totalPages = math.ceil(total / pageSize) local page = 1 while true do local start = (page - 1) * pageSize + 1 local finish = math.min(page * pageSize, total) local menu = {} for i = start, finish do local star = isItemFavorite(items[i].id) and "* " or " " table.insert(menu, star .. items[i].name .. " (" .. items[i].id .. ")") end table.insert(menu, "--- " .. page .. "/" .. totalPages .. " ---") if page < totalPages then table.insert(menu, "下一页") end if page > 1 then table.insert(menu, "上一页") end table.insert(menu, "取消") local choice = gg.choice(menu, nil, title .. " (" .. total .. "个, *已收藏)") if not choice or choice == #menu then return end if choice == #menu - 1 and page > 1 then page = page - 1 elseif choice == #menu - 2 and page < totalPages then page = page + 1 elseif choice <= total then local item = items[start + choice - 1] local isFav = isItemFavorite(item.id) local opt = gg.choice({"修改", isFav and "取消收藏" or "收藏"}, nil, item.name) if opt == 1 then setKnifeValue(item.id, item.name) return elseif opt == 2 then local added = toggleItemFavorite(item.id) gg.toast(added and "★ 已收藏" or "☆ 已取消收藏") loadItemFavorites() break end end end end -- ========== 物品收藏夹 ========== local function itemFavoriteMenu() loadItemFavorites() if #state.itemFavorites == 0 then gg.toast("物品收藏夹为空") return end local items = loadItems() local favItems = {} local idMap = {} for _, item in ipairs(items) do idMap[item.id] = item end for _, id in ipairs(state.itemFavorites) do local item = idMap[id] if item then table.insert(favItems, item) end end if #favItems == 0 then gg.toast("收藏的物品已不存在,请重新添加") return end showPaginatedWithFavorite(favItems, "物品收藏夹") end -- ========== 创建物品文件 ========== local function createItemFile() local template = [[ 机密文件 [ItemID: 408080027] 理想国试剂盒 [ItemID: 408080040] 金狮雕像 [ItemID: 408080008] 宝石项链 [ItemID: 408080029] ]] local f = io.open(CONFIG.ITEM_FILE, "w") if f then f:write(template); f:close(); gg.toast("已创建模板"); return true end return false end -- ========== 刀皮收藏 ========== local function knifeFavoriteMenu() loadKnifeFavorites() if #state.knifeFavorites == 0 then gg.toast("刀皮收藏为空") return end local menu = {} for _, id in ipairs(state.knifeFavorites) do local name = knifeIdMap[id] or "未知(" .. id .. ")" table.insert(menu, name .. " (" .. id .. ")") end table.insert(menu, "返回") local choice = gg.choice(menu, nil, "刀皮收藏") if choice and choice < #menu then local id = state.knifeFavorites[choice] local name = knifeIdMap[id] or "未知" setKnifeValue(id, name) end end -- ========== 修改刀皮菜单 ========== local function modifyMenu() if not checkInitialized() then return end loadKnifeFavorites() local page = 1 local totalPages = math.ceil(#knives / CONFIG.PAGE_SIZE) while true do local start = (page - 1) * CONFIG.PAGE_SIZE + 1 local finish = math.min(page * CONFIG.PAGE_SIZE, #knives) local menu = {} table.insert(menu, 1, "--- 功能 ---") table.insert(menu, 2, "随机刀皮") table.insert(menu, 3, "刀皮收藏") table.insert(menu, 4, "返回") local knifeStartIdx = #menu + 1 for i = start, finish do local star = isKnifeFavorite(knives[i][2]) and "* " or " " table.insert(menu, star .. knives[i][1] .. " (" .. knives[i][2] .. ")") end local knifeEndIdx = #menu table.insert(menu, "--- " .. page .. "/" .. totalPages .. " ---") local nextPageIdx = nil local prevPageIdx = nil if page < totalPages then table.insert(menu, "下一页") nextPageIdx = #menu end if page > 1 then table.insert(menu, "上一页") prevPageIdx = #menu end local choice = gg.choice(menu, nil, "选择刀皮 (*已收藏)") if not choice then return end if choice == 2 then randomKnife() return elseif choice == 3 then knifeFavoriteMenu() return elseif choice == 4 then return end if nextPageIdx and choice == nextPageIdx then page = page + 1 elseif prevPageIdx and choice == prevPageIdx then page = page - 1 elseif choice >= knifeStartIdx and choice <= knifeEndIdx then local knifeIndex = choice - knifeStartIdx + 1 local realIdx = start + knifeIndex - 1 if realIdx >= 1 and realIdx <= #knives then local id = knives[realIdx][2] local name = knives[realIdx][1] local isFav = isKnifeFavorite(id) local opt = gg.choice({"修改", isFav and "取消收藏" or "收藏"}, nil, name) if opt == 1 then setKnifeValue(id, name) return elseif opt == 2 then local added = toggleKnifeFavorite(id) gg.toast(added and "★ 已收藏" or "☆ 已取消收藏") loadKnifeFavorites() end end end end end -- ========== 修改物品菜单 ========== local function modifyItemMenu() if not checkInitialized() then return end if not fileExists(CONFIG.ITEM_FILE) then local choice = gg.choice({ "创建模板文件", "使用内置精简版", "返回" }, nil, "物品文件不存在") if choice == 1 then createItemFile() gg.alert("已创建模板\n请将数据放入:\n" .. CONFIG.ITEM_FILE) elseif choice == 2 then loadDefaultItems() gg.toast("已加载 " .. #state.itemCache .. " 个内置物品") end return end loadItemFavorites() while true do local menu = {"搜索物品", "物品收藏夹", "重新加载", "清除缓存", "返回"} local choice = gg.choice(menu, nil, "修改物品 | 共" .. (#loadItems() or 0) .. "个") if not choice or choice == #menu then return end if choice == 1 then gg.setVisible(true) local input = gg.prompt({"搜索关键词"}, {""}, {"text"}) gg.setVisible(false) if not input or not input[1] or input[1] == "" then gg.toast("请输入关键词") return end local matches = searchItems(input[1]) if #matches == 0 then gg.toast("未找到: " .. input[1]) else showPaginatedWithFavorite(matches, "搜索结果") end elseif choice == 2 then itemFavoriteMenu() elseif choice == 3 then state.itemCache = nil state.searchCache = {} loadItems() gg.toast("已重新加载") elseif choice == 4 then os.remove(CONFIG.ITEM_CACHE_FILE) os.remove(CONFIG.ITEM_FAV_FILE_NEW) state.itemCache = nil state.searchCache = {} state.itemFavorites = {} gg.toast("缓存已清除") end end end -- ========== 复制功能 ========== local maps = { {"农场", "open Farmland_715_Main"}, {"山谷", "open Valley_715_Main"}, {"北部山区", "open Lake_Main"}, {"前线要塞", "open Armory_Main"}, {"电视台", "open TVStation_Main"}, {"军港", "open CitySiege_Main"}, {"训练场", "open TutorialRange_Main"}, } local consoleCommands = { {"玩家复制体", "summon BP_UamCharacter_C"}, {"重新加载当前地图", "ReloadCurrentMap"}, {"保存关卡", "SaveWorld"}, {"锁120帧", "t.MaxFPS 120"}, {"广角视野", "fov 150"}, {"人物大小x10", "ChangeSize 10"}, {"屏幕百分比", "r.ScreenPercentage 100"}, {"关闭所有阴影", "r.ShadowQuality 0"}, {"最高阴影", "r.ShadowQuality 4"}, {"关闭环境光遮蔽", "r.AmbientOcclusion 0"}, {"关闭动态模糊", "r.MotionBlurQuality 0"}, {"关闭景深", "r.DepthOfField 0"}, {"关闭泛光", "r.Bloom 0"}, {"关闭反射", "r.ReflectionQuality 0"}, {"最低后处理", "sg.PostProcessQuality 0"}, {"显示碰撞体", "show collision"}, {"显示导航网格", "show nav"}, {"显示骨骼模型", "show skeletalmeshes"}, {"隐藏所有模型", "hide all"}, {"恢复显示全部", "show all"}, {"关闭灯光特效", "r.LightFunctionQuality 0"}, {"关闭屏幕空间反射", "r.SSR 0"}, {"最低色调映射", "r.TonemapperQuality 0"}, {"关闭雾气", "r.Fog 0"}, {"清空Niagara特效", "niagara.RemoveAllSystems"}, {"清空日志", "FlushLog"}, {"跳转指定地图", "Open 地图名"}, {"暂停游戏", "pause"}, } local function copyMenu() while true do local choice = gg.choice({ "复制地图代码", "复制刀皮ID", "复制控制台代码", "复制缓存地址", "返回" }, nil, "复制功能") if choice == 1 then local menu = {} for _, v in ipairs(maps) do table.insert(menu, v[1]) end table.insert(menu, "返回") local c = gg.choice(menu, nil, "选择地图") if c and c < #menu then gg.copyText(maps[c][2]); gg.toast("已复制") end elseif choice == 2 then local menu = {} for _, v in ipairs(knives) do table.insert(menu, v[1] .. " (" .. v[2] .. ")") end table.insert(menu, "返回") local c = gg.choice(menu, nil, "选择刀皮") if c and c < #menu then gg.copyText(tostring(knives[c][2])); gg.toast("已复制") end elseif choice == 3 then local menu = {} for _, v in ipairs(consoleCommands) do table.insert(menu, v[1]) end table.insert(menu, "返回") local c = gg.choice(menu, nil, "选择代码") if c and c < #menu then gg.copyText(consoleCommands[c][2]); gg.toast("已复制") end elseif choice == 4 then local addrs = getAddresses() if addrs and #addrs > 0 then gg.copyText(table.concat(addrs, "\n")) gg.toast("已复制 " .. #addrs .. " 个地址") else gg.toast("无缓存地址,请先初始化") end elseif choice == 5 or not choice then return end end end -- ========== 清理缓存 ========== local function clearAllCache() state.cachedAddrs = nil state.addrCacheValid = false state.initialized = false state.searchCache = {} state.itemFavorites = {} state.knifeFavorites = {} if fileExists(CONFIG.ADDR_FILE) then os.remove(CONFIG.ADDR_FILE) end if fileExists(CONFIG.KNIFE_FAV_FILE) then os.remove(CONFIG.KNIFE_FAV_FILE) end if fileExists(CONFIG.ITEM_FAV_FILE_NEW) then os.remove(CONFIG.ITEM_FAV_FILE_NEW) end if fileExists(CONFIG.ITEM_CACHE_FILE) then os.remove(CONFIG.ITEM_CACHE_FILE) end gg.toast("所有缓存已清理") end -- ========== 高级设置菜单 ========== local function advancedMenu() while true do local menu = { "清理所有缓存", "清除地址缓存", "重置全部配置", "返回" } local choice = gg.choice(menu, nil, "高级设置") if not choice or choice == #menu then return end if choice == 1 then clearAllCache() elseif choice == 2 then state.cachedAddrs = nil state.addrCacheValid = false state.initialized = false if fileExists(CONFIG.ADDR_FILE) then os.remove(CONFIG.ADDR_FILE) end gg.toast("地址缓存已清除") elseif choice == 3 then if gg.choice({"确认", "取消"}, nil, "重置所有配置?") == 1 then os.remove(CONFIG.CONFIG_FILE) os.remove(CONFIG.ADDR_FILE) os.remove(CONFIG.KNIFE_FAV_FILE) os.remove(CONFIG.ITEM_FAV_FILE_NEW) os.remove(CONFIG.ITEM_CACHE_FILE) state.cachedAddrs = nil state.addrCacheValid = false state.initialized = false state.itemCache = nil state.searchCache = {} state.itemFavorites = {} state.knifeFavorites = {} gg.toast("已重置所有配置") end end end end -- ========== 开发者 ========== local function showDevelopers() local info = "作者: 春秋大梦\nQQ: 3013991146\nQQ群: 784551820\n电报: " .. CONFIG.TELEGRAM gg.copyText(info) gg.alert("开发者信息已复制到剪贴板") end -- ========== 教程 ========== local function showTutorial() local text = [[ ========== 赛事服清梦工具 ]] .. CONFIG.VERSION .. [[ 使用教程 ========== 【使用流程】 1. 进入游戏地图(农场/山谷/电视台等) 2. 打开脚本,选择「初始化」 3. 脚本自动解析刀皮地址并缓存 4. 选择「修改刀皮」或「修改物品」 5. 选择目标即可修改 【初始化说明】 - 若搜索列表已有地址,自动识别并跳过初始化 - 必须在地图内执行,需持有M9军刀 - 成功后会缓存地址到搜索列表 【收藏功能】 - 刀皮列表和物品搜索结果中可选择"收藏" - 收藏夹独立展示,快速切换 - 刀皮收藏: /storage/emulated/0/春秋大梦_刀皮收藏.txt - 物品收藏: /storage/emulated/0/春秋大梦_物品收藏.txt 【刷物品】 1. 修改物品 -> 选择目标物品 2. 控制台执行: summon BP_UamCharacter_C 3. 复制体身上携带该物品并掉落 【重要提示】 - 切换地图后需重新初始化 - 地址缓存保存在 /knife_addrs.txt 【联系作者】 电报: ]] .. CONFIG.TELEGRAM .. [[ ========================================]] gg.copyText(text) gg.alert("教程已复制到剪贴板") end -- ========== 退出 ========== local function exitScript() if gg.choice({"确认", "取消"}, nil, "不玩了吗?") == 1 then gg.toast("再见!") os.exit() end end -- ========== 主菜单 ========== function Main() local menuTitle = "赛事服清梦工具(防闪退版) " .. CONFIG.VERSION .. "\n作者: 春秋大梦 | 电报: " .. CONFIG.TELEGRAM while true do -- 动态构建菜单 local menu = {} local menuIndex = {} -- 检测搜索列表是否有地址,决定是否显示初始化按钮 if not hasSearchResults() then table.insert(menu, "初始化") table.insert(menuIndex, "init") end table.insert(menu, "修改刀皮") table.insert(menuIndex, "knife") table.insert(menu, "修改物品") table.insert(menuIndex, "item") table.insert(menu, "复制功能") table.insert(menuIndex, "copy") table.insert(menu, "使用教程") table.insert(menuIndex, "tutorial") table.insert(menu, "开发名单") table.insert(menuIndex, "dev") table.insert(menu, "高级设置") table.insert(menuIndex, "advanced") table.insert(menu, "隐藏菜单") table.insert(menuIndex, "hide") table.insert(menu, "退出脚本") table.insert(menuIndex, "exit") local choice = gg.choice(menu, nil, menuTitle) if not choice then return end local action = menuIndex[choice] if action == "init" then initAddresses() elseif action == "knife" then modifyMenu() elseif action == "item" then modifyItemMenu() elseif action == "copy" then copyMenu() elseif action == "tutorial" then showTutorial() elseif action == "dev" then showDevelopers() elseif action == "advanced" then advancedMenu() elseif action == "hide" then gg.toast("脚本已隐藏,点击悬浮图标重新打开") return elseif action == "exit" then exitScript() end end end -- ========== 入口 ========== while true do if gg.isVisible(true) then gg.setVisible(false) Main() end gg.sleep(200) end