diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json deleted file mode 100644 index 432a85b..0000000 --- a/.config/dotnet-tools.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "csharpier": { - "version": "1.2.6", - "commands": [ - "csharpier" - ] - } - } -} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6edad4b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# EditorConfig (https://editorconfig.org) — Beanfun +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +# Rust / TOML follow Rust community convention. +[*.{rs,toml}] +indent_size = 4 + +# Markdown allows trailing whitespace (two-space line break). +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1e16023 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,10 @@ +# Force LF line endings for all text files, regardless of OS. +# Prevents CRLF issues in CI (rustfmt, prettier) on Windows runners. +* text=auto eol=lf + +# Ensure these are always treated as binary (no line-ending conversion). +*.png binary +*.ico binary +*.dll binary +*.exe binary +*.xml binary diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9d0c4ac --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 10 + + - package-ecosystem: cargo + directory: /src-tauri + schedule: + interval: weekly + open-pull-requests-limit: 10 + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + open-pull-requests-limit: 5 diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 4a41e50..9d6a803 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -4,21 +4,21 @@ on: workflow_dispatch: inputs: release_name: - description: "Release Name (leave empty to auto-generate)" + description: 'Release Name (leave empty to auto-generate)' required: false - default: "" + default: '' release_type: - description: "Release type" + description: 'Release type' required: true - default: "prerelease" + default: 'prerelease' type: choice options: - prerelease - release version_increment: - description: "Version increment type" + description: 'Version increment type' required: false - default: "patch" + default: 'patch' type: choice options: - patch @@ -30,47 +30,47 @@ env: jobs: build: + name: 'Build Beanfun.exe & Create Release' runs-on: windows-latest permissions: contents: write steps: - - name: Checkout Code + - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup .NET 8 - uses: actions/setup-dotnet@v5 + - name: Setup Node.js + uses: actions/setup-node@v4 with: - dotnet-version: "8.0.x" + node-version: '22' + cache: npm + cache-dependency-path: package-lock.json - - name: Prepare Version & Inject AssemblyInfo + - name: Install Rust (stable) + uses: dtolnay/rust-toolchain@stable + + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + with: + workspaces: src-tauri + + - name: Install frontend dependencies + run: npm ci + + - name: Prepare version id: prep_version shell: pwsh run: | - $file = Get-ChildItem -Path . -Filter "AssemblyInfo.cs" -Recurse | Select-Object -First 1 - if (-not $file) { Write-Error "AssemblyInfo.cs not found!"; exit 1 } - - $content = Get-Content $file.FullName -Raw - if ($content -match 'AssemblyVersion\("(\d+)\.(\d+)(?:\.\d+)?\.\*"\)') { + $cargoToml = Get-Content src-tauri/Cargo.toml -Raw + if ($cargoToml -match 'version\s*=\s*"(\d+)\.(\d+)\.(\d+)"') { $major = [int]$matches[1] $minor = [int]$matches[2] - } else { - $major = 5 - $minor = 8 - } - - git fetch --tags 2>$null - $tags = git tag -l "v$major.$minor.*.*" --sort=-v:refname - - $patch = 0 - $tagsArray = @($tags) - if ($tagsArray.Count -gt 0 -and $tagsArray[0]) { - $latestTag = $tagsArray[0] - if ($latestTag -match "^v\d+\.\d+\.(\d+)\.") { - $patch = [int]$matches[1] - } + $patch = [int]$matches[3] + } else { + Write-Error "Could not parse version from Cargo.toml" + exit 1 } $releaseType = "${{ github.event.inputs.release_type }}" @@ -82,44 +82,50 @@ jobs: 'minor' { $minor++; $patch=0 } 'patch' { $patch++ } } - } else { - $patch++ + } else { + $patch++ } $utcNow = (Get-Date).ToUniversalTime() $timestamp = $utcNow.ToString("yyMMddHHmm") $buildDateTime = $utcNow.ToString("yyyy-MM-dd HH:mm:ss") - $baseDate = (Get-Date -Year 2000 -Month 1 -Day 1).ToUniversalTime() - $build = [math]::Floor(($utcNow - $baseDate).TotalDays) - $revision = [math]::Floor($utcNow.TimeOfDay.TotalSeconds / 2) - - $infoVersion = "$major.$minor.$patch($timestamp)" - $tagName = "v$major.$minor.$patch.$timestamp" $semVer = "$major.$minor.$patch" + $infoVersion = "$semVer($timestamp)" + $tagName = "v$semVer.$timestamp" - Write-Host "🚀 New Version: $infoVersion" - - $content = $content -replace 'AssemblyVersion\(".*?"\)', "AssemblyVersion(`"$major.$minor.*`")" - if ($content -match 'AssemblyInformationalVersion') { - $content = $content -replace 'AssemblyInformationalVersion\(".*?"\)', "AssemblyInformationalVersion(`"$infoVersion`")" - } else { - $content += "`r`n[assembly: System.Reflection.AssemblyInformationalVersion(`"$infoVersion`")]" - } - if (-not $content.EndsWith("`n")) { $content += "`r`n" } - $content | Set-Content $file.FullName -NoNewline + Write-Host "Version: $infoVersion" "tag_name=$tagName" >> $env:GITHUB_OUTPUT "semantic_version=$semVer" >> $env:GITHUB_OUTPUT "info_version=$infoVersion" >> $env:GITHUB_OUTPUT "build_datetime=$buildDateTime" >> $env:GITHUB_OUTPUT - "build=$build" >> $env:GITHUB_OUTPUT - "revision=$revision" >> $env:GITHUB_OUTPUT - - name: Publish Application - run: dotnet publish Beanfun/Beanfun.csproj -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true -p:DebugType=none -p:InformationalVersion="${{ steps.prep_version.outputs.info_version }}" -o publish + - name: Update version in Cargo.toml, tauri.conf.json, package.json + shell: pwsh + run: | + $semVer = "${{ steps.prep_version.outputs.semantic_version }}" + + $cargo = Get-Content src-tauri/Cargo.toml -Raw -Encoding UTF8 + $cargo = $cargo -replace '(?m)^version\s*=\s*"[\d.]+"', "version = `"$semVer`"" + [System.IO.File]::WriteAllText("src-tauri/Cargo.toml", $cargo) + + $tauri = Get-Content src-tauri/tauri.conf.json -Raw -Encoding UTF8 + $tauri = $tauri -replace '"version"\s*:\s*"[\d.]+"', "`"version`": `"$semVer`"" + [System.IO.File]::WriteAllText("src-tauri/tauri.conf.json", $tauri) + + $pkg = Get-Content package.json -Raw -Encoding UTF8 + $pkg = $pkg -replace '"version"\s*:\s*"[\d.]+"', "`"version`": `"$semVer`"" + [System.IO.File]::WriteAllText("package.json", $pkg) + + - name: Build Tauri application (standalone exe) + run: npm run tauri build -- --no-bundle - - name: Prepare Release Notes + - name: Rename exe to Beanfun.exe + shell: cmd + run: ren src-tauri\target\release\beanfun.exe Beanfun.exe + + - name: Prepare release notes id: prep_release shell: pwsh env: @@ -132,16 +138,22 @@ jobs: "exists=$($exists.ToString().ToLower())" >> $env:GITHUB_OUTPUT if ($exists) { - Write-Host "⚠️ Tag $tag already exists. Skipping release creation." + Write-Host "Tag $tag already exists. Skipping release creation." exit 0 } - $lastRelease = gh api repos/${{ github.repository }}/releases --paginate 2>$null | ConvertFrom-Json | Sort-Object created_at -Descending | Select-Object -First 1 - $range = if ($lastRelease) { "$($lastRelease.tag_name)..HEAD" } else { "-n 30" } - $repoUrl = "${{ github.server_url }}/${{ github.repository }}" - $commits = git log $range --pretty=format:"- [%h]($repoUrl/commit/%H) %s - %an (%ad)" --date=short --no-merges + $lastRelease = gh api repos/${{ github.repository }}/releases --paginate 2>$null | ConvertFrom-Json | Sort-Object created_at -Descending | Select-Object -First 1 + + $logArgs = @('log', '--pretty=format:"- [%h](' + $repoUrl + '/commit/%H) %s - %an (%ad)"', '--date=short', '--no-merges') + if ($lastRelease) { + $logArgs += "$($lastRelease.tag_name)..HEAD" + } else { + $logArgs += '-n' + $logArgs += '30' + } + $commits = & git @logArgs $commitCount = if ($commits) { ($commits -split "`n").Count } else { 0 } $commitsText = if ($commits) { $commits -join "`n" } else { "No commits found" } @@ -152,15 +164,15 @@ jobs: $delimiter >> $env:GITHUB_OUTPUT "commit_count=$commitCount" >> $env:GITHUB_OUTPUT - - name: Create Release + - name: Create GitHub Release if: steps.prep_release.outputs.exists == 'false' uses: softprops/action-gh-release@v2 with: tag_name: ${{ steps.prep_version.outputs.tag_name }} name: > - ${{ - github.event.inputs.release_name != '' - && github.event.inputs.release_name + ${{ + github.event.inputs.release_name != '' + && github.event.inputs.release_name || format('v{0}', steps.prep_version.outputs.semantic_version) }} body: | @@ -191,21 +203,19 @@ jobs: |------|-------| | Full Build Version | ${{ steps.prep_version.outputs.info_version }} | | Build Date/Time (UTC) | ${{ steps.prep_version.outputs.build_datetime }} | - | MS Build Revision | ${{ steps.prep_version.outputs.build }}.${{ steps.prep_version.outputs.revision }} | | Source Commit | [View](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) | - files: publish/Beanfun.exe + files: src-tauri/target/release/Beanfun.exe draft: false prerelease: ${{ github.event.inputs.release_type == 'prerelease' }} - - name: Commit Version Change + - name: Commit version bump if: steps.prep_release.outputs.exists == 'false' shell: pwsh run: | - $file = Get-ChildItem -Path . -Filter "AssemblyInfo.cs" -Recurse | Select-Object -First 1 git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add $file.FullName + git add src-tauri/Cargo.toml src-tauri/tauri.conf.json package.json git commit -m "Bump version to ${{ steps.prep_version.outputs.semantic_version }} for release ${{ steps.prep_version.outputs.tag_name }}" git push diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..fb51e93 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,71 @@ +name: Lint, Format & Test + +on: + push: + branches: [code] + pull_request: + branches: [code] + workflow_dispatch: + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + frontend: + name: 'Frontend: ESLint / Prettier / TypeCheck / Vitest' + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: npm + cache-dependency-path: package-lock.json + + - name: Install dependencies + run: npm ci + + - name: ESLint + run: npm run lint + + - name: Prettier check + run: npm run format:check + + - name: Type check + run: npm run typecheck + + - name: Unit tests (Vitest) + run: npm run test + + rust: + name: 'Rust: fmt / Clippy / Test' + runs-on: windows-latest + defaults: + run: + working-directory: src-tauri + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Rust (stable) + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Cache Cargo + uses: Swatinem/rust-cache@v2 + with: + workspaces: src-tauri + + - name: cargo fmt + run: cargo fmt --all -- --check + + - name: cargo clippy + run: cargo clippy --all-targets -- -D warnings + + - name: cargo test + run: cargo test diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml deleted file mode 100644 index cd8281d..0000000 --- a/.github/workflows/format-check.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Format Check - -on: - push: - branches: [code] - pull_request: - branches: [code] - -jobs: - format: - runs-on: ubuntu-latest - - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.x - - - name: Restore Tools - run: dotnet tool restore - - - name: Check Formatting - run: dotnet csharpier check . diff --git a/.gitignore b/.gitignore index d294810..7b78b08 100644 --- a/.gitignore +++ b/.gitignore @@ -1,277 +1,42 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# DNX -project.lock.json -project.fragment.lock.json -artifacts/ - -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -#*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings +# Dependencies node_modules/ -orleans.codegen.cs - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -*.mdf -*.ldf -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings +# Build output +dist/ +dist-ssr/ +*.local -# Microsoft Fakes -FakesAssemblies/ +# Rust build output +target/ -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# Editor directories and files +.vscode/* +!.vscode/extensions.json .idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc -/Dotfuscated -/Build/Test -/Build/Tools +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? -# LocaleRemulator runtime artifacts -Beanfun/LRConfig.xml -Beanfun/LRHookx32.dll -Beanfun/LRHookx64.dll -Beanfun/LRProc.exe -Beanfun/LRSubMenus.dll +# OS files +Thumbs.db # AI tool local settings .claude/ # Local scripts sync-upstream.ps1 + +# Project-local task list (Cursor AI) +Todo.md diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..53fc3d1 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,12 @@ +dist/ +node_modules/ +src-tauri/target/ +src-tauri/gen/ +mockups/ +package-lock.json +*.lock + +# Auto-generated by `cargo run --example export_bindings` (tauri-specta). +# File ships its own `/* prettier-ignore */` header but prettier's +# CLI still flags it as unformatted, so ignore the whole path. +src/types/bindings.ts diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..be737e8 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,8 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100, + "tabWidth": 2, + "endOfLine": "lf" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..b9cd890 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar", "tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"] +} diff --git a/Beanfun.sln b/Beanfun.sln deleted file mode 100644 index 856127a..0000000 --- a/Beanfun.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32210.238 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Beanfun", "Beanfun\Beanfun.csproj", "{4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Debug|x64.ActiveCfg = Debug|x64 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Debug|x64.Build.0 = Debug|x64 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Debug|x86.ActiveCfg = Debug|Win32 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Debug|x86.Build.0 = Debug|Win32 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Release|Any CPU.Build.0 = Release|Any CPU - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Release|x64.ActiveCfg = Release|x64 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Release|x64.Build.0 = Release|x64 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Release|x86.ActiveCfg = Release|Win32 - {4B2F8D03-0C8F-4BAA-810D-DCACC37F5F87}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {D9F17966-B29B-4926-8EAD-44C6445E3565} - EndGlobalSection -EndGlobal diff --git a/Beanfun/API/WCDESComp.cs b/Beanfun/API/WCDESComp.cs deleted file mode 100644 index 448d569..0000000 --- a/Beanfun/API/WCDESComp.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Security.Cryptography; -using System.Text; - -namespace Beanfun -{ - class WCDESComp - { - public static string EncryStrHex(string str, string key) - { - try - { - using DES des = DES.Create(); - des.Mode = CipherMode.ECB; - des.Padding = PaddingMode.None; - des.Key = Encoding.ASCII.GetBytes(key); - byte[] byteArray = Encoding.ASCII.GetBytes(str); - ICryptoTransform desencrypt = des.CreateEncryptor(); - byte[] byteOUT = desencrypt.TransformFinalBlock(byteArray, 0, byteArray.Length); - return BitConverter.ToString(byteOUT).Replace("-", ""); - } - catch (Exception e) - { - Console.WriteLine("EncryptDESError:" + e.Message + "\n" + e.StackTrace); - return null; - } - } - - public static string DecryStrHex(string hexString, string key) - { - try - { - using DES des = DES.Create(); - des.Mode = CipherMode.ECB; - des.Padding = PaddingMode.None; - des.Key = Encoding.ASCII.GetBytes(key); - byte[] byteOUT = new byte[hexString.Length / 2]; - for (int i = 0; i < hexString.Length; i += 2) - { - byteOUT[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16); - } - ICryptoTransform desdecrypt = des.CreateDecryptor(); - return Encoding.ASCII.GetString( - desdecrypt.TransformFinalBlock(byteOUT, 0, byteOUT.Length) - ); - } - catch (Exception e) - { - Console.WriteLine("DecryptDESError:" + e.Message + "\n" + e.StackTrace); - return null; - } - } - } -} diff --git a/Beanfun/API/WindowsAPI.cs b/Beanfun/API/WindowsAPI.cs deleted file mode 100644 index cf0f950..0000000 --- a/Beanfun/API/WindowsAPI.cs +++ /dev/null @@ -1,255 +0,0 @@ -using System; -using System.Drawing; -using System.Runtime.InteropServices; -using System.Text; - -namespace Beanfun -{ - static class WindowsAPI - { - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); - - [DllImport("user32.dll", SetLastError = true)] - public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); - - [DllImport("user32.dll")] - public static extern bool SetForegroundWindow(IntPtr hWnd); - - [DllImport("user32.dll")] - public static extern byte MapVirtualKey(byte wCode, int wMap); - - public static void PostString(IntPtr hwnd, string input) - { - const int WM_CHAR = 0x102; - byte[] chars = ASCIIEncoding.ASCII.GetBytes(input); - foreach (byte ch in chars) - { - PostMessage(hwnd, WM_CHAR, ch, 0); - } - } - - public static void PostKey(IntPtr hWnd, uint wMsg, byte wParam) - { - PostMessage(hWnd, wMsg, wParam, MapVirtualKey(wParam, 0) << 16 + 1); - } - - [DllImport("user32.dll")] - public static extern int PostMessage(IntPtr hWnd, uint wMsg, int wParam, int lParam); - - [DllImport("user32.dll")] - public static extern bool ClientToScreen(IntPtr hWnd, ref System.Drawing.Point lpPoint); - - [DllImport("user32.dll")] - public static extern bool GetCursorPos(ref System.Drawing.Point lpPoint); - - [DllImport("user32.dll")] - public static extern int SetCursorPos(int x, int y); - - [DllImport("user32.dll", SetLastError = true)] - public static extern int GetWindowLong(IntPtr hWnd, int nIndex); - - [DllImport("user32.dll")] - public static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); - - [DllImport("user32.dll")] - public static extern int SetWindowCompositionAttribute( - IntPtr hwnd, - ref WindowCompositionAttributeData data - ); - - [StructLayout(LayoutKind.Sequential)] - private struct RECT - { - public int Left; - public int Top; - public int Right; - public int Bottom; - } - - [DllImport("user32.dll")] - private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect); - - public static Size GetClientAreaSize(IntPtr hWnd) - { - if (hWnd == IntPtr.Zero) - throw new ArgumentException(); - - if (GetClientRect(hWnd, out RECT clientRect)) - { - int width = clientRect.Right - clientRect.Left; - int height = clientRect.Bottom - clientRect.Top; - return new Size(width, height); - } - - return Size.Empty; - } - - public enum AccentState - { - ACCENT_DISABLED = 0, - - ACCENT_ENABLE_GRADIENT = 1, - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, - ACCENT_ENABLE_BLURBEHIND = 3, - ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, - ACCENT_INVALID_STATE = 5, - } - - [StructLayout(LayoutKind.Sequential)] - public struct AccentPolicy - { - public AccentState AccentState; - public int AccentFlags; - public int GradientColor; - public int AnimationId; - } - - [StructLayout(LayoutKind.Sequential)] - public struct WindowCompositionAttributeData - { - public WindowCompositionAttribute Attribute; - public IntPtr Data; - public int SizeOfData; - } - - public enum WindowCompositionAttribute - { - WCA_ACCENT_POLICY = 19, - } - - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - private static extern Int32 GetSystemDefaultLocaleName( - [Out] StringBuilder lpLocaleName, - Int32 cchLocaleName - ); - - public const Int32 LOCALE_NAME_MAX_LENGTH = 85; - - public static String GetSystemDefaultLocaleName() - { - StringBuilder lpLocaleName = new StringBuilder(LOCALE_NAME_MAX_LENGTH); - if (GetSystemDefaultLocaleName(lpLocaleName, LOCALE_NAME_MAX_LENGTH) > 0) - { - return lpLocaleName.ToString(); - } - - return null; - } - - [DllImport("kernel32.dll")] - public static extern IntPtr GetCurrentProcess(); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto)] - public static extern IntPtr GetModuleHandle(string moduleName); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr GetProcAddress( - IntPtr hModule, - [MarshalAs(UnmanagedType.LPStr)] string procName - ); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWow64Process(IntPtr hProcess, out bool wow64Process); - - [DllImport("kernel32.dll")] - public static extern bool AttachConsole(int processId); - - public enum BinaryType : uint - { - SCS_32BIT_BINARY = 0, // A 32-bit Windows-based application - SCS_64BIT_BINARY = 6, // A 64-bit Windows-based application. - SCS_DOS_BINARY = 1, // An MS-DOS � based application - SCS_OS216_BINARY = 5, // A 16-bit OS/2-based application - SCS_PIF_BINARY = 3, // A PIF file that executes an MS-DOS � based application - SCS_POSIX_BINARY = 4, // A POSIX � based application - SCS_WOW_BINARY = 2, // A 16-bit Windows-based application - } - - [DllImport("kernel32.dll")] - public static extern bool GetBinaryType( - string lpApplicationName, - out BinaryType lpBinaryType - ); - - public enum dwMapFlags : uint - { - NORM_IGNORECASE = 0x00000001, - NORM_IGNORENONSPACE = 0x00000002, - NORM_IGNORESYMBOLS = 0x00000004, - LCMAP_LOWERCASE = 0x00000100, - LCMAP_UPPERCASE = 0x00000200, - LCMAP_SORTKEY = 0x00000400, - LCMAP_BYTEREV = 0x00000800, - SORT_STRINGSORT = 0x00001000, - NORM_IGNOREKANATYPE = 0x00010000, - NORM_IGNOREWIDTH = 0x00020000, - LCMAP_HIRAGANA = 0x00100000, - LCMAP_KATAKANA = 0x00200000, - LCMAP_HALFWIDTH = 0x00400000, - LCMAP_FULLWIDTH = 0x00800000, - LCMAP_LINGUISTIC_CASING = 0x01000000, - LCMAP_SIMPLIFIED_CHINESE = 0x02000000, - LCMAP_TRADITIONAL_CHINESE = 0x04000000, - } - - [DllImport("kernel32.dll")] - public static extern int LCMapStringW( - int Locale, - uint dwMapFlags, - [MarshalAs(UnmanagedType.LPWStr)] string lpSrcStr, - int cchSrc, - [MarshalAs(UnmanagedType.LPWStr)] string lpDestStr, - int cchDest - ); - - [DllImport("user32.dll")] - private static extern bool OpenClipboard(IntPtr hWndNewOwner); - - [DllImport("user32.dll")] - private static extern bool CloseClipboard(); - - [DllImport("user32.dll")] - private static extern bool EmptyClipboard(); - - [DllImport("user32.dll")] - private static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem); - - [DllImport("kernel32.dll")] - private static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes); - - [DllImport("kernel32.dll")] - private static extern IntPtr GlobalLock(IntPtr hMem); - - [DllImport("kernel32.dll")] - private static extern bool GlobalUnlock(IntPtr hMem); - - private const uint CF_UNICODETEXT = 13; - private const uint GMEM_MOVEABLE = 0x0002; - - public static bool CopyText(string text) - { - if (!OpenClipboard(IntPtr.Zero)) - return false; - try - { - EmptyClipboard(); - int bytes = (text.Length + 1) * 2; - IntPtr hGlobal = GlobalAlloc(GMEM_MOVEABLE, (UIntPtr)bytes); - if (hGlobal == IntPtr.Zero) - return false; - IntPtr target = GlobalLock(hGlobal); - Marshal.Copy(text.ToCharArray(), 0, target, text.Length); - Marshal.WriteInt16(target, text.Length * 2, 0); - GlobalUnlock(hGlobal); - SetClipboardData(CF_UNICODETEXT, hGlobal); - return true; - } - finally - { - CloseClipboard(); - } - } - } -} diff --git a/Beanfun/App.xaml b/Beanfun/App.xaml deleted file mode 100644 index 313acf1..0000000 --- a/Beanfun/App.xaml +++ /dev/null @@ -1,17 +0,0 @@ - - - - Resources/#Segoe MDL2 Assets - - - - - - - diff --git a/Beanfun/App.xaml.cs b/Beanfun/App.xaml.cs deleted file mode 100644 index 03b9369..0000000 --- a/Beanfun/App.xaml.cs +++ /dev/null @@ -1,206 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Windows; -using System.Windows.Interop; -using System.Windows.Media; - -namespace Beanfun -{ - /// - /// App.xaml 的交互逻辑 - /// - public partial class App : Application - { - public static readonly Version OSVersion = Environment.OSVersion.Version; - public static readonly Version Win2000 = new Version(5, 0); - public static readonly Version WinXP = new Version(5, 1); - public static readonly Version Win2003 = new Version(5, 2); - public static readonly Version WinVista = new Version(6, 0); - public static readonly Version Win7 = new Version(6, 1); - public static readonly Version Win8 = new Version(6, 2); - public static readonly Version Win8_1 = new Version(6, 3); - public static readonly Version Win10 = new Version(10, 0); - public static readonly Version Win11 = new Version(10, 0, 22000, 0); - - public static MainWindow MainWnd - { - get - { - Window wnd = Current.MainWindow; - if (wnd != null && (typeof(MainWindow) == wnd.GetType())) - return (MainWindow)wnd; - else - return null; - } - } - - public static string LoginRegion = ConfigAppSettings.GetValue("loginRegion", "TW"); - public static int LoginMethod = int.Parse(ConfigAppSettings.GetValue("loginMethod", "0")); - - private void Main(object sender, StartupEventArgs e) - { - WindowsAPI.AttachConsole(-1); - - if (bool.Parse(ConfigAppSettings.GetValue("disableHardwareAcceleration", "false"))) - RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; - - I18n.LoadLanguage(ConfigAppSettings.GetValue("Language", null)); - - StartupUri = new Uri("MainWindow.xaml", UriKind.RelativeOrAbsolute); - } - - public bool compareFile(string path1, string path2) - { - using var hash = MD5.Create(); - using var stream_1 = File.OpenRead(path1); - byte[] hashByte_1 = hash.ComputeHash(stream_1); - - using var stream_2 = File.OpenRead(path2); - byte[] hashByte_2 = hash.ComputeHash(stream_2); - - return BitConverter.ToString(hashByte_1) == BitConverter.ToString(hashByte_2); - } - - private void Application_Exit(object sender, ExitEventArgs e) - { - if (MainWnd != null && MainWnd.bfClient != null) - try - { - MainWnd.bfClient.Logout(); - } - catch { } - } - - // --- 版本轉換邏輯 (處理幽靈點問題) --- - public static string ConvertVersion(Version version) - { - if (version < new Version(4, 1)) - return $"{version.Major}.{version.Minor}.{version.Build}({version.Revision})"; - - DateTime buildDate = new DateTime(2000, 1, 1) - .AddDays(version.Build) - .AddSeconds(version.Revision * 2); - - string timestamp = buildDate.ToString("yyMMddHHmm"); - - // 關鍵:如果 Build < 1000 代表係 Patch 號碼 - if (version.Build < 1000) - { - // 格式: 5.8.3(2604011114) - return $"{version.Major}.{version.Minor}.{version.Build}({timestamp})"; - } - else - { - // 格式: 5.8(2604011114) - return $"{version.Major}.{version.Minor}({timestamp})"; - } - } - - internal static string AssemblyVersion - { - get - { - var attr = Assembly - .GetExecutingAssembly() - .GetCustomAttribute(); - if (attr != null && !string.IsNullOrEmpty(attr.InformationalVersion)) - { - string ver = attr.InformationalVersion; - - int plusIndex = ver.IndexOf('+'); - if (plusIndex > 0) - ver = ver.Substring(0, plusIndex); - - if (ver.Contains("(")) - return ver; - } - - return ConvertVersion(Assembly.GetExecutingAssembly().GetName().Version); - } - } - - public static readonly string AppDir = Path.GetDirectoryName( - Process.GetCurrentProcess().MainModule.FileName - ); - - public static int ReleaseResource(string file) - { - string path = Path.Combine(AppDir, file); - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(file)) - { - if (stream != null) - { - if (File.Exists(path)) - { - var fileInfo = new FileInfo(path); - if (fileInfo.Length == stream.Length) - return 0; - - try - { - File.Delete(path); - } - catch - { - return -1; - } - } - - string dir = Path.GetDirectoryName(path); - if (!Directory.Exists(dir)) - Directory.CreateDirectory(dir); - - stream.Position = 0; - File.WriteAllBytes( - path, - new BinaryReader(stream).ReadBytes((int)stream.Length) - ); - return 1; - } - } - return -1; - } - - public static string GetMD5HashFromFile(string fileName) - { - try - { - using FileStream file = new FileStream( - fileName, - FileMode.Open, - FileAccess.Read, - FileShare.ReadWrite - ); - return GetMD5HashFromStream(file); - } - catch (Exception ex) - { - throw new Exception("GetMD5HashFromFile() fail, error: " + ex.Message); - } - } - - public static string GetMD5HashFromStream(Stream stream) - { - try - { - using MD5 md5 = MD5.Create(); - byte[] retVal = md5.ComputeHash(stream); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < retVal.Length; i++) - { - sb.Append(retVal[i].ToString("x2")); - } - return sb.ToString(); - } - catch (Exception ex) - { - throw new Exception("GetMD5HashFromStream() fail, error: " + ex.Message); - } - } - } -} diff --git a/Beanfun/Beanfun.csproj b/Beanfun/Beanfun.csproj deleted file mode 100644 index dc7918a..0000000 --- a/Beanfun/Beanfun.csproj +++ /dev/null @@ -1,86 +0,0 @@ - - - WinExe - net8.0-windows - true - true - Beanfun - Beanfun - Resources\icon.ico - Properties\app.manifest - Beanfun.App - true - false - false - - $(NoWarn);CA1416;SYSLIB0014 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - True - True - Resources.resx - - - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - LRConfig.xml - - - LRHookx32.dll - - - LRHookx64.dll - - - LRProc.exe - - - LRSubMenus.dll - - - diff --git a/Beanfun/Helper/AccountManager.cs b/Beanfun/Helper/AccountManager.cs deleted file mode 100644 index d609cbb..0000000 --- a/Beanfun/Helper/AccountManager.cs +++ /dev/null @@ -1,554 +0,0 @@ -/* - * 開發此功能主要用為多帳號時儲存 - * 以原有加解密寫法為基礎 - * 加上一層wrapper並用Serializable方式儲存資料 - * thanks to Stackoverflow :p - * http://stackoverflow.com/questions/5869922/c-sharp-encrypt-serialized-file-before-writing-to-disk - * http://stackoverflow.com/questions/16352879/write-list-of-objects-to-a-file - * - * Date: 2016/3/1 - * Author: 葉家郡 (a.k.a 某數) - */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using Newtonsoft.Json; -using Utility.ModifyRegistry; - -namespace Beanfun -{ - [Serializable] - class AccountRecords - { - public List regionList = null, - accountList = null, - passwdList = null, - verifyList = null; - public List methodList = null; - public List autoLoginList = null; - } - - [Serializable] - class Records - { - public List regionList = null, - accountList = null, - accountNameList = null, - passwdList = null, - verifyList = null; - public List methodList = null; - public List autoLoginList = null; - - public static Records Change(object oldRecords) - { - Records res = new Records(); - if (oldRecords is AccountRecords) - { - AccountRecords records = (AccountRecords)oldRecords; - res.regionList = records.regionList; - res.accountList = records.accountList; - res.passwdList = records.passwdList; - res.verifyList = records.verifyList; - res.methodList = records.methodList; - res.autoLoginList = records.autoLoginList; - } - return res; - } - } - - public class AccountManager - { - private static readonly log4net.ILog log = log4net.LogManager.GetLogger( - typeof(AccountManager) - ); - - private Records accountRecords = null; - private string dataPath = - System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData) - + "\\Beanfun\\Users.dat"; - - public bool init() - { - return loadRecord(); - } - - #region helper function - private void accRecInit() - { - if (accountRecords == null) - accountRecords = new Records(); - - if (accountRecords.accountList == null) - accountRecords.accountList = new List(); - - if (accountRecords.regionList == null) - accountRecords.regionList = new List(); - if (accountRecords.regionList.Count < accountRecords.accountList.Count) - { - for ( - int i = accountRecords.regionList.Count; - i < accountRecords.accountList.Count; - i++ - ) - { - accountRecords.regionList.Add("TW"); - } - } - - if (accountRecords.accountNameList == null) - accountRecords.accountNameList = new List(); - if (accountRecords.accountNameList.Count < accountRecords.accountList.Count) - { - for ( - int i = accountRecords.accountNameList.Count; - i < accountRecords.accountList.Count; - i++ - ) - { - accountRecords.accountNameList.Add(""); - } - } - - if (accountRecords.passwdList == null) - accountRecords.passwdList = new List(); - if (accountRecords.passwdList.Count < accountRecords.accountList.Count) - { - for ( - int i = accountRecords.passwdList.Count; - i < accountRecords.accountList.Count; - i++ - ) - { - accountRecords.passwdList.Add(""); - } - } - - if (accountRecords.verifyList == null) - accountRecords.verifyList = new List(); - if (accountRecords.verifyList.Count < accountRecords.accountList.Count) - { - for ( - int i = accountRecords.verifyList.Count; - i < accountRecords.accountList.Count; - i++ - ) - { - accountRecords.verifyList.Add(""); - } - } - - if (accountRecords.methodList == null) - accountRecords.methodList = new List(); - if (accountRecords.methodList.Count < accountRecords.accountList.Count) - { - for ( - int i = accountRecords.methodList.Count; - i < accountRecords.accountList.Count; - i++ - ) - { - accountRecords.methodList.Add(0); - } - } - - if (accountRecords.autoLoginList == null) - accountRecords.autoLoginList = new List(); - if (accountRecords.autoLoginList.Count < accountRecords.accountList.Count) - { - for ( - int i = accountRecords.autoLoginList.Count; - i < accountRecords.accountList.Count; - i++ - ) - { - accountRecords.autoLoginList.Add(false); - } - } - } - - private bool loadRecord() - { - var raw = readRawData(); - if (raw != null) - { - try - { - // 嘗試以新版 JSON 格式讀取資料 - accountRecords = JsonConvert.DeserializeObject(raw); - } - catch - { - accountRecords = null; - // 解析失敗時,自動視為舊版 BinaryFormatter 格式並嘗試進行無縫轉換 - TryAutoMigrateLegacyData(raw); - } - } - accRecInit(); - - return true; - } - - private bool storeRecord() - { - string json = JsonConvert.SerializeObject(accountRecords); - writeRawData(json); - return true; - } - #endregion - - #region rawdata IO - /* - * read ciphertext from File - * decrypt it and return - */ - private string readRawData() - { - try - { - if (File.Exists(dataPath)) - { - try - { - Byte[] cipher = File.ReadAllBytes(dataPath); - ModifyRegistry myRegistry = new ModifyRegistry(); - myRegistry.BaseRegistryKey = Microsoft.Win32.Registry.CurrentUser; - string entropy = myRegistry.Read("Entropy"); - byte[] plaintext = ProtectedData.Unprotect( - cipher, - Encoding.UTF8.GetBytes(entropy), - DataProtectionScope.CurrentUser - ); - return Encoding.UTF8.GetString(plaintext); - } - catch - { - File.Delete(dataPath); - } - } - - return null; - } - catch - { - return null; - } - } - - /* - * encrypt plaintext and store to File - * and save key in Program Setting - */ - private void writeRawData(string plaintext) - { - using (BinaryWriter writer = new BinaryWriter(File.Open(dataPath, FileMode.Create))) - { - var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - var random = new Random(); - string entropy = new string( - Enumerable.Repeat(chars, 8).Select(s => s[random.Next(s.Length)]).ToArray() - ); - - ModifyRegistry myRegistry = new ModifyRegistry(); - myRegistry.BaseRegistryKey = Microsoft.Win32.Registry.CurrentUser; - myRegistry.Write("Entropy", entropy); - - writer.Write(ciphertext(plaintext, entropy)); - } - } - - private byte[] ciphertext(string plaintext, string key) - { - byte[] plainByte = Encoding.UTF8.GetBytes(plaintext); - byte[] entropy = Encoding.UTF8.GetBytes(key); - return ProtectedData.Protect(plainByte, entropy, DataProtectionScope.CurrentUser); - } - #endregion - - #region Interface - public bool addAccount( - string region, - string account, - string name, - string password, - string verify, - int method, - bool autoLogin - ) - { - return addAccount(-1, region, account, name, password, verify, method, autoLogin); - } - - public bool addAccount( - int index, - string region, - string account, - string name, - string password, - string verify, - int method, - bool autoLogin - ) - { - bool isExists = false; - List regionIndex = new List(); - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if (region != accountRecords.regionList[i]) - { - continue; - } - if (account == accountRecords.accountList[i]) - { - if (index > -1 && regionIndex.Count != index) - { - removeAccount(region, account); - i--; - continue; - } - accountRecords.accountNameList[i] = name; - accountRecords.passwdList[i] = password; - accountRecords.verifyList[i] = verify; - accountRecords.methodList[i] = method; - accountRecords.autoLoginList[i] = autoLogin; - isExists = true; - break; - } - regionIndex.Add(i); - } - - if (!isExists) - { - if (index < 0 || regionIndex.Count <= index) - { - accountRecords.regionList.Add(region); - accountRecords.accountList.Add(account); - accountRecords.accountNameList.Add(name); - accountRecords.passwdList.Add(password); - accountRecords.verifyList.Add(verify); - accountRecords.methodList.Add(method); - accountRecords.autoLoginList.Add(autoLogin); - } - else - { - index = regionIndex[index]; - accountRecords.regionList.Insert(index, region); - accountRecords.accountList.Insert(index, account); - accountRecords.accountNameList.Insert(index, name); - accountRecords.passwdList.Insert(index, password); - accountRecords.verifyList.Insert(index, verify); - accountRecords.methodList.Insert(index, method); - accountRecords.autoLoginList.Insert(index, autoLogin); - } - } - - storeRecord(); - - return true; - } - - public string getNameByAccount(string region, string account) - { - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if ( - account == accountRecords.accountList[i] - && region == accountRecords.regionList[i] - ) - { - return accountRecords.accountNameList[i]; - } - } - return null; - } - - public string getPasswordByAccount(string region, string account) - { - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if ( - account == accountRecords.accountList[i] - && region == accountRecords.regionList[i] - ) - { - return accountRecords.passwdList[i]; - } - } - return null; - } - - public string getVerifyByAccount(string region, string account) - { - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if ( - account == accountRecords.accountList[i] - && region == accountRecords.regionList[i] - ) - { - return accountRecords.verifyList[i]; - } - } - return null; - } - - public int getMethodByAccount(string region, string account) - { - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if ( - account == accountRecords.accountList[i] - && region == accountRecords.regionList[i] - ) - { - return accountRecords.methodList[i]; - } - } - return -1; - } - - public bool getAutoLoginByAccount(string region, string account) - { - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if ( - account == accountRecords.accountList[i] - && region == accountRecords.regionList[i] - ) - { - return accountRecords.autoLoginList[i]; - } - } - return false; - } - - public bool removeAccount(string region, string account) - { - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if ( - account == accountRecords.accountList[i] - && region == accountRecords.regionList[i] - ) - { - accountRecords.regionList.RemoveAt(i); - accountRecords.accountList.RemoveAt(i); - accountRecords.accountNameList.RemoveAt(i); - accountRecords.passwdList.RemoveAt(i); - accountRecords.verifyList.RemoveAt(i); - accountRecords.methodList.RemoveAt(i); - accountRecords.autoLoginList.RemoveAt(i); - - storeRecord(); - return true; - } - } - return false; - } - - public string[] getAccountList() - { - return accountRecords.accountList.ToArray(); - } - - public string[] getAccountList(string region) - { - List accList = new List(); - for (int i = 0; i < accountRecords.accountList.Count; ++i) - { - if (region == accountRecords.regionList[i]) - { - accList.Add(accountRecords.accountList[i]); - } - } - return accList.ToArray(); - } - - public bool importRecord(string raw) - { - try - { - accountRecords = JsonConvert.DeserializeObject(raw); - accRecInit(); - storeRecord(); - return true; - } - catch - { - // 匯入失敗時,嘗試將其視為舊版格式進行轉換 - return TryAutoMigrateLegacyData(raw); - } - } - - public string exportRecord() - { - return JsonConvert.SerializeObject(accountRecords); - } - #endregion - - #region Legacy format migration - // Fix #182: 實作內建的舊版資料自動升級機制,取代原先會導致 404 的外部轉換工具 - // TODO: 此升級機制僅為過渡用途。建議於發布幾個版本後,確認多數活躍玩家皆已轉換至 JSON 格式時,將此方法徹底移除。 - private bool TryAutoMigrateLegacyData(string raw) - { - try - { - byte[] cipher; - try - { - cipher = Convert.FromBase64String(raw); - } - catch (FormatException) - { - return false; - } - using (var stream = new MemoryStream(cipher)) - { - // 忽略編譯器針對 BinaryFormatter 的安全性警告 - // 注意:此類別極度不安全,僅限於此處讀取舊版資料使用,新代碼嚴禁使用! -#pragma warning disable SYSLIB0011 - var bformatter = - new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); - object oldRecords = bformatter.Deserialize(stream); -#pragma warning restore SYSLIB0011 - - if (oldRecords != null) - { - // 透過 JSON 序列化作為中介,避免類別轉型 (Casting) 發生例外狀況 - string tempJson = JsonConvert.SerializeObject(oldRecords); - accountRecords = JsonConvert.DeserializeObject(tempJson); - - if (accountRecords != null) - { - accRecInit(); - storeRecord(); // 立即將轉換後的資料以最新 JSON 格式寫入,覆寫舊檔 - - log.Info("Legacy account data auto-migrated to JSON format."); - System.Windows.MessageBox.Show( - System.Windows.Application.Current.TryFindResource( - "LegacyDataMigrateSuccess" - ) as string, - System.Windows.Application.Current.TryFindResource( - "LegacyDataMigrateTitle" - ) as string, - System.Windows.MessageBoxButton.OK, - System.Windows.MessageBoxImage.Information - ); - return true; - } - } - } - } - catch (Exception ex) - { - // 若因 .NET 版本限制或資料損毀導致轉換失敗,則記錄錯誤,並讓 accRecInit 建立新的空白紀錄 - log.Error($"Auto-migration of legacy data failed: {ex.Message}"); - } - - return false; - } - #endregion - } -} diff --git a/Beanfun/Helper/ConfigAppSettings.cs b/Beanfun/Helper/ConfigAppSettings.cs deleted file mode 100644 index 1566415..0000000 --- a/Beanfun/Helper/ConfigAppSettings.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Configuration; -using System.IO; - -namespace Beanfun -{ - class ConfigAppSettings - { - public static void SetValue(string key, string value) - { - try - { - ExeConfigurationFileMap map = new ExeConfigurationFileMap(); - map.ExeConfigFilename = - System.Environment.GetFolderPath( - System.Environment.SpecialFolder.ApplicationData - ) + "\\Beanfun\\Config.xml"; - Configuration config = ConfigurationManager.OpenMappedExeConfiguration( - map, - ConfigurationUserLevel.None - ); - if (config.AppSettings.Settings[key] == null) - { - if (value != null) - config.AppSettings.Settings.Add(key, value); - } - else - { - if (value == null) - config.AppSettings.Settings.Remove(key); - else - config.AppSettings.Settings[key].Value = value; - } - config.Save(ConfigurationSaveMode.Modified); - ConfigurationManager.RefreshSection("appSettings"); - } - catch - { - try - { - string filePath = - System.Environment.GetFolderPath( - System.Environment.SpecialFolder.ApplicationData - ) + "\\Beanfun"; - DirectoryInfo dir = new DirectoryInfo(filePath); - FileSystemInfo[] fileinfo = dir.GetFileSystemInfos("Config.xml"); - foreach (FileSystemInfo i in fileinfo) - { - if (i is DirectoryInfo) - { - DirectoryInfo subdir = new DirectoryInfo(i.FullName); - subdir.Delete(true); - } - else - { - File.Delete(i.FullName); - } - } - SetValue(key, value); - } - catch { } - } - } - - public static string GetValue(string key) - { - return GetValue(key, string.Empty); - } - - public static string GetValue(string key, string def) - { - string value; - try - { - ExeConfigurationFileMap map = new ExeConfigurationFileMap(); - map.ExeConfigFilename = - System.Environment.GetFolderPath( - System.Environment.SpecialFolder.ApplicationData - ) + "\\Beanfun\\Config.xml"; - Configuration config = ConfigurationManager.OpenMappedExeConfiguration( - map, - ConfigurationUserLevel.None - ); - value = - config.AppSettings.Settings[key] == null - ? def - : config.AppSettings.Settings[key].Value; - } - catch - { - value = def; - } - return value; - } - } -} diff --git a/Beanfun/Helper/I18n.cs b/Beanfun/Helper/I18n.cs deleted file mode 100644 index e098a1f..0000000 --- a/Beanfun/Helper/I18n.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Reflection; -using System.Windows; -using System.Windows.Markup; - -namespace Beanfun -{ - class I18n - { - public static string CultureName { get; set; } - public static List CultureArray { get; } = new List(); - - internal static void LoadLanguage(string lang = null) - { - CultureInfo currentCultureInfo; - if (lang == null) - currentCultureInfo = CultureInfo.CurrentUICulture; - else - { - currentCultureInfo = CultureInfo.GetCultureInfo(lang); - if (currentCultureInfo == null) - currentCultureInfo = CultureInfo.CurrentUICulture; - } - - CultureName = currentCultureInfo.Name; - CultureArray.Clear(); - while (true) - { - if (string.IsNullOrEmpty(currentCultureInfo.Name)) - break; - CultureArray.Insert(0, currentCultureInfo.Name); - currentCultureInfo = currentCultureInfo.Parent; - } - - ResourceDictionary defaultDict = null; - if (Application.Current.Resources.MergedDictionaries.Count > 0) - defaultDict = Application.Current.Resources.MergedDictionaries[0]; - Application.Current.Resources.MergedDictionaries.Clear(); - if (defaultDict != null) - Application.Current.Resources.MergedDictionaries.Add(defaultDict); - - try - { - var langDir = Path.Combine(AppContext.BaseDirectory, @"Lang\"); - - ResourceDictionary dictionary = null; - string langPath = null; - string langUri = null; - foreach (string cultureName in CultureArray) - { - langPath = Path.Combine(langDir, cultureName + ".xaml"); - if (File.Exists(langPath)) - dictionary = - XamlReader.Load(new FileStream(langPath, FileMode.Open)) - as ResourceDictionary; - else if (!cultureName.ToUpper().Equals("ZH")) - { - langUri = $@"/Beanfun;Component/Lang/{cultureName}.xaml"; - try - { - dictionary = new ResourceDictionary - { - Source = new Uri(langUri, UriKind.Relative), - }; - } - catch { } - } - - if (dictionary != null) - Application.Current.Resources.MergedDictionaries.Add(dictionary); - } - } - catch { } - - if (Application.Current.Resources.MergedDictionaries.Count <= 0) - throw new Exception("No language file."); - } - - internal static string ToSimplified(string argSource) - { - if (!CultureArray.Contains("zh-Hans")) - return argSource; - var t = new String(' ', argSource.Length); - WindowsAPI.LCMapStringW( - CultureInfo.CurrentUICulture.LCID, - (int)WindowsAPI.dwMapFlags.LCMAP_SIMPLIFIED_CHINESE, - argSource, - argSource.Length, - t, - argSource.Length - ); - return t; - } - } -} diff --git a/Beanfun/Helper/ModifyRegistry.cs b/Beanfun/Helper/ModifyRegistry.cs deleted file mode 100644 index b92df90..0000000 --- a/Beanfun/Helper/ModifyRegistry.cs +++ /dev/null @@ -1,278 +0,0 @@ -/* *************************************** - * ModifyRegistry.cs - * --------------------------------------- - * a very simple class - * to read, write, delete and count - * registry values with C# - * --------------------------------------- - * if you improve this code - * please email me your improvement! - * --------------------------------------- - * by Francesco Natali - * - fn.varie@libero.it - - * ***************************************/ - -using System; -// and for the MessageBox function: -using System.Windows; -// it's required for reading/writing into the registry: -using Microsoft.Win32; - -namespace Utility.ModifyRegistry -{ - /// - /// An useful class to read/write/delete/count registry keys - /// - class ModifyRegistry - { - private bool showError = false; - - /// - /// A property to show or hide error messages - /// (default = false) - /// - public bool ShowError - { - get { return showError; } - set { showError = value; } - } - - private string subKey = - "SOFTWARE\\" + Application.ResourceAssembly.GetName().Name.ToUpper(); - - /// - /// A property to set the SubKey value - /// (default = "SOFTWARE\\" + Application.ProductName.ToUpper()) - /// - public string SubKey - { - get { return subKey; } - set { subKey = value; } - } - - private RegistryKey baseRegistryKey = Registry.LocalMachine; - - /// - /// A property to set the BaseRegistryKey value. - /// (default = Registry.LocalMachine) - /// - public RegistryKey BaseRegistryKey - { - get { return baseRegistryKey; } - set { baseRegistryKey = value; } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// To read a registry key. - /// input: KeyName (string) - /// output: value (string) - /// - public string Read(string KeyName) - { - // Opening the registry key - RegistryKey rk = baseRegistryKey; - // Open a subKey as read-only - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistrySubKey doesn't exist -> (null) - if (sk1 == null) - { - return null; - } - else - { - try - { - // If the RegistryKey exists I get its value - // or null is returned. - return (string)sk1.GetValue(KeyName.ToUpper()); - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Reading registry " + KeyName.ToUpper()); - return null; - } - } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// To write into a registry key. - /// input: KeyName (string) , Value (object) - /// output: true or false - /// - public bool Write(string KeyName, object Value) - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - // I have to use CreateSubKey - // (create or open it if already exits), - // 'cause OpenSubKey open a subKey as read-only - RegistryKey sk1 = rk.CreateSubKey(subKey); - // Save the value - sk1.SetValue(KeyName.ToUpper(), Value); - - return true; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Writing registry " + KeyName.ToUpper()); - return false; - } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// To delete a registry key. - /// input: KeyName (string) - /// output: true or false - /// - public bool DeleteKey(string KeyName) - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.CreateSubKey(subKey); - // If the RegistrySubKey doesn't exists -> (true) - if (sk1 == null) - return true; - else - sk1.DeleteValue(KeyName); - - return true; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Deleting SubKey " + subKey); - return false; - } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// To create a sub key. - /// - public void CreateSubKey() - { - // Opening the registry key - RegistryKey rk = baseRegistryKey; - // Open a subKey as read-only - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistrySubKey doesn't exist -> (null) - if (sk1 == null) - { - rk.CreateSubKey(subKey); - } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// To delete a sub key and any child. - /// input: void - /// output: true or false - /// - public bool DeleteSubKeyTree() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists, I delete it - if (sk1 != null) - rk.DeleteSubKeyTree(subKey); - - return true; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Deleting SubKey " + subKey); - return false; - } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// Retrive the count of subkeys at the current key. - /// input: void - /// output: number of subkeys - /// - public int SubKeyCount() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists... - if (sk1 != null) - return sk1.SubKeyCount; - else - return 0; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Retriving subkeys of " + subKey); - return 0; - } - } - - /* ************************************************************************** - * **************************************************************************/ - - /// - /// Retrive the count of values in the key. - /// input: void - /// output: number of keys - /// - public int ValueCount() - { - try - { - // Setting - RegistryKey rk = baseRegistryKey; - RegistryKey sk1 = rk.OpenSubKey(subKey); - // If the RegistryKey exists... - if (sk1 != null) - return sk1.ValueCount; - else - return 0; - } - catch (Exception e) - { - // AAAAAAAAAAARGH, an error! - ShowErrorMessage(e, "Retriving keys of " + subKey); - return 0; - } - } - - /* ************************************************************************** - * **************************************************************************/ - - private void ShowErrorMessage(Exception e, string Title) - { - if (showError == true) - MessageBox.Show(e.Message, Title, MessageBoxButton.OK, MessageBoxImage.Error); - } - } -} diff --git a/Beanfun/Helper/PacketReader.cs b/Beanfun/Helper/PacketReader.cs deleted file mode 100644 index 4892c02..0000000 --- a/Beanfun/Helper/PacketReader.cs +++ /dev/null @@ -1,178 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace MapleLib.PacketLib -{ - /// - /// Class to handle reading data from a packet - /// - public class PacketReader : IDisposable - { - protected MemoryStream _buffer; - - /// - /// The main reader tool - /// - private readonly BinaryReader _binReader; - - /// - /// Amount of data left in the reader - /// - public int Length - { - get { return (int)_buffer.Length; } - } - - /// - /// Creates a new instance of PacketReader - /// - /// Starting byte array - public PacketReader(byte[] arrayOfBytes) - { - _buffer = new MemoryStream(arrayOfBytes, false); - _binReader = new BinaryReader(_buffer, Encoding.Default); - } - - bool disposed = false; - - public void Dispose() - { - if (disposed) - return; - _binReader.Close(); - _buffer.Dispose(); - - disposed = true; - } - - /// - /// Restart reading from the point specified. - /// - /// The point of the packet to start reading from. - public void Reset(int length) - { - _buffer.Seek(length, SeekOrigin.Begin); - } - - public void Skip(int length) - { - _buffer.Position += length; - } - - public int Position - { - get { return (int)_buffer.Position; } - } - public int Remaining - { - get { return Length - (int)_buffer.Position; } - } - - /// - /// Reads an unsigned byte from the stream - /// - /// an unsigned byte from the stream - public byte ReadByte() - { - return _binReader.ReadByte(); - } - - /// - /// Reads a byte array from the stream - /// - /// Amount of bytes - /// A byte array - public byte[] ReadBytes(int count) - { - return _binReader.ReadBytes(count); - } - - /// - /// Reads a bool from the stream - /// - /// A bool - public bool ReadBool() - { - return _binReader.ReadBoolean(); - } - - /// - /// Reads a signed short from the stream - /// - /// A signed short - public short ReadShort() - { - return _binReader.ReadInt16(); - } - - /// - /// Reads an unsigned short from the stream - /// - /// A signed short - public ushort ReadUShort() - { - return _binReader.ReadUInt16(); - } - - /// - /// Reads a signed int from the stream - /// - /// A signed int - public int ReadInt() - { - return _binReader.ReadInt32(); - } - - /// - /// Reads an unsigned int from the stream - /// - /// A signed int - public uint ReadUInt() - { - return _binReader.ReadUInt32(); - } - - /// - /// Reads a signed long from the stream - /// - /// A signed long - public long ReadLong() - { - return _binReader.ReadInt64(); - } - - /// - /// Reads an unsigned long from the stream - /// - /// A signed long - public ulong ReadULong() - { - return _binReader.ReadUInt64(); - } - - /// - /// Reads an ASCII string from the stream - /// - /// Amount of bytes - /// An ASCII string - public string ReadString(int length) - { - return Encoding.Default.GetString(ReadBytes(length)); - } - - /// - /// Reads a maple string from the stream - /// - /// A maple string - public string ReadMapleString() - { - return ReadString(ReadShort()); - } - - public byte[] ToArray() - { - return _buffer.ToArray(); - } - } -} diff --git a/Beanfun/Helper/TextBlockHelper.cs b/Beanfun/Helper/TextBlockHelper.cs deleted file mode 100644 index 3b36d89..0000000 --- a/Beanfun/Helper/TextBlockHelper.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Media; -using System.Xml; - -namespace Beanfun -{ - class TextBlockHelper - { - #region FormattedText Attached dependency property - - public static string GetFormattedText(DependencyObject obj) - { - return (string)obj.GetValue(FormattedTextProperty); - } - - public static void SetFormattedText(DependencyObject obj, string value) - { - obj.SetValue(FormattedTextProperty, value); - } - - public static readonly DependencyProperty FormattedTextProperty = - DependencyProperty.RegisterAttached( - "FormattedText", - typeof(string), - typeof(TextBlockHelper), - new UIPropertyMetadata("", FormattedTextChanged) - ); - - private static void FormattedTextChanged( - DependencyObject sender, - DependencyPropertyChangedEventArgs e - ) - { - string value = e.NewValue as string; - - TextBlock textBlock = sender as TextBlock; - - if (textBlock != null) - { - textBlock.Inlines.Clear(); - textBlock.Inlines.Add(Process(value)); - } - } - - #endregion - - static Inline Process(string value) - { - XmlDocument doc = new XmlDocument(); - doc.LoadXml(value); - - Span span = new Span(); - InternalProcess(span, doc.FirstChild); - - return span; - } - - private static void InternalProcess(Span span, XmlNode xmlNode) - { - foreach (XmlNode child in xmlNode) - { - Span spanItem = new Span(); - if (child is XmlElement) - InternalProcess(spanItem, child); - switch (child.Name.ToUpper()) - { - case "B": - case "BOLD": - Bold bold = new Bold(spanItem); - span.Inlines.Add(bold); - break; - case "I": - case "ITALIC": - Italic italic = new Italic(spanItem); - span.Inlines.Add(italic); - break; - case "U": - case "UNDERLINE": - Underline underline = new Underline(spanItem); - span.Inlines.Add(underline); - break; - case "L": - case "LINEBREAK": - span.Inlines.Add(new LineBreak()); - break; - case "R": - case "RUN": - Run run = new Run(child.InnerText); - if (child.Attributes != null) - foreach (XmlNode att in child.Attributes) - { - switch (att.Name.ToUpper()) - { - case "FOREGROUND": - run.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString(att.Value) - ); - break; - case "BACKGROUND": - run.Background = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString(att.Value) - ); - break; - } - } - span.Inlines.Add(run); - break; - default: - if (child is XmlText) - span.Inlines.Add(new Run(child.InnerText)); - break; - } - } - } - } -} diff --git a/Beanfun/Helper/WindowAccentCompositor.cs b/Beanfun/Helper/WindowAccentCompositor.cs deleted file mode 100644 index 616c617..0000000 --- a/Beanfun/Helper/WindowAccentCompositor.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; -using System.Windows; -using System.Windows.Interop; -using System.Windows.Media; - -namespace Beanfun -{ - /// - /// 为窗口提供模糊特效。 - /// - public class WindowAccentCompositor - { - private readonly Window _window; - private bool _isEnabled; - private int _blurColor; - - /// - /// 创建 的一个新实例。 - /// - /// 要创建模糊特效的窗口实例。 - public WindowAccentCompositor(Window window) => - _window = window ?? throw new ArgumentNullException(nameof(window)); - - /// - /// 获取或设置此窗口模糊特效是否生效的一个状态。 - /// 默认为 false,即不生效。 - /// - [DefaultValue(false)] - public bool IsEnabled - { - get => _isEnabled; - set - { - _isEnabled = value; - OnIsEnabledChanged(value); - } - } - - /// - /// 获取或设置此窗口模糊特效叠加的颜色。 - /// - public Color Color - { - get => - Color.FromArgb( - // 取出红色分量。 - (byte)((_blurColor & 0x000000ff) >> 0), - // 取出绿色分量。 - (byte)((_blurColor & 0x0000ff00) >> 8), - // 取出蓝色分量。 - (byte)((_blurColor & 0x00ff0000) >> 16), - // 取出透明分量。 - (byte)((_blurColor & 0xff000000) >> 24) - ); - set => - _blurColor = - // 组装红色分量。 - value.R << 0 - | - // 组装绿色分量。 - value.G << 8 - | - // 组装蓝色分量。 - value.B << 16 - | - // 组装透明分量。 - value.A << 24; - } - - private void OnIsEnabledChanged(bool isEnabled) - { - Window window = _window; - var handle = new WindowInteropHelper(window).EnsureHandle(); - Composite(handle, isEnabled); - } - - private void Composite(IntPtr handle, bool isEnabled) - { - // 创建 AccentPolicy 对象。 - var accent = new WindowsAPI.AccentPolicy(); - - // 设置特效。 - if (!isEnabled) - { - accent.AccentState = WindowsAPI.AccentState.ACCENT_DISABLED; - } - else if (App.OSVersion >= App.Win11) - { - // 如果系统在 Windows 11 以上,则启用亚克力效果,并组合已设置的叠加颜色和透明度。 - // ※從 Windows 10 (1809) 開始已經支持亞克力效果但會造成窗口移動時卡頓問題 - // 请参见《在 WPF 程序中应用 Windows 10 真•亚克力效果》 - // https://blog.walterlv.com/post/using-acrylic-in-wpf-application.html - accent.AccentState = WindowsAPI.AccentState.ACCENT_ENABLE_ACRYLICBLURBEHIND; - accent.GradientColor = _blurColor; - } - else if (App.OSVersion >= App.Win10) - { - // 如果系统在 Windows 10 以上,则启用 Windows 10 早期的模糊特效。 - // ※Windows 11 上使用模糊特效會造成窗口移動時卡頓問題 - // 请参见《在 Windows 10 上为 WPF 窗口添加模糊特效》 - // https://blog.walterlv.com/post/win10/2017/10/02/wpf-transparent-blur-in-windows-10.html - accent.AccentState = WindowsAPI.AccentState.ACCENT_ENABLE_BLURBEHIND; - } - else - { - // 暂时不处理其他操作系统: - // - Windows 8/8.1 不支持任何模糊特效 - // - Windows Vista/7 支持 Aero 毛玻璃效果 - return; - } - - // 将托管结构转换为非托管对象。 - var accentPolicySize = Marshal.SizeOf(accent); - var accentPtr = Marshal.AllocHGlobal(accentPolicySize); - Marshal.StructureToPtr(accent, accentPtr, false); - - // 设置窗口组合特性。 - try - { - // 设置模糊特效。 - var data = new WindowsAPI.WindowCompositionAttributeData - { - Attribute = WindowsAPI.WindowCompositionAttribute.WCA_ACCENT_POLICY, - SizeOfData = accentPolicySize, - Data = accentPtr, - }; - WindowsAPI.SetWindowCompositionAttribute(handle, ref data); - } - finally - { - // 释放非托管对象。 - Marshal.FreeHGlobal(accentPtr); - } - } - } -} diff --git a/Beanfun/MainWindow.xaml b/Beanfun/MainWindow.xaml deleted file mode 100644 index 53eb070..0000000 --- a/Beanfun/MainWindow.xaml +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Beanfun/MainWindow.xaml.cs b/Beanfun/MainWindow.xaml.cs deleted file mode 100644 index 973020a..0000000 --- a/Beanfun/MainWindow.xaml.cs +++ /dev/null @@ -1,2761 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Management; -using System.Net; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Imaging; -using IniParser.Model; -using IniParser.Parser; -using Microsoft.Win32; -using Newtonsoft.Json.Linq; -using Utility.ModifyRegistry; - -namespace Beanfun -{ - enum LoginMethod : int - { - Regular = 0, - QRCode = 1, - GamePass = 2, - }; - - enum GameStartMode : int - { - Auto = 0, - Normal = 1, - LocaleRemulator = 2, - }; - - /// - /// MainWindow.xaml 的交互逻辑 - /// - public partial class MainWindow : Window - { - public LoginPage loginPage; - public ManageAccount manageAccPage; - public LoginWait loginWaitPage = new LoginWait(); - public AccountList accountList = null; - public VerifyPage verifyPage; - public Settings settingPage; - public About aboutPage; - public LoginTotp loginTotp; - - public System.ComponentModel.BackgroundWorker getOtpWorker; - public System.ComponentModel.BackgroundWorker loginWorker; - public System.ComponentModel.BackgroundWorker totpWorker; - public System.ComponentModel.BackgroundWorker pingWorker; - public System.ComponentModel.BackgroundWorker qrWorker; - public System.ComponentModel.BackgroundWorker verifyWorker; - public System.Windows.Threading.DispatcherTimer qrCheckLogin; - public System.Windows.Threading.DispatcherTimer checkPlayPage; - public System.Windows.Threading.DispatcherTimer checkPatcher; - public System.Windows.Threading.DispatcherTimer bfAPPAutoLogin; - - public AccountManager accountManager = null; - - public BeanfunClient bfClient; - private readonly object _bfClientLock = new object(); - - public BeanfunClient.QRCodeClass qrcodeClass; - - public string LastLoginAccountID = ""; - public string service_code = "610074", - service_region = "T9"; - public string game_exe = "MapleStory.exe"; - public string dir_value_name = "Path"; - public string win_class_name = "MapleStoryClass"; - public short login_action_type = 1; - public string game_commandLine = "tw.login.maplestory.beanfun.com 8484 BeanFun %s %s"; - private string otp; - private BitmapImage qr_default; - private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(MainWindow)); - private static readonly System.Windows.Forms.NotifyIcon _trayNotifyIcon = - new System.Windows.Forms.NotifyIcon - { - Icon = Properties.Resources.icon, - Text = Application.Current.TryFindResource("AppName") as string, - }; - - public Dictionary> GameList = - new Dictionary>(); - public GameService SelectedGame = null; - public bool UnconnectedGame = false; - - public string viewstate, - eventvalidation, - samplecaptcha; - - public Page return_page = null; - public IniData INIData = null; - - public WindowAccentCompositor compositor = null; - - public MainWindow() - { - InitializeComponent(); - - this.getOtpWorker = new System.ComponentModel.BackgroundWorker(); - this.loginWorker = new System.ComponentModel.BackgroundWorker(); - this.totpWorker = new System.ComponentModel.BackgroundWorker(); - this.pingWorker = new System.ComponentModel.BackgroundWorker(); - this.qrWorker = new System.ComponentModel.BackgroundWorker(); - this.verifyWorker = new System.ComponentModel.BackgroundWorker(); - this.qrCheckLogin = new System.Windows.Threading.DispatcherTimer(); - this.checkPlayPage = new System.Windows.Threading.DispatcherTimer(); - this.checkPatcher = new System.Windows.Threading.DispatcherTimer(); - this.bfAPPAutoLogin = new System.Windows.Threading.DispatcherTimer(); - // - // getOtpWorker - // - this.getOtpWorker.WorkerReportsProgress = true; - this.getOtpWorker.WorkerSupportsCancellation = true; - this.getOtpWorker.DoWork += this.getOtpWorker_DoWork; - this.getOtpWorker.RunWorkerCompleted += this.getOtpWorker_RunWorkerCompleted; - // - // loginWorker - // - this.loginWorker.WorkerReportsProgress = true; - this.loginWorker.WorkerSupportsCancellation = true; - this.loginWorker.DoWork += this.loginWorker_DoWork; - this.loginWorker.RunWorkerCompleted += this.loginWorker_RunWorkerCompleted; - // - // totpWorker - // - this.totpWorker.WorkerReportsProgress = true; - this.totpWorker.WorkerSupportsCancellation = true; - this.totpWorker.DoWork += this.totpWorker_DoWork; - this.totpWorker.RunWorkerCompleted += this.totpWorker_RunWorkerCompleted; - // - // pingWorker - // - this.pingWorker.WorkerReportsProgress = true; - this.pingWorker.WorkerSupportsCancellation = true; - this.pingWorker.DoWork += this.pingWorker_DoWork; - this.pingWorker.RunWorkerCompleted += this.pingWorker_RunWorkerCompleted; - // - // qrWorker - // - this.qrWorker.WorkerReportsProgress = true; - this.qrWorker.WorkerSupportsCancellation = true; - this.qrWorker.DoWork += this.qrWorker_DoWork; - this.qrWorker.RunWorkerCompleted += this.qrWorker_RunWorkerCompleted; - // - // verifyWorker - // - this.verifyWorker.WorkerReportsProgress = true; - this.verifyWorker.WorkerSupportsCancellation = true; - this.verifyWorker.DoWork += this.verifyWorker_DoWork; - this.verifyWorker.RunWorkerCompleted += this.verifyWorker_RunWorkerCompleted; - // - // qrCheckLogin - // - this.qrCheckLogin.Interval = TimeSpan.FromSeconds(2); - this.qrCheckLogin.Tick += this.qrCheckLogin_Tick; - // - // checkPlayPage - // - this.checkPlayPage.Interval = TimeSpan.FromMilliseconds(100); - this.checkPlayPage.Tick += this.checkPlayPage_Tick; - // - // checkPatcher - // - this.checkPatcher.Interval = TimeSpan.FromMilliseconds(100); - this.checkPatcher.Tick += this.checkPatcher_Tick; - // - // bfAPPAutoLogin - // - this.bfAPPAutoLogin.Interval = TimeSpan.FromSeconds(2); - this.bfAPPAutoLogin.Tick += this.bfAPPAutoLogin_Tick; - - loginPage = new LoginPage(); - manageAccPage = new ManageAccount(); - verifyPage = new VerifyPage(); - accountList = new AccountList(); - settingPage = new Settings(); - aboutPage = new About(); - loginTotp = new LoginTotp(); - - Initialize(); - - if ( - (App.OSVersion >= App.Win7 && App.OSVersion < App.Win8) - || App.OSVersion >= App.Win10 - ) - { - compositor = new WindowAccentCompositor(this); - if (App.OSVersion >= App.Win7 && App.OSVersion < App.Win8) - { - WinChrome.GlassFrameThickness = new Thickness(-1); - - const int GWL_STYLE = -16; - const int WS_SYSMENU = 0x80000; - var hwnd = new System.Windows.Interop.WindowInteropHelper(this).EnsureHandle(); - WindowsAPI.SetWindowLong( - hwnd, - GWL_STYLE, - WindowsAPI.GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU - ); - } - } - else - frame.Content = loginWaitPage; - - changeThemeColor(null); - } - - protected override void OnContentRendered(EventArgs e) - { - frame.Content = loginPage; - //frame.Content = loginTotp; - - if ( - App.LoginMethod == (int)LoginMethod.Regular - && (bool)loginPage.id_pass.checkBox_AutoLogin.IsChecked - ) - { - do_Login(); - } - - base.OnContentRendered(e); - } - - public void NavigateLoginPage() - { - frame.Content = loginPage; - - btn_Region.Visibility = Visibility.Visible; - - try - { - if (bfClient != null) - bfClient.Logout(); - } - catch { } - } - - public void changeThemeColor(string sColor) - { - if (sColor == null) - sColor = ConfigAppSettings.GetValue("ThemeColor", "#FF8201"); - Color color = (Color)ColorConverter.ConvertFromString(sColor); - bool oldIsLightColor = isLightColor(); - Background = new SolidColorBrush(color); - color.R = (byte)Math.Max(color.R - 50, 0); - color.G = (byte)Math.Max(color.G - 50, 0); - color.B = (byte)Math.Max(color.B - 50, 0); - color.A = 0xFF; - this.BorderBrush = new SolidColorBrush(color); - - // Update theme color resource for ListBox selection - Application.Current.Resources["ThemeColorBrush"] = new SolidColorBrush(color); - bool isLightMode = isLightColor(); - if (compositor != null) - { - int bgA = -1; - if (!this.IsActive) - { - compositor.IsEnabled = false; - if (App.OSVersion >= App.Win7 && App.OSVersion < App.Win8) - bgA = 0; - } - else - { - bgA = - App.OSVersion < App.Win8 ? 0x4C - : App.OSVersion < App.Win11 ? 0xCC - : 0x99; - compositor.Color = (Color) - ColorConverter.ConvertFromString( - isLightMode || ((SolidColorBrush)Background).Color == Colors.Black - ? "#00FFFFFF" - : "#00000000" - ); - if (!compositor.IsEnabled) - compositor.IsEnabled = true; - } - if (bgA != -1) - { - Color bg = ((SolidColorBrush)Background).Color; - bg.A = (byte)bgA; - Background = new SolidColorBrush(bg); - } - } - if (oldIsLightColor != isLightMode) - { - btn_About_MouseLeave(null, null); - btn_Setting_MouseLeave(null, null); - btn_Region_MouseLeave(null, null); - btn_Min_MouseLeave(null, null); - btn_Close_MouseLeave(null, null); - LogoIcon.Fill = new SolidColorBrush(isLightMode ? Colors.Black : Colors.White); - if (aboutPage != null) - aboutPage.initThemeColor(isLightMode); - } - } - - public bool isLightColor() - { - Color color = ((SolidColorBrush)Background).Color; - return (0.299 * color.R + 0.587 * color.G + 0.114 * color.B) / 255 > 0.5; - } - - public Color getTitleButtonColor() - { - return (Color)ColorConverter.ConvertFromString(isLightColor() ? "Black" : "White"); - } - - public void Initialize() - { - try - { - if (App.OSVersion < App.Win11) - { - ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; - } - // Allow SSL errors for beanfun/gamania domains; fall through for unknown sender types - // (e.g. process-mode game accelerators like UU) to preserve backward compatibility - ServicePointManager.ServerCertificateValidationCallback = ( - sender, - certificate, - chain, - errors - ) => - { - if (errors == System.Net.Security.SslPolicyErrors.None) - return true; - if (sender is HttpWebRequest req) - { - string host = req.RequestUri.Host; - return host.EndsWith(".beanfun.com") || host.EndsWith(".gamania.com"); - } - return true; - }; - if (settingPage.tradLogin != null && !(bool)settingPage.tradLogin.IsChecked) - accountList.panel_GetOtp.Visibility = Visibility.Collapsed; - - qr_default = new BitmapImage(); - qr_default.BeginInit(); - qr_default.UriSource = new Uri("pack://application:,,,/Resources/refresh.png"); - qr_default.EndInit(); - loginPage.qr.qr_image.Source = qr_default; - - string loginGame = ConfigAppSettings.GetValue("loginGame", ""); - if (loginGame != "") - { - string[] arr = loginGame.Split('_'); - if (arr != null && arr.Length > 1) - { - service_code = arr[0]; - service_region = arr[1]; - } - } - - if ((bool)settingPage.ask_update.IsChecked) - { - new Thread(() => CheckUpdates(false)).Start(); - } - - this.accountManager = new AccountManager(); - - bool res = accountManager.init(); - if (res == false) - errexit(TryFindResource("InitAccountError") as string, 0); - - settingPage.t_GamePath.PreviewMouseLeftButtonDown += this.btn_SetGamePath_Click; - LastLoginAccountID = ConfigAppSettings.GetValue("AccountID", LastLoginAccountID); - int loginMethod = accountManager.getMethodByAccount( - App.LoginRegion, - LastLoginAccountID - ); - if (loginMethod < (int)LoginMethod.Regular) - loginMethod = int.Parse(ConfigAppSettings.GetValue("loginMethod", "0")); - // Don't restore QRCode/GamePass on startup — they require active auth sessions - loginMethod = Math.Min( - loginMethod, - App.LoginRegion == "TW" ? (int)LoginMethod.QRCode : (int)LoginMethod.Regular - ); - - loginMethodInit(); - - Dispatcher.BeginInvoke(new Action(() => reLoadGameInfo())); - - App.LoginMethod = loginMethod; - loginMethodChanged(); - - _trayNotifyIcon.MouseClick += (sender, e) => - { - if (e.Button == System.Windows.Forms.MouseButtons.Left) - { - this.Visibility = Visibility.Visible; - _trayNotifyIcon.Visible = false; - } - }; - - frame.Content = loginPage; - } - catch (Exception ex) - { - Console.WriteLine(ex.StackTrace); - MessageBox.Show( - string.Format( - Regex.Unescape(TryFindResource("LoadDataError") as string), - ex.Message - ) /* + "\r\n\r\n" + ex.StackTrace*/ - ); - - new LoginRegionSelection().ShowDialog(); - } - } - - public class GameService - { - public string name { get; set; } - public string service_code { get; set; } - public string service_region { get; set; } - public string website_url { get; set; } - public string xlarge_image_name { get; set; } - public string large_image_name { get; set; } - public string small_image_name { get; set; } - public string download_url { get; set; } - - private string imageBaseUrl - { - get - { - return App.LoginRegion == "TW" - ? "https://tw.images.beanfun.com/uploaded_images/beanfun_tw/game_zone/" - : "http://hk.images.beanfun.com/uploaded_images/beanfun/game_zone/"; - } - } - - private BitmapImage xlarge_image; - public BitmapImage XLarge_image - { - get - { - if (xlarge_image == null) - xlarge_image = loadImage(large_image_name); - return xlarge_image; - } - } - - private BitmapImage large_image; - public BitmapImage Large_image - { - get - { - if (large_image == null) - large_image = loadImage(large_image_name); - return large_image; - } - } - - private BitmapImage small_image; - public BitmapImage Small_image - { - get - { - if (small_image == null) - small_image = loadImage(small_image_name); - return small_image; - } - } - - public GameService( - string name, - string service_code, - string service_region, - string website_url, - string xlarge_image_name, - string large_image_name, - string small_image_name, - string download_url - ) - { - this.name = I18n.ToSimplified(name); - this.service_code = service_code; - this.service_region = service_region; - this.website_url = website_url; - this.xlarge_image_name = xlarge_image_name; - this.large_image_name = large_image_name; - this.small_image_name = small_image_name; - this.download_url = download_url; - } - - private BitmapImage loadImage(string url) - { - if ( - !url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) - && !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase) - ) - { - url = $"{imageBaseUrl}{url}"; - } - BitmapImage image; - try - { - byte[] buffer = new WebClient().DownloadData(url); - image = new BitmapImage(); - image.BeginInit(); - image.StreamSource = new MemoryStream(buffer); - image.EndInit(); - } - catch (Exception) - { - image = null; - } - return image; - } - } - - public void selectedGameChanged() - { - string gameCode = service_code + "_" + service_region; - ConfigAppSettings.SetValue("loginGame", gameCode); - - if (INIData == null) - { - reLoadGameInfo(); - return; - } - string exe = INIData[gameCode]["exe"]; - if (exe == null) - { - new GameList().ShowDialog(); - return; - } - Regex regex = new Regex("(.*).exe"); - if (regex.IsMatch(exe)) - game_exe = regex.Match(exe).Groups[1].Value + ".exe"; - else - game_exe = ""; - regex = new Regex(".exe (.*)"); - if (regex.IsMatch(exe)) - game_commandLine = regex.Match(exe).Groups[1].Value; - else - game_commandLine = ""; - - login_action_type = 8; - string sLoginActionType = INIData[gameCode]["login_action_type"]; - if (sLoginActionType != "") - login_action_type = short.Parse(sLoginActionType); - if (login_action_type == 1) - { - settingPage.tradLogin.Visibility = Visibility.Visible; - if ((bool)settingPage.tradLogin.IsChecked) - accountList.panel_GetOtp.Visibility = Visibility.Visible; - else - accountList.panel_GetOtp.Visibility = Visibility.Collapsed; - } - else - { - settingPage.tradLogin.Visibility = Visibility.Collapsed; - accountList.panel_GetOtp.Visibility = Visibility.Visible; - } - - win_class_name = INIData[gameCode]["win_class_name"]; - if ("MapleStoryClass".Equals(win_class_name)) - { - accountList.autoPaste.Visibility = Visibility.Visible; - } - else - { - accountList.autoPaste.Visibility = Visibility.Collapsed; - } - dir_value_name = INIData[gameCode]["dir_value_name"]; - if (ConfigAppSettings.GetValue(dir_value_name + "." + gameCode, "") == "") - { - string dir_reg = INIData[gameCode]["dir_reg"]; - if (dir_reg != "") - { - dir_reg = dir_reg.Replace("HKEY_LOCAL_MACHINE\\", ""); - - try - { - ModifyRegistry myRegistry = new ModifyRegistry(); - myRegistry.BaseRegistryKey = Registry.CurrentUser; - myRegistry.SubKey = dir_reg; - if (myRegistry.Read(dir_value_name) != "") - { - ConfigAppSettings.SetValue( - dir_value_name + "." + gameCode, - myRegistry.Read(dir_value_name) - ); - settingPage.t_GamePath.Text = myRegistry.Read(dir_value_name); - } - } - catch - { - settingPage.t_GamePath.Text = ""; - } - } - } - else - { - settingPage.t_GamePath.Text = ConfigAppSettings.GetValue( - dir_value_name + "." + gameCode - ); - } - - if (gameCode == "610074_T9" || gameCode == "610075_T9") - { - settingPage.skipPlayWnd.Visibility = Visibility.Visible; - - if ((bool)settingPage.skipPlayWnd.IsChecked) - checkPlayPage.IsEnabled = true; - - settingPage.autoKillPatcher.Visibility = Visibility.Visible; - - if ((bool)settingPage.autoKillPatcher.IsChecked) - checkPatcher.IsEnabled = true; - - settingPage.btn_Tools.Visibility = Visibility.Visible; - } - else - { - settingPage.skipPlayWnd.Visibility = Visibility.Collapsed; - checkPlayPage.IsEnabled = false; - settingPage.autoKillPatcher.Visibility = Visibility.Collapsed; - checkPatcher.IsEnabled = false; - - if (gameCode == "610096_TE") - settingPage.btn_Tools.Visibility = Visibility.Visible; - else - settingPage.btn_Tools.Visibility = Visibility.Collapsed; - } - - if (this.bfClient != null && !loginWorker.IsBusy && !getOtpWorker.IsBusy) - { - this.bfClient.GetAccounts(service_code, service_region); - redrawSAccountList(); - if (this.bfClient.errmsg != null) - { - errexit(this.bfClient.errmsg, 2); - this.bfClient.errmsg = null; - } - } - switch (gameCode) - { - case "610153_TN": - case "610085_TC": - UnconnectedGame = true; - break; - default: - UnconnectedGame = false; - break; - } - - try - { - if (loginPage != null) - { - foreach (GameService gs in GameList[App.LoginRegion.ToLower()]) - { - if ( - gs.service_region == this.service_region - && gs.service_code == this.service_code - ) - { - loginPage.id_pass.imageGame.ImageSource = gs.Large_image; - accountList.imageGame.Source = gs.Small_image; - accountList.gameName.Content = gs.name; - SelectedGame = gs; - break; - } - } - } - } - catch - { /* ignore out of range */ - } - } - - public void reLoadGameInfo() - { - if (!GameList.ContainsKey(App.LoginRegion.ToLower())) - { - var capturedRegion = App.LoginRegion.ToLower(); - string host = capturedRegion == "hk" ? "bfweb.hk" : "tw"; - new Thread(() => - { - try - { - List gameList = new List(); - WebClient wc = new WebClient(); - - string res = Encoding.UTF8.GetString( - wc.DownloadData( - $"https://{host}.beanfun.com/beanfun_block/generic_handlers/get_service_ini.ashx" - ) - ); - - IniDataParser parser = new IniDataParser(); - var iniData = parser.Parse(res); - - res = Encoding.UTF8.GetString( - wc.DownloadData($"https://{host}.beanfun.com/game_zone/") - ); - Regex reg = new Regex("Services\\.ServiceList = (.*);"); - if (reg.IsMatch(res)) - { - string json = reg.Match(res).Groups[1].Value; - bool newJson = new Regex("^\\[(.*)\\]$").IsMatch(json); - if (newJson) - { - JArray jsons = JArray.Parse(json); - foreach (JObject game in jsons) - AddGameServiceFromJson(gameList, game); - } - else - { - JObject o = JObject.Parse(json); - foreach (JObject game in o["Rows"]) - AddGameServiceFromJson(gameList, game); - } - } - - Dispatcher.Invoke(() => - { - if (App.LoginRegion.ToLower() != capturedRegion) - return; - - INIData = iniData; - if (!GameList.ContainsKey(capturedRegion)) - GameList.Add(capturedRegion, gameList); - selectedGameChanged(); - }); - } - catch (Exception ex) - { - log.Error("reLoadGameInfo failed", ex); - } - }) - { - IsBackground = true, - Name = "reLoadGameInfo", - }.Start(); - return; - } - - selectedGameChanged(); - } - - private void AddGameServiceFromJson(List gameList, JObject game) - { - GameService gs = new GameService( - (string)game["ServiceFamilyName"], - (string)game["ServiceCode"], - (string)game["ServiceRegion"], - (string)game["ServiceWebsiteURL"], - (string)game["ServiceXLargeImageName"], - (string)game["ServiceLargeImageName"], - (string)game["ServiceSmallImageName"], - (string)game["ServiceDownloadURL"] - ); - gameList.Add(gs); - if (gs.service_code == service_code && gs.service_region == service_region) - SelectedGame = gs; - } - - public void CheckUpdates(bool show) - { - Update.ApplicationUpdater.CheckApplicationUpdate(show); - } - - private string reLoadVerifyPage(string response) - { - Regex regex; - - // __VIEWSTATE - regex = new Regex("id=\"__VIEWSTATE\"[^>]+value=\"([^\"]+)\""); - if (!regex.IsMatch(response)) - { - return "VerifyNoViewstate"; - } - this.viewstate = regex.Match(response).Groups[1].Value; - - // __VIEWSTATEGENERATOR (optional but store if present) - regex = new Regex("id=\"__VIEWSTATEGENERATOR\"[^>]+value=\"([^\"]+)\""); - if (regex.IsMatch(response)) - { - this.bfClient.verifyViewStateGenerator = regex.Match(response).Groups[1].Value; - } - - // __EVENTVALIDATION - regex = new Regex("id=\"__EVENTVALIDATION\"[^>]+value=\"([^\"]+)\""); - if (!regex.IsMatch(response)) - { - return "VerifyNoEventvalidation"; - } - this.eventvalidation = regex.Match(response).Groups[1].Value; - - // Captcha ID - regex = new Regex("id=\"LBD_VCID_[^\"]+\"[^>]+value=\"([^\"]+)\""); - if (!regex.IsMatch(response)) - { - return "VerifyNoSamplecaptcha"; - } - this.samplecaptcha = regex.Match(response).Groups[1].Value; - - // Auth type label - regex = new Regex("id=\"lblAuthType\">([^<]+)<"); - if (!regex.IsMatch(response)) - { - return "VerifyNoLblAuthType"; - } - verifyPage.labelAuthType.Content = regex.Match(response).Groups[1].Value; - - // Form action URL (store for submit) - regex = new Regex("action=\"(AdvanceCheck\\.aspx[^\"]+)\""); - if (regex.IsMatch(response)) - { - string formAction = regex.Match(response).Groups[1].Value.Replace("&", "&"); - this.bfClient.verifyFormAction = - $"https://tw.newlogin.beanfun.com/LoginCheck/{formAction}"; - } - - // Alert check - regex = new Regex("alert\\('(.*)'\\);"); - if (regex.IsMatch(response)) - { - return regex.Match(response).Groups[1].Value; - } - - verifyPage.imageCaptcha.Source = this.bfClient.getVerifyCaptcha(this.samplecaptcha); - return null; - } - - private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) - { - try - { - this.DragMove(); - } - catch { } - } - - private void Window_Activated(object sender, EventArgs e) - { - btn_About_MouseLeave(null, null); - btn_Setting_MouseLeave(null, null); - btn_Region_MouseLeave(null, null); - btn_Min_MouseLeave(null, null); - btn_Close_MouseLeave(null, null); - if (this.IsActive) - { - changeThemeColor(null); - } - else - { - changeThemeColor("#F3F3F3"); - this.BorderBrush = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("Gray") - ); - } - } - - private void Window_StateChanged(object sender, EventArgs e) - { - if ( - settingPage != null - && settingPage.minimize_to_tray != null - && (bool)settingPage.minimize_to_tray.IsChecked - && this.WindowState == WindowState.Minimized - ) - { - this.WindowState = WindowState.Normal; - this.Visibility = Visibility.Hidden; - _trayNotifyIcon.Visible = true; - } - } - - private void btn_About_MouseLeave(object sender, MouseEventArgs e) - { - if (this.IsActive) - btn_About.Foreground = new SolidColorBrush(getTitleButtonColor()); - else - btn_About.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("Gray") - ); - } - - private void btn_About_IsKeyboardFocusedChanged( - object sender, - DependencyPropertyChangedEventArgs e - ) - { - if (btn_About.IsKeyboardFocused) - frame.Focus(); - } - - private void btn_Setting_MouseLeave(object sender, MouseEventArgs e) - { - if (this.IsActive) - btn_Setting.Foreground = new SolidColorBrush(getTitleButtonColor()); - else - btn_Setting.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("Gray") - ); - } - - private void btn_Setting_IsKeyboardFocusedChanged( - object sender, - DependencyPropertyChangedEventArgs e - ) - { - if (btn_Setting.IsKeyboardFocused) - frame.Focus(); - } - - private void CloseGamePassBrowser() - { - foreach (Window wnd in Application.Current.Windows) - { - if (wnd is GamePassBrowser) - { - wnd.Close(); - break; - } - } - } - - private void btn_Region_Click(object sender, RoutedEventArgs e) - { - loginPage.qr.CloseEnlargeWindow(); - CloseGamePassBrowser(); - App.LoginRegion = App.LoginRegion == "TW" ? "HK" : "TW"; - ConfigAppSettings.SetValue("loginRegion", App.LoginRegion); - loginMethodInit(); - reLoadGameInfo(); - } - - private void btn_Region_MouseLeave(object sender, MouseEventArgs e) - { - if (this.IsActive) - btn_Region.Foreground = new SolidColorBrush(getTitleButtonColor()); - else - btn_Region.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("Gray") - ); - } - - private void btn_Region_IsKeyboardFocusedChanged( - object sender, - DependencyPropertyChangedEventArgs e - ) - { - if (btn_Region.IsKeyboardFocused) - frame.Focus(); - } - - private void btn_Min_MouseLeave(object sender, MouseEventArgs e) - { - if (this.IsActive) - btn_Min.Foreground = new SolidColorBrush(getTitleButtonColor()); - else - btn_Min.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("Gray") - ); - } - - private void btn_Min_IsKeyboardFocusedChanged( - object sender, - DependencyPropertyChangedEventArgs e - ) - { - if (btn_Min.IsKeyboardFocused) - frame.Focus(); - } - - private void btn_Close_MouseEnter(object sender, MouseEventArgs e) - { - btn_Close.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("White") - ); - } - - private void btn_Close_MouseLeave(object sender, MouseEventArgs e) - { - if (this.IsActive) - btn_Close.Foreground = new SolidColorBrush(getTitleButtonColor()); - else - btn_Close.Foreground = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("Gray") - ); - } - - private void btn_Close_IsKeyboardFocusedChanged( - object sender, - DependencyPropertyChangedEventArgs e - ) - { - if (btn_Close.IsKeyboardFocused) - frame.Focus(); - } - - private void btn_About_Click(object sender, RoutedEventArgs e) - { - frame.Content = aboutPage; - if (return_page != null) - return; - return_page = (Page)frame.Content; - } - - private void btn_Setting_Click(object sender, RoutedEventArgs e) - { - frame.Content = settingPage; - if (return_page != null) - return; - return_page = (Page)frame.Content; - } - - private void btn_Min_Click(object sender, RoutedEventArgs e) - { - base.WindowState = WindowState.Minimized; - } - - private void btn_Close_Click(object sender, RoutedEventArgs e) - { - System.Windows.Application.Current.Shutdown(); - } - - private void btn_SetGamePath_Click(object sender, RoutedEventArgs e) - { - string gameCode = service_code + "_" + service_region; - OpenFileDialog openFileDialog = new OpenFileDialog(); - openFileDialog.Filter = - accountList.gameName.Content - + string.Format(TryFindResource("FileDialog_Filter") as string, game_exe); - openFileDialog.Title = string.Format( - TryFindResource("FileDialog_Title") as string, - game_exe - ); - - if (openFileDialog.ShowDialog() == true) - { - string file = openFileDialog.FileName; - ConfigAppSettings.SetValue(dir_value_name + "." + gameCode, file); - settingPage.t_GamePath.Text = file; - } - } - - public void loginMethodChanged() - { - if (qrWorker.IsBusy) - qrWorker.CancelAsync(); - loginPage.qr.CloseEnlargeWindow(); - CloseGamePassBrowser(); - qrCheckLogin.IsEnabled = false; - btn_Region.IsEnabled = true; - settingPage.LoginModePanel.Visibility = - (App.LoginRegion == "TW") ? Visibility.Visible : Visibility.Collapsed; - if (App.LoginRegion == "TW") - { - loginPage.id_pass.btn_GamePass.Visibility = Visibility.Visible; - switch (App.LoginMethod) - { - case (int)LoginMethod.QRCode: - btn_Region.IsEnabled = false; - loginPage.qr.qr_image.Source = qr_default; - loginPage.login_form.Content = loginPage.qr; - if (!qrWorker.IsBusy) - qrWorker.RunWorkerAsync( - loginPage == null || loginPage.qr == null ? false : true - ); - break; - case (int)LoginMethod.GamePass: - btn_Region.IsEnabled = false; - loginPage.login_form.Content = loginPage.gamepass; - break; - default: - loginPage.login_form.Content = loginPage.id_pass; - break; - } - } - else - { - loginPage.id_pass.btn_GamePass.Visibility = Visibility.Collapsed; - loginPage.login_form.Content = loginPage.id_pass; - App.LoginMethod = (int)LoginMethod.Regular; - } - - if ( - App.LoginMethod == (int)Beanfun.LoginMethod.Regular - && ( - loginPage.id_pass.t_Password.Password == "" - || loginPage.id_pass.t_Password.Password == null - ) - ) - { - string pwd = accountManager.getPasswordByAccount( - App.LoginRegion, - loginPage.id_pass.t_AccountID.Text - ); - - if (pwd != null && pwd != "") - { - loginPage.id_pass.t_Password.Password = pwd; - loginPage.id_pass.checkBox_RememberPWD.IsChecked = true; - loginPage.id_pass.checkBox_AutoLogin.IsChecked = - accountManager.getAutoLoginByAccount( - App.LoginRegion, - loginPage.id_pass.t_AccountID.Text - ); - } - - string verify = accountManager.getVerifyByAccount( - App.LoginRegion, - loginPage.id_pass.t_AccountID.Text - ); - if (verify != null && verify != "") - { - verifyPage.t_Verify.Text = verify; - verifyPage.checkBoxRememberVerify.IsChecked = true; - } - else - { - verifyPage.t_Verify.Text = ""; - verifyPage.checkBoxRememberVerify.IsChecked = false; - } - } - } - - public void loginMethodInit() - { - try - { - if (App.LoginRegion == "TW") - { - btn_Region.Content = "TW"; - btn_Region.ToolTip = TryFindResource("ChangHKRegion") as string; - loginPage.id_pass.btn_QRCode.IsEnabled = true; - - accountList.btn_Deposite.Visibility = Visibility.Visible; - } - else - { - btn_Region.Content = "HK"; - btn_Region.ToolTip = TryFindResource("ChangTWRegion") as string; - loginPage.id_pass.btn_QRCode.IsEnabled = false; - - accountList.btn_Deposite.Visibility = Visibility.Collapsed; - } - } - catch { } - - try - { - string accId = LastLoginAccountID; - int selectedIndex = -1; - string[] accountArrays = accountManager.getAccountList(App.LoginRegion); - List accList = new List(); - - int i = 0; - foreach (string s in accountArrays) - { - if (s == accId) - selectedIndex = i; - string name = accountManager.getNameByAccount(App.LoginRegion, s); - if (name != null && name != "") - { - accList.Add(name + "(" + s + ")"); - } - else - { - accList.Add(s); - } - i++; - } - loginPage.id_pass.t_AccountID.ItemsSource = null; - loginPage.id_pass.t_AccountID.ItemsSource = accList; - - int loginMethod = accountManager.getMethodByAccount(App.LoginRegion, accId); - if (loginMethod < (int)LoginMethod.Regular) - { - if (accountArrays.Length > 0) - { - accId = accList[0]; - selectedIndex = 0; - } - loginMethod = accountManager.getMethodByAccount(App.LoginRegion, accId); - } - - if (loginMethod > -1) - { - loginPage.id_pass.t_AccountID.SelectedIndex = selectedIndex; - - App.LoginMethod = loginMethod; - loginMethodChanged(); - - string pwd = accountManager.getPasswordByAccount(App.LoginRegion, accId); - if (loginMethod != (int)LoginMethod.Regular) - pwd = ""; - - if (pwd == null || pwd == "") - { - loginPage.id_pass.t_Password.Password = ""; - loginPage.id_pass.checkBox_RememberPWD.IsChecked = false; - loginPage.id_pass.checkBox_AutoLogin.IsChecked = false; - } - } - else - { - loginPage.id_pass.t_AccountID.Text = ""; - loginPage.id_pass.t_Password.Password = ""; - loginPage.id_pass.checkBox_RememberPWD.IsChecked = false; - loginPage.id_pass.checkBox_AutoLogin.IsChecked = false; - - App.LoginMethod = (int)LoginMethod.Regular; - loginMethodChanged(); - - verifyPage.t_Verify.Text = ""; - verifyPage.checkBoxRememberVerify.IsChecked = false; - } - } - catch - { /* ignore out of range */ - } - manageAccPage.setupAccList(this); - } - - public void do_Login() - { - btn_Region.Visibility = Visibility.Collapsed; - this.loginWorker.RunWorkerAsync(App.LoginMethod); - frame.Content = loginWaitPage; - } - - public void do_Totp() - { - btn_Region.Visibility = Visibility.Collapsed; - frame.Content = loginWaitPage; - this.totpWorker.RunWorkerAsync(); - } - - public bool errexit(string msg, int method, string title = null) - { - switch (msg) - { - case "AdvanceCheckSuccessRetry": - msg = TryFindResource("AdvanceCheckSuccessRetry") as string; - method = 1; - break; - case "LoginNoResponse": - case "LoginNoSkey": - case "LoginNoOTP1": - case "LoginNoSeed": - case "LoginNoHash": - case "LoginIntResultError": - case "AKeyParseFailed": - case "authkeyParseFailed": - case "LoginUnknown": - msg = TryFindResource(msg) as string; - method = 1; - break; - case "LoginNoAkey": - msg = $"{TryFindResource("LoginNoAkey") as string}({msg})"; - break; - case "LoginNoAccountMatch": - case "LoginGetAccountErr": - case "LoginUpdateAccountListErr": - msg = $"{TryFindResource("LoginNoAccountMatch") as string}({msg})"; - break; - case "MainAccount_Not_Exist": - msg = string.Format( - TryFindResource("MainAccount_Not_Exist") as string, - App.LoginRegion == "TW" - ? TryFindResource("Taiwan") - : TryFindResource("HongKong") - ); - break; - default: - if (msg.StartsWith("OTPNoLongPollingKey:")) - { - string otpDetail = msg.Substring("OTPNoLongPollingKey:".Length); - if (string.IsNullOrEmpty(otpDetail)) - msg = TryFindResource("GetOtpInitError") as string; - else if (otpDetail.Contains("很抱歉,需先完成進階認證")) - msg = TryFindResource("NeedAuthToPlayGame") as string; - else if ( - otpDetail.Contains("尚未登入,請重新登入") - || otpDetail.Contains("無法認證登入狀態") - ) - { - msg = TryFindResource("DisconnectedFromServer") as string; - method = 1; - } - } - else - { - string localized = null; - try - { - localized = TryFindResource(msg) as string; - } - catch { } - if (localized != null) - msg = localized; - } - break; - } - - string displayMsg = I18n.ToSimplified(msg); - try - { - displayMsg = Regex.Unescape(displayMsg); - } - catch { } - - MessageBox.Show(displayMsg, title ?? TryFindResource("Error") as string); - - if (method == 0) - App.Current.Shutdown(); - else if (method == 1) - { - loginMethodChanged(); - if (accountList?.t_Password != null) - accountList.t_Password.Text = ""; - NavigateLoginPage(); - } - - return false; - } - - private volatile bool isCancelRequested; - - public void CancelWork() - { - isCancelRequested = true; - } - - public void ResumeWork() - { - isCancelRequested = false; - } - - private void OnLoginCompleted() - { - ConfigAppSettings.SetValue("loginMethod", App.LoginMethod.ToString()); - - SaveLoginCredentials(); - ShowAccountListPage(); - } - - public void GamePassLoginCompleted( - string webToken, - System.Collections.Generic.List cookies - ) - { - bfClient.GamePassLogin(webToken, cookies, service_code, service_region); - - if (bfClient.errmsg != null) - { - errexit(bfClient.errmsg, 1); - return; - } - - App.LoginMethod = (int)LoginMethod.GamePass; - ConfigAppSettings.SetValue("loginMethod", App.LoginMethod.ToString()); - ShowAccountListPage(); - } - - private void SaveLoginCredentials() - { - bool isAccountLogin = - App.LoginRegion != "TW" || App.LoginMethod != (int)LoginMethod.QRCode; - if (!isAccountLogin) - { - ConfigAppSettings.SetValue("AccountID", null); - return; - } - - var idPassForm = loginPage.id_pass; - string accountId = idPassForm.t_AccountID.Text; - LastLoginAccountID = accountId; - ConfigAppSettings.SetValue("AccountID", accountId); - - accountManager.addAccount( - App.LoginRegion, - accountId, - "", - idPassForm.checkBox_RememberPWD.IsEnabled - && (bool)idPassForm.checkBox_RememberPWD.IsChecked - ? idPassForm.t_Password.Password - : "", - (bool)verifyPage.checkBoxRememberVerify.IsChecked ? verifyPage.t_Verify.Text : "", - App.LoginMethod, - (bool)idPassForm.checkBox_AutoLogin.IsChecked - ); - - loginMethodInit(); - } - - private void ShowAccountListPage() - { - try - { - loginPage.qr.CloseEnlargeWindow(); - frame.Content = accountList; - btn_Region.Visibility = Visibility.Collapsed; - - redrawSAccountList(); - - if (!this.pingWorker.IsBusy) - this.pingWorker.RunWorkerAsync(); - - updateRemainPoint(this.bfClient.remainPoint); - - accountList.list_Account.Focus(); - - bool hasAccounts = this.bfClient.accountList.Count() > 0; - bool wantsAutoStart = (bool)settingPage.autoStartGame.IsChecked && hasAccounts; - if (wantsAutoStart) - { - bool useTradLogin = - (bool)settingPage.tradLogin.IsChecked && login_action_type == 1; - if (useTradLogin || login_action_type == 0) - runGame(); - accountList.btnGetOtp_Click(null, null); - } - } - catch - { - errexit(TryFindResource("LoginNoAccountMatch") as string, 1); - } - } - - // Login do work. - private void loginWorker_DoWork(object sender, DoWorkEventArgs e) - { - //if (this.pingWorker.IsBusy) this.pingWorker.CancelAsync(); - // while (this.pingWorker.IsBusy) - // Thread.Sleep(137); - CancelWork(); - - Console.WriteLine("loginWorker starting"); - Thread.CurrentThread.Name = "Login Worker"; - e.Result = ""; - try - { - loginWaitPage.Dispatcher.Invoke( - new Action( - delegate - { - if (App.LoginMethod != (int)LoginMethod.QRCode) - this.bfClient = new BeanfunClient(); - this.bfClient.Login( - loginPage.id_pass.t_AccountID.Text, - loginPage.id_pass.t_Password.Password, - App.LoginMethod, - this.qrcodeClass, - this.service_code, - this.service_region - ); - } - ) - ); - if (this.bfClient.errmsg != null) - e.Result = this.bfClient.errmsg; - else - e.Result = null; - } - catch (Exception ex) - { - e.Result = - (TryFindResource("LoginErrorUnknown") as string) - + "\n\n" - + ex.Message - + "\n" - + ex.StackTrace; - } - - ResumeWork(); - } - - // Login completed. - private void loginWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - Console.WriteLine("loginWorker end"); - if (e != null && e.Error != null) - { - errexit(e.Error.Message, 1); - NavigateLoginPage(); - return; - } - if (e != null && (string)e.Result != null) - { - if ((string)e.Result == "need_totp") - { - frame.Content = loginTotp; - loginTotp.btn_login.IsEnabled = true; - loginTotp.btn_cancel.IsEnabled = true; - loginTotp.otp1.Text = ""; - loginTotp.otp2.Text = ""; - loginTotp.otp3.Text = ""; - loginTotp.otp4.Text = ""; - loginTotp.otp5.Text = ""; - loginTotp.otp6.Text = ""; - loginTotp.otp1.Focus(); - return; - } - else if ((string)e.Result == "LoginAdvanceCheck") - { - MessageBox.Show(TryFindResource("MsgNeedAuth") as string); - - // Handle panel switching. - frame.Content = verifyPage; - if ((bool)verifyPage.checkBoxRememberVerify.IsChecked) - verifyPage.t_Code.Focus(); - else - verifyPage.t_Verify.Focus(); - verifyPage.t_Verify.Text = accountManager.getVerifyByAccount( - App.LoginRegion, - loginPage.id_pass.t_AccountID.Text - ); - verifyPage.checkBoxRememberVerify.IsChecked = - verifyPage.t_Verify.Text != null && verifyPage.t_Verify.Text != ""; - verifyPage.t_Code.Text = ""; - string response = this.bfClient.getVerifyPageInfo(); - if (response == null) - { - MessageBox.Show(I18n.ToSimplified(this.bfClient.errmsg)); - NavigateLoginPage(); - } - string errmsg = reLoadVerifyPage(response); - if (errmsg != null) - { - MessageBox.Show(I18n.ToSimplified(errmsg)); - NavigateLoginPage(); - } - } - else if (((string)e.Result).StartsWith("bfAPPAutoLogin.ashx")) - { - string[] args = Regex.Split((string)e.Result, "\",\""); - if (args.Length < 2) - { - errexit("LoginUnknown", 1); - return; - } - loginWaitPage.t_Info.Content = Regex.Unescape( - TryFindResource("MsgNeedBeanfunAuth") as string - ); - bfAPPAutoLogin.IsEnabled = true; - } - else - { - errexit((string)e.Result, 1); - } - return; - } - - OnLoginCompleted(); - } - - // totp do work. - private void totpWorker_DoWork(object sender, DoWorkEventArgs e) - { - //if (this.pingWorker.IsBusy) this.pingWorker.CancelAsync(); - // while (this.pingWorker.IsBusy) - // Thread.Sleep(137); - CancelWork(); - - Console.WriteLine("loginWorker starting"); - Thread.CurrentThread.Name = "Totp Worker"; - e.Result = ""; - try - { - loginWaitPage.Dispatcher.Invoke( - new Action( - delegate - { - this.bfClient.TotpLogin( - loginTotp.otp1.Text, - loginTotp.otp2.Text, - loginTotp.otp3.Text, - loginTotp.otp4.Text, - loginTotp.otp5.Text, - loginTotp.otp6.Text, - this.service_code, - this.service_region - ); - } - ) - ); - if (this.bfClient.errmsg != null) - e.Result = this.bfClient.errmsg; - else - e.Result = null; - } - catch (Exception ex) - { - e.Result = - (TryFindResource("LoginErrorUnknown") as string) - + "\n\n" - + ex.Message - + "\n" - + ex.StackTrace; - } - - ResumeWork(); - } - - // Login completed. - private void totpWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - Console.WriteLine("loginWorker end"); - if (e != null && e.Error != null) - { - errexit(e.Error.Message, 1); - NavigateLoginPage(); - return; - } - if (e != null && (string)e.Result != null) - { - if ((string)e.Result == "LoginAdvanceCheck") - { - MessageBox.Show(TryFindResource("MsgNeedAuth") as string); - - // Handle panel switching. - frame.Content = verifyPage; - if ((bool)verifyPage.checkBoxRememberVerify.IsChecked) - verifyPage.t_Code.Focus(); - else - verifyPage.t_Verify.Focus(); - verifyPage.t_Verify.Text = accountManager.getVerifyByAccount( - App.LoginRegion, - loginPage.id_pass.t_AccountID.Text - ); - verifyPage.checkBoxRememberVerify.IsChecked = - verifyPage.t_Verify.Text != null && verifyPage.t_Verify.Text != ""; - verifyPage.t_Code.Text = ""; - string response = this.bfClient.getVerifyPageInfo(); - if (response == null) - { - MessageBox.Show(I18n.ToSimplified(this.bfClient.errmsg)); - NavigateLoginPage(); - } - string errmsg = reLoadVerifyPage(response); - if (errmsg != null) - { - MessageBox.Show(I18n.ToSimplified(errmsg)); - NavigateLoginPage(); - } - } - else if (((string)e.Result).StartsWith("bfAPPAutoLogin.ashx")) - { - string[] args = Regex.Split((string)e.Result, "\",\""); - if (args.Length < 2) - { - errexit("LoginUnknown", 1); - return; - } - loginWaitPage.t_Info.Content = Regex.Unescape( - TryFindResource("MsgNeedBeanfunAuth") as string - ); - bfAPPAutoLogin.IsEnabled = true; - } - else - { - errexit((string)e.Result, 1); - } - return; - } - - OnLoginCompleted(); - } - - private void redrawSAccountList() - { - if (this.bfClient.accountAmountLimitNotice != "") - { - accountList.lbl_AccountAmountLimitNotice.Content = - this.bfClient.accountAmountLimitNotice; - accountList.accLimit.Visibility = Visibility.Visible; - int accLimit; - try - { - accLimit = int.Parse( - this.bfClient.accountAmountLimitNotice.Substring( - this.bfClient.accountAmountLimitNotice.Length - 1, - 1 - ) - ); - } - catch - { - accLimit = -1; - } - if (accLimit == -1) - { - accountList.btnAddServiceAccount.Content = TryFindResource("GoToVerify"); - accountList.btnAddServiceAccount.IsEnabled = true; - accountList.btnAddServiceAccount.Visibility = Visibility.Visible; - } - else - { - accountList.btnAddServiceAccount.Content = TryFindResource("AddServiceAccount"); - accountList.btnAddServiceAccount.IsEnabled = - this.bfClient.accountList.Count < accLimit; - accountList.btnAddServiceAccount.Visibility = - this.bfClient.accountList.Count < accLimit - ? Visibility.Visible - : Visibility.Hidden; - } - } - else - { - accountList.lbl_AccountAmountLimitNotice.Content = ""; - accountList.accLimit.Visibility = Visibility.Collapsed; - } - - accountList.list_Account.ItemsSource = null; - accountList.list_Account.ItemsSource = this.bfClient.accountList; - - string gameCode = service_code + "_" + service_region; - Visibility visable = - App.LoginRegion == "TW" ? Visibility.Visible : Visibility.Collapsed; - if (accountList.list_Account.Items.Count > 0) - { - accountList.list_Account.SelectedIndex = 0; - - accountList.m_CopyAccount.Visibility = Visibility.Visible; - //accountList.m_ChangeAccName.Visibility = !UnconnectedGame || App.LoginRegion != "TW" ? Visibility.Visible : Visibility.Collapsed; - accountList.m_ChangePassword.Visibility = UnconnectedGame - ? Visibility.Visible - : Visibility.Collapsed; - //accountList.m_AccInfo.Visibility = !UnconnectedGame || App.LoginRegion != "TW" ? Visibility.Visible : Visibility.Collapsed; - accountList.s_Account.Visibility = Visibility.Visible; - } - else - { - accountList.m_CopyAccount.Visibility = Visibility.Collapsed; - //accountList.m_ChangeAccName.Visibility = Visibility.Collapsed; - accountList.m_ChangePassword.Visibility = Visibility.Collapsed; - //accountList.m_AccInfo.Visibility = Visibility.Collapsed; - accountList.s_Account.Visibility = Visibility.Collapsed; - } - accountList.m_GetEmail.Visibility = visable; - - if (gameCode == "610074_T9" || gameCode == "610075_T9" || gameCode == "610096_TE") - accountList.btn_Tools.Visibility = Visibility.Visible; - else - accountList.btn_Tools.Visibility = Visibility.Collapsed; - } - - public void updateRemainPoint(int remainPoint) - { - accountList.m_RemainPoint.Header = string.Format( - TryFindResource("GashRemain") as string, - $"{remainPoint}{(App.LoginRegion == "TW" || remainPoint == 0 ? "" : string.Format(TryFindResource("GashRemainInGame") as string, Math.Floor(remainPoint / 2.5)))}" - ); - } - - public void runGame(string account = null, string password = null) - { - string gameCode = service_code + "_" + service_region; - string gamePath = settingPage.t_GamePath.Text; - if (gamePath == "" || !File.Exists(gamePath)) - { - MessageBoxResult result = MessageBox.Show( - TryFindResource("MsgCantFindGame") as string, - "", - MessageBoxButton.YesNo - ); - if (result == MessageBoxResult.Yes || SelectedGame == null) - { - btn_SetGamePath_Click(null, null); - } - else - { - Process.Start( - new ProcessStartInfo(SelectedGame.download_url) { UseShellExecute = true } - ); - } - return; - } - gamePath = settingPage.t_GamePath.Text; - if (gamePath == "" || !File.Exists(gamePath)) - { - return; - } - - for (int i = 0; i < gamePath.Length; i++) - { - if ( - Convert.ToInt32(Convert.ToChar(gamePath.Substring(i, 1))) - > Convert.ToInt32(Convert.ToChar(128)) - ) - { - MessageBox.Show(TryFindResource("MsgGamePathHaveWChar") as string); - break; - } - } - - List processIds = new List(); - - Regex regexx = new Regex("(.*).exe"); - string gameProcessName = ""; - if (regexx.IsMatch(game_exe)) - gameProcessName = regexx.Match(game_exe).Groups[1].Value; - if (gameProcessName != "") - { - foreach (Process process in Process.GetProcessesByName(gameProcessName)) - { - if (processIds.Contains(process.Id)) - { - continue; - } - try - { - using ( - ManagementObjectSearcher searcher = new ManagementObjectSearcher( - "select * from Win32_Process where ProcessId = " + process.Id - ) - ) - using (ManagementObjectCollection objects = searcher.Get()) - { - if ( - gamePath - == objects - .Cast() - .SingleOrDefault() - ?["executablepath"]?.ToString() - ) - { - processIds.Add(process.Id); - continue; - } - } - } - catch { } - try - { - if (process.MainModule.FileName == gamePath) - { - processIds.Add(process.Id); - continue; - } - } - catch { } - } - } - - if (processIds.Count > 0) - { - MessageBoxResult result = MessageBox.Show( - TryFindResource("MsgGameAlreadyRun") as string, - "", - MessageBoxButton.YesNo - ); - if (result == MessageBoxResult.Yes) - { - foreach (int processId in processIds) - { - try - { - Process process = Process.GetProcessById(processId); - process.Kill(); - } - catch { } - } - } - } - try - { - Console.WriteLine("try open game"); - int runMode = int.Parse(ConfigAppSettings.GetValue("startGameMode", "0")); - if (runMode == (int)GameStartMode.Auto) - { - switch (WindowsAPI.GetSystemDefaultLocaleName()) - { - case "zh-Hant": - case "zh-CHT": - case "zh-TW": - case "zh-HK": - case "zh-MO": - runMode = (int)GameStartMode.Normal; - break; - default: - if (App.OSVersion < App.WinVista) - { - errexit(TryFindResource("MsgLEDoNotSupportXP") as string, 2); - return; - } - else - { - runMode = (int)GameStartMode.LocaleRemulator; - break; - } - } - } - - if (runMode > (int)GameStartMode.LocaleRemulator) - runMode = (int)GameStartMode.LocaleRemulator; - - string commandLine = ""; - if ( - account != null - && password != null - && account != "" - && password != "" - && game_commandLine != "" - ) - { - commandLine = game_commandLine; - Regex regex = new Regex("%s"); - commandLine = regex.Replace(commandLine, account, 1); - commandLine = regex.Replace(commandLine, password, 1); - } - - switch (runMode) - { - case (int)GameStartMode.LocaleRemulator: - startByLR(gamePath, commandLine); - break; - case (int)GameStartMode.Normal: - ProcessStartInfo startInfo = new ProcessStartInfo(gamePath); - startInfo.WorkingDirectory = Path.GetDirectoryName(gamePath); - startInfo.Arguments = commandLine; - Process.Start(startInfo); - break; - } - Console.WriteLine("try open game done"); - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - errexit(Regex.Unescape(TryFindResource("MsgLocalePluginRunError") as string), 2); - } - } - - private void startByLR(string path, string command) - { - if ( - App.ReleaseResource("LRConfig.xml") == -1 - || App.ReleaseResource("LRHookx32.dll") == -1 - || App.ReleaseResource("LRHookx64.dll") == -1 - || App.ReleaseResource("LRProc.exe") == -1 - || App.ReleaseResource("LRSubMenus.dll") == -1 - ) - { - MessageBox.Show(TryFindResource("MsgLocalePluginReleaseError") as string); - return; - } - - var commandLine = string.Empty; - commandLine = path.StartsWith("\"") ? $"{path} " : $"\"{path}\" "; - commandLine += command; - System.Globalization.TextInfo culInfo = System - .Globalization.CultureInfo.GetCultureInfo("zh-HK") - .TextInfo; - - new Thread( - new ThreadStart(() => - { - try - { - var proc = new Process(); - proc.StartInfo.FileName = Path.Combine(App.AppDir, "LRProc.exe"); - proc.StartInfo.Arguments = - "ef3e7b42-a87c-4c07-ae3e-eeebeef12762 " + commandLine; - proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(path); - proc.StartInfo.UseShellExecute = true; - proc.StartInfo.Verb = "runas"; - proc.Start(); - } - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); - errexit( - Regex.Unescape(TryFindResource("MsgLocalePluginRunError") as string), - 2 - ); - } - }) - ).Start(); - } - - public bool AddServiceAccount(string name) - { - if (this.bfClient == null) - return false; - if (name == null || name == "") - return false; - - if (this.bfClient.AddServiceAccount(name, service_code, service_region)) - { - this.bfClient.GetAccounts(service_code, service_region); - int index = accountList.list_Account.SelectedIndex; - redrawSAccountList(); - accountList.list_Account.SelectedIndex = index; - return true; - } - return false; - } - - public string UnconnectedGame_AddAccount( - string name, - string txtNewPwd, - string txtNewPwd2, - string txtServiceAccountDN, - System.Collections.Specialized.NameValueCollection payload - ) - { - if (this.bfClient == null) - return null; - if (name == null || name == "") - return null; - if (txtNewPwd == null || txtNewPwd == "") - return null; - if (txtNewPwd2 == null || txtNewPwd2 == "") - return null; - - string result = this.bfClient.UnconnectedGame_AddAccount( - service_code, - service_region, - name, - txtNewPwd, - txtNewPwd2, - txtServiceAccountDN, - payload - ); - if (result == "") - { - this.bfClient.GetAccounts(service_code, service_region); - int index = accountList.list_Account.SelectedIndex; - redrawSAccountList(); - accountList.list_Account.SelectedIndex = index; - } - return result; - } - - public string UnconnectedGame_ChangePassword(string txtEmail) - { - if (this.bfClient == null) - return null; - if (txtEmail == null) - return null; - - return this.bfClient.UnconnectedGame_ChangePassword( - service_code, - service_region, - accountList.list_Account.SelectedIndex, - txtEmail - ); - } - - public System.Collections.Specialized.NameValueCollection UnconnectedGame_AddAccountInit() - { - if (this.bfClient == null) - return null; - return this.bfClient.UnconnectedGame_InitAddAccountPayload( - service_code, - service_region - ); - } - - public System.Collections.Specialized.NameValueCollection UnconnectedGame_AddUnconnectedCheck( - string name, - string txtServiceAccountDN, - System.Collections.Specialized.NameValueCollection payload - ) - { - if (this.bfClient == null) - return null; - return this.bfClient.UnconnectedGame_AddAccountCheck( - service_code, - service_region, - name, - txtServiceAccountDN, - payload - ); - } - - public System.Collections.Specialized.NameValueCollection UnconnectedGame_AddAccountCheckNickName( - string txtServiceAccountDN, - System.Collections.Specialized.NameValueCollection payload - ) - { - if (this.bfClient == null) - return null; - return this.bfClient.UnconnectedGame_AddAccountCheckNickName( - service_code, - service_region, - txtServiceAccountDN, - payload - ); - } - - public bool ChangeServiceAccountDisplayName(string newName) - { - if (this.bfClient == null) - return false; - BeanfunClient.ServiceAccount account = (BeanfunClient.ServiceAccount) - accountList.list_Account.SelectedItem; - if (newName == null || newName == "" || account == null) - return false; - if (newName == account.sname) - return true; - - string gameCode = service_code + "_" + service_region; - if (this.bfClient.ChangeServiceAccountDisplayName(newName, gameCode, account)) - { - account.sname = newName; - int index = accountList.list_Account.SelectedIndex; - redrawSAccountList(); - accountList.list_Account.SelectedIndex = index; - return true; - } - return false; - } - - public string GetServiceContract() - { - if (this.bfClient == null) - return ""; - - return this.bfClient.GetServiceContract(service_code, service_region); - } - - // getOTP do work. - private void getOtpWorker_DoWork(object sender, DoWorkEventArgs e) - { - CancelWork(); - - Console.WriteLine("getOtpWorker start"); - Thread.CurrentThread.Name = "GetOTP Worker"; - int index = (int)e.Argument; - Console.WriteLine("Count = " + this.bfClient.accountList.Count + " | index = " + index); - if (this.bfClient.accountList.Count <= index) - { - return; - } - Console.WriteLine("call GetOTP"); - Monitor.Enter(_bfClientLock); - try - { - this.otp = this.bfClient.GetOTP( - this.bfClient.accountList[index], - this.service_code, - this.service_region - ); - } - finally - { - Monitor.Exit(_bfClientLock); - } - Console.WriteLine("call GetOTP done"); - if (this.otp == null) - e.Result = -1; - else - { - e.Result = index; - } - - ResumeWork(); - return; - } - - // getOTP completed. - private void getOtpWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - accountList.btnGetOtp.Content = TryFindResource("GetOtp") as string; - if (e.Error != null) - { - errexit(e.Error.Message, 2, TryFindResource("GetOtpFailed") as string); - } - else - { - int index = (int)e.Result; - - if (index == -1) - { - errexit(this.bfClient.errmsg, 2, TryFindResource("GetOtpFailed") as string); - } - else - { - int accIndex = accountList.list_Account.SelectedIndex; - string acc = this.bfClient.accountList[index].sid; - accountList.t_Password.Text = this.otp; - - if (!(bool)settingPage.tradLogin.IsChecked && login_action_type == 1) - { - runGame(acc, accountList.t_Password.Text); - } - else - { - IntPtr hWnd = WindowsAPI.FindWindow(win_class_name, null); - if ("MapleStoryClass".Equals(win_class_name) && hWnd == IntPtr.Zero) - { - hWnd = WindowsAPI.FindWindow("MapleStoryClassTW", null); - } - if ( - hWnd == IntPtr.Zero - || !(bool)accountList.autoPaste.IsChecked - || accountList.autoPaste.Visibility != Visibility.Visible - ) - { - try - { - WindowsAPI.CopyText(accountList.t_Password.Text); - } - catch { } - ShowOtpCopiedHint(); - } - else - { - System.Drawing.Size wndSize = System.Drawing.Size.Empty; - if (hWnd != IntPtr.Zero) - { - wndSize = WindowsAPI.GetClientAreaSize(hWnd); - } - - if (wndSize != System.Drawing.Size.Empty) - { - const int WM_KEYDOWN = 0X100; - const int WM_LBUTTONDOWN = 0x0201; - const byte VK_BACK = 0x0008; - const byte VK_TAB = 0x0009; - const byte VK_ENTER = 0x000D; - const byte VK_ESCAPE = 0x001B; - const byte VK_END = 0x0023; - WindowsAPI.SetForegroundWindow(hWnd); - Thread.Sleep(100); - if ("610074".Equals(service_code) && "T9".Equals(service_region)) - { - // 按下ESC關閉提示框 - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_ESCAPE); - Thread.Sleep(100); - // 選中帳號欄 - System.Drawing.Point oldPoint = new System.Drawing.Point(0, 0); - WindowsAPI.GetCursorPos(ref oldPoint); - System.Drawing.Point point = new System.Drawing.Point(0, 0); - WindowsAPI.ClientToScreen(hWnd, ref point); - System.Drawing.Point textBoxPoint = new System.Drawing.Point( - (int)(wndSize.Width * 0.5), - (int)(wndSize.Height * 0.4) - ); - WindowsAPI.SetCursorPos( - point.X + textBoxPoint.X, - point.Y + textBoxPoint.Y - ); - int pos = (textBoxPoint.X & 0xFFFF) | (textBoxPoint.Y << 16); - WindowsAPI.PostMessage(hWnd, WM_LBUTTONDOWN, 1, pos); - Thread.Sleep(200); - WindowsAPI.SetCursorPos(oldPoint.X, oldPoint.Y); - } - // 清空帳號欄內容 - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_END); - for (int i = 0; i < 64; i++) - { - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_BACK); - } - // 輸入帳號 - WindowsAPI.PostString(hWnd, acc); - // 切換到密碼欄 - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_TAB); - // 清空密碼欄內容 - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_END); - for (int i = 0; i < 20; i++) - { - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_BACK); - } - // 輸入密碼 - WindowsAPI.PostString(hWnd, accountList.t_Password.Text); - // 按登入 - WindowsAPI.PostKey(hWnd, WM_KEYDOWN, VK_ENTER); - } - } - } - } - } - - Console.WriteLine("getOtpWorker end"); - - accountList.list_Account.IsEnabled = true; - accountList.btnGetOtp.IsEnabled = true; - accountList.btn_Logout.IsEnabled = true; - accountList.btn_ChangeGame.IsEnabled = true; - accountList.gameName.IsEnabled = true; - accountList.btn_StartGame.IsEnabled = true; - accountList.m_MenuList.IsEnabled = true; - if (this.bfClient.accountAmountLimitNotice != "") - accountList.btnAddServiceAccount.IsEnabled = - this.bfClient.accountList.Count - < int.Parse( - this.bfClient.accountAmountLimitNotice.Substring( - this.bfClient.accountAmountLimitNotice.Length - 1, - 1 - ) - ); - } - - public void ShowOtpCopiedHint(string message = null) - { - accountList.toastText.Text = - "✓ " + (message ?? TryFindResource("GetOtpSuccessAndCopy") as string ?? "Copied!"); - accountList.toastBorder.Background = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("#CC2E7D32") - ); - accountList.toastBorder.Visibility = Visibility.Visible; - var timer = new System.Windows.Threading.DispatcherTimer - { - Interval = TimeSpan.FromSeconds(2), - }; - timer.Tick += (s, _) => - { - timer.Stop(); - accountList.toastBorder.Visibility = Visibility.Collapsed; - accountList.toastBorder.Background = new SolidColorBrush( - (Color)ColorConverter.ConvertFromString("#CC333333") - ); - }; - timer.Start(); - } - - // Ping to Beanfun website. - private void pingWorker_DoWork(object sender, DoWorkEventArgs e) - { - Thread.CurrentThread.Name = "ping Worker"; - Console.WriteLine("pingWorker start"); - const int WaitSecs = 60; // 1min - - while (!isCancelRequested) - { - if (this.pingWorker.CancellationPending) - { - Console.WriteLine("break duo to cancel"); - break; - } - - if ( - this.getOtpWorker.IsBusy - || this.loginWorker.IsBusy - || this.totpWorker.IsBusy - || this.qrWorker.IsBusy - || this.verifyWorker.IsBusy - ) - { - Console.WriteLine("ping.busy sleep 1s"); - System.Threading.Thread.Sleep(1000 * 1); - continue; - } - - if (this.bfClient != null && Monitor.TryEnter(_bfClientLock)) - { - try - { - this.bfClient.Ping(); - } - finally - { - Monitor.Exit(_bfClientLock); - } - } - - for (int i = 0; i < WaitSecs; ++i) - { - if (this.pingWorker.CancellationPending) - break; - System.Threading.Thread.Sleep(1000 * 1); - } - } - } - - private void pingWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - Console.WriteLine("ping.done"); - } - - private void qrWorker_DoWork(object sender, DoWorkEventArgs e) - { - if (qrWorker.CancellationPending) - { - e.Cancel = true; - return; - } - this.bfClient = new BeanfunClient(); - string skey = this.bfClient.GetSessionkey(); - this.qrcodeClass = this.bfClient.GetQRCodeValue(skey); - } - - private void qrWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - btn_Region.IsEnabled = true; - if (e.Cancelled) - return; - if (updateQRCodeImage()) - { - qrCheckLogin.IsEnabled = true; - } - else - { - App.LoginMethod = (int)LoginMethod.Regular; - Dispatcher.BeginInvoke(new System.Action(() => loginMethodChanged())); - } - } - - private void qrCheckLogin_Tick(object sender, EventArgs e) - { - if (this.qrcodeClass == null) - { - MessageBox.Show("QRCode not get yet"); - return; - } - if (!Monitor.TryEnter(_bfClientLock)) - return; - int res; - try - { - res = this.bfClient.QRCodeCheckLoginStatus(this.qrcodeClass); - } - finally - { - Monitor.Exit(_bfClientLock); - } - if (res != 0) - this.qrCheckLogin.IsEnabled = false; - if (res == 1) - { - do_Login(); - } - if (res == -2) - { - refreshQRCode(); - } - } - - public void refreshQRCode() - { - if (!qrWorker.IsBusy) - qrWorker.RunWorkerAsync(loginPage == null || loginPage.qr == null ? false : true); - } - - public bool updateQRCodeImage() - { - loginPage.qr.btn_Refresh_QRCode.IsEnabled = false; - - BitmapImage qrCodeImage; - bool result; - if ( - this.qrcodeClass == null - || (qrCodeImage = this.bfClient.getQRCodeImage(qrcodeClass)) == null - ) - { - result = false; - loginPage.qr.qr_image.Source = qr_default; - loginPage.qr.btn_CopyQR.IsEnabled = false; - loginPage.qr.btn_EnlargeQR.IsEnabled = false; - } - else - { - result = true; - loginPage.qr.qr_image.Source = qrCodeImage; - loginPage.qr.btn_CopyQR.IsEnabled = true; - loginPage.qr.btn_EnlargeQR.IsEnabled = true; - } - loginPage.qr.btn_Refresh_QRCode.IsEnabled = true; - - return result; - } - - private void bfAPPAutoLogin_Tick(object sender, EventArgs e) - { - if (!Monitor.TryEnter(_bfClientLock)) - return; - JObject resultJson; - try - { - resultJson = this.bfClient.CheckIsRegisteDevice(service_code, service_region); - } - finally - { - Monitor.Exit(_bfClientLock); - } - if (resultJson == null || resultJson["IntResult"] == null) - return; - if ((string)resultJson["IntResult"] != "1" && (string)resultJson["IntResult"] != "0") - this.bfAPPAutoLogin.IsEnabled = false; - - switch ((string)resultJson["IntResult"]) - { - case "-3": - Console.WriteLine("登入請求被拒絕"); - errexit(TryFindResource("MsgBeanfunRejectLogin") as string, 1); - break; - case "-2": - Console.WriteLine("登入請求已逾時"); - NavigateLoginPage(); - break; - case "-1": - errexit((string)resultJson["StrReslut"], 1); - break; - case "0": - return; - case "1": - Console.WriteLine("尚未授權本次登入"); - return; - case "2": - loginWorker_RunWorkerCompleted(null, null); - break; - } - loginWaitPage.t_Info.Content = TryFindResource("MsgLogging") as string; - } - - private void checkPlayPage_Tick(object sender, EventArgs e) - { - try - { - const uint WM_CLOSE = 0x10; - IntPtr hWnd; - if ((hWnd = WindowsAPI.FindWindow("StartUpDlgClass", "MapleStory")) != IntPtr.Zero) - WindowsAPI.PostMessage(hWnd, WM_CLOSE, 0, 0); - } - catch { } - } - - private void checkPatcher_Tick(object sender, EventArgs e) - { - if (settingPage == null || settingPage.t_GamePath == null) - return; - bool found = false; - try - { - string patherPath = - Path.GetDirectoryName(settingPage.t_GamePath.Text) + "\\Patcher.exe"; - foreach (Process process in Process.GetProcessesByName("Patcher")) - { - try - { - if (process.MainModule.FileName == patherPath) - { - process.Kill(); - found = true; - } - } - catch { } - } - } - catch { } - - if (found) - { - short ClientMapleMajor = 0; - short ClientMapleMinor = 0; - short SrvMapleMajor = 0; - string SrvMapleMinor = ""; - try - { - // 獲取客戶端版本 - FileVersionInfo fileVerInfo = FileVersionInfo.GetVersionInfo( - settingPage.t_GamePath.Text - ); - ClientMapleMajor = (short)fileVerInfo.ProductMinorPart; - ClientMapleMinor = (short)fileVerInfo.FileBuildPart; - - // 獲取伺服器版本 - CancellationTokenSource c = new CancellationTokenSource(); - CancellationToken token = c.Token; - byte[] Data = null; - System.Threading.Tasks.Task task = new System.Threading.Tasks.Task( - () => - { - try - { - var tcpClient = new System.Net.Sockets.TcpClient(); - tcpClient.SendTimeout = 6000; - tcpClient.ReceiveTimeout = 6000; - string WvsLoginServerDomain = "tw.login.maplestory.beanfun.com"; - if ("610075_T9".Equals(service_code + "_" + service_region)) - WvsLoginServerDomain = "tw.loginT.maplestory.beanfun.com"; - tcpClient.Connect(WvsLoginServerDomain, 8484); - - if (tcpClient.Connected) - { - Data = new Byte[1024]; - System.Net.Sockets.NetworkStream nsData = tcpClient.GetStream(); - Int32 bytes = nsData.Read(Data, 0, Data.Length); - } - - tcpClient.Close(); - while (true) - { - if (token.IsCancellationRequested) - { - throw new OperationCanceledException(); - } - } - } - catch { } - ; - }, - token - ); - - task.Start(); - task.Wait(3000, token); - c.Cancel(); - if (Data != null) - { - if (accountList != null) - { - MapleLib.PacketLib.PacketReader packet = - new MapleLib.PacketLib.PacketReader(Data); - packet.ReadShort(); - SrvMapleMajor = packet.ReadShort(); - SrvMapleMinor = packet.ReadMapleString(); - packet.Skip(4); - packet.Skip(4); - byte MapleRegion = packet.ReadByte(); - Console.WriteLine( - "伺服器版本: " - + SrvMapleMajor - + "\r\n小版本: " - + SrvMapleMinor.Split(':')[0] - + "\r\n區域號: " - + MapleRegion - ); - - if ( - SrvMapleMajor == 0 - || SrvMapleMinor.Split(':')[0] == "" - || MapleRegion == 0 - ) - Data = null; - } - } - if (Data == null) - { - SrvMapleMajor = 0; - SrvMapleMinor = ""; - } - } - catch { } - string info = ""; - if (ClientMapleMajor != 0) - { - info += - $"\r\n{TryFindResource("ClientVersion") as string}{ClientMapleMajor}.{ClientMapleMinor}"; - if (SrvMapleMajor != 0 && SrvMapleMinor.Split(':')[0] != "") - { - info += - $"\r\n{TryFindResource("ServerVersion") as string}{SrvMapleMajor}.{SrvMapleMinor.Split(':')[0]}"; - } - } - bool isCanUpdate = - ClientMapleMajor != 0 - && SrvMapleMajor != 0 - && ClientMapleMajor >= (SrvMapleMajor - 2); - MessageBoxResult result = MessageBox.Show( - string.Format( - Regex.Unescape(TryFindResource("MsgKillPatcher") as string), - info, - isCanUpdate && ClientMapleMajor == SrvMapleMajor - ? $"V{SrvMapleMajor}.{SrvMapleMinor.Split(':')[0]}fix" - : "", - isCanUpdate - ? TryFindResource("UpdateByPatch") - : TryFindResource("UpdateByFullClient"), - isCanUpdate - ? TryFindResource("GamePatch") - : TryFindResource("GameFullClient") - ), - TryFindResource("WarningByBeanfun") as string, - MessageBoxButton.YesNo - ); - if (result == MessageBoxResult.Yes) - Process.Start( - new ProcessStartInfo( - $"https://maplestory.beanfun.com/download{(isCanUpdate ? "?download_type=2" : "")}" - ) - { - UseShellExecute = true, - } - ); - } - } - - private void verifyWorker_DoWork(object sender, DoWorkEventArgs e) - { - e.Result = null; - string response = ""; - verifyPage.Dispatcher.Invoke( - new Action( - delegate - { - response = this.bfClient.verify( - viewstate, - eventvalidation, - samplecaptcha, - verifyPage.t_Verify.Text, - verifyPage.t_Code.Text - ); - } - ) - ); - Regex regex = new Regex("alert\\('(.*)'\\);"); - string msg = null; - if (regex.IsMatch(response)) - { - msg = regex.Match(response).Groups[1].Value; - } - if (msg == null) - { - if (response.Contains("圖形驗證碼輸入錯誤")) - { - MessageBox.Show(TryFindResource("WrongCaptcha") as string); - } - else - { - MessageBox.Show(TryFindResource("WrongAuthInfo") as string); - } - } - else - { - if (msg.Contains("資料已驗證成功")) - { - e.Result = true; - } - else - { - MessageBox.Show(msg.Replace("\\n", "\n").Replace("\\r", "\r")); - } - } - if (e.Result == null) - { - string errmsg = "Error Load Verify Page"; - verifyPage.Dispatcher.Invoke( - new Action( - delegate - { - errmsg = reLoadVerifyPage(response); - verifyPage.t_Code.Text = ""; - } - ) - ); - if (errmsg != null) - { - MessageBox.Show(I18n.ToSimplified(errmsg)); - } - } - } - - private void verifyWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) - { - if (e.Result != null) - { - do_Login(); - } - } - } -} diff --git a/Beanfun/Pages/About.xaml b/Beanfun/Pages/About.xaml deleted file mode 100644 index 01156eb..0000000 --- a/Beanfun/Pages/About.xaml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Beanfun/Pages/id-pass_form.xaml.cs b/Beanfun/Pages/id-pass_form.xaml.cs deleted file mode 100644 index 7ff8b4d..0000000 --- a/Beanfun/Pages/id-pass_form.xaml.cs +++ /dev/null @@ -1,302 +0,0 @@ -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Windows; -using System.Windows.Controls; - -namespace Beanfun -{ - /// - /// id_pass_form.xaml 的交互逻辑 - /// - public partial class id_pass_form : Page - { - public id_pass_form() - { - InitializeComponent(); - - this.Loaded += (sender, e) => - { - var tb = - t_AccountID.Template.FindName("PART_EditableTextBox", t_AccountID) as TextBox; - if (tb != null) - System.Windows.Input.InputMethod.SetPreferredImeState( - tb, - System.Windows.Input.InputMethodState.Off - ); - }; - } - - private void checkBox_RememberPWD_Unchecked(object sender, RoutedEventArgs e) - { - checkBox_AutoLogin.IsChecked = false; - } - - private void checkBox_AutoLogin_Checked(object sender, RoutedEventArgs e) - { - checkBox_RememberPWD.IsChecked = true; - } - - private void RegAcc_Click(object sender, RoutedEventArgs e) - { - string url; - if (App.LoginRegion == "TW") - { - url = "https://tw.beanfun.com/TW/signup/Join_beanfun_signup.aspx?service=999999_T0"; - } - else - { - url = - "https://bfweb.hk.beanfun.com/beanfun_web_ap/signup/preregistration.aspx?service=999999_T0"; - } - new WebBrowser(url).Show(); - } - - private void FindPwd_Click(object sender, RoutedEventArgs e) - { - string url; - if (App.LoginRegion == "TW") - { - url = "https://tw.beanfun.com/member/forgot_pwd.aspx"; - } - else - { - url = "https://bfweb.hk.beanfun.com/member/forgot_pwd.aspx"; - } - new WebBrowser(url).Show(); - } - - private void btn_login_Click(object sender, RoutedEventArgs e) - { - if (t_AccountID.Text == null || t_AccountID.Text == "") - { - MessageBox.Show(TryFindResource("AccountNeed") as string); - return; - } - if (t_Password.Password == null || t_Password.Password == "") - { - MessageBox.Show(TryFindResource("PasswordNeed") as string); - return; - } - //System.Console.WriteLine("PW" + t_Password.Password); - App.MainWnd.do_Login(); - } - - private void Button_Click(object sender, RoutedEventArgs e) - { - new GameList().ShowDialog(); - } - - private void t_AccountID_TextChanged(object sender, System.EventArgs e) - { - TextBox tb = - t_AccountID.Template.FindName("PART_EditableTextBox", t_AccountID) as TextBox; - int caretIndex = 0; - if (tb != null) - caretIndex = tb.CaretIndex; - - string tbAccount = t_AccountID.Text; - - Regex regex = new Regex(@"\((.*)\)"); - if (regex.IsMatch(tbAccount)) - { - t_AccountID.Text = regex.Match(tbAccount).Groups[1].Value; - tb.Text = t_AccountID.Text; - } - - List searches = new List(); - List accList = new List(); - string[] accArr = App.MainWnd.accountManager.getAccountList(App.LoginRegion); - - bool IsFind = false; - foreach (string s in accArr) - { - if (s == t_AccountID.Text) - { - IsFind = true; - } - accList.Add(s); - } - - searches = accList.FindAll( - delegate(string s) - { - return s.Contains(t_AccountID.Text.Trim()); - } - ); - - for (int i = 0; i < accList.Count; i++) - { - string name = App.MainWnd.accountManager.getNameByAccount( - App.LoginRegion, - accList[i] - ); - if (name != null && name != "") - { - if (tbAccount == accList[i]) - tbAccount = name + "(" + accList[i] + ")"; - accList[i] = name + "(" + accList[i] + ")"; - } - } - - for (int i = 0; i < searches.Count; i++) - { - string name = App.MainWnd.accountManager.getNameByAccount( - App.LoginRegion, - searches[i] - ); - if (name != null && name != "") - { - searches[i] = name + "(" + searches[i] + ")"; - } - } - - if (!IsFind && t_AccountID.Text != "" && searches.Count > 0) - { - t_AccountID.IsDropDownOpen = true; - t_AccountID.ItemsSource = null; - t_AccountID.ItemsSource = searches; - t_AccountID.SelectedIndex = -1; - t_AccountID.Text = tbAccount; - } - else - { - t_AccountID.ItemsSource = null; - t_AccountID.ItemsSource = accList; - if (!IsFind) - { - t_AccountID.SelectedIndex = -1; - t_AccountID.Text = tbAccount; - } - t_AccountID.IsDropDownOpen = false; - - if (IsFind) - { - if (accList.Count > 0) - t_AccountID.SelectedItem = tbAccount; - - t_Password.Password = ""; - checkBox_RememberPWD.IsChecked = false; - - int loginMethod = App.MainWnd.accountManager.getMethodByAccount( - App.LoginRegion, - t_AccountID.Text - ); - if (loginMethod > -1) - App.LoginMethod = loginMethod; - App.MainWnd.loginMethodChanged(); - } - } - - if (tb != null) - tb.CaretIndex = caretIndex; - } - - private void t_AccountID_GotFocus(object sender, RoutedEventArgs e) - { - var tb = t_AccountID.Template.FindName("PART_EditableTextBox", t_AccountID) as TextBox; - if (tb != null) - { - tb.CaretIndex = tb.Text.Length; - } - } - - private void t_AccountID_DropDown(object sender, System.EventArgs e) - { - var tb = t_AccountID.Template.FindName("PART_EditableTextBox", t_AccountID) as TextBox; - if (tb != null) - { - string tbAccount = t_AccountID.Text; - string name = App.MainWnd.accountManager.getNameByAccount( - App.LoginRegion, - tbAccount - ); - if (name != null && name != "") - tbAccount = name + "(" + tbAccount + ")"; - if ( - (t_AccountID.ItemsSource as List) - .FindAll( - delegate(string s) - { - return s.Equals(tbAccount.Trim()); - } - ) - .Count <= 0 - ) - tb.SelectionLength = 0; - else - tb.CaretIndex = tb.Text.Length; - } - } - - private void DeleteButton_Click(object sender, RoutedEventArgs e) - { - string t_AccID = t_AccountID.Text; - Button closeButton = sender as Button; - string t_AccID_toDelete = (string)closeButton.Tag; - - Regex regex = new Regex(@"\((.*)\)"); - if (regex.IsMatch(t_AccID_toDelete)) - t_AccID_toDelete = regex.Match(t_AccID_toDelete).Groups[1].Value; - - MessageBoxResult result = MessageBox.Show( - string.Format(TryFindResource("MsgDeleteAccount") as string, t_AccID_toDelete), - TryFindResource("DeleteAccount") as string, - MessageBoxButton.YesNo - ); - - if (result == MessageBoxResult.Yes) - { - App.MainWnd.accountManager.removeAccount(App.LoginRegion, t_AccID_toDelete); - App.MainWnd.loginMethodInit(); - - foreach (string s in t_AccountID.Items) - { - string str = s; - if (regex.IsMatch(str)) - str = regex.Match(str).Groups[1].Value; - if (t_AccID == str) - { - t_AccountID.SelectedItem = str; - break; - } - } - } - } - - private void btn_QRCode_Click(object sender, RoutedEventArgs e) - { - App.LoginMethod = (int)LoginMethod.QRCode; - App.MainWnd.loginMethodChanged(); - } - - private async void btn_GamePass_Click(object sender, RoutedEventArgs e) - { - btn_GamePass.IsEnabled = false; - try - { - var client = new BeanfunClient(); - string skey = await System.Threading.Tasks.Task.Run(() => client.GetSessionkey()); - if (string.IsNullOrEmpty(skey)) - { - MessageBox.Show(TryFindResource("SessionKeyFailed") as string); - return; - } - App.MainWnd.bfClient = client; - new GamePassBrowser(skey).Show(); - } - catch - { - MessageBox.Show(TryFindResource("ConnectionFailed") as string); - } - finally - { - btn_GamePass.IsEnabled = true; - } - } - - private void btn_StartGame_Click(object sender, RoutedEventArgs e) - { - App.MainWnd.runGame(); - } - } -} diff --git a/Beanfun/Pages/qr_form.xaml b/Beanfun/Pages/qr_form.xaml deleted file mode 100644 index badddce..0000000 --- a/Beanfun/Pages/qr_form.xaml +++ /dev/null @@ -1,249 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -