]> git.seodisparate.com - TurnBasedMinecraftMod/commitdiff
WIP Add Config.java for setup/loading config
authorStephen Seo <seo.disparate@gmail.com>
Mon, 3 Sep 2018 06:19:33 +0000 (15:19 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 3 Sep 2018 06:19:33 +0000 (15:19 +0900)
src/main/java/com/seodisparate/TurnBasedMinecraft/TurnBasedMinecraftMod.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/Battle.java
src/main/java/com/seodisparate/TurnBasedMinecraft/common/Config.java [new file with mode: 0644]
src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java [new file with mode: 0644]
src/main/resources/TBM_Config.xml

index 0ae12db8f125ff2e24c6704fe1acd583bfb6f9ba..e4a3a045d9136a14f439ed0f87f43e8adb46cd33 100644 (file)
@@ -6,6 +6,7 @@ import org.apache.logging.log4j.Logger;
 
 import com.seodisparate.TurnBasedMinecraft.common.Battle;
 import com.seodisparate.TurnBasedMinecraft.common.BattleManager;
+import com.seodisparate.TurnBasedMinecraft.common.Config;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleDecision;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleEntered;
 import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleExited;
@@ -18,6 +19,7 @@ import net.minecraftforge.event.entity.living.LivingAttackEvent;
 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.relauncher.Side;
 
@@ -28,11 +30,16 @@ public class TurnBasedMinecraftMod
     public static final String NAME = "Turn Based Minecraft Mod";
     public static final String VERSION = "1.0";
     public static final Duration BattleDecisionTime = Duration.ofSeconds(15);
+    public static final String CONFIG_FILENAME = "TBM_Config.xml";
+    public static final String CONFIG_DIRECTORY = "config/TurnBasedMinecraft/";
+    public static final String CONFIG_FILE_PATH = CONFIG_DIRECTORY + CONFIG_FILENAME;
+    public static final int CONFIG_FILE_VERSION = 1; // TODO derive this from internal config
 
     private static Logger logger;
     private static BattleManager battleManager;
     private static int packetHandlerID = 0;
     public static Entity attackingEntity;
+    private static Config config;
     
     public static Battle currentBattle;
 
@@ -83,12 +90,14 @@ public class TurnBasedMinecraftMod
             Side.SERVER);
     }
     
-    /*
     @EventHandler
     public void postInit(FMLPostInitializationEvent event)
     {
+        if(battleManager != null)
+        {
+            config = new Config(logger);
+        }
     }
-    */
 
     @EventHandler
     public void entityAttacked(LivingAttackEvent event)
index 2395d7c3ad1682e8edf9169cf3a01cb1fd7f6bf7..78cf6e8a9be115c678102080470de8adbfb2ec5b 100644 (file)
@@ -6,7 +6,6 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Hashtable;
-import java.util.List;
 import java.util.Map;
 
 import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Config.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/Config.java
