Beispiel #1
0
 public void TestBasicRoundTrip()
 {
     using (Apk apk = new Apk(baseAPKPath)) {
         byte[] data = apk.ReadEntireEntry("assets/bin/Data/3eb70b9e20363dd488f8c4841d7db87f");
         TestRoundTrips(data, "basic");
     }
 }
Beispiel #2
0
        static void Install(
            Apk apk,
            SerializedAssets assets,
            HashSet <string> toInstall,
            InvocationResult res,
            Dictionary <string, string> levels
            )
        {
            foreach (string levelID in toInstall)
            {
                string levelFolder = levels[levelID];
                try {
                    JsonLevel level = JsonLevel.LoadFromFolder(levelFolder);
                    // We use transactions here so if these throw
                    // an exception, which happens when levels are
                    // invalid, then it doesn't modify the APK in
                    // any way that might screw things up later.
                    var      assetsTxn = new SerializedAssets.Transaction(assets);
                    var      apkTxn    = new Apk.Transaction();
                    AssetPtr levelPtr  = level.AddToAssets(assetsTxn, apkTxn, levelID);

                    // Danger should be over, nothing here should fail
                    assetsTxn.ApplyTo(assets);
                    apkTxn.ApplyTo(apk);
                    res.installedLevels.Add(levelID);
                } catch (FileNotFoundException e) {
                    res.installSkipped.Add(levelID, $"Missing file referenced by level: {e.FileName}");
                } catch (JsonReaderException e) {
                    res.installSkipped.Add(levelID, $"Invalid level JSON: {e.Message}");
                }
            }
        }
        public RenamerWindow(Apk apk)
        {
            InitializeComponent();

            this.apk    = apk;
            this.config = new Config();
        }
Beispiel #4
0
        public void TestLoadBeatmap()
        {
            using (Apk apk = new Apk(baseAPKPath)) {
                byte[]                       data    = apk.ReadEntireEntry(Apk.MainAssetsFile);
                SerializedAssets             assets  = SerializedAssets.FromBytes(data);
                SerializedAssets.AssetObject obj     = assets.objects[62];
                MonoBehaviorAssetData        monob   = (MonoBehaviorAssetData)obj.data;
                BeatmapDataBehaviorData      beatmap = (BeatmapDataBehaviorData)monob.data;

                using (Stream fileStream = new FileStream(repoPath("testoutput/beatmap_deflated.bin"), FileMode.Create)) {
                    using (MemoryStream memoryStream = new MemoryStream(beatmap.projectedData)) {
                        using (DeflateStream ds = new DeflateStream(memoryStream, CompressionMode.Decompress)) {
                            ds.CopyTo(fileStream);
                        }
                    }
                }


                BeatmapSaveData saveData = BeatmapSaveData.DeserializeFromBinary(beatmap.projectedData);
                Assert.NotEmpty(saveData._notes);
                byte[] outData = saveData.SerializeToBinary(false);
                File.WriteAllBytes(repoPath("testoutput/beatmap_roundtrip.bin"), outData);

                BeatmapSaveData saveData2 = BeatmapSaveData.DeserializeFromBinary(outData, false);
                Assert.NotEmpty(saveData._notes);
                byte[] outData2 = saveData.SerializeToBinary(false);
                File.WriteAllBytes(repoPath("testoutput/beatmap_roundtrip2.bin"), outData);
            }
        }
Beispiel #5
0
        private async void TxtPath_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!(sender is TextBox tb))
            {
                return;
            }

            txtLabel.Text      = ". . . .";
            txtLabel.ToolTip   = null;
            txtPackage.Text    = ". . . .";
            txtPackage.ToolTip = null;
            txtVersion.Text    = ". . . .";
            txtVersion.ToolTip = null;
            txtAbi.Text        = ". . . .";
            txtAbi.ToolTip     = null;
            txtSdk.Text        = ". . . .";
            imgIcon.Source     = App.GetPlaystoreImageFromResources();
            gbAction.IsEnabled = false;

            if (string.IsNullOrWhiteSpace(tb.Text))
            {
                return;
            }
            if (loadedApk == null || loadedApk.FilePath != tb.Text)
            {
                ShowLoading();

                var aapt = await Aapt.DumbBadging(tb.Text);

                if (aapt.Success)
                {
                    loadedApk = aapt.Apk;

                    txtLabel.Text    = loadedApk.Label;
                    txtLabel.ToolTip = txtLabel.Text;

                    txtPackage.Text    = loadedApk.PackageName;
                    txtPackage.ToolTip = txtPackage.Text;

                    txtVersion.Text    = string.Format("{0} ( {1} )", loadedApk.VersionName, loadedApk.VersionCode);
                    txtVersion.ToolTip = txtVersion.Text;

                    txtAbi.Text    = loadedApk.AbiList;
                    txtAbi.ToolTip = txtAbi.Text;

                    txtSdk.Text = loadedApk.SdkVersion.ToString();

                    imgIcon.Source     = loadedApk.Icon;
                    gbAction.IsEnabled = true;
                }
                // file corrupt or error
                else
                {
                    txtLabel.Text   = "file corrupt?";
                    txtPackage.Text = "not an apk file? unusual file path?";
                }

                ShowLoading(false);
            }
        }
Beispiel #6
0
        private async Task Run()
        {
            GoogleCredential creds;

            using (var stream = new FileStream(_credsFilePath, FileMode.Open))
            {
                creds = GoogleCredential.FromStream(stream).CreateScoped(
                    AndroidPublisherService.Scope.Androidpublisher);
            }

            var service = new AndroidPublisherService(new BaseClientService.Initializer
            {
                HttpClientInitializer = creds
            });

            var editRequest = service.Edits.Insert(null, Package);
            var edit        = await editRequest.ExecuteAsync();

            Console.WriteLine("Created edit with id {0}.", edit.Id);

            Apk apk = null;

            using (var stream = new FileStream(_apkFilePath, FileMode.Open))
            {
                var uploadMedia = service.Edits.Apks.Upload(Package, edit.Id, stream,
                                                            "application/vnd.android.package-archive");

                var progress = await uploadMedia.UploadAsync();

                if (progress.Status == Google.Apis.Upload.UploadStatus.Completed)
                {
                    apk = uploadMedia.ResponseBody;
                }
                else
                {
                    throw new Exception("Upload failed.");
                }
            }

            Console.WriteLine("Version code {0} has been uploaded.", apk.VersionCode);

            var trackRequest = service.Edits.Tracks.Update(new Track
            {
                VersionCodes = new List <int?> {
                    apk.VersionCode
                }
            }, Package, edit.Id, _track);

            var updatedTrack = await trackRequest.ExecuteAsync();

            Console.WriteLine("Track {0} has been updated.", updatedTrack.TrackValue);

            var commitRequest = service.Edits.Commit(Package, edit.Id);
            var commitEdit    = await commitRequest.ExecuteAsync();

            Console.WriteLine("App edit with id {0} has been comitted.", commitEdit.Id);
        }
