├── .gitignore ├── Components ├── AMDaemonPatches.cs ├── AMMAnagerPatches.cs ├── BackupSettingPatches.cs ├── BookkeepPatches.cs ├── CreditPatches.cs ├── JvsPatches.cs ├── OperationManagerPatches.cs ├── SaveLoad │ ├── AccessCodePatches.cs │ ├── AimeIdPatches.cs │ ├── AimePatches.cs │ ├── AimeResultPatches.cs │ ├── AimeUnitPatches.cs │ └── PacketPatches.cs ├── SequenceInitializePatches.cs ├── SerialPatches.cs ├── Settings.cs └── SysConfigPatches.cs ├── FileSystem.cs ├── Harmony.cs ├── Logging ├── ConsoleLogListener.cs ├── FileLogListener.cs ├── GameLogListener.cs ├── ILogListener.cs ├── Log.cs ├── LogLevel.cs └── TraceLogListener.cs ├── Main.cs └── UnityParrot.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Coverlet is a free, cross platform Code Coverage Tool 141 | coverage*[.json, .xml, .info] 142 | 143 | # Visual Studio code coverage results 144 | *.coverage 145 | *.coveragexml 146 | 147 | # NCrunch 148 | _NCrunch_* 149 | .*crunch*.local.xml 150 | nCrunchTemp_* 151 | 152 | # MightyMoose 153 | *.mm.* 154 | AutoTest.Net/ 155 | 156 | # Web workbench (sass) 157 | .sass-cache/ 158 | 159 | # Installshield output folder 160 | [Ee]xpress/ 161 | 162 | # DocProject is a documentation generator add-in 163 | DocProject/buildhelp/ 164 | DocProject/Help/*.HxT 165 | DocProject/Help/*.HxC 166 | DocProject/Help/*.hhc 167 | DocProject/Help/*.hhk 168 | DocProject/Help/*.hhp 169 | DocProject/Help/Html2 170 | DocProject/Help/html 171 | 172 | # Click-Once directory 173 | publish/ 174 | 175 | # Publish Web Output 176 | *.[Pp]ublish.xml 177 | *.azurePubxml 178 | # Note: Comment the next line if you want to checkin your web deploy settings, 179 | # but database connection strings (with potential passwords) will be unencrypted 180 | *.pubxml 181 | *.publishproj 182 | 183 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 184 | # checkin your Azure Web App publish settings, but sensitive information contained 185 | # in these scripts will be unencrypted 186 | PublishScripts/ 187 | 188 | # NuGet Packages 189 | *.nupkg 190 | # NuGet Symbol Packages 191 | *.snupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | *.appxbundle 217 | *.appxupload 218 | 219 | # Visual Studio cache files 220 | # files ending in .cache can be ignored 221 | *.[Cc]ache 222 | # but keep track of directories ending in .cache 223 | !?*.[Cc]ache/ 224 | 225 | # Others 226 | ClientBin/ 227 | ~$* 228 | *~ 229 | *.dbmdl 230 | *.dbproj.schemaview 231 | *.jfm 232 | *.pfx 233 | *.publishsettings 234 | orleans.codegen.cs 235 | 236 | # Including strong name files can present a security risk 237 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 238 | #*.snk 239 | 240 | # Since there are multiple workflows, uncomment next line to ignore bower_components 241 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 242 | #bower_components/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- [Bb]ackup.rdl 268 | *- [Bb]ackup ([0-9]).rdl 269 | *- [Bb]ackup ([0-9][0-9]).rdl 270 | 271 | # Microsoft Fakes 272 | FakesAssemblies/ 273 | 274 | # GhostDoc plugin setting file 275 | *.GhostDoc.xml 276 | 277 | # Node.js Tools for Visual Studio 278 | .ntvs_analysis.dat 279 | node_modules/ 280 | 281 | # Visual Studio 6 build log 282 | *.plg 283 | 284 | # Visual Studio 6 workspace options file 285 | *.opt 286 | 287 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 288 | *.vbw 289 | 290 | # Visual Studio LightSwitch build output 291 | **/*.HTMLClient/GeneratedArtifacts 292 | **/*.DesktopClient/GeneratedArtifacts 293 | **/*.DesktopClient/ModelManifest.xml 294 | **/*.Server/GeneratedArtifacts 295 | **/*.Server/ModelManifest.xml 296 | _Pvt_Extensions 297 | 298 | # Paket dependency manager 299 | .paket/paket.exe 300 | paket-files/ 301 | 302 | # FAKE - F# Make 303 | .fake/ 304 | 305 | # CodeRush personal settings 306 | .cr/personal 307 | 308 | # Python Tools for Visual Studio (PTVS) 309 | __pycache__/ 310 | *.pyc 311 | 312 | # Cake - Uncomment if you are using it 313 | # tools/** 314 | # !tools/packages.config 315 | 316 | # Tabs Studio 317 | *.tss 318 | 319 | # Telerik's JustMock configuration file 320 | *.jmconfig 321 | 322 | # BizTalk build output 323 | *.btp.cs 324 | *.btm.cs 325 | *.odx.cs 326 | *.xsd.cs 327 | 328 | # OpenCover UI analysis results 329 | OpenCover/ 330 | 331 | # Azure Stream Analytics local run output 332 | ASALocalRun/ 333 | 334 | # MSBuild Binary and Structured Log 335 | *.binlog 336 | 337 | # NVidia Nsight GPU debugger configuration file 338 | *.nvuser 339 | 340 | # MFractors (Xamarin productivity tool) working folder 341 | .mfractor/ 342 | 343 | # Local History for Visual Studio 344 | .localhistory/ 345 | 346 | # BeatPulse healthcheck temp database 347 | healthchecksdb 348 | 349 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 350 | MigrationBackup/ 351 | 352 | # Ionide (cross platform F# VS Code tools) working folder 353 | .ionide/ -------------------------------------------------------------------------------- /Components/AMDaemonPatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | 3 | namespace UnityParrot.Components 4 | { 5 | public class AMDaemonPatches 6 | { 7 | public static void Patch() 8 | { 9 | Harmony.MakeRET(typeof(Error), "Set", false, new System.Type[] { typeof(int), typeof(int) }); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Components/AMMAnagerPatches.cs: -------------------------------------------------------------------------------- 1 | using Harmony; 2 | using MU3.AM; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | 7 | namespace UnityParrot.Components 8 | { 9 | public class AMManagerPatches 10 | { 11 | public static void Patch() 12 | { 13 | Harmony.PatchAllInType(typeof(AMManagerPatches)); 14 | } 15 | 16 | [MethodPatch(PatchType.Transpiler, typeof(AMManager), "execute")] 17 | static IEnumerable AMManagerExecuteTranspiler(IEnumerable instructions) 18 | { 19 | var codes = new List(instructions); 20 | codes.RemoveAt(0); // remove Core.Execute(); call 21 | return codes.AsEnumerable(); 22 | } 23 | 24 | [MethodPatch(PatchType.Transpiler, typeof(AMManager), "Execute_WaitAMDaemonReady")] 25 | static IEnumerable AMManagerExecuteWaitAMDaemonReadyTranspiler(IEnumerable instructions) 26 | { 27 | var codes = new List(instructions); 28 | 29 | // remove checks 30 | codes.RemoveRange(0, 3); 31 | codes.RemoveRange(5 - 3, 10); 32 | 33 | return codes.AsEnumerable(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Components/BackupSettingPatches.cs: -------------------------------------------------------------------------------- 1 | using MU3.AM; 2 | using MU3.DB; 3 | 4 | namespace UnityParrot.Components 5 | { 6 | public class BackupSettingPatches 7 | { 8 | public static void Patch() 9 | { 10 | Harmony.PatchAllInType(typeof(BackupSettingPatches)); 11 | Harmony.MakeRET(typeof(BackupSetting), "get_isEventModeSettingAvailable", false); 12 | } 13 | 14 | [MethodPatch(PatchType.Prefix, typeof(BackupSetting), "get_gpPurchaseCreditLimit")] 15 | static bool gpPurchaseCreditLimit(ref GpPurchaseCreditLimitID __result) 16 | { 17 | __result = GpPurchaseCreditLimitID.Off; 18 | return false; 19 | } 20 | 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Components/BookkeepPatches.cs: -------------------------------------------------------------------------------- 1 | using Harmony; 2 | using MU3.AM; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection.Emit; 7 | 8 | namespace UnityParrot.Components 9 | { 10 | public class BookkeepPatches 11 | { 12 | public static void Patch() 13 | { 14 | Harmony.PatchAllInType(typeof(BookkeepPatches)); 15 | Harmony.MakeRET(typeof(BackupBookkeep), "updateCredit"); 16 | Harmony.MakeRET(typeof(BackupBookkeep), "updateRunningTime", methodTypes: new Type[] { }); 17 | } 18 | 19 | [MethodPatch(PatchType.Transpiler, typeof(BackupBookkeep), "clearTotal")] 20 | static IEnumerable ClearTotalTranspiler(IEnumerable instructions) 21 | { 22 | var codes = new List(instructions); 23 | 24 | codes.RemoveRange(0, 4); 25 | codes.RemoveRange(10 - 4, 4); 26 | 27 | return codes.AsEnumerable(); 28 | } 29 | 30 | // both of these funcs only have one 'call' instruction so the same code can be applied to both 31 | [MethodPatch(PatchType.Transpiler, typeof(BackupBookkeep), "startPlayTime")] 32 | [MethodPatch(PatchType.Transpiler, typeof(BackupBookkeep), "endPlayTime")] 33 | static IEnumerable PlayTimeTranspiler(IEnumerable instructions) 34 | { 35 | var codes = new List(instructions); 36 | 37 | int targetIdx = 0; 38 | 39 | for (int i = 0; i < codes.Count; i++) 40 | { 41 | if (codes[i].opcode == OpCodes.Call) 42 | { 43 | targetIdx = i; 44 | } 45 | } 46 | 47 | // we remove: 48 | // ldc.i4.0 push 0 to stack 49 | // call [func] 50 | // pop 51 | 52 | codes.RemoveRange(targetIdx - 1, 3); 53 | 54 | return codes.AsEnumerable(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Components/CreditPatches.cs: -------------------------------------------------------------------------------- 1 | using MU3.AM; 2 | using MU3.DB; 3 | using System.Collections.Generic; 4 | 5 | namespace UnityParrot.Components 6 | { 7 | public class CreditPatches 8 | { 9 | public static void Patch() 10 | { 11 | Harmony.PatchAllInType(typeof(CreditPatches)); 12 | Harmony.MakeRET(typeof(Credit), "clearAimeLog"); 13 | Harmony.MakeRET(typeof(Credit), "initialize"); 14 | Harmony.MakeRET(typeof(Credit), "isGameCostEnough", true); 15 | Harmony.MakeRET(typeof(Credit), "onCoinIn", true); 16 | Harmony.MakeRET(typeof(Credit), "payGameCost", true); 17 | Harmony.MakeRET(typeof(Credit), "sendAimeLog"); 18 | Harmony.MakeRET(typeof(Credit), "terminate"); 19 | } 20 | 21 | [MethodPatch(PatchType.Prefix, typeof(Credit), "get_addableCoin")] 22 | static bool addableCoin(ref int __result) 23 | { 24 | __result = 0; 25 | return false; 26 | } 27 | 28 | [MethodPatch(PatchType.Prefix, typeof(Credit), "get_coin")] 29 | static bool coin(ref int __result) 30 | { 31 | __result = 10; 32 | return false; 33 | } 34 | 35 | [MethodPatch(PatchType.Prefix, typeof(Credit), "get_CoinAmount")] 36 | static bool CoinAmount(ref int __result) 37 | { 38 | __result = 1; 39 | return false; 40 | } 41 | 42 | [MethodPatch(PatchType.Prefix, typeof(Credit), "get_credit")] 43 | static bool credit(ref int __result) 44 | { 45 | __result = 10; 46 | return false; 47 | } 48 | 49 | [MethodPatch(PatchType.Prefix, typeof(Credit), "toCoins")] 50 | static bool toCoins(ref int __result, int __0) 51 | { 52 | __result = __0; 53 | return false; 54 | } 55 | 56 | [MethodPatch(PatchType.Prefix, typeof(Credit), "getGpProductList")] 57 | static bool getGpProductList(ref List __result) 58 | { 59 | __result = new List(); 60 | __result.Add(new Product(GpProductID.A_Credit1, GpProductID.A_Credit1)); 61 | __result.Add(new Product(GpProductID.A_Credit2, GpProductID.A_Credit2)); 62 | __result.Add(new Product(GpProductID.A_Credit3, GpProductID.A_Credit3)); 63 | 64 | return false; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Components/JvsPatches.cs: -------------------------------------------------------------------------------- 1 | using Harmony; 2 | using MU3.DB; 3 | using MU3.Mecha; 4 | using MU3.Client; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Reflection; 9 | using System.Text; 10 | using UnityEngine; 11 | using NekoClient.Logging; 12 | 13 | namespace UnityParrot.Components 14 | { 15 | 16 | public class JvsPatches 17 | { 18 | public static void Patch() 19 | { 20 | Harmony.MakeRET(typeof(Jvs), "execute"); 21 | 22 | Type type = typeof(Jvs).GetNestedType("JvsSwitch", (BindingFlags)62); 23 | 24 | Harmony.PerformPatch("JvsSwitch # .ctor", 25 | type.GetConstructor((BindingFlags)62, null, new Type[] { typeof(int), typeof(string), typeof(KeyCode), typeof(bool), typeof(bool) }, null), 26 | transpiler: Harmony.GetPatch("JvsSwitchCtorPatch", typeof(JvsPatches))); 27 | 28 | Harmony.PatchAllInType(typeof(JvsPatches)); 29 | } 30 | 31 | static IEnumerable JvsSwitchCtorPatch(IEnumerable instructions) 32 | { 33 | var codes = new List(instructions); 34 | 35 | codes.RemoveRange(27, 23); 36 | 37 | return codes.AsEnumerable(); 38 | } 39 | 40 | static float analogRange; 41 | static float limitBuffer = 0.7f; 42 | static float lastAnalog = 0.0f; 43 | 44 | [MethodPatch(PatchType.Prefix, typeof(Jvs), "initialize")] 45 | private static bool initialize() 46 | { 47 | if (SettingsManager.instance.settings.AnalogRotateAxis) 48 | { 49 | analogRange = (float)Screen.height / 2.0f; 50 | } else 51 | { 52 | analogRange = (float)Screen.width / 2.0f; 53 | } 54 | return true; 55 | } 56 | 57 | [MethodPatch(PatchType.Prefix, typeof(Jvs), "getRawState")] 58 | private static bool getRawState(ref bool __result, JvsButtonID __0) 59 | { 60 | switch (__0) 61 | { 62 | case JvsButtonID.Begin: 63 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonBegin); 64 | break; 65 | case JvsButtonID.Service: 66 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonService); 67 | break; 68 | case JvsButtonID.Push0: 69 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonPush0); 70 | break; 71 | case JvsButtonID.Push1: 72 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonPush1); 73 | break; 74 | case JvsButtonID.LeftWall: 75 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonLeftWall); 76 | break; 77 | case JvsButtonID.Left1: 78 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonLeft1); 79 | break; 80 | case JvsButtonID.Left2: 81 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonLeft2); 82 | break; 83 | case JvsButtonID.Left3: 84 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonLeft3); 85 | break; 86 | case JvsButtonID.LeftMenu: 87 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonLeftMenu); 88 | break; 89 | case JvsButtonID.RightMenu: 90 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonRightMenu); 91 | break; 92 | case JvsButtonID.Right1: 93 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonRight1); 94 | break; 95 | case JvsButtonID.Right2: 96 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonRight2); 97 | break; 98 | case JvsButtonID.Right3: 99 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonRight3); 100 | break; 101 | case JvsButtonID.RightWall: 102 | __result = Input.GetKey(SettingsManager.instance.settings.ButtonRightWall); 103 | break; 104 | } 105 | 106 | return false; 107 | } 108 | 109 | [MethodPatch(PatchType.Prefix, typeof(Jvs), "getTriggerOn")] 110 | private static bool getTriggerOn(ref bool __result, JvsButtonID __0) 111 | { 112 | switch (__0) 113 | { 114 | case JvsButtonID.Begin: 115 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonBegin); 116 | break; 117 | case JvsButtonID.Service: 118 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonService); 119 | break; 120 | case JvsButtonID.Push0: 121 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonPush0); 122 | break; 123 | case JvsButtonID.Push1: 124 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonPush1); 125 | break; 126 | case JvsButtonID.LeftWall: 127 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonLeftWall); 128 | break; 129 | case JvsButtonID.Left1: 130 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonLeft1); 131 | break; 132 | case JvsButtonID.Left2: 133 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonLeft2); 134 | break; 135 | case JvsButtonID.Left3: 136 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonLeft3); 137 | break; 138 | case JvsButtonID.LeftMenu: 139 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonLeftMenu); 140 | break; 141 | case JvsButtonID.RightMenu: 142 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonRightMenu); 143 | break; 144 | case JvsButtonID.Right1: 145 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonRight1); 146 | break; 147 | case JvsButtonID.Right2: 148 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonRight2); 149 | break; 150 | case JvsButtonID.Right3: 151 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonRight3); 152 | break; 153 | case JvsButtonID.RightWall: 154 | __result = Input.GetKeyDown(SettingsManager.instance.settings.ButtonRightWall); 155 | break; 156 | } 157 | 158 | return false; 159 | } 160 | 161 | [MethodPatch(PatchType.Prefix, typeof(Jvs), "getTriggerOff")] 162 | private static bool getTriggerOff(ref bool __result, JvsButtonID __0) 163 | { 164 | switch (__0) 165 | { 166 | case JvsButtonID.Begin: 167 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonBegin); 168 | break; 169 | case JvsButtonID.Service: 170 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonService); 171 | break; 172 | case JvsButtonID.Push0: 173 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonPush0); 174 | break; 175 | case JvsButtonID.Push1: 176 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonPush1); 177 | break; 178 | case JvsButtonID.LeftWall: 179 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonLeftWall); 180 | break; 181 | case JvsButtonID.Left1: 182 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonLeft1); 183 | break; 184 | case JvsButtonID.Left2: 185 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonLeft2); 186 | break; 187 | case JvsButtonID.Left3: 188 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonLeft3); 189 | break; 190 | case JvsButtonID.LeftMenu: 191 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonLeftMenu); 192 | break; 193 | case JvsButtonID.RightMenu: 194 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonRightMenu); 195 | break; 196 | case JvsButtonID.Right1: 197 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonRight1); 198 | break; 199 | case JvsButtonID.Right2: 200 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonRight2); 201 | break; 202 | case JvsButtonID.Right3: 203 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonRight3); 204 | break; 205 | case JvsButtonID.RightWall: 206 | __result = Input.GetKeyUp(SettingsManager.instance.settings.ButtonRightWall); 207 | break; 208 | } 209 | 210 | return false; 211 | } 212 | 213 | // Use height because the touchpad is rotated 214 | 215 | [MethodPatch(PatchType.Prefix, typeof(Jvs), "getAnalog")] 216 | private static bool getAnalog(ref float __result) 217 | { 218 | if (SettingsManager.instance.settings.AnalogControlStyle == AnalogControlStyle.Touchpad.ToString()) 219 | { 220 | if (Input.touchCount > 0) 221 | { 222 | Touch touch = Input.GetTouch(0); 223 | __result = SettingsManager.instance.settings.AnalogRotateAxis ? touch.position.y : touch.position.x; 224 | __result = (__result - analogRange) / (analogRange * limitBuffer); 225 | } else 226 | { 227 | __result = lastAnalog; 228 | } 229 | } 230 | else if (SettingsManager.instance.settings.AnalogControlStyle == AnalogControlStyle.Mouse.ToString()) 231 | { 232 | Vector3 mouse = Input.mousePosition; 233 | __result = SettingsManager.instance.settings.AnalogRotateAxis ? mouse.y : mouse.x; 234 | __result = (__result - analogRange) / (analogRange * limitBuffer); 235 | } 236 | else if (SettingsManager.instance.settings.AnalogControlStyle == AnalogControlStyle.Buttons.ToString()) 237 | { 238 | if (Input.GetKey(SettingsManager.instance.settings.AnalogLeftButton) & 239 | !Input.GetKey(SettingsManager.instance.settings.AnalogRightButton)) 240 | { 241 | __result = lastAnalog - Time.deltaTime * SettingsManager.instance.settings.AnalogButtonSensitivity; 242 | } else if (!Input.GetKey(SettingsManager.instance.settings.AnalogLeftButton) & 243 | Input.GetKey(SettingsManager.instance.settings.AnalogRightButton)) 244 | { 245 | __result = lastAnalog + Time.deltaTime * SettingsManager.instance.settings.AnalogButtonSensitivity; 246 | } else 247 | { 248 | __result = lastAnalog; 249 | } 250 | } 251 | 252 | __result = __result > 1 ? 1 : __result; 253 | __result = __result < -1 ? -1 : __result; 254 | lastAnalog = __result; 255 | __result = SettingsManager.instance.settings.AnalogInvertAxis ? -1 * __result : __result; 256 | 257 | return false; 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /Components/OperationManagerPatches.cs: -------------------------------------------------------------------------------- 1 | using MU3.Data; 2 | using MU3.Operation; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace UnityParrot.Components 9 | { 10 | public class OperationManagerPatches 11 | { 12 | public static void Patch() 13 | { 14 | Harmony.PatchAllInType(typeof(OperationManagerPatches)); 15 | Harmony.MakeRET(typeof(OperationManager), "isAimeOffline"); 16 | Harmony.MakeRET(typeof(OperationManager), "isAimeLoginDisable"); 17 | Harmony.MakeRET(typeof(OperationManager), "isAutoRebootNeeded"); 18 | Harmony.MakeRET(typeof(OperationManager), "isClosed"); 19 | Harmony.MakeRET(typeof(OperationManager), "isCoinAcceptable", true); 20 | Harmony.MakeRET(typeof(OperationManager), "isLoginDisable"); 21 | Harmony.MakeRET(typeof(OperationManager), "isRebootNeeded"); 22 | Harmony.MakeRET(typeof(OperationManager), "isShowClosingRemainingMinutes"); 23 | Harmony.MakeRET(typeof(OperationManager), "isUnderServerMaintenance"); 24 | } 25 | 26 | [MethodPatch(PatchType.Prefix, typeof(OperationManager), "getCreditUseRestrictionByClose")] 27 | static bool getCreditUseRestrictionByClose(ref ClosingManager.CreditUseRestriction __result) 28 | { 29 | __result = ClosingManager.CreditUseRestriction.None; 30 | return false; 31 | } 32 | 33 | [MethodPatch(PatchType.Prefix, typeof(OperationManager), "getCreditUseRestrictionByMaintenance")] 34 | static bool getCreditUseRestrictionByMaintenance(ref ClosingManager.CreditUseRestriction __result) 35 | { 36 | __result = ClosingManager.CreditUseRestriction.None; 37 | return false; 38 | } 39 | 40 | public static bool patchUpdateGamePeriodOnce = true; 41 | [MethodPatch(PatchType.Prefix, typeof(OperationManager), "updateGamePeriod")] 42 | private static bool updateGamePeriod(ref OperationData ____downloadData) 43 | { 44 | if (patchUpdateGamePeriodOnce) 45 | { 46 | ____downloadData.isUpdate = true; 47 | patchUpdateGamePeriodOnce = false; 48 | } 49 | 50 | return true; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Components/SaveLoad/AccessCodePatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | 3 | namespace UnityParrot.Components 4 | { 5 | public class AccessCodePatches 6 | { 7 | public static void Patch() 8 | { 9 | Harmony.MakeRET(typeof(AccessCode), "get_IsValid", true); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Components/SaveLoad/AimeIdPatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | 3 | namespace UnityParrot.Components 4 | { 5 | public class AimeIdPatches 6 | { 7 | public static void Patch() 8 | { 9 | Harmony.MakeRET(typeof(AimeId), "get_IsValid", true); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Components/SaveLoad/AimePatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | using AMDaemon.Abaas; 3 | using System; 4 | using UnityEngine; 5 | 6 | namespace UnityParrot.Components 7 | { 8 | public class InitAimePatches 9 | { 10 | public static void Patch() 11 | { 12 | Harmony.PatchAllInType(typeof(InitAimePatches)); 13 | } 14 | 15 | [MethodPatch(PatchType.Prefix, typeof(Aime), "get_Units")] 16 | private static bool GetUnits(ref LazyCollection __result) 17 | { 18 | NekoClient.Logging.Log.Info("GetUnits"); 19 | 20 | __result = new LazyCollection(() => 21 | { 22 | return 1; 23 | }, 24 | (a) => 25 | { 26 | return (AimeUnit)Activator.CreateInstance(typeof(AimeUnit), (System.Reflection.BindingFlags)62, null, new object[] { IntPtr.Zero }, null); 27 | }, true); 28 | 29 | return false; 30 | } 31 | } 32 | 33 | public class AimePatches : MonoBehaviour 34 | { 35 | static bool shouldCoreBeReady = false; 36 | 37 | void Start() 38 | { 39 | Harmony.PatchAllInType(typeof(AimePatches)); 40 | } 41 | 42 | void Update() 43 | { 44 | if (UnityEngine.Input.GetKey(SettingsManager.instance.settings.AimeButton)) 45 | { 46 | shouldCoreBeReady = true; 47 | } 48 | } 49 | 50 | [MethodPatch(PatchType.Prefix, typeof(AMDaemon.Core), "get_IsReady")] 51 | private static bool IsReady(ref bool __result) 52 | { 53 | if (shouldCoreBeReady) 54 | { 55 | __result = true; 56 | } 57 | else 58 | { 59 | __result = false; 60 | } 61 | 62 | return false; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Components/SaveLoad/AimeResultPatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | using System; 3 | 4 | namespace UnityParrot.Components 5 | { 6 | public class AimeResultPatches 7 | { 8 | public static void Patch() 9 | { 10 | Harmony.PatchAllInType(typeof(AimeResultPatches)); 11 | 12 | Harmony.PerformPatch("AimeResult # .ctor", 13 | typeof(AimeResult).GetConstructor((System.Reflection.BindingFlags)62, null, new Type[] { typeof(IntPtr) }, null), 14 | prefix: Harmony.GetPatch("AimeResultCtorPatch", typeof(Main))); 15 | } 16 | 17 | private static bool AimeResultCtorPatch() 18 | { 19 | NekoClient.Logging.Log.Info("AimeResult .ctor"); 20 | return false; 21 | } 22 | 23 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_AccessCode")] 24 | private static bool GetAccessCode(ref AccessCode __result) 25 | { 26 | NekoClient.Logging.Log.Info("AimeResult AccessCode"); 27 | __result = AccessCode.Zero; 28 | 29 | return false; 30 | } 31 | 32 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_AimeId")] 33 | private static bool GetAimeId(ref AimeId __result) 34 | { 35 | NekoClient.Logging.Log.Info("AimeResult AimeId"); 36 | __result = new AimeId(1337u); 37 | 38 | return false; 39 | } 40 | 41 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_FirmVersion")] 42 | private static bool GetFirmVersion(ref string __result) 43 | { 44 | NekoClient.Logging.Log.Info("AimeResult FirmVersion"); 45 | __result = ""; 46 | 47 | return false; 48 | } 49 | 50 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_HardVersion")] 51 | private static bool GetHardVersion(ref string __result) 52 | { 53 | NekoClient.Logging.Log.Info("AimeResult HardVersion"); 54 | __result = ""; 55 | 56 | return false; 57 | } 58 | 59 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_IsMobile")] 60 | private static bool GetIsMobile(ref bool __result) 61 | { 62 | NekoClient.Logging.Log.Info("AimeResult IsMobile"); 63 | __result = false; 64 | 65 | return false; 66 | } 67 | 68 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_IsReaderDetected")] 69 | private static bool GetIsReaderDetected(ref bool __result) 70 | { 71 | NekoClient.Logging.Log.Info("AimeResult IsReaderDetected"); 72 | __result = true; 73 | 74 | return false; 75 | } 76 | 77 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_IsSegaIdRegistered")] 78 | private static bool GetIsSegaIdRegistered(ref bool __result) 79 | { 80 | NekoClient.Logging.Log.Info("AimeResult IsSegaIdRegistered"); 81 | __result = false; 82 | 83 | return false; 84 | } 85 | 86 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_IsValid")] 87 | private static bool GetIsValid(ref bool __result) 88 | { 89 | NekoClient.Logging.Log.Info("AimeResult IsValid"); 90 | __result = true; 91 | 92 | return false; 93 | } 94 | 95 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_OfflineId")] 96 | private static bool GetAimeOfflineId(ref AimeOfflineId __result) 97 | { 98 | NekoClient.Logging.Log.Info("AimeResult OfflineId"); 99 | __result = AimeOfflineId.Make(AccessCode.Zero); 100 | 101 | return false; 102 | } 103 | 104 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_RelatedAimeIdCount")] 105 | private static bool GetRelatedAimeIdCount(ref int __result) 106 | { 107 | NekoClient.Logging.Log.Info("AimeResult RelatedAimeIdCount"); 108 | __result = 0; 109 | 110 | return false; 111 | } 112 | 113 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_RelatedAimeIds")] 114 | private static bool GetRelatedAimeIds(ref LazyCollection __result) 115 | { 116 | NekoClient.Logging.Log.Info("AimeResult RelatedAimeIds"); 117 | __result = new LazyCollection(() => 118 | { 119 | return 0; 120 | }, 121 | (a) => 122 | { 123 | return AimeId.Zero; 124 | }, true); 125 | 126 | return false; 127 | } 128 | 129 | [MethodPatch(PatchType.Prefix, typeof(AimeResult), "get_SegaIdAuthKey")] 130 | private static bool GetSegaIdAuthKey(ref string __result) 131 | { 132 | NekoClient.Logging.Log.Info("AimeResult SegaIdAuthKey"); 133 | __result = "skeeter yeeter"; 134 | 135 | return false; 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Components/SaveLoad/AimeUnitPatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using UnityEngine; 7 | 8 | namespace UnityParrot.Components 9 | { 10 | public class AimeUnitPatches 11 | { 12 | public static void Patch() 13 | { 14 | Harmony.PatchAllInType(typeof(AimeUnitPatches)); 15 | 16 | Harmony.PerformPatch("AimeUnit#.ctor", 17 | typeof(AimeUnit).GetConstructor((System.Reflection.BindingFlags)62, null, new Type[] { typeof(IntPtr) }, null), 18 | prefix: Harmony.GetPatch("AimeUnitCtorPatch", typeof(Main))); 19 | } 20 | 21 | private static bool AimeUnitCtorPatch() 22 | { 23 | NekoClient.Logging.Log.Info("AimeUnit .ctor"); 24 | return false; 25 | } 26 | 27 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "Start")] 28 | private static bool AimeStart(AimeCommand __0, ref bool __result) 29 | { 30 | NekoClient.Logging.Log.Info($"AimeUnit Start: {__0.ToString()}"); 31 | __result = true; 32 | 33 | return false; 34 | } 35 | 36 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "Cancel")] 37 | private static bool AimeCancel(ref bool __result) 38 | { 39 | NekoClient.Logging.Log.Info("AimeUnit Cancel"); 40 | 41 | __result = false; 42 | 43 | return false; 44 | } 45 | 46 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_Confirm")] 47 | private static bool GetConfirm(ref AimeConfirm __result) 48 | { 49 | NekoClient.Logging.Log.Info("AimeUnit Confirm"); 50 | 51 | __result = AimeConfirm.AimeDB; 52 | 53 | return false; 54 | } 55 | 56 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_HasConfirm")] 57 | private static bool GetHasConfirm(ref bool __result) 58 | { 59 | NekoClient.Logging.Log.Info("AimeUnit HasConfirm"); 60 | __result = true; 61 | 62 | return false; 63 | } 64 | 65 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_HasError")] 66 | private static bool GetHasError(ref bool __result) 67 | { 68 | NekoClient.Logging.Log.Info("AimeUnit HasError"); 69 | __result = false; 70 | 71 | return false; 72 | } 73 | 74 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_HasResult")] 75 | private static bool GetHasResult(ref bool __result) 76 | { 77 | NekoClient.Logging.Log.Info("AimeUnit HasResult"); 78 | __result = true; 79 | 80 | return false; 81 | } 82 | 83 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_IsBusy")] 84 | private static bool GetIsBusy(ref bool __result) 85 | { 86 | NekoClient.Logging.Log.Info("AimeUnit IsBusy"); 87 | 88 | __result = false; 89 | 90 | return false; 91 | } 92 | 93 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_LedStatus")] 94 | private static bool GetLedStatus(ref AimeLedStatus __result) 95 | { 96 | NekoClient.Logging.Log.Info("AimeUnit LedStatus"); 97 | 98 | __result = AimeLedStatus.Success; 99 | 100 | return false; 101 | } 102 | 103 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "SetLed")] 104 | private static bool SetLed(ref bool __result) 105 | { 106 | NekoClient.Logging.Log.Info("AimeUnit SetLed"); 107 | 108 | __result = false; 109 | 110 | return false; 111 | } 112 | 113 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "SetLedStatus")] 114 | private static bool SetLedStatus(ref bool __result) 115 | { 116 | NekoClient.Logging.Log.Info("AimeUnit SetLedStatus"); 117 | 118 | __result = false; 119 | 120 | return false; 121 | } 122 | 123 | [MethodPatch(PatchType.Prefix, typeof(AimeUnit), "get_Result")] 124 | private static bool GetResult(ref AimeResult __result) 125 | { 126 | NekoClient.Logging.Log.Info("AimeUnit Result"); 127 | __result = (AimeResult)Activator.CreateInstance(typeof(AimeResult), (System.Reflection.BindingFlags)62, null, new object[] { IntPtr.Zero }, null); 128 | 129 | return false; 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Components/SaveLoad/PacketPatches.cs: -------------------------------------------------------------------------------- 1 | using Harmony; 2 | using MU3.AM; 3 | using MU3.Client; 4 | using MU3.DataStudio; 5 | using MU3.DB; 6 | using MU3.User; 7 | using MU3.Util; 8 | using NekoClient.Logging; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using System.Reflection; 13 | using System.Text; 14 | using UnityEngine; 15 | 16 | /* why are fuckin weebs so bad at game */ 17 | /* sega y u do it like dis */ 18 | namespace UnityParrot.Components 19 | { 20 | class PacketPatches : MonoBehaviour 21 | { 22 | void Start() 23 | { 24 | Harmony.PatchAllInType(typeof(PacketPatches)); 25 | } 26 | 27 | [MethodPatch(PatchType.Prefix, typeof(Packet), "procImpl")] 28 | private static bool ProcImpl(ref Packet.State __result, Packet __instance, ref Packet.State ___state_) 29 | { 30 | Log.Info($"Packet procImpl: {__instance.query.URL}"); 31 | ___state_ = Packet.State.Done; 32 | __result = Packet.State.Done; 33 | 34 | return false; 35 | } 36 | 37 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserData), "proc")] 38 | private static bool PacketGetUserDataProc(ref Packet.State __result, ref PacketGetUserData __instance) 39 | { 40 | Log.Info($"PacketGetUserData proc"); 41 | 42 | GetUserData query = __instance.query as GetUserData; 43 | 44 | if (!FileSystem.Configuration.FileExists("UserData.json")) 45 | { 46 | query.response_ = GetUserDataResponse.create(); 47 | query.response_.userData.trophyId = GameDefaultID.TrophyID.getValue(); 48 | query.response_.userId = Singleton.instance.UserId; 49 | FileSystem.Configuration.SaveJson("UserData.json", query.response_); 50 | } 51 | 52 | query.response_ = FileSystem.Configuration.LoadJson("UserData.json"); 53 | return true; 54 | } 55 | 56 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserPreview), "proc")] 57 | private static bool PacketGetUserPreviewGetResponse(ref Packet.State __result, ref PacketGetUserPreview __instance) 58 | { 59 | Log.Info($"PacketGetUserPreview proc"); 60 | 61 | GetUserPreview query = __instance.query as GetUserPreview; 62 | 63 | if (!FileSystem.Configuration.FileExists("UserPrev.json")) 64 | { 65 | query.response_ = GetUserPreviewResponse.create(); 66 | query.response_.trophyId = GameDefaultID.TrophyID.getValue(); 67 | query.response_.userId = Singleton.instance.UserId; 68 | FileSystem.Configuration.SaveJson("UserPrev.json", query.response_); 69 | } 70 | 71 | query.response_ = FileSystem.Configuration.LoadJson("UserPrev.json"); 72 | return true; 73 | } 74 | 75 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserMusicItem), "proc")] 76 | private static bool PacketGetUserMusicItemProc(ref Packet.State __result, ref PacketGetUserMusicItem __instance) 77 | { 78 | Log.Info($"PacketGetUserMusicItem proc"); 79 | 80 | GetUserMusicItem query = __instance.query as GetUserMusicItem; 81 | 82 | if (!FileSystem.Configuration.FileExists("UserMusicItem.json")) 83 | { 84 | query.response_ = GetUserMusicItemResponse.create(); 85 | FileSystem.Configuration.SaveJson("UserMusicItem.json", query.response_); 86 | } 87 | 88 | query.response_ = FileSystem.Configuration.LoadJson("UserMusicItem.json"); 89 | return true; 90 | } 91 | 92 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserMusic), "proc")] 93 | private static bool PacketGetUserMusicProc(ref Packet.State __result, ref PacketGetUserMusic __instance) 94 | { 95 | Log.Info($"PacketGetUserMusic proc"); 96 | 97 | GetUserMusic query = __instance.query as GetUserMusic; 98 | 99 | if (!FileSystem.Configuration.FileExists("UserMusic.json")) 100 | { 101 | query.response_ = GetUserMusicResponse.create(); 102 | FileSystem.Configuration.SaveJson("UserMusic.json", query.response_); 103 | } 104 | 105 | query.response_ = FileSystem.Configuration.LoadJson("UserMusic.json"); 106 | return true; 107 | } 108 | 109 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserCard), "proc")] 110 | private static bool PacketGetUserCardProc(ref Packet.State __result, ref PacketGetUserCard __instance) 111 | { 112 | Log.Info($"PacketGetUserCard proc"); 113 | 114 | GetUserCard query = __instance.query as GetUserCard; 115 | 116 | if (!FileSystem.Configuration.FileExists("UserCard.json")) 117 | { 118 | query.response_ = GetUserCardResponse.create(); 119 | FileSystem.Configuration.SaveJson("UserCard.json", query.response_); 120 | } 121 | 122 | query.response_ = FileSystem.Configuration.LoadJson("UserCard.json"); 123 | return true; 124 | } 125 | 126 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserCharacter), "proc")] 127 | private static bool PacketGetUserCharacterProc(ref Packet.State __result, ref PacketGetUserCharacter __instance) 128 | { 129 | Log.Info($"PacketGetUserCharacter proc"); 130 | 131 | GetUserCharacter query = __instance.query as GetUserCharacter; 132 | 133 | if (!FileSystem.Configuration.FileExists("UserCharacter.json")) 134 | { 135 | query.response_ = GetUserCharacterResponse.create(); 136 | FileSystem.Configuration.SaveJson("UserCharacter.json", query.response_); 137 | } 138 | 139 | query.response_ = FileSystem.Configuration.LoadJson("UserCharacter.json"); 140 | return true; 141 | } 142 | 143 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserStory), "proc")] 144 | private static bool PacketGetUserStoryProc(ref Packet.State __result, ref PacketGetUserStory __instance) 145 | { 146 | Log.Info($"PacketGetUserStory proc"); 147 | 148 | GetUserStory query = __instance.query as GetUserStory; 149 | 150 | if (!FileSystem.Configuration.FileExists("UserStory.json")) 151 | { 152 | query.response_ = GetUserStoryResponse.create(); 153 | FileSystem.Configuration.SaveJson("UserStory.json", query.response_); 154 | } 155 | 156 | query.response_ = FileSystem.Configuration.LoadJson("UserStory.json"); 157 | return true; 158 | } 159 | 160 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserChapter), "proc")] 161 | private static bool PacketGetUserChapterProc(ref Packet.State __result, ref PacketGetUserChapter __instance) 162 | { 163 | Log.Info($"PacketGetUserChapter proc"); 164 | 165 | GetUserChapter query = __instance.query as GetUserChapter; 166 | 167 | if (!FileSystem.Configuration.FileExists("UserChapter.json")) 168 | { 169 | query.response_ = GetUserChapterResponse.create(); 170 | FileSystem.Configuration.SaveJson("UserChapter.json", query.response_); 171 | } 172 | 173 | query.response_ = FileSystem.Configuration.LoadJson("UserChapter.json"); 174 | return true; 175 | } 176 | 177 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserDeckByKey), "proc")] 178 | private static bool PacketGetUserDeckByKeyProc(ref Packet.State __result, ref PacketGetUserDeckByKey __instance) 179 | { 180 | Log.Info($"PacketGetUserDeckByKey proc"); 181 | 182 | GetUserDeckByKey query = __instance.query as GetUserDeckByKey; 183 | 184 | if (!FileSystem.Configuration.FileExists("UserDeckByKey.json")) 185 | { 186 | query.response_ = GetUserDeckByKeyResponse.create(); 187 | FileSystem.Configuration.SaveJson("UserDeckByKey.json", query.response_); 188 | } 189 | 190 | query.response_ = FileSystem.Configuration.LoadJson("UserDeckByKey.json"); 191 | return true; 192 | } 193 | 194 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserTrainingRoomByKey), "proc")] 195 | private static bool PacketGetUserTrainingRoomByKeyProc(ref Packet.State __result, ref PacketGetUserTrainingRoomByKey __instance) 196 | { 197 | Log.Info($"PacketGetUserTrainingRoomByKey proc"); 198 | 199 | GetUserTrainingRoomByKey query = __instance.query as GetUserTrainingRoomByKey; 200 | 201 | if (!FileSystem.Configuration.FileExists("UserTrainingRoomByKey.json")) 202 | { 203 | query.response_ = GetUserTrainingRoomByKeyResponse.create(); 204 | FileSystem.Configuration.SaveJson("UserTrainingRoomByKey.json", query.response_); 205 | } 206 | 207 | query.response_ = FileSystem.Configuration.LoadJson("UserTrainingRoomByKey.json"); 208 | return true; 209 | } 210 | 211 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserOption), "proc")] 212 | private static bool PacketGetUserOptionProc(ref Packet.State __result, ref PacketGetUserOption __instance) 213 | { 214 | Log.Info($"PacketGetUserOption proc"); 215 | 216 | GetUserOption query = __instance.query as GetUserOption; 217 | 218 | if (!FileSystem.Configuration.FileExists("UserOption.json")) 219 | { 220 | query.response_ = GetUserOptionResponse.create(); 221 | FileSystem.Configuration.SaveJson("UserOption.json", query.response_); 222 | } 223 | 224 | query.response_ = FileSystem.Configuration.LoadJson("UserOption.json"); 225 | return true; 226 | } 227 | 228 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserActivityMusic), "proc")] 229 | private static bool PacketGetUserActivityMusicProc(ref Packet.State __result, ref PacketGetUserActivityMusic __instance) 230 | { 231 | // TODO: check what needs doing here? 232 | Log.Info($"PacketGetUserActivityMusic proc"); 233 | 234 | GetUserActivity query = __instance.query as GetUserActivity; 235 | 236 | if (!FileSystem.Configuration.FileExists("UserActivityMusic.json")) 237 | { 238 | query.response_ = GetUserActivityResponse.create(); 239 | FileSystem.Configuration.SaveJson("UserActivityMusic.json", query.response_); 240 | } 241 | 242 | query.response_ = FileSystem.Configuration.LoadJson("UserActivityMusic.json"); 243 | return true; 244 | } 245 | 246 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserActivityPlay), "proc")] 247 | private static bool PacketGetUserActivityPlayProc(ref Packet.State __result, ref PacketGetUserActivityPlay __instance) 248 | { 249 | Log.Info($"PacketGetUserActivityPlay proc"); 250 | 251 | GetUserActivity query = __instance.query as GetUserActivity; 252 | 253 | if (!FileSystem.Configuration.FileExists("UserActivityPlay.json")) 254 | { 255 | query.response_ = GetUserActivityResponse.create(); 256 | FileSystem.Configuration.SaveJson("UserActivityPlay.json", query.response_); 257 | } 258 | 259 | query.response_ = FileSystem.Configuration.LoadJson("UserActivityPlay.json"); 260 | return true; 261 | } 262 | 263 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserRatinglog), "proc")] 264 | private static bool PacketGetUserRatinglogProc(ref Packet.State __result, ref PacketGetUserRatinglog __instance) 265 | { 266 | Log.Info($"PacketGetUserRatinglog proc"); 267 | 268 | GetUserRatinglog query = __instance.query as GetUserRatinglog; 269 | 270 | if (!FileSystem.Configuration.FileExists("UserRatingLog.json")) 271 | { 272 | query.response_ = GetUserRatinglogResponse.create(); 273 | FileSystem.Configuration.SaveJson("UserRatingLog.json", query.response_); 274 | } 275 | 276 | query.response_ = FileSystem.Configuration.LoadJson("UserRatingLog.json"); 277 | return true; 278 | } 279 | 280 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserRecentRating), "proc")] 281 | private static bool PacketGetUserRecentRatingProc(ref Packet.State __result, ref PacketGetUserRecentRating __instance) 282 | { 283 | Log.Info($"PacketGetUserRecentRating proc"); 284 | 285 | GetUserRecentRating query = __instance.query as GetUserRecentRating; 286 | 287 | if (!FileSystem.Configuration.FileExists("UserRecentRating.json")) 288 | { 289 | query.response_ = GetUserRecentRatingResponse.create(); 290 | FileSystem.Configuration.SaveJson("UserRecentRating.json", query.response_); 291 | } 292 | 293 | query.response_ = FileSystem.Configuration.LoadJson("UserRecentRating.json"); 294 | return true; 295 | } 296 | 297 | static FileSystem userItemFS = new FileSystem("UnityParrot\\Configuration\\UserItem"); 298 | static FieldInfo userItemKind; 299 | 300 | static ItemType UserItemKind(PacketGetUserItem instance) 301 | { 302 | if (userItemKind == null) 303 | { 304 | userItemKind = typeof(PacketGetUserItem).GetField("_itemKind", (BindingFlags)62); 305 | } 306 | 307 | return (ItemType)userItemKind.GetValue(instance); 308 | } 309 | 310 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserItem), "proc")] 311 | private static bool PacketGetUserItemProc(ref Packet.State __result, PacketGetUserItem __instance, ItemType ____itemKind) 312 | { 313 | Log.Info($"PacketGetUserItem proc"); 314 | 315 | GetUserItem query = __instance.query as GetUserItem; 316 | 317 | string itemKindStr = ____itemKind.ToString(); 318 | if (!userItemFS.FileExists($"{itemKindStr}.json")) 319 | { 320 | query.response_ = GetUserItemResponse.create(); 321 | userItemFS.SaveJson($"{itemKindStr}.json", query.response_); 322 | } 323 | 324 | query.response_ = userItemFS.LoadJson($"{itemKindStr}.json"); 325 | return true; 326 | } 327 | 328 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserEventPoint), "proc")] 329 | private static bool PacketGetUserEventPointProc(ref Packet.State __result, ref PacketGetUserEventPoint __instance) 330 | { 331 | Log.Info($"PacketGetUserEventPoint proc"); 332 | 333 | GetUserEventPoint query = __instance.query as GetUserEventPoint; 334 | 335 | if (!FileSystem.Configuration.FileExists("UserEventPoint.json")) 336 | { 337 | query.response_ = GetUserEventPointResponse.create(); 338 | FileSystem.Configuration.SaveJson("UserEventPoint.json", query.response_); 339 | } 340 | 341 | query.response_ = FileSystem.Configuration.LoadJson("UserEventPoint.json"); 342 | return true; 343 | } 344 | 345 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserEventRanking), "proc")] 346 | private static bool PacketGetUserEventRankingProc(ref Packet.State __result, ref PacketGetUserEventRanking __instance) 347 | { 348 | Log.Info($"PacketGetUserEventRanking proc"); 349 | 350 | GetUserEventRanking query = __instance.query as GetUserEventRanking; 351 | 352 | if (!FileSystem.Configuration.FileExists("UserEventRanking.json")) 353 | { 354 | query.response_ = GetUserEventRankingResponse.create(); 355 | FileSystem.Configuration.SaveJson("UserEventRanking.json", query.response_); 356 | } 357 | 358 | query.response_ = FileSystem.Configuration.LoadJson("UserEventRanking.json"); 359 | return true; 360 | } 361 | 362 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserMissionPoint), "proc")] 363 | private static bool PacketGetUserMissionPointProc(ref Packet.State __result, ref PacketGetUserMissionPoint __instance) 364 | { 365 | Log.Info($"PacketGetUserMissionPoint proc"); 366 | 367 | GetUserMissionPoint query = __instance.query as GetUserMissionPoint; 368 | 369 | if (!FileSystem.Configuration.FileExists("UserMissionPoint.json")) 370 | { 371 | query.response_ = GetUserMissionPointResponse.create(); 372 | FileSystem.Configuration.SaveJson("UserMissionPoint.json", query.response_); 373 | } 374 | 375 | query.response_ = FileSystem.Configuration.LoadJson("UserMissionPoint.json"); 376 | return true; 377 | } 378 | 379 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserLoginBonus), "proc")] 380 | private static bool PacketGetUserLoginBonusProc(ref Packet.State __result, ref PacketGetUserLoginBonus __instance) 381 | { 382 | Log.Info($"PacketGetUserLoginBonus proc"); 383 | 384 | GetUserLoginBonus query = __instance.query as GetUserLoginBonus; 385 | 386 | if (!FileSystem.Configuration.FileExists("UserLoginBonus.json")) 387 | { 388 | query.response_ = GetUserLoginBonusResponse.create(); 389 | FileSystem.Configuration.SaveJson("UserLoginBonus.json", query.response_); 390 | } 391 | 392 | query.response_ = FileSystem.Configuration.LoadJson("UserLoginBonus.json"); 393 | return true; 394 | } 395 | 396 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserRegion), "proc")] 397 | private static bool PacketGetUserRegionProc(ref Packet.State __result, ref PacketGetUserRegion __instance) 398 | { 399 | Log.Info($"PacketGetUserRegion proc"); 400 | 401 | GetUserRegion query = __instance.query as GetUserRegion; 402 | 403 | if (!FileSystem.Configuration.FileExists("UserRegion.json")) 404 | { 405 | query.response_ = GetUserRegionResponse.create(); 406 | FileSystem.Configuration.SaveJson("UserRegion.json", query.response_); 407 | } 408 | 409 | query.response_ = FileSystem.Configuration.LoadJson("UserRegion.json"); 410 | return true; 411 | } 412 | 413 | [MethodPatch(PatchType.Prefix, typeof(PacketGetUserBpBase), "proc")] 414 | private static bool PacketGetUserBpBaseProc(ref Packet.State __result, ref PacketGetUserBpBase __instance) 415 | { 416 | Log.Info($"PacketGetUserBpBase proc"); 417 | 418 | GetUserBpBase query = __instance.query as GetUserBpBase; 419 | 420 | if (!FileSystem.Configuration.FileExists("UserBpBase.json")) 421 | { 422 | query.response_ = GetUserBpBaseResponse.create(); 423 | FileSystem.Configuration.SaveJson("UserBpBase.json", query.response_); 424 | } 425 | 426 | query.response_ = FileSystem.Configuration.LoadJson("UserBpBase.json"); 427 | return true; 428 | } 429 | 430 | [MethodPatch(PatchType.Prefix, typeof(PacketGameLogin), "proc")] 431 | private static bool PacketGameLoginProc(ref Packet.State __result, PacketGameLogin __instance) 432 | { 433 | Log.Info($"PacketGameLoginProc proc"); 434 | 435 | (__instance.query as GameLogin).response_ = new GameLoginResponse() 436 | { 437 | returnCode = 1 438 | }; 439 | 440 | return true; 441 | } 442 | 443 | [MethodPatch(PatchType.Transpiler, typeof(MU3.Scene_39_Logout), "Upsert_Init")] 444 | private static IEnumerable UpsertInitTranspiler(IEnumerable instructions) 445 | { 446 | List codes = new List(instructions); 447 | 448 | codes.RemoveRange(0, 10); 449 | 450 | return codes.AsEnumerable(); 451 | } 452 | 453 | [MethodPatch(PatchType.Prefix, typeof(PacketUpsertUserAll), "proc")] 454 | private static bool PacketUpsertUserAllProc(ref Packet.State __result, PacketUpsertUserAll __instance) 455 | { 456 | Log.Info($"!!!!! SAVING !!!!!"); 457 | 458 | UpsertUserAll query = __instance.query as UpsertUserAll; 459 | 460 | void UpdateUserData(UserData[] array) 461 | { 462 | GetUserDataResponse temporary = new GetUserDataResponse(); 463 | temporary.userData = array[0]; 464 | temporary.userId = Singleton.instance.UserId; 465 | temporary.bpRank = (int)UserUtil.calcBpRank(Singleton.instance.BattlePoint); 466 | FileSystem.Configuration.SaveJson("UserData.json", temporary); 467 | 468 | GetUserPreviewResponse temporary1 = new GetUserPreviewResponse(); 469 | temporary1.userId = temporary.userId; 470 | temporary1.isLogin = false; 471 | temporary1.lastLoginDate = temporary.userData.lastPlayDate; 472 | temporary1.userName = temporary.userData.userName; 473 | temporary1.reincarnationNum = temporary.userData.reincarnationNum; 474 | temporary1.level = temporary.userData.level; 475 | temporary1.exp = temporary.userData.exp; 476 | temporary1.playerRating = temporary.userData.playerRating; 477 | temporary1.lastGameId = temporary.userData.lastGameId; 478 | temporary1.lastRomVersion = temporary.userData.lastRomVersion; 479 | temporary1.lastDataVersion = temporary.userData.lastDataVersion; 480 | temporary1.lastPlayDate = temporary.userData.lastPlayDate; 481 | temporary1.nameplateId = temporary.userData.nameplateId; 482 | temporary1.trophyId = temporary.userData.trophyId; 483 | temporary1.cardId = temporary.userData.cardId; 484 | temporary1.dispPlayerLv = 1; 485 | temporary1.dispRating = 1; 486 | temporary1.dispBP = 1; 487 | temporary1.headphone = 0; 488 | FileSystem.Configuration.SaveJson("UserPrev.json", temporary1); 489 | } 490 | 491 | void UpdateUserOption(MU3.Client.UserOption[] array) 492 | { 493 | GetUserOptionResponse temporary = GetUserOptionResponse.create(); 494 | temporary.userOption = array[0]; 495 | temporary.userId = Singleton.instance.UserId; 496 | FileSystem.Configuration.SaveJson("UserOption.json", temporary); 497 | } 498 | 499 | void UpdateUserActivity() 500 | { 501 | void UpdateForType(string fileName, List array, UserActivityConst.Kind kind) 502 | { 503 | GetUserActivityResponse temporary = new GetUserActivityResponse(); 504 | List userActivityList = new List(); 505 | foreach (var item in array) 506 | { 507 | MU3.Client.UserActivity activity = new MU3.Client.UserActivity(); 508 | item.copyTo(activity); 509 | userActivityList.Add(activity); 510 | } 511 | 512 | temporary.userActivityList = userActivityList.ToArray(); 513 | temporary.length = temporary.userActivityList.Length; 514 | temporary.userId = Singleton.instance.UserId; 515 | temporary.kind = (int) kind; 516 | 517 | FileSystem.Configuration.SaveJson(fileName, temporary); 518 | } 519 | 520 | UserManager instance = Singleton.instance; 521 | UpdateForType("UserActivityMusic.json", instance.userActivityMusic, UserActivityConst.Kind.Music); 522 | UpdateForType("UserActivityPlay.json", instance.userActivityPlay, UserActivityConst.Kind.PlayActivity); 523 | } 524 | 525 | void UpdateUserRecentRating(MU3.Client.UserRecentRating[] array) 526 | { 527 | string fileName = "UserRecentRating.json"; 528 | GetUserRecentRatingResponse temporary = new GetUserRecentRatingResponse(); 529 | 530 | temporary.userRecentRatingList = array; 531 | temporary.userId = Singleton.instance.UserId; 532 | temporary.length = temporary.userRecentRatingList.Length; 533 | FileSystem.Configuration.SaveJson(fileName, temporary); 534 | } 535 | 536 | void UpdateUserBpBase(MU3.Client.UserBpBase[] array) 537 | { 538 | string fileName = "UserBpBase.json"; 539 | if (!FileSystem.Configuration.FileExists(fileName)) 540 | { 541 | GetUserBpBaseResponse bpBase = GetUserBpBaseResponse.create(); 542 | FileSystem.Configuration.SaveJson(fileName, bpBase); 543 | } 544 | 545 | GetUserBpBaseResponse temporary = FileSystem.Configuration.LoadJson(fileName); 546 | foreach (var item in array) 547 | { 548 | temporary.userBpBaseList = new[] { item } 549 | .Concat(temporary.userBpBaseList) 550 | .ToArray(); 551 | } 552 | 553 | temporary.length = temporary.userBpBaseList.Length; 554 | temporary.userId = Singleton.instance.UserId; 555 | FileSystem.Configuration.SaveJson("UserBpBase.json", temporary); 556 | } 557 | 558 | 559 | void UpdateUserCharacter(MU3.Client.UserCharacter[] array) 560 | { 561 | string fileName = "UserCharacter.json"; 562 | if (!FileSystem.Configuration.FileExists(fileName)) 563 | { 564 | GetUserCharacterResponse userCharacter = GetUserCharacterResponse.create(); 565 | FileSystem.Configuration.SaveJson(fileName, userCharacter); 566 | } 567 | 568 | GetUserCharacterResponse temporary = FileSystem.Configuration.LoadJson(fileName); 569 | foreach (var item in array) 570 | { 571 | temporary.userCharacterList = temporary.userCharacterList 572 | .Where(a => a.characterId != item.characterId) 573 | .Concat(new[] { item }) 574 | .ToArray(); 575 | } 576 | 577 | temporary.length = temporary.userCharacterList.Length; 578 | temporary.nextIndex = 0; 579 | temporary.userId = Singleton.instance.UserId; 580 | FileSystem.Configuration.SaveJson(fileName, temporary); 581 | } 582 | 583 | void UpdateUserCard(MU3.Client.UserCard[] array) 584 | { 585 | string fileName = "UserCard.json"; 586 | if (!FileSystem.Configuration.FileExists(fileName)) 587 | { 588 | GetUserCardResponse userCard = GetUserCardResponse.create(); 589 | FileSystem.Configuration.SaveJson(fileName, userCard); 590 | } 591 | 592 | GetUserCardResponse temporary = FileSystem.Configuration.LoadJson(fileName); 593 | foreach (var item in array) 594 | { 595 | temporary.userCardList = temporary.userCardList 596 | .Where(a => a.cardId != item.cardId) 597 | .Concat(new[] { item }) 598 | .ToArray(); 599 | } 600 | temporary.length = temporary.userCardList.Length; 601 | temporary.nextIndex = 0; 602 | temporary.userId = Singleton.instance.UserId; 603 | 604 | FileSystem.Configuration.SaveJson(fileName, temporary); 605 | } 606 | 607 | void UpdateUserDeck(MU3.Client.UserDeck[] array) 608 | { 609 | string fileName = "UserDeckByKey.json"; 610 | if (!FileSystem.Configuration.FileExists(fileName)) 611 | { 612 | GetUserDeckByKeyResponse userDeckByKey = GetUserDeckByKeyResponse.create(); 613 | FileSystem.Configuration.SaveJson(fileName, userDeckByKey); 614 | } 615 | 616 | GetUserDeckByKeyResponse temporary = FileSystem.Configuration.LoadJson(fileName); 617 | foreach (var item in array) 618 | { 619 | temporary.userDeckList = temporary.userDeckList 620 | .Where(a => a.deckId != item.deckId) 621 | .Concat(new[] { item }) 622 | .ToArray(); 623 | } 624 | temporary.length = temporary.userDeckList.Length; 625 | temporary.userId = Singleton.instance.UserId; 626 | 627 | FileSystem.Configuration.SaveJson(fileName, temporary); 628 | } 629 | 630 | void UpdateUserTrainingRoom(MU3.Client.UserTrainingRoom[] array) 631 | { 632 | string fileName = "UserTrainingRoomByKey.json"; 633 | if (!FileSystem.Configuration.FileExists(fileName)) 634 | { 635 | GetUserTrainingRoomByKeyResponse userTrainingRoom = GetUserTrainingRoomByKeyResponse.create(); 636 | FileSystem.Configuration.SaveJson(fileName, userTrainingRoom); 637 | } 638 | 639 | GetUserTrainingRoomByKeyResponse temporary = FileSystem.Configuration.LoadJson(fileName); 640 | foreach (var item in array) 641 | { 642 | temporary.userTrainingRoomList = temporary.userTrainingRoomList 643 | .Where(a => a.roomId != item.roomId) 644 | .Concat(new[] { item }) 645 | .ToArray(); 646 | } 647 | temporary.length = temporary.userTrainingRoomList.Length; 648 | temporary.userId = Singleton.instance.UserId; 649 | 650 | FileSystem.Configuration.SaveJson("UserTrainingRoom.json", temporary); 651 | } 652 | 653 | void UpdateUserStory(MU3.Client.UserStory[] array) 654 | { 655 | string fileName = "UserStory.json"; 656 | if (!FileSystem.Configuration.FileExists(fileName)) 657 | { 658 | GetUserStoryResponse userStory = GetUserStoryResponse.create(); 659 | FileSystem.Configuration.SaveJson(fileName, userStory); 660 | } 661 | 662 | GetUserStoryResponse temporary = FileSystem.Configuration.LoadJson(fileName); 663 | foreach (var item in array) 664 | { 665 | temporary.userStoryList = temporary.userStoryList 666 | .Where(a => a.storyId != item.storyId) 667 | .Concat(new[] { item }) 668 | .ToArray(); 669 | } 670 | temporary.length = temporary.userStoryList.Length; 671 | temporary.userId = Singleton.instance.UserId; 672 | 673 | FileSystem.Configuration.SaveJson(fileName, temporary); 674 | } 675 | 676 | void UpdateUserChapter(MU3.Client.UserChapter[] array) 677 | { 678 | string fileName = "UserChapter.json"; 679 | if (!FileSystem.Configuration.FileExists(fileName)) 680 | { 681 | GetUserChapterResponse userChapter = GetUserChapterResponse.create(); 682 | FileSystem.Configuration.SaveJson(fileName, userChapter); 683 | } 684 | 685 | GetUserChapterResponse temporary = FileSystem.Configuration.LoadJson(fileName); 686 | foreach (var item in array) 687 | { 688 | temporary.userChapterList = temporary.userChapterList 689 | .Where(a => a.chapterId != item.chapterId) 690 | .Concat(new[] { item }) 691 | .ToArray(); 692 | } 693 | temporary.length = temporary.userChapterList.Length; 694 | temporary.userId = Singleton.instance.UserId; 695 | 696 | FileSystem.Configuration.SaveJson(fileName, temporary); 697 | } 698 | 699 | void UpdateUserItem(UserItem[] array) 700 | { 701 | void UpdateForType(string fileName, ItemType itemType) 702 | { 703 | if (!userItemFS.FileExists(fileName)) 704 | { 705 | GetUserItemResponse userItemList = GetUserItemResponse.create(); 706 | userItemFS.SaveJson(fileName, userItemList); 707 | } 708 | 709 | GetUserItemResponse temporary = userItemFS.LoadJson(fileName); 710 | foreach (var item in array.Where(a => a.itemKind == (int)itemType)) 711 | { 712 | temporary.userItemList = temporary.userItemList 713 | .Where(a => a.itemId != item.itemId) 714 | .Concat(new[] { item }) 715 | .ToArray(); 716 | } 717 | 718 | temporary.length = temporary.userItemList.Length; 719 | temporary.itemKind = (int)itemType; 720 | temporary.nextIndex = 0; 721 | temporary.userId = Singleton.instance.UserId; 722 | 723 | userItemFS.SaveJson(fileName, temporary); 724 | } 725 | 726 | UpdateForType("Trophy.json", ItemType.Trophy); 727 | UpdateForType("GachaTicket.json", ItemType.GachaTicket); 728 | UpdateForType("LimitBreakItem.json", ItemType.LimitBreakItem); 729 | UpdateForType("NamePlate.json", ItemType.NamePlate); 730 | UpdateForType("Present.json", ItemType.Present); 731 | UpdateForType("ProfileVoice.json", ItemType.ProfileVoice); 732 | } 733 | 734 | void UpdateUserMusicItem(MU3.Client.UserMusicItem[] array) 735 | { 736 | string fileName = "UserMusicItem.json"; 737 | if (!FileSystem.Configuration.FileExists(fileName)) 738 | { 739 | GetUserMusicItemResponse userMusicItemList = GetUserMusicItemResponse.create(); 740 | FileSystem.Configuration.SaveJson(fileName, userMusicItemList); 741 | } 742 | 743 | GetUserMusicItemResponse temporary = FileSystem.Configuration.LoadJson(fileName); 744 | foreach (var item in array) 745 | { 746 | temporary.userMusicItemList = temporary.userMusicItemList 747 | .Where(a => a.musicId != item.musicId) 748 | .Concat(new[] { item }) 749 | .ToArray(); 750 | } 751 | 752 | temporary.length = temporary.userMusicItemList.Length; 753 | temporary.nextIndex = 0; 754 | temporary.userId = Singleton.instance.UserId; 755 | 756 | FileSystem.Configuration.SaveJson(fileName, temporary); 757 | } 758 | 759 | void UpdateUserMusic(MU3.Client.UserMusicDetail[] array) 760 | { 761 | string fileName = "UserMusic.json"; 762 | if (!FileSystem.Configuration.FileExists(fileName)) 763 | { 764 | GetUserMusicResponse userMusicList = GetUserMusicResponse.create(); 765 | UserMusicDetail userMusicDetail = new UserMusicDetail(); 766 | userMusicList.length = 0; 767 | FileSystem.Configuration.SaveJson(fileName, userMusicList); 768 | } 769 | 770 | GetUserMusicResponse temporary = FileSystem.Configuration.LoadJson(fileName); 771 | foreach (var item in array) 772 | { 773 | bool addedItem = false; 774 | foreach (var userMusic in temporary.userMusicList) { 775 | if (userMusic.length != 0) 776 | { 777 | if (item.musicId == userMusic.userMusicDetailList[0].musicId) 778 | { 779 | userMusic.userMusicDetailList = userMusic.userMusicDetailList 780 | .Where(a => a.level != item.level) 781 | .Concat(new[] { item }) 782 | .ToArray(); 783 | userMusic.length = userMusic.userMusicDetailList.Length; 784 | addedItem = true; 785 | break; 786 | } 787 | } 788 | } 789 | 790 | if (!addedItem) 791 | { 792 | MU3.Client.UserMusic userMusic = new MU3.Client.UserMusic(); 793 | userMusic.userMusicDetailList = userMusic.userMusicDetailList.Add(item).ToArray(); 794 | userMusic.length = userMusic.userMusicDetailList.Length; 795 | temporary.userMusicList = temporary.userMusicList.Add(userMusic).ToArray(); 796 | temporary.length = temporary.userMusicList.Length; 797 | } 798 | } 799 | 800 | temporary.nextIndex = 0; 801 | temporary.userId = Singleton.instance.UserId; 802 | 803 | FileSystem.Configuration.SaveJson(fileName, temporary); 804 | } 805 | 806 | void UpdateUserLoginBonus(MU3.Client.UserLoginBonus[] array) 807 | { 808 | string fileName = "UserLoginBonus.json"; 809 | if (!FileSystem.Configuration.FileExists(fileName)) 810 | { 811 | GetUserLoginBonusResponse userLoginBonus = GetUserLoginBonusResponse.create(); 812 | FileSystem.Configuration.SaveJson(fileName, userLoginBonus); 813 | } 814 | 815 | GetUserLoginBonusResponse temporary = FileSystem.Configuration.LoadJson(fileName); 816 | foreach (var item in array) 817 | { 818 | temporary.userLoginBonusList = temporary.userLoginBonusList 819 | .Where(a => a.bonusId != item.bonusId) 820 | .Concat(new[] { item }) 821 | .ToArray(); 822 | } 823 | temporary.length = temporary.userLoginBonusList.Length; 824 | temporary.userId = Singleton.instance.UserId; 825 | 826 | FileSystem.Configuration.SaveJson(fileName, temporary); 827 | } 828 | 829 | void UpdateUserEventPoint(MU3.Client.UserEventPoint[] array) 830 | { 831 | string fileName = "UserEventPoint.json"; 832 | if (!FileSystem.Configuration.FileExists(fileName)) 833 | { 834 | GetUserEventPointResponse userEventPoint = GetUserEventPointResponse.create(); 835 | FileSystem.Configuration.SaveJson(fileName, userEventPoint); 836 | } 837 | 838 | GetUserEventPointResponse temporary = FileSystem.Configuration.LoadJson(fileName); 839 | foreach (var item in array) 840 | { 841 | temporary.userEventPointList = temporary.userEventPointList 842 | .Where(a => a.eventId != item.eventId) 843 | .Concat(new[] { item }) 844 | .ToArray(); 845 | } 846 | temporary.length = temporary.userEventPointList.Length; 847 | temporary.userId = Singleton.instance.UserId; 848 | 849 | FileSystem.Configuration.SaveJson(fileName, temporary); 850 | } 851 | 852 | void UpdateUserMissionPoint(MU3.Client.UserMissionPoint[] array) 853 | { 854 | string fileName = "UserMissionPoint.json"; 855 | if (!FileSystem.Configuration.FileExists(fileName)) 856 | { 857 | GetUserMissionPointResponse userEventPoint = GetUserMissionPointResponse.create(); 858 | FileSystem.Configuration.SaveJson(fileName, userEventPoint); 859 | } 860 | 861 | GetUserMissionPointResponse temporary = FileSystem.Configuration.LoadJson(fileName); 862 | foreach (var item in array) 863 | { 864 | temporary.userMissionPointList = temporary.userMissionPointList 865 | .Where(a => a.eventId != item.eventId) 866 | .Concat(new[] { item }) 867 | .ToArray(); 868 | } 869 | temporary.length = temporary.userMissionPointList.Length; 870 | temporary.userId = Singleton.instance.UserId; 871 | 872 | FileSystem.Configuration.SaveJson(fileName, temporary); 873 | } 874 | 875 | void UpdateUserRatingLog(MU3.Client.UserRatinglog[] array) 876 | { 877 | string fileName = "UserRatingLog.json"; 878 | if (!FileSystem.Configuration.FileExists(fileName)) 879 | { 880 | GetUserRatinglogResponse userEventPoint = GetUserRatinglogResponse.create(); 881 | FileSystem.Configuration.SaveJson(fileName, userEventPoint); 882 | } 883 | 884 | GetUserRatinglogResponse temporary = FileSystem.Configuration.LoadJson(fileName); 885 | foreach (var item in array) 886 | { 887 | temporary.userRatinglogList = temporary.userRatinglogList 888 | .Where(a => a.highestRating != item.highestRating) 889 | .Concat(new[] { item }) 890 | .ToArray(); 891 | } 892 | temporary.length = temporary.userRatinglogList.Length; 893 | temporary.userId = Singleton.instance.UserId; 894 | 895 | FileSystem.Configuration.SaveJson(fileName, temporary); 896 | } 897 | 898 | 899 | if (query == null) 900 | { 901 | Log.Info("!!!!! No data to save. !!!!!"); 902 | return false; 903 | } 904 | 905 | var upsert = query.request_.upsertUserAll; 906 | 907 | UpdateUserData(upsert.userData); 908 | UpdateUserOption(upsert.userOption); 909 | UpdateUserActivity(); 910 | UpdateUserRecentRating(upsert.userRecentRatingList); 911 | UpdateUserBpBase(upsert.userBpBaseList); 912 | if (!string.IsNullOrEmpty(upsert.isNewMusicDetailList)) UpdateUserMusic(upsert.userMusicDetailList); 913 | if (!string.IsNullOrEmpty(upsert.isNewCharacterList)) UpdateUserCharacter(upsert.userCharacterList); 914 | if (!string.IsNullOrEmpty(upsert.isNewCardList)) UpdateUserCard(upsert.userCardList); 915 | if (!string.IsNullOrEmpty(upsert.isNewDeckList)) UpdateUserDeck(upsert.userDeckList); 916 | if (!string.IsNullOrEmpty(upsert.isNewTrainingRoomList)) UpdateUserTrainingRoom(upsert.userTrainingRoomList); 917 | if (!string.IsNullOrEmpty(upsert.isNewStoryList)) UpdateUserStory(upsert.userStoryList); 918 | if (!string.IsNullOrEmpty(upsert.isNewChapterList)) UpdateUserChapter(upsert.userChapterList); 919 | if (!string.IsNullOrEmpty(upsert.isNewItemList)) UpdateUserItem(upsert.userItemList); 920 | if (!string.IsNullOrEmpty(upsert.isNewMusicItemList)) UpdateUserMusicItem(upsert.userMusicItemList); 921 | if (!string.IsNullOrEmpty(upsert.isNewLoginBonusList)) UpdateUserLoginBonus(upsert.userLoginBonusList); 922 | if (!string.IsNullOrEmpty(upsert.isNewEventPointList)) UpdateUserEventPoint(upsert.userEventPointList); 923 | if (!string.IsNullOrEmpty(upsert.isNewMissionPointList)) UpdateUserMissionPoint(upsert.userMissionPointList); 924 | if (!string.IsNullOrEmpty(upsert.isNewRatinglogList)) UpdateUserRatingLog(upsert.userRatinglogList); 925 | if (UserManager.Exists) 926 | { 927 | Singleton.instance.updateLastRemainedGP(); 928 | } 929 | typeof(PacketUpsertUserAll).GetMethod("clearFlags", (BindingFlags)62).Invoke(__instance, null); 930 | 931 | __result = Packet.State.Done; 932 | (__instance.query as UpsertUserAll).response_ = new UpsertUserAllResponse() 933 | { 934 | returnCode = 1 935 | }; 936 | 937 | return false; 938 | } 939 | } 940 | } 941 | -------------------------------------------------------------------------------- /Components/SequenceInitializePatches.cs: -------------------------------------------------------------------------------- 1 | namespace UnityParrot.Components 2 | { 3 | public class SequenceInitializePatches 4 | { 5 | public static void Patch() 6 | { 7 | Harmony.MakeRET(typeof(MU3.Sequence.Initialize), "Enter_CollabAdvertise"); 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Components/SerialPatches.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | 3 | namespace UnityParrot.Components 4 | { 5 | class SerialPatches 6 | { 7 | public static void Patch() 8 | { 9 | Harmony.PatchAllInType(typeof(SerialPatches)); 10 | } 11 | 12 | [MethodPatch(PatchType.Prefix, typeof(SerialId), "get_Value")] 13 | private static bool GetSerialId(ref string __result) 14 | { 15 | __result = "T3KNOG0DZ"; 16 | 17 | return false; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Components/Settings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using NekoClient.Logging; 6 | using MU3.Util; 7 | 8 | namespace UnityParrot.Components 9 | { 10 | public enum AnalogControlStyle 11 | { 12 | Mouse = 0, 13 | Touchpad = 1, 14 | Buttons = 2 15 | } 16 | 17 | [Serializable] 18 | public class Settings 19 | { 20 | public string ButtonBegin; 21 | public string ButtonService; 22 | public string ButtonPush0; 23 | public string ButtonPush1; 24 | public string ButtonLeftWall; 25 | public string ButtonLeft1; 26 | public string ButtonLeft2; 27 | public string ButtonLeft3; 28 | public string ButtonRight1; 29 | public string ButtonRight2; 30 | public string ButtonRight3; 31 | public string ButtonRightWall; 32 | public string ButtonRightMenu; 33 | public string ButtonLeftMenu; 34 | 35 | public string AnalogControlStyle; 36 | public bool AnalogInvertAxis; 37 | public bool AnalogRotateAxis; 38 | public string AnalogLeftButton; 39 | public string AnalogRightButton; 40 | public float AnalogButtonSensitivity; 41 | 42 | public bool DisplayFullscreen; 43 | 44 | public string AimeButton; 45 | 46 | public bool EnableEvents; 47 | public bool RotatingWeeklyEvents; 48 | public bool RotatingDailyEvents; 49 | public int EventId; 50 | } 51 | 52 | public class SettingsManager : SingletonMonoBehaviour 53 | { 54 | protected Settings settings_; 55 | public Settings settings 56 | { 57 | get { return this.settings_; } 58 | } 59 | 60 | void Start() 61 | { 62 | string fileName = "Settings.json"; 63 | settings_ = new Settings(); 64 | 65 | if (!FileSystem.Configuration.FileExists(fileName)) 66 | { 67 | settings_.ButtonBegin = "f8"; 68 | settings_.ButtonService = "f9"; 69 | settings_.ButtonPush0 = "f10"; 70 | settings_.ButtonPush1 = "f11"; 71 | settings_.ButtonLeftWall = "a"; 72 | settings_.ButtonLeft1 = "s"; 73 | settings_.ButtonLeft2 = "d"; 74 | settings_.ButtonLeft3 = "f"; 75 | settings_.ButtonRight1 = "w"; 76 | settings_.ButtonRight2 = "e"; 77 | settings_.ButtonRight3 = "r"; 78 | settings_.ButtonRightWall = "g"; 79 | settings_.ButtonRightMenu = "t"; 80 | settings_.ButtonLeftMenu = "q"; 81 | 82 | settings_.AnalogControlStyle = AnalogControlStyle.Mouse.ToString(); 83 | settings_.AnalogInvertAxis = false; 84 | settings_.AnalogRotateAxis = false; 85 | settings_.AnalogLeftButton = "left"; 86 | settings_.AnalogRightButton = "right"; 87 | settings_.AnalogButtonSensitivity = 1.5f; 88 | 89 | settings_.DisplayFullscreen = true; 90 | 91 | settings_.AimeButton = "f2"; 92 | 93 | settings_.EnableEvents = false; 94 | settings_.EventId = -1; 95 | settings_.RotatingWeeklyEvents = false; 96 | settings_.RotatingDailyEvents = false; 97 | 98 | FileSystem.Configuration.SaveJson(fileName, settings_); 99 | } 100 | 101 | settings_ = FileSystem.Configuration.LoadJson(fileName); 102 | } 103 | } 104 | 105 | 106 | 107 | 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /Components/SysConfigPatches.cs: -------------------------------------------------------------------------------- 1 | using MU3; 2 | using MU3.Sys; 3 | using System.IO; 4 | using UnityEngine; 5 | 6 | namespace UnityParrot.Components 7 | { 8 | public class SysConfigPatches 9 | { 10 | public static void Patch() 11 | { 12 | Harmony.PatchAllInType(typeof(SysConfigPatches)); 13 | 14 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isPlatformAlls", true); 15 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isDummyJvs", false); 16 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isNewButtonAssign", false); 17 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isRevertAnalog", true); 18 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isInvertWallButtonL", false); 19 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isInvertWallButtonR", false); 20 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isDummyCredit", false); 21 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isDummyAime", false); 22 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isIgnoreError", true); 23 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isUseOptionDev", false); 24 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isWasapiExclusive", false); 25 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isUseNetwork", false); 26 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isUseAllnet", false); 27 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isUseLocalCollab", false); 28 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isForceLogout", false); 29 | // get_serverUri 30 | // get_cameraType 31 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isKeyboardInput", true); 32 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isKeyboardCredit", false); 33 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isKeyboardDebug", false); 34 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isQuickStart", false); 35 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isDispDelay", false); 36 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadNoteTap", true); 37 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadNoteHold", true); 38 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadNoteFlick", true); 39 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadBell", true); 40 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadBullet", true); 41 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadTapLane", true); 42 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadWallLane", true); 43 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadEnemyLane", true); 44 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadField", true); 45 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadOneway", true); 46 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isLoadSoflan", true); 47 | Harmony.MakeRET(typeof(MU3.Sys.Config), "get_isSimpleLane", false); 48 | } 49 | 50 | [MethodPatch(PatchType.Prefix, typeof(MU3.Sys.Config), "get_serverUri")] 51 | static bool ServerUri(ref string __result) 52 | { 53 | __result = string.Empty; 54 | return false; 55 | } 56 | 57 | [MethodPatch(PatchType.Prefix, typeof(MU3.Sys.Config), "get_cameraType")] 58 | static bool CameraType(ref int __result) 59 | { 60 | __result = 1; 61 | return false; 62 | } 63 | 64 | [MethodPatch(PatchType.Prefix, typeof(NetConfig), "get_ClientId")] 65 | static bool ClientId(ref string __result) 66 | { 67 | __result = "JEMOEDER"; 68 | return false; 69 | } 70 | 71 | [MethodPatch(PatchType.Prefix, typeof(MU3.Sys.Path), "get_logPath")] 72 | static bool LogPath(ref string __result) 73 | { 74 | __result = Directory.GetCurrentDirectory(); 75 | return false; 76 | } 77 | 78 | [MethodPatch(PatchType.Prefix, typeof(MU3.SystemUI), "initialize")] 79 | static bool initialize() 80 | { 81 | Screen.fullScreen = SettingsManager.instance.settings.DisplayFullscreen; 82 | return true; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /FileSystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using UnityEngine; 6 | 7 | namespace UnityParrot 8 | { 9 | public class FileSystem 10 | { 11 | private string m_basePath = "UnityParrot"; 12 | 13 | public static FileSystem Configuration = new FileSystem("UnityParrot\\Configuration"); 14 | 15 | public Func Format = null; 16 | 17 | public FileSystem() { } 18 | 19 | public FileSystem(string basePath) 20 | { 21 | m_basePath = basePath; 22 | Directory.CreateDirectory(m_basePath); 23 | } 24 | 25 | public static class Formats 26 | { 27 | public static string TimePrefix(string data) 28 | { 29 | var now = DateTime.Now; 30 | var time = $"{now.Day}/{now.Month}/{now.Year} {now.Hour}:{now.Minute}:{now.Second}"; 31 | return $"{time} >> {data}"; 32 | } 33 | } 34 | 35 | 36 | public T LoadJson(string fileName) 37 | { 38 | return JsonUtility.FromJson(File.ReadAllText($"{m_basePath}\\{fileName}")); 39 | //return JsonConvert.DeserializeObject(File.ReadAllText($"{m_basePath}\\{fileName}")); 40 | } 41 | 42 | public T TryLoadJson(string fileName) 43 | { 44 | if (!FileExists(fileName)) 45 | { 46 | return default(T); 47 | } 48 | 49 | return LoadJson(fileName); 50 | } 51 | 52 | public void SaveJson(string fileName, T data) 53 | { 54 | File.WriteAllText($"{m_basePath}\\{fileName}", JsonUtility.ToJson(data, true)); 55 | //File.WriteAllText($"{m_basePath}\\{fileName}", JsonConvert.SerializeObject(data, Formatting.Indented)); 56 | } 57 | 58 | public string LoadText(string fileName) 59 | { 60 | return File.ReadAllText($"{m_basePath}\\{fileName}"); 61 | } 62 | 63 | public string[] LoadLines(string fileName) 64 | { 65 | return File.ReadAllLines($"{m_basePath}\\{fileName}"); 66 | } 67 | 68 | public void SaveText(string fileName, string data, bool append = false) 69 | { 70 | string dataCopy = data; 71 | 72 | if (Format != null) 73 | { 74 | dataCopy = Format(data); 75 | } 76 | 77 | string path = $"{m_basePath}\\{fileName}"; 78 | 79 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 80 | 81 | if (append) 82 | { 83 | File.AppendAllText(path, dataCopy); 84 | return; 85 | } 86 | 87 | File.WriteAllText(path, dataCopy); 88 | } 89 | 90 | public void SaveText(string fileName, string[] data, bool append = false) 91 | { 92 | string[] dataCopy = data; 93 | 94 | if (Format != null) 95 | { 96 | for (int i = 0; i < dataCopy.Length; i++) 97 | { 98 | dataCopy[i] = Format(data[i]); 99 | } 100 | } 101 | 102 | string path = $"{m_basePath}\\{fileName}"; 103 | 104 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 105 | 106 | if (append) 107 | { 108 | File.AppendAllText(path, string.Join("\n", dataCopy)); 109 | return; 110 | } 111 | 112 | File.WriteAllLines(path, dataCopy); 113 | } 114 | 115 | public void SaveText(string fileName, IEnumerable data, bool append = false) 116 | { 117 | SaveText($"{m_basePath}\\{fileName}", data.ToArray(), append); 118 | } 119 | 120 | public bool FileExists(string fileName) 121 | { 122 | return File.Exists($"{m_basePath}\\{fileName}"); 123 | } 124 | 125 | public string GetFilePath(string fileName) 126 | { 127 | return $"{m_basePath}\\{fileName}"; 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /Harmony.cs: -------------------------------------------------------------------------------- 1 | using Harmony; 2 | using MU3.Battle; 3 | using NekoClient.Logging; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Reflection; 9 | using System.Text; 10 | using UnityEngine; 11 | using Debug = UnityEngine.Debug; 12 | 13 | namespace UnityParrot 14 | { 15 | public enum PatchType 16 | { 17 | Prefix, 18 | Postfix, 19 | Transpiler 20 | }; 21 | 22 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] 23 | public class MethodPatchAttribute : Attribute 24 | { 25 | public Type TargetType; 26 | public string TargetMethod; 27 | public PatchType PatchType; 28 | 29 | public MethodPatchAttribute(PatchType patchType, Type targetType, string targetMethod) 30 | { 31 | PatchType = patchType; 32 | TargetType = targetType; 33 | TargetMethod = targetMethod; 34 | } 35 | } 36 | 37 | public static class Harmony 38 | { 39 | private static readonly HarmonyInstance ms_harmony; 40 | 41 | public static HarmonyInstance Instance 42 | => ms_harmony; 43 | 44 | public static HarmonyMethod GetPatch(string name, Type type, BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic) 45 | => new HarmonyMethod(type.GetMethod(name, flags) 46 | ?? type.GetProperties().FirstOrDefault((PropertyInfo p) => p.GetGetMethod().Name == name)?.GetGetMethod()); 47 | 48 | 49 | public static void PatchAllInType(Type targetType) 50 | { 51 | var methods = targetType.GetMethods((BindingFlags)62); 52 | 53 | foreach (var m in methods) 54 | { 55 | var attrs = m.GetCustomAttributes(typeof(MethodPatchAttribute), true); 56 | 57 | if (attrs.Length > 0) 58 | { 59 | foreach (var attr in attrs) 60 | { 61 | MethodPatchAttribute a = (MethodPatchAttribute)attr; 62 | 63 | HarmonyMethod harmonyMethod = GetPatch(m.Name, targetType); 64 | 65 | PerformPatch($"{targetType.Name} # {a.TargetMethod} ({m.Name})", 66 | a.TargetType.GetMethod(a.TargetMethod, (BindingFlags)62), 67 | a.PatchType == PatchType.Prefix ? harmonyMethod : null, 68 | a.PatchType == PatchType.Postfix ? harmonyMethod : null, 69 | a.PatchType == PatchType.Transpiler ? harmonyMethod : null); 70 | } 71 | } 72 | } 73 | } 74 | 75 | public static void PerformPatch(string patchName, MethodBase original, HarmonyMethod prefix = null, HarmonyMethod postfix = null, HarmonyMethod transpiler = null) 76 | { 77 | string logMessage = $"Performing {patchName} patch... "; 78 | 79 | try 80 | { 81 | if (original == null) 82 | { 83 | logMessage += "failed! method does not exist! \t\t\t!!!!!"; 84 | } 85 | else 86 | { 87 | ms_harmony.Patch(original, prefix, postfix, transpiler); 88 | logMessage += "succeeded!"; 89 | } 90 | } 91 | catch (Exception e) 92 | { 93 | logMessage += $"failed! (Exception: {e.Message})"; 94 | } 95 | 96 | Log.Info(logMessage); 97 | } 98 | 99 | 100 | public static void MakeRET(Type targetType, string methodName, bool retVal = false, Type[] methodTypes = null) 101 | { 102 | MethodInfo meth = default; 103 | 104 | if (methodTypes != null) 105 | { 106 | meth = targetType.GetMethod(methodName, (BindingFlags)62, null, methodTypes, null); 107 | } 108 | else 109 | { 110 | meth = targetType.GetMethod(methodName, (BindingFlags)62); 111 | } 112 | 113 | var ret = meth.ReturnType; 114 | 115 | if (ret == typeof(void)) 116 | { 117 | PerformPatch($"MakeRET {targetType.Name} # {methodName}", meth, GetPatch("DontContinue", typeof(Harmony))); 118 | } 119 | else if (ret == typeof(bool)) 120 | { 121 | PerformPatch($"MakeRET {targetType.Name} # {methodName}", meth, GetPatch(retVal ? "ReturnTrue" : "ReturnFalse", typeof(Harmony))); 122 | } 123 | else 124 | { 125 | Log.Info($"MakeRET not supported for type: {ret.FullName}"); 126 | } 127 | } 128 | 129 | 130 | static bool ReturnFalse(ref bool __result) 131 | { 132 | __result = false; 133 | return false; 134 | } 135 | 136 | static bool ReturnTrue(ref bool __result) 137 | { 138 | __result = true; 139 | return false; 140 | } 141 | 142 | static bool DontContinue() 143 | { 144 | return false; 145 | } 146 | 147 | 148 | static Harmony() 149 | { 150 | ms_harmony = HarmonyInstance.Create("UnityParrot.ONGEKI.Patches"); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Logging/ConsoleLogListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NekoClient.Logging 4 | { 5 | public class ConsoleLogListener : ILogListener 6 | { 7 | public void LogMessage(string source, string message, LogLevel level) 8 | { 9 | string levelS = level.ToString().ToUpper(); 10 | string sourceS = (source == string.Empty) ? string.Empty : ("[" + source + "]"); 11 | 12 | string text = string.Format("{0} - {2}", sourceS, levelS, message); 13 | Console.WriteLine(text); 14 | } 15 | 16 | public bool WantsFilteredMessages { get { return true; } } 17 | } 18 | } -------------------------------------------------------------------------------- /Logging/FileLogListener.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.IO; 4 | 5 | namespace NekoClient.Logging 6 | { 7 | public class FileLogListener : ILogListener 8 | { 9 | private StreamWriter _writer; 10 | 11 | public FileLogListener(string filename, bool append) 12 | { 13 | try 14 | { 15 | _writer = new StreamWriter(filename, append); 16 | } 17 | catch (IOException) 18 | { 19 | _writer = null; 20 | } 21 | } 22 | 23 | public void LogMessage(string source, string message, LogLevel level) 24 | { 25 | if (_writer == null) 26 | { 27 | return; 28 | } 29 | 30 | string date = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); 31 | string levelS = level.ToString().ToUpper(); 32 | string sourceS = (source == string.Empty) ? string.Empty : ("[" + source + "]"); 33 | 34 | //string text = string.Format("{0} - {1} - {2}: {3}", date, sourceS, levelS, message); 35 | string text = string.Format("{0} - {2}: {3}", date, sourceS, levelS, message); 36 | _writer.WriteLine(text); 37 | _writer.Flush(); 38 | } 39 | 40 | public bool WantsFilteredMessages { get { return true; } } 41 | } 42 | } -------------------------------------------------------------------------------- /Logging/GameLogListener.cs: -------------------------------------------------------------------------------- 1 | namespace NekoClient.Logging 2 | { 3 | public class GameLogListener : ILogListener 4 | { 5 | public void LogMessage(string source, string message, LogLevel level) 6 | { 7 | UnityEngine.Debug.Log($"[{source}:{level.ToString()}] {message}"); 8 | } 9 | 10 | public bool WantsFilteredMessages { get { return true; } } 11 | } 12 | } -------------------------------------------------------------------------------- /Logging/ILogListener.cs: -------------------------------------------------------------------------------- 1 | namespace NekoClient.Logging 2 | { 3 | public interface ILogListener 4 | { 5 | void LogMessage(string source, string message, LogLevel level); 6 | 7 | bool WantsFilteredMessages { get; } 8 | } 9 | } -------------------------------------------------------------------------------- /Logging/Log.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Reflection; 5 | 6 | namespace NekoClient.Logging 7 | { 8 | public static class Log 9 | { 10 | private static List _listeners; 11 | private static LogLevel _filter; 12 | 13 | public static void Initialize(LogLevel filter) 14 | { 15 | _listeners = new List(); 16 | _filter = filter; 17 | } 18 | 19 | public static void AddListener(ILogListener listener) 20 | { 21 | _listeners.Add(listener); 22 | } 23 | 24 | public static void Write(LogLevel level, string message, params object[] args) 25 | { 26 | Write(level, string.Format(message, args)); 27 | } 28 | 29 | public static void Write(LogLevel level, string message) 30 | { 31 | // get the source 32 | string source = GetSource(); 33 | 34 | // check filteredness 35 | bool isAllowed = IsLevelAllowed(level); 36 | 37 | // and, well, what do we do next? transmit it to all the listeners? 38 | foreach (ILogListener listener in _listeners) 39 | { 40 | if (!listener.WantsFilteredMessages || isAllowed) 41 | { 42 | listener.LogMessage(source, message, level); 43 | } 44 | } 45 | } 46 | 47 | public static void Debug(string message) 48 | { 49 | Write(LogLevel.Debug, message); 50 | } 51 | 52 | public static void Debug(string format, params object[] args) 53 | { 54 | Debug(String.Format(format, args)); 55 | } 56 | 57 | public static void Info(string message) 58 | { 59 | Write(LogLevel.Info, message); 60 | } 61 | 62 | public static void Info(string format, params object[] args) 63 | { 64 | Info(String.Format(format, args)); 65 | } 66 | 67 | public static void Error(string message) 68 | { 69 | Write(LogLevel.Error, message); 70 | } 71 | 72 | public static void Error(Exception e) 73 | { 74 | Error(e.ToString()); 75 | } 76 | 77 | public static void Error(string format, params object[] args) 78 | { 79 | Error(String.Format(format, args)); 80 | } 81 | 82 | private static bool IsLevelAllowed(LogLevel level) 83 | { 84 | return (_filter & level) == level; 85 | } 86 | 87 | private static string GetSource() 88 | { 89 | // skip 2 frames: GetSource and its caller 90 | StackTrace trace = new StackTrace(2); 91 | StackFrame[] frames = trace.GetFrames(); 92 | 93 | // might not need a foreach, but doing to to be sure 94 | foreach (StackFrame frame in frames) 95 | { 96 | MethodBase method = frame.GetMethod(); 97 | Type type = method.DeclaringType; 98 | 99 | Assembly assembly = type.Assembly; 100 | 101 | // only remove System? 102 | if (assembly.GetName().Name == "System") 103 | { 104 | continue; 105 | } 106 | 107 | // in case there are > 2 frames 108 | if (type.Name == "Log") 109 | { 110 | continue; 111 | } 112 | 113 | string method_t = method.Name; 114 | if (method_t == ".ctor") method_t = type.Name; // contructor 115 | 116 | method_t = method_t.Replace("<", "").Replace(">g__", "::").Split('|')[0]; // clean up nested funcs 117 | 118 | // that sounds just about nice 119 | return string.Format("{0}::{1}", type.Name, method_t); 120 | } 121 | 122 | return ""; 123 | } 124 | } 125 | } -------------------------------------------------------------------------------- /Logging/LogLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NekoClient.Logging 4 | { 5 | [Flags] 6 | public enum LogLevel 7 | { 8 | None = 0, 9 | Trace = 1, 10 | Debug = 2, 11 | Info = 4, 12 | Warning = 8, 13 | Error = 16, 14 | Critical = 32, 15 | All = 63 16 | } 17 | } -------------------------------------------------------------------------------- /Logging/TraceLogListener.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace NekoClient.Logging 4 | { 5 | public class TraceLogListener : ILogListener 6 | { 7 | public void LogMessage(string source, string message, LogLevel level) 8 | { 9 | Trace.WriteLine("[" + source + "] " + message); 10 | } 11 | 12 | public bool WantsFilteredMessages { get { return false; } } 13 | } 14 | } -------------------------------------------------------------------------------- /Main.cs: -------------------------------------------------------------------------------- 1 | using AMDaemon; 2 | using NekoClient.Logging; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Threading; 8 | using UnityEngine; 9 | 10 | namespace UnityParrot 11 | { 12 | class Main 13 | { 14 | static void InitPatches() 15 | { 16 | Components.OperationManagerPatches.Patch(); 17 | 18 | Components.InitAimePatches.Patch(); 19 | Components.AimeUnitPatches.Patch(); 20 | Components.AimeResultPatches.Patch(); 21 | Components.AccessCodePatches.Patch(); 22 | Components.AimeIdPatches.Patch(); 23 | 24 | Components.AMDaemonPatches.Patch(); 25 | Components.AMManagerPatches.Patch(); 26 | Components.BackupSettingPatches.Patch(); 27 | Components.BookkeepPatches.Patch(); 28 | Components.CreditPatches.Patch(); 29 | Components.JvsPatches.Patch(); 30 | Components.SequenceInitializePatches.Patch(); 31 | Components.SerialPatches.Patch(); 32 | Components.SysConfigPatches.Patch(); 33 | } 34 | 35 | public static void Initialize() 36 | { 37 | Log.Initialize(LogLevel.All); 38 | Log.AddListener(new ConsoleLogListener()); 39 | Log.AddListener(new TraceLogListener()); 40 | Log.AddListener(new FileLogListener(FileSystem.Configuration.GetFilePath("..\\UnityParrot.log"), true)); 41 | 42 | InitPatches(); 43 | 44 | new Thread(() => 45 | { 46 | Thread.Sleep(500); 47 | 48 | GameObject mainObject = new GameObject(); 49 | 50 | mainObject.AddComponent(); 51 | mainObject.AddComponent(); 52 | mainObject.AddComponent(); 53 | 54 | UnityEngine.Object.DontDestroyOnLoad(mainObject); 55 | 56 | }).Start(); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /UnityParrot.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net3.5 5 | portable 6 | UnityParrot 7 | 8 | 9 | 10 | 11 | 12 | 13 | ..\package\mu3_Data\Managed\Assembly-CSharp.dll 14 | 15 | 16 | 17 | ..\package\mu3_Data\Managed\AMDaemon.NET.dll 18 | 19 | 20 | 21 | ..\package\mu3_Data\Managed\Assembly-CSharp-firstpass.dll 22 | 23 | 24 | 25 | ..\package\mu3_Data\Managed\UnityEngine.dll 26 | 27 | 28 | 29 | --------------------------------------------------------------------------------