new file mode 100644 (file)
index 0000000..1d8897f
--- /dev/null
@@ -0,0 +1,245 @@
+package com.seodisparate.TurnBasedMinecraft.common;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.logging.log4j.Logger;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+import com.seodisparate.TurnBasedMinecraft.common.EntityInfo.Category;
+
+public class Config
+{
+    private Map<Class, EntityInfo> entityInfoMap;
+    private Set<EntityInfo.Category> ignoreBattleTypes;
+    private Logger logger;
+    
+    private enum ConfigParseResult
+    {
+        IS_OLD,
+        SUCCESS
+    }
+    
+    public Config(Logger logger)
+    {
+        entityInfoMap = new HashMap<Class, EntityInfo>();
+        ignoreBattleTypes = new HashSet<EntityInfo.Category>();
+        this.logger = logger;
+        
+        try
+        {
+            File testLoad = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+            if(!testLoad.exists())
+            {
+                writeConfig();
+            }
+        }
+        catch (Exception e)
+        {
+            logger.error("Failed to check/create-new config file");
+        }
+        
+        // parse xml
+        File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+        if(!configFile.exists() || !configFile.canRead())
+        {
+            logger.error("Failed to read/parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+            return;
+        }
+        try
+        {
+            ConfigParseResult result = parseConfig(configFile);
+            if(result == ConfigParseResult.IS_OLD)
+            {
+                moveOldConfig();
+                writeConfig();
+                ConfigParseResult resultSecond = parseConfig(configFile);
+                if(resultSecond != ConfigParseResult.SUCCESS)
+                {
+                    logger.error("Failed to parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+                }
+            }
+            else if(result != ConfigParseResult.SUCCESS)
+            {
+                logger.error("Failed to parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+            }
+        } catch (Exception e)
+        {
+            logger.error("Failed to parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+        }
+    }
+    
+    private void writeConfig() throws IOException
+    {
+        File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+        File dirs = configFile.getParentFile();
+        dirs.mkdirs();
+        InputStream configStream = this.getClass().getResourceAsStream(TurnBasedMinecraftMod.CONFIG_FILENAME);
+        FileOutputStream configOutput = new FileOutputStream(configFile);
+        byte[] buf = new byte[4096];
+        int read = 0;
+        while(read != -1)
+        {
+            read = configStream.read(buf);
+            if(read > 0)
+            {
+                configOutput.write(buf, 0, read);
+            }
+        }
+        configStream.close();
+        configOutput.close();
+    }
+    
+    private void moveOldConfig()
+    {
+        File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
+        if(configFile.exists())
+        {
+            configFile.renameTo(new File(TurnBasedMinecraftMod.CONFIG_DIRECTORY + "_"
+                    + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(Instant.now())));
+        }
+    }
+    
+    private ConfigParseResult parseConfig(File configFile) throws XMLStreamException, FactoryConfigurationError, IOException
+    {
+        FileInputStream fis = new FileInputStream(configFile);
+        XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(fis);
+        while(xmlReader.hasNext())
+        {
+            xmlReader.next();
+            if(xmlReader.isStartElement())
+            {
+                if(xmlReader.getLocalName().equals("TurnBasedMinecraftConfig"))
+                {
+                    continue;
+                }
+                else if(xmlReader.getLocalName().equals("Version"))
+                {
+                    if(Integer.parseInt(xmlReader.getElementText()) < TurnBasedMinecraftMod.CONFIG_FILE_VERSION)
+                    {
+                        logger.info("Config file is older version, moving it and writing a new one in its place");
+                        xmlReader.close();
+                        fis.close();
+                        return ConfigParseResult.IS_OLD;
+                    }
+                    continue;
+                }
+                else if(xmlReader.getLocalName().equals("IgnoreBattleTypes"))
+                {
+                    do
+                    {
+                        xmlReader.next();
+                        if(xmlReader.isStartElement())
+                        {
+                            ignoreBattleTypes.add(Category.fromString(xmlReader.getLocalName()));
+                        }
+                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("IgnoreBattleTypes")));
+                }
+                else if(xmlReader.getLocalName().equals("EntityStats"))
+                {
+                    do
+                    {
+                        xmlReader.next();
+                        if(xmlReader.isStartElement())
+                        {
+                            String classType = xmlReader.getLocalName();
+                            EntityInfo eInfo = new EntityInfo();
+                            try
+                            {
+                                eInfo.classType = Class.forName(classType);
+                            } catch (ClassNotFoundException e)
+                            {
+                                logger.error("Failed to get class of name " + classType);
+                                continue;
+                            }
+                            do
+                            {
+                                xmlReader.next();
+                                if(xmlReader.isStartElement())
+                                {
+                                    if(xmlReader.getLocalName().equals("AttackPower"))
+                                    {
+                                        for(int i = 0; i < xmlReader.getAttributeCount(); ++i)
+                                        {
+                                            if(xmlReader.getAttributeLocalName(i).equals("Probability"))
+                                            {
+                                                eInfo.attackProbability = Integer.parseInt(xmlReader.getAttributeValue(i));
+                                            }
+                                        }
+                                        eInfo.attackPower = Integer.parseInt(xmlReader.getElementText());
+                                    }
+                                    else if(xmlReader.getLocalName().equals("AttackEffect"))
+                                    {
+                                        for(int i = 0; i < xmlReader.getAttributeCount(); ++i)
+                                        {
+                                            if(xmlReader.getAttributeLocalName(i).equals("Probability"))
+                                            {
+                                                eInfo.attackEffectProbability = Integer.parseInt(xmlReader.getAttributeValue(i));
+                                            }
+                                        }
+                                        eInfo.attackEffect = EntityInfo.Effect.fromString(xmlReader.getElementText());
+                                    }
+                                    else if(xmlReader.getLocalName().equals("Evasion"))
+                                    {
+                                        eInfo.evasion = Integer.parseInt(xmlReader.getElementText());
+                                    }
+                                    else if(xmlReader.getLocalName().equals("DefenseDamage"))
+                                    {
+                                        for(int i = 0; i < xmlReader.getAttributeCount(); ++i)
+                                        {
+                                            if(xmlReader.getAttributeLocalName(i).equals("Probability"))
+                                            {
+                                                eInfo.defenseDamageProbability = Integer.parseInt(xmlReader.getAttributeValue(i));
+                                            }
+                                        }
+                                        eInfo.defenseDamage = Integer.parseInt(xmlReader.getElementText());
+                                    }
+                                    else if(xmlReader.getLocalName().equals("Category"))
+                                    {
+                                        eInfo.category = Category.fromString(xmlReader.getElementText());
+                                    }
+                                    else if(xmlReader.getLocalName().equals("Conflicts"))
+                                    {
+                                        do
+                                        {
+                                            xmlReader.next();
+                                            if(xmlReader.isStartElement())
+                                            {
+                                                try
+                                                {
+                                                    Class conflictingType = Class.forName(xmlReader.getLocalName());
+                                                    eInfo.conflictingTypes.add(conflictingType);
+                                                } catch(ClassNotFoundException e)
+                                                {
+                                                    logger.warn("Invalid conflicting type for entity " + eInfo.classType.getName());
+                                                }
+                                            }
+                                        } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("Conflicts")));
+                                    }
+                                }
+                            } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals(classType)));
+                            entityInfoMap.put(eInfo.classType, eInfo);
+                        }
+                    } while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("EntityStats")));
+                }
+            }
+        }
+        xmlReader.close();
+        fis.close();
+        return ConfigParseResult.SUCCESS;
+    }
+}
diff --git a/src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java b/src/main/java/com/seodisparate/TurnBasedMinecraft/common/EntityInfo.java
new file mode 100644 (file)
index 0000000..a068575
--- /dev/null
@@ -0,0 +1,225 @@
+package com.seodisparate.TurnBasedMinecraft.common;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EntityInfo
+{
+    public Class classType;
+    public List<Class> conflictingTypes;
+    public int attackPower;
+    public int attackProbability;
+    public Effect attackEffect;
+    public int attackEffectProbability;
+    public int defenseDamage;
+    public int defenseDamageProbability;
+    public int evasion;
+    public Category category;
+    
+    public enum Category
+    {
+        MONSTER,
+        PASSIVE,
+        ANIMAL,
+        BOSS,
+        UNKNOWN;
+        
+        public static Category fromString(String c)
+        {
+            c = c.toLowerCase();
+            if(c.equals("monster"))
+            {
+                return MONSTER;
+            }
+            else if(c.equals("passive"))
+            {
+                return PASSIVE;
+            }
+            else if(c.equals("animal"))
+            {
+                return ANIMAL;
+            }
+            else if(c.equals("boss"))
+            {
+                return BOSS;
+            }
+            else
+            {
+                return UNKNOWN;
+            }
+        }
+    }
+    
+    public enum Effect
+    {
+        SPEED,
+        SLOW,
+        HASTE,
+        MINING_FATIGUE,
+        STRENGTH,
+        JUMP_BOOST,
+        NAUSEA,
+        REGENERATION,
+        RESISTANCE,
+        FIRE_RESISTANCE,
+        WATER_BREATHING,
+        INVISIBILITY,
+        BLINDNESS,
+        NIGHT_VISION,
+        HUNGER,
+        WEAKNESS,
+        POISON,
+        WITHER,
+        ABSORPTION,
+        SATURATION,
+        GLOWING,
+        LEVITATION,
+        LUCK,
+        UNLUCK,
+        FIRE,
+        UNKNOWN;
+        
+        public static Effect fromString(String c)
+        {
+            c = c.toLowerCase();
+            if(c.equals("speed"))
+            {
+                return SPEED;
+            }
+            else if(c.equals("slow"))
+            {
+                return SLOW;
+            }
+            else if(c.equals("haste"))
+            {
+                return HASTE;
+            }
+            else if(c.equals("mining_fatigue") || c.equals("fatigue"))
+            {
+                return MINING_FATIGUE;
+            }
+            else if(c.equals("strength"))
+            {
+                return STRENGTH;
+            }
+            else if(c.equals("jump_boost"))
+            {
+                return JUMP_BOOST;
+            }
+            else if(c.equals("nausea"))
+            {
+                return NAUSEA;
+            }
+            else if(c.equals("regeneration"))
+            {
+                return REGENERATION;
+            }
+            else if(c.equals("resistance"))
+            {
+                return RESISTANCE;
+            }
+            else if(c.equals("fire_resistance"))
+            {
+                return FIRE_RESISTANCE;
+            }
+            else if(c.equals("water_breathing"))
+            {
+                return WATER_BREATHING;
+            }
+            else if(c.equals("invisibility"))
+            {
+                return INVISIBILITY;
+            }
+            else if(c.equals("blindness") || c.equals("blind"))
+            {
+                return BLINDNESS;
+            }
+            else if(c.equals("night_vision"))
+            {
+                return NIGHT_VISION;
+            }
+            else if(c.equals("hunger"))
+            {
+                return HUNGER;
+            }
+            else if(c.equals("weakness"))
+            {
+                return WEAKNESS;
+            }
+            else if(c.equals("poison"))
+            {
+                return POISON;
+            }
+            else if(c.equals("wither"))
+            {
+                return WITHER;
+            }
+            else if(c.equals("absorption"))
+            {
+                return ABSORPTION;
+            }
+            else if(c.equals("saturation"))
+            {
+                return SATURATION;
+            }
+            else if(c.equals("glowing"))
+            {
+                return GLOWING;
+            }
+            else if(c.equals("levitation"))
+            {
+                return LEVITATION;
+            }
+            else if(c.equals("luck"))
+            {
+                return LUCK;
+            }
+            else if(c.equals("unluck"))
+            {
+                return UNLUCK;
+            }
+            else if(c.equals("fire"))
+            {
+                return FIRE;
+            }
+            else
+            {
+                return UNKNOWN;
+            }
+        }
+    }
+    
+    public EntityInfo()
+    {
+        classType = null;
+        conflictingTypes = new ArrayList<Class>();
+        attackPower = 0;
+        attackProbability = 70;
+        attackEffect = Effect.UNKNOWN;
+        attackEffectProbability = 50;
+        defenseDamage = 0;
+        defenseDamageProbability = 0;
+        evasion = 15;
+        category = Category.UNKNOWN;
+    }
+    
+    public EntityInfo clone()
+    {
+        EntityInfo newEntityInfo = new EntityInfo();
+        newEntityInfo.classType = classType;
+        newEntityInfo.conflictingTypes = new ArrayList<Class>();
+        for(Class c : conflictingTypes)
+        {
+            newEntityInfo.conflictingTypes.add(c);
+        }
+        newEntityInfo.attackPower = attackPower;
+        newEntityInfo.attackProbability = attackProbability;
+        newEntityInfo.attackEffect = attackEffect;
+        newEntityInfo.attackEffectProbability = attackEffectProbability;
+        newEntityInfo.defenseDamage = defenseDamage;
+        newEntityInfo.defenseDamageProbability = defenseDamageProbability;
+        newEntityInfo.evasion = evasion;
+        newEntityInfo.category = category;
+        return newEntityInfo;
+    }
+}
index a897bd931a89017820b926fa7ceaaceeec5747ce..937660fab9ceca68b0469164ea0c15a6eb1d5e8b 100644 (file)
                        <AttackPower Probability="50">5</AttackPower>
                        <AttackEffect Probability="75">fire</AttackEffect>
                        <Evasion>5</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityBlaze>
                <net.minecraft.entity.monster.EntityCaveSpider>
                        <AttackPower Probability="75">2</AttackPower>
                        <AttackEffect Probability="90">poison</AttackEffect>
                        <Evasion>35</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityCaveSpider>
                <net.minecraft.entity.monster.EntityCreeper>
                        <IgnoreBattle>true</IgnoreBattle>
                        <AttackPower Probability="17" Variance="7">15</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityCreeper>
                <net.minecraft.entity.monster.EntityElderGuardian>
                        <AttackPower Probability="65">8</AttackPower>
                        <DefenseDamage Probability="35">2</DefenseDamage>
                        <Evasion>25</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityElderGuardian>
                <net.minecraft.entity.monster.EntityEnderman>
                        <AttackPower Probability="80">7</AttackPower>
                        <Evasion>40</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityEnderman>
                <net.minecraft.entity.monster.EntityEndermite>
                        <AttackPower Probability="80">2</AttackPower>
                        <Evasion>40</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityEndermite>
                <net.minecraft.entity.monster.EntityEvoker>
                        <AttackPower Probability="60">6</AttackPower>
                        <Evasion>35</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityEvoker>
                <net.minecraft.entity.monster.EntityGhast>
                        <IgnoreBattle>true</IgnoreBattle>
                        <AttackPower Probability="20">13</AttackPower>
                        <Evasion>35</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityGhast>
                <net.minecraft.entity.monster.EntityGiantZombie>
                        <AttackPower Probability="35">11</AttackPower>
                        <Evasion>2</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityGiantZombie>
                <net.minecraft.entity.monster.EntityGuardian>
                        <AttackPower Probability="55">6</AttackPower>
                        <DefenseDamage Probability="30">2</DefenseDamage>
                        <Evasion>25</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityGuardian>
                <net.minecraft.entity.monster.EntityHusk>
                        <AttackPower Probability="70">3</AttackPower>
                        <AttackEffect Probability="95">hunger</AttackEffect>
                        <Evasion>5</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityHusk>
                <net.minecraft.entity.monster.EntityIronGolem>
                        <AttackPower Probability="85" Variance="7">14</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityIronGolem>
                <net.minecraft.entity.monster.EntityMagmaCube>
                        <AttackPower Probability="35">3</AttackPower>
                        <Evasion>12</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityMagmaCube>
                <net.minecraft.entity.monster.EntityPigZombie>
                        <AttackPower Probability="70">8</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityPigZombie>
                <net.minecraft.entity.monster.EntityPolarBear>
                        <AttackPower Probability="67">6</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>animal</Category>
                </net.minecraft.entity.monster.EntityPolarBear>
                <net.minecraft.entity.monster.EntityShulker>
                        <AttackPower Probability="80">4</AttackPower>
                        <Evasion>15</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityShulker>
                <net.minecraft.entity.monster.EntitySilverFish>
                        <AttackPower Probability="85">1</AttackPower>
                        <Evasion>37</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntitySilverFish>
                <net.minecraft.entity.monster.EntitySkeleton>
                        <AttackPower Probability="75" Variance="1">3</AttackPower>
                        <Evasion>13</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntitySkeleton>
                <net.minecraft.entity.monster.EntitySlime>
                        <AttackPower Probability="35">2</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntitySlime>
