package cyano.poweradvantage;
import cyano.poweradvantage.api.ConduitType;
import cyano.poweradvantage.init.WorldGen;
import cyano.poweradvantage.registry.FuelRegistry;
import cyano.poweradvantage.registry.MachineGUIRegistry;
import cyano.poweradvantage.registry.still.recipe.DistillationRecipeRegistry;
import net.minecraft.block.Block;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.GameData;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.logging.log4j.Level;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
// NOTE: other mods dependant on this one need to add the following to their @Mod annotation:
// dependencies = "required-after:poweradvantage"
/* IDEA list
* drain block ✓
* fluid pipes ✓
* portable tank block ✓
* item chute ✓
* fluid discharge block ✓
* example crusher machine (SteamAfvantage will be the example mod) ✓
* -- SteamAdvantage mod --
* Coal-Fired Steam Boiler ✓
* Boiler Tank ✓
* Steam Conduit ✓
* Steam Powered Rock Crusher ✓
* Steam Powered Blast Furnace ✓
* Steam Powered Drill ✓
* Steam Powered Lift (pushes up special lift blocks, like an extendable piston) ✓
* Steam Powered Machine Shop (automatable crafter)
* Musket (slow-loading ranged weapon) ✓
* Steam Powered Defense Cannon (manual aiming and requires redstone trigger)
* Oil-Burning Steam Boiler
* Bioreactor (slowly makes liquid fuel from organic matter)
* -- ElectricalAdvantage --
* Electricity Conduit ✓
* Steam Powered Generator ✓
* Solar Generator ✓
* Water Turbine Generator ✓
* Wind Turbine Generator
* Electric Boiler (makes steam power from electricity)
* Electric Battery ✓
* Electric Furnace ✓
* Electric Arc Furnace ✓
* Electric Rock Crusher ✓
* Electric Drill ✓
* Electric Assembler ✓
* Revolver Pistol (six-shots between slow reloads)
* Electric Defense Cannon (auto-aiming and automatically attacks hostile mobs) ✓
* Electric Lift (electric version of steam lift)
* Electric Tools
* Electric Charging Station
* Electric Robot Station
* Robots:
* - Farm-bot (farms)
* - Lumber-bot (cuts and plants trees)
* - Kill-bot (kills mobs with arrows or bullets)
* - Drill-bot (digs)
* - Construction-bot (builds villager homes)
* - Chef-bot (cooks food)
* - Fish-bot (fishes)
*
* IDEAS:
* -- MagicAdvantage -- (power from colored mana)
* Mana:
* - Red (fire)
* - Blue (water)
* - White (air)
* - Brown (earth)
* - Purple (darkness, not found naturally in overworld)
* - Yellow (light, not found naturally in overworld)
* mana crystal generates in the world and slowly grow over time
* fully grown mana crystals are hazardous to be near and sprout new crystals in neighboring air blocks
* mining a mana crystal drops mana
* magical machines are powered by mana and have extra effects depending on mane used for power
* Mana Pool (stores mana and powers near-by magic machines)
* Mana Focus (giant crystal that extends the range of the mana pool)
* Red Mana Condenser (turns fuel into red mana)
* Blue Mana Condenser (generates blue mana if submerged in water)
* Brown Mana Condenser (turns plants into brown mana)
* White Mana Condenser (generates white mana while high in the sky)
* Yellow Mana Condenser (generates yellow mana while sunlight shines on it)
* Purple Mana Condenser (hurts nearby entities and generates purple mana)
* Magical Excavator (mines the area)
* - red mana: smelt items as they're mined
* - blue mana: mine faster
* - brown mana: fill mined area with dirt
* - white mana: mine larger area
* - yellow mana: occasionally mines a duplicate block (+10% yield)
* - purple mana: destroy worthless blocks instead of mining them
* Magical Conjurer (summons entities/items)
* - red mana: random treasure chest loot item
* - blue mana: random fishing result
* - brown mana: random ore or crop
* - white mana: random animal
* - yellow mana: random mana shard
* - purple mana: random hostile mob, occasionally from Nether
* Magical Spirit Shrine
* - red mana: attacks hostile mobs and smelts near-by blocks (turns trees into charcoal and cobblestone into stone)
* - blue mana: plants crops and trees using items in nearby chests
* - brown mana: adds mining haste effect to nearby players
* - white mana: harvests crops and leaves and picks-up nearby items and puts them in a chest
* - yellow mana: lights up the area (places fae lights)
* - purple mana: hurts all mobs and steals from player inventories
* Magical Furnace (expanded furnace 3x3)
* - red mana: smelts more items per mana shard
* - blue mana: unsmelts items
* - brown mana: has small change of spitting out a random mana shard after each smelt
* - white mana: smelts faster (but does not smelt more items per mana shard)
* - yellow mana: has chance of not consuming input items
* - purple mana: smelts super fast, with 12.5% loss
* Magical Mystery Box (does stuff to items placed inside)
* - red mana: smelts items
* - blue mana: turns water buckets into ice blocks, lava buckets into obsidian
* - brown mana: grows/duplicates plant items
* - white mana: crafts blocks into fancier forms (e.g. stone into stone bricks)
* - yellow mana: repairs items
* - purple mana: destroys items, creating XP orbs
*
* -- QuantumAdvantage -- (wireless power)
* Fusion Generator (burns water for electricity)
* Quantum Entanglement Generator (powered by electricity, wirelessly sends power to quantum machines and also recharges quantum batteries in player inventories)
* Quantum Relay (range extender for Quantum Entanglement Generator)
* Quantum Furnace (super-fast 3x3 expanded furnace)
* Quantum Teleporter
* Quantum Disassembler (like crusher, but also yields 1 stone block per ore)
* Quantum Defense Cannon (automatically hurts all enemy mobs within range)
* Quantum Quarry (like BuildCraft Quarry)
* Quantum Farm (manages farming in nearby area)
* Quantum Tools (powered by a quantum battery in player inventory)
* Ray Gun (gun with no reload time, powered by a quantum battery in player inventory)
* Private Quantum Storage Chest (like ender chest with bigger inventory)
* Public Quantum Storage Chest (like ender chest, but all players on same team have access)
* Quantum Shield (worn as chestplate, provides full armor protection and repairs with quantum energy)
* Quantum Goggles (worn as helmet, lets user see ores and entity through walls and see in the dark)
* Quantum Leg Enhancements (worn as leggings, bestows fast speed and player can walk up 1-block height change without jumping)
* Quantum Shoes (slow fall and air jumping, allows for primitive flight)
* Instant *** (place on ground to make building instantly appear)
* Instant Camp
* Instant Farm
* Instant House
* Instant Castle
*/
/**
* <p>This is the main mod class for Power Advantage. Forge/FML will create an
* instance of this class and call its initializer functions. There are some
* utility functions in this class that makers of add-on mods may wish to use,
* such as PowerAdvantage.getInstance(). </p>
* <p>
* Note that to make a mod that uses the PowerAdvantage API, you will need to make a few
* adjustments to add the appropriate dependancies.
* </p><p>
* First, you need to add the required libraries to your project. Create a folder in your project
* called <b>lib</b>. Then grab the PowerAdvantage and BaseMetals API .jar files and put them in
* the <b>lib</b> folder. It will also be helpful to put the javadoc .zip files in this folder as
* well.
* </p><p>
* Next, you need to specify the dependencies in the @mod annotation. For example:<br>
* <code>@Mod(modid = MyMod.MODID, version = MyMod.VERSION, name=MyMod.NAME, dependencies = "required-after:poweradvantage;required-after:basemetals")</code>
* </p><p>
* After that, you need to update your gradle build script to include the dependencies. Add the
* following to <b>build.gradle</b> (adjusting the version numbers on the .jar filenames as
* neessary):<br><code>
allprojects {
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
dependencies {
compile files(
'lib/basemetals-1.6.0-dev.jar'
'lib/PowerAdvantage-API-1.4.0.jar'
)
}
</code><br>This is necessary to include the API in your compile build path and also specify that you
* are compiling with Java 7 (Java 6 will not work).
* </p><p>
* Finally, you need to add the API .jar files to your IDE project configuration. In Eclipse,
* right-click on your project and go to <i>Properties</i>, then click on <i>Java Build Path</i> and
* click on the <i>Libraries</i> tab. Then click <i>Add Jars...</i> and select the BaseMetals and
* PowerAdvantage API jars in your <b>lib</b> folder and close the window by clicking OK.
* </p>
* @author DrCyano
*
*/
@Mod(modid = PowerAdvantage.MODID, version = PowerAdvantage.VERSION, name=PowerAdvantage.NAME, dependencies = "required-after:basemetals",
acceptedMinecraftVersions = "[1.10.2,)")
public class PowerAdvantage
{
/** The identifier for this mod */
public static final String MODID = "poweradvantage";
/** The display name for this mod */
public static final String NAME = "Power Advantage";
/** The version of this mod, in the format major.minor.update */
public static final String VERSION = "2.3.0";
// TODO: add condenser (makes water from steam)
// TODO: add ice machine (uses water and electricity to make blocks of ice)
/* TODO: new tutorial:
1. Download and setup IDE (IntelliJ)
2. Simple steam-powered food oven ("pressure cooker")
3. Add animated GUI to steam-powered food oven
4. Bucket filler (with universal bucket)
5. Steam battery
6. Redstone-powered steam boiler (dual-energy machine)
*/
/** singleton instance */
private static PowerAdvantage instance;
/**
* This is the recipe mode set for this mod. Add-on mods may want to adjust their recipes
* accordingly.
*/
public static RecipeMode recipeMode = RecipeMode.NORMAL;
public static boolean useOtherFluids = false;
/** adjustment for frequency of loot spawns in treasure chests */
public static float chestLootFactor = 0.5f;
/** If true, plastic will be registered as rubber in ore dictionary */
public static boolean plasticIsAlsoRubber = true;
/** used to convert energy to RF types when attempting autmoatic conversion */
public static final Map<ConduitType, Float> rfConversionTable = new HashMap<>();
/** used to convert energy to Tech Reborn types when attempting automatic conversion */
public static final Map<ConduitType, Float> trConversionTable = new HashMap<>();
public static boolean detectedRF = false;
public static boolean detectedTechReborn = false;
private String[] distillRecipes = new String[0]; // used to pass config data to the init() method
/**
* Pre-initialization step. Used for initializing objects and reading the
* config file
* @param event FML event object
*/
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
FMLLog.info("%s: loading config file", MODID);
instance = this;
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
String[] presets = {"NORMAL", "TECH_PROGRESSION", "APOCALYPTIC"};
String mode = config.getString("recipe_mode", "options", "NORMAL", "NORMAL, APOCALYPTIC, or TECH_PROGRESSION. \n"
+ "Sets the style of recipes used in your game. \n"
+ "In NORMAL mode, everything needed is craftable from vanilla items and the machines are \n"
+ "available pretty much as soon as the player returns from their first mining expedition. \n"
+ "In APOCALYPTIC mode, some important items are not craftable, but can be found in \n"
+ "treasure chests, requiring the players to pillage for their machines. \n"
+ "In TECH_PROGRESSION mode, important items are very complicated to craft using vanilla \n"
+ "items, but are easy to duplicate once they are made. This gives the players a sense of \n"
+ "invention and rising throught the ages from stone-age to space-age.",presets).toUpperCase(Locale.US).trim();
switch (mode){
case "NORMAL":
recipeMode = RecipeMode.NORMAL;
break;
case "APOCALYPTIC":
recipeMode = RecipeMode.APOCALYPTIC;
break;
case "TECH_PROGRESSION":
recipeMode = RecipeMode.TECH_PROGRESSION;
break;
default:
FMLLog.severe(MODID+" does not recognize recipe_mode '"+mode+"'");
throw new IllegalArgumentException("'"+mode+"' is not valid for config option 'recipe_mode'. Valid options are: NORMAL, APOCALYPTIC, or TECH_PROGRESSION");
}
chestLootFactor = config.getFloat("treasure_chest_loot_factor", "options", 0.5f, 0.0f, 1000.0f,
"Controls the rarity of items from this mod being found in treasure chests relative to \n"
+ "the frequency of other chest loot items. Set to 0 to disable metal ingots from \n"
+ "appearing in treasure chests.");
plasticIsAlsoRubber = config.getBoolean("plastic_equals_rubber", "options", plasticIsAlsoRubber,
"If true, then plastic will be useable in recipes as if it were rubber (for cross-mod compatibility)");
distillRecipes = config.getString("distiller_recipes", "recipes",
"2*crude_oil->1*refined_oil;2*oil->1*refined_oil",
"List of distiller recipes in the format of #*name1->#*name2 where # is an \n"
+ "integer number and name1 and name2 are the fluid names of the input and \n"
+ "output of the recipe")
.split(";");
useOtherFluids = config.getBoolean("use_other_fluids", "Other Power Mods", useOtherFluids,
"If true, then Power Advantage will use existing fluids added by other mods where possible");
String[] conversions = config.getString("RF_conversions", "Other Power Mods",
"steam=8;electricity=0.25;quantum=8",
"List of conversions from Power Advantage power types to RF, in units of RF per energy unit")
.split(";");
for(String c : conversions){
if(!c.contains("=")) continue;
String name = c.substring(0, c.indexOf('=')).trim().toLowerCase(Locale.US);
String val = c.substring(c.indexOf('=')+1).trim();
try{
Number d;
if(val.contains(".")){
d = new Double(Double.parseDouble(val));
} else {
d = Long.parseLong(val);
}
FMLLog.info("Adding conversion factor of "+d+" units of RF per unit of "+name);
rfConversionTable.put(new ConduitType(name), d.floatValue());
}catch(NumberFormatException ex){
FMLLog.severe("Cannot parse '"+val+"' as number");
}
}
String[] conversions2 = config.getString("TechReborn_conversions", "Other Power Mods",
"electricity=0.25",
"List of conversions from Power Advantage power types to EU, in units of EU per energy unit")
.split(";");
for(String c : conversions2){
if(!c.contains("=")) continue;
String name = c.substring(0, c.indexOf('=')).trim().toLowerCase(Locale.US);
String val = c.substring(c.indexOf('=')+1).trim();
try{
Number d;
if(val.contains(".")){
d = new Double(Double.parseDouble(val));
} else {
d = Long.parseLong(val);
}
FMLLog.info("Adding conversion factor of "+d+" EU per unit of "+name);
trConversionTable.put(new ConduitType(name), d.floatValue());
}catch(NumberFormatException ex){
FMLLog.severe("Cannot parse '"+val+"' as number");
}
}
config.save();
FMLLog.info("%s: creating orespawn file (if it doesn't already exist)", MODID);
Path orespawnFolder = Paths.get(event.getSuggestedConfigurationFile().toPath().getParent().toString(),"orespawn");
Path orespawnFile = Paths.get(orespawnFolder.toString(),MODID+".json");
if(!Files.exists(orespawnFile)){
try{
Files.createDirectories(orespawnFile.getParent());
Files.write(orespawnFile, Arrays.asList(WorldGen.ORESPAWN_FILE_CONTENTS.split("\n")), Charset.forName("UTF-8"));
} catch (IOException e) {
FMLLog.severe(MODID+": Error: Failed to write file "+orespawnFile);
}
}
FMLLog.info("%s: initializing fluids, blocks, items, and loot tables", MODID);
cyano.poweradvantage.init.Fluids.init();
cyano.poweradvantage.init.Blocks.init();
cyano.poweradvantage.init.Items.init();
cyano.poweradvantage.init.TreasureChests.init(event.getSuggestedConfigurationFile().toPath().getParent());
// keep this next comment, it is useful for finding Vanilla recipes
//OreDictionary.initVanillaEntries();
if(event.getSide() == Side.CLIENT){
clientPreInit(event);
}
if(event.getSide() == Side.SERVER){
serverPreInit(event);
}
FMLLog.info("%s: preinit complete", MODID);
}
@SideOnly(Side.CLIENT)
private void clientPreInit(FMLPreInitializationEvent event){
// client-only code
cyano.poweradvantage.init.Blocks.bakeModels();
}
@SideOnly(Side.SERVER)
private void serverPreInit(FMLPreInitializationEvent event){
// client-only code
}
/**
* Initialization step. Used for adding renderers and most content to the
* game
* @param event FML event object
*/
@EventHandler
public void init(FMLInitializationEvent event)
{
FMLLog.info("%s: starting main inititalization", MODID);
try {
FMLLog.info("%s: testing whether we have to support redstone flux", MODID);
Class rfClass = Class.forName("cofh.api.energy.IEnergyReceiver", false, getClass().getClassLoader());
detectedRF = rfClass != null;
FMLLog.info("%s: RF class detected: %s", MODID, rfClass);
} catch (ClassNotFoundException e) {
detectedRF = false;
FMLLog.info("%s: did not detect RF classes: %s", MODID, e.getMessage());
}
try {
FMLLog.info("%s: testing whether we have to support Tech Reborn", MODID);
Class trClass = Class.forName("reborncore.api.power.IEnergyInterfaceTile", false, getClass().getClassLoader());
detectedTechReborn = trClass != null;
FMLLog.info("%s: Tech Reborn class detected: %s", MODID, trClass);
} catch (ClassNotFoundException e) {
detectedTechReborn = false;
FMLLog.info("%s: did not detect Tech Reborn classes: %s", MODID, e.getMessage());
}
FMLLog.info("%s: adding GUI handler", MODID);
NetworkRegistry.INSTANCE.registerGuiHandler(PowerAdvantage.getInstance(), MachineGUIRegistry.getInstance());
GameRegistry.registerFuelHandler(FuelRegistry.getInstance());
FMLLog.info("%s: initializing more content", MODID);
cyano.poweradvantage.init.Fuels.init();
cyano.poweradvantage.init.Entities.init();
cyano.poweradvantage.init.Recipes.init();
cyano.poweradvantage.init.Recipes.initDistillationRecipes(distillRecipes);
cyano.poweradvantage.init.Villages.init();
cyano.poweradvantage.init.GUI.init();
FMLLog.info("%s: mod support data registries", MODID);
cyano.poweradvantage.init.ModSupport.init(detectedRF,detectedTechReborn);
if(event.getSide() == Side.CLIENT){
clientInit(event);
}
if(event.getSide() == Side.SERVER){
serverInit(event);
}
FMLLog.info("%s: initialize phase complete", MODID);
}
@SideOnly(Side.CLIENT)
private void clientInit(FMLInitializationEvent event){
// client-only code
FMLLog.info("%s: initializing renders", MODID);
cyano.poweradvantage.init.Items.registerItemRenders(event);
cyano.poweradvantage.init.Blocks.registerItemRenders(event);
cyano.poweradvantage.init.ModSupport.registerItemRenders(event);
}
@SideOnly(Side.SERVER)
private void serverInit(FMLInitializationEvent event){
// client-only code
}
/**
* Post-initialization step. Used for cross-mod options
* @param event FML event object
*/
@EventHandler
public void postInit(FMLPostInitializationEvent event)
{
FMLLog.info("%s: starting post-inititalization phase", MODID);
// alternative sprockets and other recipe adjustments (there may or may not be rods, depending on Base Metals version
for(ItemStack s : OreDictionary.getOres("gearSteel")){
OreDictionary.registerOre("sprocket",s);
}
if(recipeMode == RecipeMode.NORMAL){
for(ItemStack s : OreDictionary.getOres("gear")){
OreDictionary.registerOre("sprocket",s);
}
OreDictionary.registerOre("rod", Items.STICK);
}
if(recipeMode == RecipeMode.TECH_PROGRESSION && OreDictionary.getOres("rod").isEmpty()){
// no rod items, need substitute
OreDictionary.getOres("barsSteel").stream().forEach((ItemStack i)->OreDictionary.registerOre("rod",i));
}
FMLLog.info("%s: clearing cached data", MODID);
// Clear caches
DistillationRecipeRegistry.clearRecipeCache();
// Handle inter-mod action
Map<String,Set<Block>> modBlocks = sortBlocksByModID();
// hacking
//printHackingInfo(); // XXX: hacker stuff
if(event.getSide() == Side.CLIENT){
clientPostInit(event);
}
if(event.getSide() == Side.SERVER){
serverPostInit(event);
}
FMLLog.info("%s: post-init phase complete", MODID);
}
@SideOnly(Side.CLIENT)
private void clientPostInit(FMLPostInitializationEvent event){
// client-only code
}
@SideOnly(Side.SERVER)
private void serverPostInit(FMLPostInitializationEvent event){
// client-only code
}
/**
* Gets a singleton instance of this mod. Is null until the completion of the
* pre-initialization step
* @return The global instance of this mod
*/
public static PowerAdvantage getInstance() {
return instance;
}
private Map<String, Set<Block>> sortBlocksByModID() {
Map<String, Set<Block>> modMap = new HashMap<>();
GameData.getBlockRegistry().forEach((Block b)->{
final String modid = GameData.getBlockRegistry().getNameForObject(b).getResourceDomain();
modMap.computeIfAbsent(modid, (String id)->new HashSet<Block>());
modMap.get(modid).add(b);
});
return Collections.unmodifiableMap(modMap);
}
private void printHackingInfo() {
try {
// Object dump all blocks and class dump all tile entities
GameData.getBlockRegistry().forEach((Block b) -> {
FMLLog.info("Block: %s %s", b.getUnlocalizedName(), objectDump(b));
});
GameData.getItemRegistry().forEach((Item i) -> {
FMLLog.info("Item: %s %s", i.getUnlocalizedName(), objectDump(i));
});
FMLLog.info("class TileEntity: %s", superDump(null, TileEntity.class));
try {
Field f = TileEntity.class.getDeclaredField("field_145853_j");
f.setAccessible(true);
Map m = (Map) f.get(null);
// do TileEntity class dump
for (Object o : m.keySet()) {
FMLLog.info("TileEntity: %s", superDump(null, (Class) o));
}
} catch (Exception ex) {
FMLLog.severe("%s: Exception\n%s", MODID, ex);
}
}catch(Exception ex){
FMLLog.log(Level.INFO,ex,"Java reflection error during dump operation");
}
}
private static String objectDump(Object o){
if(o == null) return "null";
StringBuilder sb = new StringBuilder("\n");
Class c = o.getClass();
sb.append(c.getName()).append(" extends ").append(c.getSuperclass()).append("\n\t");
Class[] interfaces = c.getInterfaces();
if(interfaces != null && interfaces.length > 0){
sb.append("\t").append("Interfaces").append("\n\t");
for(Class i : interfaces){
sb.append(i.getName()).append("\n\t");
}
}
sb.append("\t").append("Variables").append("\n\t");
Field[] variables = c.getDeclaredFields();
for(Field f : variables){
if(Modifier.isPrivate(f.getModifiers())) sb.append("private ");
if(Modifier.isProtected(f.getModifiers())) sb.append("protected ");
if(Modifier.isPublic(f.getModifiers())) sb.append("public ");
if(Modifier.isStatic( f.getModifiers())) sb.append("static ");
if(Modifier.isFinal( f.getModifiers())) sb.append("final ");
sb.append(f.getType().getName()).append(" ");
sb.append(f.getName());
sb.append(" = ");
f.setAccessible(true);
if(Modifier.isStatic( f.getModifiers())){
try {
sb.append(f.get(null));
} catch (IllegalArgumentException | IllegalAccessException e) {
sb.append(e.getMessage());
}
} else {
try {
sb.append(f.get(o));
} catch (IllegalArgumentException | IllegalAccessException e) {
sb.append(e.getMessage());
}
}
sb.append("\n\t");
}
sb.append("\n\t");
sb.append("\t").append("Methods").append("\n\t");
Method[] functions = c.getDeclaredMethods();
for(Method f : functions){
if(Modifier.isPrivate(f.getModifiers())) sb.append("private ");
if(Modifier.isProtected(f.getModifiers())) sb.append("protected ");
if(Modifier.isPublic(f.getModifiers())) sb.append("public ");
if(Modifier.isStatic( f.getModifiers())) sb.append("static ");
sb.append(f.getReturnType().getName()).append(" ");
sb.append(f.getName()).append("(");
Parameter[] params = f.getParameters();
if(params != null && params.length > 0){
for(int i = 0; i < params.length; i++){
Parameter p = params[i];
if(i > 0) sb.append(", ");
sb.append(p.getType().getSimpleName());
}
}
sb.append(")\n\t");
}
return sb.toString();
}
private static String dumpField(Field f, Object inst) throws IllegalAccessException {
StringBuilder sb = new StringBuilder();
if(Modifier.isPrivate(f.getModifiers())) sb.append("private ");
if(Modifier.isProtected(f.getModifiers())) sb.append("protected ");
if(Modifier.isPublic(f.getModifiers())) sb.append("public ");
if(Modifier.isStatic( f.getModifiers())) sb.append("static ");
if(Modifier.isFinal( f.getModifiers())) sb.append("final ");
sb.append(f.getType().getCanonicalName()).append(" ");
if(inst != null || Modifier.isStatic(f.getModifiers())) {
f.setAccessible(true);
sb.append(f.getName()).append(" = ");
if (Modifier.isStatic(f.getModifiers())) {
sb.append(String.valueOf(f.get(null)));
} else {
sb.append(String.valueOf(f.get(inst)));
}
}
return sb.toString();
}
private static String dumpMethod(Method m) throws IllegalAccessException {
StringBuilder sb = new StringBuilder();
if(Modifier.isPrivate(m.getModifiers())) sb.append("private ");
if(Modifier.isProtected(m.getModifiers())) sb.append("protected ");
if(Modifier.isPublic(m.getModifiers())) sb.append("public ");
if(Modifier.isStatic( m.getModifiers())) sb.append("static ");
if(Modifier.isFinal( m.getModifiers())) sb.append("final ");
sb.append(m.getReturnType().getCanonicalName()).append(" ");
sb.append(m.getName()).append("(");
boolean b = false;
for(Class p : m.getParameterTypes()){
if(b) sb.append(", ");
if(p.isArray()){
sb.append(p.getComponentType().getSimpleName()).append("[]");
} else {
sb.append(p.getSimpleName());
}
b = true;
}
sb.append(")");
return sb.toString();
}
public static String superDump(Object o) throws IllegalAccessException {
Class c = o.getClass();
StringBuilder sb = new StringBuilder();
sb.append(c.getCanonicalName()).append(" ")
.append(String.valueOf(o))
.append(" {");
sb.append("\n\t").append( superDump(o, c));
sb.append("}");
return sb.toString();
}
public static String superDump(Object o, Class c) throws IllegalAccessException {
StringBuilder sb = new StringBuilder();
sb.append("class ").append(c.getCanonicalName());
if(c.getInterfaces().length > 0) sb.append(" implements ");
boolean b = false;
for(Class i : c.getInterfaces()){
if(b) sb.append(", ");
sb.append(i.getSimpleName());
b = true;
}
sb.append(":\n");
for(Field f : c.getDeclaredFields()){
sb.append("\t").append(dumpField(f,o)).append("\n");
}
for(Method m : c.getDeclaredMethods()){
sb.append("\t").append(dumpMethod(m)).append("\n");
}
for(Class i : c.getInterfaces()){
for(Method m : i.getDeclaredMethods()){
sb.append("\t@Implementation(").append(i.getCanonicalName()).append(") ")
.append(dumpMethod(m)).append("\n");
}
}
if(c.getSuperclass() != null && !c.equals(Object.class)){
sb.append("\nextends ").append(superDump(o,c.getSuperclass()));
}
return sb.toString();
}
}