mirror of
https://github.com/zeldaret/website.git
synced 2026-09-29 23:14:32 -04:00
Progress boxes constructed separately
(Still need to fix numbering)
This commit is contained in:
@@ -34,13 +34,13 @@ export class GameSummaryComponent implements OnChanges {
|
||||
|
||||
ngOnChanges(): void {
|
||||
// Matching is second
|
||||
this.gamesService.getGameCSV(this.data.csv_info[1].data).subscribe(
|
||||
this.gamesService.getGameCSV(this.data.csvData[1]).subscribe(
|
||||
res => {
|
||||
const points = res.split("\n").filter((line) => line != "");
|
||||
const latestPoint = points[points.length - 1];
|
||||
const column = latestPoint.split(",");
|
||||
|
||||
let i = this.data.charts[0].index;
|
||||
let i = this.data.progressMeta[0].index;
|
||||
this.total = +column[i] / +column[i + 1];
|
||||
},
|
||||
err => console.error(err)
|
||||
|
||||
@@ -15,14 +15,10 @@ export class GameChartComponent implements OnChanges {
|
||||
|
||||
constructor() { }
|
||||
|
||||
/**
|
||||
* The names of the lines to use in this chart.
|
||||
*/
|
||||
// @Input() line_names: string[] = null;
|
||||
/**
|
||||
* The CSV data to use for this chart.
|
||||
*/
|
||||
@Input() datasets: string[] = null;
|
||||
@Input() csvData: string[] = null;
|
||||
/**
|
||||
* The chart metadata stored in the game settings.
|
||||
*/
|
||||
@@ -34,24 +30,28 @@ export class GameChartComponent implements OnChanges {
|
||||
|
||||
ngOnChanges(): void {
|
||||
// don't do anything until all inputs are provided
|
||||
if (typeof this.datasets !== "object" || typeof this.metadata !== "object") {
|
||||
if (typeof this.csvData !== "object" || typeof this.metadata !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
// set up chart data
|
||||
const metadata = this.metadata;
|
||||
let nonmatchingData = this.parseData(this.datasets[0]);
|
||||
let matchingData = this.parseData(this.datasets[1]);
|
||||
let nonmatchingData = this.parseData(this.csvData[0]);
|
||||
let matchingData = this.parseData(this.csvData[1]);
|
||||
|
||||
// Names for lines
|
||||
let nonmatchingName = this.metadata.line_names[0];
|
||||
let matchingName = this.metadata.line_names[1];
|
||||
let nonmatchingName = this.metadata.series[0];
|
||||
let matchingName = this.metadata.series[1];
|
||||
|
||||
|
||||
let joined = Array.prototype.concat(matchingData, nonmatchingData);
|
||||
joined.sort((a, b) => a["y"] - b["y"]);
|
||||
const interval = 1 / 5;
|
||||
const max = Math.max(interval, Math.ceil(joined.slice(-1)[0].y / interval) * interval);
|
||||
let max = Math.max(interval, Math.ceil(joined.slice(-1)[0].y / interval) * interval);
|
||||
|
||||
if (max < 0.9) {
|
||||
max = null;
|
||||
}
|
||||
|
||||
const options: Options = {
|
||||
chart: { type: "line" },
|
||||
@@ -64,11 +64,11 @@ export class GameChartComponent implements OnChanges {
|
||||
|
||||
tooltip += `Date: ${new Date(data.x).toLocaleString()}<br/>\n`;
|
||||
tooltip += `Commit: ${data["commit"]}<br/>\n`
|
||||
tooltip += `Total ${metadata.series[0].metric}: ${(+data.y * 100).toFixed(2)}%<br/>\n`
|
||||
tooltip += `Total ${metadata.subdivisions[0].metric}: ${(+data.y * 100).toFixed(2)}%<br/>\n`
|
||||
tooltip += `-------------------------------------------<br/>\n`;
|
||||
|
||||
for (let i = 0; i < metadata.series.length - 1; i += 1) {
|
||||
const text = metadata.series[i + 1].description
|
||||
for (let i = 0; i < metadata.subdivisions.length - 1; i += 1) {
|
||||
const text = metadata.subdivisions[i + 1].description
|
||||
.replace("{0}", data["metrics"][i][0])
|
||||
.replace("{1}", data["metrics"][i][1])
|
||||
.replace("{2}", (+data["metrics"][i][2] * 100).toFixed(2));
|
||||
@@ -92,7 +92,8 @@ export class GameChartComponent implements OnChanges {
|
||||
type: "line",
|
||||
name: nonmatchingName,
|
||||
data: nonmatchingData,
|
||||
color: "#ffc107"
|
||||
color: "#ffc107",
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
type: "line",
|
||||
|
||||
@@ -1,6 +1,42 @@
|
||||
<n64-box [number]="1" heading="{{ meta.subtitle }}">
|
||||
<strong class="key">Last updated</strong>
|
||||
<strong class="value date">{{ lastUpdate }}</strong>
|
||||
<br>
|
||||
<hr>
|
||||
<table>
|
||||
<thead>
|
||||
<th scope="col"></th>
|
||||
<ng-container *ngFor="let name of meta.series; let j = index">
|
||||
<th scope="col" [ngClass]="{nonmatching: j === 0, matching: j === 1}">{{ name }}</th>
|
||||
</ng-container>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<strong class="key">Total</strong>
|
||||
</th>
|
||||
<td *ngFor="let total of totals; let j = index">
|
||||
<strong [ngClass]="{nonmatching: j === 0, matching: j === 1}">{{ (total * 100).toFixed(2) }}%</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngFor="let metric of metrics | keyvalue: originalOrder">
|
||||
<th scope="row" class="key">{{ metric.key }}</th>
|
||||
<td *ngFor="let val of metric.value; let j = index">
|
||||
<div [ngClass]="{nonmatching: j === 0, matching: j === 1}">{{ (val * 100).toFixed(2) }}%</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</n64-box>
|
||||
<n64-box [simple]="true">
|
||||
<game-chart [csvData]="csvData" [metadata]="meta"></game-chart>
|
||||
</n64-box>
|
||||
|
||||
|
||||
<!--
|
||||
<ng-container *ngFor="let chart of metrics; let i = index">
|
||||
<div class="box-wrapper">
|
||||
<n64-box [number]="i" heading="{{ game.charts[i].subtitle }}">
|
||||
<n64-box [number]="i" heading="{{ game.progressMeta[i].subtitle }}">
|
||||
<strong class="key">Last updated</strong>
|
||||
<strong class="value date">{{ lastUpdate }}</strong>
|
||||
<br/>
|
||||
@@ -8,7 +44,7 @@
|
||||
<table>
|
||||
<thead>
|
||||
<th scope="col"> {{ (totals[i] | keyvalue)[0].key }}</th>
|
||||
<ng-container *ngFor="let name of game.charts[i].line_names; let j = index">
|
||||
<ng-container *ngFor="let name of game.progressMeta[i].series; let j = index">
|
||||
<th scope="col" [ngClass]="{nonmatching: j === 0, matching: j === 1}">{{ name }}</th>
|
||||
</ng-container>
|
||||
</thead>
|
||||
@@ -31,7 +67,7 @@
|
||||
</table>
|
||||
</n64-box>
|
||||
<n64-box [simple]="true">
|
||||
<game-chart [datasets]="datasets" [metadata]="game.charts[i]"></game-chart>
|
||||
<game-chart [csvData]="csvData" [metadata]="game.progressMeta[i]"></game-chart>
|
||||
</n64-box>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container> -->
|
||||
@@ -1,9 +1,9 @@
|
||||
import { KeyValue } from '@angular/common';
|
||||
import { ThrowStmt } from '@angular/compiler';
|
||||
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { concat, forkJoin } from 'rxjs';
|
||||
import { GamesService } from 'src/app/games/games.service';
|
||||
import { IGame } from 'src/app/games/games.service.interface';
|
||||
import { IChart, IGame } from 'src/app/games/games.service.interface';
|
||||
|
||||
/**
|
||||
* A single project displayed in a box, alongside one or more graphs.
|
||||
@@ -20,83 +20,70 @@ export class GameProgressComponent implements OnChanges {
|
||||
/**
|
||||
* Game object which holds info on how to parse the CSV data.
|
||||
*/
|
||||
@Input() game: IGame = null;
|
||||
@Input() meta: IChart = null;
|
||||
/**
|
||||
* CSV data.
|
||||
*/
|
||||
@Input() csvData: string[] = [];
|
||||
|
||||
/**
|
||||
* The date time string for when this project was last updated
|
||||
*/
|
||||
lastUpdate: string = "";
|
||||
lastUpdate: string = "";
|
||||
/**
|
||||
* The simple numbers showing the total progress on respective charts.
|
||||
*/
|
||||
totals: {[key: string]: number[]}[] = [];
|
||||
totals: number[] = [];
|
||||
/**
|
||||
* Separate project metrics parsed from the CSV.
|
||||
*/
|
||||
metrics: {[key: string]: number[]}[] = [];
|
||||
/**
|
||||
* CSV data for use with the chart.
|
||||
*/
|
||||
datasets: string[];
|
||||
metrics: { [key: string]: number[] } = {};
|
||||
/**
|
||||
* Names for lines for use with the chart.
|
||||
*/
|
||||
line_names: string[];
|
||||
series: string[];
|
||||
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.line_names = this.game.csv_info.map((info) => info.name);
|
||||
// don't do anything until all inputs are provided
|
||||
console.log(this.meta);
|
||||
if (typeof this.csvData !== "object" || typeof this.meta !== "object") {
|
||||
return;
|
||||
}
|
||||
|
||||
forkJoin(
|
||||
this.game.csv_info.map((info) => this.gamesService.getGameCSV(info.data), this)
|
||||
).subscribe(
|
||||
res => {
|
||||
this.datasets = res;
|
||||
|
||||
// reset on page load
|
||||
this.totals = [];
|
||||
this.metrics = [];
|
||||
this.lastUpdate = null;
|
||||
// reset on page load
|
||||
this.totals = [];
|
||||
this.metrics = {};
|
||||
this.lastUpdate = null;
|
||||
|
||||
for (const data of this.csvData) {
|
||||
const points = data.split("\n").filter((line) => line != "");
|
||||
const latestPoint = points[points.length - 1];
|
||||
const column = latestPoint.split(",");
|
||||
if (this.lastUpdate === null) {
|
||||
this.lastUpdate = new Date(+column[1] * 1000).toLocaleString();
|
||||
}
|
||||
|
||||
for (const _ of this.game.charts) {
|
||||
this.metrics.push({});
|
||||
// this.totals.push({[this.meta.subdivisions[0].metric]: []});
|
||||
// this.totals[this.meta.subdivisions[0].metric].push([this.meta.subdivisions[0].metric]);
|
||||
|
||||
let i = this.meta.index;
|
||||
this.totals.push(+column[i] / +column[i + 1]);
|
||||
i += 2;
|
||||
|
||||
for (const subdivision of this.meta.subdivisions.slice(1)) {
|
||||
if (!(subdivision.metric in this.metrics)) {
|
||||
this.metrics[subdivision.metric] = [];
|
||||
}
|
||||
|
||||
for (const data of res) {
|
||||
const points = data.split("\n").filter((line) => line != "");
|
||||
const latestPoint = points[points.length - 1];
|
||||
const column = latestPoint.split(",");
|
||||
if (this.lastUpdate === null) {
|
||||
this.lastUpdate = new Date(+column[1] * 1000).toLocaleString();
|
||||
}
|
||||
|
||||
for (const chart of this.game.charts) {
|
||||
this.totals.push({ [chart.series[0].metric]: [] });
|
||||
}
|
||||
|
||||
let c = 0;
|
||||
for (const chart of this.game.charts) {
|
||||
let i = chart.index;
|
||||
this.totals[c][chart.series[0].metric].push(+column[i] / +column[i+1]);
|
||||
i += 2;
|
||||
|
||||
for (const serie of chart.series.slice(1)) {
|
||||
if (!(serie.metric in this.metrics[c])) {
|
||||
this.metrics[c][serie.metric] = [];
|
||||
}
|
||||
this.metrics[c][serie.metric].push(+column[i] / +column[i+1]);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
c += 1;
|
||||
}
|
||||
}
|
||||
},
|
||||
err => console.error(err)
|
||||
);
|
||||
this.metrics[subdivision.metric].push(+column[i] / +column[i + 1]);
|
||||
i += 2;
|
||||
}
|
||||
|
||||
}
|
||||
console.log(this.metrics)
|
||||
}
|
||||
|
||||
|
||||
originalOrder(a: KeyValue<any, any>, b: KeyValue<any, any>): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<h1>{{ game.title }}</h1>
|
||||
<article>
|
||||
<game-progress [game]="game"></game-progress>
|
||||
</article>
|
||||
|
||||
<ng-container *ngFor="let meta of game.progressMeta">
|
||||
<article>
|
||||
<game-progress [csvData]="csvData" [meta]="meta"></game-progress>
|
||||
</article>
|
||||
</ng-container>
|
||||
|
||||
<article>
|
||||
<game-faq [game]="game"></game-faq>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnChanges, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { forkJoin } from 'rxjs';
|
||||
import { GamesService } from '../games.service';
|
||||
import { IGame } from '../games.service.interface';
|
||||
import { IChart, IGame } from '../games.service.interface';
|
||||
|
||||
/**
|
||||
* Container component for the tabs and relevant content.
|
||||
* Container component for relevant content on a game.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'game',
|
||||
@@ -18,8 +19,13 @@ export class GameComponent implements OnInit {
|
||||
/**
|
||||
* The summary to use to display basic game info.
|
||||
*/
|
||||
game: IGame;
|
||||
game: IGame;
|
||||
/**
|
||||
* Data obtained from the CSV files.
|
||||
*/
|
||||
csvData: string[];
|
||||
|
||||
// Get the CSVs if the navigated slug is correct, otherwise navigate to 404
|
||||
ngOnInit(): void {
|
||||
this.route.params.subscribe(
|
||||
res => {
|
||||
@@ -27,12 +33,19 @@ export class GameComponent implements OnInit {
|
||||
this.gamesService.getGames().subscribe(
|
||||
res => {
|
||||
// redirect if an unknown slug is provided
|
||||
const index = res.findIndex((game) => game.slug === slug)
|
||||
if (index !== -1) {
|
||||
this.game = res[index];
|
||||
const index = res.findIndex((game) => game.slug === slug);
|
||||
if (index === -1) {
|
||||
this.router.navigateByUrl("/404", { skipLocationChange: true });
|
||||
}
|
||||
else {
|
||||
this.router.navigateByUrl("/404", { skipLocationChange: true });
|
||||
this.game = res[index];
|
||||
forkJoin([
|
||||
this.gamesService.getGameCSV(this.game.csvs.nonmatching),
|
||||
this.gamesService.getGameCSV(this.game.csvs.matching)
|
||||
]).subscribe(
|
||||
res => this.csvData = res,
|
||||
err => console.error(err)
|
||||
);
|
||||
}
|
||||
},
|
||||
err => {
|
||||
@@ -43,5 +56,4 @@ export class GameComponent implements OnInit {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -20,22 +20,18 @@ export interface IGame {
|
||||
* Links to display as an icon. The key defines the icon, and the value is the link href.
|
||||
*/
|
||||
links: {[type: string]: string};
|
||||
// /**
|
||||
// * The name of the "matching" CSV to read.
|
||||
// */
|
||||
// matching: string;
|
||||
// /**
|
||||
// * The name of the "nonmatching" CSV to read.
|
||||
// */
|
||||
// nonmatching: string;
|
||||
/**
|
||||
* Information on which csvs to use and what to call them.
|
||||
* Struct with names of CSVs to use
|
||||
*/
|
||||
csv_info: ICSVInfo[];
|
||||
csvs: ICSVs;
|
||||
/**
|
||||
* The charts to display for this game.
|
||||
* Data from CSVs
|
||||
*/
|
||||
charts: IChart[];
|
||||
csvData: string[];
|
||||
/**
|
||||
* The charts and data for each game.
|
||||
*/
|
||||
progressMeta: IChart[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,35 +79,35 @@ export interface IChart {
|
||||
/**
|
||||
* The index to start counting pairs from. If none provided, will assume 5.
|
||||
*/
|
||||
index?: number;
|
||||
/**
|
||||
* The series to have for each chart.
|
||||
*/
|
||||
series: ISeries[];
|
||||
index: number;
|
||||
/**
|
||||
* Names to use for the lines
|
||||
*/
|
||||
line_names: string[];
|
||||
series: string[];
|
||||
/**
|
||||
* The series to have for each chart.
|
||||
*/
|
||||
subdivisions: ISubdivision[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a csv of chart data and its name.
|
||||
*/
|
||||
export interface ICSVInfo {
|
||||
export interface ICSVs {
|
||||
/**
|
||||
* The name of the csv type to display with the line.
|
||||
* CSV file to get the matching data from.
|
||||
*/
|
||||
name?: string;
|
||||
matching: string;
|
||||
/**
|
||||
* CSV file to get the data from.
|
||||
* CSV file to get the nonmatching data from.
|
||||
*/
|
||||
data: string;
|
||||
nonmatching: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a singles series within a chart.
|
||||
*/
|
||||
export interface ISeries {
|
||||
export interface ISubdivision {
|
||||
/**
|
||||
* The name of the metric to display at the top.
|
||||
*/
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
csv_version,timestamp,git_hash,src,total,boot,boot_total,code,code_total,ovl,ovl_total,asm,nonMatchingFunctions,assets,assets_total,archive,archive_total,audio,audio_total,interface,interface_total,misc,misc total,objects,objects_total,scenes,scenes_total,text,text_total
|
||||
2,1615435438,e788bfecbfb10afd4182332db99bb562ea75b1de,103860,4747680,31572,86160,58624,1065936,13664,3595584,4597948,49,0,40817824,0,434608,0,6029280,0,749728,0,3953872,0,13518320,0,15695712,0,436304
|
||||
2,1615511099,72f2b6aa4d154514008f61cc35025875a0528e02,103860,4747680,31572,86160,58624,1065936,13664,3595584,4597948,49,0,40817824,0,434608,0,6029280,0,749728,0,3953872,0,13518320,0,15695712,0,436304
|
||||
2,1615512459,a983d14081b0e0daee4428769e7968071a1e9401,103860,4747680,31572,86160,58624,1065936,13664,3595584,4597948,49,0,40817824,0,434608,0,6029280,0,749728,0,3953872,0,13518320,0,15695712,0,436304
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
csv_version,timestamp,git_hash,src,total,boot,boot_total,code,code_total,ovl,ovl_total,asm,nonMatchingFunctions,assets,assets_total,archive,archive_total,audio,audio_total,interface,interface_total,misc,misc total,objects,objects_total,scenes,scenes_total,text,text_total
|
||||
2,1615435438,e788bfecbfb10afd4182332db99bb562ea75b1de,120152,4747680,36352,86160,70136,1065936,13664,3595584,4582152,0,0,40817824,0,434608,0,6029280,0,749728,0,3953872,0,13518320,0,15695712,0,436304
|
||||
2,1615511099,72f2b6aa4d154514008f61cc35025875a0528e02,120152,4747680,36352,86160,70136,1065936,13664,3595584,4582152,0,0,40817824,0,434608,0,6029280,0,749728,0,3953872,0,13518320,0,15695712,0,436304
|
||||
2,1615512459,a983d14081b0e0daee4428769e7968071a1e9401,120152,4747680,36352,86160,70136,1065936,13664,3595584,4582152,0,0,40817824,0,434608,0,6029280,0,749728,0,3953872,0,13518320,0,15695712,0,436304
|
||||
|
||||
|
+33
-33
@@ -6,23 +6,21 @@
|
||||
"github": "https://www.github.com/zeldaret/oot"
|
||||
},
|
||||
"faq": "oot_faq",
|
||||
"csv_info": [
|
||||
{
|
||||
"name": "nonmatching",
|
||||
"data": "progress-oot-nonmatching"
|
||||
},
|
||||
{
|
||||
"name": "matching",
|
||||
"data": "progress-oot-matching"
|
||||
}
|
||||
],
|
||||
"charts": [
|
||||
"csvs": {
|
||||
"matching": "progress-oot-matching",
|
||||
"nonmatching": "progress-oot-nonmatching"
|
||||
},
|
||||
"progressMeta": [
|
||||
{
|
||||
"type": "code",
|
||||
"title": "Ocarina of Time MQ Debug Rom",
|
||||
"subtitle": "Code decompilation progress",
|
||||
"index": 3,
|
||||
"line_names": ["Nonmatching", "Matching"],
|
||||
"series": [
|
||||
"Nonmatching",
|
||||
"Matching"
|
||||
],
|
||||
"subdivisions": [
|
||||
{
|
||||
"metric": "Code",
|
||||
"description": "{0} / {1} bytes of all code decompiled ({2}%)"
|
||||
@@ -50,34 +48,32 @@
|
||||
"github": "https://www.github.com/zeldaret/mm"
|
||||
},
|
||||
"faq": "mm_faq",
|
||||
"csv_info": [
|
||||
{
|
||||
"name": "nonmatching",
|
||||
"data": "progress-mm-nonmatching"
|
||||
},
|
||||
{
|
||||
"name": "matching",
|
||||
"data": "progress-mm-matching"
|
||||
}
|
||||
],
|
||||
"charts": [
|
||||
"csvs": {
|
||||
"matching": "progress-mm-matching",
|
||||
"nonmatching": "progress-mm-nonmatching"
|
||||
},
|
||||
"progressMeta": [
|
||||
{
|
||||
"type": "code",
|
||||
"title": "Majora's Mask",
|
||||
"subtitle": "Code decompilation progress",
|
||||
"line_names": ["Nonmatching", "Matching"],
|
||||
"index": 3,
|
||||
"series": [
|
||||
"Nonmatching",
|
||||
"Matching"
|
||||
],
|
||||
"index": 3,
|
||||
"subdivisions": [
|
||||
{
|
||||
"metric": "Code",
|
||||
"description": "{0} / {1} bytes of all code decompiled ({2}%)"
|
||||
},
|
||||
{
|
||||
"metric": "boot",
|
||||
"description": "{0} / {1} bytes of boot decompiled ({2}%)"
|
||||
"metric": "Code",
|
||||
"description": "{0} / {1} bytes of code decompiled ({2}%)"
|
||||
},
|
||||
{
|
||||
"metric": "code",
|
||||
"description": "{0} / {1} bytes of code decompiled ({2}%)"
|
||||
"metric": "Boot",
|
||||
"description": "{0} / {1} bytes of boot decompiled ({2}%)"
|
||||
},
|
||||
{
|
||||
"metric": "Overlays",
|
||||
@@ -86,11 +82,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "assets",
|
||||
"title": "Majora's Mask",
|
||||
"subtitle": "Asset decompilation progress",
|
||||
"line_names": ["Debinarised", "Identified"],
|
||||
"index": 13,
|
||||
"subtitle": "Asset analysis progress",
|
||||
"series": [
|
||||
"Debinarised",
|
||||
"Identified"
|
||||
],
|
||||
"index": 13,
|
||||
"subdivisions": [
|
||||
{
|
||||
"metric": "Assets",
|
||||
"description": "{0} / {1} bytes of all assets decompiled ({2}%)"
|
||||
@@ -127,4 +127,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
Reference in New Issue
Block a user