Beispiel #7
0
        void UploadMedia_ResponseReceived(Apk obj)
        {
            _versionCode = obj.VersionCode.Value;
            Logger.WrightLog("Upload: version code: " + _versionCode);

            if (uploadType == UploadType.library)
            {
                Logger.WrightLog("Upload finished. Find it in Console artifact library");
                return;
            }
            UpdateTrack(uploadType.ToString().ToLower());
        }
Beispiel #8
0
        private void BuildCommand_Execute()
        {
            if (Apk == null)
            {
                return;
            }

            if (!Apk.HasJava())
            {
                MessBox.ShowDial(StringResources.JavaNotFoundError, StringResources.ErrorLower);
                return;
            }

            ClearVisLog();

            bool success = false;
            var  errors  = new List <Error>();

            LoadingWindow.ShowWindow(
                beforeStarting: () => IsBusy     = true,
                threadActions: source => success = Apk.Compile(out errors),
                finishActions: () =>
            {
                IsBusy = false;

                VisLog(LogLine);
                VisLog(success ? StringResources.Finished : StringResources.ErrorWhileCompiling);
                VisLog(LogLine);

                if (GlobalVariables.AppSettings.ShowNotifications)
                {
                    NotificationService.Instance.ShowMessage(StringResources.CompilationFinished);
                }

                if (!success && errors.Any(error => error.Type != Error.ErrorType.None))
                {
                    if (MessBox.ShowDial("Обнаружены ошибки. Попробовать исправить?", "", MessBox.MessageButtons.Yes, MessBox.MessageButtons.No) == MessBox.MessageButtons.Yes)
                    {
                        Apktools.FixErrors(errors);
                        BuildCommand_Execute();
                    }
                }
                else
                {
                    VisLog(StringResources.FileIsSituatedIn + " " + Apk.NewApk);
                }

                RaiseCommandsCanExecute();
            },
                cancelVisibility: Visibility.Collapsed,
                ownerWindow: _window
                );
        }
Beispiel #9
0
 public void TestTextReplaceRoundTrip()
 {
     using (Apk apk = new Apk(baseAPKPath)) {
         byte[]           data       = apk.ReadEntireEntry(apk.TextFile());
         SerializedAssets textAssets = SerializedAssets.FromBytes(data, apk.version);
         var           aotext        = textAssets.GetAssetAt(1);
         TextAssetData ta            = aotext.data as TextAssetData;
         string        oldScript     = ta.script;
         var           segments      = ta.ReadLocaleText();
         ta.WriteLocaleText(segments);
         Assert.Equal(oldScript, ta.script);
     }
 }
Beispiel #10
0
        public async Task <bool> LaunchActivity(string device, Apk apk)
        {
            try
            {
                var result = await RunAsync("-s {0} shell am start -n \"{1}/{2}\" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER", device, apk.PackageName, apk.LaunchableActivity);

                return(result.ToLower().Contains("error"));
            }
            catch (Exception e)
            {
                Debug.Print("Adb.LunchActivity: {0}", e.Message);
                return(false);
            }
        }
Beispiel #11
0
        static void UpdateColors(Apk apk, CustomColors colors, InvocationResult res)
        {
            SerializedAssets colorAssets = SerializedAssets.FromBytes(
                apk.ReadEntireEntry(apk.ColorsFile()), apk.version);
            // There should only be one color manager
            var colorManager = colorAssets.FindScript <ColorManager>(cm => true);

            colorManager.UpdateColor(colorAssets, colors.colorA, ColorManager.ColorSide.A);
            colorManager.UpdateColor(colorAssets, colors.colorB, ColorManager.ColorSide.B);
            apk.ReplaceAssetsFile(apk.ColorsFile(), colorAssets.ToBytes());
            res.newColors = new CustomColors()
            {
                colorA = colorManager.colorA.FollowToScript <SimpleColor>(colorAssets),
                colorB = colorManager.colorB.FollowToScript <SimpleColor>(colorAssets),
            };
        }
Beispiel #12
0
        private void SignCommand_Execute()
        {
            if (Apk?.NewApk == null)
            {
                return;
            }

            if (!Apk.HasJava())
            {
                MessBox.ShowDial(StringResources.JavaNotFoundError, StringResources.ErrorLower);
                return;
            }

            bool success = false;

            LoadingWindow.ShowWindow(
                beforeStarting: () => IsBusy     = true,
                threadActions: source => success = Apk.Sign(),
                finishActions: () =>
            {
                IsBusy = false;

                VisLog(LogLine);
                VisLog(success ? StringResources.Finished : StringResources.ErrorWhileSigning);

                if (success)
                {
                    string message = $"{StringResources.FileIsSituatedIn} {Apk.SignedApk}";

                    VisLog(message);

                    string dir = Path.GetDirectoryName(Apk.SignedApk);

                    if (dir != null && MessBox.ShowDial(message, StringResources.Finished, MessBox.MessageButtons.OK, StringResources.Open) == StringResources.Open)
                    {
                        Process.Start(dir);
                    }
                }
            },
                cancelVisibility: Visibility.Collapsed,
                ownerWindow: _window
                );

            VisLog(string.Format("{0}{1}Signing...{1}{0}", LogLine, Environment.NewLine));
        }
