Commit c6aa1fe9 authored by Marius Lindvall's avatar Marius Lindvall

Migration from code.varden.info

Migrated from https://code.varden.info/repo/TorchStats/
parent 0f4e8db9
The MIT License (MIT)
Copyright (c) 2014 Marius Lindvall
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# TorchStats
## What is it?
Have you ever been annoyed at having too few stats in Minecraft? It tells you stuff like how many blocks you've broken, and yeah, that's nice. But how much time have you really played? How much time have you spent on the main menu? Questions like these are what TorchStats answers.
**TorchStats is still an alpha project.** That means, it probably has a lot of bugs and missing features. However, when it's completed, I hope this will be a great addition to the already existing Minecraft statistics.
## Features
* Saves a lot of various parameters about gameplay to an NBT-based data file
* You can access these stats in the Statistics menu
* Uses an own window to display it's stats, for the best experience
* Select between two themes: Monster Cave and The Nether
## Screenshots
![Updated statistics menu](https://varden.info/image.php?sid=9&img=torchstats-general.png)
![TorchStats statistics window](https://varden.info/image.php?sid=9&img=torchstats-gui.png)
## Installation
1. Find the Minecraft jar file.
* In 1.6 and above, this is .minecraft\versions\<version>\<version>.jar
* In 1.5.2 and below, this is .minecraft\bin\minecraft.jar
2. Open it with an archiving program like 7-zip.
3. Copy files from TorchStats into the Jar file.
4. Close 7-zip.
5. Play Minecraft!
## Frequently Asked Question
**Q: Does this mod require ModLoader or Forge?**
A: No.
**Q: Can I include this mod in my mod pack?**
A: If you contact me prior to adding it, and you get my written consent, then yes. I usually accept my things being put in mod packs, but NOT if it has been added without my consent and with understanding of the requirements I send you.
**Q: How do I install it?**
A: Open up your minecraft.jar file with a compression utility like 7-Zip or WinRAR, delete the folder META-INF and move the class file you downloaded into the .jar.
**Q: Do I have to pay anything to download this mod?**
A: Of course not!
**Q: Help, Minecraft freezes, blackscreens or crashes when I use the mod! What is wrong?**
A: First of all, check that you deleted the META-INF folder. If you have, ensure you're installing the correct version for your game. If you are, check that you don't have any other mods installed that add a class file with the same name as this one. If you DO have conflicting mods, please tell me of them, and I will add them to the list of incompatible mods. If you DON'T have conflicting mods, read the "Submitting a crash report" section below.
## Known bugs
* Multiplayer stats not yet implemented.
package varden.torchstats;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.src.*;
/**
*
* @author bilde2910
*/
public class mod_TSBase {
private static mod_TSGui globalGui;
private static Minecraft mc;
public static boolean initialized = false;
public static void logInfo(String info) {
mod_TSBase.mc.getLogAgent().logInfo("[MOD] TorchStats - " + info);
}
public static void logError(String info) {
mod_TSBase.mc.getLogAgent().logInfo("[MOD-ERROR] TorchStats - " + info);
}
public static void init(Minecraft mc) {
if (!initialized) {
initialized = true;
mod_TSBase.mc = mc;
globalGui = new mod_TSGui();
mod_TSTimer.init(mc);
}
}
public static NBTTagInt[] convArr(ArrayList<NBTBase> arr) {
NBTTagInt[] retarr = new NBTTagInt[arr.size()];
int index = 0;
for (NBTBase b : arr) {
retarr[index++] = (NBTTagInt) b;
}
return retarr;
}
public static void setInfo() {
NBTTagCompound baseNbt = mod_TSTimer.getBaseTag();
NBTTagCompound statsData = baseNbt.getCompoundTag("statsData");
setPlaytimeTime(baseNbt);
setPlaytimePeak(statsData);
setPlaytimeBiome(statsData);
setPlaytimeMenu(statsData);
setPlaytimeSession(statsData);
}
public static void setPlaytimeTime(NBTTagCompound baseNbt) {
NBTTagCompound statsData = baseNbt.getCompoundTag("statsData");
int sec = statsData.getTagList("ingameData").tagCount();
double submin = sec / 60;
String timeunit = "second";
if (sec != 1 && sec < 60) {
timeunit = "seconds";
} else if (sec >= 60 && sec < 120) {
timeunit = "minute";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 120 && sec < 3600) {
timeunit = "minutes";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 3600 && sec < 7200) {
timeunit = "hour";
sec = (int) Math.floor(sec / 3600);
} else {
timeunit = "hours";
sec = (int) Math.floor(sec / 3600);
}
globalGui.liPlaytimeTime.setText(String.format(liPlaytimeTime, sec, timeunit));
// Sub
submin = submin / 0.96;
submin = Math.round(submin) / 10.0;
double origSubmin = submin;
long timeSinceFirstPlayed = new Date().getTime() - baseNbt.getLong("firstPlayed");
double hrSFP = timeSinceFirstPlayed / 3600000.0;
sec = (int) (statsData.getInteger("totalTime") / hrSFP);
submin = sec / 60;
timeunit = "second";
if (sec != 1 && sec < 60) {
timeunit = "seconds";
} else if (sec >= 60 && sec < 120) {
timeunit = "minute";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 120 && sec < 3600) {
timeunit = "minutes";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 3600 && sec < 7200) {
timeunit = "hour";
sec = (int) Math.floor(sec / 3600);
} else {
timeunit = "hours";
sec = (int) Math.floor(sec / 3600);
}
globalGui.liPlaytimeTimeSub.setText(String.format(liPlaytimeTimeSub, origSubmin + "%", sec, timeunit));
}
public static void setPlaytimePeak(NBTTagCompound statsData) {
int sec = statsData.getInteger("peakTime");
double submin = sec / 60;
String timeunit = "second";
if (sec != 1 && sec < 60) {
timeunit = "seconds";
} else if (sec >= 60 && sec < 120) {
timeunit = "minute";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 120 && sec < 3600) {
timeunit = "minutes";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 3600 && sec < 7200) {
timeunit = "hour";
sec = (int) Math.floor(sec / 3600);
} else {
timeunit = "hours";
sec = (int) Math.floor(sec / 3600);
}
globalGui.liPlaytimePeak.setText(String.format(liPlaytimePeak, sec, timeunit));
// Sub
submin = submin / 0.96;
submin = Math.round(submin) / 10.0;
globalGui.liPlaytimePeakSub.setText(String.format(liPlaytimePeakSub, submin + "%"));
}
public static void setPlaytimeBiome(NBTTagCompound statsData) {
NBTTagCompound biomeData = statsData.getCompoundTag("biomeTimeList");
Collection<NBTBase> biomes = biomeData.getTags();
ArrayList<NBTBase> biomeArrays = new ArrayList<NBTBase>();
biomeArrays.addAll(biomes);
NBTTagInt[] biomeArr = convArr(biomeArrays);
String topBiome = "???";
int biomeTime = 0;
for (int i=0; i<biomeArr.length; i++) {
int thisTime = biomeData.getInteger(biomeArr[i].getName());
if (thisTime > biomeTime) {
biomeTime = thisTime;
topBiome = biomeArr[i].getName();
}
}
globalGui.liPlaytimeBiome.setText(String.format(liPlaytimeBiome, topBiome));
// Sub
int totalTime = statsData.getInteger("ingameTime");
double perc = Math.round((double) biomeTime / (double) totalTime * 1000.0) / 10.0;
globalGui.liPlaytimeBiomeSub.setText(String.format(liPlaytimeBiomeSub, perc + "%"));
}
public static void setPlaytimeMenu(NBTTagCompound statsData) {
int sec = statsData.getInteger("menuTime");
int osec = sec;
double submin = sec / 60;
String timeunit = "second";
if (sec != 1 && sec < 60) {
timeunit = "seconds";
} else if (sec >= 60 && sec < 120) {
timeunit = "minute";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 120 && sec < 3600) {
timeunit = "minutes";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 3600 && sec < 7200) {
timeunit = "hour";
sec = (int) Math.floor(sec / 3600);
} else {
timeunit = "hours";
sec = (int) Math.floor(sec / 3600);
}
globalGui.liPlaytimeMenu.setText(String.format(liPlaytimeMenu, sec, timeunit));
// Sub
int totalTime = statsData.getInteger("totalTime");
double perc = Math.round((double) osec / (double) totalTime * 100000.0) / 1000.0;
globalGui.liPlaytimeMenuSub.setText(String.format(liPlaytimeMenuSub, perc + "%"));
}
public static void setPlaytimeSession(NBTTagCompound statsData) {
int sec = statsData.getInteger("ingameTime");
int sc = statsData.getInteger("sessionCount");
sc++;
sec /= sc;
double submin = sec / 60;
String timeunit = "second";
if (sec != 1 && sec < 60) {
timeunit = "seconds";
} else if (sec >= 60 && sec < 120) {
timeunit = "minute";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 120 && sec < 3600) {
timeunit = "minutes";
sec = (int) Math.floor(sec / 60);
} else if (sec >= 3600 && sec < 7200) {
timeunit = "hour";
sec = (int) Math.floor(sec / 3600);
} else {
timeunit = "hours";
sec = (int) Math.floor(sec / 3600);
}
globalGui.liPlaytimeSession.setText(String.format(liPlaytimeSession, sec, timeunit));
// Sub
globalGui.liPlaytimeSessionSub.setText(liPlaytimeSessionSub);
}
public static void showStatForm() {
setInfo();
if (!mod_TSTimer.guiRunning) {
mod_TSTimer.setGuiTimerRunning(true);
}
globalGui.setVisible(true);
}
public static boolean isGuiVisible() {
return globalGui.isVisible();
}
// Playtime stats
private static String liPlaytimeTime = "The last 24 hours, you've played for %s %s.";
private static String liPlaytimeTimeSub = "That's %s of your waking time. On average, you play %s %s per 24 hours.";
private static String liPlaytimePeak = "The longest period of time you've played is %s %s.";
private static String liPlaytimePeakSub = "That's %s of your waking time. Remember to eat and sleep!";
private static String liPlaytimeBiome = "You most frequently stay in %s biomes.";
private static String liPlaytimeBiomeSub = "During %s of your Minecraft play time, you stay in this biome.";
private static String liPlaytimeMenu = "You spent %s %s on the game's main menu.";
private static String liPlaytimeMenuSub = "That's about %s of Minecraft's total running time.";
private static String liPlaytimeSession = "Your average single play session is %s %s.";
private static String liPlaytimeSessionSub = "This is how much time that passes between joining and leaving a game.";
// Multiplayer stats
private static String liMultiplayerTime = "You've been playing online for %s %s.";
private static String liMultiplayerTimeSub = "That means you spend %s of your play time online.";
private static String liMultiplayerPlayerCount = "You've met %s unique %s.";
private static String liMultiplayerPlayerCountSub = "In total, you've seen all players %s %s.";
private static String liMultiplayerData = "You've downloaded %s %s data from servers.";
private static String liMultiplayerDataSub = "You also uploaded %s %s data back.";
private static String liMultiplayerSpeed = "Your average download speed is %s %s/sec.";
private static String liMultiplayerSpeedSub = "Average upload speed is %s %s/sec.";
private static String liMultiplayerRenderedPlayer = "You've seen a maximum of %s %s in your render area.";
private static String liMultiplayerRenderedPlayerSub = "Usually, there are only %s other %s in your rendered area at the same time.";
}
This diff is collapsed.
package varden.torchstats;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.TimerTask;
import net.minecraft.src.*;
public class mod_TSTimer {
/**
* Triggered every second.
* Counts total Minecraft running time.
*/
private static java.util.Timer generalTimer;
public static boolean generalRunning = false;
/**
* Triggered every second.
* Counts time played ingame, and various parameters.
*/
private static java.util.Timer ingameTimer;
public static boolean ingameRunning = false;
/**
* Triggered every second.
* Counts time spent on the game menu.
*/
private static java.util.Timer menuTimer;
public static boolean menuRunning = false;
/**
* Triggered every 10 seconds.
* Started after 500 msec.
* Saves the file.
*/
private static java.util.Timer saveTimer;
public static boolean saveRunning = false;
/**
* Triggered every second.
* Updates the GUI window, when visible.
*/
private static java.util.Timer guiTimer;
public static boolean guiRunning = false;
private static Minecraft mc;
public static boolean initialized = false;
private static int sessionTime;
private static int playTime;
private static String nbtLocation;
private static volatile NBTTagCompound baseNbt = new NBTTagCompound("root");
public static void init(Minecraft mc) {
mod_TSTimer.mc = mc;
try {
nbtLocation = new File(mc.mcDataDir, "torchstats.dat").getAbsolutePath();
mod_TSBase.logInfo("Trying to read TorchStats file...");
baseNbt = CompressedStreamTools.readCompressed(new FileInputStream(nbtLocation));
} catch (IOException e) {
mod_TSBase.logInfo("Creating TorchStats file...");
baseNbt = new NBTTagCompound();
NBTTagList menuList = new NBTTagList();
NBTTagCompound tempTag = new NBTTagCompound();
baseNbt.setCompoundTag("statsData", tempTag);
baseNbt.setLong("firstPlayed", new Date().getTime());
}
}
public static NBTTagCompound getBaseTag() {
return baseNbt;
}
public static void setGeneralTimerRunning(boolean running) {
if (running) {
if (!generalRunning) {
playTime = 0;
mod_TSBase.logInfo("Starting general timer with 1000 msec frequency");
generalRunning = true;
generalTimer = new java.util.Timer();
generalTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
NBTTagCompound statsData = baseNbt.getCompoundTag("statsData");
NBTTagList dataList = statsData.getTagList("ingameData");
NBTTagCompound currentData = new NBTTagCompound();
// Peak time
playTime++;
int currentSessionRecord = statsData.getInteger("peakTime");
if (playTime > currentSessionRecord) {
statsData.setInteger("peakTime", playTime);
}
// 24hr time
NBTTagCompound currentCompound = new NBTTagCompound();
currentCompound.setLong("timeStamp", new Date().getTime());
dataList.appendTag(currentCompound);
statsData.setTag("ingameData", dataList);
// Total running time
int currentTime = statsData.getInteger("totalTime");
currentTime++;
statsData.setInteger("totalTime", currentTime);
// Also check if in-game
if (mc.theWorld != null) {
if (!ingameRunning) {
setIngameTimerRunning(true);
}
if (menuRunning) {
setMenuTimerRunning(false);
}
}
}
}, 1000, 1000);
}
} else {
generalRunning = false;
generalTimer.cancel();
mod_TSBase.logInfo("Stopped general timer");
}
}
public static void setIngameTimerRunning(boolean running) {
if (running) {
if (!ingameRunning) {
sessionTime = 0;
mod_TSBase.logInfo("Starting ingame timer with 1000 msec frequency");
ingameRunning = true;
ingameTimer = new java.util.Timer();
ingameTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (mc.theWorld == null) {
setIngameTimerRunning(false);
}
NBTTagCompound statsData = baseNbt.getCompoundTag("statsData");
NBTTagCompound currentData = new NBTTagCompound();
// Biome
try {
NBTTagCompound biomeData = statsData.getCompoundTag("biomeTimeList");
EntityClientPlayerMP thePlayer = mc.thePlayer;
int posx = (int)Math.floor(thePlayer.posX);
int posz = (int)Math.floor(thePlayer.posZ);
Chunk currentChunk = mc.theWorld.getChunkFromBlockCoords(posx, posz);
String biomeName = currentChunk.getBiomeGenForWorldCoords(posx & 15, posz & 15, mc.theWorld.getWorldChunkManager()).biomeName;
int cBiomeD = biomeData.getInteger(biomeName);
cBiomeD++;
biomeData.setInteger(biomeName, cBiomeD);
statsData.setCompoundTag("biomeTimeList", biomeData);
} catch (Exception ex) {
mod_TSBase.logError("Exception occurred while getting biome information");
}
// Max session time
sessionTime++;
int currentSessionRecord = statsData.getInteger("maxSession");
if (sessionTime > currentSessionRecord) {
statsData.setInteger("maxSession", sessionTime);
}
// Total ingame time
int currentTime = statsData.getInteger("ingameTime");
currentTime++;
statsData.setInteger("ingameTime", currentTime);
}
}, 0, 1000);
}
} else {
ingameRunning = false;
ingameTimer.cancel();
mod_TSBase.logInfo("Stopped ingame timer");
NBTTagCompound statsData = baseNbt.getCompoundTag("statsData");
int sessionCount = statsData.getInteger("sessionCount");
sessionCount++;
statsData.setInteger("sessionCount", sessionCount);
}
}
public static void setMenuTimerRunning(boolean running) {
if (running) {
if (!menuRunning) {
mod_TSBase.logInfo("Starting main menu timer with 1000 msec frequency");
menuRunning = true;
menuTimer = new java.util.Timer();
menuTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
int menuTime = baseNbt.getCompoundTag("statsData").getInteger("menuTime");
menuTime++;
baseNbt.getCompoundTag("statsData").setInteger("menuTime", menuTime);
}
}, 1000, 1000);
}
} else {
menuRunning = false;
menuTimer.cancel();
mod_TSBase.logInfo("Stopped menu timer");
}
}
public static void setSaveTimerRunning(boolean running) {
if (running) {
if (!saveRunning) {
mod_TSBase.logInfo("Starting save timer with 10000 msec frequency");
saveRunning = true;
saveTimer = new java.util.Timer();
saveTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
forceSave();
}
}, 1500, 10000);
}
} else {
saveRunning = false;
saveTimer.cancel();
mod_TSBase.logInfo("Stopped save timer");
}
}
public static void setGuiTimerRunning(boolean running) {
if (running) {
if (!guiRunning) {
mod_TSBase.logInfo("Starting GUI timer with 1000 msec frequency");
guiRunning = true;
guiTimer = new java.util.Timer();
guiTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (!mod_TSBase.isGuiVisible()) {
setGuiTimerRunning(false);
}
mod_TSBase.setInfo();
}
}, 1000, 1000);
}
} else {
guiRunning = false;
guiTimer.cancel();
mod_TSBase.logInfo("Stopped GUI timer");
}
}
private static NBTTagList clean24Hr(NBTTagList tag) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.HOUR, -24);
Date oldTime = cal.getTime();
long date = oldTime.getTime();
for (int i = tag.tagCount() - 1; i >= 0; i--) {
long current = ((NBTTagCompound)tag.tagAt(i)).getLong("timeStamp");
if (current < date) {
tag.removeTag(i);
}
}
return tag;
}
public static boolean forceSave() {
NBTTagCompound statsData = baseNbt.getCompoundTag("statsData");
NBTTagList dataList = statsData.getTagList("ingameData");
NBTTagList tbcList = (NBTTagList) dataList.copy();
dataList = clean24Hr(tbcList);
statsData.setTag("ingameData", dataList);
try {
CompressedStreamTools.writeCompressed(baseNbt, new FileOutputStream(nbtLocation));
return true;
} catch (IOException e) {
mod_TSBase.logInfo("ERROR: Could not save NBT tag!");
return false;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment