#!/usr/bin/env ruby require "json" require "set" # Run with gen-stats.rb SERVER_DIR = ARGV[0] || "." ADVENTURE_BIOMES = [ "Beach", "Birch Forest", "Birch Forest Hills", "Cold Beach", "Cold Taiga", "Cold Taiga Hills", "Deep Ocean", "Desert", "DesertHills", "Extreme Hills", "Extreme Hills+", "Forest", "ForestHills", "FrozenRiver", "Ice Mountains", "Ice Plains", "Jungle", "JungleEdge", "JungleHills", "Mega Taiga", "Mega Taiga Hills", "Mesa", "Mesa Plateau", "Mesa Plateau F", "MushroomIsland", "MushroomIslandShore", "Ocean", "Plains", "River", "Roofed Forest", "Savanna", "Savanna Plateau", "Stone Beach", "Swampland", "Taiga", "TaigaHills", ] class GenStats def initialize @all_explored_biomes = [] end def run user_cache = JSON.load(File.read("#{SERVER_DIR}/usercache.json")) @users_by_uuid = user_cache.reduce({}) do |result, user| result[user["uuid"]] = user result end @all_stats = { "Play Time" => {}, "Achievements" => {}, "Unexplored Biomes" => {}, "Deaths" => {}, "Damage Dealt" => {}, "Damage Taken" => {}, "Mob Kills" => {}, "Killed" => {}, "Killed By" => {}, "Items Broken" => {}, "Enchant Item Count" => {}, "Animals Bred" => {}, "Foot Travel Distance" => {}, "Horse Travel Distance" => {}, "Boat Travel Distance" => {}, "Crouch Distance" => {}, "Climb Distance" => {}, "Fall Distance" => {}, "Walk Under Water Distance" => {}, "Walk On Water Distance" => {}, } Dir["#{SERVER_DIR}/world/stats/*.json"].each do |stats_fname| load_stats(stats_fname) end print_stats end private def load_stats(stats_fname) File.basename(stats_fname) =~ /^(.*)\.json/ user_name = if @users_by_uuid[$1] @users_by_uuid[$1]["name"] else $1 end stats_file = JSON.load(File.read(stats_fname)) stats = stats_file["stats"] || {} stats["minecraft:custom"] ||= {} @all_stats["Play Time"][user_name] = begin # stat is actually in ticks apparently minutes = (stats["minecraft:custom"]["minecraft:play_one_minute"] || 0) / 20 / 60 hours = (minutes / 60).floor minutes -= (hours * 60) days = (hours / 24).floor hours -= (days * 24) "#{days}d #{hours}h #{minutes}m" end # @all_stats["Achievements"][user_name] = # stats.find_all do |stat_name, stat_value| # stat_name.start_with?("achievement.") and (stat_value.is_a?(Integer) or (stat_value.is_a?(Hash) and stat_value["value"] and stat_value["value"] > 0)) # end.size # @all_stats["Unexplored Biomes"][user_name] = # if stats["achievement.exploreAllBiomes"] # explored_biomes = stats["achievement.exploreAllBiomes"]["progress"] # unexplored_biomes = ADVENTURE_BIOMES - explored_biomes # @all_explored_biomes += explored_biomes # unexplored_biomes.sort.join(", ") # end @all_stats["Deaths"][user_name] = stats["minecraft:custom"]["minecraft:deaths"] || 0 @all_stats["Damage Dealt"][user_name] = stats["minecraft:custom"]["minecraft:damage_dealt"] || 0 @all_stats["Damage Taken"][user_name] = stats["minecraft:custom"]["minecraft:damage_taken"] || 0 @all_stats["Mob Kills"][user_name] = stats["minecraft:custom"]["minecraft:mob_kills"] || 0 @all_stats["Killed"][user_name] = (stats["minecraft:killed"] || {}).reduce({}) do |result, (stat_name, stat_value)| if stat_name =~ /^minecraft:(\w+)$/ result[$1] = stat_value end result end @all_stats["Killed By"][user_name] = (stats["minecraft:killed_by"] || {}).reduce({}) do |result, (stat_name, stat_value)| if stat_name =~ /^minecraft:(\w+)$/ result[$1] = stat_value end result end @all_stats["Items Broken"][user_name] = (stats["minecraft:broken"] || {}).reduce({}) do |result, (stat_name, stat_value)| if stat_name =~ /^minecraft:(\w+)$/ result[$1] = stat_value end result end @all_stats["Enchant Item Count"][user_name] = stats["minecraft:custom"]["minecraft:enchant_item"] @all_stats["Animals Bred"][user_name] = stats["minecraft:custom"]["minecraft:animals_bred"] { "Foot Travel Distance" => ["sprint_one_cm", "walk_one_cm"], "Horse Travel Distance" => ["horse_one_cm"], "Boat Travel Distance" => ["boat_one_cm"], "Crouch Distance" => ["crouch_one_cm"], "Climb Distance" => ["climb_one_cm"], "Fall Distance" => ["fall_one_cm"], "Walk Under Water Distance" => ["walk_under_water_one_cm"], "Walk On Water Distance" => ["walk_on_water_one_cm"], }.each_pair do |stat_name, stat_fields| dist = stat_fields.reduce(0) do |result, stat_field| result + (stats["minecraft:custom"]["minecraft:#{stat_field}"] || 0) end # convert cm to m dist = (dist + 500) / 1000 @all_stats[stat_name][user_name] = dist end end def print_stats @all_stats.each do |stat_name, stats| next if stats.empty? puts "== #{stat_name} ==" if stats.first.last.is_a?(Hash) keys = stats.reduce([]) do |result, (player_name, stat_value)| result + stat_value.keys end.uniq.sort puts "|= Player |= #{keys.join(" |= ")}" stats.sort.each do |player_name, stat_value| values = keys.map do |key| stat_value[key] end puts "| #{player_name} | #{values.join(" | ")}" end else puts "|= Player |= Value" stats.sort.each do |player_name, stat_value| puts "| #{player_name} | #{stat_value}" end end puts if stat_name == "Unexplored Biomes" puts("Common Unexplored Biomes: " + (ADVENTURE_BIOMES - @all_explored_biomes).sort.join(", ")) puts end end end end GenStats.new.run