-               <net.minecraft.entity.monster.EntitySnowman
-                       Passive="true">
+               <net.minecraft.entity.monster.EntitySnowman>
                        <AttackPower Probability="80">0</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.monster.EntitySnowman>
                <net.minecraft.entity.monster.EntitySpider>
                        <AttackPower Probability="70">2</AttackPower>
                        <Conflicts>
                                <net.minecraft.entity.monster.EntityCaveSpider></net.minecraft.entity.monster.EntityCaveSpider>
                        </Conflicts>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntitySpider>
                <net.minecraft.entity.monster.EntityStray>
                        <AttackPower Probability="75" Variance="1">3</AttackPower>
-                       <AttackEffect Probability="90">slowness</AttackEffect>
+                       <AttackEffect Probability="90">slow</AttackEffect>
                        <Evasion>13</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityStray>
                <net.minecraft.entity.monster.EntityVex>
                        <AttackPower Probability="65">9</AttackPower>
                        <Evasion>30</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityVex>
                <net.minecraft.entity.monster.EntityVindicator>
                        <AttackPower Probability="70">13</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityVindicator>
                <net.minecraft.entity.monster.EntityWitch>
                        <AttackPower Probability="75" Variance="1">5</AttackPower>
                        <Evasion>8</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityWitch>
                <net.minecraft.entity.monster.EntityWitherSkeleton>
                        <AttackPower Probability="70">8</AttackPower>
                        <AttackEffect Probability="90">wither</AttackEffect>
                        <Evasion>7</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityWitherSkeleton>
                <net.minecraft.entity.monster.EntityZombie>
                        <AttackPower Probability="70">3</AttackPower>
                                <net.minecraft.entity.monster.EntityZombieVillager></net.minecraft.entity.monster.EntityZombieVillager>
                        </Conflicts>
                        <Evasion>5</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityZombie>
                <net.minecraft.entity.monster.EntityZombieVillager>
                        <AttackPower Probability="70">3</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>monster</Category>
                </net.minecraft.entity.monster.EntityZombieVillager>
