diff --git a/Arctium Game Launcher.slnx b/Arctium Game Launcher.slnx
new file mode 100644
index 0000000..8f9f44f
--- /dev/null
+++ b/Arctium Game Launcher.slnx
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/Arctium.WoW.Launcher.sln b/Arctium.WoW.Launcher.sln
deleted file mode 100644
index e6607ac..0000000
--- a/Arctium.WoW.Launcher.sln
+++ /dev/null
@@ -1,34 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31521.260
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Arctium.WoW.Launcher", "src\Arctium.WoW.Launcher.csproj", "{661B173A-D445-4706-9FF2-C0408ED62FA2}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
- Release|x64 = Release|x64
- ReleaseCustomFiles|x64 = ReleaseCustomFiles|x64
- ReleaseCustomFilesSilentMode|x64 = ReleaseCustomFilesSilentMode|x64
- ReleaseSilentMode|x64 = ReleaseSilentMode|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.Debug|x64.ActiveCfg = Debug|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.Debug|x64.Build.0 = Debug|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.Release|x64.ActiveCfg = Release|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.Release|x64.Build.0 = Release|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.ReleaseCustomFiles|x64.ActiveCfg = ReleaseCustomFiles|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.ReleaseCustomFiles|x64.Build.0 = ReleaseCustomFiles|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.ReleaseCustomFilesSilentMode|x64.ActiveCfg = ReleaseCustomFilesSilentMode|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.ReleaseCustomFilesSilentMode|x64.Build.0 = ReleaseCustomFilesSilentMode|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.ReleaseSilentMode|x64.ActiveCfg = ReleaseSilentMode|x64
- {661B173A-D445-4706-9FF2-C0408ED62FA2}.ReleaseSilentMode|x64.Build.0 = ReleaseSilentMode|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {3B82A525-E7C4-4B51-9C88-3AE74C1AEC60}
- EndGlobalSection
-EndGlobal
diff --git a/LICENSE b/LICENSE
index 4219928..97f0514 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2021-2023 Arctium
+Copyright (c) 2021-2026 Arctium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 4d0407d..0e4ea34 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,46 @@
-# THE FUTURE OF THIS LAUNCHER
+# Arctium Game Launcher (Public version)
+A game launcher for World of Warcraft that allows you to connect to custom servers with a valid tls certificate attached.
-Binary releases [HERE](https://arctium.io/wow/)
+**NOTE**: This is a publicly available, stripped down version of the launcher. The **full-featured** launcher is distributed under different terms and is available at https://arctium.io
-As of today (2023-09-30) this project goes closed source and is not longer be MIT licensed.
+### License, Copyright & Contributions
-This does not affect the license of already published sources.
+Please see our Open Source project [Documentation Repo](https://github.com/Arctium/Documentation)
-### This launcher is going to be closed source in future.
+## Special Request <3
+Please do NOT remove the name `arctium` from the final binary.
+Blizzard filters their crash logs based on localhost and the string `arctium` in the binary name.
-What does this mean?
+### Supported Clients
+* 1.14.4 or later
+* 3.4.2 or later
+* 10.1.5 or later
-- **No new MIT licensed binary releases.**
-- **No new features, game support updates or OS updates on this repo.**
-- **Current source with the listed supported game versions and supported systems stays public as it is.**
-- **Future releases with updates for new game versions, operating systems, ... will be available at the same link (https://arctium.io/wow)**
+**Later = all future version in that branch.**
-#### Old README
-Most recent README available here: [README](README_OLD.md)
+### NOTE FOR SERVER CONNECTIONS
+* A valid certificate matching your authentication/bnet server host name.
+ That certificate needs to be loaded by the authentication/bnet server too
+
+### Binary Releases
+There are no binary releases of this version. Our **full-featured** launcher has binary releases at https://arctium.io
+
+## Building
+
+### Build Prerequisites
+* [.NET Core SDK 10.0.0 or later](https://dotnet.microsoft.com/download/dotnet/10.0)
+* Optional for native builds: C++ workload through Visual Studio 2026 or latest C++ build tools
+
+### Build Instructions Windows (native)
+* Execute `dotnet publish -r win-x64 -c Configuration -p:platform="x64" -p:PublishAot=true`
+* Native output is placed in the `build` folder.
+
+## Usage
+
+### Windows Usage
+1. Copy `Actium Game Launcher.exe` to your World of Warcraft folder.
+2. Edit the `WTF/Config.wtf` to set your portal or use a different config file with the `-config Config2.wtf` launch arg.
+3. Run the `Actium Game Launcher.exe`
+
+### Launch Parameters
+Use `--help`
diff --git a/README_OLD.md b/README_OLD.md
deleted file mode 100644
index dc99251..0000000
--- a/README_OLD.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# WoW-Launcher
-A game launcher for World of Warcraft that allows you to connect to custom servers.
-
-### License, Copyright & Contributions
-
-Please see our Open Source project [Documentation Repo](https://github.com/Arctium/Documentation)
-
-## Special Request <3
-
-Please do NOT remove the name `arctium` from the final binary.
-Blizzard filters their crash logs based on localhost and the string `arctium` in the binary name.
-
-### NOTE FOR LOCAL DEVELOPMENT & SERVER CONNECTIONS
-#### Applies to: 1.14.4 or later, 3.4.2 or later, 10.1.5 or later
-* **Dev Mode is enabled by default for local game portals.**
-* LOCAL HOSTNAME & IP: `REQUIRES` the `--dev` command line parameter to force the dev mode to avoid issues with invalid certificate chains. The launcher auto detectes local addresses and enables it.
-* EXTERNAL HOSTNAME:
- * `DO NOT` use the `--dev` command line parameter. It's blocked by the launcher.
- * `USE` a valid certificate matching your authentication/bnet server host name.
- * That certificate needs to be loaded by the authentication/bnet server too.
-* EXTERNAL IP: `NOT SUPPORTED`
-
-### Binary Releases
-You can find signed binary releases at [Releases](https://github.com/Arctium/WoW-Launcher/releases)
-
-### Supported Game Versions (Windows x86 64 bit, Release)
-* Dragonflight: 10.x
-* Shadowlands: 9.x
-* Classic BC/WotLK: 2.5.x, 3.4.x (--version Classic)
-* Classic Era: 1.14.x (--version ClassicEra)
-
-## Building
-
-### Build Prerequisites
-* [.NET Core SDK 7.0.0 or later](https://dotnet.microsoft.com/download/dotnet/7.0)
-* Optional for native builds: C++ workload through Visual Studio 2022 or latest C++ build tools
-
-### Build Instructions Windows (native)
-* Available runtime identifiers/platforms: win-x64/x64, win-arm64/ARM64
-* Available release configurations: Release, ReleaseSilentMode, ReleaseCustomFiles, ReleaseCustomFilesSilentMode
-* Execute `dotnet publish -r RuntimeIdentifier -c Configuration -p:platform="Platform"`
-* Native output is placed in `build\Configuration\bin\native`
-
-## Usage
-
-### Windows Usage
-1. Copy `Actium WoW Launcher.exe` to your World of Warcraft folder.
-2. Optional: Edit the `WTF/Config.wtf` to set your portal or use a different config file with the `-config Config2.wtf` launch arg.
-3. Run the `Actium WoW Launcher.exe`
-
-### Static Auth Seed Usage
-* Use the --staticseed launch parameter
-* On server side add `179D3DC3235629D07113A9B3867F97A7` as auth seed in the database.
-
-### Custom File Loading Usage
-1. Get or create your own file mapping (.txt) file(s) and place it in the `mappings` folder.
- File Format: `fileId;filePath`
-2. Place your custom files (mods) in the `files` folder. Be sure to follow the correct folder structure.
-
-### File mapping sources
-* https://github.com/wowdev/wow-listfile
-
-### Launch Parameters
-Use `--help`
-
-## WARNING
-
-DO NOT USE THIS AS BASE FOR ANY OFFICIAL SERVER TOOLS.
-IT WILL GET YOU BANNED THERE!!!
-
diff --git a/src/Arctium.Game.Launcher.csproj b/src/Arctium.Game.Launcher.csproj
new file mode 100644
index 0000000..534f7bf
--- /dev/null
+++ b/src/Arctium.Game.Launcher.csproj
@@ -0,0 +1,27 @@
+
+
+ ../build/$(Configuration)/bin
+ Arctium Game Launcher
+ logo.ico
+ Exe
+ net10.0
+ disable
+ preview
+ Arctium
+ x64
+ enable
+ $(DefineConstants);$(Platform)
+ Debug;Release
+
+
+
+ true
+ 1
+
+
+
+
+
+
+
+
diff --git a/src/Arctium.WoW.Launcher.csproj b/src/Arctium.WoW.Launcher.csproj
deleted file mode 100644
index e8b60d4..0000000
--- a/src/Arctium.WoW.Launcher.csproj
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
- ../build/$(Configuration)/bin
- Arctium WoW Launcher
- logo.ico
- Exe
- net8.0
- True
- False
- False
- disable
- preview
- 10.0.0.0
- 10.0.0.0
- Arctium
- x64
- win-x64
- enable
- $(DefineConstants);$(Platform)
- Debug;Release;ReleaseSilentMode;ReleaseCustomFiles;ReleaseCustomFilesSilentMode
- True
-
-
- true
- false
- false
- false
- true
- false
- true
- false
- true
- true
- Speed
- false
-
-
-
- $(DefineConstants);$(Platform);CUSTOM_FILES
- False
-
-
-
- none
- false
-
-
-
- $(DefineConstants);$(Platform);CUSTOM_FILES
- none
- false
-
-
-
- WinExe
- none
- false
-
-
-
- WinExe
- $(DefineConstants);$(Platform);CUSTOM_FILES
- none
- false
-
-
-
-
-
-
diff --git a/src/Constants/GameVersion.cs b/src/Constants/GameVersion.cs
index 81af183..c82381c 100644
--- a/src/Constants/GameVersion.cs
+++ b/src/Constants/GameVersion.cs
@@ -1,11 +1,13 @@
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+// Copyright (c) Arctium.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Constants;
+namespace Arctium.Game.Launcher.Constants;
enum GameVersion
{
Retail,
Classic,
- ClassicEra
+ ClassicEra,
+ ClassicTitan
}
diff --git a/src/Constants/MemProtection.cs b/src/Constants/MemProtection.cs
index 73ec43c..3e663e8 100644
--- a/src/Constants/MemProtection.cs
+++ b/src/Constants/MemProtection.cs
@@ -1,19 +1,9 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Constants;
+namespace Arctium.Game.Launcher.Constants;
enum MemProtection
{
- NoAccess = 0x1,
- ReadOnly = 0x2,
- ReadWrite = 0x4,
- WriteCopy = 0x8,
- Execute = 0x10,
- ExecuteRead = 0x20,
- ExecuteReadWrite = 0x40,
- ExecuteWriteCopy = 0x80,
- Guard = 0x100,
- NoCache = 0x200,
- WriteCombine = 0x400,
+ ReadWrite = 0x4,
}
diff --git a/src/Constants/MemState.cs b/src/Constants/MemState.cs
deleted file mode 100644
index 937da01..0000000
--- a/src/Constants/MemState.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) Arctium.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Arctium.WoW.Launcher.Constants;
-
-enum MemState
-{
- Commit = 0x1000,
- Reserve = 0x2000,
- Free = 0x10000
-}
diff --git a/src/Constants/MemType.cs b/src/Constants/MemType.cs
deleted file mode 100644
index 2497e17..0000000
--- a/src/Constants/MemType.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) Arctium.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Arctium.WoW.Launcher.Constants;
-
-enum MemType : uint
-{
- Private = 0x20000,
- Mapped = 0x40000,
- Image = 0x1000000
-}
diff --git a/src/Constants/NtStatus.cs b/src/Constants/NtStatus.cs
deleted file mode 100644
index cbbe797..0000000
--- a/src/Constants/NtStatus.cs
+++ /dev/null
@@ -1,346 +0,0 @@
-// Copyright (c) Arctium.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Arctium.WoW.Launcher.Constants;
-
-enum NtStatus : uint
-{
- // Success
- Success = 0x00000000,
- Wait0 = 0x00000000,
- Wait1 = 0x00000001,
- Wait2 = 0x00000002,
- Wait3 = 0x00000003,
- Wait63 = 0x0000003f,
- Abandoned = 0x00000080,
- AbandonedWait0 = 0x00000080,
- AbandonedWait1 = 0x00000081,
- AbandonedWait2 = 0x00000082,
- AbandonedWait3 = 0x00000083,
- AbandonedWait63 = 0x000000bf,
- UserApc = 0x000000c0,
- KernelApc = 0x00000100,
- Alerted = 0x00000101,
- Timeout = 0x00000102,
- Pending = 0x00000103,
- Reparse = 0x00000104,
- MoreEntries = 0x00000105,
- NotAllAssigned = 0x00000106,
- SomeNotMapped = 0x00000107,
- OpLockBreakInProgress = 0x00000108,
- VolumeMounted = 0x00000109,
- RxActCommitted = 0x0000010a,
- NotifyCleanup = 0x0000010b,
- NotifyEnumDir = 0x0000010c,
- NoQuotasForAccount = 0x0000010d,
- PrimaryTransportConnectFailed = 0x0000010e,
- PageFaultTransition = 0x00000110,
- PageFaultDemandZero = 0x00000111,
- PageFaultCopyOnWrite = 0x00000112,
- PageFaultGuardPage = 0x00000113,
- PageFaultPagingFile = 0x00000114,
- CrashDump = 0x00000116,
- ReparseObject = 0x00000118,
- NothingToTerminate = 0x00000122,
- ProcessNotInJob = 0x00000123,
- ProcessInJob = 0x00000124,
- ProcessCloned = 0x00000129,
- FileLockedWithOnlyReaders = 0x0000012a,
- FileLockedWithWriters = 0x0000012b,
-
- // Informational
- Informational = 0x40000000,
- ObjectNameExists = 0x40000000,
- ThreadWasSuspended = 0x40000001,
- WorkingSetLimitRange = 0x40000002,
- ImageNotAtBase = 0x40000003,
- RegistryRecovered = 0x40000009,
-
- // Warning
- Warning = 0x80000000,
- GuardPageViolation = 0x80000001,
- DatatypeMisalignment = 0x80000002,
- Breakpoint = 0x80000003,
- SingleStep = 0x80000004,
- BufferOverflow = 0x80000005,
- NoMoreFiles = 0x80000006,
- HandlesClosed = 0x8000000a,
- PartialCopy = 0x8000000d,
- DeviceBusy = 0x80000011,
- InvalidEaName = 0x80000013,
- EaListInconsistent = 0x80000014,
- NoMoreEntries = 0x8000001a,
- LongJump = 0x80000026,
- DllMightBeInsecure = 0x8000002b,
-
- // Error
- Error = 0xc0000000,
- Unsuccessful = 0xc0000001,
- NotImplemented = 0xc0000002,
- InvalidInfoClass = 0xc0000003,
- InfoLengthMismatch = 0xc0000004,
- AccessViolation = 0xc0000005,
- InPageError = 0xc0000006,
- PagefileQuota = 0xc0000007,
- InvalidHandle = 0xc0000008,
- BadInitialStack = 0xc0000009,
- BadInitialPc = 0xc000000a,
- InvalidCid = 0xc000000b,
- TimerNotCanceled = 0xc000000c,
- InvalidParameter = 0xc000000d,
- NoSuchDevice = 0xc000000e,
- NoSuchFile = 0xc000000f,
- InvalidDeviceRequest = 0xc0000010,
- EndOfFile = 0xc0000011,
- WrongVolume = 0xc0000012,
- NoMediaInDevice = 0xc0000013,
- NoMemory = 0xc0000017,
- NotMappedView = 0xc0000019,
- UnableToFreeVm = 0xc000001a,
- UnableToDeleteSection = 0xc000001b,
- IllegalInstruction = 0xc000001d,
- AlreadyCommitted = 0xc0000021,
- AccessDenied = 0xc0000022,
- BufferTooSmall = 0xc0000023,
- ObjectTypeMismatch = 0xc0000024,
- NonContinuableException = 0xc0000025,
- BadStack = 0xc0000028,
- NotLocked = 0xc000002a,
- NotCommitted = 0xc000002d,
- InvalidParameterMix = 0xc0000030,
- ObjectNameInvalid = 0xc0000033,
- ObjectNameNotFound = 0xc0000034,
- ObjectNameCollision = 0xc0000035,
- ObjectPathInvalid = 0xc0000039,
- ObjectPathNotFound = 0xc000003a,
- ObjectPathSyntaxBad = 0xc000003b,
- DataOverrun = 0xc000003c,
- DataLate = 0xc000003d,
- DataError = 0xc000003e,
- CrcError = 0xc000003f,
- SectionTooBig = 0xc0000040,
- PortConnectionRefused = 0xc0000041,
- InvalidPortHandle = 0xc0000042,
- SharingViolation = 0xc0000043,
- QuotaExceeded = 0xc0000044,
- InvalidPageProtection = 0xc0000045,
- MutantNotOwned = 0xc0000046,
- SemaphoreLimitExceeded = 0xc0000047,
- PortAlreadySet = 0xc0000048,
- SectionNotImage = 0xc0000049,
- SuspendCountExceeded = 0xc000004a,
- ThreadIsTerminating = 0xc000004b,
- BadWorkingSetLimit = 0xc000004c,
- IncompatibleFileMap = 0xc000004d,
- SectionProtection = 0xc000004e,
- EasNotSupported = 0xc000004f,
- EaTooLarge = 0xc0000050,
- NonExistentEaEntry = 0xc0000051,
- NoEasOnFile = 0xc0000052,
- EaCorruptError = 0xc0000053,
- FileLockConflict = 0xc0000054,
- LockNotGranted = 0xc0000055,
- DeletePending = 0xc0000056,
- CtlFileNotSupported = 0xc0000057,
- UnknownRevision = 0xc0000058,
- RevisionMismatch = 0xc0000059,
- InvalidOwner = 0xc000005a,
- InvalidPrimaryGroup = 0xc000005b,
- NoImpersonationToken = 0xc000005c,
- CantDisableMandatory = 0xc000005d,
- NoLogonServers = 0xc000005e,
- NoSuchLogonSession = 0xc000005f,
- NoSuchPrivilege = 0xc0000060,
- PrivilegeNotHeld = 0xc0000061,
- InvalidAccountName = 0xc0000062,
- UserExists = 0xc0000063,
- NoSuchUser = 0xc0000064,
- GroupExists = 0xc0000065,
- NoSuchGroup = 0xc0000066,
- MemberInGroup = 0xc0000067,
- MemberNotInGroup = 0xc0000068,
- LastAdmin = 0xc0000069,
- WrongPassword = 0xc000006a,
- IllFormedPassword = 0xc000006b,
- PasswordRestriction = 0xc000006c,
- LogonFailure = 0xc000006d,
- AccountRestriction = 0xc000006e,
- InvalidLogonHours = 0xc000006f,
- InvalidWorkstation = 0xc0000070,
- PasswordExpired = 0xc0000071,
- AccountDisabled = 0xc0000072,
- NoneMapped = 0xc0000073,
- TooManyLuidsRequested = 0xc0000074,
- LuidsExhausted = 0xc0000075,
- InvalidSubAuthority = 0xc0000076,
- InvalidAcl = 0xc0000077,
- InvalidSid = 0xc0000078,
- InvalidSecurityDescr = 0xc0000079,
- ProcedureNotFound = 0xc000007a,
- InvalidImageFormat = 0xc000007b,
- NoToken = 0xc000007c,
- BadInheritanceAcl = 0xc000007d,
- RangeNotLocked = 0xc000007e,
- DiskFull = 0xc000007f,
- ServerDisabled = 0xc0000080,
- ServerNotDisabled = 0xc0000081,
- TooManyGuidsRequested = 0xc0000082,
- GuidsExhausted = 0xc0000083,
- InvalidIdAuthority = 0xc0000084,
- AgentsExhausted = 0xc0000085,
- InvalidVolumeLabel = 0xc0000086,
- SectionNotExtended = 0xc0000087,
- NotMappedData = 0xc0000088,
- ResourceDataNotFound = 0xc0000089,
- ResourceTypeNotFound = 0xc000008a,
- ResourceNameNotFound = 0xc000008b,
- ArrayBoundsExceeded = 0xc000008c,
- FloatDenormalOperand = 0xc000008d,
- FloatDivideByZero = 0xc000008e,
- FloatInexactResult = 0xc000008f,
- FloatInvalidOperation = 0xc0000090,
- FloatOverflow = 0xc0000091,
- FloatStackCheck = 0xc0000092,
- FloatUnderflow = 0xc0000093,
- IntegerDivideByZero = 0xc0000094,
- IntegerOverflow = 0xc0000095,
- PrivilegedInstruction = 0xc0000096,
- TooManyPagingFiles = 0xc0000097,
- FileInvalid = 0xc0000098,
- InstanceNotAvailable = 0xc00000ab,
- PipeNotAvailable = 0xc00000ac,
- InvalidPipeState = 0xc00000ad,
- PipeBusy = 0xc00000ae,
- IllegalFunction = 0xc00000af,
- PipeDisconnected = 0xc00000b0,
- PipeClosing = 0xc00000b1,
- PipeConnected = 0xc00000b2,
- PipeListening = 0xc00000b3,
- InvalidReadMode = 0xc00000b4,
- IoTimeout = 0xc00000b5,
- FileForcedClosed = 0xc00000b6,
- ProfilingNotStarted = 0xc00000b7,
- ProfilingNotStopped = 0xc00000b8,
- NotSameDevice = 0xc00000d4,
- FileRenamed = 0xc00000d5,
- CantWait = 0xc00000d8,
- PipeEmpty = 0xc00000d9,
- CantTerminateSelf = 0xc00000db,
- InternalError = 0xc00000e5,
- InvalidParameter1 = 0xc00000ef,
- InvalidParameter2 = 0xc00000f0,
- InvalidParameter3 = 0xc00000f1,
- InvalidParameter4 = 0xc00000f2,
- InvalidParameter5 = 0xc00000f3,
- InvalidParameter6 = 0xc00000f4,
- InvalidParameter7 = 0xc00000f5,
- InvalidParameter8 = 0xc00000f6,
- InvalidParameter9 = 0xc00000f7,
- InvalidParameter10 = 0xc00000f8,
- InvalidParameter11 = 0xc00000f9,
- InvalidParameter12 = 0xc00000fa,
- MappedFileSizeZero = 0xc000011e,
- TooManyOpenedFiles = 0xc000011f,
- Cancelled = 0xc0000120,
- CannotDelete = 0xc0000121,
- InvalidComputerName = 0xc0000122,
- FileDeleted = 0xc0000123,
- SpecialAccount = 0xc0000124,
- SpecialGroup = 0xc0000125,
- SpecialUser = 0xc0000126,
- MembersPrimaryGroup = 0xc0000127,
- FileClosed = 0xc0000128,
- TooManyThreads = 0xc0000129,
- ThreadNotInProcess = 0xc000012a,
- TokenAlreadyInUse = 0xc000012b,
- PagefileQuotaExceeded = 0xc000012c,
- CommitmentLimit = 0xc000012d,
- InvalidImageLeFormat = 0xc000012e,
- InvalidImageNotMz = 0xc000012f,
- InvalidImageProtect = 0xc0000130,
- InvalidImageWin16 = 0xc0000131,
- LogonServer = 0xc0000132,
- DifferenceAtDc = 0xc0000133,
- SynchronizationRequired = 0xc0000134,
- DllNotFound = 0xc0000135,
- IoPrivilegeFailed = 0xc0000137,
- OrdinalNotFound = 0xc0000138,
- EntryPointNotFound = 0xc0000139,
- ControlCExit = 0xc000013a,
- PortNotSet = 0xc0000353,
- DebuggerInactive = 0xc0000354,
- CallbackBypass = 0xc0000503,
- PortClosed = 0xc0000700,
- MessageLost = 0xc0000701,
- InvalidMessage = 0xc0000702,
- RequestCanceled = 0xc0000703,
- RecursiveDispatch = 0xc0000704,
- LpcReceiveBufferExpected = 0xc0000705,
- LpcInvalidConnectionUsage = 0xc0000706,
- LpcRequestsNotAllowed = 0xc0000707,
- ResourceInUse = 0xc0000708,
- ProcessIsProtected = 0xc0000712,
- VolumeDirty = 0xc0000806,
- FileCheckedOut = 0xc0000901,
- CheckOutRequired = 0xc0000902,
- BadFileType = 0xc0000903,
- FileTooLarge = 0xc0000904,
- FormsAuthRequired = 0xc0000905,
- VirusInfected = 0xc0000906,
- VirusDeleted = 0xc0000907,
- TransactionalConflict = 0xc0190001,
- InvalidTransaction = 0xc0190002,
- TransactionNotActive = 0xc0190003,
- TmInitializationFailed = 0xc0190004,
- RmNotActive = 0xc0190005,
- RmMetadataCorrupt = 0xc0190006,
- TransactionNotJoined = 0xc0190007,
- DirectoryNotRm = 0xc0190008,
- CouldNotResizeLog = 0xc0190009,
- TransactionsUnsupportedRemote = 0xc019000a,
- LogResizeInvalidSize = 0xc019000b,
- RemoteFileVersionMismatch = 0xc019000c,
- CrmProtocolAlreadyExists = 0xc019000f,
- TransactionPropagationFailed = 0xc0190010,
- CrmProtocolNotFound = 0xc0190011,
- TransactionSuperiorExists = 0xc0190012,
- TransactionRequestNotValid = 0xc0190013,
- TransactionNotRequested = 0xc0190014,
- TransactionAlreadyAborted = 0xc0190015,
- TransactionAlreadyCommitted = 0xc0190016,
- TransactionInvalidMarshallBuffer = 0xc0190017,
- CurrentTransactionNotValid = 0xc0190018,
- LogGrowthFailed = 0xc0190019,
- ObjectNoLongerExists = 0xc0190021,
- StreamMiniversionNotFound = 0xc0190022,
- StreamMiniversionNotValid = 0xc0190023,
- MiniversionInaccessibleFromSpecifiedTransaction = 0xc0190024,
- CantOpenMiniversionWithModifyIntent = 0xc0190025,
- CantCreateMoreStreamMiniversions = 0xc0190026,
- HandleNoLongerValid = 0xc0190028,
- NoTxfMetadata = 0xc0190029,
- LogCorruptionDetected = 0xc0190030,
- CantRecoverWithHandleOpen = 0xc0190031,
- RmDisconnected = 0xc0190032,
- EnlistmentNotSuperior = 0xc0190033,
- RecoveryNotNeeded = 0xc0190034,
- RmAlreadyStarted = 0xc0190035,
- FileIdentityNotPersistent = 0xc0190036,
- CantBreakTransactionalDependency = 0xc0190037,
- CantCrossRmBoundary = 0xc0190038,
- TxfDirNotEmpty = 0xc0190039,
- IndoubtTransactionsExist = 0xc019003a,
- TmVolatile = 0xc019003b,
- RollbackTimerExpired = 0xc019003c,
- TxfAttributeCorrupt = 0xc019003d,
- EfsNotAllowedInTransaction = 0xc019003e,
- TransactionalOpenNotAllowed = 0xc019003f,
- TransactedMappingUnsupportedRemote = 0xc0190040,
- TxfMetadataAlreadyPresent = 0xc0190041,
- TransactionScopeCallbacksNotSet = 0xc0190042,
- TransactionRequiredPromotion = 0xc0190043,
- CannotExecuteFileInTransaction = 0xc0190044,
- TransactionsNotFrozen = 0xc0190045,
-
- MaximumNtStatus = 0xffffffff
-}
diff --git a/src/IO/WinMemory.cs b/src/IO/WinMemory.cs
index 3c77cf0..11ecb30 100644
--- a/src/IO/WinMemory.cs
+++ b/src/IO/WinMemory.cs
@@ -1,23 +1,19 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-using static Arctium.WoW.Launcher.Misc.NativeWindows;
-using static Arctium.WoW.Launcher.Misc.Helpers;
+using static Arctium.Game.Launcher.Misc.NativeWindows;
+using static Arctium.Game.Launcher.Misc.Helpers;
-namespace Arctium.WoW.Launcher.IO;
+namespace Arctium.Game.Launcher.IO;
class WinMemory
{
public byte[] Data { get; set; }
-
public nint BaseAddress { get; }
-
- ProcessBasicInformation _peb;
readonly nint _processHandle;
- readonly Dictionary _patchList;
- public WinMemory(ProcessInformation processInformation, long binaryLength)
+ public WinMemory(ProcessInformation processInformation)
{
_processHandle = processInformation.ProcessHandle;
@@ -28,22 +24,18 @@ class WinMemory
if (BaseAddress == 0)
throw new InvalidOperationException("Error while reading PEB data.");
-
- Data = Read(BaseAddress, (int)binaryLength);
-
- _patchList = new Dictionary();
}
public void RefreshMemoryData(int size)
{
// Reset previous memory data.
- Data = null;
+ if (Data != null)
+ Array.Clear(Data, 0, Data.Length);
- while (Data == null)
+ while (Data == null || Unsafe.ReadUnaligned(ref Data[0]) == 0)
{
Console.WriteLine("Refreshing client data...");
-
- Data = Read(BaseAddress, size);
+ ReadToData(BaseAddress, size);
}
}
@@ -65,7 +57,20 @@ class WinMemory
return 0;
}
- public nint Read(long address) => Read((nint)address);
+ public void ReadToData(nint address, int size)
+ {
+ try
+ {
+ Data ??= new byte[size];
+
+ ReadProcessMemory(_processHandle, address, Data, size, out var dummy);
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+
public byte[] Read(nint address, int size)
{
@@ -85,29 +90,6 @@ class WinMemory
return null;
}
- public byte[] Read(long address, int size) => Read((nint)address, size);
-
- public int ReadDataLength(nint address, string separator)
- {
- var length = 0L;
- var seperatorBytes = Encoding.UTF8.GetBytes(separator).Select(b => (short)b).ToArray();
- var dataLength = 1000;
-
- // Read in batches here.
- while (length == 0)
- {
- length = Read(address, dataLength)?.FindPattern(seperatorBytes) ?? 0;
-
- dataLength += 1000;
-
- // Not found!
- if (dataLength >= 100_000)
- return -1;
- }
-
- return (int)length;
- }
-
public void Write(nint address, byte[] data, MemProtection newProtection = MemProtection.ReadWrite)
{
try
@@ -126,9 +108,24 @@ class WinMemory
}
}
- public void Write(long address, byte[] data, MemProtection newProtection = MemProtection.ReadWrite) => Write((nint)address, data, newProtection);
+ public async Task TryPatchPatterns(byte[][] patches, string patchName, bool? printInfo = null, bool exitOnFail = true, bool patchAll = false, params short[][] patterns)
+ {
+ if (patches.Length == 0 || patterns.Length == 0)
+ return;
- public Task PatchMemory(short[] pattern, byte[] patch, string patchName, bool? printInfo = null)
+ if (!patchAll && await PatchMemory(patterns[0], patches[0], $"{patchName}", printInfo, exitOnFail))
+ return;
+
+ for (var i = 0; i < patterns.Length; i++)
+ {
+ Console.ResetColor();
+
+ if (await PatchMemory(patterns[i], patches[i], $"{patchName} {i + 1}", printInfo, exitOnFail: false) && !patchAll)
+ break;
+ }
+ }
+
+ public Task PatchMemory(short[] pattern, byte[] patch, string patchName, bool? printInfo = null, bool exitOnFail = true)
{
printInfo ??= IsDebugBuild();
@@ -140,198 +137,54 @@ class WinMemory
// No result for the given pattern.
if (patchOffset == 0)
{
- Console.ForegroundColor = ConsoleColor.Yellow;
+ if (exitOnFail)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"[{patchName}] No result found.");
+ Console.WriteLine("Press any key to exit...");
- Console.WriteLine($"[{patchName}] No result found.");
- Console.WriteLine("Press any key to exit...");
- Console.ReadKey();
+ // Only wait if a console is available.
+ if (!Console.IsInputRedirected)
+ Console.ReadKey();
- Launcher.CancellationTokenSource.Cancel();
+ Launcher.CancellationTokenSource.Cancel();
+
+ return Task.FromResult(false);
+ }
+
+ if (printInfo.Value)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"[{patchName}] No result found. This is just a warning! KEEP GOING...");
+ Console.ResetColor();
+ }
+
+ return Task.FromResult(false);
}
- while (Read(patchOffset, patch.Length)?.SequenceEqual(patch) == false)
- Write(patchOffset, patch);
+ while (Read((nint)patchOffset, patch.Length)?.SequenceEqual(patch) == false)
+ Write((nint)patchOffset, patch);
if (printInfo.Value)
{
- Console.Write($"[{patchName}]");
+ Console.Write($"[{patchName}] at 0x{patchOffset:X}");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(" Done.");
Console.ResetColor();
Console.WriteLine();
}
- return Task.CompletedTask;
+ return Task.FromResult(true);
}
- public Task QueuePatch(long patchOffset, byte[] patch, string patchName, bool? printInfo = null)
- {
- Launcher.CancellationTokenSource.Token.ThrowIfCancellationRequested();
-
- printInfo ??= IsDebugBuild();
-
- if (printInfo.Value)
- {
- Console.WriteLine($"[{patchName}] Adding...");
-
- _patchList[patchName] = (patchOffset, patch);
-
- Console.Write($"[{patchName}]");
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine(" Done.");
- Console.ResetColor();
- Console.WriteLine();
- }
- else
- _patchList[patchName] = (patchOffset, patch);
-
- return Task.CompletedTask;
- }
-
- public Task QueuePatch(short[] pattern, byte[] patch, string patchName, int offsetBase = 0, bool? printInfo = null)
- {
- long patchOffset = Data.FindPattern(pattern);
-
- // No result for the given pattern.
- if (patchOffset == 0)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"[{patchName}] No result found.");
- Console.ResetColor();
- Console.WriteLine("Press any key to exit...");
- Console.ReadKey();
-
- Launcher.CancellationTokenSource.Cancel();
-
- return Task.CompletedTask;
- }
-
- return QueuePatch(patchOffset + offsetBase, patch, patchName, printInfo);
- }
-
- bool RemapAndPatch(nint viewAddress, int viewSize)
- {
- // Suspend before remapping to prevent crashes.
- NtSuspendProcess(_processHandle);
-
- Data = Read(viewAddress, viewSize);
-
- if (Data != null)
- {
- nint newViewHandle = 0;
- var maxSize = new LargeInteger { Quad = viewSize };
-
- try
- {
- if (NtCreateSection(ref newViewHandle, 0xF001F, 0, ref maxSize, 0x40u, 0x8000000 | 0x400000, 0) == NtStatus.Success &&
- NtUnmapViewOfSection(_processHandle, viewAddress) == NtStatus.Success)
- {
- var viewBase = viewAddress;
-
- // Map the view with original protections.
- var result = NtMapViewOfSection(newViewHandle, _processHandle, ref viewBase, 0, (ulong)viewSize, out var viewOffset,
- out var newViewSize, 2, 0, (int)MemProtection.ExecuteRead);
-
- if (result == NtStatus.Success)
- {
- // Apply our patches.
- ApplyPatches(true);
-
- nint viewBase2 = 0;
-
- // Create a writable view to write our patches through to preserve the original protections.
- result = NtMapViewOfSection(newViewHandle, _processHandle, ref viewBase2, 0, (uint)viewSize, out var viewOffset2,
- out var newViewSize2, 2, 0, (int)MemProtection.ReadWrite);
-
- if (result == NtStatus.Success)
- {
- // Write our patched data trough the writable view to the memory.
- if (WriteProcessMemory(_processHandle, viewBase2, Data, viewSize, out var dummy))
- {
- // Unmap them writeable view, it's not longer needed.
- NtUnmapViewOfSection(_processHandle, viewBase2);
-
- // Check if the allocation protections is the right one.
- if (VirtualQueryEx(_processHandle, BaseAddress, out MemoryBasicInformation mbi, MemoryBasicInformation.Size) != 0
- && mbi.AllocationProtect == MemProtection.ExecuteRead)
- {
- // Also check if we can change the page protection.
- if (!VirtualProtectEx(_processHandle, BaseAddress, 0x4000, (uint)MemProtection.ReadWrite, out var oldProtect))
- NtResumeProcess(_processHandle);
-
- return true;
- }
- }
- }
- }
-
- Console.WriteLine("Error while mapping the view with the given protection.");
- }
- }
- finally
- {
- NtClose(newViewHandle);
- }
- }
- else
- Console.WriteLine("Error while creating the view backup.");
-
- NtResumeProcess(_processHandle);
-
- return false;
- }
-
- void ApplyPatches(bool remap)
- {
- foreach (var p in _patchList)
- {
- var address = p.Value.Address;
-
- if (address == 0)
- continue;
-
- var patch = p.Value.Data;
-
- // We are in a different section here.
- if (address > Data.Length)
- {
- if (address < BaseAddress)
- address += BaseAddress;
-
- Write(address, patch);
-
- continue;
- }
-
- if (remap)
- {
- for (var i = 0; i < patch.Length; i++)
- Data[address + i] = patch[i];
- }
- }
- }
-
- public bool RemapAndPatch(bool remap)
- {
- if (!remap)
- {
- ApplyPatches(false);
- return true;
- }
-
- if (VirtualQueryEx(_processHandle, BaseAddress, out var mbi, MemoryBasicInformation.Size) != 0)
- return RemapAndPatch(mbi.BaseAddress, (int)mbi.RegionSize);
-
- return false;
- }
-
- /// Private functions.
nint ReadImageBaseFromPEB(nint processHandle)
{
try
{
- if (NtQueryInformationProcess(processHandle, 0, ref _peb, ProcessBasicInformation.Size, out _) == NtStatus.Success)
- return Read(_peb.PebBaseAddress + 0x10);
+ ProcessBasicInformation peb = default;
+
+ if (NtQueryInformationProcess(processHandle, 0, ref peb, ProcessBasicInformation.Size, out _) == 0)
+ return Read(peb.PebBaseAddress + 0x10);
}
catch (Exception ex)
{
@@ -340,22 +193,4 @@ class WinMemory
return 0;
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsShortJump(byte[] instructions, int startIndex = 0)
- {
- return instructions[startIndex] >= 0x70 && instructions[startIndex] < 0x7F;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsJump(byte[] instructions, int startIndex = 0)
- {
- return instructions[startIndex] == 0x0F && instructions[startIndex + 1] >= 0x80 && instructions[startIndex + 1] <= 0x8F;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool IsUnconditionalJump(byte[] instructions, int startIndex = 0)
- {
- return instructions[startIndex] == 0xE9 || instructions[startIndex] == 0xEB;
- }
}
diff --git a/src/LaunchOptions.cs b/src/LaunchOptions.cs
index bc27d60..d22b522 100644
--- a/src/LaunchOptions.cs
+++ b/src/LaunchOptions.cs
@@ -1,24 +1,22 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.CommandLine.Builder;
using System.CommandLine.Parsing;
-namespace Arctium.WoW.Launcher;
+namespace Arctium.Game.Launcher;
static class LaunchOptions
{
- public static bool IsDevModeAllowed { get; set; }
-
public static Option Version = new("--version", () => GameVersion.Retail);
public static Option GamePath = new("--path");
public static Option GameBinary = new("--binary");
public static Option KeepCache = new("--keepcache", () => true);
- public static Option UseStaticAuthSeed = new("--staticseed");
- public static Option DevMode = new("--dev", () => true, "Required for local development without valid certificates.");
+ public static Option VersionUrl = new("--versionurl");
+ public static Option CdnsUrl = new("--cdnsurl");
public static Option ProductName = new("--product", () => "wow");
public static Option CdnRegion = new("--region", () => "EU");
- public static Option SkipConnectionPatching = new("--skip", () => false, "Allows connection to servers that come with already patched clients.");
+ public static Option BgsPortal = new("--portal");
// Game command line options.
public static Option GameConfig = new("-config", () => "Config.wtf");
@@ -31,18 +29,18 @@ static class LaunchOptions
.UseSuggestDirective()
.Build();
- public static RootCommand RootCommand = new("Arctium WoW Launcher")
+ public static RootCommand RootCommand = new("Arctium Game Launcher")
{
Version,
GamePath,
GameBinary,
KeepCache,
- UseStaticAuthSeed,
- DevMode,
+ VersionUrl,
+ CdnsUrl,
ProductName,
CdnRegion,
+ BgsPortal,
GameConfig,
- SkipConnectionPatching
};
static Command ConfigureCommandLine(Command rootCommand)
diff --git a/src/Launcher.cs b/src/Launcher.cs
index b762995..efb182c 100644
--- a/src/Launcher.cs
+++ b/src/Launcher.cs
@@ -1,34 +1,46 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.CommandLine.Parsing;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
+using static Arctium.Game.Launcher.Misc.Helpers;
-using static Arctium.WoW.Launcher.Misc.Helpers;
-
-namespace Arctium.WoW.Launcher;
+namespace Arctium.Game.Launcher;
static class Launcher
{
+ public static nint GameProcessHandle { get; private set; }
public static readonly CancellationTokenSource CancellationTokenSource = new();
- public static async ValueTask PrepareGameLaunch(ParseResult commandLineResult, IPFilter ipFilter)
+ static List _tryClients = [GameVersion.Retail, GameVersion.Classic, GameVersion.ClassicEra, GameVersion.ClassicTitan];
+ static bool _useVersionV2;
+ static byte[] _binaryData;
+
+ public static async ValueTask PrepareGameLaunch(ParseResult commandLineResult, GameVersion? branchOverwrite)
{
+ Console.ResetColor();
+
var gameVersion = commandLineResult.GetValueForOption(LaunchOptions.Version);
+
+ if (branchOverwrite.HasValue)
+ gameVersion = branchOverwrite.Value;
+
var (subFolder, binaryName, majorGameVersion, minGameBuild) = gameVersion switch
{
- GameVersion.Retail => ("_retail_", "Wow.exe", new[] { 9, 10 }, 37862),
- GameVersion.Classic => ("_classic_", "WowClassic.exe", new[] { 2, 3 }, 39926),
- GameVersion.ClassicEra => ("_classic_era_", "WowClassic.exe", new[] { 1 }, 40347),
+ GameVersion.Retail => ("_retail_", "Wow.exe", [10, 11, 12], 50401),
+ GameVersion.Classic => ("_classic_", "WowClassic.exe", [2, 3, 4, 5], 50063),
+ GameVersion.ClassicEra => ("_classic_era_", "WowClassic.exe", [1], 51001),
+ GameVersion.ClassicTitan => ("_classic_titan_", "WowClassic.exe", new[] { 3 }, 64393),
_ => throw new NotImplementedException("Invalid game version specified."),
};
+ _tryClients.RemoveAll(c => c == gameVersion);
+
Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine($"Mode: Custom Server ({gameVersion})");
- Console.WriteLine();
+ Console.WriteLine($"Mode: Public Custom Server ({gameVersion})");
Console.ResetColor();
var currentFolder = AppDomain.CurrentDomain.BaseDirectory;
@@ -51,10 +63,29 @@ static class Launcher
gameBinaryPath = $"{gameFolder}/{binaryName}";
}
+ gameFolder = gameFolder.Replace("\\/", "/").Replace("\\", "/");
+ gameBinaryPath = gameBinaryPath.Replace("\\/", "/").Replace("\\", "/");
+
if (!File.Exists(gameBinaryPath) || !majorGameVersion.Contains(GetVersionValueFromClient(gameBinaryPath).Major))
{
Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"[Error] No {gameVersion} client found.");
+ Console.WriteLine($"No {gameVersion} client found at '{gameBinaryPath}'");
+
+ if (_tryClients.Count > 0)
+ {
+ var nextClient = _tryClients.First();
+
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"Trying a different branch...");
+ Console.ResetColor();
+
+ return await PrepareGameLaunch(commandLineResult, nextClient);
+ }
+ else
+ {
+ Console.WriteLine();
+ Console.WriteLine($"No supported client found.");
+ }
return string.Empty;
}
@@ -85,77 +116,113 @@ static class Launcher
}
var configPath = $"{gameFolder}/WTF/{commandLineResult.GetValueForOption(LaunchOptions.GameConfig)}";
- (string IPAddress, string HostName, int Port) portal = new();
-
- if (!File.Exists(configPath))
- LaunchOptions.IsDevModeAllowed = false;
- else
- {
- var config = File.ReadAllText(configPath);
-
- portal = ParsePortal(config);
-
- LaunchOptions.IsDevModeAllowed = IsDevModeAllowed(ipFilter, portal.IPAddress);
- }
-
- if (!LaunchOptions.IsDevModeAllowed)
- LaunchOptions.DevMode = new("--dev", () => false);
-
- var devModeEnabled = commandLineResult.GetValueForOption(LaunchOptions.DevMode) && LaunchOptions.IsDevModeAllowed;
Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine($"Developer mode: {(devModeEnabled ? "Enabled" : "Disabled")}");
Console.WriteLine();
- Console.WriteLine($"Client Portal '{portal.HostName}'");
+ Console.WriteLine($"Client Config: \"{configPath}\"");
+ Console.ResetColor();
+
+ (string IPAddress, string HostName, int Port) portal = new();
+
+
+ var config = File.ReadAllText(configPath);
+ var bgsPortal = commandLineResult.GetValueForOption(LaunchOptions.BgsPortal);
+
+ portal = ParseOrSetPortal(ref config, bgsPortal);
+
+ if (!string.IsNullOrEmpty(bgsPortal))
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"Config Portal Overwrite:\"{bgsPortal}\"");
+ Console.ResetColor();
+ Console.WriteLine();
+
+ File.WriteAllText(configPath, config);
+ }
+
+ _binaryData = File.ReadAllBytes(gameBinaryPath);
+ _useVersionV2 = UsesVersionV2(_binaryData);
+
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"Client Path: '{gameBinaryPath}'");
+ Console.WriteLine($"Client Portal: '{portal.HostName}:{portal.Port}'");
Console.ForegroundColor = ConsoleColor.Gray;
- // Check for valid certificate when dev mode is disabled.
- if (!devModeEnabled)
+
+ if (string.IsNullOrEmpty(portal.HostName) || string.IsNullOrWhiteSpace(portal.HostName))
{
- try
- {
- using var tcpClient = new TcpClient();
- using var tcpClientTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine();
+ Console.WriteLine("Client Portal should not be empty.");
+ Console.WriteLine("Be sure to have a valid portal in your Config.wtf file.");
+ Console.ResetColor();
- await tcpClient.ConnectAsync(portal.HostName, portal.Port, tcpClientTimeout.Token);
+ return string.Empty;
+ }
- using var sslStream = new SslStream(tcpClient.GetStream(), false,
- (_, _, _, sslPolicyErrors) =>
- {
- // Redirect to the trusted cert warning.
- if (sslPolicyErrors != SslPolicyErrors.None)
- throw new AuthenticationException();
+ // Return if no valid ip address has been found.
+ if (string.IsNullOrEmpty(portal.IPAddress) || string.IsNullOrWhiteSpace(portal.IPAddress))
+ return string.Empty;
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine($"Certificate for server '{portal.HostName}' successfully validated.");
- Console.WriteLine();
- Console.ResetColor();
+ // Check for valid certificate.
+ try
+ {
+ using var tcpClient = new TcpClient();
- return true;
- },
- null
- );
+ // 3.5 seconds timeout.
+ const int timeout = 3500;
- sslStream.AuthenticateAsClient(portal.HostName);
- }
- catch (Exception exception) when (exception is SocketException or OperationCanceledException)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"{portal.HostName}:{portal.Port} is offline.");
- Console.ResetColor();
+ tcpClient.ReceiveTimeout = timeout;
+ tcpClient.SendTimeout = timeout;
- return string.Empty;
- }
- catch (AuthenticationException)
- {
- Console.ForegroundColor = ConsoleColor.Yellow;
- Console.WriteLine($"Server with host name {portal.HostName} does not have a trusted certificate attached.");
- Console.WriteLine("If you are the server owner be sure to generate one and replace the default bnet server certificate.");
- Console.WriteLine("One way to generate one is through Let's Encrypt.");
- Console.ResetColor();
+ using var tcpClientTimeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(timeout));
- return string.Empty;
- }
+ await tcpClient.ConnectAsync(portal.HostName, portal.Port, tcpClientTimeout.Token);
+
+ using var sslStream = new SslStream(tcpClient.GetStream(), false,
+ (_, _, _, sslPolicyErrors) =>
+ {
+ // Redirect to the trusted cert warning.
+ if (sslPolicyErrors != SslPolicyErrors.None)
+ throw new AuthenticationException();
+
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine($"Certificate for server '{portal.HostName}' successfully validated.");
+ Console.WriteLine();
+ Console.ResetColor();
+
+ return true;
+ },
+ null
+ );
+
+ sslStream.AuthenticateAsClient(portal.HostName);
+ }
+ catch (IOException exception)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"Server {portal.HostName}:{portal.Port}: {exception.Message}");
+ Console.ResetColor();
+
+ return string.Empty;
+ }
+ catch (AuthenticationException)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine($"Server with host name {portal.HostName}:{portal.Port} does not have a trusted certificate attached.");
+ Console.WriteLine("If you are the server owner be sure to generate one and replace the default bnet server certificate.");
+ Console.WriteLine("One way to generate one is through Let's Encrypt.");
+ Console.ResetColor();
+
+ return string.Empty;
+ }
+ catch (Exception exception) when (exception is SocketException or OperationCanceledException)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"{portal.HostName}:{portal.Port} is offline or not reachable from the current network.");
+ Console.ResetColor();
+
+ return string.Empty;
}
return gameBinaryPath;
@@ -168,7 +235,61 @@ static class Launcher
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Client Build {clientVersion}");
- Console.WriteLine($"Client Path '{appPath}'");
+ Console.ResetColor();
+
+ // Assign the region and product dependent version url to check it's online status.
+ string[] versionUrls = CreateVersionUrls(commandLineResult, clientVersion);
+
+ static string[] CreateVersionUrls(ParseResult commandLineResult, (int Major, int Minor, int Revision, int Build) clientVersion)
+ {
+ var versionUrl = commandLineResult.GetValueForOption(LaunchOptions.VersionUrl);
+
+ // Always return a forced version url parameter.
+ if (!string.IsNullOrEmpty(versionUrl))
+ return [versionUrl, versionUrl, versionUrl];
+
+ return [];
+ }
+
+ bool hasCustomVersionUrl = commandLineResult.HasOption(LaunchOptions.VersionUrl);
+ bool hasCustomCdnUrl = commandLineResult.HasOption(LaunchOptions.CdnsUrl);
+
+ if (hasCustomCdnUrl || hasCustomVersionUrl)
+ {
+ Console.ForegroundColor = ConsoleColor.Yellow;
+ Console.WriteLine("Warning: Custom version servers were specified.");
+ Console.WriteLine("The game will connect to these servers.");
+ Console.ResetColor();
+ }
+
+ var cdnsUrl = commandLineResult.GetValueForOption(LaunchOptions.CdnsUrl);
+
+ if (hasCustomCdnUrl && (!CheckUrl(cdnsUrl, fallbackUrls: [Patterns.Common.CdnsUrl]).GetAwaiter().GetResult()))
+ cdnsUrl = Patterns.Common.CdnsUrl;
+
+ Console.ForegroundColor = ConsoleColor.Cyan;
+
+ Console.WriteLine();
+ Console.WriteLine("Game CDN connection info:");
+ Console.WriteLine($"Version source(s):");
+
+ if (versionUrls.Length == 0)
+ {
+ foreach (var vUrl in new[] { Patterns.Common.VersionUrl, Patterns.Common.Version2Url, Patterns.Common.Version2ChinaUrl })
+ Console.WriteLine($"- {vUrl}");
+ }
+ else
+ {
+ if (versionUrls.All(element => element.Equals(versionUrls[0])))
+ Console.WriteLine($"- {versionUrls[0]}");
+ else
+ {
+ foreach (var vUrl in versionUrls)
+ Console.WriteLine($"- {vUrl}");
+ }
+ }
+
+ Console.WriteLine($"CDNs source: {cdnsUrl}");
Console.WriteLine();
Console.ResetColor();
@@ -178,158 +299,80 @@ static class Launcher
try
{
Console.ForegroundColor = ConsoleColor.White;
- Console.WriteLine("Starting WoW client...");
+ Console.WriteLine("Starting game client...");
- var createSuccess = NativeWindows.CreateProcess(null, $"{appPath} {gameCommandLine}", 0, 0, false, 4, 0, new FileInfo(appPath).DirectoryName,
+ var createSuccess = NativeWindows.CreateProcess(null, $"\"{appPath}\" {gameCommandLine}", 0, 0, false, 4, 0, new FileInfo(appPath).DirectoryName,
ref startupInfo, out processInfo);
// On some systems we have to launch the game with the application name used.
if (!createSuccess)
- createSuccess = NativeWindows.CreateProcess(appPath, $" {gameCommandLine}", 0, 0, false, 4, 0, null, ref startupInfo, out processInfo);
+ createSuccess = NativeWindows.CreateProcess(appPath, $" {gameCommandLine}", 0, 0, false, 4, 0, new FileInfo(appPath).DirectoryName, ref startupInfo, out processInfo);
// Start process with suspend flags.
if (createSuccess)
{
- using var gameAppData = new MemoryStream(File.ReadAllBytes(appPath));
+ GameProcessHandle = processInfo.ProcessHandle;
- var memory = new WinMemory(processInfo, gameAppData.Length);
+ using var gameAppData = File.OpenRead(appPath);
- // Resume the process to initialize it.
- NativeWindows.NtResumeProcess(processInfo.ProcessHandle);
+ var appDataLength = gameAppData.Length;
+ var memory = new WinMemory(processInfo);
- MemoryBasicInformation mbi;
-
- // Wait for the memory region to be initialized.
- while (NativeWindows.VirtualQueryEx(processInfo.ProcessHandle, memory.BaseAddress, out mbi, MemoryBasicInformation.Size) == 0 ||
- mbi.RegionSize <= 0x1000)
- { }
-
- if (mbi.BaseAddress != 0)
+ if (memory.BaseAddress != 0)
{
- NativeWindows.NtSuspendProcess(processInfo.ProcessHandle);
-
- byte[] certBundleData = Convert.FromBase64String(Patches.Common.CertBundleData);
+ Process gameProcess = Process.GetProcessById((int)processInfo.ProcessId);
// Refresh the client data before patching.
- memory.RefreshMemoryData((int)gameAppData.Length);
+ memory.RefreshMemoryData((int)appDataLength);
- // We need to cache this here since we are using our RSA modulus as auth seed.
- var modulusOffset = memory.Data.FindPattern(Patterns.Common.CryptoRsaModulus);
- var legacyCertMode = clientVersion is (1, >= 14, <= 3, _) or (3, 4, <= 1, _) or (9, _, _, _) or (10, <= 1, < 5, _);
-
- if (!commandLineResult.GetValueForOption(LaunchOptions.SkipConnectionPatching))
+ // Custom CDN related patches.
+ if ((hasCustomVersionUrl && hasCustomCdnUrl))
{
- if (legacyCertMode)
+ var versionUrlPatches = new byte[versionUrls.Length][];
+
+ for (var i = 0; i < versionUrls.Length; i++)
+ versionUrlPatches[i] = Encoding.UTF8.GetBytes(versionUrls[i] + '\0');
+
+ // 11.1.7 added new v2 links.
+ if (_useVersionV2)
{
- Task.WaitAll(new[]
- {
- memory.PatchMemory(Patterns.Common.CertBundle, certBundleData, "Certificate Bundle"),
- memory.PatchMemory(Patterns.Common.SignatureModulus, Patches.Common.SignatureModulus, "Certificate Signature RsaModulus")
- }, CancellationTokenSource.Token);
+ Task.WaitAll(
+ [
+ memory.TryPatchPatterns(versionUrlPatches, "Version URL", true, false, true,
+ Patterns.Common.Version2UrlNew.ToPattern(), Patterns.Common.Version2ChinaUrlNew.ToPattern()),
+ ], CancellationTokenSource.Token);
}
-
- // Wait for all direct memory patch tasks to complete,
- Task.WaitAll(new[]
+ else
{
- memory.PatchMemory(Patterns.Common.ConnectToModulus, Patches.Common.RsaModulus, "ConnectTo RsaModulus"),
-
- // Recent clients have a different signing algorithm in EnterEncryptedMode.
- clientVersion is (9, 2, 7, _) or (3, _, _, _) or (10, _, _, _) or (1, >= 14, >= 4, _)
- ? memory.PatchMemory(Patterns.Common.CryptoEdPublicKey, Patches.Common.CryptoEdPublicKey, "GameCrypto Ed25519 PublicKey")
- : memory.PatchMemory(Patterns.Common.CryptoRsaModulus, Patches.Common.RsaModulus, "GameCrypto RsaModulus"),
-
- memory.PatchMemory(Patterns.Common.Portal, Patches.Common.Portal, "Login Portal"),
- memory.PatchMemory(Patterns.Windows.LauncherLogin, Patches.Windows.LauncherLogin, "Launcher Login Registry")
- }, CancellationTokenSource.Token);
+ Task.WaitAll(
+ [
+ memory.TryPatchPatterns(versionUrlPatches, "Version URL", true, false, true,
+ Patterns.Common.VersionUrl.ToPattern(), Patterns.Common.Version2Url.ToPattern(), Patterns.Common.Version2ChinaUrl.ToPattern()),
+ memory.PatchMemory(Patterns.Common.CdnsUrl.ToPattern(), Encoding.UTF8.GetBytes(cdnsUrl), "CDNs URL", exitOnFail: false),
+ ], CancellationTokenSource.Token);
+ }
}
+ // Wait for all direct memory patch tasks to complete.
+ Task.WaitAll(
+ [
+ memory.PatchMemory(Patterns.Common.ConnectToModulus, Patches.Common.RsaModulus, "ConnectTo RsaModulus"),
+ memory.PatchMemory(Patterns.Common.CryptoEdPublicKey, Patches.Common.CryptoEdPublicKey, "GameCrypto Ed25519 PublicKey"),
+ memory.PatchMemory(Patterns.Common.Portal, Patches.Common.Portal, "Login Portal"),
+ memory.PatchMemory(Patterns.Windows.LauncherLogin, Patches.Windows.LauncherLogin, "Launcher Login Registry")
+ ], CancellationTokenSource.Token);
+
NativeWindows.NtResumeProcess(processInfo.ProcessHandle);
- // Enable anti crash in dev mode, custom file mode or static auth seed mode.
-#if CUSTOM_FILES
- var antiCrash = true;
-#else
- var antiCrash = legacyCertMode || commandLineResult.HasOption(LaunchOptions.UseStaticAuthSeed) ||
- commandLineResult.GetValueForOption(LaunchOptions.DevMode) && LaunchOptions.IsDevModeAllowed;
-#endif
+ Console.WriteLine("Done :) ");
- WaitForUnpack(ref processInfo, memory, ref mbi, gameAppData, antiCrash);
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("You can login now.");
+ Console.WriteLine("Closing in 3 seconds...");
+ Thread.Sleep(3000);
+ Console.ResetColor();
- if (!commandLineResult.GetValueForOption(LaunchOptions.SkipConnectionPatching))
- {
- if (legacyCertMode)
- {
- Task.WaitAll(new[]
- {
- memory.QueuePatch(Patterns.Windows.CertBundle, Patches.Windows.CertBundle, "CertBundle"),
- memory.QueuePatch(Patterns.Windows.CertCommonName, Patches.Windows.CertCommonName, "CertCommonName", 5)
- }, CancellationTokenSource.Token);
- }
- else if (LaunchOptions.IsDevModeAllowed && commandLineResult.GetValueForOption(LaunchOptions.DevMode))
- {
- Task.WaitAll(new[]
- {
- memory.QueuePatch(Patterns.Windows.CertChain, Patches.Windows.CertChain, "CertChain"),
- memory.QueuePatch(Patterns.Windows.CertCommonName, Patches.Windows.CertCommonName, "CertCommonName", 5)
- }, CancellationTokenSource.Token);
- }
- }
-
- if (commandLineResult.HasOption(LaunchOptions.UseStaticAuthSeed))
- {
- Console.ForegroundColor = ConsoleColor.Cyan;
- Console.WriteLine("Static auth seed used. Be sure that the server you are connecting to supports it.");
- Console.ResetColor();
-
- // Generates a patch for the auth seed so we don't have to update them on each build.
- var authSeedFunctionOffset = GenerateAuthSeedFunctionPatch(memory, modulusOffset);
-
- Task.WaitAll(new[]
- {
- memory.QueuePatch(authSeedFunctionOffset, Patches.Windows.AuthSeed, "CustomAuthSeedFunction")
- }, CancellationTokenSource.Token);
- }
-#if CUSTOM_FILES
- Task.WaitAll(new[]
- {
- (clientVersion is (10, _, _, _))
- ? memory.QueuePatch(Patterns.Windows.LoadByFileIdAlternate, Patches.Windows.NoJump, "LoadByFileId", 3)
- : memory.QueuePatch(Patterns.Windows.LoadByFileId, Patches.Windows.NoJump, "LoadByFileId", 6),
-
- (clientVersion is (10, _, _, _))
- ? memory.QueuePatch(Patterns.Windows.LoadByFilePathAlternate, Patches.Windows.NoJump, "LoadByFilePath", 3)
- : memory.QueuePatch(Patterns.Windows.LoadByFilePath, Patches.Windows.NoJump, "LoadByFilePath", 3)
- }, CancellationTokenSource.Token);
-
- var (idAlloc, stringAlloc) = ModLoader.LoadFileMappings(processInfo.ProcessHandle);
-
- if (idAlloc != 0 && stringAlloc != 0)
- {
- if (!ModLoader.HookClient(memory, processInfo.ProcessHandle, idAlloc, stringAlloc))
- return false;
- }
-#endif
-
- NativeWindows.NtResumeProcess(processInfo.ProcessHandle);
-
- if (memory.RemapAndPatch(antiCrash))
- {
- Console.WriteLine("Done :) ");
-
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine("You can login now.");
-
- Console.ResetColor();
-
- return true;
- }
- else
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine("Error while launching the client.");
-
- NativeWindows.TerminateProcess(processInfo.ProcessHandle, 0);
- }
+ return true;
}
}
}
@@ -354,142 +397,4 @@ static class Launcher
return false;
}
-
- static bool IsDevModeAllowed(IPFilter ipFilter, string portalIP) => ipFilter.IsInRange(portalIP);
-
- static long GenerateAuthSeedFunctionPatch(WinMemory memory, long modulusOffset)
- {
- var authSeedLoadOffset = memory.Data.FindPattern(Patterns.Windows.AuthSeed);
-
- if (authSeedLoadOffset == 0)
- throw new InvalidDataException("authSeedLoadOffset");
-
- var leaStartOffset = authSeedLoadOffset + 9;
- var leaValue = Unsafe.ReadUnaligned(ref memory.Data[leaStartOffset + 3]);
- var authSeedWrapperOffset = leaStartOffset + leaValue + 7;
- var jmpValue = Unsafe.ReadUnaligned(ref memory.Data[authSeedWrapperOffset + 6]);
- var authSeedFunctionOffset = authSeedWrapperOffset + 5 + jmpValue + 5;
-
- // Write the modulus offset to our custom get seed functions.
- // Resulting static auth seed is: 179D3DC3235629D07113A9B3867F97A7
- Unsafe.WriteUnaligned(ref Patches.Windows.AuthSeed[3], (uint)(modulusOffset - authSeedFunctionOffset - 7));
-
- return authSeedFunctionOffset;
- }
-
- static void WaitForUnpack(ref ProcessInformation processInfo, WinMemory memory, ref MemoryBasicInformation mbi, Stream gameAppData, bool antiCrash)
- {
- // Wait for client initialization.
- var initOffset = memory.Read(mbi.BaseAddress, (int)mbi.RegionSize)?.FindPattern(Patterns.Windows.Init) ?? 0;
-
- while (initOffset == 0)
- {
- initOffset = memory.Read(mbi.BaseAddress, (int)mbi.RegionSize)?.FindPattern(Patterns.Windows.Init) ?? 0;
-
- Console.WriteLine("Waiting for client initialization...");
- }
-
- initOffset += BitConverter.ToUInt32(memory.Read(initOffset + memory.BaseAddress + 2, 4), 0) + 10;
-
- while (memory.Read(initOffset + memory.BaseAddress, 1)?[0] == null ||
- memory.Read(initOffset + memory.BaseAddress, 1)?[0] == 0)
- memory.Data = memory.Read(mbi.BaseAddress, (int)mbi.RegionSize);
-
- if (antiCrash)
- PrepareAntiCrash(memory, ref mbi, ref processInfo);
-
- memory.RefreshMemoryData((int)mbi.RegionSize);
- }
-
- static void PrepareAntiCrash(WinMemory memory, ref MemoryBasicInformation mbi, ref ProcessInformation processInfo)
- {
- memory.RefreshMemoryData((int)mbi.RegionSize);
-
- // Suspend the process and handle the patches.
- NativeWindows.NtSuspendProcess(processInfo.ProcessHandle);
-
- // Get Integrity check locations
- var integrityOffsets = memory.Data.FindPattern(Patterns.Windows.Integrity, int.MaxValue, (int)mbi.RegionSize).ToArray();
-
- // Encrypt integrity offsets and patches and add them to the patch list.
- for (var i = 0; i < integrityOffsets.Length; i++)
- memory.QueuePatch(integrityOffsets[i], Patches.Windows.Integrity, $"Integrity{i}");
-
- // Get Integrity check locations
- var integrityOffsets2 = memory.Data.FindPattern(Patterns.Windows.Integrity2, int.MaxValue, (int)mbi.RegionSize).ToArray();
-
- // Encrypt integrity offsets and patches and add them to the patch list.
- for (var i = 0; i < integrityOffsets2.Length; i++)
- memory.QueuePatch(integrityOffsets2[i], Patches.Windows.Integrity, $"Integrity{integrityOffsets.Length + i}");
-
- // Get Remap check locations.
- var remapOffsets = memory.Data.FindPattern(Patterns.Windows.Remap, int.MaxValue, (int)mbi.RegionSize);
- var lastAddress = 0;
-
- foreach (var a in remapOffsets)
- {
- var instructionStart = (int)a + 4;
- var instructions = new byte[6];
-
- Buffer.BlockCopy(memory.Data, instructionStart, instructions, 0, 6);
-
- // Skip unconditional jumps.
- if (WinMemory.IsUnconditionalJump(instructions))
- continue;
-
- int operandValue;
-
- if (WinMemory.IsShortJump(instructions))
- operandValue = instructions[1] + 2;
- else if (WinMemory.IsJump(instructions))
- operandValue = BitConverter.ToInt32(instructions, 2) + 6;
- else
- throw new InvalidDataException("Invalid operand value.");
-
- var jumpToValue = a + operandValue + 4;
- var tempPatches = new ConcurrentDictionary();
-
- // Find all references of real code parts inside the remap check functions.
- Parallel.For(lastAddress, memory.Data.Length, i =>
- {
- if (WinMemory.IsJump(memory.Data, i))
- {
- var jumpOperand = BitConverter.ToInt32(memory.Data, i + 2);
- var jumpSize = (int)jumpToValue - i - 6;
-
- if (jumpOperand == jumpSize)
- {
- // Add 1 because we patch the instruction start.
- // This results in a shorter overall instruction length.
- var jumpBytes = new byte[] { 0xE9 }.Concat(BitConverter.GetBytes(jumpSize + 1)).ToArray();
-
- tempPatches.TryAdd($"Jump{i}", (i, jumpBytes));
- }
- }
- else if (WinMemory.IsShortJump(memory.Data, i))
- {
- var jumpOperand = memory.Data[i + 1];
- var jumpSize = (int)jumpToValue - i - 2;
-
- if (jumpOperand == jumpSize)
- {
- // Check for 0x48 here. This is an indicator for the test instructions.
- // Might need some better checks or future updates.
- if (memory.Data[i - 3] == 0x48)
- {
- var jumpBytes = new byte[] { 0xEB };
-
- tempPatches.TryAdd($"ShortJump{i}", (i, jumpBytes));
- }
- }
- }
- });
-
- // Add the remap crash patches to the patch list.
- foreach (var p in tempPatches)
- memory.QueuePatch(p.Value.Item1, p.Value.Item2, p.Key);
-
- lastAddress = (int)a;
- }
- }
}
diff --git a/src/Misc/Extensions.cs b/src/Misc/Extensions.cs
index c3943e5..6719b2e 100644
--- a/src/Misc/Extensions.cs
+++ b/src/Misc/Extensions.cs
@@ -1,30 +1,11 @@
// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Misc;
+namespace Arctium.Game.Launcher.Misc;
static class Extensions
{
public static nint ToNint(this byte[] buffer) => (nint)BitConverter.ToInt64(buffer, 0);
- public static nint ToNint(this long value) => (nint)value;
-
- public static byte[] GetCopy(this byte[] data)
- {
- var copy = new byte[data.Length];
-
- Array.Copy(data, copy, data.Length);
-
- return copy;
- }
-
- public static short[] GetCopy(this short[] data)
- {
- var copy = new short[data.Length];
-
- Array.Copy(data, copy, data.Length);
-
- return copy;
- }
public static long FindPattern(this byte[] data, short[] pattern, long start, long baseOffset = 0)
{
@@ -49,28 +30,5 @@ static class Extensions
}
public static long FindPattern(this byte[] data, short[] pattern, long baseOffset = 0) => FindPattern(data, pattern, 0L, baseOffset);
-
- public static HashSet FindPattern(this byte[] data, short[] pattern, int maxMatches, long maxOffset)
- {
- var matchList = new HashSet();
-
- long match = 0;
-
- do
- {
- match = data.FindPattern(pattern, match, 0);
-
- if (match == 0)
- continue;
-
- matchList.Add(match);
-
- match += pattern.Length;
-
- } while ((matchList.Count < maxMatches || match < maxOffset) && match != 0);
-
- return matchList;
- }
-
public static short[] ToPattern(this string data) => Encoding.UTF8.GetBytes(data).Select(b => (short)b).ToArray();
}
diff --git a/src/Misc/Helpers.cs b/src/Misc/Helpers.cs
index f29afb0..e63e546 100644
--- a/src/Misc/Helpers.cs
+++ b/src/Misc/Helpers.cs
@@ -1,10 +1,10 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Net;
using System.Net.Sockets;
-namespace Arctium.WoW.Launcher.Misc;
+namespace Arctium.Game.Launcher.Misc;
static class Helpers
{
@@ -17,6 +17,13 @@ static class Helpers
#endif
}
+ public static void PublisherCheck()
+ {
+ // "Arctium" should not be removed from the final binary name.
+ if (!Process.GetCurrentProcess().ProcessName.Contains("arctium", StringComparison.InvariantCultureIgnoreCase))
+ Process.GetCurrentProcess().Kill();
+ }
+
public static (int Major, int Minor, int Revision, int Build) GetVersionValueFromClient(string fileName)
{
var fileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
@@ -25,43 +32,43 @@ static class Helpers
fileVersionInfo.FileBuildPart, fileVersionInfo.FilePrivatePart);
}
- public static void PrintHeader(string serverName)
+ public static void PrintHeader()
{
+ Console.ForegroundColor = ConsoleColor.Green;
+ Console.WriteLine("Arctium Game Launcher");
+ Console.ResetColor();
+ Console.Write("Game: ");
Console.ForegroundColor = ConsoleColor.Cyan;
-
- Console.WriteLine(@"_____________World of Warcraft___________");
- Console.WriteLine(@" _ _ ");
- Console.WriteLine(@" /\ | | (_) ");
- Console.WriteLine(@" / \ _ __ ___| |_ _ _ _ _ __ ___ ");
- Console.WriteLine(@" / /\ \ | '__/ __| __| | | | | '_ ` _ \ ");
- Console.WriteLine(@" / ____ \| | | (__| |_| | |_| | | | | | |");
- Console.WriteLine(@"/_/ \_\_| \___|\__|_|\__,_|_| |_| |_|");
- Console.WriteLine("");
-
- var sb = new StringBuilder();
-
- sb.Append("_________________________________________");
-
- var nameStart = (42 - serverName.Length) / 2;
-
- sb.Insert(nameStart, serverName);
- sb.Remove(nameStart + serverName.Length, serverName.Length);
-
- Console.WriteLine(sb);
- Console.WriteLine("{0,30}", "https://arctium.io");
-
+ Console.WriteLine("World of Warcraft");
+ Console.ResetColor();
+ Console.Write("Support: ");
+ Console.ForegroundColor = ConsoleColor.Cyan;
+ Console.WriteLine("https://arctium.io");
+ Console.ResetColor();
Console.WriteLine();
Console.WriteLine($"Operating System: {RuntimeInformation.OSDescription}");
}
- public static (string IPAddress, string HostName, int Port) ParsePortal(string config)
+ public static (string IPAddress, string HostName, int Port) ParseOrSetPortal(ref string config, string customPortal = null)
{
const string portalKey = "SET portal";
- var portalIndex = config.IndexOf(portalKey, StringComparison.Ordinal);
+ var portalIndex = config.IndexOf(portalKey, StringComparison.OrdinalIgnoreCase);
if (portalIndex == -1)
- throw new ArgumentException("Config file does not contain the portal variable.");
+ {
+ if (string.IsNullOrEmpty(customPortal))
+ throw new ArgumentException("Config file does not contain a valid portal variable.");
+
+ // Append a new portal variable to the config.
+ config += $"{Environment.NewLine}{portalKey} \"{customPortal}\"";
+ }
+
+ // Re-evaluate the portal variable.
+ portalIndex = config.IndexOf(portalKey, StringComparison.OrdinalIgnoreCase);
+
+ if (portalIndex == -1)
+ throw new ArgumentException("Config file does not contain a valid portal variable.");
var startQuoteIndex = config.IndexOf('"', portalIndex);
@@ -78,8 +85,32 @@ static class Helpers
var colonIndex = portalSpan.IndexOf(':');
var ipSpan = colonIndex != -1 ? portalSpan[..colonIndex] : portalSpan;
var port = colonIndex != -1 ? int.Parse(portalSpan[(colonIndex + 1)..]) : 1119;
+
+ // Check if we have more than one portal line.
+ var lastPortalIndex = config.IndexOf(portalKey, portalIndex + portalLength, StringComparison.OrdinalIgnoreCase);
+
+ if (lastPortalIndex != -1 && lastPortalIndex != portalIndex)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine();
+ Console.WriteLine("Client portal is set multiple times. Please check your config file!");
+ Console.ResetColor();
+
+ return (string.Empty, string.Empty, port);
+ }
+
var portalString = ipSpan.ToString().Trim();
+ // Override portal variable if a custom one is provided.
+ if (!string.IsNullOrEmpty(customPortal))
+ {
+ portalString = customPortal;
+ config = string.Concat(config.AsSpan(0, startQuoteIndex + 1), portalString, config.AsSpan(endQuoteIndex));
+
+ // Let's re-parse the new portal for verification purposes.
+ return ParseOrSetPortal(ref config);
+ }
+
try
{
if (IPAddress.TryParse(portalString, out var ipAddress))
@@ -88,22 +119,39 @@ static class Helpers
var ipv4Address = Dns.GetHostAddresses(portalString).FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork);
if (ipv4Address == null)
- throw new Exception("No IPv4 address found for the provided hostname.");
+ {
+ var ipv6Address = Dns.GetHostAddresses(portalString).FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetworkV6);
+
+ if (ipv6Address == null)
+ throw new Exception("No IPv4/IPv6 address found for the provided host name.");
+
+ return (ipv6Address.ToString(), portalString, port);
+ }
return (ipv4Address.ToString(), portalString, port);
}
+ catch (SocketException socketException) when (socketException.SocketErrorCode == SocketError.HostNotFound)
+ {
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine($"DNS resolution failed for portal: {portalString}");
+ Console.ForegroundColor = ConsoleColor.Gray;
+
+ return (string.Empty, portalString, port);
+ }
catch (SocketException)
{
- Console.WriteLine("No valid portal found. Dev (Local) mode disabled.");
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine("No valid portal found.");
+ Console.ForegroundColor = ConsoleColor.Gray;
- return (string.Empty, string.Empty, port);
+ return (string.Empty, portalString, port);
}
}
- public static async Task CheckUrl(string url, string fallbackUrl)
+ public static async Task CheckUrl(string url, string[] fallbackUrls)
{
using var httpClient = new HttpClient();
-
+
httpClient.Timeout = TimeSpan.FromSeconds(5);
try
@@ -111,15 +159,31 @@ static class Helpers
var result = await httpClient.GetAsync(url);
if (!result.IsSuccessStatusCode)
- Console.WriteLine($"{url} not reachable. Falling back to {fallbackUrl}");
+ {
+ Console.WriteLine();
+ Console.WriteLine($"{url} not reachable. Falling back to: ");
+
+ foreach (var furl in fallbackUrls)
+ Console.WriteLine($"- {furl}");
+ }
return result.IsSuccessStatusCode;
}
catch (Exception)
{
- Console.WriteLine($"{url} not reachable. Falling back to {fallbackUrl}");
+ Console.WriteLine();
+ Console.WriteLine($"{url} not reachable. Falling back to: ");
+
+ foreach (var furl in fallbackUrls)
+ Console.WriteLine($"- {furl}");
return false;
}
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool UsesVersionV2(byte[] appPath)
+ {
+ return appPath.FindPattern(Patterns.Common.Version2UrlNew.ToPattern()) > 0;
+ }
}
diff --git a/src/Misc/IPFilter.cs b/src/Misc/IPFilter.cs
deleted file mode 100644
index f06b2cc..0000000
--- a/src/Misc/IPFilter.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) Arctium.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System.Net;
-
-namespace Arctium.WoW.Launcher.Misc;
-
-public class IPFilter
-{
- readonly List<(IPAddress, IPAddress)> _ipRanges = new();
-
- public void AddCidrRange(ReadOnlySpan cidr)
- {
- var separatorIndex = cidr.IndexOf('/');
-
- if (separatorIndex < 0)
- return;
-
- var subnetMaskLengthSpan = cidr[(separatorIndex + 1)..];
-
- if (!int.TryParse(subnetMaskLengthSpan, out var subnetMaskLength))
- return;
-
- Span subnetMaskBytes = stackalloc byte[4];
-
- for (var i = 0; i < subnetMaskLength; i++)
- subnetMaskBytes[i / 8] |= (byte)(1 << (7 - i % 8));
-
- if (!IPAddress.TryParse(cidr[..separatorIndex], out var ip))
- return;
-
- ReadOnlySpan ipBytes = ip.GetAddressBytes();
-
- Span networkAddressBytes = stackalloc byte[4];
- Span broadcastAddressBytes = stackalloc byte[4];
-
- for (var i = 0; i < 4; i++)
- {
- networkAddressBytes[i] = (byte)(ipBytes[i] & subnetMaskBytes[i]);
- broadcastAddressBytes[i] = (byte)(networkAddressBytes[i] | ~subnetMaskBytes[i]);
- }
-
- _ipRanges.Add((new(networkAddressBytes), new(broadcastAddressBytes)));
- }
-
- public bool IsInRange(ReadOnlySpan targetIP)
- {
- if (!IPAddress.TryParse(targetIP, out var ip))
- return false;
-
- ReadOnlySpan targetBytes = ip.GetAddressBytes();
-
- foreach (var range in _ipRanges)
- {
- ReadOnlySpan networkAddressBytes = range.Item1.GetAddressBytes();
- ReadOnlySpan broadcastAddressBytes = range.Item2.GetAddressBytes();
-
- var isInRange = true;
-
- for (var i = 0; i < 4; i++)
- {
- if ((targetBytes[i] & networkAddressBytes[i]) != networkAddressBytes[i] ||
- (targetBytes[i] & broadcastAddressBytes[i]) != targetBytes[i])
- {
- isInRange = false;
- break;
- }
- }
-
- if (isInRange)
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/Misc/NativeWindows.cs b/src/Misc/NativeWindows.cs
index 56b1ecd..0d61ee2 100644
--- a/src/Misc/NativeWindows.cs
+++ b/src/Misc/NativeWindows.cs
@@ -1,12 +1,10 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Misc;
+namespace Arctium.Game.Launcher.Misc;
static class NativeWindows
{
- /// kernel32.dll
- // Process
[DllImport("kernel32.dll", EntryPoint = "CreateProcessA", SetLastError = true)]
public static extern bool CreateProcess(string lpApplicationName, string lpCommandLine, nint lpProcessAttributes, nint lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, nint lpEnvironment, string lpCurrentDirectory, ref StartupInfo lpStartupInfo, out ProcessInformation lpProcessInformation);
@@ -16,13 +14,6 @@ static class NativeWindows
[DllImport("kernel32.dll", EntryPoint = "CloseHandle")]
public static extern void CloseHandle(nint handle);
- // Memory
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern int VirtualQueryEx(nint hProcess, nint lpBaseAddress, out MemoryBasicInformation mbi, int dwSize);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern nint VirtualAllocEx(nint hProcess, nint lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
-
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool VirtualProtectEx(nint hProcess, nint lpAddress, uint dwSize, uint flNewProtect, out uint lpflOldProtect);
@@ -35,27 +26,12 @@ static class NativeWindows
[DllImport("kernel32.dll", EntryPoint = "FlushInstructionCache", SetLastError = true)]
public static extern bool FlushInstructionCache(nint hProcess, nint lpBaseAddress, uint dwSize);
- /// ntdll.dll
- // Process
[DllImport("ntdll.dll", SetLastError = true)]
- public static extern NtStatus NtQueryInformationProcess(nint hProcess, int pic, ref ProcessBasicInformation pbi, int cb, out int pSize);
-
- // Page/View
- [DllImport("ntdll.dll", SetLastError = true)]
- public static extern NtStatus NtCreateSection(ref nint sectionHandle, uint accessMask, nint zero, ref LargeInteger maximumSize, uint protection, uint allocationAttributes, nint zero2);
-
- [DllImport("ntdll.dll", SetLastError = true)]
- public static extern NtStatus NtMapViewOfSection(nint sectionHandle, nint proccessHandle, ref nint baseAddress, nint zero, ulong regionSize, out LargeInteger sectionOffset, out uint viewSize, uint viewSection, nint zero2, int protection);
-
- [DllImport("ntdll.dll", SetLastError = true)]
- public static extern NtStatus NtUnmapViewOfSection(nint processHandle, nint baseAddress);
+ public static extern int NtQueryInformationProcess(nint hProcess, int pic, ref ProcessBasicInformation pbi, int cb, out int pSize);
[DllImport("ntdll.dll", SetLastError = true)]
public static extern nint NtResumeProcess(nint processHandle);
[DllImport("ntdll.dll", SetLastError = true)]
public static extern nint NtSuspendProcess(nint processHandle);
-
- [DllImport("ntdll.dll", SetLastError = true)]
- public static extern nint NtClose(nint handle);
}
diff --git a/src/ModLoader.cs b/src/ModLoader.cs
deleted file mode 100644
index bf20570..0000000
--- a/src/ModLoader.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-// Copyright (c) Arctium.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Arctium.WoW.Launcher;
-
-class ModLoader
-{
- static readonly HashSet _loadedFileIds = new();
-
- public static bool HookClient(WinMemory memory, nint processHandle, nint idAlloc, nint stringAlloc)
- {
- var asm = new byte[]
- {
- 0x85, 0xD2, 0x0F, 0x88, 0x72, 0xAF, 0xFF, 0xFF, 0x33, 0xC0,
- 0x49, 0xB9, 0x22, 0x22, 0x22, 0x22, 0x11, 0x11, 0x11, 0x11,
- 0x8D, 0x0C, 0x40, 0xC1, 0xE1, 0x02, 0x42, 0x39, 0x14, 0x09,
- 0x74, 0x0C, 0xFF, 0xC0, 0x3D, 0xEF, 0xBE, 0xAD, 0xDE, 0x72,
- 0xEB, 0x33, 0xC0, 0xC3, 0x4A, 0x8B, 0x44, 0x09, 0x04, 0xC3
- };
-
- var trampolineInjectAddress = NativeWindows.VirtualAllocEx(processHandle, IntPtr.Zero, (uint)asm.Length + 32, 0x00001000, (uint)MemProtection.ExecuteRead);
- var hookInstructions = new byte[] { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x90 };
-
- // Copy the asm code address.
- Buffer.BlockCopy(BitConverter.GetBytes(trampolineInjectAddress), 0, hookInstructions, 2, 8);
-
- // Inside the file load func!!!
- var hookAddress = memory.Data.FindPattern(Patterns.Windows.CustomFileIdHook);
-
- if (hookAddress == 0)
- throw new InvalidDataException("CustomFileIdHook");
-
- // Read original data from the hook function.
- var originalBytes = memory.Read(memory.BaseAddress + hookAddress, 13);
-
- // Apply the hook.
- memory.QueuePatch(hookAddress, hookInstructions, "CustomFileIdHook");
-
- // Copy count bytes.
- Buffer.BlockCopy(BitConverter.GetBytes(_loadedFileIds.Count), 0, asm, 35, 4);
-
- // Copy mapping ptr bytes.
- Buffer.BlockCopy(BitConverter.GetBytes(idAlloc), 0, asm, 12, 8);
-
- // Calculate the jump address bytes.
- var trampolineJmpAddress = (uint)(trampolineInjectAddress + asm.Length - (trampolineInjectAddress + 2) - 6);
-
- // Copy trampoline bytes.
- Buffer.BlockCopy(BitConverter.GetBytes(trampolineJmpAddress), 0, asm, 4, 4);
-
- memory.Write(trampolineInjectAddress, asm);
-
- var jmpInstruction = new byte[] { 0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x90 };
-
- // Copy the address where we continue to the jump instruction set.
- Buffer.BlockCopy(BitConverter.GetBytes((ulong)(hookAddress + memory.BaseAddress + 13)), 0, jmpInstruction, 2, 8);
-
- memory.Write(trampolineInjectAddress + asm.Length, originalBytes.Concat(jmpInstruction).ToArray());
-
- return true;
- }
-
- public static (nint idAlloc, nint stringAlloc) LoadFileMappings(nint processHandle)
- {
- var loadedMappings = new List<(byte[] fileId, byte[] path, uint StringPos)>();
- var count = 0u;
- var localStringLength = 0u;
-
- Console.WriteLine();
- Console.WriteLine($"Loading file mappings from '{AppDomain.CurrentDomain.BaseDirectory}files':");
-
- Directory.CreateDirectory($"{AppDomain.CurrentDomain.BaseDirectory}mappings");
-
- // Add all file mappings
- foreach (var f in Directory.EnumerateFiles($"{AppDomain.CurrentDomain.BaseDirectory}mappings", "*.txt", SearchOption.TopDirectoryOnly))
- {
- Console.ForegroundColor = ConsoleColor.DarkYellow;
- Console.ForegroundColor = ConsoleColor.Gray;
- Console.Write($"- {new FileInfo(f).Name}");
-
- try
- {
- GetFileMappingData(loadedMappings, out var localCount, ref localStringLength, f);
-
- count += localCount;
-
- Console.ForegroundColor = ConsoleColor.Green;
- Console.WriteLine(" (Done)");
- Console.ForegroundColor = ConsoleColor.Gray;
- }
- catch (Exception ex)
- {
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine(" (Failed)");
- Console.ForegroundColor = ConsoleColor.Gray;
-
- Console.WriteLine(ex);
- Console.WriteLine(ex.StackTrace);
- }
- }
-
- Console.WriteLine();
-
- // Just startup without doing anything.
- if (loadedMappings.Count == 0)
- {
- Console.WriteLine("No custom files.");
- }
- else
- {
- Console.ForegroundColor = ConsoleColor.DarkGreen;
- Console.WriteLine($"Loaded {loadedMappings.Count} file mappings.");
- Console.ForegroundColor = ConsoleColor.Gray;
- Console.WriteLine();
-
- // Allocate file mapping data.
- return AllocateFileMapping(processHandle, loadedMappings, count, localStringLength);
- }
-
- return default;
- }
-
- static void GetFileMappingData(List<(byte[] fileId, byte[] path, uint StringPos)> loadedMappings, out uint count, ref uint stringLength, string mappingFile)
- {
- var mappings = File.ReadAllLines(mappingFile).Where(s => s.Trim() != "")
- .Select(s => s.ToLowerInvariant().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
- .ToLookup(k => k[1], k => k[0]);
-
- var filesDir = $@"{AppDomain.CurrentDomain.BaseDirectory}files";
-
- // Create if it doesn't exist.
- Directory.CreateDirectory(filesDir);
-
- Console.WriteLine();
-
- foreach (var f in Directory.EnumerateFiles(filesDir, "*", SearchOption.AllDirectories))
- {
- // Get the sub path inside the files folder.
- var filesDirLength = Encoding.UTF8.GetByteCount(filesDir);
- var pathBytes = Encoding.UTF8.GetBytes(f);
- var path = Encoding.UTF8.GetString(pathBytes.Skip(filesDirLength + 1).ToArray()).Replace("\\", "/").ToLowerInvariant();
-
- foreach (var fileId in mappings[path])
- {
- var id = uint.Parse(fileId);
-
- if (_loadedFileIds.Contains(id))
- {
- Console.WriteLine($"Skipping overlapping file '{id} - {f}'.");
- continue;
- }
-
- _loadedFileIds.Add(id);
-
- loadedMappings.Add((BitConverter.GetBytes(id), pathBytes, stringLength));
-
- stringLength += ((uint)pathBytes.Length + 1);
- }
- }
-
- count = (uint)loadedMappings.Count;
- }
-
- static (nint, nint) AllocateFileMapping(nint handle, List<(byte[] fileId, byte[] path, uint StringPos)> loadedMappings, uint count, uint stringLength)
- {
- var idAlloc = NativeWindows.VirtualAllocEx(handle, IntPtr.Zero, (count * (4 + 8)), 0x00001000, 0x04);
- var stringAlloc = NativeWindows.VirtualAllocEx(handle, IntPtr.Zero, stringLength, 0x00001000, 0x04);
- var idAllocData = new byte[(count * (4 + 8))];
- var stringAllocData = new byte[stringLength];
-
- Parallel.For(0, loadedMappings.Count, m =>
- {
- var (fileId, path, stringPos) = loadedMappings[m];
-
- Buffer.BlockCopy(fileId, 0, idAllocData, m * 12, fileId.Length);
- Buffer.BlockCopy(BitConverter.GetBytes(stringAlloc + stringPos), 0, idAllocData, (m * 12) + 4, 8);
- Buffer.BlockCopy(path, 0, stringAllocData, (int)stringPos, path.Length);
- });
-
- NativeWindows.WriteProcessMemory(handle, idAlloc, idAllocData, idAllocData.Length, out var _);
- NativeWindows.WriteProcessMemory(handle, stringAlloc, stringAllocData, stringAllocData.Length, out var _);
-
- // READ ONLY
- NativeWindows.VirtualProtectEx(handle, idAlloc, (count * (4 + 8)), 0x02, out var _);
- NativeWindows.VirtualProtectEx(handle, stringAlloc, stringLength, 0x02, out var _);
-
- return (idAlloc, stringAlloc);
- }
-}
diff --git a/src/Patches/Common.cs b/src/Patches/Common.cs
index e6036a4..bc881e7 100644
--- a/src/Patches/Common.cs
+++ b/src/Patches/Common.cs
@@ -1,7 +1,7 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Patches;
+namespace Arctium.Game.Launcher.Patches;
static class Common
{
@@ -23,32 +23,8 @@ static class Common
0x60, 0x9F, 0x45, 0x7A, 0xA9, 0x26, 0x8A, 0x2F, 0x85, 0x0C, 0xF2, 0x19, 0xC6, 0x53, 0x92, 0xF7,
0xF0, 0xB8, 0x32, 0xCB, 0x5B, 0x66, 0xCE, 0x51, 0x54, 0xB4, 0xC3, 0xD3, 0xD4, 0xDC, 0xB3, 0xEE };
- public static byte[] SignatureModulus = { 0x17, 0x9D, 0x3D, 0xC3, 0x23, 0x56, 0x29, 0xD0, 0x71, 0x13, 0xA9, 0xB3, 0x86, 0x7F, 0x97, 0xA7,
- 0xA7, 0x2D, 0x42, 0x19, 0x42, 0xA8, 0x17, 0xB0, 0xE0, 0xD6, 0x9F, 0x58, 0x4A, 0x2B, 0x63, 0x76,
- 0x20, 0xD9, 0x7E, 0xA8, 0x8B, 0x0E, 0x2F, 0xBA, 0x3B, 0x8D, 0xF2, 0x24, 0x92, 0xCD, 0x55, 0x05,
- 0xC4, 0x87, 0xE2, 0xA6, 0xEA, 0x2B, 0xE6, 0x01, 0xC1, 0x49, 0xE7, 0x80, 0x42, 0x76, 0x76, 0xAE,
- 0x2C, 0xCA, 0x04, 0x03, 0xA1, 0x99, 0xEB, 0xDA, 0x2B, 0x11, 0x55, 0x81, 0x83, 0x4F, 0x91, 0xA9,
- 0x7E, 0x6D, 0x36, 0xDD, 0x7F, 0x90, 0xFE, 0xC5, 0xA6, 0x30, 0x1B, 0xE1, 0x44, 0xC4, 0xD5, 0x1E,
- 0xA3, 0x8D, 0xE2, 0x8A, 0xFF, 0x39, 0xE8, 0xAB, 0xDB, 0x71, 0x3B, 0x07, 0x56, 0xBF, 0xFB, 0x54,
- 0x45, 0x16, 0x3C, 0x97, 0xD1, 0xD7, 0xAE, 0xF6, 0x46, 0x23, 0xCD, 0x1B, 0x52, 0x80, 0xF2, 0xE9,
- 0x0E, 0x65, 0xA7, 0xD8, 0xA3, 0x82, 0x91, 0x03, 0xE4, 0xE4, 0xB7, 0xC0, 0xCD, 0xAA, 0xD3, 0x1D,
- 0xFA, 0x3C, 0xDD, 0x17, 0x33, 0x76, 0x14, 0x39, 0xD3, 0x3B, 0xD9, 0xD0, 0x05, 0x15, 0x48, 0x02,
- 0x14, 0x72, 0xA0, 0x04, 0xBD, 0x7B, 0x64, 0xBB, 0x25, 0x97, 0x15, 0x6E, 0x04, 0xD3, 0x48, 0x0A,
- 0x9D, 0xCC, 0x8D, 0xCB, 0x3C, 0x7C, 0x04, 0x92, 0x49, 0x6D, 0x2B, 0x05, 0x37, 0x1A, 0xBF, 0x01,
- 0x3E, 0xED, 0xBC, 0x62, 0x0A, 0x2E, 0xAF, 0x0D, 0x96, 0x80, 0xCF, 0xDD, 0x52, 0xCC, 0x9A, 0xA4,
- 0x9F, 0x44, 0xA1, 0x59, 0xC7, 0x77, 0xC9, 0x26, 0xB3, 0xFD, 0xA5, 0xDA, 0xB1, 0x29, 0x27, 0x60,
- 0xDA, 0x2B, 0x4B, 0x22, 0x40, 0xAB, 0x4F, 0xD3, 0xDD, 0x91, 0x5C, 0x54, 0x4C, 0x4B, 0xB8, 0xAB,
- 0x68, 0x84, 0x47, 0xCA, 0xE6, 0x8D, 0xFF, 0x12, 0xEC, 0x03, 0x5C, 0xAF, 0xC7, 0xC6, 0x90, 0xB7 };
-
public static byte[] CryptoEdPublicKey = { 0x02, 0x59, 0x6F, 0x0D, 0x0C, 0x06, 0x1A, 0x8B, 0x30, 0x74, 0x59, 0x88, 0xFD, 0x72, 0xC5, 0x9E,
0x29, 0xEC, 0x36, 0x7F, 0xB0, 0xF3, 0x41, 0xF2, 0x8E, 0x0F, 0x08, 0xD0, 0x37, 0xBA, 0xFC, 0x69 };
public static byte[] Portal = new byte[Patterns.Common.Portal.Length];
-
- // Our own ca_bundle.txt.signed file.
- // Supported certificates:
- // - Arctium Sandbox
- // - TrinityCore
- // - CypherCore
- public static string CertBundleData = "eyJDcmVhdGVkIjoxNDYzNDA3MjM4LCJDZXJ0aWZpY2F0ZXMiOlt7IlVyaSI6IiouKiIsIlNoYUhhc2hQdWJsaWNLZXlJbmZvIjoiRDlDOUVBODcyQjgxQ0U4RkE0MDU1QTQ1NTI3QjA5MzAyQzVDRTEwRDlGOTQwNDMwMENBOTc2NzY0ODA0QUU3RiJ9LHsiVXJpIjoiKi4qIiwiU2hhSGFzaFB1YmxpY0tleUluZm8iOiJCMTI0MUQ4MzE5OTlENEE2N0IwQzZGOUE2ODczMzFDODdGQkE5QjJDREM0Q0FDMzY5NEFEQUQ2MjJGMDE5NTJCIn1dLCJQdWJsaWNLZXlzIjpbeyJVcmkiOiIqLioiLCJTaGFIYXNoUHVibGljS2V5SW5mbyI6IkQ5QzlFQTg3MkI4MUNFOEZBNDA1NUE0NTUyN0IwOTMwMkM1Q0UxMEQ5Rjk0MDQzMDBDQTk3Njc2NDgwNEFFN0YifSx7IlVyaSI6IiouKiIsIlNoYUhhc2hQdWJsaWNLZXlJbmZvIjoiQjEyNDFEODMxOTk5RDRBNjdCMEM2RjlBNjg3MzMxQzg3RkJBOUIyQ0RDNENBQzM2OTRBREFENjIyRjAxOTUyQiJ9XSwiU2lnbmluZ0NlcnRpZmljYXRlcyI6W3siUmF3RGF0YSI6Ii0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLU1JSUZ6VENDQTdXZ0F3SUJBZ0lKQU5OcjdsdHVPcnZFTUEwR0NTcUdTSWIzRFFFQkN3VUFNSHd4Q3pBSkJnTlZCQVlUQWtSRk1STXdFUVlEVlFRSURBcFRiMjFsTFZOMFlYUmxNUm93R0FZRFZRUUtEQkZCY21OMGFYVnRJRVZ0ZFd4aGRHbHZiakVkTUJzR0ExVUVDd3dVUVhKamRHbDFiU0JGYlhWc1lYUnBiMjRnUTBFeEhUQWJCZ05WQkFNTUZFRnlZM1JwZFcwZ1JXMTFiR0YwYVc5dUlFTkJNQ0FYRFRFMk1EVXhOakU1TURNek5Gb1lEekl3TlRZd05UQTJNVGt3TXpNMFdqQjhNUXN3Q1FZRFZRUUdFd0pFUlRFVE1CRUdBMVVFQ0F3S1UyOXRaUzFUZEdGMFpURWFNQmdHQTFVRUNnd1JRWEpqZEdsMWJTQkZiWFZzWVhScGIyNHhIVEFiQmdOVkJBc01GRUZ5WTNScGRXMGdSVzExYkdGMGFXOXVJRU5CTVIwd0d3WURWUVFEREJSQmNtTjBhWFZ0SUVWdGRXeGhkR2x2YmlCRFFUQ0NBaUl3RFFZSktvWklodmNOQVFFQkJRQURnZ0lQQURDQ0Fnb0NnZ0lCQUwyekdPL1RpQm04OUtLa1lZeWEyaDJ6UWhLVTA2T2VqT0RrWUMvUEJ0RjlkRFJRL1E3KzRqek4rSnVBK1RsM3RUakNVMTZXSFZYUEtXSXRNN1c1d0N1RlN3ZkdaUkh5cUwvQ0k5dHUyUWFsVVVQUVdBTFJvUE5HUGRDbFdvOUdydHpIaW5kYSs2WnBJQmQxS2RYZUVFbnh0MGl4K0VKRisxWUpveW51dlJyMHlCbzFuUkE3bjY4TzAwZ00wdGhaa0VuUDd1K1UrZWdaWnBTTjU0N01NSVFvMWlqUDk1V2p4d2FBUC9QRzc3NGxnd3V1Q1E1dk5KNUNHaHdPbVIzMFBwUUo3RGRFYjFOUFFDWDRKWkhYa3RnMktrUkt0T09oYjFoN2FvNDNVZzMwUVhKQ0FxQXlmYW0rZkxIVVpmQzVyS1JhYm0xa3FXcVQwTWtXRzArMnpFWWIvYmVqellWZVdRMncySlZod1UzamFmNE8vcEljQTM4eExxelRIQTB1M1hrKzdPcmlIdTFDMWl4a0pqK1ZYczdhOFI2eUMyZE9qbGIxL0Y0MDgrNlFlMFpXTExTSnNDNndWTmoyaDdQMk5tUGg2M0puVmk5M1VnOVFlMUdWM1Rvb2dKVW1DNmpPS2VidXp4ZHpBelZwekhKSU92QzZkeWVjSER4VHZxYVNTRjBxdXo4T2grZHhHYlh3QnlmK2pKQ3c3S0ZFVFB2ci9ya1F2YjJlQkk0aXZjR0lDQWJjMzY3cnJuUTRTV0VlNksrenBNSzd2cWpFSG1LNmVSRjBlN2RMV01UeXpSeHdtV0RCVkJMMEZaME5nQXpMMDF3dlcxWDFVbENvWlJKZVcxYUtYYWVSZEl3UldNWlNFT3hHaUp2b2ZRQkFjTWtsZlU3YmswWUltb2Q1QWdNQkFBR2pVREJPTUIwR0ExVWREZ1FXQkJRdERMaXVIVjJ3MU9xSXFCN294eDRkdjVKSzNUQWZCZ05WSFNNRUdEQVdnQlF0RExpdUhWMncxT3FJcUI3b3h4NGR2NUpLM1RBTUJnTlZIUk1FQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUI1ZHJmYnQzZFZWWFljWnA1M0c0TTFiM3NNa1FacGFGZ0tyYXh0R3BGbHdCV0JId2cvSE9zSWNyUUxRbVdFdlFNbmRabFAvdy9PaDVmbXJiSS8wZTl2OTJURHlHL3hOUG9IdXJaa1gxb2xPaWp1YS8vTGxZRXBPSVltR29oMlF2WitiMlZFVnQ2VHZ0d1JqL0xSZVA4SFJaZmNTR05YdVRZL2s3TUZzTUZFeEpqOC9ITXgrclFaRXBPTXF3aVdkM3RVMWZnK25abHFvcUtlM1lsVEhwTXVuN3RQc0ZDMFUwOTc2cmNWNHlobGIyU0t2eHlyS3djK0V5YkF5d0diczBCYktLZFlkOTdGa2Z1NnkwQnF6YmVTM3NmeC9QT3ozVXpBOWJUTStVaksvbVZLZjUxSkdKdEFZdkFFUVJ0Q3YycW1BMERkQVRuM3lFY01mNzhDQysvaWdsL3JzRk95anlDdWdjMHlFNnFRSFZBOWZKSmU3UUgydVJPUVhlWE1kMlNjVVdrTzE0UlFxOGhOUXJaQi92R1RIM2VFY0pxZlg2UlZ6b3p4M2w5bEFMRDZZb2QzUExpcXNnTVE0Y2w3UVRUUlB6SnNRVHBWZFF4RytIR1dXb3h0UTI4ZDkyWFVPRjI2bUJFQ3l5cDArbm5KVmVHYmhtdGRZeUZHREVrcFhIUjYyeWhyNnorRUpVdFNnSGhaeVN2eGk1SXBJRXhTdHZxZVRqNDVWTXJrZ0V2bmxrTU4vZW1hbUlEYTBIVStsV0s5dWJuSGRSV0g1dFZCQUpHNDdlcndKY0NqV1gzUHNWUFhDZUNuQnBUR3IyWWl2SXRTZldJS0VsSG1PTG1QR2FaVzd2OHp5bm1ISFRvUGgvMkRBck9rMWV4V2c1Z3JVeEVnMnZ0QkMyQVR4UT09LS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLSJ9LHsiUmF3RGF0YSI6Ii0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLU1JSUY1RENDQTh5Z0F3SUJBZ0lKQUlnTHNsd2s0MFh6TUEwR0NTcUdTSWIzRFFFQkN3VUFNSDh4Q3pBSkJnTlZCQVlUQWxWVE1SUXdFZ1lEVlFRS0RBdFVjbWx1YVhSNVEyOXlaVEVxTUNnR0ExVUVDd3doVkhKcGJtbDBlVU52Y21VZ1EyVnlkR2xtYVdOaGRHVWdRWFYwYUc5eWFYUjVNUzR3TEFZRFZRUUREQ1ZVY21sdWFYUjVRMjl5WlNCQ1lYUjBiR1V1Ym1WMElFRjFjbTl5WVNCU2IyOTBJRU5CTUI0WERURTJNREl5T0RFeU5Ea3dPRm9YRFRNMk1ESXlNekV5TkRrd09Gb3dmekVMTUFrR0ExVUVCaE1DVlZNeEZEQVNCZ05WQkFvTUMxUnlhVzVwZEhsRGIzSmxNU293S0FZRFZRUUxEQ0ZVY21sdWFYUjVRMjl5WlNCRFpYSjBhV1pwWTJGMFpTQkJkWFJvYjNKcGRIa3hMakFzQmdOVkJBTU1KVlJ5YVc1cGRIbERiM0psSUVKaGRIUnNaUzV1WlhRZ1FYVnliM0poSUZKdmIzUWdRMEV3Z2dJaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQ0R3QXdnZ0lLQW9JQ0FRREdyWVd2UzBtVlBhckpkOTZFNHovcWpDdlc2ZVIwYnVRKytWTkVxVmdlRzE0azRWNDF3a0V6YWtCNG5yMm9HSDEwejlKL2FxTGxXbnhhT2wreUo3QmFvbVVBQU9nSmFDeXFBSjhIYUVVKzdCYkRPNE1aWG10dzFBM1ljSHNCa1Z4NXdHbTN0Y0g1SUVYZlZodk5aRHF3QW1ZSWNtN2dLRmduZHM2UkZKbVJ4RjRXem5XaVJyMk1Ra1NPci9rYzJlUTJWVWc1YWZUbFR4WnZhL21YRVZwU2hpbnZiaGFNU2dGQlcrUWFoQ3dCSlZRYUxoRW4rV2M2WU51SEZtWi9pNzE2eEdiM2N1WXU4OVRGNDZpS1EvOUJtOHlFRkdnOFFBMjhJWlExc1hnVnB6Skk5ZW93RnRxQXdobDY1aXBqR3c0eEgzM29mK1djd0pRTmpGN0hYeW1ScWswV0FhMmp0WE9FaVNoSTNYRGxvYmxYN3ZLYkFlOVJGcGZWSXFUOFVmS1NPSkdRRFZ6dmw0d1NpaElOc2hPN1lnSXFwOTdNR25XdG5sV0NEYjJtY1NqOEpqbnpSakcya1paQ05SLzJsZ2ZDRy8xVkYrUUxoLzN2RDIrTjVZa0pacUJLMUpURkZ4K3A2NmxWUVdmZGgyTVhQbEdqYXQzNDNIWkdtMFlSN25Sam5nTzJqM1l0VG9qZEp4UmZMZ3p0UXY5NGpNdFdQSEUzOHlzVUs3bVM2S0txWVhxeUIxOUlPSEwyUUI4ZmptT04xaENkMHdEVzQyWkIyM3l3TmtBU3c2dUpEUjAyeFhOMndpeW5JSWIzY3o2em91WGQ2MHdDN3V0TVR2ZXE4K3JoRkZnbUZEZEkybzlnd1dRUEEvNDNPWUlsQWRLVmcyTlJoWGIvNmJ6Rmt3SURBUUFCbzJNd1lUQWRCZ05WSFE0RUZnUVVFdDZneGhmbUhFYzdyQk9xSEpFZk5rekd2M013SHdZRFZSMGpCQmd3Rm9BVUV0Nmd4aGZtSEVjN3JCT3FISkVmTmt6R3YzTXdEd1lEVlIwVEFRSC9CQVV3QXdFQi96QU9CZ05WSFE4QkFmOEVCQU1DQVlZd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQkFGekNKa2NEQ1BWTWFsK1RobGlwMjZMUGtzelo0eldUc05zYlVZbVNlN2gwa21NV3Q0eDNtbVpJVGZ3Yi9leXNZQ25IVGhCVlRqWGo5VldCR2ZiRUNaL3hkeVhDMnVyK3FwME1tN3hIMld1c3dmN3lmUEMrVVNOTzYrL3RGUzI4MkZPL25NMHF1YUtWa25PQzhpb0NvQVNzQklDQjlsd1JvWVJLTkJ3Um4zcGtKcGxIZXBHYWhhSmV6NGVlZHVqTzNkenhEZEQzMnp5Mi9BZmRlRlhUeGhXWThQVGpNQktDMnpwVVFEN0tkdmwrRDhTZklzcTczYjhhOVhtaGROWDdxVGM2TWplY0NEN1dIQVAycnJLN2VwalRhVkpwNCtQWWx3N3FmaXgvTlQxZk5rcTJNYjJFNzdoMmVUb1VHMW1qcy9tdkcvNFdmVkNmTWFCSE9LYXc2ZnlaVUxmMzY2SmJ4MDJyOEswNVA1b3V2UzFaMERlMW1aSnVVRVVZaFRSU3MyUE9JZHJtVnJuOVI4M1k0bDdUS05QSmVscTJ1eUVjNHIrL2ZScmVySWxUNEhWbExQVEMzU2RXOHl0WVNVWlh4KzFOZkpmUWltaWV2ZUl5SWFUT1YzU2ZDNEVmZVh0UHRVcGNWSnZtRlhxVmJuWE9PN2JRVTYzYmZGdXVWU2VVNk9YV2pvRlJWa2RITllUR1VHYjV4ZzRoZ1dxbExXdldnMFdQZ0xMYWJNYmV0clA2YzUvUWhtbC9sMDduSkhlTG9WeGxGdXdzTDhIR2V1MEpXcW5td2FtcDQvbW1ibFJDOVVmeXJJUWVEUzhnc3g4cS90MnpkelQ0YkJwaDBucVlrWlN5aUlvUXpsTXJZZHJXeGVKbTNzUmVSMEczRmx1TCswM1RHSnlwR2Zoci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0ifSx7IlJhd0RhdGEiOiItLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS1NSUlGMmpDQ0E4S2dBd0lCQWdJQkFUQU5CZ2txaGtpRzl3MEJBUXNGQURCL01Rc3dDUVlEVlFRR0V3SlZVekVVTUJJR0ExVUVDZ3dMVkhKcGJtbDBlVU52Y21VeEtqQW9CZ05WQkFzTUlWUnlhVzVwZEhsRGIzSmxJRU5sY25ScFptbGpZWFJsSUVGMWRHaHZjbWwwZVRFdU1Dd0dBMVVFQXd3bFZISnBibWwwZVVOdmNtVWdRbUYwZEd4bExtNWxkQ0JCZFhKdmNtRWdVbTl2ZENCRFFUQWVGdzB4TmpBeU1qZ3hNekF4TWpKYUZ3MHpOakF5TWpNeE16QXhNakphTUhveEN6QUpCZ05WQkFZVEFsVlRNUlF3RWdZRFZRUUtEQXRVY21sdWFYUjVRMjl5WlRFcU1DZ0dBMVVFQ3d3aFZISnBibWwwZVVOdmNtVWdRMlZ5ZEdsbWFXTmhkR1VnUVhWMGFHOXlhWFI1TVNrd0p3WURWUVFERENCVWNtbHVhWFI1UTI5eVpTQkNZWFIwYkdVdWJtVjBJRUYxY205eVlTQkRRVENDQWlJd0RRWUpLb1pJaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFNT2ltMG9NSjhoZWQyWk8wbjRGU1dDSytBcVRLcU9LRXdrWnptditmMGpkNWRIOUY5RG1sa3FHSlhiMUZXc2QrNXJwNkdiREhvck1zSkRJS0JmV3VOeG9WSHZnU1FVbkJYb3NZL1RUWG42RGJMQ05oWlduZnhBUnpBcDhUL0ZYTC9ybHdoUjFjWWtOK1d1Z0FxNTgvQWEra2hhRzJKTnZTYi9lMXk1S2lKN3dLTjJOYkZMWi9kSXNsQkU1Z0p6Z081aFUxOVdNMHZTWFJsMlB3MGdXQk52dlpVYTRGSDR0Vzk1emRBUnRBeEpQZ2cxZDIxcXRYbmZiRTh4VENMS0U1R0FJbE9LK3I5KzNlbHQ2eStFWmlaOGNxL2IvSmZwKzFHTkJBbFZMbHBQelM3TFFmK0R0VktKNEZUdEFEV21SV0VFeTR2YVVoYmxEZm8ybm9rTmRtY25UeTkzYm1PSHdKbEtrUlpWVC92d2hLbE1TSU50QkVYSmZaUytVTStDdmhJQWhTd1J3U2E5N056OFdFcE52V0p3bC9lVVQzRCtKT0YrYmtsVHZSN1Z3d3d0dVBnSmtzOCthTENqRUMvVDVuN0tvdHhUVjF0VzVPRDNEeTN1ckowMUlOZTBTRUhNTVBWUGoyZWpxSGcybmRHUkZkQzBRbG1JeE5wYVNHcXM1SDEycnhibXd5T3B2MlAwK0VTd2xXQ0puODdXVUpoYnM5ZXozbHI4T3lYQnlNcHZVNXdxSnh6clRNa0oyeEhRcDhYVklKY2xLSHQvaXJFeHJ1L3Y3d1MwNXVzdnI1ZkM0dUNJQ0FxUU81RWQ2T3ZQKy9rclczWU5SLzVVZ3pVcEZ6KzJtZDRBSVh1cjh1VTZxVkVjMzFmS3VmaVRXblZTMmgzdjF0Y2NHc0tnL0FnTUJBQUdqWmpCa01CMEdBMVVkRGdRV0JCU08xd3FjZ3FhODdjRHI4ZlBrdTRQa2wwTGhXVEFmQmdOVkhTTUVHREFXZ0JRUzNxREdGK1ljUnp1c0U2b2NrUjgyVE1hL2N6QVNCZ05WSFJNQkFmOEVDREFHQVFIL0FnRUFNQTRHQTFVZER3RUIvd1FFQXdJQmhqQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FnRUF2eG55WE50Um9zTG5yRzRCQ2dyM3p3SHhIMFQ0aDJ5bGxDc3FjTTlERTNkQnp5anRJb29ITElFdHVLNUp0WktRYXdoOTVIZzlZL2UrYWlYUGdpSVp0c29ibUpuOEdvdmpCNkpwVXNpQTVJN05xTmZPZmNzWnUzOS9QWkMyRjBDOHQ3TTFGSG1RcFNFbkw1bTlwR25KNEt6aXkvWno0d29BZVQrdGlwSklTRFBKbldqdkl0UU9TOFd2L21TY2JIYS84WjdvMjFaSVRaTUdSRzhMSW84RnBjK3A4VlQ5eXNKMVd2UC9DYzFnNzAzb2pwZXJBRHNwS3BBL3lBV1NJMFdCcmxOVVVQM3pOL1JOS0pxK3B3S1NhZCszbzMwdFlHRGtmVFVNREZmc0o2OFV3YWxaSFB1d0N1RzVnNFpJaE1Rd3F6ZU9oWDhuVzQwUGNzYzlkUVBJRjJKekZIZlNSdEFVajBKQ2I1ZFMwOEFIN3oyd1FSRUxremVSNXgvNUdCNmI5Zmc5NnhqY0hXVHNmYkg3SzYzZTZMdjQrWkVnZ2ZCaXA1VkNMOXhBeU5LMjJwMVR2WExZNzNWMnp5cUo5ZEgvOGxHV2ZtK092UTFoelFid1BKN0o4QlBJdStmSkphT3plNTU3UUtUbWVIWVB2b2ovcTNYMnhMeU1YVzIzNmZ1NUVCWEsxUmhEZ3JSWHhmNGFIQjBCem43bnF1eVVVOHNwZExHOTdPbGp2R0VpRVNMajlvV1liWEtMbldxejZUV09uQW1UdFJMYUsyaWF1M2lQKzdsd2thb2VRNkRaSERrZ0x0aVR4N1Z3c1NKWlRVNW8rVFBqNHdmalM5SmwzajhQTVZQcGZHNUlGRjNFck9Fc3ovS1B1OU56ajd4L2wrT3RxSHc0UGl0aHVpZz0tLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tIn1dfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOR0lT+XnZUCBN5ZRi3SVMCEurGS3ATVHui4bUxpDs/aui1qBuU+GHnMN8U3H3C8mOPh5U6MfGreIKBBUsuhc3LmAPJe+fGswbLJnIEffIUQ9dBsfBTSneIi30bRAB/c312lxTy+Hpl7GhL1NmqH5+/1dtqE8urRr5Pdbzr2BskYlTT35yBuluJYn9C9tLZN+lNKMgN1y2xtopeCb/z4yVb80zGpdbQyNl4cXALDiw8O7k0v0XwurODtk8mws9QfQhfNfx+vpOATtO2V+QgYt4PgCibkOmbTmL3JagC9ExjKeyx4nRatm7ur/4m1WSPXDfVRpsJknxDsYaMrrS4X8GDOXBPQ==";
}
diff --git a/src/Patches/Windows.cs b/src/Patches/Windows.cs
index 446f143..994bc01 100644
--- a/src/Patches/Windows.cs
+++ b/src/Patches/Windows.cs
@@ -1,18 +1,10 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Patches;
+namespace Arctium.Game.Launcher.Patches;
static class Windows
{
- public static byte[] Integrity = { 0xC2, 0x00, 0x00 };
- public static byte[] CertBundle = { 0x90, 0x90 };
- public static byte[] CertCommonName = { 0xB0, 0x01 };
- public static byte[] CertChain = { 0xB3, 0x01 };
- public static byte[] ShortJump = { 0xEB };
- public static byte[] NoJump = { 0x00, 0x00, 0x00, 0x00 };
- public static byte[] AuthSeed = { 0x0F, 0x28, 0x05, 0xEF, 0xBE, 0xAD, 0xDE, 0x0F, 0x11, 0x02, 0xC3 };
-
// Registry entry used for -launcherlogin.
public static byte[] LauncherLogin = Encoding.UTF8.GetBytes(@"Software\Custom Game Server Dev\Battle.net\Launch Options\");
}
diff --git a/src/Patterns/Common.cs b/src/Patterns/Common.cs
index f652b0e..6d17d79 100644
--- a/src/Patterns/Common.cs
+++ b/src/Patterns/Common.cs
@@ -1,15 +1,19 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Patterns;
+namespace Arctium.Game.Launcher.Patterns;
static class Common
{
public static short[] ConnectToModulus = { 0x91, 0xD5, 0x9B, 0xB7, 0xD4, 0xE1, 0x83, 0xA5 };
- public static short[] SignatureModulus = { 0x35, 0xFF, 0x17, 0xE7, 0x33, 0xC4, 0xD3, 0xD4 };
public static short[] CryptoRsaModulus = { 0x71, 0xFD, 0xFA, 0x60, 0x14, 0x0D, 0xF2, 0x05 };
- public static short[] CryptoEdPublicKey = { 0x15, 0xD6, 0x18, 0xBD, 0x7D, 0xB5, 0x77, 0xBD };
+ public static short[] CryptoEdPublicKey = { 0x15, 0xD6, 0x18, 0xBD, 0x7D, 0xB5, 0x77, 0xBD, 0x9A, 0x8D, 0x45, 0x76, 0x9C, 0x59, 0xE4, 0xFC, 0x63 };
- public static short[] CertBundle = "{\"Created\":".ToPattern();
+ public static string VersionUrl = "http://%s.patch.battle.net:1119/%s/versions";
+ public static string Version2Url = "https://%s.version.battle.net/v2/products/%s/versions";
+ public static string Version2UrlNew = "https://%s.version.battle.net/v2/products/%s/%s";
+ public static string Version2ChinaUrl = "https://cn.version.battlenet.com.cn/v2/products/%s/versions";
+ public static string Version2ChinaUrlNew = "https://cn.version.battlenet.com.cn/v2/products/%s/%s";
+ public static string CdnsUrl = "http://%s.patch.battle.net:1119/%s/cdns";
public static short[] Portal = ".actual.battle.net\0".ToPattern();
}
diff --git a/src/Patterns/Windows.cs b/src/Patterns/Windows.cs
index 15bb3e5..78f871b 100644
--- a/src/Patterns/Windows.cs
+++ b/src/Patterns/Windows.cs
@@ -1,34 +1,10 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Patterns;
+namespace Arctium.Game.Launcher.Patterns;
static class Windows
{
- public static short[] Init = { 0xC7, 0x05, -1, -1, -1, -1, 0x01, 0x00, 0x00, 0x00, 0x48, 0x8D, -1, -1, -1, -1, -1, 0x48, 0x8D, -1, -1, -1, -1, -1, 0xE8, -1, -1, -1, -1, 0x85 };
-
- // Anti Crash.
- public static short[] Integrity = { 0x44, 0x89, -1, 0x24, -1, 0x44, 0x89, -1, 0x24, -1, 0x89, -1, 0x24, -1, 0x48, 0x89, -1, 0x24, -1, 0x53, 0x56, 0x57 };
- public static short[] Integrity2 = { 0x44, 0x89, -1, 0x24, -1, 0x44, 0x89, -1, 0x24, -1, 0x89, -1, 0x24, -1, 0x48, 0x89, -1, 0x24, -1, 0x53, 0x57 };
- public static short[] Remap = { 0x48, -1, -1, 0x1E, 0x0F, 0x83 };
-
- // Certificate bundle loading.
- public static short[] CertBundle = { 0x75, 0x06, 0x48, -1, -1, 0x60, 0x5F, 0xC3 };
- public static short[] CertCommonName = { 0x80, -1, 0x2A, 0x75, -1, 0x32, 0xC0, 0x48 };
-
- // Developer mode.
- public static short[] CertChain = { 0x32, 0xDB, 0xEB, 0x02, 0xB3, 0x01, 0x48, 0x83, -1, -1, 0x00, 0x00, 0x00, 0x00 };
-
- // Auth seed function.
- public static short[] AuthSeed = { 0x57, 0x6F, 0x57, 0x00, 0xE8, -1, -1, -1, -1, 0x48, 0x8D };
-
- // Custom files (mods).
- public static short[] LoadByFileId = { 0x41, -1, -1, 0x01, 0x0F, 0x84, -1, 0x00, 0x00, 0x00, 0x48, 0x8B, -1, -1, -1, -1, -1, 0x8B };
- public static short[] LoadByFileIdAlternate = { 0x01, 0x0F, 0x84, -1, -1, -1, -1, 0x48, 0x8B, -1, -1, -1, -1, -1, 0x8B, -1, 0xE8 };
- public static short[] LoadByFilePath = { 0x01, 0x0F, 0x84, -1, -1, -1, -1, 0x48, 0x8B, -1, -1, -1, -1, -1, 0x44, 0x89, -1, -1, -1, 0x48, 0x85, 0xC9 };
- public static short[] LoadByFilePathAlternate = { 0x01, 0x0F, 0x84, -1, -1, -1, -1, 0x48, 0x8B, -1, -1, -1, -1, -1, 0x44, 0x89, -1, -1, -1, 0x00, 0x00, 0x00, 0x48, 0x85, 0xC9 };
- public static short[] CustomFileIdHook = { 0x48, 0x89, 0x5C, 0x24, 0x08, 0x57, 0x48, 0x83, 0xEC, 0x20, 0x48, 0x8B, -1, 0x48, -1, -1, 0x48, -1, -1, -1, -1, -1, -1, 0xE8, -1, -1, -1, -1, 0x48, -1, -1, -1, -1, -1, -1, 0x48, -1, -1, 0x74, -1, 0x48, -1, 0xCD };
-
// Registry entry used for -launcherlogin.
public static short[] LauncherLogin = @"Software\Blizzard Entertainment\Battle.net\Launch Options\".ToPattern();
}
diff --git a/src/Program.cs b/src/Program.cs
index bbe6723..290ad3e 100644
--- a/src/Program.cs
+++ b/src/Program.cs
@@ -1,71 +1,46 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.CommandLine.Parsing;
-using Arctium.WoW.Launcher;
+using Arctium.Game.Launcher;
-using static Arctium.WoW.Launcher.Misc.Helpers;
+using static Arctium.Game.Launcher.Misc.Helpers;
-// "Arctium" should not be removed from the final binary name.
-if (!Process.GetCurrentProcess().ProcessName.Contains("arctium", StringComparison.InvariantCultureIgnoreCase))
- WaitAndExit();
+PublisherCheck();
+PrintHeader();
-Console.ForegroundColor = ConsoleColor.Red;
-Console.WriteLine("THIS LAUNCHER IS DISCONTINUED!!! Stop asking for support.");
-Console.ForegroundColor = ConsoleColor.Yellow;
-Console.WriteLine("You can find the new supported launcher on https://arctium.io");
+var versionInfo = FileVersionInfo.GetVersionInfo(Environment.ProcessPath);
+Console.WriteLine($"Using {(int)(Environment.ProcessorCount * 0.75)} of {Environment.ProcessorCount} processors.");
Console.WriteLine();
-Console.ResetColor();
-WaitAndExit(5000);
-PrintHeader("WoW Client Launcher");
+PublisherCheck();
LaunchOptions.RootCommand.SetHandler(async context =>
{
- CreateDevIPFilter(out var ipFilter);
+ try
+ {
+ // Prefer / instead of \ for the client path.
+ var appPath = (await Launcher.PrepareGameLaunch(context.ParseResult, default)).Replace("\\", "/");
+ var gameCommandLine = string.Join(" ", context.ParseResult.UnmatchedTokens);
- // Prefer / instead of \ for the client path.
- var appPath = (await Launcher.PrepareGameLaunch(context.ParseResult, ipFilter)).Replace("\\", "/");
- var gameCommandLine = string.Join(" ", context.ParseResult.UnmatchedTokens);
+ // Add config parameter to the game command line.
+ gameCommandLine += $" -config {context.ParseResult.GetValueForOption(LaunchOptions.GameConfig)}";
- // Add config parameter to the game command line.
- gameCommandLine += $" -config {context.ParseResult.GetValueForOption(LaunchOptions.GameConfig)}";
+ if (string.IsNullOrEmpty(appPath) || !Launcher.LaunchGame(appPath, gameCommandLine, context.ParseResult))
+ WaitAndExit(5000);
+ }
+ catch (Exception ex)
+ {
+ if (Launcher.GameProcessHandle != nint.Zero)
+ NativeWindows.TerminateProcess(Launcher.GameProcessHandle, 0);
- if (string.IsNullOrEmpty(appPath) || !Launcher.LaunchGame(appPath, gameCommandLine, context.ParseResult))
- WaitAndExit(5000);
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.WriteLine(ex.Message);
+ Console.ResetColor();
+ }
});
await LaunchOptions.Instance.InvokeAsync(args);
-return;
-
-void CreateDevIPFilter(out IPFilter ipFilter)
-{
- ipFilter = new IPFilter();
-
- ipFilter.AddCidrRange("0.0.0.0/8");
- ipFilter.AddCidrRange("10.0.0.0/8");
- ipFilter.AddCidrRange("100.64.0.0/10");
- ipFilter.AddCidrRange("127.0.0.0/8");
- ipFilter.AddCidrRange("169.254.0.0/16");
- ipFilter.AddCidrRange("172.16.0.0/12");
- ipFilter.AddCidrRange("192.0.0.0/24");
- ipFilter.AddCidrRange("192.0.0.0/29");
- ipFilter.AddCidrRange("192.0.0.8/32");
- ipFilter.AddCidrRange("192.0.0.9/32");
- ipFilter.AddCidrRange("192.0.0.170/32");
- ipFilter.AddCidrRange("192.0.0.171/32");
- ipFilter.AddCidrRange("192.0.2.0/24");
- ipFilter.AddCidrRange("192.31.196.0/24");
- ipFilter.AddCidrRange("192.52.193.0/24");
- ipFilter.AddCidrRange("192.88.99.0/24");
- ipFilter.AddCidrRange("192.168.0.0/16");
- ipFilter.AddCidrRange("192.175.48.0/24");
- ipFilter.AddCidrRange("198.18.0.0/15");
- ipFilter.AddCidrRange("198.51.100.0/24");
- ipFilter.AddCidrRange("203.0.113.0/24");
- ipFilter.AddCidrRange("240.0.0.0/4");
- ipFilter.AddCidrRange("255.255.255.255/32");
-}
static void WaitAndExit(int ms = 2000)
{
@@ -75,4 +50,4 @@ static void WaitAndExit(int ms = 2000)
Thread.Sleep(ms);
Environment.Exit(0);
-}
+}
\ No newline at end of file
diff --git a/src/Structures/LargeInteger.cs b/src/Structures/LargeInteger.cs
deleted file mode 100644
index a0eb5f5..0000000
--- a/src/Structures/LargeInteger.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Arctium.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-namespace Arctium.WoW.Launcher.Structures;
-
-[StructLayout(LayoutKind.Explicit, Size = 8)]
-struct LargeInteger
-{
- [FieldOffset(0)]
- public long Quad;
- [FieldOffset(0)]
- public uint Low;
- [FieldOffset(4)]
- public int High;
-
- public static int Size => Marshal.SizeOf();
-}
diff --git a/src/Structures/MemoryBasicInformation.cs b/src/Structures/MemoryBasicInformation.cs
index 83c8928..03e5826 100644
--- a/src/Structures/MemoryBasicInformation.cs
+++ b/src/Structures/MemoryBasicInformation.cs
@@ -1,7 +1,7 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Structures;
+namespace Arctium.Game.Launcher.Structures;
[StructLayout(LayoutKind.Sequential)]
struct MemoryBasicInformation
@@ -10,9 +10,9 @@ struct MemoryBasicInformation
public nint AllocationBase;
public MemProtection AllocationProtect;
public nint RegionSize;
- public MemState State;
+ public int State;
public MemProtection Protect;
- public MemType Type;
+ public int Type;
public static int Size => Marshal.SizeOf();
}
diff --git a/src/Structures/ProcessBasicInformation.cs b/src/Structures/ProcessBasicInformation.cs
index 84a1e07..2e5afd3 100644
--- a/src/Structures/ProcessBasicInformation.cs
+++ b/src/Structures/ProcessBasicInformation.cs
@@ -1,7 +1,7 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Structures;
+namespace Arctium.Game.Launcher.Structures;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ProcessBasicInformation
diff --git a/src/Structures/ProcessInformation.cs b/src/Structures/ProcessInformation.cs
index 8fac950..58f104c 100644
--- a/src/Structures/ProcessInformation.cs
+++ b/src/Structures/ProcessInformation.cs
@@ -1,7 +1,7 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Structures;
+namespace Arctium.Game.Launcher.Structures;
struct ProcessInformation
{
diff --git a/src/Structures/StartupInfo.cs b/src/Structures/StartupInfo.cs
index 1a74e7c..826d30e 100644
--- a/src/Structures/StartupInfo.cs
+++ b/src/Structures/StartupInfo.cs
@@ -1,7 +1,7 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-namespace Arctium.WoW.Launcher.Structures;
+namespace Arctium.Game.Launcher.Structures;
struct StartupInfo
{
diff --git a/src/Usings.cs b/src/Usings.cs
index 561cd2e..36c97a8 100644
--- a/src/Usings.cs
+++ b/src/Usings.cs
@@ -1,14 +1,13 @@
-// Copyright (c) Arctium.
+// Copyright (c) Arctium.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-global using System.Collections.Concurrent;
global using System.CommandLine;
global using System.Diagnostics;
global using System.Runtime.CompilerServices;
global using System.Runtime.InteropServices;
global using System.Text;
-global using Arctium.WoW.Launcher.Constants;
-global using Arctium.WoW.Launcher.IO;
-global using Arctium.WoW.Launcher.Misc;
-global using Arctium.WoW.Launcher.Structures;
+global using Arctium.Game.Launcher.Constants;
+global using Arctium.Game.Launcher.IO;
+global using Arctium.Game.Launcher.Misc;
+global using Arctium.Game.Launcher.Structures;