Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/models/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
MAAEND_SANITY_TASK_DETAIL_LABELS,
MAAEND_SANITY_TASK_FIELDS,
MAAEND_SANITY_TASK_LABELS,
MAAEND_STAGE_WITH_AB,
MAAEND_REWARDS_SET_OPTIONS,
MAAEND_TASKS,
MAAEND_SANITY_TASK_TYPES,
PLAN_CONSUMER_VALUES,
Expand Down Expand Up @@ -1170,7 +1170,7 @@ def getTags(self) -> str:
}
)

if detail_key in MAAEND_STAGE_WITH_AB:
if detail_key in MAAEND_REWARDS_SET_OPTIONS:
tags.append(
{
"text": (
Expand Down
577 changes: 225 additions & 352 deletions app/task/MaaEnd/AutoProxy.py

Large diffs are not rendered by default.

9 changes: 2 additions & 7 deletions app/task/MaaEnd/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,7 @@ async def check(self) -> str:
if (
self.task_info.mode == "AutoProxy"
and not (
Path(
Config.ScriptConfig[uuid.UUID(self.script_info.script_id)].get(
"Info", "Path"
)
)
/ "config/mxu-MaaEnd.json"
Path(script_config.get("Info", "Path")) / "config/mxu-MaaEnd.json"
).exists()
):
return "MaaEnd 配置文件不存在, 请检查 MaaEnd 路径设置或先启动 MaaEnd 完成配置文件生成!"
Expand Down Expand Up @@ -192,7 +187,7 @@ async def final_task(self):
await Config.ScriptConfig[uuid.UUID(self.script_info.script_id)].unlock()
logger.success(f"已解锁脚本配置 {self.script_info.script_id}")

if self.task_info.mode in ["AutoProxy"]:
if self.task_info.mode == "AutoProxy":
if self.emulator_manager is not None:
await self.emulator_manager.close(
self.script_config.get("Game", "EmulatorIndex")
Expand Down
11 changes: 4 additions & 7 deletions app/task/MaaEnd/resource_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,12 @@ def get_cached(

root_path = root_path.resolve()
with cls._cache_lock:
cached = cls._loader_cache.get(root_path)
if cached is not None and not force_reload:
return cached

if force_reload:
cls._loader_cache.pop(root_path, None)

if not force_reload:
loader = cls._load_from_disk_cache(root_path)
else:
loader = cls._loader_cache.get(root_path) or cls._load_from_disk_cache(
root_path
)
if loader is not None:
cls._loader_cache[root_path] = loader
return loader
Expand Down
15 changes: 14 additions & 1 deletion app/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,29 @@

import sys
import types
from typing import TYPE_CHECKING

from .constants import *
from .logger import get_logger
from .security import (
dpapi_encrypt,
dpapi_decrypt,
dpapi_encrypt,
format_exception_reason,
sanitize_log_message,
)

if TYPE_CHECKING:
from .LogMonitor import LogMonitor as LogMonitor
from .LogMonitor import strptime as strptime
from .ProcessManager import ProcessInfo as ProcessInfo
from .ProcessManager import ProcessManager as ProcessManager
from .ProcessManager import ProcessResult as ProcessResult
from .ProcessManager import ProcessRunner as ProcessRunner
from .ProcessManager import activate_window_by_pid as activate_window_by_pid
from .ProcessManager import has_visible_window as has_visible_window
from .ProcessManager import is_process_alive as is_process_alive
from .ProcessManager import is_process_running as is_process_running

_LAZY_EXPORTS = {
"LogMonitor": (".LogMonitor", "LogMonitor"),
"strptime": (".LogMonitor", "strptime"),
Expand Down
21 changes: 19 additions & 2 deletions app/utils/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,25 @@
}
"""MaaEnd协议空间任务选项列表"""

MAAEND_STAGE_WITH_AB = set(["OperatorEXP", "Promotions", "SkillUp", "WeaponTune"])
"""MAAEnd任务包含AB关的关卡列表"""
MAAEND_REWARDS_SET_OPTIONS = {
"OperatorEXP": (
"OperatorEXPRewardsSetOption",
{"RewardsSetA": "CognitiveCarriers", "RewardsSetB": "AdvancedCombatRecord"},
),
"Promotions": (
"PromotionsRewardsSetOption",
{"RewardsSetA": "Protoset", "RewardsSetB": "Protodisk"},
),
"SkillUp": (
"SkillUpRewardsSetOption",
{"RewardsSetA": "Protohedron", "RewardsSetB": "Protoprism"},
),
"WeaponTune": (
"WeaponTuneRewardsSetOption",
{"RewardsSetA": "HeavyCastDie", "RewardsSetB": "CastDie"},
),
}
"""MaaEnd含AB关关卡的奖励组选项: 关卡 -> (MaaEnd选项名, 奖励组 -> 产出)"""

MAAEND_TASK_GROUPS = {
"Sanity": {
Expand Down
87 changes: 15 additions & 72 deletions frontend/electron/services/issueReportCore.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import * as fs from 'fs'
import * as os from 'os'
import * as path from 'path'
import AdmZip = require('adm-zip')

import { getLogger } from './logger'
import { StreamingZipWriter } from './streamingZip'

const logger = getLogger('问题包')

export const MAX_ENTRY_BYTES = 25 * 1024 * 1024
export const MAX_ARCHIVE_BYTES = 95 * 1024 * 1024
const TEXT_EXTENSIONS = new Set([
'.cfg',
'.csv',
Expand All @@ -34,14 +32,11 @@ export interface ReportEntry {
path: string
sourceSize: number
storedSize: number
status: 'included' | 'truncated' | 'skipped'
reason?: string
}

export interface CollectorState {
zip: AdmZip
zip: StreamingZipWriter
entries: ReportEntry[]
archiveBytes: number
}

export interface HistoryLogCandidate {
Expand Down Expand Up @@ -175,37 +170,22 @@ export function discoverInstallations(
return installations
}

export function addEntry(
state: CollectorState,
archivePath: string,
sourceSize: number,
content: Buffer,
status: ReportEntry['status'],
reason?: string
): void {
state.zip.addFile(archivePath, content)
state.archiveBytes += content.byteLength
state.entries.push({
path: archivePath,
sourceSize,
storedSize: content.byteLength,
status,
reason,
})
export function createCollector(zipPath: string): CollectorState {
fs.mkdirSync(path.dirname(zipPath), { recursive: true })
return { zip: new StreamingZipWriter(zipPath), entries: [] }
}

export function addSkippedEntry(
export function addEntry(
state: CollectorState,
archivePath: string,
sourceSize: number,
reason: string
content: Buffer
): void {
state.zip.addBuffer(archivePath, content)
state.entries.push({
path: archivePath,
sourceSize,
storedSize: 0,
status: 'skipped',
reason,
storedSize: content.byteLength,
})
}

Expand Down Expand Up @@ -237,54 +217,22 @@ export function addDiagnosticFile(
return
}

const remainingBytes = MAX_ARCHIVE_BYTES - state.archiveBytes
if (remainingBytes <= 0) {
addSkippedEntry(state, archivePath, stat.size, '问题包已达到总大小限制')
return
}

if (isTextFile(sourcePath)) {
try {
const content = readDiagnosticContent(sourcePath)
if (content.byteLength <= MAX_ENTRY_BYTES && content.byteLength <= remainingBytes) {
addEntry(state, archivePath, stat.size, content, 'included')
return
}

const storedSize = Math.min(MAX_ENTRY_BYTES, remainingBytes)
if (storedSize <= 0) {
addSkippedEntry(state, archivePath, stat.size, '问题包已达到总大小限制')
return
}

const tail = content.subarray(content.byteLength - storedSize)
addEntry(
state,
`${archivePath}.tail`,
stat.size,
Buffer.concat([Buffer.from('[文件过大,仅保留文件末尾内容。]\n', 'utf-8'), tail]).subarray(
0,
storedSize
),
'truncated',
`原始文件超过 ${MAX_ENTRY_BYTES} 字节`
)
addEntry(state, archivePath, stat.size, content)
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
return
} catch (error) {
addSkippedEntry(state, archivePath, stat.size, `读取文本文件失败: ${String(error)}`)
logger.debug(`读取文本文件失败: ${sourcePath}, ${String(error)}`)
return
}
}

if (stat.size > MAX_ENTRY_BYTES || stat.size > remainingBytes) {
addSkippedEntry(state, archivePath, stat.size, '二进制文件超过问题包大小限制')
return
}

try {
addEntry(state, archivePath, stat.size, fs.readFileSync(sourcePath), 'included')
state.zip.addFile(archivePath, sourcePath)
state.entries.push({ path: archivePath, sourceSize: stat.size, storedSize: stat.size })
} catch (error) {
addSkippedEntry(state, archivePath, stat.size, `读取二进制文件失败: ${String(error)}`)
logger.debug(`读取二进制文件失败: ${sourcePath}, ${String(error)}`)
}
}

Expand Down Expand Up @@ -342,12 +290,7 @@ export function addSanitizedJsonFile(
} else {
const content = Buffer.from(`${JSON.stringify(sanitizeJsonValue(json), null, 2)}\n`, 'utf-8')
const sourceSize = fs.statSync(sourcePath).size
const remainingBytes = MAX_ARCHIVE_BYTES - state.archiveBytes
if (content.byteLength > MAX_ENTRY_BYTES || content.byteLength > remainingBytes) {
addSkippedEntry(state, archivePath, sourceSize, '脱敏配置超过问题包大小限制')
} else {
addEntry(state, archivePath, sourceSize, content, 'included')
}
addEntry(state, archivePath, sourceSize, content)
}
return true
} catch (error) {
Expand Down
12 changes: 4 additions & 8 deletions frontend/electron/services/maaEndIssueReportService.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import * as fs from 'fs'
import * as path from 'path'
import AdmZip = require('adm-zip')

import { getLogger } from './logger'
import {
CollectorState,
addDirectory,
addLatestMasHistoryLog,
addSanitizedJsonFile,
createCollector,
discoverInstallations,
resolveDataRoots,
} from './issueReportCore'
Expand All @@ -22,8 +20,7 @@ export interface MaaEndIssueReportResult {
}

export function createMaaEndIssueReport(appRoot: string, zipPath: string): MaaEndIssueReportResult {
const zip = new AdmZip()
const state: CollectorState = { zip, entries: [], archiveBytes: 0 }
const state = createCollector(zipPath)
const dataRoots = resolveDataRoots(appRoot)
const installations = discoverInstallations(dataRoots, {
configType: 'MaaEndConfig',
Expand Down Expand Up @@ -65,12 +62,11 @@ export function createMaaEndIssueReport(appRoot: string, zipPath: string): MaaEn
}

try {
fs.mkdirSync(path.dirname(zipPath), { recursive: true })
zip.writeZip(zipPath)
state.zip.finalize()
logger.info(`MaaEnd 问题包已导出: ${zipPath}`)
return {
success: true,
message: `MaaEnd 问题包导出成功,已收集 ${state.entries.filter(entry => entry.status !== 'skipped').length} 个文件`,
message: `MaaEnd 问题包导出成功,已收集 ${state.entries.length} 个文件`,
zipPath,
}
} catch (error) {
Expand Down
11 changes: 4 additions & 7 deletions frontend/electron/services/okNteIssueReportService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import * as fs from 'fs'
import * as path from 'path'
import AdmZip = require('adm-zip')

import { getLogger } from './logger'
import {
Expand All @@ -9,6 +7,7 @@ import {
addDiagnosticFile,
addDirectory,
addLatestMasHistoryLog,
createCollector,
discoverInstallations,
resolveDataRoots,
} from './issueReportCore'
Expand Down Expand Up @@ -53,8 +52,7 @@ export interface OkNteIssueReportResult {
}

export function createOkNteIssueReport(appRoot: string, zipPath: string): OkNteIssueReportResult {
const zip = new AdmZip()
const state: CollectorState = { zip, entries: [], archiveBytes: 0 }
const state = createCollector(zipPath)
const dataRoots = resolveDataRoots(appRoot)
const installations = discoverInstallations(dataRoots, {
configType: 'OkNteConfig',
Expand All @@ -80,12 +78,11 @@ export function createOkNteIssueReport(appRoot: string, zipPath: string): OkNteI
addLatestOkNteScriptLog(state, installations)

try {
fs.mkdirSync(path.dirname(zipPath), { recursive: true })
zip.writeZip(zipPath)
state.zip.finalize()
logger.info(`OK-NTE 问题包已导出: ${zipPath}`)
return {
success: true,
message: `OK-NTE 问题包导出成功,已收集 ${state.entries.filter(entry => entry.status !== 'skipped').length} 个文件`,
message: `OK-NTE 问题包导出成功,已收集 ${state.entries.length} 个文件`,
zipPath,
}
} catch (error) {
Expand Down
11 changes: 4 additions & 7 deletions frontend/electron/services/okwwIssueReportService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import * as fs from 'fs'
import * as path from 'path'
import AdmZip = require('adm-zip')

import { getLogger } from './logger'
import {
Expand All @@ -9,6 +7,7 @@ import {
addDiagnosticFile,
addDirectory,
addLatestMasHistoryLog,
createCollector,
discoverInstallations,
resolveDataRoots,
} from './issueReportCore'
Expand Down Expand Up @@ -53,8 +52,7 @@ export interface OkwwIssueReportResult {
}

export function createOkwwIssueReport(appRoot: string, zipPath: string): OkwwIssueReportResult {
const zip = new AdmZip()
const state: CollectorState = { zip, entries: [], archiveBytes: 0 }
const state = createCollector(zipPath)
const dataRoots = resolveDataRoots(appRoot)
const installations = discoverInstallations(dataRoots, {
configType: 'OkwwConfig',
Expand All @@ -80,12 +78,11 @@ export function createOkwwIssueReport(appRoot: string, zipPath: string): OkwwIss
addLatestOkwwScriptLog(state, installations)

try {
fs.mkdirSync(path.dirname(zipPath), { recursive: true })
zip.writeZip(zipPath)
state.zip.finalize()
logger.info(`OK-WW 问题包已导出: ${zipPath}`)
return {
success: true,
message: `OK-WW 问题包导出成功,已收集 ${state.entries.filter(entry => entry.status !== 'skipped').length} 个文件`,
message: `OK-WW 问题包导出成功,已收集 ${state.entries.length} 个文件`,
zipPath,
}
} catch (error) {
Expand Down
Loading
Loading