Beispiel #13
0
        static void EnsureInstalled(
            Apk apk,
            SerializedAssets assets,
            HashSet <string> existingLevels,
            InvocationResult res,
            Dictionary <string, string> ensureInstalled
            )
        {
            LevelCollectionBehaviorData extrasCollection = assets.FindExtrasLevelCollection();

            foreach (KeyValuePair <string, string> entry in ensureInstalled)
            {
                string levelID     = entry.Key;
                string levelFolder = entry.Value;
                try {
                    JsonLevel level = JsonLevel.LoadFromFolder(levelFolder);
                    if (existingLevels.Contains(levelID))
                    {
                        res.installSkipped.Add(levelID, "Present");
                    }
                    else
                    {
                        // We use transactions here so if these throw
                        // an exception, which happens when levels are
                        // invalid, then it doesn't modify the APK in
                        // any way that might screw things up later.
                        var      assetsTxn = new SerializedAssets.Transaction(assets);
                        var      apkTxn    = new Apk.Transaction();
                        AssetPtr levelPtr  = level.AddToAssets(assetsTxn, apkTxn, levelID);

                        // Danger should be over, nothing here should fail
                        assetsTxn.ApplyTo(assets);
                        extrasCollection.levels.Add(levelPtr);
                        apkTxn.ApplyTo(apk);

                        existingLevels.Add(levelID);
                        res.installedLevels.Add(levelID);
                    }
                } catch (FileNotFoundException e) {
                    res.installSkipped.Add(levelID, $"Missing file referenced by level: {e.FileName}");
                } catch (JsonReaderException e) {
                    res.installSkipped.Add(levelID, $"Invalid level JSON: {e.Message}");
                }
            }
        }
Beispiel #14
0
        static InvocationResult RunInvocation(Invocation inv)
        {
            InvocationResult res = new InvocationResult();

            try {
                using (Apk apk = new Apk(inv.apkPath)) {
                    if (inv.patchSignatureCheck)
                    {
                        apk.PatchSignatureCheck();
                        res.didSignatureCheckPatch = true;
                    }

                    SerializedAssets mainAssets = SerializedAssets.FromBytes(
                        apk.ReadEntireEntry(apk.MainAssetsFile()), apk.version
                        );

                    SyncLevels(apk, mainAssets, inv, res);

                    apk.ReplaceAssetsFile(apk.MainAssetsFile(), mainAssets.ToBytes());

                    if (inv.colors != null)
                    {
                        UpdateColors(apk, inv.colors, res);
                    }

                    if (inv.replaceText != null)
                    {
                        UpdateText(apk, inv.replaceText, res);
                    }

                    apk.Save();
                }

                if (inv.sign)
                {
                    Signer.Sign(inv.apkPath);
                    res.didSign = true;
                }
            } catch (Exception e) {
                res.error = e.ToString();
            }

            return(res);
        }
Beispiel #15
0
        public void TestBigFile()
        {
            using (Apk apk = new Apk(baseAPKPath)) {
                byte[] data   = apk.ReadEntireEntry(Apk.MainAssetsFile);
                var    assets = TestRoundTrips(data, "big");

                var existing = assets.ExistingLevelIDs();
                Assert.NotEmpty(existing);
                Assert.False(existing.Contains("BUBBLETEA"), "Run tests on a non-patched APK");

                JsonLevel level = JsonLevel.LoadFromFolder(repoPath("testdata/bubble_tea_song/"));
                // pass null as the apk so it doesn't get modified
                AssetPtr levelPtr = level.AddToAssets(assets, null);

                LevelCollectionBehaviorData extrasCollection = assets.FindExtrasLevelCollection();
                extrasCollection.levels.Add(levelPtr);
                byte[] outData = assets.ToBytes();
                File.WriteAllBytes($"../../../../testoutput/bubble_tea_mod.asset", outData);
            }
        }
Beispiel #16
0
        static InvocationResult RunInvocation(Invocation inv)
        {
            InvocationResult res = new InvocationResult();

            try {
                using (Apk apk = new Apk(inv.apkPath)) {
                    if (inv.patchSignatureCheck)
                    {
                        apk.PatchSignatureCheck();
                        res.didSignatureCheckPatch = true;
                    }

                    byte[]           data           = apk.ReadEntireEntry(apk.MainAssetsFile());
                    SerializedAssets assets         = SerializedAssets.FromBytes(data, apk.version);
                    HashSet <string> existingLevels = assets.ExistingLevelIDs();

                    if (inv.ensureInstalled.Count > 0)
                    {
                        Program.EnsureInstalled(apk, assets, existingLevels, res, inv.ensureInstalled);

                        byte[] outData = assets.ToBytes();
                        apk.ReplaceAssetsFile(apk.MainAssetsFile(), outData);
                    }

                    res.presentLevels = existingLevels.ToList();

                    apk.Save();
                }

                if (inv.sign)
                {
                    Signer.Sign(inv.apkPath);
                    res.didSign = true;
                }
            } catch (Exception e) {
                res.error = e.ToString();
            }

            return(res);
        }
Beispiel #17
0
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("arguments: pathToAPKFileToModify levelFolders...");
                return;
            }
            string apkPath = args[0];

            using (Apk apk = new Apk(apkPath)) {
                apk.PatchSignatureCheck();

                byte[]           data   = apk.ReadEntireEntry(Apk.MainAssetsFile);
                SerializedAssets assets = SerializedAssets.FromBytes(data);

                HashSet <string>            existingLevels   = assets.ExistingLevelIDs();
                LevelCollectionBehaviorData extrasCollection = assets.FindExtrasLevelCollection();
                for (int i = 1; i < args.Length; i++)
                {
                    Utils.FindLevels(args[i], levelFolder => {
                        JsonLevel level = JsonLevel.LoadFromFolder(levelFolder);
                        string levelID  = level.LevelID();
                        if (existingLevels.Contains(levelID))
                        {
                            Console.WriteLine($"Present: {level._songName}");
                        }
                        else
                        {
                            Console.WriteLine($"Adding:  {level._songName}");
                            AssetPtr levelPtr = level.AddToAssets(assets, apk);
                            extrasCollection.levels.Add(levelPtr);
                            existingLevels.Add(levelID);
                        }
                    });
                }

                byte[] outData = assets.ToBytes();
                apk.ReplaceAssetsFile(Apk.MainAssetsFile, outData);
            }
        }