-               <net.minecraft.entity.passive.EntityBat
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityBat>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>35</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityBat>
-               <net.minecraft.entity.passive.EntityChicken
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityChicken>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityChicken>
-               <net.minecraft.entity.passive.EntityCow
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityCow>
                        <AttackPower Probability="50">0</AttackPower>
                        <Evasion>1</Evasion>
                        <Conflicts>
                                <net.minecraft.entity.passive.EntityMooshroom></net.minecraft.entity.passive.EntityMooshroom>
                        </Conflicts>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityCow>
-               <net.minecraft.entity.passive.EntityDonkey
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityDonkey>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityDonkey>
-               <net.minecraft.entity.passive.EntityHorse
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityHorse>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityHorse>
-               <net.minecraft.entity.passive.EntityLlama
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityLlama>
                        <AttackPower Probability="70">1</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityLlama>
-               <net.minecraft.entity.passive.EntityMooshroom
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityMooshroom>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>1</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityMooshroom>
-               <net.minecraft.entity.passive.EntityMule
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityMule>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityMule>
-               <net.minecraft.entity.passive.EntityOcelot
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityOcelot>
                        <AttackPower Probability="70" Variance="1">1</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityOcelot>
-               <net.minecraft.entity.passive.EntityParrot
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityParrot>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>35</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityParrot>
-               <net.minecraft.entity.passive.EntityPig
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityPig>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>10</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityPig>
-               <net.minecraft.entity.passive.EntityRabbit
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityRabbit>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>40</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityRabbit>
-               <net.minecraft.entity.passive.EntitySheep
-                       Passive="true">
+               <net.minecraft.entity.passive.EntitySheep>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntitySheep>
-               <net.minecraft.entity.passive.EntitySkeletonHorse
-                       Passive="true">
+               <net.minecraft.entity.passive.EntitySkeletonHorse>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntitySkeletonHorse>
-               <net.minecraft.entity.passive.EntitySquid
-                       Passive="true">
+               <net.minecraft.entity.passive.EntitySquid>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>15</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntitySquid>
-               <net.minecraft.entity.passive.EntityVillager
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityVillager>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>5</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityVillager>
                <net.minecraft.entity.passive.EntityWolf>
                        <AttackPower Probability="70">4</AttackPower>
                        <Evasion>20</Evasion>
+                       <Category>animal</Category>
                </net.minecraft.entity.passive.EntityWolf>
-               <net.minecraft.entity.passive.EntityZombieHorse
-                       Passive="true">
+               <net.minecraft.entity.passive.EntityZombieHorse>
                        <AttackPower Probability="70">0</AttackPower>
                        <Evasion>8</Evasion>
+                       <Category>passive</Category>
                </net.minecraft.entity.passive.EntityZombieHorse>
-               <net.minecraft.entity.boss.EntityDragon
-                       Boss="true">
+               <net.minecraft.entity.boss.EntityDragon>
                        <AttackPower Probability="70" Variance="2">10</AttackPower>
                        <Evasion>27</Evasion>
+                       <Category>boss</Category>
                </net.minecraft.entity.boss.EntityDragon>
-               <net.minecraft.entity.boss.EntityWither
-                       Boss="true">
+               <net.minecraft.entity.boss.EntityWither>
                        <AttackPower Probability="70">8</AttackPower>
                        <Evasion>20</Evasion>
                        <AttackEffect Probability="90">wither</AttackEffect>
+                       <Category>boss</Category>
                </net.minecraft.entity.boss.EntityWither>
        </EntityStats>
 </TurnBasedMinecraftConfig>
\ No newline at end of file