2012-01-15 00:51:37 +01:00
|
|
|
package net.citizensnpcs;
|
|
|
|
|
2012-01-19 11:52:58 +01:00
|
|
|
import java.io.File;
|
2012-02-12 08:19:32 +01:00
|
|
|
import java.io.IOException;
|
2012-02-17 08:48:20 +01:00
|
|
|
import java.sql.SQLException;
|
2012-01-29 21:58:19 +01:00
|
|
|
import java.util.logging.Level;
|
2012-01-19 11:52:58 +01:00
|
|
|
|
2012-01-23 15:30:15 +01:00
|
|
|
import net.citizensnpcs.Settings.Setting;
|
2012-01-15 00:51:37 +01:00
|
|
|
import net.citizensnpcs.api.CitizensAPI;
|
2012-03-08 02:03:32 +01:00
|
|
|
import net.citizensnpcs.api.event.CitizensReloadEvent;
|
2012-01-19 11:52:58 +01:00
|
|
|
import net.citizensnpcs.api.exception.NPCLoadException;
|
2012-01-18 05:04:08 +01:00
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
2012-04-12 17:31:54 +02:00
|
|
|
import net.citizensnpcs.api.scripting.EventRegistrar;
|
2012-05-03 17:22:31 +02:00
|
|
|
import net.citizensnpcs.api.scripting.ObjectProvider;
|
2012-04-12 17:01:56 +02:00
|
|
|
import net.citizensnpcs.api.scripting.ScriptCompiler;
|
2012-04-30 15:38:18 +02:00
|
|
|
import net.citizensnpcs.api.trait.TraitManager;
|
2012-02-12 09:00:19 +01:00
|
|
|
import net.citizensnpcs.api.util.DataKey;
|
|
|
|
import net.citizensnpcs.api.util.DatabaseStorage;
|
2012-03-30 16:01:36 +02:00
|
|
|
import net.citizensnpcs.api.util.NBTStorage;
|
2012-02-12 09:00:19 +01:00
|
|
|
import net.citizensnpcs.api.util.Storage;
|
|
|
|
import net.citizensnpcs.api.util.YamlStorage;
|
2012-01-25 16:29:54 +01:00
|
|
|
import net.citizensnpcs.command.CommandManager;
|
2012-01-25 21:07:49 +01:00
|
|
|
import net.citizensnpcs.command.Injector;
|
2012-02-08 16:22:42 +01:00
|
|
|
import net.citizensnpcs.command.command.AdminCommands;
|
2012-02-27 09:32:43 +01:00
|
|
|
import net.citizensnpcs.command.command.EditorCommands;
|
2012-02-08 09:26:14 +01:00
|
|
|
import net.citizensnpcs.command.command.HelpCommands;
|
2012-01-25 16:29:54 +01:00
|
|
|
import net.citizensnpcs.command.command.NPCCommands;
|
2012-04-13 17:59:51 +02:00
|
|
|
import net.citizensnpcs.command.command.ScriptCommands;
|
2012-02-29 11:50:45 +01:00
|
|
|
import net.citizensnpcs.command.exception.CommandException;
|
2012-01-25 16:29:54 +01:00
|
|
|
import net.citizensnpcs.command.exception.CommandUsageException;
|
|
|
|
import net.citizensnpcs.command.exception.ServerCommandException;
|
|
|
|
import net.citizensnpcs.command.exception.UnhandledCommandException;
|
|
|
|
import net.citizensnpcs.command.exception.WrappedCommandException;
|
2012-02-27 16:59:39 +01:00
|
|
|
import net.citizensnpcs.editor.Editor;
|
2012-03-08 02:03:32 +01:00
|
|
|
import net.citizensnpcs.npc.CitizensCharacterManager;
|
2012-03-09 21:53:02 +01:00
|
|
|
import net.citizensnpcs.npc.CitizensNPC;
|
2012-01-15 00:51:37 +01:00
|
|
|
import net.citizensnpcs.npc.CitizensNPCManager;
|
2012-03-08 02:03:32 +01:00
|
|
|
import net.citizensnpcs.npc.CitizensTraitManager;
|
2012-01-16 04:15:32 +01:00
|
|
|
import net.citizensnpcs.util.Messaging;
|
2012-02-12 08:19:32 +01:00
|
|
|
import net.citizensnpcs.util.Metrics;
|
2012-01-25 16:29:54 +01:00
|
|
|
import net.citizensnpcs.util.StringHelper;
|
2012-01-15 00:51:37 +01:00
|
|
|
|
2012-01-22 18:43:58 +01:00
|
|
|
import org.bukkit.ChatColor;
|
2012-01-19 11:52:58 +01:00
|
|
|
import org.bukkit.command.Command;
|
|
|
|
import org.bukkit.command.CommandSender;
|
2012-01-29 21:58:19 +01:00
|
|
|
import org.bukkit.craftbukkit.CraftServer;
|
2012-02-24 00:45:45 +01:00
|
|
|
import org.bukkit.entity.EntityType;
|
2012-01-19 11:52:58 +01:00
|
|
|
import org.bukkit.entity.Player;
|
2012-01-15 00:51:37 +01:00
|
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
|
|
|
2012-02-12 08:19:32 +01:00
|
|
|
import com.google.common.collect.Iterators;
|
2012-02-04 07:48:23 +01:00
|
|
|
|
2012-01-15 06:09:31 +01:00
|
|
|
public class Citizens extends JavaPlugin {
|
2012-03-27 16:42:15 +02:00
|
|
|
private final CitizensCharacterManager characterManager = new CitizensCharacterManager();
|
2012-02-12 08:19:32 +01:00
|
|
|
private final CommandManager commands = new CommandManager();
|
2012-03-10 11:33:11 +01:00
|
|
|
private boolean compatible;
|
2012-03-27 16:42:15 +02:00
|
|
|
private Settings config;
|
2012-04-18 04:12:17 +02:00
|
|
|
private ClassLoader contextClassLoader;
|
2012-03-10 11:33:11 +01:00
|
|
|
private CitizensNPCManager npcManager;
|
2012-04-12 19:19:45 +02:00
|
|
|
private Storage saves;
|
2012-04-30 15:38:18 +02:00
|
|
|
private TraitManager traitManager;
|
2012-03-02 14:04:40 +01:00
|
|
|
|
2012-03-02 11:36:54 +01:00
|
|
|
public CommandManager getCommandManager() {
|
|
|
|
return commands;
|
|
|
|
}
|
|
|
|
|
|
|
|
public CitizensNPCManager getNPCManager() {
|
|
|
|
return npcManager;
|
|
|
|
}
|
|
|
|
|
2012-01-23 09:45:34 +01:00
|
|
|
@Override
|
|
|
|
public boolean onCommand(CommandSender sender, Command cmd, String cmdName, String[] args) {
|
2012-01-25 16:29:54 +01:00
|
|
|
Player player = null;
|
|
|
|
if (sender instanceof Player)
|
|
|
|
player = (Player) sender;
|
|
|
|
|
|
|
|
try {
|
|
|
|
// must put command into split.
|
|
|
|
String[] split = new String[args.length + 1];
|
|
|
|
System.arraycopy(args, 0, split, 1, args.length);
|
|
|
|
split[0] = cmd.getName().toLowerCase();
|
|
|
|
|
2012-02-12 08:19:32 +01:00
|
|
|
String modifier = args.length > 0 ? args[0] : "";
|
2012-01-25 16:29:54 +01:00
|
|
|
|
2012-02-12 08:19:32 +01:00
|
|
|
if (!commands.hasCommand(split[0], modifier) && !modifier.isEmpty()) {
|
|
|
|
return suggestClosestModifier(sender, split[0], modifier);
|
2012-01-25 16:29:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
NPC npc = null;
|
2012-03-01 11:45:44 +01:00
|
|
|
if (player != null && player.getMetadata("selected").size() > 0)
|
|
|
|
npc = npcManager.getNPC(player.getMetadata("selected").get(0).asInt());
|
2012-04-20 16:19:03 +02:00
|
|
|
// TODO: change the args supplied to a context style system for
|
|
|
|
// flexibility (ie. adding more context in the future without
|
|
|
|
// changing everything)
|
2012-01-25 16:29:54 +01:00
|
|
|
try {
|
2012-02-12 08:19:32 +01:00
|
|
|
commands.execute(split, player, player == null ? sender : player, npc);
|
2012-01-25 16:29:54 +01:00
|
|
|
} catch (ServerCommandException ex) {
|
2012-02-29 11:50:45 +01:00
|
|
|
Messaging.send(sender, "You must be in-game to execute that command.");
|
2012-01-25 16:29:54 +01:00
|
|
|
} catch (CommandUsageException ex) {
|
|
|
|
Messaging.sendError(player, ex.getMessage());
|
|
|
|
Messaging.sendError(player, ex.getUsage());
|
2012-02-29 11:50:45 +01:00
|
|
|
} catch (WrappedCommandException ex) {
|
|
|
|
throw ex.getCause();
|
|
|
|
} catch (UnhandledCommandException ex) {
|
2012-01-25 16:29:54 +01:00
|
|
|
return false;
|
2012-02-29 11:50:45 +01:00
|
|
|
} catch (CommandException ex) {
|
2012-03-12 00:26:40 +01:00
|
|
|
Messaging.sendError(sender, ex.getMessage());
|
2012-01-25 16:29:54 +01:00
|
|
|
}
|
2012-02-29 11:50:45 +01:00
|
|
|
} catch (NumberFormatException ex) {
|
2012-01-25 16:29:54 +01:00
|
|
|
Messaging.sendError(player, "That is not a valid number.");
|
2012-02-29 11:50:45 +01:00
|
|
|
} catch (Throwable ex) {
|
|
|
|
ex.printStackTrace();
|
2012-03-12 00:26:40 +01:00
|
|
|
if (sender instanceof Player) {
|
|
|
|
Messaging.sendError(player, "Please report this error: [See console]");
|
|
|
|
Messaging.sendError(player, ex.getClass().getName() + ": " + ex.getMessage());
|
|
|
|
}
|
2012-01-23 09:45:34 +01:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-19 12:43:21 +01:00
|
|
|
@Override
|
|
|
|
public void onDisable() {
|
2012-04-20 15:49:30 +02:00
|
|
|
tearDownScripting();
|
2012-01-29 21:58:19 +01:00
|
|
|
// Don't bother with this part if MC versions are not compatible
|
2012-01-30 12:58:59 +01:00
|
|
|
if (compatible) {
|
2012-02-28 08:41:15 +01:00
|
|
|
save();
|
2012-04-24 17:05:38 +02:00
|
|
|
npcManager.safeRemove();
|
2012-03-10 11:33:11 +01:00
|
|
|
npcManager = null;
|
2012-02-27 11:59:33 +01:00
|
|
|
getServer().getScheduler().cancelTasks(this);
|
2012-01-29 21:58:19 +01:00
|
|
|
}
|
2012-01-21 13:53:58 +01:00
|
|
|
|
2012-01-19 12:43:21 +01:00
|
|
|
Messaging.log("v" + getDescription().getVersion() + " disabled.");
|
|
|
|
}
|
2012-01-15 00:51:37 +01:00
|
|
|
|
2012-01-19 12:43:21 +01:00
|
|
|
@Override
|
|
|
|
public void onEnable() {
|
2012-01-29 21:58:19 +01:00
|
|
|
// Disable if the server is not using the compatible Minecraft version
|
2012-01-30 12:58:59 +01:00
|
|
|
String mcVersion = ((CraftServer) getServer()).getServer().getVersion();
|
2012-04-05 17:03:30 +02:00
|
|
|
compatible = mcVersion.startsWith(COMPATIBLE_MC_VERSION);
|
2012-01-30 12:58:59 +01:00
|
|
|
if (!compatible) {
|
2012-01-29 21:58:19 +01:00
|
|
|
Messaging.log(Level.SEVERE, "v" + getDescription().getVersion() + " is not compatible with Minecraft v"
|
|
|
|
+ mcVersion + ". Disabling.");
|
|
|
|
getServer().getPluginManager().disablePlugin(this);
|
|
|
|
return;
|
|
|
|
}
|
2012-04-18 04:12:17 +02:00
|
|
|
registerScriptHelpers();
|
2012-01-29 21:58:19 +01:00
|
|
|
|
2012-04-15 01:32:43 +02:00
|
|
|
config = new Settings(getDataFolder());
|
2012-01-19 11:52:58 +01:00
|
|
|
|
2012-04-18 04:12:17 +02:00
|
|
|
setupStorage();
|
2012-02-12 08:19:32 +01:00
|
|
|
|
2012-03-10 11:33:11 +01:00
|
|
|
npcManager = new CitizensNPCManager(this, saves);
|
2012-03-23 12:55:53 +01:00
|
|
|
traitManager = new CitizensTraitManager(this);
|
2012-01-23 17:05:22 +01:00
|
|
|
CitizensAPI.setNPCManager(npcManager);
|
|
|
|
CitizensAPI.setCharacterManager(characterManager);
|
2012-03-10 11:33:11 +01:00
|
|
|
CitizensAPI.setTraitManager(traitManager);
|
2012-04-30 15:38:18 +02:00
|
|
|
CitizensAPI.setDataFolder(getDataFolder());
|
2012-01-23 17:05:22 +01:00
|
|
|
|
2012-01-22 08:10:25 +01:00
|
|
|
getServer().getPluginManager().registerEvents(new EventListen(npcManager), this);
|
2012-01-16 04:15:32 +01:00
|
|
|
|
2012-01-25 16:29:54 +01:00
|
|
|
registerCommands();
|
2012-01-23 15:30:15 +01:00
|
|
|
|
2012-01-19 12:43:21 +01:00
|
|
|
Messaging.log("v" + getDescription().getVersion() + " enabled.");
|
2012-01-18 05:04:08 +01:00
|
|
|
|
2012-01-19 12:43:21 +01:00
|
|
|
// Setup NPCs after all plugins have been enabled (allows for multiworld
|
|
|
|
// support and for NPCs to properly register external settings)
|
2012-03-11 21:14:36 +01:00
|
|
|
if (getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
|
2012-01-19 12:43:21 +01:00
|
|
|
@Override
|
|
|
|
public void run() {
|
2012-04-19 05:52:07 +02:00
|
|
|
setupNPCs();
|
2012-01-19 12:43:21 +01:00
|
|
|
}
|
2012-01-20 08:27:14 +01:00
|
|
|
}) == -1) {
|
2012-01-29 21:58:19 +01:00
|
|
|
Messaging.log(Level.SEVERE, "Issue enabling plugin. Disabling.");
|
2012-01-19 12:43:21 +01:00
|
|
|
getServer().getPluginManager().disablePlugin(this);
|
|
|
|
}
|
2012-02-12 11:02:36 +01:00
|
|
|
|
|
|
|
// Run metrics last
|
2012-04-20 15:49:30 +02:00
|
|
|
startMetrics();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startMetrics() {
|
2012-02-12 11:02:36 +01:00
|
|
|
new Thread() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
2012-05-05 17:22:11 +02:00
|
|
|
Metrics metrics = new Metrics(Citizens.this);
|
|
|
|
metrics.addCustomData(new Metrics.Plotter("Total NPCs") {
|
2012-02-12 11:02:36 +01:00
|
|
|
@Override
|
2012-03-02 11:36:54 +01:00
|
|
|
public int getValue() {
|
|
|
|
return Iterators.size(npcManager.iterator());
|
2012-02-12 11:02:36 +01:00
|
|
|
}
|
|
|
|
});
|
2012-05-05 17:22:11 +02:00
|
|
|
Metrics.Graph graph = metrics.createGraph("Character Type Usage");
|
|
|
|
for(Object i : characterManager.getRegistered()){
|
|
|
|
graph.addPlotter(new Metrics.Plotter(i.toString()) {
|
|
|
|
@Override
|
|
|
|
public int getValue() {
|
2012-05-05 21:24:50 +02:00
|
|
|
return 1;
|
2012-05-05 17:22:11 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
metrics.start();
|
|
|
|
} catch (IOException e) {
|
2012-02-12 11:02:36 +01:00
|
|
|
Messaging.log("Unable to load metrics");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}.start();
|
2012-01-19 12:43:21 +01:00
|
|
|
}
|
2012-01-18 05:04:08 +01:00
|
|
|
|
2012-04-18 04:12:17 +02:00
|
|
|
private void setupStorage() {
|
|
|
|
String type = Setting.STORAGE_TYPE.asString();
|
|
|
|
if (type.equalsIgnoreCase("db") || type.equalsIgnoreCase("database")) {
|
|
|
|
try {
|
|
|
|
saves = new DatabaseStorage(Setting.DATABASE_DRIVER.asString(), Setting.DATABASE_URL.asString(),
|
|
|
|
Setting.DATABASE_USERNAME.asString(), Setting.DATABASE_PASSWORD.asString());
|
|
|
|
} catch (SQLException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
Messaging.log("Unable to connect to database, falling back to YAML");
|
|
|
|
}
|
|
|
|
} else if (type.equalsIgnoreCase("nbt")) {
|
|
|
|
saves = new NBTStorage(getDataFolder() + File.separator + Setting.STORAGE_FILE.asString(),
|
|
|
|
"Citizens NPC Storage");
|
|
|
|
}
|
|
|
|
if (saves == null) {
|
|
|
|
saves = new YamlStorage(getDataFolder() + File.separator + Setting.STORAGE_FILE.asString(),
|
|
|
|
"Citizens NPC Storage");
|
|
|
|
}
|
|
|
|
Messaging.log("Save method set to", saves.toString());
|
|
|
|
}
|
|
|
|
|
2012-03-02 11:36:54 +01:00
|
|
|
private void registerCommands() {
|
|
|
|
commands.setInjector(new Injector(this));
|
|
|
|
|
|
|
|
// Register command classes
|
|
|
|
commands.register(AdminCommands.class);
|
|
|
|
commands.register(EditorCommands.class);
|
|
|
|
commands.register(HelpCommands.class);
|
|
|
|
commands.register(NPCCommands.class);
|
2012-04-13 17:59:51 +02:00
|
|
|
commands.register(ScriptCommands.class);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void registerScriptHelpers() {
|
2012-04-20 15:49:30 +02:00
|
|
|
setupScripting();
|
2012-04-13 17:59:51 +02:00
|
|
|
ScriptCompiler compiler = CitizensAPI.getScriptCompiler();
|
|
|
|
compiler.registerGlobalContextProvider(new EventRegistrar(this));
|
2012-05-03 17:22:31 +02:00
|
|
|
compiler.registerGlobalContextProvider(new ObjectProvider("plugin", this));
|
2012-02-28 08:41:15 +01:00
|
|
|
}
|
|
|
|
|
2012-02-27 11:59:33 +01:00
|
|
|
public void reload() throws NPCLoadException {
|
2012-02-27 16:59:39 +01:00
|
|
|
Editor.leaveAll();
|
2012-04-15 01:32:43 +02:00
|
|
|
config.reload();
|
2012-03-11 21:14:36 +01:00
|
|
|
npcManager.safeRemove();
|
2012-02-27 11:59:33 +01:00
|
|
|
setupNPCs();
|
2012-03-08 02:03:32 +01:00
|
|
|
|
|
|
|
getServer().getPluginManager().callEvent(new CitizensReloadEvent());
|
2012-02-27 11:59:33 +01:00
|
|
|
}
|
|
|
|
|
2012-04-20 15:49:30 +02:00
|
|
|
private void setupScripting() {
|
2012-04-18 04:12:17 +02:00
|
|
|
contextClassLoader = Thread.currentThread().getContextClassLoader();
|
|
|
|
Thread.currentThread().setContextClassLoader(getClassLoader());
|
|
|
|
// workaround to fix scripts not loading plugin classes properly
|
|
|
|
}
|
|
|
|
|
2012-04-20 15:49:30 +02:00
|
|
|
private void tearDownScripting() {
|
2012-04-18 04:12:17 +02:00
|
|
|
Thread.currentThread().setContextClassLoader(contextClassLoader);
|
|
|
|
}
|
|
|
|
|
2012-03-02 11:36:54 +01:00
|
|
|
public void save() {
|
2012-03-11 21:14:36 +01:00
|
|
|
for (NPC npc : npcManager)
|
2012-03-09 21:53:02 +01:00
|
|
|
((CitizensNPC) npc).save(saves.getKey("npc." + npc.getId()));
|
2012-04-14 18:49:18 +02:00
|
|
|
|
2012-03-02 11:36:54 +01:00
|
|
|
saves.save();
|
2012-02-04 07:48:23 +01:00
|
|
|
}
|
|
|
|
|
2012-04-18 04:12:17 +02:00
|
|
|
// TODO: refactor
|
2012-04-19 05:52:07 +02:00
|
|
|
private void setupNPCs() {
|
2012-03-11 21:14:36 +01:00
|
|
|
saves.load();
|
2012-01-29 12:43:27 +01:00
|
|
|
int created = 0, spawned = 0;
|
|
|
|
for (DataKey key : saves.getKey("npc").getIntegerSubKeys()) {
|
2012-01-19 12:43:21 +01:00
|
|
|
int id = Integer.parseInt(key.name());
|
2012-04-19 05:52:07 +02:00
|
|
|
if (!key.keyExists("name")) {
|
|
|
|
Messaging.log("Could not find a name for the NPC with ID '" + id + "'.");
|
|
|
|
continue;
|
|
|
|
}
|
2012-04-20 17:19:15 +02:00
|
|
|
String unparsedEntityType = key.getString("traits.type", "PLAYER");
|
2012-04-20 16:45:09 +02:00
|
|
|
EntityType type = EntityType.fromName(unparsedEntityType);
|
2012-03-27 16:42:15 +02:00
|
|
|
if (type == null) {
|
|
|
|
try {
|
2012-04-20 16:45:09 +02:00
|
|
|
type = EntityType.valueOf(unparsedEntityType);
|
2012-03-27 16:42:15 +02:00
|
|
|
} catch (IllegalArgumentException ex) {
|
2012-04-20 16:45:09 +02:00
|
|
|
Messaging.log("NPC type '" + unparsedEntityType
|
|
|
|
+ "' was not recognized. Did you spell it correctly?");
|
2012-04-19 05:52:07 +02:00
|
|
|
continue;
|
2012-03-27 16:42:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
NPC npc = npcManager.createNPC(type, id, key.getString("name"), null);
|
2012-04-24 17:05:38 +02:00
|
|
|
((CitizensNPC) npc).load(key);
|
2012-02-12 08:19:32 +01:00
|
|
|
|
2012-01-29 12:43:27 +01:00
|
|
|
++created;
|
|
|
|
if (npc.isSpawned())
|
|
|
|
++spawned;
|
2012-01-19 12:43:21 +01:00
|
|
|
}
|
2012-01-30 19:55:16 +01:00
|
|
|
Messaging.log("Loaded " + created + " NPCs (" + spawned + " spawned).");
|
2012-01-19 12:43:21 +01:00
|
|
|
}
|
2012-03-02 11:36:54 +01:00
|
|
|
|
|
|
|
private boolean suggestClosestModifier(CommandSender sender, String command, String modifier) {
|
|
|
|
int minDist = Integer.MAX_VALUE;
|
|
|
|
String closest = "";
|
|
|
|
for (String string : commands.getAllCommandModifiers(command)) {
|
|
|
|
int distance = StringHelper.getLevenshteinDistance(modifier, string);
|
|
|
|
if (minDist > distance) {
|
|
|
|
minDist = distance;
|
|
|
|
closest = string;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!closest.isEmpty()) {
|
|
|
|
sender.sendMessage(ChatColor.GRAY + "Unknown command. Did you mean:");
|
|
|
|
sender.sendMessage(StringHelper.wrap(" /") + command + " " + StringHelper.wrap(closest));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2012-03-27 16:42:15 +02:00
|
|
|
|
2012-03-31 23:15:53 +02:00
|
|
|
private static final String COMPATIBLE_MC_VERSION = "1.2.5";
|
2012-01-15 00:51:37 +01:00
|
|
|
}
|