Beispiel #18
0
        private void UploadObbFiles(AndroidPublisherService service, AppEdit edit, Apk apk,
                                    IAndroidDistributionSettings configs, string[] obbs)
        {
            foreach (var obbPath in obbs)
            {
                var upload = service.Edits.Expansionfiles.Upload(
                    configs.PackageName,
                    edit.Id,
                    apk.VersionCode.Value,
                    EditsResource.ExpansionfilesResource.UploadMediaUpload.ExpansionFileTypeEnum.Main,
                    new FileStream(obbPath, FileMode.Open),
                    "application/octet-stream"
                    );
                Debug.Log($"Starting Uploading Obb:{obbPath}");
                upload.ResponseReceived += response =>
                {
                    if (response == null)
                    {
                        throw new Exception("Failed Upload " + obbPath);
                    }
                    else
                    {
                        Debug.Log("Success Upload " + obbPath);
                    }
                };
                var result = upload.Upload();
                if (result.Exception != null)
                {
                    throw new Exception("Error: " + result.Exception.Message);
                }

                if (result.Status != UploadStatus.Completed)
                {
                    throw new Exception("Obb not uploaded");
                }
                Debug.Log($"Finish Uploading Obb:{obbPath}");
            }
        }
Beispiel #19
0
        static void UpdateText(Apk apk, Dictionary <string, string> replaceText, InvocationResult res)
        {
            SerializedAssets textAssets = SerializedAssets.FromBytes(apk.ReadEntireEntry(apk.TextFile()), apk.version);
            var           aotext        = textAssets.GetAssetAt(1);
            TextAssetData ta            = aotext.data as TextAssetData;
            var           segments      = ta.ReadLocaleText();

            TextAssetData.ApplyWatermark(segments);

            foreach (var entry in replaceText)
            {
                Dictionary <string, string> value;
                if (!segments.TryGetValue(entry.Key, out value))
                {
                    continue;
                }
                value["ENGLISH"] = entry.Value;
            }

            ta.WriteLocaleText(segments);
            apk.ReplaceAssetsFile(apk.TextFile(), textAssets.ToBytes());
            res.didReplaceText = true;
        }
Beispiel #20
0
        public void TestBigFile()
        {
            using (Apk apk = new Apk(baseAPKPath)) {
                byte[] data   = apk.ReadEntireEntry(Apk.MainAssetsFile);
                var    assets = TestRoundTrips(data, "big");

                var existing = assets.ExistingLevelIDs();
                Assert.NotEmpty(existing);
                Assert.False(existing.Contains("BUBBLETEA"), "Run tests on a non-patched APK");

                JsonLevel level = JsonLevel.LoadFromFolder(repoPath("testdata/bubble_tea_song/"));

                var      assetsTxn = new SerializedAssets.Transaction(assets);
                var      apkTxn    = new Apk.Transaction();
                AssetPtr levelPtr  = level.AddToAssets(assetsTxn, apkTxn, level.GenerateBasicLevelID());
                assetsTxn.ApplyTo(assets);
                // don't apply apkTxn so our tests don't modify the APK

                LevelCollectionBehaviorData extrasCollection = assets.FindExtrasLevelCollection();
                extrasCollection.levels.Add(levelPtr);
                byte[] outData = assets.ToBytes();
                File.WriteAllBytes($"../../../../testoutput/bubble_tea_mod.asset", outData);
            }
        }
Beispiel #21
0
        public AdbWindow(Apk apk)
        {
            InitializeComponent();

            // make all flyout width same as root
            foreach (Flyout flayout in Flyouts.Items)
            {
                flayout.Width = this.Width;
            }

            // set switch in settings
            cfg = new Config();
            swInstall.IsChecked   = cfg.AutoInstall();
            swUninstall.IsChecked = cfg.AutoUninstall();
            swClose.IsChecked     = cfg.AutoClose();

            // define adb
            adb                     = new Adb();
            adb.OnProcess          += (value) => ShowLoading(value);
            adb.OutputDataReceived += (msg) => CommandOutput_Insert(msg, false);
            adb.ErrorDataReceived  += (msg) => CommandOutput_Insert(msg, true);

            this.apk = apk;
        }
Beispiel #22
0
        private void OnUploadResponce(Apk apk, AndroidPublisherService androidPublisherService, IAndroidDistributionSettings configs, AppEdit edit)
        {
            if (apk == null)
            {
                return;
            }

            var track = androidPublisherService.LoadTrackBranch(configs, edit);

            track.UpdateTrackInformation(apk.VersionCode, configs);

            //Verify if exist any obb
            var needUploadExtensionsFiles = CheckIfNeedProcessObb(configs, out string[] obbs);

            if (needUploadExtensionsFiles)
            {
                UploadObbFiles(androidPublisherService, edit, apk, configs, obbs);
            }

            var updatedTrack = androidPublisherService.Edits.Tracks
                               .Update(track, configs.PackageName, edit.Id, track.TrackValue).Execute();

            Debug.Log("Track " + updatedTrack.TrackValue + " has been updated.");
        }
