Created
July 2, 2025 01:19
-
-
Save AlphaGameDeveloper/e71cc4c5662e2a12be238b5ffd13355c to your computer and use it in GitHub Desktop.
Minecraft AutoTip mod dashboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import os | |
from datetime import datetime | |
from collections import defaultdict | |
# CHANGE THIS FOR YOUR GAME INSTANCE | |
path = "/path/to/your/.minecraft/config/autotip/(UUID)/stats" | |
""" | |
{ | |
"date": { | |
"year": 2025, | |
"month": 6, | |
"day": 23 | |
}, | |
"tipsSent": 27, | |
"tipsReceived": 30, | |
"xpSent": 1350, | |
"xpReceived": 1800, | |
"gameStatistics": { | |
"Turbo Kart Racers": { | |
"coinsSent": 45, | |
"coinsReceived": 400 | |
}, | |
"SkyWars": { | |
"coinsSent": 45, | |
"coinsReceived": 300 | |
}, | |
"Smash Heroes": { | |
"coinsSent": 45, | |
"coinsReceived": 100 | |
}, | |
"Mega Walls": { | |
"coinsSent": 45, | |
"coinsReceived": 200 | |
}, | |
"UHC Champions": { | |
"coinsSent": 30, | |
"coinsReceived": 200 | |
}, | |
"Warlords": { | |
"coinsSent": 30, | |
"coinsReceived": 300 | |
}, | |
"The Walls": { | |
"coinsSent": 45, | |
"coinsReceived": 400 | |
}, | |
"VampireZ": { | |
"coinsSent": 45, | |
"coinsReceived": 400 | |
}, | |
"Arcade Games": { | |
"coinsSent": 114, | |
"coinsReceived": 500 | |
}, | |
"Arena Brawl": { | |
"coinsSent": 45, | |
"coinsReceived": 400 | |
}, | |
"Blitz SG": { | |
"coinsSent": 45, | |
"coinsReceived": 300 | |
}, | |
"Quakecraft": { | |
"coinsSent": 45, | |
"coinsReceived": 400 | |
}, | |
"Paintball Warfare": { | |
"coinsSent": 45, | |
"coinsReceived": 400 | |
}, | |
"Cops and Crims": { | |
"coinsSent": 30, | |
"coinsReceived": 200 | |
} | |
} | |
} | |
""" | |
def load_stats(): | |
"""Load and process all autotip statistics from the directory.""" | |
stats = { | |
"TOTAL": { | |
"tips_sent": 0, | |
"tips_received": 0, | |
"xp_sent": 0, | |
"xp_received": 0, | |
"coins_sent": 0, | |
"coins_received": 0 | |
}, | |
"games": defaultdict(lambda: { | |
"coins_sent": 0, | |
"coins_received": 0 | |
}), | |
"daily_stats": [], | |
"files_processed": 0 | |
} | |
if not os.path.exists(path): | |
print(f"Error: Directory {path} does not exist!") | |
return stats | |
for file in os.listdir(path): | |
if ".at" not in file: | |
continue | |
try: | |
with open(os.path.join(path, file), "r") as f: | |
data = json.load(f) | |
stats["files_processed"] += 1 | |
# Process tips and XP | |
tips_sent = data.get("tipsSent", 0) | |
tips_received = data.get("tipsReceived", 0) | |
xp_sent = data.get("xpSent", 0) | |
xp_received = data.get("xpReceived", 0) | |
stats["TOTAL"]["tips_sent"] += tips_sent | |
stats["TOTAL"]["tips_received"] += tips_received | |
stats["TOTAL"]["xp_sent"] += xp_sent | |
stats["TOTAL"]["xp_received"] += xp_received | |
# Process game statistics | |
game_stats = data.get("gameStatistics", {}) | |
for game, game_data in game_stats.items(): | |
coins_sent = game_data.get("coinsSent", 0) | |
coins_received = game_data.get("coinsReceived", 0) | |
stats["games"][game]["coins_sent"] += coins_sent | |
stats["games"][game]["coins_received"] += coins_received | |
stats["TOTAL"]["coins_sent"] += coins_sent | |
stats["TOTAL"]["coins_received"] += coins_received | |
# Store daily stats | |
date_info = data.get("date", {}) | |
if date_info: | |
daily_stat = { | |
"date": f"{date_info.get('year', 0)}-{date_info.get('month', 0):02d}-{date_info.get('day', 0):02d}", | |
"tips_sent": tips_sent, | |
"tips_received": tips_received, | |
"xp_sent": xp_sent, | |
"xp_received": xp_received, | |
"total_coins_sent": sum(game_data.get("coinsSent", 0) for game_data in game_stats.values()), | |
"total_coins_received": sum(game_data.get("coinsReceived", 0) for game_data in game_stats.values()) | |
} | |
stats["daily_stats"].append(daily_stat) | |
except Exception as e: | |
print(f"Error processing file {file}: {e}") | |
# Sort daily stats by date | |
stats["daily_stats"].sort(key=lambda x: x["date"]) | |
return stats | |
def generate_html_report(stats): | |
"""Generate a fancy HTML report with all statistics.""" | |
# Calculate some interesting metrics | |
total_tips_ratio = (stats["TOTAL"]["tips_received"] / max(stats["TOTAL"]["tips_sent"], 1)) | |
total_xp_ratio = (stats["TOTAL"]["xp_received"] / max(stats["TOTAL"]["xp_sent"], 1)) | |
total_coins_ratio = (stats["TOTAL"]["coins_received"] / max(stats["TOTAL"]["coins_sent"], 1)) | |
# Find top games by coins received | |
top_games = sorted(stats["games"].items(), | |
key=lambda x: x[1]["coins_received"], | |
reverse=True)[:10] | |
html_content = f""" | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>๐ฎ Minecraft AutoTip Statistics Dashboard</title> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<style> | |
* {{ | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
}} | |
body {{ | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
min-height: 100vh; | |
color: #333; | |
}} | |
.container {{ | |
max-width: 1400px; | |
margin: 0 auto; | |
padding: 20px; | |
}} | |
.header {{ | |
text-align: center; | |
margin-bottom: 40px; | |
color: white; | |
}} | |
.header h1 {{ | |
font-size: 3em; | |
margin-bottom: 10px; | |
text-shadow: 2px 2px 4px rgba(0,0,0,0.3); | |
}} | |
.header p {{ | |
font-size: 1.2em; | |
opacity: 0.9; | |
}} | |
.stats-grid {{ | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
gap: 20px; | |
margin-bottom: 40px; | |
}} | |
.stat-card {{ | |
background: white; | |
border-radius: 15px; | |
padding: 25px; | |
box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
transition: transform 0.3s ease, box-shadow 0.3s ease; | |
}} | |
.stat-card:hover {{ | |
transform: translateY(-5px); | |
box-shadow: 0 15px 40px rgba(0,0,0,0.15); | |
}} | |
.stat-card h3 {{ | |
color: #4a5568; | |
margin-bottom: 15px; | |
font-size: 1.3em; | |
border-bottom: 2px solid #e2e8f0; | |
padding-bottom: 10px; | |
}} | |
.stat-value {{ | |
font-size: 2.5em; | |
font-weight: bold; | |
color: #2d3748; | |
margin-bottom: 5px; | |
}} | |
.stat-label {{ | |
color: #718096; | |
font-size: 0.9em; | |
}} | |
.ratio-positive {{ | |
color: #38a169; | |
}} | |
.ratio-negative {{ | |
color: #e53e3e; | |
}} | |
.games-section {{ | |
background: white; | |
border-radius: 15px; | |
padding: 30px; | |
margin-bottom: 40px; | |
box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
}} | |
.games-grid {{ | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); | |
gap: 15px; | |
margin-top: 20px; | |
}} | |
.game-card {{ | |
background: #f7fafc; | |
border-radius: 10px; | |
padding: 15px; | |
border-left: 4px solid #4299e1; | |
}} | |
.game-name {{ | |
font-weight: bold; | |
color: #2d3748; | |
margin-bottom: 8px; | |
}} | |
.game-stats {{ | |
display: flex; | |
justify-content: space-between; | |
font-size: 0.9em; | |
color: #4a5568; | |
}} | |
.chart-container {{ | |
background: white; | |
border-radius: 15px; | |
padding: 30px; | |
margin-bottom: 40px; | |
box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
}} | |
.progress-bar {{ | |
background: #e2e8f0; | |
border-radius: 10px; | |
height: 8px; | |
margin-top: 10px; | |
overflow: hidden; | |
}} | |
.progress-fill {{ | |
height: 100%; | |
background: linear-gradient(90deg, #4299e1, #3182ce); | |
border-radius: 10px; | |
transition: width 0.5s ease; | |
}} | |
.footer {{ | |
text-align: center; | |
color: white; | |
margin-top: 40px; | |
opacity: 0.8; | |
}} | |
.metric-highlight {{ | |
background: linear-gradient(135deg, #667eea, #764ba2); | |
color: white; | |
border-radius: 10px; | |
padding: 15px; | |
margin: 10px 0; | |
}} | |
@media (max-width: 768px) {{ | |
.header h1 {{ | |
font-size: 2em; | |
}} | |
.stats-grid {{ | |
grid-template-columns: 1fr; | |
}} | |
}} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="header"> | |
<h1>๐ฎ Minecraft AutoTip Dashboard</h1> | |
<p>Comprehensive Statistics Report</p> | |
<p>Generated on {datetime.now().strftime("%B %d, %Y at %I:%M %p")}</p> | |
</div> | |
<div class="stats-grid"> | |
<div class="stat-card"> | |
<h3>๐ฐ Tips Overview</h3> | |
<div class="stat-value">{stats["TOTAL"]["tips_received"]:,}</div> | |
<div class="stat-label">Tips Received</div> | |
<div class="stat-value" style="font-size: 1.5em; margin-top: 10px;">{stats["TOTAL"]["tips_sent"]:,}</div> | |
<div class="stat-label">Tips Sent</div> | |
<div class="metric-highlight"> | |
Ratio: <span class="{'ratio-positive' if total_tips_ratio > 1 else 'ratio-negative'}">{total_tips_ratio:.2f}x</span> | |
</div> | |
</div> | |
<div class="stat-card"> | |
<h3>โญ Experience Points</h3> | |
<div class="stat-value">{stats["TOTAL"]["xp_received"]:,}</div> | |
<div class="stat-label">XP Received</div> | |
<div class="stat-value" style="font-size: 1.5em; margin-top: 10px;">{stats["TOTAL"]["xp_sent"]:,}</div> | |
<div class="stat-label">XP Sent</div> | |
<div class="metric-highlight"> | |
Ratio: <span class="{'ratio-positive' if total_xp_ratio > 1 else 'ratio-negative'}">{total_xp_ratio:.2f}x</span> | |
</div> | |
</div> | |
<div class="stat-card"> | |
<h3>๐ช Coins Summary</h3> | |
<div class="stat-value">{stats["TOTAL"]["coins_received"]:,}</div> | |
<div class="stat-label">Coins Received</div> | |
<div class="stat-value" style="font-size: 1.5em; margin-top: 10px;">{stats["TOTAL"]["coins_sent"]:,}</div> | |
<div class="stat-label">Coins Sent</div> | |
<div class="metric-highlight"> | |
Ratio: <span class="{'ratio-positive' if total_coins_ratio > 1 else 'ratio-negative'}">{total_coins_ratio:.2f}x</span> | |
</div> | |
</div> | |
<div class="stat-card"> | |
<h3>๐ Data Summary</h3> | |
<div class="stat-value">{stats["files_processed"]}</div> | |
<div class="stat-label">Files Processed</div> | |
<div class="stat-value" style="font-size: 1.5em; margin-top: 10px;">{len(stats["daily_stats"])}</div> | |
<div class="stat-label">Days Tracked</div> | |
<div class="stat-value" style="font-size: 1.5em; margin-top: 10px;">{len(stats["games"])}</div> | |
<div class="stat-label">Games Played</div> | |
</div> | |
</div> | |
<div class="games-section"> | |
<h3>๐ฏ Top Games by Coins Received</h3> | |
<div class="games-grid">""" | |
# Add top games | |
for i, (game_name, game_data) in enumerate(top_games): | |
coins_ratio = game_data["coins_received"] / max(game_data["coins_sent"], 1) | |
max_coins = max(g[1]["coins_received"] for g in top_games) | |
progress_width = (game_data["coins_received"] / max_coins) * 100 if max_coins > 0 else 0 | |
html_content += f""" | |
<div class="game-card"> | |
<div class="game-name">#{i+1} {game_name}</div> | |
<div class="game-stats"> | |
<span>Received: {game_data["coins_received"]:,}</span> | |
<span>Sent: {game_data["coins_sent"]:,}</span> | |
</div> | |
<div class="game-stats"> | |
<span>Ratio: <span class="{'ratio-positive' if coins_ratio > 1 else 'ratio-negative'}">{coins_ratio:.2f}x</span></span> | |
</div> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: {progress_width}%"></div> | |
</div> | |
</div>""" | |
# Add daily stats chart if we have data | |
if stats["daily_stats"]: | |
dates = [stat["date"] for stat in stats["daily_stats"]] | |
tips_received = [stat["tips_received"] for stat in stats["daily_stats"]] | |
xp_received = [stat["xp_received"] for stat in stats["daily_stats"]] | |
html_content += f""" | |
</div> | |
</div> | |
<div class="chart-container"> | |
<h3>๐ Daily Trends</h3> | |
<canvas id="dailyChart" width="400" height="200"></canvas> | |
</div>""" | |
# Add JavaScript for charts | |
html_content += f""" | |
<div class="footer"> | |
<p>๐ฎ Keep gaming and spreading those tips! ๐ฎ</p> | |
<p>Data sourced from AutoTip statistics โข Last updated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p> | |
</div> | |
</div> | |
<script> | |
const ctx = document.getElementById('dailyChart').getContext('2d'); | |
const chart = new Chart(ctx, {{ | |
type: 'line', | |
data: {{ | |
labels: {dates}, | |
datasets: [{{ | |
label: 'Tips Received', | |
data: {tips_received}, | |
borderColor: '#4299e1', | |
backgroundColor: 'rgba(66, 153, 225, 0.1)', | |
tension: 0.4 | |
}}, {{ | |
label: 'XP Received', | |
data: {xp_received}, | |
borderColor: '#38a169', | |
backgroundColor: 'rgba(56, 161, 105, 0.1)', | |
tension: 0.4, | |
yAxisID: 'y1' | |
}}] | |
}}, | |
options: {{ | |
responsive: true, | |
interaction: {{ | |
mode: 'index', | |
intersect: false, | |
}}, | |
scales: {{ | |
x: {{ | |
display: true, | |
title: {{ | |
display: true, | |
text: 'Date' | |
}} | |
}}, | |
y: {{ | |
type: 'linear', | |
display: true, | |
position: 'left', | |
title: {{ | |
display: true, | |
text: 'Tips' | |
}} | |
}}, | |
y1: {{ | |
type: 'linear', | |
display: true, | |
position: 'right', | |
title: {{ | |
display: true, | |
text: 'XP' | |
}}, | |
grid: {{ | |
drawOnChartArea: false, | |
}}, | |
}} | |
}} | |
}} | |
}}); | |
</script>""" | |
else: | |
html_content += """ | |
</div> | |
</div> | |
<div class="footer"> | |
<p>๐ฎ Keep gaming and spreading those tips! ๐ฎ</p> | |
<p>Data sourced from AutoTip statistics โข Last updated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}</p> | |
</div> | |
</div>""" | |
return html_content | |
def main(): | |
print("๐ฎ Loading Minecraft AutoTip Statistics...") | |
stats = load_stats() | |
print(f"โ Processed {stats['files_processed']} files") | |
print(f"๐ Found data for {len(stats['daily_stats'])} days") | |
print(f"๐ฏ Tracked {len(stats['games'])} different games") | |
# Generate HTML report | |
print("๐จ Generating fancy HTML report...") | |
html_content = generate_html_report(stats) | |
# Save to /tmp | |
output_file = "/tmp/minecraft_autotip_dashboard.html" | |
with open(output_file, "w", encoding="utf-8") as f: | |
f.write(html_content) | |
print(f"๐พ Report saved to: {output_file}") | |
print("\n" + "="*50) | |
print("๐ SUMMARY STATISTICS") | |
print("="*50) | |
print(f"Tips: {stats['TOTAL']['tips_received']:,} received | {stats['TOTAL']['tips_sent']:,} sent") | |
print(f"XP: {stats['TOTAL']['xp_received']:,} received | {stats['TOTAL']['xp_sent']:,} sent") | |
print(f"Coins: {stats['TOTAL']['coins_received']:,} received | {stats['TOTAL']['coins_sent']:,} sent") | |
print("="*50) | |
return output_file | |
if __name__ == "__main__": | |
output_file = main() | |
os.system(f"open {output_file}") # Open the report in the default browser |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment