├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── babel.config.js ├── config.example.yml ├── jest.config.js ├── nginx.conf.sample ├── package-lock.json ├── package.json ├── src ├── config.ts ├── helper.ts ├── index.ts ├── logger.ts ├── progressbar.ts └── utils.ts ├── tests ├── .eslintrc.js ├── config.test.js └── mocks │ └── config.yml ├── tsconfig.json ├── types ├── common.d.ts ├── minecraft.d.ts └── nyaa-stats.d.ts ├── typings ├── gauge │ └── index.d.ts └── mcnbt │ └── index.d.ts └── web ├── .browserslistrc ├── .eslintrc.js ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── font │ ├── Inter-Black.woff │ ├── Inter-Black.woff2 │ ├── Inter-BlackItalic.woff │ ├── Inter-BlackItalic.woff2 │ ├── Inter-Bold.woff │ ├── Inter-Bold.woff2 │ ├── Inter-BoldItalic.woff │ ├── Inter-BoldItalic.woff2 │ ├── Inter-ExtraBold.woff │ ├── Inter-ExtraBold.woff2 │ ├── Inter-ExtraBoldItalic.woff │ ├── Inter-ExtraBoldItalic.woff2 │ ├── Inter-ExtraLight.woff │ ├── Inter-ExtraLight.woff2 │ ├── Inter-ExtraLightItalic.woff │ ├── Inter-ExtraLightItalic.woff2 │ ├── Inter-Italic.woff │ ├── Inter-Italic.woff2 │ ├── Inter-Light.woff │ ├── Inter-Light.woff2 │ ├── Inter-LightItalic.woff │ ├── Inter-LightItalic.woff2 │ ├── Inter-Medium.woff │ ├── Inter-Medium.woff2 │ ├── Inter-MediumItalic.woff │ ├── Inter-MediumItalic.woff2 │ ├── Inter-Regular.woff │ ├── Inter-Regular.woff2 │ ├── Inter-SemiBold.woff │ ├── Inter-SemiBold.woff2 │ ├── Inter-SemiBoldItalic.woff │ ├── Inter-SemiBoldItalic.woff2 │ ├── Inter-Thin.woff │ ├── Inter-Thin.woff2 │ ├── Inter-ThinItalic.woff │ ├── Inter-ThinItalic.woff2 │ ├── Inter-italic.var.woff2 │ ├── Inter-roman.var.woff2 │ ├── Inter.var.woff2 │ └── inter.css └── index.html ├── src ├── app.vue ├── assets │ ├── achievements │ │ ├── InvSprite.png │ │ ├── acquireIron.png │ │ ├── bakeCake.png │ │ ├── blazeRod.png │ │ ├── bookcase.png │ │ ├── breedCow.png │ │ ├── buildBetterPickaxe.png │ │ ├── buildFurnace.png │ │ ├── buildHoe.png │ │ ├── buildPickaxe.png │ │ ├── buildSword.png │ │ ├── buildWorkBench.png │ │ ├── cookFish.png │ │ ├── diamonds.png │ │ ├── diamondsToYou.png │ │ ├── enchantments.png │ │ ├── exploreAllBiomes.png │ │ ├── flyPig.png │ │ ├── fullBeacon.png │ │ ├── ghast.png │ │ ├── index.js │ │ ├── killCow.png │ │ ├── killEnemy.png │ │ ├── killWither.png │ │ ├── makeBread.png │ │ ├── mineWood.png │ │ ├── onARail.png │ │ ├── openInventory.png │ │ ├── overkill.png │ │ ├── overpowered.png │ │ ├── portal.png │ │ ├── potion.png │ │ ├── snipeSkeleton.png │ │ ├── spawnWither.png │ │ ├── theEnd.png │ │ └── theEnd2.png │ ├── advancement-data.json │ ├── advancements │ │ ├── adventure │ │ │ ├── adventuring_time.png │ │ │ ├── arbalistic.png │ │ │ ├── avoid_vibration.png │ │ │ ├── blowback.png │ │ │ ├── brush_armadillo.png │ │ │ ├── bullseye.png │ │ │ ├── craft_decorated_pot_using_only_sherds.png │ │ │ ├── crafters_crafting_crafters.png │ │ │ ├── fall_from_world_height.png │ │ │ ├── hero_of_the_village.png │ │ │ ├── honey_block_slide.png │ │ │ ├── index.js │ │ │ ├── kill_a_mob.png │ │ │ ├── kill_all_mobs.png │ │ │ ├── kill_mob_near_sculk_catalyst.png │ │ │ ├── lighten_up.png │ │ │ ├── lightning_rod_with_villager_no_fire.png │ │ │ ├── minecraft_trials_edition.png │ │ │ ├── ol_betsy.png │ │ │ ├── overoverkill.png │ │ │ ├── play_jukebox_in_meadows.png │ │ │ ├── read_power_of_chiseled_bookshelf.png │ │ │ ├── revaulting.png │ │ │ ├── root.png │ │ │ ├── salvage_sherd.png │ │ │ ├── shoot_arrow.png │ │ │ ├── sleep_in_bed.png │ │ │ ├── sniper_duel.png │ │ │ ├── spyglass_at_dragon.png │ │ │ ├── spyglass_at_ghast.png │ │ │ ├── spyglass_at_parrot.png │ │ │ ├── summon_iron_golem.png │ │ │ ├── throw_trident.png │ │ │ ├── totem_of_undying.png │ │ │ ├── trade.png │ │ │ ├── trade_at_world_height.png │ │ │ ├── trim_with_all_exclusive_armor_patterns.png │ │ │ ├── trim_with_any_armor_pattern.png │ │ │ ├── two_birds_one_arrow.png │ │ │ ├── under_lock_and_key.png │ │ │ ├── very_very_frightening.png │ │ │ ├── voluntary_exile.png │ │ │ ├── walk_on_powder_snow_with_leather_boots.png │ │ │ ├── who_needs_rockets.png │ │ │ └── whos_the_pillager_now.png │ │ ├── end │ │ │ ├── dragon_breath.png │ │ │ ├── dragon_egg.png │ │ │ ├── elytra.png │ │ │ ├── enter_end_gateway.png │ │ │ ├── find_end_city.png │ │ │ ├── index.js │ │ │ ├── kill_dragon.png │ │ │ ├── levitate.png │ │ │ ├── respawn_dragon.gif │ │ │ └── root.png │ │ ├── husbandry │ │ │ ├── allay_deliver_cake_to_note_block.png │ │ │ ├── allay_deliver_item_to_player.png │ │ │ ├── axolotl_in_a_bucket.png │ │ │ ├── balanced_diet.png │ │ │ ├── bred_all_animals.png │ │ │ ├── breed_an_animal.png │ │ │ ├── complete_catalogue.png │ │ │ ├── feed_snifflet.png │ │ │ ├── fishy_business.png │ │ │ ├── froglights.png │ │ │ ├── index.js │ │ │ ├── kill_axolotl_target.png │ │ │ ├── leash_all_frog_variants.png │ │ │ ├── make_a_sign_glow.png │ │ │ ├── obtain_netherite_hoe.png │ │ │ ├── obtain_sniffer_egg.png │ │ │ ├── plant_any_sniffer_seed.png │ │ │ ├── plant_seed.png │ │ │ ├── remove_wolf_armor.png │ │ │ ├── repair_wolf_armor.png │ │ │ ├── ride_a_boat_with_a_goat.png │ │ │ ├── root.png │ │ │ ├── safely_harvest_honey.png │ │ │ ├── silk_touch_nest.png │ │ │ ├── tactical_fishing.png │ │ │ ├── tadpole_in_a_bucket.png │ │ │ ├── tame_an_animal.png │ │ │ ├── wax_off.png │ │ │ ├── wax_on.png │ │ │ └── whole_pack.png │ │ ├── index.js │ │ ├── nether │ │ │ ├── all_effects.png │ │ │ ├── all_potions.png │ │ │ ├── brew_potion.png │ │ │ ├── charge_respawn_anchor.png │ │ │ ├── create_beacon.png │ │ │ ├── create_full_beacon.png │ │ │ ├── distract_piglin.png │ │ │ ├── explore_nether.png │ │ │ ├── fast_travel.png │ │ │ ├── find_bastion.png │ │ │ ├── find_fortress.png │ │ │ ├── get_wither_skull.png │ │ │ ├── index.js │ │ │ ├── loot_bastion.png │ │ │ ├── netherite_armor.png │ │ │ ├── obtain_ancient_debris.png │ │ │ ├── obtain_blaze_rod.png │ │ │ ├── obtain_crying_obsidian.png │ │ │ ├── return_to_sender.png │ │ │ ├── ride_strider.png │ │ │ ├── ride_strider_in_overworld_lava.png │ │ │ ├── root.png │ │ │ ├── summon_wither.gif │ │ │ ├── uneasy_alliance.png │ │ │ └── use_lodestone.png │ │ └── story │ │ │ ├── cure_zombie_villager.png │ │ │ ├── deflect_arrow.png │ │ │ ├── enchant_item.gif │ │ │ ├── enter_the_end.png │ │ │ ├── enter_the_nether.png │ │ │ ├── follow_ender_eye.png │ │ │ ├── form_obsidian.png │ │ │ ├── index.js │ │ │ ├── iron_tools.png │ │ │ ├── lava_bucket.png │ │ │ ├── mine_diamond.png │ │ │ ├── mine_stone.png │ │ │ ├── obtain_armor.png │ │ │ ├── root.png │ │ │ ├── shiny_gear.png │ │ │ ├── smelt_iron.png │ │ │ └── upgrade_tools.png │ ├── base.scss │ ├── bg-wool-dark.png │ └── lang.json ├── common │ ├── utils.js │ └── velocity.js ├── components │ ├── achievement-block.vue │ ├── advancement-gui.vue │ ├── advancement-icon.vue │ ├── advancement-info-panel.vue │ ├── advancement-title.vue │ ├── app-menu.vue │ ├── footer.vue │ ├── form-switch.vue │ ├── modal-layer.vue │ ├── navbar.vue │ ├── player-advancement-panel.vue │ ├── player-aside-panel.vue │ ├── player-avatar.vue │ ├── player-grid.vue │ ├── player-list.vue │ ├── player-name-history.vue │ ├── player-ore-graph.vue │ ├── player-skin-renderer │ │ ├── helper.js │ │ ├── index.js │ │ ├── layout.js │ │ ├── namemc-skins.js │ │ └── player-skin-renderer.vue │ ├── player-statistic-panel.vue │ ├── search-box.vue │ ├── sliding-transition.vue │ └── welcome.vue ├── composables │ ├── lang.js │ ├── local-config.js │ └── random-player.js ├── main.js ├── router │ └── index.js ├── store │ └── index.js └── views │ ├── Playground.vue │ ├── home.vue │ └── player.vue ├── tailwind.config.js └── vue.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [Makefile] 16 | indent_style = tab 17 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const __PROD__ = process.env.NODE_ENV === 'production' 2 | 3 | module.exports = { 4 | root: true, 5 | env: { 6 | es2020: true, 7 | node: true, 8 | }, 9 | parserOptions: { 10 | parser: '@typescript-eslint/parser', 11 | }, 12 | plugins: [ 13 | '@typescript-eslint', 14 | ], 15 | extends: [ 16 | 'eslint:recommended', 17 | 'plugin:@typescript-eslint/recommended', 18 | ], 19 | rules: { 20 | 'no-var': 'error', 21 | 'quotes': ['error', 'single'], 22 | 'semi': ['error', 'never'], 23 | 'object-curly-spacing': ['error', 'never'], 24 | 'space-before-function-paren': ['error', 'always'], 25 | 'comma-dangle': [__PROD__ ? 'error' : 'warn', 'always-multiline'], 26 | 'no-debugger': __PROD__ ? 'error' : 'off', 27 | 'no-console': 'off', 28 | }, 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | test 5 | /config.yml 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | 25 | __*__ 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 NyaaCat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NyaaStats 2 | A user state page builder for Minecraft. 3 | 4 | # How to use 5 | You can simply build your own web pages, just follow this instruction. 6 | 7 | _You need to do these commands in a series._ 8 | 9 | ## First grab user data from map folder 10 | 1. Clone the project. 11 | 2. Run `npm install`. 12 | 3. Rename `config.example.yml` to `config.yml`, read it and update it with your preferences. 13 | 4. Run `npm start`. It might take a long time running several tasks for each of your players, so be patient. The result data will be written to the directory you defined as `render.output` in `config.yml`. 14 | 15 | ## Build web pages 16 | 1. Go into `web` folder. 17 | 2. Run `npm install && npm run build`. 18 | 19 | ## Prepare to deploy 20 | Now you can find all the files you need in the `web/dist` folder. Create a folder named `webroot` and collect your files: 21 | 22 | 1. Move everything UNDER `web/dist` to webroot folder. 23 | 2. Move the `render.output` directory you defined to `webroot/data`. 24 | 25 | Your webroot folder should now look like this: 26 | 27 | ``` 28 | - webroot 29 | + index.html 30 | + css 31 | - data # here's the data that main application produces 32 | + info.json 33 | + players.json 34 | + (...) Player UUID directories 35 | + fonts 36 | + img 37 | + js 38 | ``` 39 | 40 | ## That's all! 41 | 42 | Upload webroot folder to your server, and configure your server like this: (We assume you use Nginx) 43 | 44 | ``` 45 | server { 46 | listen 80 default_server; 47 | listen [::]:80 default_server; 48 | 49 | root /your/path/to/webroot; 50 | 51 | index index.html; 52 | 53 | server_name example.com; 54 | 55 | location / { 56 | try_files $uri $uri/ @rewrites; 57 | } 58 | 59 | location @rewrites { 60 | rewrite ^(.+)$ /index.html last; 61 | } 62 | } 63 | ``` 64 | 65 | > If you don't use Nginx, or you don't want to change any server config (by switching to "hash mode"), please read https://router.vuejs.org/guide/essentials/history-mode.html for further information. 66 | > 67 | > In case you want to switch, the router config can be found at `/web/src/router/index.js`. 68 | 69 | ## Update player data 70 | 71 | Run `npm start` in the root folder of this project which means recreate the data folder and upload it to your web root. You don't need to run other commands everytime you update players' data but needed when we upgrade the code of our web client. 72 | 73 | # Credits 74 | The skin render is almost a copy of [NameMC](https://namemc.com). Thanks for their excellent work. 75 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', {targets: {node: 'current'}}], 4 | '@babel/preset-typescript', 5 | ], 6 | } 7 | -------------------------------------------------------------------------------- /config.example.yml: -------------------------------------------------------------------------------- 1 | # NYAA-STATS CONFIGURATION FILE 2 | 3 | # Grabber (main program) configuration 4 | render: 5 | # Data sources 6 | 7 | # [Required] `level.dat` file path. Example: "/opt/minecraft/world/level.dat" 8 | level: data/level.dat 9 | # [Required] `playerdata` directory path. Example: "/opt/minecraft/world/playerdata" 10 | playerdata: data/playerdata 11 | # [Required] `stats` directory path. Example: "/opt/minecraft/world/stats" 12 | stats: data/stats 13 | # [Required] `advancements` directory path. Example: "/opt/minecraft/world/advancements" 14 | advancements: data/advancements 15 | # Whether to only process whitelisted players. Possible values: 16 | # {string} - `whitelist.json` file path. Example: "/opt/minecraft/whitelist.json" 17 | # (unset) - Disable this feature (to process all reachable players) 18 | whitelist: whitelist.json 19 | # Banned UUID list. Possible values: 20 | # {string} - `banned-players.json` file path. Example: "/opt/minecraft/banned-players.json" 21 | # (unset) - Disable this feature (to assume no bans) 22 | banned-players: banned-players.json 23 | # Whether to render banned players. Default value: `false` 24 | render-banned: false 25 | # [Required] Crafatar service URL, used for player avatar/skin model generating 26 | crafatar: https://crafatar.com 27 | 28 | # Output 29 | 30 | # [Required] Output data directory path (absolute or relative to runtime `config.yml`) 31 | # Example: "webroot/data" 32 | output: web/public/data 33 | # Whether to prompt confirmation to clear output directory. You may want to set `false` if you're 34 | # using cronjob. Possible values: 35 | # `true` | (unset) - Prompt confirmation. You can choose yes or no to output directory clearing 36 | # `false` - Disable this feature (will not clear output directory) 37 | confirm-clear-data: true 38 | # [Deprecated] 39 | time-format: # time format on display, details http://momentjs.com/docs/#/displaying/format/ 40 | full: dddd, MMMM Do, YYYY HH:mm:ss ZZ 41 | short: MMMM Do, YYYY 42 | compact: YYYY-M-D HH:mm:ss 43 | 44 | # API usage configuration 45 | api: 46 | # [Required] Mojang API request rate limit (N req per second) 47 | ratelimit: 2 48 | 49 | # Web app configuration 50 | web: 51 | # [Required] Web app title, will be displayed at page header and as window title 52 | title: Nyaa Stats 53 | # [Required] Server name, will be displayed at welcome section and page footer 54 | servername: Minecraft Server 55 | # [Required] Server homepage URL, will be displayed at welcome section 56 | homepage: https://minecraft.example.com 57 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // The directory where Jest should store its cached dependency information 12 | // cacheDirectory: "/private/var/folders/0h/1bsnxdrn0db9f6wcnmt49lvm0000gp/T/jest_dy", 13 | 14 | // Automatically clear mock calls and instances between every test 15 | clearMocks: true, 16 | 17 | // Indicates whether the coverage information should be collected while executing the test 18 | collectCoverage: true, 19 | 20 | // An array of glob patterns indicating a set of files for which coverage information should be collected 21 | // collectCoverageFrom: undefined, 22 | 23 | // The directory where Jest should output its coverage files 24 | coverageDirectory: '__coverage__', 25 | 26 | // An array of regexp pattern strings used to skip coverage collection 27 | coveragePathIgnorePatterns: [ 28 | '/node_modules/', 29 | '/mocks/', 30 | ], 31 | 32 | // Indicates which provider should be used to instrument code for coverage 33 | // coverageProvider: "babel", 34 | 35 | // A list of reporter names that Jest uses when writing coverage reports 36 | // coverageReporters: [ 37 | // "json", 38 | // "text", 39 | // "lcov", 40 | // "clover" 41 | // ], 42 | 43 | // An object that configures minimum threshold enforcement for coverage results 44 | // coverageThreshold: undefined, 45 | 46 | // A path to a custom dependency extractor 47 | // dependencyExtractor: undefined, 48 | 49 | // Make calling deprecated APIs throw helpful error messages 50 | // errorOnDeprecated: false, 51 | 52 | // Force coverage collection from ignored files using an array of glob patterns 53 | // forceCoverageMatch: [], 54 | 55 | // A path to a module which exports an async function that is triggered once before all test suites 56 | // globalSetup: undefined, 57 | 58 | // A path to a module which exports an async function that is triggered once after all test suites 59 | // globalTeardown: undefined, 60 | 61 | // A set of global variables that need to be available in all test environments 62 | // globals: {}, 63 | 64 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 65 | // maxWorkers: "50%", 66 | 67 | // An array of directory names to be searched recursively up from the requiring module's location 68 | // moduleDirectories: [ 69 | // "node_modules" 70 | // ], 71 | 72 | // An array of file extensions your modules use 73 | // moduleFileExtensions: [ 74 | // "js", 75 | // "json", 76 | // "jsx", 77 | // "ts", 78 | // "tsx", 79 | // "node" 80 | // ], 81 | 82 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 83 | // moduleNameMapper: {}, 84 | 85 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 86 | // modulePathIgnorePatterns: [], 87 | 88 | // Activates notifications for test results 89 | // notify: false, 90 | 91 | // An enum that specifies notification mode. Requires { notify: true } 92 | // notifyMode: "failure-change", 93 | 94 | // A preset that is used as a base for Jest's configuration 95 | // preset: undefined, 96 | 97 | // Run tests from one or more projects 98 | // projects: undefined, 99 | 100 | // Use this configuration option to add custom reporters to Jest 101 | // reporters: undefined, 102 | 103 | // Automatically reset mock state between every test 104 | // resetMocks: false, 105 | 106 | // Reset the module registry before running each individual test 107 | // resetModules: false, 108 | 109 | // A path to a custom resolver 110 | // resolver: undefined, 111 | 112 | // Automatically restore mock state between every test 113 | // restoreMocks: false, 114 | 115 | // The root directory that Jest should scan for tests and modules within 116 | // rootDir: undefined, 117 | 118 | // A list of paths to directories that Jest should use to search for files in 119 | // roots: [ 120 | // "" 121 | // ], 122 | 123 | // Allows you to use a custom runner instead of Jest's default test runner 124 | // runner: "jest-runner", 125 | 126 | // The paths to modules that run some code to configure or set up the testing environment before each test 127 | // setupFiles: [], 128 | 129 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 130 | // setupFilesAfterEnv: [], 131 | 132 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 133 | // snapshotSerializers: [], 134 | 135 | // The test environment that will be used for testing 136 | testEnvironment: 'node', 137 | 138 | // Options that will be passed to the testEnvironment 139 | // testEnvironmentOptions: {}, 140 | 141 | // Adds a location field to test results 142 | // testLocationInResults: false, 143 | 144 | // The glob patterns Jest uses to detect test files 145 | // testMatch: [ 146 | // "**/__tests__/**/*.[jt]s?(x)", 147 | // "**/?(*.)+(spec|test).[tj]s?(x)" 148 | // ], 149 | 150 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 151 | // testPathIgnorePatterns: [ 152 | // "/node_modules/" 153 | // ], 154 | 155 | // The regexp pattern or array of patterns that Jest uses to detect test files 156 | // testRegex: [], 157 | 158 | // This option allows the use of a custom results processor 159 | // testResultsProcessor: undefined, 160 | 161 | // This option allows use of a custom test runner 162 | // testRunner: "jasmine2", 163 | 164 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 165 | // testURL: "http://localhost", 166 | 167 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 168 | // timers: "real", 169 | 170 | // A map from regular expressions to paths to transformers 171 | // transform: undefined, 172 | 173 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 174 | // transformIgnorePatterns: [ 175 | // "/node_modules/" 176 | // ], 177 | 178 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 179 | // unmockedModulePathPatterns: undefined, 180 | 181 | // Indicates whether each individual test should be reported during the run 182 | // verbose: undefined, 183 | 184 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 185 | // watchPathIgnorePatterns: [], 186 | 187 | // Whether to use watchman for file crawling 188 | // watchman: true, 189 | } 190 | -------------------------------------------------------------------------------- /nginx.conf.sample: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | listen [::]:80 default_server; 4 | 5 | root /your/root/path; 6 | 7 | index index.html; 8 | 9 | server_name example.com; 10 | 11 | location / { 12 | try_files $uri $uri/ @rewrites; 13 | } 14 | 15 | location @rewrites { 16 | rewrite ^(.+)$ /index.html last; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nyaa-stats", 3 | "version": "2.4.0", 4 | "description": "Web Stats for NyaaCat", 5 | "main": "src/index.ts", 6 | "engines": { 7 | "node": ">=12.18.0" 8 | }, 9 | "directories": { 10 | "test": "test" 11 | }, 12 | "scripts": { 13 | "start": "ts-node .", 14 | "lint": "eslint --fix src/**/*.ts tests/**/*.js *.js", 15 | "test": "jest" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/NyaaCat/NyaaStats.git" 20 | }, 21 | "keywords": [ 22 | "Minecraft", 23 | "stats" 24 | ], 25 | "author": "Phoenix Nemo ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/NyaaCat/NyaaStats/issues" 29 | }, 30 | "homepage": "https://github.com/NyaaCat/NyaaStats#readme", 31 | "dependencies": { 32 | "axios": "^0.19.2", 33 | "fs-extra": "^2.0.0", 34 | "gauge": "^2.7.4", 35 | "inquirer": "^5.2.0", 36 | "js-yaml": "^3.13.1", 37 | "log4js": "^2.11.0", 38 | "mcnbt": "github:SilentDepth/mcnbt#6ecad3f", 39 | "moment": "^2.24.0", 40 | "ts-node": "^8.10.2" 41 | }, 42 | "devDependencies": { 43 | "@babel/preset-env": "^7.10.4", 44 | "@babel/preset-typescript": "^7.10.4", 45 | "@types/fs-extra": "^2.1.0", 46 | "@types/inquirer": "^6.0.0", 47 | "@types/js-yaml": "^3.12.5", 48 | "@types/node": "^12.19.0", 49 | "@typescript-eslint/eslint-plugin": "^3.6.0", 50 | "@typescript-eslint/parser": "^3.6.0", 51 | "eslint": "^7.4.0", 52 | "jest": "^26.1.0", 53 | "typescript": "^4.0.5" 54 | }, 55 | "volta": { 56 | "node": "12.18.0" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import path from 'path' 4 | import yaml from 'js-yaml' 5 | import fs from 'fs-extra' 6 | 7 | import * as logger from './logger' 8 | 9 | interface Config extends NSConfig { 10 | __filename: string 11 | __dirname: string 12 | 13 | resolve (filepath: string): string 14 | 15 | get (keyPath: string | string[]): T 16 | } 17 | 18 | let config: Config 19 | 20 | export default function loadConfig (configPath = './config.yml'): Config { 21 | const filename = path.resolve(configPath) 22 | 23 | if (config?.__filename === filename) { 24 | return config 25 | } 26 | 27 | let _config: NSConfig 28 | try { 29 | // TODO: `.yaml` support 30 | _config = yaml.safeLoad(fs.readFileSync(configPath, 'utf-8')) as NSConfig 31 | } catch (err) /* istanbul ignore next */ { 32 | logger.Config.error('Error occurred while reading config') 33 | logger.Config.error(err.toString()) 34 | process.exit(1) 35 | } 36 | 37 | const dirname = path.parse(filename).dir 38 | config = Object.assign(_config, { 39 | __filename: filename, 40 | __dirname: dirname, 41 | resolve (filepath: string): string { 42 | return path.resolve(dirname, filepath) 43 | }, 44 | get (keyPath: string | string[]): T { 45 | if (typeof keyPath === 'string') { 46 | keyPath = keyPath.split('.') 47 | } 48 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 49 | // @ts-ignore 50 | // FIXME: Better typing 51 | return keyPath.reduce((value, key) => value[key], config) 52 | }, 53 | }) 54 | return config 55 | } 56 | -------------------------------------------------------------------------------- /src/helper.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra' 2 | import axios from 'axios' 3 | import inquirer from 'inquirer' 4 | 5 | import * as logger from './logger' 6 | 7 | export async function download (apiPath: string, dest: string): Promise { 8 | logger.Assets.info('DOWNLOAD', apiPath) 9 | const {data} = await axios.get(apiPath, { 10 | headers: {'Accept': 'image/*'}, 11 | responseType: 'stream', 12 | }) 13 | .catch(err => { 14 | // Sometimes Crafatar responds with 500 AND the correct image. If this is 15 | // the case, just return the body which is enough of use. 16 | if (err.response.headers['content-length'] && err.response.headers['content-type'].startsWith('image/')) { 17 | return {data: err.response.data} 18 | } 19 | logger.Assets.error('DOWNLOAD', apiPath, err.toString()) 20 | return {data: null} 21 | }) 22 | data?.pipe(fs.createWriteStream(dest)) 23 | } 24 | 25 | export function writeJSON (dest: string, data: never): void { 26 | fs.outputFile(dest, JSON.stringify(data), (err) => { 27 | if (err) { 28 | logger.WriteJSON.error('CREATE', dest, err.toString()) 29 | } else { 30 | logger.WriteJSON.info('CREATE', dest) 31 | } 32 | }) 33 | } 34 | 35 | export function mergeStats (data: McPlayerStatsJson): McPlayerStatsJson { 36 | const merged: McPlayerStatsJson = {} 37 | if (Object.prototype.hasOwnProperty.call(data, 'stats')) { 38 | for (const key in data.stats) { 39 | for (const s in data.stats[key]) { 40 | merged[key + '/' + s] = data.stats[key][s] 41 | } 42 | } 43 | return merged 44 | } 45 | return data 46 | } 47 | 48 | export function defaultSkin (uuid: LongUuid): 'Alex' | 'Steve' { 49 | // Great thanks to Minecrell for research into Minecraft and Java's UUID hashing! 50 | // https://git.io/xJpV 51 | // MC uses `uuid.hashCode() & 1` for alex 52 | // that can be compacted to counting the LSBs of every 4th byte in the UUID 53 | // an odd sum means alex, an even sum means steve 54 | // XOR-ing all the LSBs gives us 1 for alex and 0 for steve 55 | const isEven = (c: string) => { 56 | if (c >= '0' && c <= '9') { 57 | return (Number(c) & 1) === 0 58 | } else if (c >= 'a' && c <= 'f') { 59 | return (Number(c) & 1) === 1 60 | } 61 | console.log('Invalid digit', c) 62 | return null 63 | } 64 | const lsbsEven = 65 | (isEven(uuid[7]) !== isEven(uuid[23])) !== (isEven(uuid[15]) !== isEven(uuid[31])) 66 | return lsbsEven ? 'Alex' : 'Steve' 67 | } 68 | 69 | export async function confirm (message: string, _default = true): Promise { 70 | const prompt = inquirer.createPromptModule() 71 | try { 72 | const res = await prompt<{confirm: boolean}>({ 73 | type: 'confirm', 74 | name: 'confirm', 75 | default: _default, 76 | message, 77 | }) 78 | return res.confirm 79 | } catch (error) { 80 | logger.Default.error('Cannot get user input.') 81 | return false 82 | } 83 | } 84 | 85 | export function delay (ms: number): Promise { 86 | return new Promise(resolve => setTimeout(resolve, ms)) 87 | } 88 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra' 2 | import path from 'path' 3 | 4 | import loadConfig from './config' 5 | import Utils from './utils' 6 | import {confirm, writeJSON} from './helper' 7 | import * as logger from './logger' 8 | import ProgressBar from './progressbar' 9 | 10 | process.on('SIGINT', () => { 11 | process.exit() 12 | }) 13 | 14 | process.stdout.write('\x1Bc') 15 | 16 | const utils = new Utils() 17 | const config = loadConfig() 18 | 19 | void async function main () { 20 | const bannedUuidList = config.get('render.banned-players') ? utils.getBannedPlayers() : [] 21 | 22 | const uuidList = (() => { 23 | let list = config.render.whitelist ? utils.getWhitelistedPlayers() : utils.getAllPlayers() 24 | if (!config.get('render.render-banned') && bannedUuidList.length) { 25 | list = list.filter(uuid => !bannedUuidList.some(ban => ban === uuid)) 26 | } 27 | return list 28 | })() 29 | logger.Default.info('Players to process:', uuidList.length) 30 | 31 | if (config.render.advancements) { 32 | logger.Default.info('Advancements is set: Render mode set to 1.12+') 33 | } else { 34 | logger.Default.info('Advancements not set: Render mode set to 1.11') 35 | } 36 | 37 | const outputDir = config.resolve(config.render.output) 38 | logger.Default.info('CREATE OUTPUT DIR', outputDir) 39 | 40 | if (config.get('render.confirm-clear-data') !== false) { 41 | const prompt = await confirm('Do you want to clean the output folder?') 42 | if (prompt) { 43 | try { 44 | // Clean output dir 45 | for (const f of fs.readdirSync(outputDir)) { 46 | // ...but keep players.json as we need the name history in it 47 | // This file will be re-generated anyway 48 | if (f !== 'players.json') { 49 | fs.removeSync(path.join(outputDir, f)) 50 | } 51 | } 52 | } catch (err) { 53 | throw new Error(err) 54 | } 55 | } 56 | } 57 | 58 | const players = [] 59 | 60 | const progress = new ProgressBar(uuidList.length) 61 | progress.start() 62 | 63 | for (const uuid of uuidList) { 64 | try { 65 | const banned = config.get('render.render-banned') ? bannedUuidList.some(ban => ban === uuid) : false 66 | let data 67 | try { 68 | data = await utils.createPlayerData(uuid, banned) 69 | } catch (error) { 70 | logger.Default.error(`Failed to create player data for ${uuid}`, error.toString()) 71 | continue 72 | } 73 | players.push({ 74 | uuid: data.data.uuid_short, 75 | playername: data.data.playername, 76 | names: data.data.names, 77 | seen: data.data.seen, 78 | }) 79 | } finally { 80 | progress.tick(uuid) 81 | } 82 | } 83 | 84 | progress.stop() 85 | 86 | players.sort((a, b) => (b.seen ?? 0) - (a.seen ?? 0)) 87 | writeJSON(path.join(outputDir, 'players.json'), players as never) 88 | 89 | const worldTime = await utils.getWorldTime() 90 | writeJSON(path.join(outputDir, 'info.json'), { 91 | worldTime, 92 | timeFormat: config.get('render.time-format'), 93 | lastUpdate: Date.now(), 94 | ...config.web, 95 | } as never) 96 | }() 97 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | import log4js from 'log4js' 2 | 3 | log4js.configure({ 4 | appenders: { 5 | Default: {type: 'stdout'}, 6 | Config: {type: 'stdout'}, 7 | PlayerData: {type: 'stdout'}, 8 | MojangAPI: {type: 'stdout'}, 9 | Assets: {type: 'stdout'}, 10 | WriteJSON: {type: 'stdout'}, 11 | }, 12 | categories: { 13 | default: { 14 | appenders: ['Default'], 15 | level: 'info', 16 | }, 17 | }, 18 | }) 19 | 20 | export const Default = log4js.getLogger('Default') 21 | export const Config = log4js.getLogger('Config') 22 | export const PlayerData = log4js.getLogger('PlayerData') 23 | export const MojangAPI = log4js.getLogger('MojangAPI') 24 | export const Assets = log4js.getLogger('Assets') 25 | export const WriteJSON = log4js.getLogger('WriteJSON') 26 | -------------------------------------------------------------------------------- /src/progressbar.ts: -------------------------------------------------------------------------------- 1 | import Timeout = NodeJS.Timeout 2 | 3 | import Gauge from 'gauge' 4 | 5 | export default class ProgressBar { 6 | gauge: Gauge 7 | total: number 8 | completed: number 9 | startTime: number 10 | pulse: string 11 | timer?: Timeout 12 | 13 | constructor (total: number) { 14 | this.gauge = new Gauge() 15 | this.total = total 16 | this.completed = 0 17 | this.startTime = 0 18 | this.pulse = '' 19 | } 20 | 21 | tick (text: string): void { 22 | this.completed += 1 23 | this.gauge.show(text, this.completed / this.total) 24 | const now = (new Date()).valueOf() 25 | const avgTime = (now - this.startTime) / this.completed 26 | const time = Math.floor((this.total - this.completed) * avgTime / 1000) 27 | this.pulse = `${this.completed}/${this.total} ${time}s left` 28 | } 29 | 30 | start (): void { 31 | this.gauge.show() 32 | this.timer = setInterval(() => { 33 | this.gauge.pulse(this.pulse) 34 | }, 100) 35 | this.startTime = (new Date()).valueOf() 36 | } 37 | 38 | stop (): void { 39 | this.timer && clearInterval(this.timer) 40 | this.gauge.hide() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true, 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /tests/config.test.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | 3 | import loadConfig from '../src/config' 4 | 5 | describe('config', () => { 6 | const configPath = path.resolve(__dirname, './mocks/config.yml') 7 | const config = loadConfig(configPath) 8 | 9 | test('access config data via dot notation', () => { 10 | expect(config.render['server-dir']).toBe('/opt/minecraft') 11 | }) 12 | 13 | test('access config data via Config#get()', () => { 14 | expect(config.get(['render', 'server-dir'])).toBe('/opt/minecraft') 15 | expect(config.get('render.server-dir')).toBe('/opt/minecraft') 16 | }) 17 | 18 | test('Config#resolve() should resolve argument respecting config file location', () => { 19 | expect(config.resolve('file')).toBe(path.resolve(configPath, '../file')) 20 | expect(config.resolve('./file')).toBe(path.resolve(configPath, '../file')) 21 | expect(config.resolve('../file')).toBe(path.resolve(configPath, '../../file')) 22 | expect(config.resolve('/file')).toBe('/file') 23 | }) 24 | 25 | test('should return the same config object when calling loadConfig() again with same configPath', () => { 26 | expect(loadConfig(configPath)).toBe(config) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /tests/mocks/config.yml: -------------------------------------------------------------------------------- 1 | render: 2 | server-dir: /opt/minecraft 3 | render-banned: true 4 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | "allowJs": true, /* Allow javascript files to be compiled. */ 11 | "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | "rootDirs": [ /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | "." 49 | ], 50 | "typeRoots": [ /* List of folders to include type definitions from. */ 51 | "./typings", 52 | "./types" 53 | ], 54 | // "types": [], /* Type declaration files to be included in compilation. */ 55 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 56 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 57 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 58 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 59 | 60 | /* Source Map Options */ 61 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 62 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 63 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 64 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 65 | 66 | /* Experimental Options */ 67 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 68 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 69 | 70 | /* Advanced Options */ 71 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 72 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 73 | }, 74 | "include": [ 75 | "*.ts" 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /types/common.d.ts: -------------------------------------------------------------------------------- 1 | type Json = null | number | string | boolean | {[k: string]: Json} | Json[] 2 | -------------------------------------------------------------------------------- /types/minecraft.d.ts: -------------------------------------------------------------------------------- 1 | type LongUuid = string // "12345678-90ab-cdef-1234-567890abcdef" 2 | type ShortUuid = string // "1234567890abcdef1234567890abcdef" 3 | type Uuid = LongUuid | ShortUuid 4 | type PlayerName = string 5 | type UTCTimestamp = number 6 | type TickTime = number 7 | 8 | interface McWhitelistRecord { 9 | uuid: LongUuid 10 | name: PlayerName 11 | } 12 | 13 | type McWhitelistJson = McWhitelistRecord[] 14 | 15 | interface McBannedPlayerRecord { 16 | uuid: LongUuid 17 | name: string 18 | created: string 19 | source: string 20 | expires: string 21 | reason: string 22 | } 23 | 24 | type McBannedPlayersJson = McBannedPlayerRecord[] 25 | 26 | type McPlayerStatsJson = Json // FIXME: implement it 27 | 28 | type McPlayerAdvancementsJson = Json // FIXME: implement it 29 | 30 | interface McNameHistoryRecord { 31 | name: string 32 | changedToAt?: UTCTimestamp 33 | } 34 | 35 | type McNameHistory = McNameHistoryRecord[] 36 | 37 | interface McPlayerProfile { 38 | id: ShortUuid 39 | name: PlayerName 40 | legacy?: true 41 | properties: [ 42 | { 43 | name: 'textures' 44 | value: string 45 | signature?: string 46 | } 47 | ] 48 | } 49 | 50 | interface McPlayerTextures { 51 | timestamp: UTCTimestamp 52 | profileId: ShortUuid 53 | profileName: PlayerName 54 | signatureRequired?: true 55 | textures: { 56 | SKIN?: { 57 | url: string 58 | metadata?: { 59 | model: 'slim' 60 | } 61 | } 62 | CAPE?: { 63 | url: string 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /types/nyaa-stats.d.ts: -------------------------------------------------------------------------------- 1 | interface NSConfig { 2 | web: { 3 | title?: string 4 | servername?: string 5 | homepage?: string 6 | } 7 | render: { 8 | crafatar: string 9 | level: string 10 | playerdata: string 11 | stats: string 12 | advancements: string 13 | whitelist?: string 14 | 'banned-players'?: string 15 | 'render-banned'?: boolean 16 | output: string 17 | 'time-format': { 18 | full: string 19 | short: string 20 | compact: string 21 | } 22 | 'confirm-clear-data'?: boolean 23 | } 24 | api: { 25 | ratelimit: number 26 | } 27 | } 28 | 29 | interface NSPlayerStatsJson { 30 | stats: { 31 | // FIXME: not really correct 32 | [key: string]: number 33 | } 34 | stats_source: { 35 | [key: string]: number 36 | } 37 | advancements: { 38 | [key: string]: { 39 | criteria: { 40 | [condition: string]: string 41 | } 42 | done: boolean 43 | } 44 | } 45 | data: NSPlayerInfoData 46 | } 47 | 48 | interface NSPlayerNameHistoryRecord { 49 | name: PlayerName 50 | detectedAt: UTCTimestamp 51 | } 52 | 53 | interface NSPlayerInfoData { 54 | uuid: LongUuid 55 | uuid_short: ShortUuid 56 | seen?: UTCTimestamp 57 | time_start?: UTCTimestamp 58 | time_last?: UTCTimestamp 59 | time_lived?: number 60 | playername: PlayerName 61 | names: Array 62 | banned?: boolean 63 | lastUpdate: UTCTimestamp 64 | } 65 | -------------------------------------------------------------------------------- /typings/gauge/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'gauge' { 2 | class Gauge { 3 | show (status?: string | object | null, completed?: number): void 4 | 5 | hide (cb?: () => any): void 6 | 7 | pulse (subsection?: string): void 8 | } 9 | 10 | export = Gauge 11 | } 12 | -------------------------------------------------------------------------------- /typings/mcnbt/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'mcnbt' { 2 | class Tag { 3 | getValue (): unknown 4 | 5 | select (tagName: string): Tag 6 | } 7 | 8 | class NBT { 9 | loadFromZlibCompressedFile (filename: string, callback: (err: Nodejs.ErrnoException) => void): void 10 | 11 | select (tagName: string): Tag 12 | } 13 | 14 | export = NBT 15 | } 16 | -------------------------------------------------------------------------------- /web/.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | not ie <= 11 3 | -------------------------------------------------------------------------------- /web/.eslintrc.js: -------------------------------------------------------------------------------- 1 | const __PROD__ = process.env.NODE_ENV === 'production' 2 | 3 | module.exports = { 4 | root: true, 5 | extends: [ 6 | '../.eslintrc.js', 7 | 'plugin:vue/essential', 8 | 'plugin:vue/recommended', 9 | 'plugin:vue/strongly-recommended', 10 | ], 11 | parserOptions: { 12 | parser: 'babel-eslint', 13 | }, 14 | rules: { 15 | 'vue/max-attributes-per-line': [__PROD__ ? 'error' : 'warn', {singleline: 3}], 16 | 'vue/script-indent': [__PROD__ ? 'error' : 'warn', 2, {baseIndent: 1}], 17 | 'vue/singleline-html-element-content-newline': 'off', 18 | }, 19 | overrides: [ 20 | { 21 | files: ['*.vue'], 22 | rules: { 23 | indent: 'off', 24 | }, 25 | }, 26 | ], 27 | } 28 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # web 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /web/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'], 3 | } 4 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "serve": "vue-cli-service serve", 4 | "build": "vue-cli-service build --report", 5 | "lint": "vue-cli-service lint" 6 | }, 7 | "dependencies": { 8 | "axios": "^0.19.2", 9 | "core-js": "^3.6.5", 10 | "css-element-queries": "^1.2.3", 11 | "date-fns": "^2.14.0", 12 | "three": "^0.118.3", 13 | "velocity-animate": "^1.5.2", 14 | "vue": "^2.6.11", 15 | "vue-router": "^3.3.4", 16 | "vuex": "^3.4.0" 17 | }, 18 | "devDependencies": { 19 | "@tailwindcss/ui": "^0.3.0", 20 | "@vue/cli-plugin-babel": "^4.4.6", 21 | "@vue/cli-plugin-eslint": "^4.4.6", 22 | "@vue/cli-service": "^4.4.6", 23 | "babel-eslint": "^10.1.0", 24 | "eslint-plugin-vue": "^6.2.2", 25 | "node-fetch": "^2.6.0", 26 | "sass": "^1.26.9", 27 | "sass-loader": "^8.0.2", 28 | "tailwindcss": "^1.4.6", 29 | "vue-template-compiler": "^2.6.11" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /web/public/font/Inter-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Black.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Black.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-BlackItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-BlackItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-BlackItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Bold.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Bold.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-BoldItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-BoldItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraBold.woff -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraBold.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraBoldItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraLight.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraLight.woff -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraLight.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraLightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraLightItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-ExtraLightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ExtraLightItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Italic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Italic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Light.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Light.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-LightItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-LightItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Medium.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Medium.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-MediumItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-MediumItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-MediumItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Regular.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Regular.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-SemiBold.woff -------------------------------------------------------------------------------- /web/public/font/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-SemiBoldItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Thin.woff -------------------------------------------------------------------------------- /web/public/font/Inter-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-Thin.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-ThinItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ThinItalic.woff -------------------------------------------------------------------------------- /web/public/font/Inter-ThinItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-ThinItalic.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-italic.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-italic.var.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter-roman.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter-roman.var.woff2 -------------------------------------------------------------------------------- /web/public/font/Inter.var.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/public/font/Inter.var.woff2 -------------------------------------------------------------------------------- /web/public/font/inter.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Inter'; 3 | font-style: normal; 4 | font-weight: 100; 5 | font-display: swap; 6 | src: url("Inter-Thin.woff2?v=3.12") format("woff2"), 7 | url("Inter-Thin.woff?v=3.12") format("woff"); 8 | } 9 | @font-face { 10 | font-family: 'Inter'; 11 | font-style: italic; 12 | font-weight: 100; 13 | font-display: swap; 14 | src: url("Inter-ThinItalic.woff2?v=3.12") format("woff2"), 15 | url("Inter-ThinItalic.woff?v=3.12") format("woff"); 16 | } 17 | 18 | @font-face { 19 | font-family: 'Inter'; 20 | font-style: normal; 21 | font-weight: 200; 22 | font-display: swap; 23 | src: url("Inter-ExtraLight.woff2?v=3.12") format("woff2"), 24 | url("Inter-ExtraLight.woff?v=3.12") format("woff"); 25 | } 26 | @font-face { 27 | font-family: 'Inter'; 28 | font-style: italic; 29 | font-weight: 200; 30 | font-display: swap; 31 | src: url("Inter-ExtraLightItalic.woff2?v=3.12") format("woff2"), 32 | url("Inter-ExtraLightItalic.woff?v=3.12") format("woff"); 33 | } 34 | 35 | @font-face { 36 | font-family: 'Inter'; 37 | font-style: normal; 38 | font-weight: 300; 39 | font-display: swap; 40 | src: url("Inter-Light.woff2?v=3.12") format("woff2"), 41 | url("Inter-Light.woff?v=3.12") format("woff"); 42 | } 43 | @font-face { 44 | font-family: 'Inter'; 45 | font-style: italic; 46 | font-weight: 300; 47 | font-display: swap; 48 | src: url("Inter-LightItalic.woff2?v=3.12") format("woff2"), 49 | url("Inter-LightItalic.woff?v=3.12") format("woff"); 50 | } 51 | 52 | @font-face { 53 | font-family: 'Inter'; 54 | font-style: normal; 55 | font-weight: 400; 56 | font-display: swap; 57 | src: url("Inter-Regular.woff2?v=3.12") format("woff2"), 58 | url("Inter-Regular.woff?v=3.12") format("woff"); 59 | } 60 | @font-face { 61 | font-family: 'Inter'; 62 | font-style: italic; 63 | font-weight: 400; 64 | font-display: swap; 65 | src: url("Inter-Italic.woff2?v=3.12") format("woff2"), 66 | url("Inter-Italic.woff?v=3.12") format("woff"); 67 | } 68 | 69 | @font-face { 70 | font-family: 'Inter'; 71 | font-style: normal; 72 | font-weight: 500; 73 | font-display: swap; 74 | src: url("Inter-Medium.woff2?v=3.12") format("woff2"), 75 | url("Inter-Medium.woff?v=3.12") format("woff"); 76 | } 77 | @font-face { 78 | font-family: 'Inter'; 79 | font-style: italic; 80 | font-weight: 500; 81 | font-display: swap; 82 | src: url("Inter-MediumItalic.woff2?v=3.12") format("woff2"), 83 | url("Inter-MediumItalic.woff?v=3.12") format("woff"); 84 | } 85 | 86 | @font-face { 87 | font-family: 'Inter'; 88 | font-style: normal; 89 | font-weight: 600; 90 | font-display: swap; 91 | src: url("Inter-SemiBold.woff2?v=3.12") format("woff2"), 92 | url("Inter-SemiBold.woff?v=3.12") format("woff"); 93 | } 94 | @font-face { 95 | font-family: 'Inter'; 96 | font-style: italic; 97 | font-weight: 600; 98 | font-display: swap; 99 | src: url("Inter-SemiBoldItalic.woff2?v=3.12") format("woff2"), 100 | url("Inter-SemiBoldItalic.woff?v=3.12") format("woff"); 101 | } 102 | 103 | @font-face { 104 | font-family: 'Inter'; 105 | font-style: normal; 106 | font-weight: 700; 107 | font-display: swap; 108 | src: url("Inter-Bold.woff2?v=3.12") format("woff2"), 109 | url("Inter-Bold.woff?v=3.12") format("woff"); 110 | } 111 | @font-face { 112 | font-family: 'Inter'; 113 | font-style: italic; 114 | font-weight: 700; 115 | font-display: swap; 116 | src: url("Inter-BoldItalic.woff2?v=3.12") format("woff2"), 117 | url("Inter-BoldItalic.woff?v=3.12") format("woff"); 118 | } 119 | 120 | @font-face { 121 | font-family: 'Inter'; 122 | font-style: normal; 123 | font-weight: 800; 124 | font-display: swap; 125 | src: url("Inter-ExtraBold.woff2?v=3.12") format("woff2"), 126 | url("Inter-ExtraBold.woff?v=3.12") format("woff"); 127 | } 128 | @font-face { 129 | font-family: 'Inter'; 130 | font-style: italic; 131 | font-weight: 800; 132 | font-display: swap; 133 | src: url("Inter-ExtraBoldItalic.woff2?v=3.12") format("woff2"), 134 | url("Inter-ExtraBoldItalic.woff?v=3.12") format("woff"); 135 | } 136 | 137 | @font-face { 138 | font-family: 'Inter'; 139 | font-style: normal; 140 | font-weight: 900; 141 | font-display: swap; 142 | src: url("Inter-Black.woff2?v=3.12") format("woff2"), 143 | url("Inter-Black.woff?v=3.12") format("woff"); 144 | } 145 | @font-face { 146 | font-family: 'Inter'; 147 | font-style: italic; 148 | font-weight: 900; 149 | font-display: swap; 150 | src: url("Inter-BlackItalic.woff2?v=3.12") format("woff2"), 151 | url("Inter-BlackItalic.woff?v=3.12") format("woff"); 152 | } 153 | 154 | /* ------------------------------------------------------- 155 | Variable font. 156 | Usage: 157 | 158 | html { font-family: 'Inter', sans-serif; } 159 | @supports (font-variation-settings: normal) { 160 | html { font-family: 'Inter var', sans-serif; } 161 | } 162 | */ 163 | @font-face { 164 | font-family: 'Inter var'; 165 | font-weight: 100 900; 166 | font-display: swap; 167 | font-style: normal; 168 | font-named-instance: 'Regular'; 169 | src: url("Inter-roman.var.woff2?v=3.12") format("woff2"); 170 | } 171 | @font-face { 172 | font-family: 'Inter var'; 173 | font-weight: 100 900; 174 | font-display: swap; 175 | font-style: italic; 176 | font-named-instance: 'Italic'; 177 | src: url("Inter-italic.var.woff2?v=3.12") format("woff2"); 178 | } 179 | 180 | 181 | /* -------------------------------------------------------------------------- 182 | [EXPERIMENTAL] Multi-axis, single variable font. 183 | 184 | Slant axis is not yet widely supported (as of February 2019) and thus this 185 | multi-axis single variable font is opt-in rather than the default. 186 | 187 | When using this, you will probably need to set font-variation-settings 188 | explicitly, e.g. 189 | 190 | * { font-variation-settings: "slnt" 0deg } 191 | .italic { font-variation-settings: "slnt" 10deg } 192 | 193 | */ 194 | @font-face { 195 | font-family: 'Inter var experimental'; 196 | font-weight: 100 900; 197 | font-display: swap; 198 | font-style: oblique 0deg 10deg; 199 | src: url("Inter.var.woff2?v=3.12") format("woff2"); 200 | } 201 | -------------------------------------------------------------------------------- /web/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | NyaaStats 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /web/src/app.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 53 | 54 | 67 | -------------------------------------------------------------------------------- /web/src/assets/achievements/InvSprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/InvSprite.png -------------------------------------------------------------------------------- /web/src/assets/achievements/acquireIron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/acquireIron.png -------------------------------------------------------------------------------- /web/src/assets/achievements/bakeCake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/bakeCake.png -------------------------------------------------------------------------------- /web/src/assets/achievements/blazeRod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/blazeRod.png -------------------------------------------------------------------------------- /web/src/assets/achievements/bookcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/bookcase.png -------------------------------------------------------------------------------- /web/src/assets/achievements/breedCow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/breedCow.png -------------------------------------------------------------------------------- /web/src/assets/achievements/buildBetterPickaxe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/buildBetterPickaxe.png -------------------------------------------------------------------------------- /web/src/assets/achievements/buildFurnace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/buildFurnace.png -------------------------------------------------------------------------------- /web/src/assets/achievements/buildHoe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/buildHoe.png -------------------------------------------------------------------------------- /web/src/assets/achievements/buildPickaxe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/buildPickaxe.png -------------------------------------------------------------------------------- /web/src/assets/achievements/buildSword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/buildSword.png -------------------------------------------------------------------------------- /web/src/assets/achievements/buildWorkBench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/buildWorkBench.png -------------------------------------------------------------------------------- /web/src/assets/achievements/cookFish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/cookFish.png -------------------------------------------------------------------------------- /web/src/assets/achievements/diamonds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/diamonds.png -------------------------------------------------------------------------------- /web/src/assets/achievements/diamondsToYou.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/diamondsToYou.png -------------------------------------------------------------------------------- /web/src/assets/achievements/enchantments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/enchantments.png -------------------------------------------------------------------------------- /web/src/assets/achievements/exploreAllBiomes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/exploreAllBiomes.png -------------------------------------------------------------------------------- /web/src/assets/achievements/flyPig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/flyPig.png -------------------------------------------------------------------------------- /web/src/assets/achievements/fullBeacon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/fullBeacon.png -------------------------------------------------------------------------------- /web/src/assets/achievements/ghast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/ghast.png -------------------------------------------------------------------------------- /web/src/assets/achievements/index.js: -------------------------------------------------------------------------------- 1 | export const InvSprite = require('./InvSprite.png') 2 | export const acquireIron = require('./acquireIron.png') 3 | export const bakeCake = require('./bakeCake.png') 4 | export const blazeRod = require('./blazeRod.png') 5 | export const bookcase = require('./bookcase.png') 6 | export const breedCow = require('./breedCow.png') 7 | export const buildBetterPickaxe = require('./buildBetterPickaxe.png') 8 | export const buildFurnace = require('./buildFurnace.png') 9 | export const buildHoe = require('./buildHoe.png') 10 | export const buildPickaxe = require('./buildPickaxe.png') 11 | export const buildSword = require('./buildSword.png') 12 | export const buildWorkBench = require('./buildWorkBench.png') 13 | export const cookFish = require('./cookFish.png') 14 | export const diamonds = require('./diamonds.png') 15 | export const diamondsToYou = require('./diamondsToYou.png') 16 | export const enchantments = require('./enchantments.png') 17 | export const exploreAllBiomes = require('./exploreAllBiomes.png') 18 | export const flyPig = require('./flyPig.png') 19 | export const fullBeacon = require('./fullBeacon.png') 20 | export const ghast = require('./ghast.png') 21 | export const index = require('./index.js') 22 | export const killCow = require('./killCow.png') 23 | export const killEnemy = require('./killEnemy.png') 24 | export const killWither = require('./killWither.png') 25 | export const makeBread = require('./makeBread.png') 26 | export const mineWood = require('./mineWood.png') 27 | export const onARail = require('./onARail.png') 28 | export const openInventory = require('./openInventory.png') 29 | export const overkill = require('./overkill.png') 30 | export const overpowered = require('./overpowered.png') 31 | export const portal = require('./portal.png') 32 | export const potion = require('./potion.png') 33 | export const snipeSkeleton = require('./snipeSkeleton.png') 34 | export const spawnWither = require('./spawnWither.png') 35 | export const theEnd = require('./theEnd.png') 36 | export const theEnd2 = require('./theEnd2.png') 37 | -------------------------------------------------------------------------------- /web/src/assets/achievements/killCow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/killCow.png -------------------------------------------------------------------------------- /web/src/assets/achievements/killEnemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/killEnemy.png -------------------------------------------------------------------------------- /web/src/assets/achievements/killWither.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/killWither.png -------------------------------------------------------------------------------- /web/src/assets/achievements/makeBread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/makeBread.png -------------------------------------------------------------------------------- /web/src/assets/achievements/mineWood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/mineWood.png -------------------------------------------------------------------------------- /web/src/assets/achievements/onARail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/onARail.png -------------------------------------------------------------------------------- /web/src/assets/achievements/openInventory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/openInventory.png -------------------------------------------------------------------------------- /web/src/assets/achievements/overkill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/overkill.png -------------------------------------------------------------------------------- /web/src/assets/achievements/overpowered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/overpowered.png -------------------------------------------------------------------------------- /web/src/assets/achievements/portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/portal.png -------------------------------------------------------------------------------- /web/src/assets/achievements/potion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/potion.png -------------------------------------------------------------------------------- /web/src/assets/achievements/snipeSkeleton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/snipeSkeleton.png -------------------------------------------------------------------------------- /web/src/assets/achievements/spawnWither.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/spawnWither.png -------------------------------------------------------------------------------- /web/src/assets/achievements/theEnd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/theEnd.png -------------------------------------------------------------------------------- /web/src/assets/achievements/theEnd2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/achievements/theEnd2.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/adventuring_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/adventuring_time.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/arbalistic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/arbalistic.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/avoid_vibration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/avoid_vibration.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/blowback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/blowback.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/brush_armadillo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/brush_armadillo.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/bullseye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/bullseye.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/craft_decorated_pot_using_only_sherds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/craft_decorated_pot_using_only_sherds.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/crafters_crafting_crafters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/crafters_crafting_crafters.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/fall_from_world_height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/fall_from_world_height.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/hero_of_the_village.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/hero_of_the_village.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/honey_block_slide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/honey_block_slide.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export const adventuring_time = require('./adventuring_time.png'); 3 | export const arbalistic = require('./arbalistic.png'); 4 | export const avoid_vibration = require('./avoid_vibration.png'); 5 | export const blowback = require('./blowback.png'); 6 | export const bullseye = require('./bullseye.png'); 7 | export const brush_armadillo = require('./brush_armadillo.png'); 8 | export const craft_decorated_pot_using_only_sherds = require('./craft_decorated_pot_using_only_sherds.png'); 9 | export const crafters_crafting_crafters = require('./crafters_crafting_crafters.png'); 10 | export const fall_from_world_height = require('./fall_from_world_height.png'); 11 | export const hero_of_the_village = require('./hero_of_the_village.png'); 12 | export const honey_block_slide = require('./honey_block_slide.png'); 13 | export const kill_a_mob = require('./kill_a_mob.png'); 14 | export const kill_all_mobs = require('./kill_all_mobs.png'); 15 | export const kill_mob_near_sculk_catalyst = require('./kill_mob_near_sculk_catalyst.png'); 16 | export const lighten_up = require('./lighten_up.png'); 17 | export const lightning_rod_with_villager_no_fire = require('./lightning_rod_with_villager_no_fire.png'); 18 | export const minecraft_trials_edition = require('./minecraft_trials_edition.png'); 19 | export const ol_betsy = require('./ol_betsy.png'); 20 | export const overoverkill = require('./overoverkill.png'); 21 | export const play_jukebox_in_meadows = require('./play_jukebox_in_meadows.png'); 22 | export const read_power_of_chiseled_bookshelf = require('./read_power_of_chiseled_bookshelf.png'); 23 | export const revaulting = require('./revaulting.png'); 24 | export const root = require('./root.png'); 25 | export const salvage_sherd = require('./salvage_sherd.png'); 26 | export const shoot_arrow = require('./shoot_arrow.png'); 27 | export const sleep_in_bed = require('./sleep_in_bed.png'); 28 | export const sniper_duel = require('./sniper_duel.png'); 29 | export const spyglass_at_dragon = require('./spyglass_at_dragon.png'); 30 | export const spyglass_at_ghast = require('./spyglass_at_ghast.png'); 31 | export const spyglass_at_parrot = require('./spyglass_at_parrot.png'); 32 | export const summon_iron_golem = require('./summon_iron_golem.png'); 33 | export const throw_trident = require('./throw_trident.png'); 34 | export const totem_of_undying = require('./totem_of_undying.png'); 35 | export const trade = require('./trade.png'); 36 | export const trade_at_world_height = require('./trade_at_world_height.png'); 37 | export const trim_with_all_exclusive_armor_patterns = require('./trim_with_all_exclusive_armor_patterns.png'); 38 | export const trim_with_any_armor_pattern = require('./trim_with_any_armor_pattern.png'); 39 | export const two_birds_one_arrow = require('./two_birds_one_arrow.png'); 40 | export const very_very_frightening = require('./very_very_frightening.png'); 41 | export const voluntary_exile = require('./voluntary_exile.png'); 42 | export const walk_on_powder_snow_with_leather_boots = require('./walk_on_powder_snow_with_leather_boots.png'); 43 | export const who_needs_rockets = require('./who_needs_rockets.png'); 44 | export const whos_the_pillager_now = require('./whos_the_pillager_now.png'); 45 | export const under_lock_and_key = require('./under_lock_and_key.png'); -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/kill_a_mob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/kill_a_mob.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/kill_all_mobs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/kill_all_mobs.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/kill_mob_near_sculk_catalyst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/kill_mob_near_sculk_catalyst.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/lighten_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/lighten_up.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/lightning_rod_with_villager_no_fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/lightning_rod_with_villager_no_fire.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/minecraft_trials_edition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/minecraft_trials_edition.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/ol_betsy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/ol_betsy.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/overoverkill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/overoverkill.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/play_jukebox_in_meadows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/play_jukebox_in_meadows.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/read_power_of_chiseled_bookshelf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/read_power_of_chiseled_bookshelf.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/revaulting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/revaulting.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/root.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/salvage_sherd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/salvage_sherd.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/shoot_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/shoot_arrow.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/sleep_in_bed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/sleep_in_bed.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/sniper_duel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/sniper_duel.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/spyglass_at_dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/spyglass_at_dragon.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/spyglass_at_ghast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/spyglass_at_ghast.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/spyglass_at_parrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/spyglass_at_parrot.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/summon_iron_golem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/summon_iron_golem.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/throw_trident.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/throw_trident.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/totem_of_undying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/totem_of_undying.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/trade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/trade.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/trade_at_world_height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/trade_at_world_height.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/trim_with_all_exclusive_armor_patterns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/trim_with_all_exclusive_armor_patterns.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/trim_with_any_armor_pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/trim_with_any_armor_pattern.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/two_birds_one_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/two_birds_one_arrow.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/under_lock_and_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/under_lock_and_key.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/very_very_frightening.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/very_very_frightening.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/voluntary_exile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/voluntary_exile.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/walk_on_powder_snow_with_leather_boots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/walk_on_powder_snow_with_leather_boots.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/who_needs_rockets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/who_needs_rockets.png -------------------------------------------------------------------------------- /web/src/assets/advancements/adventure/whos_the_pillager_now.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/adventure/whos_the_pillager_now.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/dragon_breath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/dragon_breath.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/dragon_egg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/dragon_egg.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/elytra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/elytra.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/enter_end_gateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/enter_end_gateway.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/find_end_city.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/find_end_city.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export const dragon_breath = require('./dragon_breath.png'); 3 | export const dragon_egg = require('./dragon_egg.png'); 4 | export const elytra = require('./elytra.png'); 5 | export const enter_end_gateway = require('./enter_end_gateway.png'); 6 | export const find_end_city = require('./find_end_city.png'); 7 | export const kill_dragon = require('./kill_dragon.png'); 8 | export const levitate = require('./levitate.png'); 9 | export const respawn_dragon = require('./respawn_dragon.gif'); 10 | export const root = require('./root.png'); -------------------------------------------------------------------------------- /web/src/assets/advancements/end/kill_dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/kill_dragon.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/levitate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/levitate.png -------------------------------------------------------------------------------- /web/src/assets/advancements/end/respawn_dragon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/respawn_dragon.gif -------------------------------------------------------------------------------- /web/src/assets/advancements/end/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/end/root.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/allay_deliver_cake_to_note_block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/allay_deliver_cake_to_note_block.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/allay_deliver_item_to_player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/allay_deliver_item_to_player.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/axolotl_in_a_bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/axolotl_in_a_bucket.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/balanced_diet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/balanced_diet.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/bred_all_animals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/bred_all_animals.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/breed_an_animal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/breed_an_animal.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/complete_catalogue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/complete_catalogue.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/feed_snifflet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/feed_snifflet.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/fishy_business.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/fishy_business.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/froglights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/froglights.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export const allay_deliver_cake_to_note_block = require('./allay_deliver_cake_to_note_block.png'); 3 | export const allay_deliver_item_to_player = require('./allay_deliver_item_to_player.png'); 4 | export const axolotl_in_a_bucket = require('./axolotl_in_a_bucket.png'); 5 | export const balanced_diet = require('./balanced_diet.png'); 6 | export const bred_all_animals = require('./bred_all_animals.png'); 7 | export const breed_an_animal = require('./breed_an_animal.png'); 8 | export const complete_catalogue = require('./complete_catalogue.png'); 9 | export const feed_snifflet = require('./feed_snifflet.png'); 10 | export const fishy_business = require('./fishy_business.png'); 11 | export const froglights = require('./froglights.png'); 12 | export const kill_axolotl_target = require('./kill_axolotl_target.png'); 13 | export const leash_all_frog_variants = require('./leash_all_frog_variants.png'); 14 | export const make_a_sign_glow = require('./make_a_sign_glow.png'); 15 | export const obtain_netherite_hoe = require('./obtain_netherite_hoe.png'); 16 | export const obtain_sniffer_egg = require('./obtain_sniffer_egg.png'); 17 | export const plant_any_sniffer_seed = require('./plant_any_sniffer_seed.png'); 18 | export const plant_seed = require('./plant_seed.png'); 19 | export const remove_wolf_armor = require('./remove_wolf_armor.png'); 20 | export const repair_wolf_armor = require('./repair_wolf_armor.png'); 21 | export const ride_a_boat_with_a_goat = require('./ride_a_boat_with_a_goat.png'); 22 | export const root = require('./root.png'); 23 | export const safely_harvest_honey = require('./safely_harvest_honey.png'); 24 | export const silk_touch_nest = require('./silk_touch_nest.png'); 25 | export const tactical_fishing = require('./tactical_fishing.png'); 26 | export const tadpole_in_a_bucket = require('./tadpole_in_a_bucket.png'); 27 | export const tame_an_animal = require('./tame_an_animal.png'); 28 | export const wax_off = require('./wax_off.png'); 29 | export const wax_on = require('./wax_on.png'); 30 | export const whole_pack = require('./whole_pack.png'); -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/kill_axolotl_target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/kill_axolotl_target.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/leash_all_frog_variants.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/leash_all_frog_variants.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/make_a_sign_glow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/make_a_sign_glow.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/obtain_netherite_hoe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/obtain_netherite_hoe.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/obtain_sniffer_egg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/obtain_sniffer_egg.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/plant_any_sniffer_seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/plant_any_sniffer_seed.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/plant_seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/plant_seed.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/remove_wolf_armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/remove_wolf_armor.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/repair_wolf_armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/repair_wolf_armor.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/ride_a_boat_with_a_goat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/ride_a_boat_with_a_goat.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/root.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/safely_harvest_honey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/safely_harvest_honey.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/silk_touch_nest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/silk_touch_nest.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/tactical_fishing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/tactical_fishing.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/tadpole_in_a_bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/tadpole_in_a_bucket.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/tame_an_animal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/tame_an_animal.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/wax_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/wax_off.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/wax_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/wax_on.png -------------------------------------------------------------------------------- /web/src/assets/advancements/husbandry/whole_pack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/husbandry/whole_pack.png -------------------------------------------------------------------------------- /web/src/assets/advancements/index.js: -------------------------------------------------------------------------------- 1 | import * as adventure from './adventure' 2 | import * as end from './end' 3 | import * as husbandry from './husbandry' 4 | import * as nether from './nether' 5 | import * as story from './story' 6 | 7 | export const advancements = { 8 | adventure, 9 | end, 10 | husbandry, 11 | nether, 12 | story, 13 | } 14 | 15 | export default advancements 16 | -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/all_effects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/all_effects.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/all_potions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/all_potions.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/brew_potion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/brew_potion.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/charge_respawn_anchor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/charge_respawn_anchor.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/create_beacon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/create_beacon.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/create_full_beacon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/create_full_beacon.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/distract_piglin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/distract_piglin.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/explore_nether.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/explore_nether.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/fast_travel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/fast_travel.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/find_bastion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/find_bastion.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/find_fortress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/find_fortress.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/get_wither_skull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/get_wither_skull.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export const all_effects = require('./all_effects.png'); 3 | export const all_potions = require('./all_potions.png'); 4 | export const brew_potion = require('./brew_potion.png'); 5 | export const charge_respawn_anchor = require('./charge_respawn_anchor.png'); 6 | export const create_beacon = require('./create_beacon.png'); 7 | export const create_full_beacon = require('./create_full_beacon.png'); 8 | export const distract_piglin = require('./distract_piglin.png'); 9 | export const explore_nether = require('./explore_nether.png'); 10 | export const fast_travel = require('./fast_travel.png'); 11 | export const find_bastion = require('./find_bastion.png'); 12 | export const find_fortress = require('./find_fortress.png'); 13 | export const get_wither_skull = require('./get_wither_skull.png'); 14 | export const loot_bastion = require('./loot_bastion.png'); 15 | export const netherite_armor = require('./netherite_armor.png'); 16 | export const obtain_ancient_debris = require('./obtain_ancient_debris.png'); 17 | export const obtain_blaze_rod = require('./obtain_blaze_rod.png'); 18 | export const obtain_crying_obsidian = require('./obtain_crying_obsidian.png'); 19 | export const return_to_sender = require('./return_to_sender.png'); 20 | export const ride_strider = require('./ride_strider.png'); 21 | export const ride_strider_in_overworld_lava = require('./ride_strider_in_overworld_lava.png'); 22 | export const root = require('./root.png'); 23 | export const summon_wither = require('./summon_wither.gif'); 24 | export const uneasy_alliance = require('./uneasy_alliance.png'); 25 | export const use_lodestone = require('./use_lodestone.png'); -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/loot_bastion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/loot_bastion.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/netherite_armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/netherite_armor.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/obtain_ancient_debris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/obtain_ancient_debris.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/obtain_blaze_rod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/obtain_blaze_rod.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/obtain_crying_obsidian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/obtain_crying_obsidian.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/return_to_sender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/return_to_sender.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/ride_strider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/ride_strider.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/ride_strider_in_overworld_lava.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/ride_strider_in_overworld_lava.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/root.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/summon_wither.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/summon_wither.gif -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/uneasy_alliance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/uneasy_alliance.png -------------------------------------------------------------------------------- /web/src/assets/advancements/nether/use_lodestone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/nether/use_lodestone.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/cure_zombie_villager.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/cure_zombie_villager.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/deflect_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/deflect_arrow.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/enchant_item.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/enchant_item.gif -------------------------------------------------------------------------------- /web/src/assets/advancements/story/enter_the_end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/enter_the_end.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/enter_the_nether.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/enter_the_nether.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/follow_ender_eye.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/follow_ender_eye.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/form_obsidian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/form_obsidian.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export const cure_zombie_villager = require('./cure_zombie_villager.png'); 3 | export const deflect_arrow = require('./deflect_arrow.png'); 4 | export const enchant_item = require('./enchant_item.gif'); 5 | export const enter_the_end = require('./enter_the_end.png'); 6 | export const enter_the_nether = require('./enter_the_nether.png'); 7 | export const follow_ender_eye = require('./follow_ender_eye.png'); 8 | export const form_obsidian = require('./form_obsidian.png'); 9 | export const iron_tools = require('./iron_tools.png'); 10 | export const lava_bucket = require('./lava_bucket.png'); 11 | export const mine_diamond = require('./mine_diamond.png'); 12 | export const mine_stone = require('./mine_stone.png'); 13 | export const obtain_armor = require('./obtain_armor.png'); 14 | export const root = require('./root.png'); 15 | export const shiny_gear = require('./shiny_gear.png'); 16 | export const smelt_iron = require('./smelt_iron.png'); 17 | export const upgrade_tools = require('./upgrade_tools.png'); -------------------------------------------------------------------------------- /web/src/assets/advancements/story/iron_tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/iron_tools.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/lava_bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/lava_bucket.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/mine_diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/mine_diamond.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/mine_stone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/mine_stone.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/obtain_armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/obtain_armor.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/root.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/root.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/shiny_gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/shiny_gear.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/smelt_iron.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/smelt_iron.png -------------------------------------------------------------------------------- /web/src/assets/advancements/story/upgrade_tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/advancements/story/upgrade_tools.png -------------------------------------------------------------------------------- /web/src/assets/base.scss: -------------------------------------------------------------------------------- 1 | /*! purgecss start ignore */ 2 | @tailwind base; 3 | 4 | html { 5 | font-size: 16px; 6 | } 7 | 8 | button, input { 9 | &:focus { 10 | @apply outline-none; 11 | } 12 | } 13 | 14 | svg { 15 | @apply fill-current; 16 | } 17 | 18 | @tailwind components; 19 | 20 | // TODO: Not useful, remove it 21 | .page-section { 22 | @apply px-4; 23 | 24 | @screen md { 25 | @apply px-5; 26 | } 27 | 28 | @screen xl { 29 | @apply w-page px-0 mx-auto; 30 | } 31 | } 32 | /*! purgecss end ignore */ 33 | 34 | @tailwind utilities; 35 | 36 | .px-page { 37 | @apply px-4; 38 | 39 | @screen md { 40 | @apply px-5; 41 | } 42 | 43 | @screen xl { 44 | @apply px-0; 45 | } 46 | } 47 | 48 | .font-tnum { 49 | font-feature-settings: "tnum"; 50 | } 51 | 52 | .image-pixelated { 53 | image-rendering: pixelated; 54 | } 55 | -------------------------------------------------------------------------------- /web/src/assets/bg-wool-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NyaaCat/NyaaStats/856a8bca7ecabaf45c032134e6b59773f5ad3973/web/src/assets/bg-wool-dark.png -------------------------------------------------------------------------------- /web/src/common/utils.js: -------------------------------------------------------------------------------- 1 | import {format as dfFormat, parse as dfParse} from 'date-fns' 2 | 3 | /** 4 | * Parse date string from stats data 5 | * 6 | * @param {String} dateStr 7 | * @return {Date} 8 | */ 9 | export function parseDate (dateStr) { 10 | return dfParse(dateStr, 'yyyy-MM-dd HH:mm:ss xx', new Date()) 11 | } 12 | 13 | /** 14 | * Normalize date format 15 | * 16 | * @param {Date | String | Number} date 17 | * @param {"long" | "short"} [format="long"] 18 | * @return {String} 19 | */ 20 | export function normalizeDate (date, format = 'long') { 21 | if (typeof date === 'string') { 22 | date = parseDate(date) 23 | } 24 | format = { 25 | long: 'yyyy-MM-dd HH:mm:ss', 26 | short: 'yyyy-MM-dd', 27 | }[format] 28 | return dfFormat(date, format) 29 | } 30 | 31 | /** 32 | * Get user agent scrollbar's width (in pixel) 33 | * 34 | * @return {Number} 35 | */ 36 | export function getScrollbarWidth () { 37 | const content = document.createElement('div') 38 | content.setAttribute('style', 'height: 10px;') 39 | const wrapper = document.createElement('div') 40 | wrapper.setAttribute('style', 'width: 100%; height: 0; position: fixed; left: 0; bottom: 0; visibility: hidden; overflow: scroll;') 41 | wrapper.append(content) 42 | document.body.append(wrapper) 43 | const scrollbarWidth = wrapper.offsetWidth - content.offsetWidth 44 | document.body.removeChild(wrapper) 45 | return scrollbarWidth 46 | } 47 | 48 | /** 49 | * Create retina-friendly image (as DataURL) 50 | * 51 | * @param pixelMap {Array>} 52 | * @param colorMap {Object<*, [Number, Number, Number, ?Number]>} 53 | * @param scale {Number=1} 54 | * @return {String} 55 | */ 56 | export function createImage (pixelMap, colorMap, scale = 1) { 57 | const width = pixelMap[0].length 58 | const height = pixelMap.length 59 | 60 | const canvas = document.createElement('canvas') 61 | Object.assign(canvas, {width, height}) 62 | 63 | const ctx = canvas.getContext('2d') 64 | const imageData = ctx.createImageData(width, height) 65 | 66 | pixelMap.flat().forEach((ci, idx) => { 67 | if (!ci) return 68 | 69 | const i = idx * 4 70 | const color = colorMap[ci] 71 | if (color) { 72 | imageData.data[i ] = color[0] 73 | imageData.data[i + 1] = color[1] 74 | imageData.data[i + 2] = color[2] 75 | imageData.data[i + 3] = color[3] ?? 255 76 | } 77 | }) 78 | ctx.putImageData(imageData, 0, 0) 79 | 80 | return (devicePixelRatio * scale > 1 ? scaleImage(canvas, devicePixelRatio * scale) : canvas).toDataURL() 81 | } 82 | 83 | /** 84 | * Scale an image without smoothing 85 | * 86 | * @param source {HTMLCanvasElement} 87 | * @param scale {Number} 88 | * @return {HTMLCanvasElement} 89 | */ 90 | function scaleImage (source, scale) { 91 | const canvas = document.createElement('canvas') 92 | canvas.width = source.width * scale 93 | canvas.height = source.height * scale 94 | 95 | const ctx = canvas.getContext('2d') 96 | ctx.imageSmoothingEnabled = false 97 | ctx.drawImage(source, 0, 0, source.width, source.height, 0, 0, canvas.width, canvas.height) 98 | 99 | return canvas 100 | } 101 | -------------------------------------------------------------------------------- /web/src/common/velocity.js: -------------------------------------------------------------------------------- 1 | import 'velocity-animate' 2 | 3 | HTMLElement.prototype.velocity = function (...args) { 4 | /* eslint-disable no-undef */ 5 | Velocity(this, ...args) 6 | } 7 | -------------------------------------------------------------------------------- /web/src/components/achievement-block.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 71 | -------------------------------------------------------------------------------- /web/src/components/advancement-gui.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 150 | 151 | 161 | -------------------------------------------------------------------------------- /web/src/components/advancement-icon.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 62 | -------------------------------------------------------------------------------- /web/src/components/advancement-info-panel.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 106 | 107 | 112 | -------------------------------------------------------------------------------- /web/src/components/advancement-title.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 94 | 95 | 112 | -------------------------------------------------------------------------------- /web/src/components/app-menu.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 124 | 125 | 136 | -------------------------------------------------------------------------------- /web/src/components/footer.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /web/src/components/form-switch.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 35 | -------------------------------------------------------------------------------- /web/src/components/modal-layer.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 93 | 94 | 111 | -------------------------------------------------------------------------------- /web/src/components/navbar.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 36 | 37 | 42 | -------------------------------------------------------------------------------- /web/src/components/player-advancement-panel.vue: -------------------------------------------------------------------------------- 1 | 71 | 72 | 194 | 195 | 222 | -------------------------------------------------------------------------------- /web/src/components/player-aside-panel.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 27 | -------------------------------------------------------------------------------- /web/src/components/player-avatar.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 24 | -------------------------------------------------------------------------------- /web/src/components/player-grid.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 30 | -------------------------------------------------------------------------------- /web/src/components/player-list.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 91 | -------------------------------------------------------------------------------- /web/src/components/player-name-history.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 62 | -------------------------------------------------------------------------------- /web/src/components/player-ore-graph.vue: -------------------------------------------------------------------------------- 1 | 100 | 101 | 194 | 195 | 214 | -------------------------------------------------------------------------------- /web/src/components/player-skin-renderer/helper.js: -------------------------------------------------------------------------------- 1 | export const TAU = 2 * Math.PI 2 | 3 | export function toCanvas (image, x, y, w, h) { 4 | x = (typeof x === 'undefined' ? 0 : x) 5 | y = (typeof y === 'undefined' ? 0 : y) 6 | w = (typeof w === 'undefined' ? image.width : w) 7 | h = (typeof h === 'undefined' ? image.height : h) 8 | const canvas = document.createElement('canvas') 9 | canvas.width = w 10 | canvas.height = h 11 | const ctx = canvas.getContext('2d') 12 | ctx.drawImage(image, x, y, w, h, 0, 0, w, h) 13 | return canvas 14 | } 15 | 16 | export function makeOpaque (image) { 17 | const canvas = toCanvas(image) 18 | const ctx = canvas.getContext('2d') 19 | const data = ctx.getImageData(0, 0, canvas.width, canvas.height) 20 | const pixels = data.data 21 | for (let p = 3; p < pixels.length; p += 4) { 22 | pixels[p] = 255 23 | } 24 | ctx.putImageData(data, 0, 0) 25 | return canvas 26 | } 27 | 28 | export function hasAlphaLayer (image) { 29 | const canvas = toCanvas(image) 30 | const ctx = canvas.getContext('2d') 31 | const data = ctx.getImageData(0, 0, canvas.width, canvas.height) 32 | const pixels = data.data 33 | for (let p = 3; p < pixels.length; p += 4) { 34 | if (pixels[p] !== 255) { 35 | return true 36 | } 37 | } 38 | return false 39 | } 40 | 41 | export function toRadians (d) { 42 | return d * (TAU / 360) 43 | } 44 | -------------------------------------------------------------------------------- /web/src/components/player-skin-renderer/index.js: -------------------------------------------------------------------------------- 1 | export {default as default} from './player-skin-renderer.vue' 2 | -------------------------------------------------------------------------------- /web/src/components/player-skin-renderer/player-skin-renderer.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 54 | -------------------------------------------------------------------------------- /web/src/components/player-statistic-panel.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 217 | -------------------------------------------------------------------------------- /web/src/components/search-box.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 87 | -------------------------------------------------------------------------------- /web/src/components/sliding-transition.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 71 | -------------------------------------------------------------------------------- /web/src/components/welcome.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 59 | -------------------------------------------------------------------------------- /web/src/composables/lang.js: -------------------------------------------------------------------------------- 1 | import langData from '@/assets/lang.json' 2 | import useLocalConfig from './local-config' 3 | 4 | const config = useLocalConfig() 5 | 6 | function t (key, ...args) { 7 | /** @type {String | undefined} */ 8 | const tmpl = langData[config.lang][key] 9 | return tmpl 10 | ? /%(?!=%)/.test(tmpl) 11 | ? tmpl.split('%s').reduce((result, part, idx) => result + args[idx - 1] + part) 12 | : tmpl 13 | : key 14 | } 15 | 16 | Object.defineProperty(t, 'lang', { 17 | get () { 18 | return config.lang 19 | }, 20 | }) 21 | 22 | export default function useLang () { 23 | return { 24 | lang: config.lang, 25 | t, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /web/src/composables/local-config.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | const StorageKey = { 4 | Lang: 'config_lang', 5 | ShowAllAdvancements: 'config_show_all_advancements', 6 | ShowLongStatistics: 'config_show_long_statistics', 7 | } 8 | 9 | function handleBooleanStorage (key, val) { 10 | if (val) localStorage.setItem(key, '1') 11 | else localStorage.removeItem(key) 12 | } 13 | 14 | const vm = new Vue({ 15 | data: { 16 | lang: localStorage.getItem(StorageKey.Lang) ?? 'zh_cn', 17 | showAllAdvancements: Boolean(+localStorage.getItem(StorageKey.ShowAllAdvancements)), 18 | showLongStatistics: Boolean(+localStorage.getItem(StorageKey.ShowLongStatistics)), 19 | }, 20 | 21 | watch: { 22 | lang (val) { 23 | localStorage.setItem(StorageKey.Lang, val) 24 | this.setLangAttr() 25 | }, 26 | showAllAdvancements: val => handleBooleanStorage(StorageKey.ShowAllAdvancements, val), 27 | showLongStatistics: val => handleBooleanStorage(StorageKey.ShowLongStatistics, val), 28 | }, 29 | 30 | created () { 31 | this.setLangAttr() 32 | }, 33 | 34 | methods: { 35 | setLangAttr () { 36 | document.documentElement.setAttribute('lang', {'zh_cn': 'cmn', 'en_us': 'en'}[this.lang]) 37 | }, 38 | }, 39 | }) 40 | 41 | export default function useLocalConfig () { 42 | return { 43 | get lang () {return vm.lang}, 44 | set lang (val) {vm.lang = val}, 45 | 46 | get showAllAdvancements () {return vm.showAllAdvancements}, 47 | set showAllAdvancements (val) {vm.showAllAdvancements = val}, 48 | 49 | get showLongStatistics () {return vm.showLongStatistics}, 50 | set showLongStatistics (val) {vm.showLongStatistics = val}, 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /web/src/composables/random-player.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import $store from '@/store' 4 | import $router from '@/router' 5 | 6 | const state = Vue.observable({ 7 | randomMode: false, 8 | }) 9 | 10 | function goRandom () { 11 | state.randomMode = true 12 | // TODO: Implement `usePlayerList` 13 | const idx = Math.floor(Math.random() * $store.state.playerList.length) 14 | $router.push('/player/' + $store.state.playerList[idx].uuid) 15 | } 16 | 17 | function stopRandom () { 18 | state.randomMode = false 19 | } 20 | 21 | export default function useRandomPlayer () { 22 | return { 23 | state, 24 | goRandom, 25 | stopRandom, 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /web/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import '@/assets/base.scss' 4 | import '@/common/velocity' 5 | import useLang from '@/composables/lang' 6 | import router from './router' 7 | import store from './store' 8 | import App from './app.vue' 9 | 10 | Vue.config.productionTip = false 11 | 12 | Vue.mixin({ 13 | computed: { 14 | t () { 15 | return useLang().t 16 | }, 17 | }, 18 | }) 19 | 20 | if (process.env.NODE_ENV === 'development') { 21 | Vue.mixin({ 22 | mounted () { 23 | this.$el.setAttribute?.( 24 | 'data-component-name', 25 | (this.$el.dataset.componentName ? this.$el.dataset.componentName + ' ' : '') + (this.$options.name ?? 'AnonymousComponent'), 26 | ) 27 | }, 28 | 29 | methods: { 30 | log: console.log, 31 | }, 32 | }) 33 | } 34 | 35 | /* eslint-disable no-new */ 36 | new Vue({ 37 | router, 38 | store, 39 | render: h => h(App), 40 | }).$mount('#app') 41 | -------------------------------------------------------------------------------- /web/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | import store from '../store' 5 | 6 | Vue.use(Router) 7 | 8 | const router = new Router({ 9 | mode: 'history', 10 | routes: [ 11 | { 12 | path: '/', 13 | component: () => import('../views/home.vue'), 14 | }, 15 | { 16 | path: '/player/:uuid', 17 | component: () => import('../views/player.vue'), 18 | }, 19 | // ...process.env.NODE_ENV === 'development' ? [{ 20 | // path: '/playground', 21 | // component: () => import('../views/playground.vue'), 22 | // }] : [], 23 | ], 24 | }) 25 | 26 | router.beforeResolve((to, from, next) => { 27 | store.commit('setFooterUpdateTime', null) 28 | next() 29 | }) 30 | 31 | export default router 32 | -------------------------------------------------------------------------------- /web/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import axios from 'axios' 4 | 5 | Vue.use(Vuex) 6 | 7 | const store = new Vuex.Store({ 8 | state: { 9 | info: { 10 | title: 'NyaaStats', 11 | servername: 'Minecraft Server', 12 | lastUpdate: 0, 13 | worldTime: 0, 14 | }, 15 | players: {}, 16 | playerList: [], 17 | keyword: '', 18 | 19 | footerUpdateTime: null, 20 | }, 21 | 22 | mutations: { 23 | setInfo (state, data) { 24 | state.info = data 25 | }, 26 | 27 | setPlayer (state, [uuid, data]) { 28 | Vue.set(state.players, uuid, data) 29 | }, 30 | 31 | setPlayerList (state, data) { 32 | state.playerList = data 33 | }, 34 | 35 | setKeyword (state, keyword) { 36 | state.keyword = keyword 37 | }, 38 | 39 | setFooterUpdateTime (state, value) { 40 | state.footerUpdateTime = value 41 | }, 42 | }, 43 | 44 | actions: { 45 | async fetchInfo ({commit}) { 46 | let data 47 | 48 | try { 49 | data = (await axios.get('/data/info.json')).data 50 | } catch (e) { 51 | console.error(e) 52 | return Promise.reject(e) 53 | } 54 | 55 | commit('setInfo', data) 56 | return data 57 | }, 58 | 59 | async fetchPlayers ({commit}) { 60 | let data 61 | 62 | try { 63 | data = (await axios.get('/data/players.json')).data 64 | } catch (e) { 65 | console.error(e) 66 | return Promise.reject(e) 67 | } 68 | 69 | commit('setPlayerList', data) 70 | return data 71 | }, 72 | 73 | async fetchStats ({commit}, uuid) { 74 | let data 75 | 76 | try { 77 | data = (await axios.get(`/data/${uuid}/stats.json`)).data 78 | } catch (e) { 79 | console.error(e) 80 | return Promise.reject(e) 81 | } 82 | 83 | commit('setPlayer', [uuid, data]) 84 | return data 85 | }, 86 | }, 87 | }) 88 | 89 | export default store 90 | -------------------------------------------------------------------------------- /web/src/views/Playground.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 72 | 73 | 84 | -------------------------------------------------------------------------------- /web/src/views/home.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 134 | -------------------------------------------------------------------------------- /web/src/views/player.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 145 | 146 | 163 | -------------------------------------------------------------------------------- /web/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: { 3 | extend: { 4 | colors: { 5 | mcgray: '#aaa', 6 | mcwhite: '#fff', 7 | }, 8 | fill: theme => ({ 9 | ...theme('colors'), 10 | }), 11 | spacing: { 12 | page: '1200px', 13 | header: '50px', 14 | text: '1em', 15 | 'text-icon': '1.2em', 16 | }, 17 | fontFamily: { 18 | sans: [ 19 | '-apple-system', 20 | 'Noto Sans', 21 | 'Helvetica Neue', 22 | 'Helvetica', 23 | 'Nimbus Sans L', 24 | 'Arial', 25 | 'Liberation Sans', 26 | 'PingFang SC', 27 | 'Hiragino Sans GB', 28 | 'Noto Sans CJK SC', 29 | 'Source Han Sans SC', 30 | 'Source Han Sans CN', 31 | 'Microsoft YaHei', 32 | 'Wenquanyi Micro Hei', 33 | 'WenQuanYi Zen Hei', 34 | 'ST Heiti', 35 | 'SimHei', 36 | 'WenQuanYi Zen Hei Sharp', 37 | 'sans-serif', 38 | ], 39 | }, 40 | }, 41 | }, 42 | variants: { 43 | borderWidth: ['responsive', 'first', 'last'], 44 | cursor: ['responsive', 'focus'], 45 | display: ['responsive', 'group-hover'], 46 | margin: ['responsive', 'first'], 47 | }, 48 | plugins: [ 49 | require('@tailwindcss/ui'), 50 | ], 51 | purge: [ 52 | './src/**/*.vue', 53 | './src/**/*.jsx', 54 | ], 55 | } 56 | -------------------------------------------------------------------------------- /web/vue.config.js: -------------------------------------------------------------------------------- 1 | const {resolve} = require('path') 2 | const fs = require('fs-extra') 3 | const fetch = require('node-fetch') 4 | const agent = process.env.NODE_ENV === 'development' && (process.env.https_proxy || process.env.http_proxy) 5 | ? require('https-proxy-agent')(process.env.https_proxy || process.env.http_proxy) 6 | : undefined 7 | 8 | const MOCK_DIR = resolve(__dirname, '../__mock__') 9 | 10 | module.exports = { 11 | devServer: { 12 | proxy: { 13 | '^/mojang-api': { 14 | target: 'https://api.mojang.com', 15 | pathRewrite: { 16 | '^/mojang-api/': '/', 17 | }, 18 | }, 19 | }, 20 | before (app) { 21 | app.get(/^\/data/, async ({path}, /** @type {express.response} */ res) => { 22 | const file = resolve(MOCK_DIR, './' + path) 23 | 24 | if (!fs.existsSync(file)) { 25 | await fetch('https://stats.craft.moe' + path, {agent}) 26 | .then(res => res.buffer()) 27 | .then(buffer => fs.outputFile(file, buffer)) 28 | } 29 | res.sendFile(file) 30 | }) 31 | 32 | app.get(/^\/skin/, ({path}, res) => { 33 | res.sendFile(resolve(__dirname, '..' + path)) 34 | }) 35 | }, 36 | }, 37 | } 38 | --------------------------------------------------------------------------------