Beispiel #23
0
        // ReSharper disable once UnusedMethodReturnValue.Local
        private bool UploadApk(string apkFileName, string expansionFileName, string track, List <UpdateInfo> apkChanges)
        {
            if (_serviceThread != null)
            {
                return(false);
            }

            if (!File.Exists(apkFileName))
            {
                UpdateStatus("Apk file not existing");
                return(false);
            }

            if (!string.IsNullOrEmpty(expansionFileName) && !File.Exists(expansionFileName))
            {
                UpdateStatus("Expansion file not existing");
                return(false);
            }

            UpdateStatus(string.Empty);
            _cts           = new CancellationTokenSource();
            _serviceThread = new Thread(async() =>
            {
                UpdateStatus(string.Empty);
                StringBuilder sb = new StringBuilder();
                try
                {
                    if (apkChanges != null)
                    {
                        sb.Append("Changes info for languages: ");
                        foreach (UpdateInfo updateInfo in apkChanges)
                        {
                            sb.Append($"{updateInfo.Language} ");
                        }
                        sb.AppendLine();
                        UpdateStatus(sb.ToString());
                    }

                    UserCredential credential = await GetCredatials();
                    using (AndroidPublisherService service = new AndroidPublisherService(GetInitializer(credential)))
                    {
                        EditsResource edits = service.Edits;
                        EditsResource.InsertRequest editRequest = edits.Insert(null, PackageName);
                        AppEdit appEdit = await editRequest.ExecuteAsync(_cts.Token);

                        bool reuseExpansion         = false;
                        ExpansionInfo expansionInfo = await GetNewestExpansionFile(edits, appEdit);
                        if (expansionInfo != null)
                        {
                            sb.AppendLine($"Latest expansion: apk version={expansionInfo.ApkVersion}, expansion version={expansionInfo.ExpansionVersion}, size={expansionInfo.FileSize}");
                            if (!string.IsNullOrEmpty(expansionFileName))
                            {
                                FileInfo fileInfo = new FileInfo(expansionFileName);
                                if (fileInfo.Exists && fileInfo.Length == expansionInfo.FileSize)
                                {
                                    sb.AppendLine("Size unchanged, reusing old expansion file");
                                    reuseExpansion = true;
                                }
                            }
                        }

                        Apk apkUploaded = null;
                        using (FileStream apkStream = new FileStream(apkFileName, FileMode.Open, FileAccess.Read))
                        {
                            long fileLength = (apkStream.Length > 0) ? apkStream.Length : 1;
                            EditsResource.ApksResource.UploadMediaUpload upload = edits.Apks.Upload(PackageName, appEdit.Id, apkStream, "application/vnd.android.package-archive");
                            upload.ChunkSize        = ResumableUpload.MinimumChunkSize;
                            upload.ProgressChanged += progress =>
                            {
                                UpdateStatus(sb.ToString() + $"Apk progress: {100 * progress.BytesSent / fileLength}%");
                            };
                            upload.ResponseReceived += apk =>
                            {
                                apkUploaded = apk;
                            };
                            IUploadProgress uploadProgress = await upload.UploadAsync(_cts.Token);
                            sb.AppendLine($"Upload status: {uploadProgress.Status.ToString()}");
                            UpdateStatus(sb.ToString());
                            if (uploadProgress.Exception != null)
                            {
                                throw uploadProgress.Exception;
                            }
                        }

                        int?versionCode = apkUploaded?.VersionCode;
                        if (!versionCode.HasValue)
                        {
                            throw new Exception("No apk version code");
                        }
                        sb.AppendLine($"Version code uploaded: {versionCode.Value}");
                        UpdateStatus(sb.ToString());

                        if (!string.IsNullOrEmpty(expansionFileName) && !reuseExpansion)
                        {
                            using (FileStream expansionStream = new FileStream(expansionFileName, FileMode.Open, FileAccess.Read))
                            {
                                long fileLength = (expansionStream.Length > 0) ? expansionStream.Length : 1;
                                EditsResource.ExpansionfilesResource.UploadMediaUpload upload = edits.Expansionfiles.Upload(PackageName, appEdit.Id, versionCode.Value,
                                                                                                                            EditsResource.ExpansionfilesResource.UploadMediaUpload.ExpansionFileTypeEnum.Main, expansionStream, "application/octet-stream");
                                upload.ChunkSize        = ResumableUpload.MinimumChunkSize;
                                upload.ProgressChanged += progress =>
                                {
                                    UpdateStatus(sb.ToString() + $"Expansion progress: {100 * progress.BytesSent / fileLength}%");
                                };
                                IUploadProgress uploadProgress = await upload.UploadAsync(_cts.Token);
                                sb.AppendLine($"Upload status: {uploadProgress.Status.ToString()}");
                                UpdateStatus(sb.ToString());
                                if (uploadProgress.Exception != null)
                                {
                                    throw uploadProgress.Exception;
                                }
                            }
                        }
                        else
                        {
                            if (expansionInfo != null)
                            {
                                ExpansionFile expansionRef = new ExpansionFile {
                                    ReferencesVersion = expansionInfo.ExpansionVersion
                                };
                                await edits.Expansionfiles.Update(expansionRef, PackageName, appEdit.Id, versionCode.Value,
                                                                  EditsResource.ExpansionfilesResource.UpdateRequest.ExpansionFileTypeEnum.Main).ExecuteAsync(_cts.Token);
                                sb.AppendLine($"Expansion version {expansionInfo.ExpansionVersion} assigned");
                            }
                            else
                            {
                                sb.AppendLine("No existing expansion found!");
                            }
                        }

                        Track updateTrack = new Track {
                            VersionCodes = new List <int?> {
                                versionCode.Value
                            }
                        };
                        EditsResource.TracksResource.UpdateRequest updateRequest = edits.Tracks.Update(updateTrack, PackageName, appEdit.Id, track);
                        Track updatedTrack = await updateRequest.ExecuteAsync(_cts.Token);
                        sb.AppendLine($"Track updated: {updatedTrack.TrackValue}");
                        UpdateStatus(sb.ToString());

                        if (apkChanges != null)
                        {
                            foreach (UpdateInfo updateInfo in apkChanges)
                            {
                                ApkListing apkListing = new ApkListing
                                {
                                    RecentChanges = updateInfo.Changes
                                };
                                await edits.Apklistings.Update(apkListing, PackageName, appEdit.Id, versionCode.Value, updateInfo.Language).ExecuteAsync(_cts.Token);
                                sb.AppendLine($"Changes for language {updateInfo.Language} updated");
                                UpdateStatus(sb.ToString());
                            }
                        }

                        EditsResource.CommitRequest commitRequest = edits.Commit(PackageName, appEdit.Id);
                        AppEdit appEditCommit = await commitRequest.ExecuteAsync(_cts.Token);
                        sb.AppendLine($"App edit committed: {appEditCommit.Id}");
                        UpdateStatus(sb.ToString());
                    }
                }
                catch (Exception e)
                {
                    sb.AppendLine($"Exception: {e.Message}");
                }
                finally
                {
                    _serviceThread = null;
                    _cts.Dispose();
                    UpdateStatus(sb.ToString());
                }
            });
            _serviceThread.Start();

            return(true);
        }
