Skip to content

Instantly share code, notes, and snippets.

@AlphaGameDeveloper
Created July 2, 2025 01:19
Show Gist options
  • Save AlphaGameDeveloper/e71cc4c5662e2a12be238b5ffd13355c to your computer and use it in GitHub Desktop.
Save AlphaGameDeveloper/e71cc4c5662e2a12be238b5ffd13355c to your computer and use it in GitHub Desktop.
Minecraft AutoTip mod dashboard
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