Beispiel #24
0
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("arguments: pathToAPKFileToModify levelFolders...");
                return;
            }
            string apkPath = args[0];

            using (Apk apk = new Apk(apkPath)) {
                apk.PatchSignatureCheck();

                byte[]           data   = apk.ReadEntireEntry(apk.MainAssetsFile());
                SerializedAssets assets = SerializedAssets.FromBytes(data, apk.version);

                HashSet <string>            existingLevels   = assets.ExistingLevelIDs();
                LevelCollectionBehaviorData extrasCollection = assets.FindExtrasLevelCollection();
                for (int i = 1; i < args.Length; i++)
                {
                    Utils.FindLevels(args[i], levelFolder => {
                        try {
                            JsonLevel level = JsonLevel.LoadFromFolder(levelFolder);
                            string levelID  = level.GenerateBasicLevelID();
                            if (existingLevels.Contains(levelID))
                            {
                                Console.WriteLine($"Present: {level._songName}");
                            }
                            else
                            {
                                Console.WriteLine($"Adding:  {level._songName}");
                                // We use transactions here so if these throw
                                // an exception, which happens when levels are
                                // invalid, then it doesn't modify the APK in
                                // any way that might screw things up later.
                                var assetsTxn     = new SerializedAssets.Transaction(assets);
                                var apkTxn        = new Apk.Transaction();
                                AssetPtr levelPtr = level.AddToAssets(assetsTxn, apkTxn, levelID);

                                // Danger should be over, nothing here should fail
                                assetsTxn.ApplyTo(assets);
                                extrasCollection.levels.Add(levelPtr);
                                existingLevels.Add(levelID);
                                apkTxn.ApplyTo(apk);
                            }
                        } catch (FileNotFoundException e) {
                            Console.WriteLine("[SKIPPING] Missing file referenced by level: {0}", e.FileName);
                        } catch (JsonReaderException e) {
                            Console.WriteLine("[SKIPPING] Invalid level JSON: {0}", e.Message);
                        }
                    });
                }

                byte[] outData = assets.ToBytes();
                apk.ReplaceAssetsFile(apk.MainAssetsFile(), outData);

                apk.Save();
            }

            Console.WriteLine("Signing APK...");
            Signer.Sign(apkPath);
        }
Beispiel #25
0
        static void SyncLevels(
            Apk apk,
            SerializedAssets mainAssets,
            Invocation inv,
            InvocationResult res
            )
        {
            if (inv.levels == null || inv.packs == null)
            {
                throw new ApplicationException("Either the 'levels' or 'packs' key is missing. Note the 'levels' key changed names from 'ensureInstalled' in the new version.");
            }

            Dictionary <string, ulong> existingLevels = mainAssets.FindLevels();
            ulong maxBasePathID = mainAssets.MainAssetsMaxBaseGamePath();

            // === Load root level pack
            SerializedAssets rootPackAssets = SerializedAssets.FromBytes(apk.ReadEntireEntry(apk.RootPackFile()), apk.version);
            string           mainFileName   = apk.MainAssetsFileName();
            int mainFileI = rootPackAssets.externals.FindIndex(e => e.pathName == mainFileName) + 1;
            BeatmapLevelPackCollection rootLevelPack = rootPackAssets.FindMainLevelPackCollection();
            // Might be null if we're on a version older than v1.1.0
            AlwaysOwnedBehaviorData alwaysOwned = mainAssets.FindScript <AlwaysOwnedBehaviorData>(x => true);

            // === Remove existing custom packs
            rootLevelPack.beatmapLevelPacks.RemoveAll(ptr => ptr.fileID == mainFileI && ptr.pathID > maxBasePathID);
            if (alwaysOwned != null)
            {
                alwaysOwned.levelPacks.RemoveAll(ptr => ptr.fileID == 0 && ptr.pathID > maxBasePathID);
            }
            LevelPackBehaviorData.RemoveCustomPacksFromEnd(mainAssets);

            // === Remove old-school custom levels from Extras pack
            var extrasCollection = mainAssets.FindExtrasLevelCollection();

            extrasCollection.levels.RemoveAll(ptr => ptr.pathID > maxBasePathID);

            // === Remove existing levels
            var toRemove = new HashSet <string>();

            foreach (var entry in existingLevels)
            {
                if (inv.levels.ContainsKey(entry.Key))
                {
                    continue;                                   // requested
                }
                if (entry.Value <= maxBasePathID)
                {
                    continue;                              // base game level
                }
                toRemove.Add(entry.Key);
            }
            foreach (string levelID in toRemove)
            {
                var ao     = mainAssets.GetAssetObjectFromScript <LevelBehaviorData>(p => p.levelID == levelID);
                var apkTxn = new Apk.Transaction();
                Utils.RemoveLevel(mainAssets, ao, apkTxn);
                apkTxn.ApplyTo(apk);
            }
            res.removedLevels = toRemove.ToList();

            // === Install new levels
            var toInstall = new HashSet <string>();

            foreach (var entry in inv.levels)
            {
                if (existingLevels.ContainsKey(entry.Key))
                {
                    continue;                                       // already installed
                }
                toInstall.Add(entry.Key);
            }
            Program.Install(apk, mainAssets, toInstall, res, inv.levels);

            // === Create new custom packs
            Dictionary <string, ulong> availableLevels = mainAssets.FindLevels();

            foreach (LevelPack pack in inv.packs)
            {
                if (pack.name == null || pack.id == null || pack.levelIDs == null)
                {
                    throw new ApplicationException("Packs require name, id and levelIDs list");
                }
                var            txn  = new SerializedAssets.Transaction(mainAssets);
                CustomPackInfo info = LevelPackBehaviorData.CreateCustomPack(
                    txn, pack.id, pack.name, pack.coverImagePath
                    );
                txn.ApplyTo(mainAssets);

                var customCollection = info.collection.FollowToScript <LevelCollectionBehaviorData>(mainAssets);
                foreach (string levelID in pack.levelIDs)
                {
                    ulong levelPathID;
                    if (!availableLevels.TryGetValue(levelID, out levelPathID))
                    {
                        res.missingFromPacks.Add(levelID);
                        continue;
                    }
                    customCollection.levels.Add(new AssetPtr(0, levelPathID));
                }

                rootLevelPack.beatmapLevelPacks.Add(new AssetPtr(mainFileI, info.pack.pathID));
                if (alwaysOwned != null)
                {
                    alwaysOwned.levelPacks.Add(info.pack);
                }
            }
            res.presentLevels = availableLevels.Keys.ToList();

            apk.ReplaceAssetsFile(apk.RootPackFile(), rootPackAssets.ToBytes());
        }
Beispiel #26
0
        static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("arguments: pathToAPKFileToModify [-r removeSongs] levelFolders...");
                return;
            }
            bool removeSongs = false;

            if (args.Contains("-r") || args.Contains("removeSongs"))
            {
                removeSongs = true;
            }
            bool replaceExtras = false;

            if (args.Contains("-e"))
            {
                replaceExtras = true;
            }
            string apkPath = args[0];

            using (Apk apk = new Apk(apkPath)) {
                apk.PatchSignatureCheck();

                byte[]           data   = apk.ReadEntireEntry(Apk.MainAssetsFile);
                SerializedAssets assets = SerializedAssets.FromBytes(data);

                string           colorPath   = "assets/bin/Data/sharedassets1.assets";
                SerializedAssets colorAssets = SerializedAssets.FromBytes(apk.ReadEntireEntry(colorPath));

                //string textAssetsPath = "assets/bin/Data/c4dc0d059266d8d47862f46460cf8f31";
                string           textAssetsPath = "assets/bin/Data/231368cb9c1d5dd43988f2a85226e7d7";
                SerializedAssets textAssets     = SerializedAssets.FromBytes(apk.ReadEntireEntry(textAssetsPath));

                HashSet <string>            existingLevels   = assets.ExistingLevelIDs();
                LevelCollectionBehaviorData customCollection = assets.FindCustomLevelCollection();
                LevelPackBehaviorData       customPack       = assets.FindCustomLevelPack();
                ulong customPackPathID = assets.GetAssetObjectFromScript <LevelPackBehaviorData>(mob => mob.name == "CustomLevelPack", b => true).pathID;

                for (int i = 1; i < args.Length; i++)
                {
                    if (args[i] == "-r" || args[i] == "removeSongs" || args[i] == "-e")
                    {
                        continue;
                    }
                    if (args[i] == "-t")
                    {
                        if (i + 2 >= args.Length)
                        {
                            // There is not enough data after the text
                            // Reset it.
                            //continue;
                        }
                        var ao = textAssets.GetAssetAt(1);
                        TextAssetAssetData ta  = ao.data as TextAssetAssetData;
                        string             key = args[i + 1].ToUpper();

                        var segments = Utils.ReadLocaleText(ta.script, new List <char>()
                        {
                            ',', ',', '\n'
                        });

                        //segments.ToList().ForEach(a => Console.Write(a.Trim() + ","));
                        List <string> value;
                        if (!segments.TryGetValue(key.Trim(), out value))
                        {
                            Console.WriteLine($"[ERROR] Could not find key: {key} in text!");
                        }
                        Console.WriteLine($"Found key at index: {key.Trim()} with value: {value[value.Count - 1]}");
                        segments[key.Trim()][value.Count - 1] = args[i + 2];
                        Console.WriteLine($"New value: {args[i + 2]}");
                        Utils.ApplyWatermark(segments);
                        ta.script = Utils.WriteLocaleText(segments, new List <char>()
                        {
                            ',', ',', '\n'
                        });
                        i += 2;
                        apk.ReplaceAssetsFile(textAssetsPath, textAssets.ToBytes());
                        //Console.WriteLine((a.data as TextAsset).script);
                        continue;
                    }
                    if (args[i] == "-c1" || args[i] == "-c2")
                    {
                        if (i + 1 >= args.Length)
                        {
                            // There is nothing after the color
                            // Reset it.
                            Utils.ResetColors(colorAssets);
                            apk.ReplaceAssetsFile(colorPath, colorAssets.ToBytes());
                            continue;
                        }
                        if (!args[i + 1].StartsWith("("))
                        {
                            // Reset it.
                            Utils.ResetColors(colorAssets);
                            apk.ReplaceAssetsFile(colorPath, colorAssets.ToBytes());
                            continue;
                        }
                        if (i + 4 >= args.Length)
                        {
                            Console.WriteLine($"[ERROR] Cannot parse color, not enough colors! Please copy-paste a series of floats");
                            i += 4;
                            continue;
                        }

                        SimpleColor c = new SimpleColor
                        {
                            r = Convert.ToSingle(args[i + 1].Split(',')[0].Replace('(', '0')),
                            g = Convert.ToSingle(args[i + 2].Split(',')[0].Replace('(', '0')),
                            b = Convert.ToSingle(args[i + 3].Split(',')[0].Replace(')', '0')),
                            a = Convert.ToSingle(args[i + 4].Split(',')[0].Replace(')', '.'))
                        };

                        ColorManager dat = Utils.CreateColor(colorAssets, c);

                        var ptr = colorAssets.AppendAsset(new MonoBehaviorAssetData()
                        {
                            data   = c,
                            name   = "CustomColor" + args[i][args[i].Length - 1],
                            script = new AssetPtr(1, SimpleColor.PathID),
                        });
                        Console.WriteLine($"Created new CustomColor for colorA at PathID: {ptr.pathID}");
                        if (args[i] == "-c1")
                        {
                            dat.colorA = ptr;
                        }
                        else
                        {
                            dat.colorB = ptr;
                        }

                        apk.ReplaceAssetsFile(colorPath, colorAssets.ToBytes());

                        i += 4;
                        continue;
                    }
                    if (args[i] == "-g")
                    {
                        string           path = "assets/bin/Data/level11";
                        SerializedAssets a    = SerializedAssets.FromBytes(apk.ReadEntireEntry(path));
                        var gameobject        = a.FindGameObject("LeftSaber");
                        var script            = gameobject.components[4].FollowToScript <Saber>(a);
                        Console.WriteLine($"GameObject: {gameobject}");
                        foreach (AssetPtr p in gameobject.components)
                        {
                            Console.WriteLine($"Component: {p.pathID} followed: {p.Follow(a)}");
                        }
                        Console.WriteLine($"Left saber script: {script}");
                        // Find all objects that have the GameObject: LeftSaber (pathID = 20, fileID = 0 (142))

                        continue;
                    }
                    if (args[i] == "-s")
                    {
                        string cusomCoverFile = args[i + 1];
                        try
                        {
                            Texture2DAssetData dat = assets.GetAssetAt(14).data as Texture2DAssetData;

                            //assets.SetAssetAt(14, dat);
                            var ptr = assets.AppendAsset(Texture2DAssetData.CoverFromImageFile(args[i + 1], "CustomSongs", true));
                            Console.WriteLine($"Added Texture at PathID: {ptr.pathID} with new Texture2D from file: {args[i + 1]}");
                            var sPtr = assets.AppendAsset(Utils.CreateSprite(assets, ptr));
                            Console.WriteLine($"Added Sprite at PathID: {sPtr.pathID}!");

                            customPack.coverImage = sPtr;
                        } catch (FileNotFoundException)
                        {
                            Console.WriteLine($"[ERROR] Custom cover file does not exist: {args[i+1]}");
                        }
                        i++;
                        continue;
                    }
                    Utils.FindLevels(args[i], levelFolder => {
                        try {
                            JsonLevel level = JsonLevel.LoadFromFolder(levelFolder);
                            string levelID  = level.GenerateBasicLevelID();
                            var apkTxn      = new Apk.Transaction();

                            if (existingLevels.Contains(levelID))
                            {
                                if (removeSongs)
                                {
                                    // Currently does not handle transactions
                                    Console.WriteLine($"Removing: {level._songName}");
                                    existingLevels.Remove(levelID);

                                    var l  = assets.GetLevelMatching(levelID);
                                    var ao = assets.GetAssetObjectFromScript <LevelBehaviorData>(p => p.levelID == l.levelID);

                                    ulong lastLegitPathID = 201;

                                    // Currently, this removes all songs matching the song
                                    // the very first time it runs
                                    customCollection.levels.RemoveAll(ptr => ptr.pathID > lastLegitPathID && ao.pathID == ptr.pathID);
                                    foreach (string s in l.OwnedFiles(assets))
                                    {
                                        if (apk != null)
                                        {
                                            apk.RemoveFileAt($"assets/bin/Data/{s}");
                                        }
                                    }

                                    Utils.RemoveLevel(assets, l);

                                    apkTxn.ApplyTo(apk);
                                }
                                else
                                {
                                    Console.WriteLine($"Present: {level._songName}");
                                }
                            }
                            else
                            {
                                Console.WriteLine($"Adding:  {level._songName}");
                                // We use transactions here so if these throw
                                // an exception, which happens when levels are
                                // invalid, then it doesn't modify the APK in
                                // any way that might screw things up later.
                                var assetsTxn     = new SerializedAssets.Transaction(assets);
                                AssetPtr levelPtr = level.AddToAssets(assetsTxn, apkTxn, levelID);

                                // Danger should be over, nothing here should fail
                                assetsTxn.ApplyTo(assets);
                                customCollection.levels.Add(levelPtr);
                                existingLevels.Add(levelID);
                                apkTxn.ApplyTo(apk);
                            }
                        } catch (FileNotFoundException e) {
                            Console.WriteLine("[SKIPPING] Missing file referenced by level: {0}", e.FileName);
                        } catch (JsonReaderException e) {
                            Console.WriteLine("[SKIPPING] Invalid level JSON: {0}", e.Message);
                        }
                    });
                }
                byte[] outData = assets.ToBytes();
                apk.ReplaceAssetsFile(Apk.MainAssetsFile, outData);

                string           mainPackFile   = "assets/bin/Data/sharedassets19.assets";
                SerializedAssets mainPackAssets = SerializedAssets.FromBytes(apk.ReadEntireEntry(mainPackFile));

                // Modify image to be CustomLevelPack image?
                //customPack.coverImage = new AssetPtr(assets.externals.FindIndex(e => e.pathName == "sharedassets19.assets"))
                // Adds custom pack to the set of all packs
                int fileI = mainPackAssets.externals.FindIndex(e => e.pathName == "sharedassets17.assets") + 1;
                Console.WriteLine($"Found sharedassets17.assets at FileID: {fileI}");
                var mainLevelPack = mainPackAssets.FindMainLevelPackCollection();
                var pointerPacks  = mainLevelPack.beatmapLevelPacks[mainLevelPack.beatmapLevelPacks.Count - 1];
                Console.WriteLine($"Original last pack FileID: {pointerPacks.fileID} PathID: {pointerPacks.pathID}");
                if (!mainLevelPack.beatmapLevelPacks.Any(ptr => ptr.fileID == fileI && ptr.pathID == customPackPathID))
                {
                    Console.WriteLine($"Added CustomLevelPack to {mainPackFile}");
                    if (replaceExtras)
                    {
                        Console.WriteLine("Replacing ExtrasPack!");
                        mainLevelPack.beatmapLevelPacks[2] = new AssetPtr(fileI, customPackPathID);
                    }
                    else
                    {
                        Console.WriteLine("Adding as new Pack!");
                        mainLevelPack.beatmapLevelPacks.Add(new AssetPtr(fileI, customPackPathID));
                    }
                }
                pointerPacks = mainLevelPack.beatmapLevelPacks[mainLevelPack.beatmapLevelPacks.Count - 1];
                Console.WriteLine($"New last pack FileID: {pointerPacks.fileID} PathID: {pointerPacks.pathID}");
                apk.ReplaceAssetsFile(mainPackFile, mainPackAssets.ToBytes());

                Console.WriteLine("Complete!");
            }

            Console.WriteLine("Signing APK...");
            Signer.Sign(apkPath);
        }