Browse Source

Port für BlockProtection, AFK, Effekt-Basics, Environment, DataTools

Kajetan Johannes Hammerle 7 years ago
parent
commit
bd936b7987
41 changed files with 2400 additions and 177 deletions
  1. 8 0
      build.gradle
  2. 26 26
      gradlew
  3. 4 4
      gradlew.bat
  4. 14 13
      src/main/java/me/km/KajetansMod.java
  5. 37 0
      src/main/java/me/km/afk/AfkListener.java
  6. 70 0
      src/main/java/me/km/afk/CommandAFK.java
  7. 3 4
      src/main/java/me/km/api/MessageSender.java
  8. 1 1
      src/main/java/me/km/api/ModuleTabCommand.java
  9. 78 21
      src/main/java/me/km/api/Utils.java
  10. 0 1
      src/main/java/me/km/blockprotections/BlockProtection.java
  11. 5 4
      src/main/java/me/km/blockprotections/SemiProtections.java
  12. 2 3
      src/main/java/me/km/commands/CommandItemInfo.java
  13. 1 0
      src/main/java/me/km/commands/CommandPotion.java
  14. 1 1
      src/main/java/me/km/commands/CommandSkull.java
  15. 10 3
      src/main/java/me/km/commands/CommandTest.java
  16. 292 0
      src/main/java/me/km/datatools/CommandDataTools.java
  17. 160 0
      src/main/java/me/km/datatools/CommandVillager.java
  18. 99 0
      src/main/java/me/km/datatools/DataToolsEvents.java
  19. 104 0
      src/main/java/me/km/effects/ActiveEffectBase.java
  20. 54 0
      src/main/java/me/km/effects/CommandWand.java
  21. 193 0
      src/main/java/me/km/effects/Effect.java
  22. 84 0
      src/main/java/me/km/effects/EffectBlockChanger.java
  23. 21 0
      src/main/java/me/km/effects/EffectCause.java
  24. 208 0
      src/main/java/me/km/effects/EffectUtils.java
  25. 68 0
      src/main/java/me/km/effects/PlayerUsesEffectEvent.java
  26. 55 0
      src/main/java/me/km/environment/CommandHealStats.java
  27. 32 0
      src/main/java/me/km/environment/CommandTemperature.java
  28. 184 0
      src/main/java/me/km/environment/EnvironmentAPI.java
  29. 137 0
      src/main/java/me/km/environment/EnvironmentEvents.java
  30. 97 0
      src/main/java/me/km/environment/EnvironmentTick.java
  31. 7 3
      src/main/java/me/km/items/ModItems.java
  32. 1 89
      src/main/java/me/km/nms/NmsUtilities.java
  33. 15 3
      src/main/java/me/km/permissions/Permissions.java
  34. 52 0
      src/main/java/me/km/skills/Skill.java
  35. 20 0
      src/main/java/me/km/utils/EntityInventory.java
  36. 31 0
      src/main/java/me/km/utils/InventoryUtils.java
  37. 1 1
      src/main/java/me/km/utils/ItemStackBuilder.java
  38. 195 0
      src/main/java/me/km/utils/ItemStackUtils.java
  39. 30 0
      src/main/java/me/km/utils/ReflectionUtils.java
  40. BIN
      src/main/resources/assets/km/textures/blocks/real_hay_block_side.png
  41. BIN
      src/main/resources/assets/km/textures/blocks/real_hay_block_top.png

+ 8 - 0
build.gradle

@@ -75,4 +75,12 @@ processResources {
     from(sourceSets.main.resources.srcDirs) {
         exclude 'mcmod.info'
     }
+    
+    //rename '(.+_at.cfg)', 'META-INF/$1'
 }
+/*
+jar {
+    manifest {
+        attributes 'FMLAT': 'km_at.cfg'
+    }
+}*/

+ 26 - 26
gradlew

@@ -6,12 +6,30 @@
 ##
 ##############################################################################
 
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
 
 APP_NAME="Gradle"
 APP_BASE_NAME=`basename "$0"`
 
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
 # Use the maximum available, or set MAX_FD != -1 to use that value.
 MAX_FD="maximum"
 
@@ -30,6 +48,7 @@ die ( ) {
 cygwin=false
 msys=false
 darwin=false
+nonstop=false
 case "`uname`" in
   CYGWIN* )
     cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
   MINGW* )
     msys=true
     ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
 esac
 
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
-    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
 # Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
     MAX_FD_LIMIT=`ulimit -H -n`
     if [ $? -eq 0 ] ; then
         if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
 if $cygwin ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath
     ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`

+ 4 - 4
gradlew.bat

@@ -8,14 +8,14 @@
 @rem Set local scope for the variables with windows NT shell
 if "%OS%"=="Windows_NT" setlocal
 
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
 set DIRNAME=%~dp0
 if "%DIRNAME%" == "" set DIRNAME=.
 set APP_BASE_NAME=%~n0
 set APP_HOME=%DIRNAME%
 
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
 @rem Find java.exe
 if defined JAVA_HOME goto findJavaFromJavaHome
 
@@ -46,7 +46,7 @@ echo location of your Java installation.
 goto fail
 
 :init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
 
 if not "%OS%" == "Windows_NT" goto win9xME_args
 if "%@eval[2+2]" == "4" goto 4NT_args

+ 14 - 13
src/main/java/me/km/KajetansMod.java

@@ -8,6 +8,7 @@ import me.km.chatmanager.ChatManager;
 import me.km.databank.DataBank;
 import me.km.dimensions.ModDimensions;
 import me.km.dimensions.WorldData;
+import me.km.effects.EffectUtils;
 import me.km.entities.ModEntities;
 import me.km.fluids.ModFluids;
 import me.km.items.ModItems;
@@ -36,15 +37,15 @@ public class KajetansMod
     public static PlayerManager playerbank;
     public static Module generalCommands;
     public static ChatManager chatManager;
-    //public static Module afkManager;
+    public static Module afkManager;
     //public static Module plots;
     public static Module blocks;
-    //public static Module datatools;
+    public static Module datatools;
     public static WorldData worldManager;
     //public static Module environment;
     //public static QuestAPI quest;
     //public static JobAPI jobs;
-    //public static EffectUtils effects;
+    public static EffectUtils effects;
     //public static SkillManager skills;
     //public static Module scrolls;
     //public static Customs customs;
@@ -107,9 +108,9 @@ public class KajetansMod
         chatManager.registerEvents("me.km.chatmanager");
         
         // AFK-Manager
-        /*afkManager = new Module("AfkManager", "AFK", TextFormatting.GRAY);
-        afkManager.registerCommands(e, "me.kt.afk");
-        afkManager.registerEvents("me.kt.afk");*/
+        afkManager = new Module("AfkManager", "AFK", TextFormatting.GRAY);
+        afkManager.registerCommands(e, "me.km.afk");
+        afkManager.registerEvents("me.km.afk");
         
         // Plot-System
         /*plots = new Module("Plots", "Plots", TextFormatting.GOLD);
@@ -124,9 +125,9 @@ public class KajetansMod
         blocks.registerEvents("me.km.blockprotections");
         
         // DataTools
-        /*datatools = new Module("DataTools", "DataTools", TextFormatting.GRAY);
-        datatools.registerCommands(e, "me.kt.datatools");          
-        datatools.registerEvents("me.kt.datatools");*/
+        datatools = new Module("DataTools", "DataTools", TextFormatting.GRAY);
+        datatools.registerCommands(e, "me.km.datatools");          
+        datatools.registerEvents("me.km.datatools");
 
         // Worldmanager
         worldManager = new WorldData("WorldManager", "Worlds", TextFormatting.RED);
@@ -147,9 +148,9 @@ public class KajetansMod
         jobs.registerEvents("me.kt.jobsystem"); */
         
         // Effectsystem
-        /*effects = new EffectUtils("Effects", "Effects", TextFormatting.BLUE);
-        effects.registerCommands(e, "me.kt.effects"); 
-        effects.registerEvents("me.kt.effects.passive"); */
+        effects = new EffectUtils("Effects", "Effects", TextFormatting.BLUE);
+        effects.registerCommands(e, "me.km.effects"); 
+        effects.registerEvents("me.km.effects.passive"); 
         
         // Skillshopsystem
         /*skills = new SkillManager("SkillSystem", "Skills", TextFormatting.BLUE);
@@ -198,7 +199,7 @@ public class KajetansMod
     @Mod.EventHandler
     public void postInit(FMLPostInitializationEvent event) 
     {
-
+        ModItems.lateInit();
     }
     
     /*public static void main(String[] args)

+ 37 - 0
src/main/java/me/km/afk/AfkListener.java

@@ -0,0 +1,37 @@
+package me.km.afk;
+
+import me.km.api.Module;
+import me.km.api.ModuleListener;
+import java.util.HashSet;
+import java.util.UUID;
+import net.minecraft.entity.player.EntityPlayer;
+
+public class AfkListener extends ModuleListener
+{
+    private final HashSet<UUID> afk;
+    
+    public AfkListener(Module m) 
+    {
+        super(m);
+        afk = new HashSet<>();
+    }
+    
+    // -------------------------------------------------------------------------
+    // Afk abrufen und setzen
+    // -------------------------------------------------------------------------
+    
+    public boolean isAfk(EntityPlayer p)
+    {
+        return afk.contains(p.getUniqueID());
+    }
+    
+    public void setAfk(EntityPlayer p, boolean b)
+    {
+        if(b)
+        {
+            afk.add(p.getUniqueID());
+            return;
+        }
+        afk.remove(p.getUniqueID());
+    }
+}

+ 70 - 0
src/main/java/me/km/afk/CommandAFK.java

@@ -0,0 +1,70 @@
+package me.km.afk;
+
+import me.km.KajetansMod;
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.api.Utils;
+import me.km.exception.PlayerNotFoundException;
+import me.km.permissions.Permission;
+import me.km.permissions.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
+
+public class CommandAFK extends ModuleCommand
+{
+    public CommandAFK(Module m) 
+    {
+        super("afk", m);
+        super.setDescription("Schaltet den AFK-Zustand ein / aus");
+        super.setUsage("/afk [player]");
+        super.setPermission(Permissions.AFK);
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        EntityPlayer affectedPlayer;
+        try
+        {
+            if(!Permission.hasPermission(cs, Permissions.AFK))
+            {
+                throw new IndexOutOfBoundsException();
+            }   
+            affectedPlayer = Utils.getPlayerByName(arg[0]); 
+        }
+        catch(PlayerNotFoundException ex)
+        {
+            this.getModule().send(cs, GlobalText.cantFindPlayer(arg[0]));
+            return true;
+        }
+        catch(IndexOutOfBoundsException ex)
+        {
+            if(!(cs instanceof EntityPlayer))
+            {
+                this.getModule().send(cs, GlobalText.missingParameter());
+                return true;
+            }
+            affectedPlayer = (EntityPlayer) cs;
+        }
+
+        AfkListener man = KajetansMod.afkManager.getEvent(AfkListener.class);
+        if(man.isAfk(affectedPlayer))
+        {
+            man.setAfk(affectedPlayer, false);
+            this.getModule().send(affectedPlayer, "Du bist nicht mehr AFK.");
+            if(!cs.equals(affectedPlayer))
+            {
+                this.getModule().send(cs, affectedPlayer.getName() + " ist nicht mehr AFK.");
+            }
+            return true;
+        }
+        man.setAfk(affectedPlayer, true);
+        this.getModule().send(affectedPlayer, "Du bist nun AFK.");
+        if(!cs.equals(affectedPlayer))
+        {
+            this.getModule().send(cs, affectedPlayer.getName() + " ist nun AFK.");
+        }
+        return true;
+    }
+}

+ 3 - 4
src/main/java/me/km/api/MessageSender.java

@@ -4,9 +4,8 @@ import java.util.ArrayList;
 import me.km.KajetansMod;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
 import net.minecraft.util.text.ITextComponent;
-import net.minecraft.util.text.TextComponentUtils;
 import net.minecraft.util.text.TextFormatting;
 import net.minecraft.util.text.TextComponentString;
 import net.minecraft.world.World;
@@ -44,10 +43,10 @@ public class MessageSender
         send(cs, msg, 0);
     }
     
-    public void sendToPlayers(World w, BlockPos l, double radius, String msg)
+    public void sendToPlayers(World w, Vec3d v, double radius, String msg)
     {
         ITextComponent s = prefixes.get(0).createCopy().appendText(msg);
-        Utils.getNearbyEntities(w, l, radius, EntityPlayer.class).forEach(p -> ((EntityPlayer) p).sendMessage(s));
+        Utils.getNearbyEntities(w, v, radius, EntityPlayer.class).forEach(p -> ((EntityPlayer) p).sendMessage(s));
     }
     
     public void sendBroadcast(String msg)

+ 1 - 1
src/main/java/me/km/api/ModuleTabCommand.java

@@ -22,6 +22,6 @@ public abstract class ModuleTabCommand extends ModuleCommand
     @Override
     public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) 
     {
-        return args.length == argument - 1 ? CommandBase.getListOfStringsMatchingLastWord(args, list) : Collections.<String>emptyList();
+        return args.length == argument + 1 ? CommandBase.getListOfStringsMatchingLastWord(args, list) : Collections.<String>emptyList();
     }
 }

+ 78 - 21
src/main/java/me/km/api/Utils.java

@@ -1,5 +1,6 @@
 package me.km.api;
 
+import me.km.utils.ItemStackBuilder;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -374,46 +375,102 @@ public class Utils
     @SuppressWarnings("unchecked")
     public static List<Entity> getEntitiesExcluding(Entity ent, World w, BlockPos pos, BlockPos pos2)
     {       
-        return w.getEntitiesWithinAABBExcludingEntity(ent, new AxisAlignedBB(pos, pos2));
+        return w.getEntitiesWithinAABBExcludingEntity(ent, new AxisAlignedBB(pos, pos2).expandXyz(1));
     }
     
     @SuppressWarnings("unchecked")
-    public static <T extends Entity> Collection<T> getNearbyEntities(World w, BlockPos l, double radius, Class<T> type)
+    public static <T extends Entity> Collection<T> getNearbyEntities(World w, Vec3d v, double radius, Class<T> type)
     {       
         double sqareRadius = radius * radius;
         return w.getEntitiesWithinAABB(type, new AxisAlignedBB(
-                l.getX() - radius, l.getY() - radius, l.getZ() - radius, 
-                l.getX() + radius, l.getY() + radius, l.getZ() + radius), ent -> ent.getDistanceSq(l) <= sqareRadius);
+                v.xCoord - radius, v.yCoord - radius, v.zCoord - radius, 
+                v.xCoord + radius, v.yCoord + radius, v.zCoord + radius), ent -> ent.getDistanceSq(v.xCoord, v.yCoord, v.zCoord) <= sqareRadius);
+    }
+    
+    public static List<EntityPlayer> getNearbyPlayers(World w, double x, double y, double z, double radius)
+    {       
+        double sqareRadius = radius * radius;
+        return w.playerEntities.stream().filter(p -> p.getDistanceSq(x, y, z) <= sqareRadius).collect(Collectors.toList());
+    }
+    
+    public static List<EntityPlayer> getNearbyPlayers(World w, Vec3d v, double radius)
+    {       
+        return getNearbyPlayers(w, v.xCoord, v.yCoord, v.zCoord, radius);
     }
 
-    public static <T extends Entity> T getNearestEntity(World w, BlockPos l, double radius, Class<T> type)
+    public static <T extends Entity> T getNearestEntity(World w, Vec3d v, double radius, Class<T> type)
     {
-        return getNearbyEntities(w, l, radius, type).stream().min((e1, e2) -> Double.compare(
-                        e1.getDistanceSq(l), 
-                        e2.getDistanceSq(l)))
+        return getNearbyEntities(w, v, radius, type).stream().min((e1, e2) -> Double.compare(
+                        e1.getDistanceSq(v.xCoord, v.yCoord, v.zCoord), 
+                        e2.getDistanceSq(v.xCoord, v.yCoord, v.zCoord)))
                 .orElse(null);
     }
     
+    public static boolean doesIntersect(AxisAlignedBB bound, Vec3d start, Vec3d unit)
+    {
+        double lowerX = Double.NEGATIVE_INFINITY;
+        double upperX = Double.POSITIVE_INFINITY;
+        if(unit.xCoord != 0)
+        {
+            if(unit.xCoord > 0)
+            {
+                lowerX = (bound.minX - start.xCoord) / unit.xCoord;
+                upperX = (bound.maxX - start.xCoord) / unit.xCoord;
+            }
+            else
+            {
+                lowerX = (bound.maxX - start.xCoord) / unit.xCoord;
+                upperX = (bound.minX - start.xCoord) / unit.xCoord;
+            }
+        }
+        
+        double lowerY = Double.NEGATIVE_INFINITY;
+        double upperY = Double.POSITIVE_INFINITY;
+        if(unit.yCoord != 0)
+        {
+            if(unit.yCoord > 0)
+            {
+                lowerY = (bound.minY - start.yCoord) / unit.yCoord;
+                upperY = (bound.maxY - start.yCoord) / unit.yCoord;
+            }
+            else
+            {
+                lowerY = (bound.maxY - start.yCoord) / unit.yCoord;
+                upperY = (bound.minY - start.yCoord) / unit.yCoord;
+            }
+        }
+        
+        double lowerZ = Double.NEGATIVE_INFINITY;
+        double upperZ = Double.POSITIVE_INFINITY;
+        if(unit.zCoord != 0)
+        {
+            if(unit.zCoord > 0)
+            {
+                lowerZ = (bound.minZ - start.zCoord) / unit.zCoord;
+                upperZ = (bound.maxZ - start.zCoord) / unit.zCoord;
+            }
+            else
+            {
+                lowerZ = (bound.maxZ - start.zCoord) / unit.zCoord;
+                upperZ = (bound.minZ - start.zCoord) / unit.zCoord;
+            }
+        }
+
+        return Math.max(Math.max(lowerX, lowerY), lowerZ) < Math.min(Math.min(upperX, upperY), upperZ);
+    }
+    
     @SuppressWarnings("unchecked")
-    public static <T extends Entity> T getTargetedEntity(EntityPlayer p, int radius, Class<T> type)
+    public static <T extends Entity> T getTargetedEntity(EntityPlayer p, double radius, Class<T> type)
     {
         World w = p.getEntityWorld();
         BlockPos l = getPlayerTarget(p, radius);
-        Vec3d end = new Vec3d(l.getX(), l.getY(), l.getZ());
         Vec3d eye = getEyeLocation(p);
+        Vec3d unit = new Vec3d(l.getX() - eye.xCoord, l.getY() - eye.yCoord, l.getZ() - eye.zCoord);
+        
         List<Entity> col = getEntitiesExcluding(p, w, new BlockPos(eye), l);
         col.removeIf(ent -> !type.isAssignableFrom(ent.getClass()));
-        
         // Entfernt Entities, die sich nicht mit dem Blick-Vektor schneiden
-        col.removeIf(ent -> 
-        {
-            AxisAlignedBB bound = ent.getCollisionBoundingBox();
-            if(bound == null)
-            {
-                return true;
-            }
-            return bound.calculateIntercept(eye, end) == null;
-        });
+        col.removeIf(ent -> !doesIntersect(ent.getEntityBoundingBox().expandXyz(0.1), eye, unit));
 
         return (T) col.stream().sorted((Entity e1, Entity e2) -> 
         {
@@ -439,7 +496,7 @@ public class Utils
         World w = p.getEntityWorld();
         Vec3d start = getEyeLocation(p);
         Vec3d end = start.add(p.getLookVec().scale(range));
-        RayTraceResult ray = w.rayTraceBlocks(start, end, true);
+        RayTraceResult ray = w.rayTraceBlocks(start, end, true, true, false);
         if(ray == null)
         {
             return new BlockPos(end);

+ 0 - 1
src/main/java/me/km/blockprotections/BlockProtection.java

@@ -84,7 +84,6 @@ public class BlockProtection extends ModuleListener
         if(Utils.shouldBeProtected(state.getBlock()))
         {
             BlockPos pos = e.getPos();
-            this.getModule().send(p, pos.toString());
             if(Utils.getStateValue(state, BlockDoor.HALF) == BlockDoor.EnumDoorHalf.UPPER)
             {
                 pos = pos.add(0, -1, 0);

+ 5 - 4
src/main/java/me/km/blockprotections/SemiProtections.java

@@ -1,6 +1,5 @@
 package me.km.blockprotections;
 
-import me.km.KajetansMod;
 import me.km.api.Module;
 import me.km.api.ModuleListener;
 import me.km.permissions.Permission;
@@ -8,7 +7,6 @@ import me.km.permissions.Permissions;
 import net.minecraft.block.BlockCrops;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.util.math.BlockPos;
 import net.minecraftforge.event.world.BlockEvent;
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 
@@ -39,8 +37,11 @@ public class SemiProtections extends ModuleListener
                 return;
             }*/
             e.setCanceled(true); 
-            b.getBlock().dropBlockAsItem(e.getWorld(), e.getPos(), b, 0);
-            e.getWorld().setBlockState(e.getPos(), b.withProperty(BlockCrops.AGE, 7));
+            if(b.getValue(BlockCrops.AGE) == 7)
+            {
+                b.getBlock().dropBlockAsItem(e.getWorld(), e.getPos(), b, 0);
+            }
+            e.getWorld().setBlockState(e.getPos(), b.withProperty(BlockCrops.AGE, 0));
         }
     }
 }

+ 2 - 3
src/main/java/me/km/commands/CommandItemInfo.java

@@ -5,11 +5,10 @@ import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.nms.NmsUtilities;
 import me.km.permissions.Permissions;
+import me.km.utils.ItemStackUtils;
 import net.minecraft.command.ICommandSender;
-import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.item.ItemStack;
-import net.minecraft.util.text.ITextComponent;
 import net.minecraft.util.text.TextComponentString;
 
 public class CommandItemInfo extends ModuleCommand
@@ -42,7 +41,7 @@ public class CommandItemInfo extends ModuleCommand
         m.send(cs, "DV: §6" + stack.getItemDamage());
         m.send(cs, "Meta: §6" + stack.getMetadata());
         m.send(cs, "Item: §6" + stack.getItem());
-        NmsUtilities.sendCopyableText(p, NmsUtilities.getNbtString(stack).replace("\"", "'"));
+        NmsUtilities.sendCopyableText(p, ItemStackUtils.getNbtString(stack).replace("\"", "'"));
         return true;
     }
 }

+ 1 - 0
src/main/java/me/km/commands/CommandPotion.java

@@ -60,6 +60,7 @@ public class CommandPotion extends ModuleTabCommand
             ArrayList<PotionEffect> list = new ArrayList<>();
             list.add(new PotionEffect(Utils.getPotion(arg[0]), Integer.parseInt(arg[1]), Integer.parseInt(arg[2])));
             PotionUtils.addCustomPotionEffectToList(com, list);
+            hand.setTagCompound(com);
             this.getModule().send(cs, "Der Effekt wurde hinzugefügt.");
         }
         catch(NumberFormatException ex)

+ 1 - 1
src/main/java/me/km/commands/CommandSkull.java

@@ -3,7 +3,7 @@ package me.km.commands;
 import com.mojang.authlib.GameProfile;
 import me.km.KajetansMod;
 import me.km.api.GlobalText;
-import me.km.api.ItemStackBuilder;
+import me.km.utils.ItemStackBuilder;
 import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.permissions.Permissions;

+ 10 - 3
src/main/java/me/km/commands/CommandTest.java

@@ -6,9 +6,10 @@ import me.km.api.ModuleCommand;
 import me.km.api.Utils;
 import me.km.permissions.Permissions;
 import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLivingBase;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.init.Blocks;
-import net.minecraft.util.math.BlockPos;
 
 public class CommandTest extends ModuleCommand
 {
@@ -29,8 +30,14 @@ public class CommandTest extends ModuleCommand
             return true;
         }
         EntityPlayer p = (EntityPlayer) cs;
-        BlockPos pos = Utils.getPlayerTarget(p);
-        p.getEntityWorld().setBlockState(pos, Blocks.REDSTONE_BLOCK.getDefaultState());
+        Entity test = Utils.getTargetedEntity(p, 30, EntityLivingBase.class);
+        if(test == null)
+        {
+            this.getModule().send(cs, "null");
+            return true;
+        }
+        p.getEntityWorld().setBlockState(test.getPosition(), Blocks.REDSTONE_BLOCK.getDefaultState());
+        //p.getEntityWorld().setBlockState(pos, Blocks.REDSTONE_BLOCK.getDefaultState());
         //this.getModule().send(cs, "Es passiert nichts.");
         return true;
     }

+ 292 - 0
src/main/java/me/km/datatools/CommandDataTools.java

@@ -0,0 +1,292 @@
+package me.km.datatools;
+
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.api.Utils;
+import me.km.chatmanager.ChatManager;
+import me.km.nms.NmsUtilities;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import me.km.permissions.Permissions;
+import me.km.utils.ItemStackUtils;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.inventory.EntityEquipmentSlot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.text.TextComponentString;
+
+public class CommandDataTools extends ModuleCommand
+{
+    private final ArrayList<String> first;
+    
+    public CommandDataTools(Module m) 
+    {
+        super("datatools", m);
+        super.setDescription("Spezielle Commands um Daten zu verändern");
+        super.setUsage("/datatools für die Hilfe");
+        super.setPermission(Permissions.DATATOOLS);  
+        
+        first = new ArrayList<>(Arrays.asList(new String[]
+                {"print-nbt", "flag", "attribute", "hide-entity", "show-entity", "name-entity", "name-item", "lore-item", "silent-entity"})); 
+    }
+
+    @Override
+    public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) 
+    {
+        List<String> names = new ArrayList<>();
+        switch (args.length) 
+        {
+            case 1:
+                first.stream().filter(e -> e.toLowerCase().startsWith(args[0].toLowerCase())).forEach(e ->
+                {
+                    names.add(e);
+                }); 
+                break;
+            case 2:
+                if(args[0].equals("flag"))
+                {
+                    Arrays.stream(ItemStackUtils.ItemFlag.values()).filter(e -> e.toString().toLowerCase().startsWith(args[1].toLowerCase())).forEach(e ->
+                    {
+                        names.add(e.toString());
+                    });
+                }
+                else if(args[0].equals("attribute"))
+                {
+                    Arrays.stream(ItemStackUtils.Attribute.values()).filter(e -> e.toString().toLowerCase().startsWith(args[1].toLowerCase())).forEach(e ->
+                    {
+                        names.add(e.toString());
+                    });
+                }   
+                break;
+            case 3:
+                if(args[0].equals("attribute"))
+                {
+                    Arrays.stream(EntityEquipmentSlot.values()).filter(e -> e.toString().toLowerCase().startsWith(args[2].toLowerCase())).forEach(e ->
+                    {
+                        names.add(e.toString());
+                    });
+                }   
+                break;
+            case 5:
+                if(args[0].equals("attribute"))
+                {
+                    Arrays.stream(ItemStackUtils.Operation.values()).filter(e -> e.toString().toLowerCase().startsWith(args[4].toLowerCase())).forEach(e ->
+                    {
+                        names.add(e.toString());
+                    });
+                }   
+                break;    
+        }
+        return names;  
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        if(!(cs instanceof EntityPlayerMP))
+        {
+            this.getModule().send(cs, GlobalText.onlyPlayer());
+            return true;
+        }
+        EntityPlayerMP p = (EntityPlayerMP) cs;
+        Module m = this.getModule();
+        if(arg.length >= 1)
+        {         
+            switch (arg[0]) 
+            {
+                case "print-nbt":
+                {
+                    Entity ent = Utils.getTargetedEntity(p, 3, Entity.class);
+                    if(ent == null)
+                    {
+                        m.send(cs, "Du musst auf ein Objekt gerichtet sein.");
+                        return true;
+                    }       
+                    this.getModule().send(cs, GlobalText.Spacer());
+                    this.getModule().send(cs, "NBT-Daten " + ent.getName());
+                    String nbt = NmsUtilities.getNbtString(ent);
+                    cs.sendMessage(new TextComponentString(NmsUtilities.highlightNbtSyntax(nbt)));   
+                    NmsUtilities.sendCopyableText(p, nbt);
+                    return true;
+                }
+                /*case "test":
+                {
+                    Entity ent = Utils.getTargetedEntity(p, 3, Entity.class);
+                    if(ent == null)
+                    {
+                        m.send(cs, "Du musst auf ein Objekt gerichtet sein.");
+                        return true;
+                    }       
+                    NmsUtilities.canDestroyBlocks((LivingEntity) ent);
+                    return true;
+                }*/
+                case "flag":
+                {
+                    if(arg.length < 2)
+                    {
+                        break;
+                    }
+                    ItemStack stack = p.getHeldItemMainhand();
+                    if(stack == ItemStack.EMPTY)
+                    {
+                        m.send(cs, "Du musst ein Item in der Hand halten.");
+                        return true;
+                    }
+                    try
+                    {
+                        ItemStackUtils.ItemFlag flag = ItemStackUtils.ItemFlag.valueOf(arg[1].toUpperCase());
+                        ItemStackUtils.addItemFlag(stack, flag);
+                        m.send(cs, "Die Flag wurde hinzugefügt.");
+                    }
+                    catch(IllegalArgumentException ex)
+                    {
+                        m.send(cs, "Die gegebene Flag existiert nicht.");
+                    }                           
+                    return true;
+                }
+                case "attribute":
+                {
+                    ItemStack stack = p.getHeldItemMainhand();
+                    if(stack == ItemStack.EMPTY)
+                    {
+                        m.send(cs, "Du musst ein Item in der Hand halten.");
+                        return true;
+                    }                            
+                    if(arg.length < 5)
+                    {
+                        break;
+                    }
+                    try
+                    {
+                        ItemStackUtils.addAttribute(stack, ItemStackUtils.Attribute.valueOf(arg[1]), 
+                                EntityEquipmentSlot.valueOf(arg[2]), Double.parseDouble(arg[3]), ItemStackUtils.Operation.valueOf(arg[4]));
+                        m.send(cs, "Das Attribut wurde hinzugefügt.");
+                    } 
+                    catch(NumberFormatException ex)
+                    {
+                        m.send(cs, "Die angegebene Zahl ist ungültig.");
+                    }
+                    catch(IllegalArgumentException ex)
+                    {
+                        m.send(cs, "Ein angegebener Enum existiert nicht.");
+                    }
+                    return true;
+                }
+                case "hide-entity":
+                {
+                    Entity ent = Utils.getTargetedEntity(p, 3, Entity.class);
+                    if(ent == null)
+                    {
+                        m.send(cs, "Du musst auf ein Objekt gerichtet sein.");
+                        return true;
+                    }                        
+                    ent.setInvisible(true);
+                    m.send(cs, "Das Objekt sollte nun unsichtbar sein.");
+                    return true;    
+                }
+                case "show-entity":
+                    Collection<Entity> ents = Utils.getNearbyEntities(p.getEntityWorld(), p.getPositionVector(), 3, Entity.class);
+                    if(ents.isEmpty())
+                    {
+                        m.send(cs, "Du musst mindestens ein Objekt in deiner Nähe haben.");
+                        return true;
+                    } 
+                    ents.stream().forEach(ent -> ent.setInvisible(false));
+                    m.send(cs, "Alle Objekte in deiner Nähe sollten wieder sichtbar sein.");
+                    return true;  
+                case "silent-entity":
+                {
+                    Entity ent = Utils.getTargetedEntity(p, 3, Entity.class);
+                    if(ent == null)
+                    {
+                        m.send(cs, "Du musst auf ein Objekt gerichtet sein.");
+                        return true;
+                    }                                 
+                    ent.setSilent(true);
+                    m.send(cs, "Das Objekt sollte nun still sein.");
+                    return true;    
+                }
+                case "name-entity":
+                {
+                    if(arg.length < 2)
+                    {
+                        break;
+                    }
+                    Entity ent = Utils.getTargetedEntity(p, 3, Entity.class);
+                    if(ent == null)
+                    {
+                        m.send(cs, "Du musst auf ein Objekt gerichtet sein.");
+                        return true;
+                    }                                
+                    String s = ChatManager.colorMessage(Utils.connectSpaces(arg, 1), p);
+                    ent.setCustomNameTag(s);
+                    m.send(cs, "Das Objekt träg nun den Namen '" + s + "§r'.");
+                    return true; 
+                }
+                case "name-item":
+                {
+                    if(arg.length < 2)
+                    { 
+                        break;
+                    }
+                    ItemStack hand = p.getHeldItemMainhand();
+                    if(hand == ItemStack.EMPTY)
+                    {
+                        m.send(cs, "Du musst ein Item in der Hand halten.");
+                        return true;
+                    }                          
+                    String s = ChatManager.colorMessage(Utils.connectSpaces(arg, 1), p);
+                    hand.setStackDisplayName(s);
+                    m.send(cs, "Das Item trägt nun den Namen '" + s + "§r'.");
+                    return true;
+                }
+                case "lore-item":
+                    if(arg.length < 3)
+                    {
+                        break;
+                    }
+                    ItemStack hand = p.getHeldItemMainhand();
+                    if(hand == ItemStack.EMPTY)
+                    {
+                        m.send(cs, "Du musst ein Item in der Hand halten.");
+                        return true;
+                    }                          
+                    int line;
+                    try
+                    {
+                        line = Integer.parseInt(arg[1]);
+                        if(line < 0)
+                        {
+                            throw new NumberFormatException();
+                        }
+                    }
+                    catch(NumberFormatException ex)
+                    {
+                        m.send(cs, GlobalText.noNaturalNumber());
+                        return true;
+                    }            
+                    Utils.setLore(hand, ChatManager.colorMessage(Utils.connectSpaces(arg, 2), p), line);
+                    m.send(cs, "Die neue Lore wurde hinzugefügt.");
+                    return true;
+            }
+        }
+        
+        m.send(cs, "/datatools ...");
+        m.sendHelpListElement(cs, "print-nbt", "Gibt Information über eine Entity");
+        m.sendHelpListElement(cs, "flag <flag>", "Fügt dem ItemStack eine Flag hinzu");
+        m.sendHelpListElement(cs, "attribute <a> <slot> <d> <op>", "Fügt ein Attribut hinzu");
+        m.sendHelpListElement(cs, "hide-entity", "Macht eine Entitiy unsichtbar");
+        m.sendHelpListElement(cs, "show-entity", "Macht umliegende Entities sichtbar");
+        m.sendHelpListElement(cs, "silent-entity", "Macht eine Entitiy still");
+        m.sendHelpListElement(cs, "name-entity <name>", "Setzt einen Namen für eine Entity");
+        m.sendHelpListElement(cs, "name-item <name>", "Setzt einen Namen für ein Item");
+        m.sendHelpListElement(cs, "lore-item <line> <lore>", "Setzt eine Lore für ein Item");
+        return true;  
+    }
+}

+ 160 - 0
src/main/java/me/km/datatools/CommandVillager.java

@@ -0,0 +1,160 @@
+package me.km.datatools;
+
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.api.Utils;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import me.km.permissions.Permissions;
+import me.km.utils.EntityInventory;
+import me.km.utils.InventoryUtils;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.passive.EntityVillager;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.village.MerchantRecipe;
+import net.minecraft.village.MerchantRecipeList;
+import net.minecraft.world.World;
+import net.minecraftforge.fml.common.registry.VillagerRegistry;
+
+public class CommandVillager extends ModuleCommand
+{
+    private final ArrayList<String> vil;
+    
+    public CommandVillager(Module m) 
+    {
+        super("villager", m);
+        super.setDescription("Spezielle Commands für Villager");
+        super.setUsage("/villager für die Hilfe");
+        super.setPermission(Permissions.VILLAGER);
+        
+        vil = new ArrayList<>(Arrays.asList(new String[] {"inv", "trades", "spawn", "child"})); 
+    }
+
+    @Override
+    public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) 
+    {
+        List<String> names = new ArrayList<>();     
+        if(args.length == 1)
+        {
+            vil.stream().filter(e -> e.toLowerCase().startsWith(args[0].toLowerCase())).forEach(e -> 
+            {                   
+                names.add(e);
+            });
+            return names;
+        }     
+        return names;  
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        if(!(cs instanceof EntityPlayerMP))
+        {
+            this.getModule().send(cs, GlobalText.onlyPlayer());
+            return true;
+        }
+        EntityPlayerMP p = (EntityPlayerMP) cs;
+        Module m = this.getModule();
+        if(arg.length >= 1)
+        {         
+            switch (arg[0])    
+            {
+                case "inv":
+                {
+                    EntityVillager v = Utils.getTargetedEntity(p, 3, EntityVillager.class);
+                    if(v == null)
+                    {
+                        m.send(cs, "Du musst auf einen Villager gerichtet sein.");
+                        return true;
+                    }       
+                    p.displayGUIChest(InventoryUtils.getInventory(v));
+                    return true;
+                }
+                case "trades":
+                {
+                    EntityVillager v = Utils.getTargetedEntity(p, 3, EntityVillager.class);
+                    if(v == null)
+                    {
+                        m.send(cs, "Du musst auf einen Villager gerichtet sein.");
+                        return true;
+                    }         
+                    EntityInventory inv = new EntityInventory("ChangeTrades - " + v.getEntityId(), 54, v);
+                    int i = 0;
+                    MerchantRecipeList list = v.getRecipes(null);
+                    if(list != null)
+                    {
+                        for(MerchantRecipe mr : list)
+                        {
+                            inv.setInventorySlotContents(i, mr.getItemToSell().copy());
+                            inv.setInventorySlotContents(i + 9, mr.getItemToBuy().copy());
+                            inv.setInventorySlotContents(i + 18, mr.getSecondItemToBuy().copy());                         
+                            i++;
+                            if(i >= 9)
+                            {
+                                i = 27;
+                            }
+                            if(i >= 36)
+                            {
+                                break;
+                            }
+                        }
+                    }
+                    p.displayGUIChest(inv);
+                    return true;
+                }
+                case "spawn":   
+                    if(arg.length >= 2)
+                    {                                                      
+                        try
+                        {
+                            World w = p.getEntityWorld();
+                            EntityVillager v = new EntityVillager(w, Integer.parseInt(arg[1]));
+                            v.setPosition(p.posX, p.posY, p.posZ);       
+                            v.setAIMoveSpeed(0);
+                            w.spawnEntity(v);
+                            return true;
+                        }
+                        catch(NumberFormatException ex)
+                        {
+                            m.send(cs, "Die ID ist ungültig.");
+                        } 
+                        catch(IllegalArgumentException ex)
+                        {
+                            m.send(cs, "Dieser Typ von Villager existiert nicht.");
+                        } 
+                    }
+                    break;
+                case "child":   
+                    if(arg.length >= 2)
+                    {                                                      
+                        try
+                        {
+                            World w = p.getEntityWorld();
+                            EntityVillager v = new EntityVillager(w, Integer.parseInt(arg[1]));
+                            v.setGrowingAge(Integer.MIN_VALUE);
+                            v.setPosition(p.posX, p.posY, p.posZ);       
+                            v.setAIMoveSpeed(0);
+                            w.spawnEntity(v);
+                            return true;
+                        }
+                        catch(IllegalArgumentException ex)
+                        {
+                            m.send(cs, "Dieser Typ von Villager existiert nicht.");
+                        } 
+                    }
+                    break;
+            }
+        }
+        // Help Menu
+        m.send(cs, "/villager ...");
+        m.sendHelpListElement(cs, "inv", "Öffnet den Inventar eines Villagers");
+        m.sendHelpListElement(cs, "trades", "Öffnet die Trades vom Villager");
+        m.sendHelpListElement(cs, "spawn <profid>", "Spawnt einen Villager");
+        m.sendHelpListElement(cs, "child <profid>", "Spawnt einen Villager");
+        return true;
+    }
+}

+ 99 - 0
src/main/java/me/km/datatools/DataToolsEvents.java

@@ -0,0 +1,99 @@
+package me.km.datatools;
+
+import me.km.api.Module;
+import me.km.api.ModuleListener;
+import me.km.utils.EntityInventory;
+import me.km.utils.InventoryUtils;
+import me.km.utils.ReflectionUtils;
+import net.minecraft.entity.passive.EntityVillager;
+import net.minecraft.inventory.ContainerChest;
+import net.minecraft.item.ItemStack;
+import net.minecraft.village.MerchantRecipe;
+import net.minecraft.village.MerchantRecipeList;
+import net.minecraftforge.event.entity.living.LivingHurtEvent;
+import net.minecraftforge.event.entity.EntityJoinWorldEvent;
+import net.minecraftforge.event.entity.player.PlayerContainerEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+public class DataToolsEvents extends ModuleListener 
+{
+    public DataToolsEvents(Module m)
+    {
+        super(m);
+    }
+    
+    @SubscribeEvent
+    public void VillagerClose(PlayerContainerEvent.Close e)
+    {             
+        if(!(e.getContainer() instanceof ContainerChest))
+        {
+            return;
+        }
+        ContainerChest c = (ContainerChest) e.getContainer();
+        if(!(c.getLowerChestInventory() instanceof EntityInventory))
+        {
+            return;
+        }
+        EntityInventory inv = (EntityInventory) c.getLowerChestInventory();
+        if(inv.getName().startsWith("ChangeInventory"))
+        {
+            InventoryUtils.setInventory(inv);
+            this.getModule().send(e.getEntityPlayer(), "Der Villager-Inventar wurde überschrieben.");
+        }
+        else if(inv.getName().startsWith("ChangeTrades"))
+        {
+            EntityVillager v = (EntityVillager) inv.getEntity();
+            MerchantRecipeList list = v.getRecipes(null);
+            if(list == null)
+            {
+                return; // will never happen
+            }
+            else
+            {
+                list.clear();
+            }
+            MerchantRecipe mr;
+            for(int i = 0; i < 36; i++)
+            {
+                if(i == 9)
+                {
+                    i = 27;
+                }
+                if(inv.getStackInSlot(i) == ItemStack.EMPTY)
+                {
+                    continue;                
+                }          
+
+                mr = new MerchantRecipe(inv.getStackInSlot(i + 9), inv.getStackInSlot(i + 18), inv.getStackInSlot(i), 0, Integer.MAX_VALUE);
+                list.add(mr);
+            }
+            this.getModule().send(e.getEntityPlayer(), "Die Villager-Trades wurde überschrieben.");
+        }
+    }
+    
+    @SubscribeEvent
+    public void removeVanillaTrades(EntityJoinWorldEvent e)
+    {
+        // removes vanilla trades and prevents further loading of new ones
+        if (e.getEntity() instanceof EntityVillager)
+        {
+            EntityVillager v = (EntityVillager) e.getEntity();
+            ReflectionUtils.setCareerLevel(v, 10);
+            MerchantRecipeList list = v.getRecipes(null);
+            if(list != null)
+            {
+                list.clear();
+            }
+        }
+    }
+
+    
+    @SubscribeEvent
+    public void VillagerProtect(LivingHurtEvent e)
+    { 
+        if(e.getEntityLiving() instanceof EntityVillager && !e.getSource().isCreativePlayer())
+        {
+            e.setCanceled(true);
+        }
+    }
+}

+ 104 - 0
src/main/java/me/km/effects/ActiveEffectBase.java

@@ -0,0 +1,104 @@
+package me.km.effects;
+
+import me.km.KajetansMod;
+import me.km.environment.EnvironmentAPI;
+import net.minecraft.entity.player.EntityPlayer;
+
+public abstract class ActiveEffectBase 
+{
+    protected abstract int getManaCost(int manaFactor);
+    
+    public int getCoolDown()
+    {
+        return 0;
+    }
+    
+    public boolean run(EntityPlayer p, int power, int manaFactor, EffectCause cause)
+    {
+        if(cause != EffectCause.NOTHING)
+        {
+            if(KajetansMod.playerbank.getData(p).hasData("shadow"))
+            {
+                p.setInvisible(false);
+                KajetansMod.playerbank.getData(p).removeData("shadow");
+            } 
+            if(KajetansMod.playerbank.getData(p).hasData("silence"))
+            {
+                KajetansMod.effects.send(p, "Du kannst gerade keine Skills nutzen.");
+                return false;
+            }
+        }
+        int manaCost = getManaCost(manaFactor);
+        // Effect-Event-Start
+        PlayerUsesEffectEvent e = new PlayerUsesEffectEvent(p, power, manaCost, cause, this.getClass());
+        // TODO send pseudo event to SnuviScript
+        //Bukkit.getPluginManager().callEvent(e); 
+        if(e.isCanceled())
+        {
+            return false;
+        }
+        else
+        {
+            power = e.getPower();
+            manaFactor = e.getMana();
+        }
+        // Effect-Event-End
+        if(p.isCreative())
+        {
+            return executeEffect(p, power);
+        }
+        if(!KajetansMod.playerbank.getData(p).hasData(this.getClass().getSimpleName()))
+        {
+            if(manaFactor == 0)
+            {
+                if(executeEffect(p, power))
+                {
+                    int cooldown = getCoolDown();
+                    if(cooldown > 0)
+                    {
+                        KajetansMod.playerbank.getData(p).addTimedData(this.getClass().getSimpleName(), cooldown);
+                    }
+                    return true;
+                }
+                return false;
+            }
+            int mana = EnvironmentAPI.getMana(p);
+            if(mana < manaCost)
+            {
+                KajetansMod.effects.send(p, "Du hast zu wenig Mana. (§a" + mana + "§r/§c" + manaCost + "§r)");
+                return false;
+            }
+            if(executeEffect(p, power))
+            {
+                int cooldown = getCoolDown();
+                if(cooldown > 0)
+                {
+                    KajetansMod.playerbank.getData(p).addTimedData(this.getClass().getSimpleName(), cooldown);
+                }
+                EnvironmentAPI.changeMana(p, -manaCost);
+                return true;
+            }
+            return false;
+        }
+        KajetansMod.effects.send(p, "Der Cooldown läuft noch.");
+        return false;
+    }
+    
+    protected abstract boolean executeEffect(EntityPlayer p, int power);
+    
+    public static boolean executeEffect(Class<? extends ActiveEffectBase> c, EntityPlayer p, int power, int manaFactor, EffectCause cause)
+    {
+        if(c == null)
+        {
+            return false;
+        }
+        try
+        {
+            return c.newInstance().run(p, power, manaFactor, cause);
+        }
+        catch(SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException ex)
+        {
+            throw new IllegalArgumentException();
+        }
+    }
+}

+ 54 - 0
src/main/java/me/km/effects/CommandWand.java

@@ -0,0 +1,54 @@
+package me.km.effects;
+
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.permissions.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
+
+public class CommandWand extends ModuleCommand
+{   
+    public CommandWand(Module m) 
+    {
+        super("wand", m);
+        super.setDescription("Erstellt einen Zauberstab");
+        super.setUsage("/wand <name> <effect>");
+        super.setPermission(Permissions.WAND);
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        if(!(cs instanceof EntityPlayer))
+        {
+            this.getModule().send(cs, GlobalText.onlyPlayer());
+            return true;
+        }
+        EntityPlayer p = (EntityPlayer) cs;
+        if(arg.length >= 2)
+        {     
+            // TODO
+            this.getModule().send(cs, GlobalText.notImplementedYet());
+            /*CustomMaterial cm;
+            try
+            {
+                cm = CustomMaterial.valueOf(arg[0]);
+            }
+            catch(IllegalArgumentException ex)
+            {
+                this.getModule().send(cs, "Dieser Zauberstab existiert nicht.");
+                return true;
+            }
+            Class<? extends ActiveEffectBase> c = EffectUtils.getEffectClass(arg[1]);
+            if(c == null)
+            { 
+                this.getModule().send(cs, "Dieser aktive Effekt existiert nicht.");
+                return true;
+            }
+            p.getWorld().dropItem(p.getLocation(), cm.getItemStack(1, "Effect: " + arg[1]));*/
+            return true;
+        } 
+        return false;
+    }
+}

+ 193 - 0
src/main/java/me/km/effects/Effect.java

@@ -0,0 +1,193 @@
+package me.km.effects;
+
+import java.util.ArrayList;
+import me.km.skills.Skill;
+
+public enum Effect
+{
+    // comments indicate, that events aren't in active oder passive effect packages
+    // passive effects
+    ENCHANTER               (false),   // me.kt.custom.CustomEnchanting 
+    LESS_HUNGER             (false),   // me.kt.environment.EnvironmentTick
+    LESS_THIRST             (false),   // me.kt.environment.EnvironmentAPI
+    LESS_ENERGY_USE         (false),   // me.kt.environment.EnvironmentAPI
+    LESS_COLD               (false),   // me.kt.environment.EnvironmentAPI
+    FASTER_MANA             (false),   // me.kt.environment.EnvironmentAPI    
+    BREED_COW               (false),        
+    BREED_PIG               (false),
+    BREED_SHEEP             (false),
+    BREED_RABBIT            (false),
+    BREED_CHICKEN           (false),
+    BREED_HORSE             (false),
+    BREED_MUSHROOMCOW       (false),
+    GRAVEL_SAND_DIGGER      (false),
+    MORE_MINERALS           (false),
+    MORE_CROPS              (false),
+    TREE_PICKER             (false),
+    MORE_SAPLINGS           (false),
+    CAKE_POWER              (false),
+    SNEAKING                (false),
+    SCENT                   (false),
+    MUGGING                 (false),
+    FAST_DIGGING            (false),
+    XP_COLLECTOR            (false),
+    MORE_DROPS              (false),
+    FASTER_ARROWS           (false),
+    ARROW_SAVER             (false),
+    MORE_AXE_DAMAGE         (false),
+    MORE_HOE_DAMAGE         (false),
+    MORE_PICKAXE_DAMAGE     (false),
+    MORE_SHOVEL_DAMAGE      (false),
+    MORE_SWORD_DAMAGE       (false),
+    MORE_DAGGER_DAMAGE      (false),
+    MORE_HAMMER_DAMAGE      (false),
+    MORE_STICK_DAMAGE       (false),
+    FISHING                 (false),
+    POTION_SAVER            (false),
+    BREWING                 (false),
+    CAULDRON_FILLING        (false),
+    SMELTING                (false),
+    NO_POISON               (false),
+    LESS_FALL_DAMAGE        (false),
+    LESS_DAMAGE             (false),
+    SMITH                   (false),
+    FAST_ENDERPEARL_SHOOT   (false),
+    PEARL_SAVER             (false),
+    NO_ENDERPEARL_DAMAGE    (false),
+    GOLD_WASHER             (false),
+    GOLD_RUSH               (false),
+    USE_WAND                (false),
+    LESS_ITEM_LOSS          (false);
+    
+    // TODO
+    // active effects
+    /*ARCANE_SHOT             (true, ArcaneShot.class),
+    BLINDING_SHOT           (true, BlindingShot.class),
+    BUNNY_HOP               (true, BunnyHop.class),
+    CALL_BACK               (true, CallBack.class),
+    CLUSTER_BOMB            (true, ClusterBomb.class),
+    DAY                     (true, Day.class),
+    DOOMED                  (true, Doomed.class),
+    EARTHQUAKE              (true, Earthquake.class),
+    ELEVATION               (true, Elevation.class),
+    ELVISH_HORN             (true, ElvishHorn.class),
+    ENDERCHEST              (true, Enderchest.class),
+    EXPLOSION               (true, Explosion.class),
+    FALL_IMMUNITY           (true, FallImmunity.class),
+    FIRE                    (true, Fire.class),
+    FIREBALL                (true, Fireball.class),
+    FIRE_SHOT               (true, FireShot.class),
+    FLYING                  (true, Flying.class),
+    FREEZE                  (true, Freeze.class),
+    GRAPPLING_HOOK          (true, GrapplingHook.class),
+    HARM                    (true, Harm.class),
+    HARVEST                 (true, Harvest.class),
+    HEAL                    (true, Heal.class),
+    HEAL_RAIN               (true, HealRain.class),
+    HEARTS                  (true, Hearts.class),
+    HEART_SEEKER            (true, HeartSeeker.class),
+    IMMORTALITY             (true, Immortality.class),
+    INVISIBILITY            (true, Invisibility.class),
+    JUMP                    (true, Jump.class),
+    KICK                    (true, Kick.class),
+    LEAF_COCOON             (true, LeafCocoon.class),
+    LOCK_PICK               (true, LockPick.class),
+    LUCKY                   (true, Lucky.class),
+    MUSKET                  (true, Musket.class),
+    NAIL_DOWN               (true, NailDown.class),
+    NAIL_TRAP               (true, NailTrap.class),
+    NET_TRAP                (true, NetTrap.class),
+    NIGHT                   (true, Night.class),
+    P_HEAL                  (true, PHeal.class),
+    POISON                  (true, Poison.class),
+    POISONED_BLADE          (true, PoisonedBlade.class),
+    POISON_VOLLEY           (true, PoisonVolley.class),
+    POWER                   (true, Power.class),
+    POWER_ATTACK            (true, PowerAttack.class),
+    PULL                    (true, Pull.class),
+    PUSH                    (true, Push.class),
+    QUICK_SHOT              (true, QuickShot.class),
+    RAIN                    (true, Rain.class),
+    RAPID_FIRE              (true, RapidFire.class),
+    ROOTING                 (true, Rooting.class),
+    SHADOW                  (true, Shadow.class),
+    SHADOW_HIT              (true, ShadowHit.class),
+    SHADOW_STEP             (true, ShadowStep.class),
+    SILENCE                 (true, Silence.class),
+    SLOWING_SHOT            (true, SlowingShot.class),
+    SMOKE_BOMB              (true, SmokeBomb.class),
+    SPRINT                  (true, Sprint.class),
+    STONE                   (true, Stone.class),
+    SUN                     (true, Sun.class),
+    TELEPORT_PLAYER         (true, TeleportPlayer.class),
+    THOR                    (true, Thor.class),
+    UNLUCKY                 (true, Unlucky.class),
+    VINE_TRAP               (true, VineTrap.class),
+    WORKBENCH               (true, Workbench.class);*/
+    
+    private final ArrayList<Skill> skills;
+    private final Class<? extends ActiveEffectBase> c;
+    private final boolean active;
+    
+    Effect(boolean active, Class<? extends ActiveEffectBase> c) 
+    {
+        skills = new ArrayList<>();
+        this.active = active;
+        this.c = c;
+    }
+    
+    Effect(boolean active) 
+    {
+        this(active, null);
+    }
+    
+    public void addSkill(Skill s)
+    {
+        skills.add(s);
+    }
+    
+    public ArrayList<Skill> getSkills()
+    {
+        return skills;
+    }
+    
+    public void clearSkills()
+    {
+        skills.clear();
+    }
+    
+    public boolean isActive()
+    {
+        return active;
+    }
+    
+    public int getManaCost(int power)
+    {
+        if(c != null)
+        {
+            try
+            {
+                return c.newInstance().getManaCost(power);
+            }
+            catch(InstantiationException | IllegalAccessException ex)
+            {
+                return 0;
+            }
+        }
+        return 0;
+    }
+    
+    public Class<? extends ActiveEffectBase> getEffectBase()
+    {
+        return c;
+    }
+    
+    public String getEffectString()
+    {
+        if(c == null)
+        {
+            return null;
+        }
+        return c.getSimpleName();
+    }
+}

+ 84 - 0
src/main/java/me/km/effects/EffectBlockChanger.java

@@ -0,0 +1,84 @@
+package me.km.effects;
+
+import me.km.KajetansMod;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+import net.minecraft.block.Block;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+
+public class EffectBlockChanger
+{
+    private World w;
+    private ArrayList<ChangeBlock> list;
+    
+    public EffectBlockChanger(World w)
+    {
+        this.w = w;
+        list = new ArrayList<>();
+    }
+    
+    public void addBlock(BlockPos pos, Block b, int s)
+    {
+        if(w.isAirBlock(pos))
+        {
+            list.add(new ChangeBlock(pos, b, s));
+        }
+    }
+    
+    public void addBlock(BlockPos pos, Block b)
+    {
+        addBlock(pos, b, 0);
+    }
+    
+    public void run(int clean)
+    {
+        list.forEach(c -> c.run());
+        KajetansMod.scheduler.scheduleTask(() -> list.forEach(c -> c.clear()), clean);
+    }
+    
+    public World getWorld()
+    {
+        return w;
+    }
+    
+    public void forEachBlockPos(Consumer<? super BlockPos> c)
+    {
+        list.stream().map(l -> l.pos).forEach(c);
+    }
+    
+    private class ChangeBlock
+    {
+        private BlockPos pos;
+        private IBlockState state;
+
+        public ChangeBlock(BlockPos pos, Block b, int s)
+        {
+            if(s != 0)
+            {
+                this.state = b.getStateFromMeta(s);
+            }
+            else
+            {
+                this.state = b.getDefaultState();
+            }
+            this.pos = pos;
+        }
+
+        public ChangeBlock(BlockPos pos, Block b)
+        {
+            this(pos, b, 0);
+        }
+
+        public void run()
+        {
+            w.setBlockState(pos, state);
+        }
+
+        public void clear()
+        {
+            w.setBlockToAir(pos);
+        }
+    }
+}

+ 21 - 0
src/main/java/me/km/effects/EffectCause.java

@@ -0,0 +1,21 @@
+package me.km.effects;
+
+public enum EffectCause 
+{
+    /**
+     * the effect was started by a scroll
+     */
+    SCROLL, 
+    /**
+     * the effect was started by a wand
+     */
+    WAND,
+    /**
+     * the effect was started by a skill
+     */
+    SKILL,
+    /**
+     * the effect was started by an item, no event is thrown
+     */
+    NOTHING
+}

+ 208 - 0
src/main/java/me/km/effects/EffectUtils.java

@@ -0,0 +1,208 @@
+package me.km.effects;
+
+import java.util.Collection;
+import java.util.stream.Collectors;
+import me.km.KajetansMod;
+import me.km.api.Module;
+import me.km.api.Utils;
+import net.minecraft.entity.EntityAreaEffectCloud;
+import net.minecraft.entity.EntityLiving;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.entity.passive.EntityAnimal;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.init.MobEffects;
+import net.minecraft.init.SoundEvents;
+import net.minecraft.network.play.server.SPacketParticles;
+import net.minecraft.network.play.server.SPacketSoundEffect;
+import net.minecraft.potion.Potion;
+import net.minecraft.potion.PotionEffect;
+import net.minecraft.potion.PotionType;
+import net.minecraft.util.EnumParticleTypes;
+import net.minecraft.util.SoundCategory;
+import net.minecraft.util.SoundEvent;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.util.text.TextFormatting;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import scala.remote;
+
+public class EffectUtils extends Module
+{
+    public EffectUtils(String mname, String prefix, TextFormatting color) 
+    {
+        super(mname, prefix, color);
+    }
+    
+    /** Returns the level of a players effect
+     *
+     * @param p a player
+     * @param eff an effect
+     * @return the level of the effect, 0 on non existance for the player
+     */
+    public static int getEffectLevel(EntityPlayer p, Effect eff)
+    {
+        // TODO
+        return 0;
+        /*JobAPI job = KajetansMod.jobs;
+        return eff.getSkills().stream().mapToInt(s -> job.getSkillLevel(p, s)).max().orElse(0);*/
+    }
+    
+    @SuppressWarnings(value = "unchecked")
+    public static Class<? extends ActiveEffectBase> getEffectClass(String s)
+    {
+        Class<? extends ActiveEffectBase> c;
+        try
+        {
+            c = (Class<? extends ActiveEffectBase>) Class.forName("me.km.effects.active." + s);
+        }
+        catch(ClassNotFoundException | ClassCastException ex)
+        {
+            return null;
+        }
+        return c;
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Entity-Collections
+    // -----------------------------------------------------------------------------------
+    
+    public static Collection<EntityPlayer> getPlayersOfGuild(EntityPlayer p, World w, Vec3d v, double radius)
+    {       
+        Collection<EntityPlayer> col = Utils.getNearbyPlayers(w, v, radius);
+        if(col.isEmpty())
+        {
+            return col;
+        }
+        int id = KajetansMod.playerbank.getGuildId(p);
+        col.removeIf(pl -> KajetansMod.playerbank.getGuildId(pl) != id);
+        return col;
+    }
+    
+    public static Collection<EntityPlayer> getPlayersOfGuild(EntityPlayer p, double radius)
+    {       
+        return getPlayersOfGuild(p, p.world, p.getPositionVector(), radius);
+    }
+    
+    public static Collection<EntityLivingBase> getEntsOfNotGuild(EntityPlayer p, World w, Vec3d v, double radius)
+    {       
+        // TODO
+        boolean animals = false; //KajetansMod.plots.getDataBank(ProtectionBank.class).canBuild(l, p);
+        boolean pvp = !KajetansMod.worldManager.getWorldPreferences(w).pvpProtection;
+        boolean ppvp = KajetansMod.playerbank.getDataBank().getTag(p, "pvp") >= 1;
+        int id = KajetansMod.playerbank.getGuildId(p);
+        
+        return Utils.getNearbyEntities(w, v, radius, EntityLivingBase.class).stream()
+                .filter(ent -> animals || !(ent instanceof EntityAnimal))
+                .filter(ent -> pvp || !(ent instanceof EntityPlayer) || (ppvp && 
+                        KajetansMod.playerbank.getDataBank().getTag((EntityPlayer) ent, "pvp") >= 1))
+                .filter(ent -> !(ent instanceof EntityPlayer) || 
+                        (id != KajetansMod.playerbank.getGuildId((EntityPlayer) ent)))
+                .filter(ent -> !(ent.equals(p)))
+                .collect(Collectors.toList());
+    }
+    
+    public static Collection<EntityLivingBase> getEntsOfNotGuild(EntityPlayer p, double radius)
+    {       
+        return getEntsOfNotGuild(p, p.world, p.getPositionVector(), radius);
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Target Selector
+    // -----------------------------------------------------------------------------------
+    
+    public static BlockPos getPlayerTarget(EntityPlayer p, int range)
+    {      
+        return Utils.getPlayerTarget(p, range + 7).up();
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Particles
+    // -----------------------------------------------------------------------------------
+    
+    public static void spawnParticle(WorldServer w, EnumParticleTypes particle, float x, float y, float z, float offX, float offY, float offZ, float speed, int count, int... data)
+    {
+        SPacketParticles packet = new SPacketParticles(particle, false, x, y, z, offX, offY, offZ, speed, count, data);
+        Utils.getNearbyPlayers(w, x, y, z, 512).forEach(p -> ((EntityPlayerMP) p).connection.sendPacket(packet));
+    }
+    
+    public static void spawnParticle(WorldServer w, EnumParticleTypes particle, float x, float y, float z, float offX, float offY, float offZ, int count)
+    {
+        spawnParticle(w, particle, x, y, z, offX, offY, offZ, 1, count, new int[0]);
+    }
+    
+    public static void spawnParticle(WorldServer w, EnumParticleTypes particle, float x, float y, float z, int count)
+    {
+        spawnParticle(w, particle, x, y, z, 0, 0, 0, count);
+    }
+    
+    public static void spawnParticle(WorldServer w, EnumParticleTypes particle, Vec3d v, int count)
+    {
+        spawnParticle(w, particle, (float) v.xCoord, (float) v.yCoord, (float) v.zCoord, 0, 0, 0, count);
+    }
+    
+    public static void playSpell(EntityPlayerMP p, int level)
+    {
+        spawnParticle(p.getServerWorld(), EnumParticleTypes.SPELL, (float) p.posX, (float) p.posY + 1, (float) p.posZ, 0.5f, 0.5f, 0.5f, 1, 10 + level, new int[0]);
+    }
+    
+    public static <T> void playEffectCircleWithData(WorldServer w, Vec3d v, EnumParticleTypes particle, double radius, int counter)
+    {
+        double x = v.xCoord;
+        float y = (float) v.yCoord;
+        double z = v.yCoord;
+        double angle = 2 * Math.PI / counter;
+        for(int i = 0; i < counter; i++)
+        {
+            spawnParticle(w, particle, (float) (x + Math.cos(i * angle) * radius), y, (float) (z + Math.sin(i * angle) * radius), 1);
+        }                
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Sounds
+    // -----------------------------------------------------------------------------------
+    
+    public static void playSound(WorldServer w, SoundEvent se, SoundCategory sc, double x, double y, double z)
+    {
+        SPacketSoundEffect packet = new SPacketSoundEffect(se, sc, x, y, z, 1, 1);
+        Utils.getNearbyPlayers(w, x, y, z, 128).forEach(p -> ((EntityPlayerMP) p).connection.sendPacket(packet));
+    }
+    
+    public static void playSound(EntityPlayerMP p, SoundEvent se, SoundCategory sc)
+    {
+        playSound(p.getServerWorld(), se, sc, p.posX, p.posY, p.posZ);
+    }
+
+    // -----------------------------------------------------------------------------------
+    // Potions
+    // -----------------------------------------------------------------------------------
+    
+    public static void addPotionTo(EntityLivingBase ent, Potion potion, int duration, int amplifier)
+    {
+        if(ent.isPotionActive(potion)) 
+        {
+            ent.removePotionEffect(potion);
+        }
+        ent.addPotionEffect(new PotionEffect(potion, duration, amplifier));
+    }
+    
+    public static void spawnPotionCloud(Vec3d v, EntityPlayerMP p, PotionType potion, int duration, float radius)
+    {
+        EntityAreaEffectCloud cloud = new EntityAreaEffectCloud(p.getServerWorld(), v.xCoord, v.yCoord, v.zCoord);
+        cloud.setDuration(duration);
+        cloud.setRadius(radius);
+        cloud.setOwner(p);
+        cloud.setWaitTime(5);
+        cloud.setPotion(potion);
+        p.getServerWorld().spawnEntity(cloud);
+    }
+    
+    public static void spawnPotionCloud(Vec3d v, EntityPlayerMP p, PotionType potion, int level)
+    {
+        BlockPos pos = getPlayerTarget(p, level);
+        spawnPotionCloud(new Vec3d(pos.getX(), pos.getY(), pos.getZ()), p, potion, 40 * level, 0.5f + level / 4f);
+        playSpell(p, level);
+        playSound(p, SoundEvents.ENTITY_FIREWORK_BLAST, SoundCategory.PLAYERS);
+    }
+}

+ 68 - 0
src/main/java/me/km/effects/PlayerUsesEffectEvent.java

@@ -0,0 +1,68 @@
+package me.km.effects;
+
+import net.minecraft.entity.player.EntityPlayer;
+
+public class PlayerUsesEffectEvent
+{
+    private final EntityPlayer p;
+    private int power;
+    private int mana;
+    private final EffectCause cause;
+    private boolean cancel;
+    private final String effect;
+
+    public PlayerUsesEffectEvent(EntityPlayer p, int power, int mana, EffectCause cause, Class<? extends ActiveEffectBase> effect) 
+    {
+        this.p = p;
+        this.power = power;
+        this.mana = mana;
+        this.cause = cause;
+        this.cancel = false;
+        this.effect = effect.getSimpleName();
+    }
+    
+    public EntityPlayer getPlayer()
+    {
+        return p;
+    }
+    
+    public int getPower()
+    {
+        return power;
+    }
+    
+    public void setPower(int power)
+    {
+        this.power = power;
+    }
+    
+    public int getMana()
+    {
+        return mana;
+    }
+    
+    public void setMana(int mana)
+    {
+        this.mana = mana;
+    }
+    
+    public EffectCause getCause()
+    {
+        return cause;
+    }
+    
+    public String getEffect()
+    {
+        return effect;
+    }
+    
+    public boolean isCanceled() 
+    {
+        return cancel;
+    }
+
+    public void setCanceled(boolean cancel) 
+    {
+        this.cancel = cancel;
+    }
+}

+ 55 - 0
src/main/java/me/km/environment/CommandHealStats.java

@@ -0,0 +1,55 @@
+package me.km.environment;
+
+import me.km.api.Utils;
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.exception.PlayerNotFoundException;
+import me.km.permissions.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
+
+public class CommandHealStats extends ModuleCommand
+{
+    public CommandHealStats(Module m) 
+    {
+        super("healstats", m);
+        super.setDescription("Füllt die Zusatzstats eines Spielers");
+        super.setUsage("/healstats [player]");
+        super.setPermission(Permissions.HEAL_STATS);
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        EntityPlayer affectedPlayer;
+        Module m = this.getModule();
+        try
+        {
+            affectedPlayer = Utils.getPlayerByName(arg[0]);    
+            m.send(cs, "Die Stats von " + affectedPlayer.getName() + " wurden gefüllt.");
+            m.send(affectedPlayer, "Deine Stats wurden gefüllt.");
+        }
+        catch(PlayerNotFoundException ex)
+        {
+            m.send(cs, GlobalText.cantFindPlayer(arg[0]));
+            return true;
+        }
+        catch(IndexOutOfBoundsException ex)
+        {
+            if(!(cs instanceof EntityPlayer))
+            {
+                m.send(cs, GlobalText.missingParameter());
+                return true;
+            }     
+            affectedPlayer = (EntityPlayer) cs;
+            m.send(affectedPlayer, "Deine Stats wurden gefüllt.");
+        }
+        EnvironmentAPI.resetThirst(affectedPlayer);
+        EnvironmentAPI.resetEnergy(affectedPlayer);
+        EnvironmentAPI.resetCold(affectedPlayer);
+        EnvironmentAPI.resetMana(affectedPlayer);
+        return true;
+    }
+}
+

+ 32 - 0
src/main/java/me/km/environment/CommandTemperature.java

@@ -0,0 +1,32 @@
+package me.km.environment;
+
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.permissions.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
+
+public class CommandTemperature extends ModuleCommand
+{
+    public CommandTemperature(Module m) 
+    {
+        super("temperature", m);
+        super.setDescription("Zeigt dir die aktuelle Temperatur an");
+        super.setUsage("/temperature");
+        super.setPermission(Permissions.TEMPERATURE);
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        if(!(cs instanceof EntityPlayer))
+        {
+            this.getModule().send(cs, GlobalText.onlyPlayer());
+            return true;
+        }
+        EntityPlayer p = (EntityPlayer) cs;
+        this.getModule().send(cs, "Die Temperatur beträgt hier " + EnvironmentAPI.getTemperature(p.getEntityWorld(), p.getPosition()) + "°C.");
+        return true;
+    }
+}

+ 184 - 0
src/main/java/me/km/environment/EnvironmentAPI.java

@@ -0,0 +1,184 @@
+package me.km.environment;
+
+import java.util.HashMap;
+import java.util.UUID;
+import me.km.effects.Effect;
+import me.km.effects.EffectUtils;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.EnumSkyBlock;
+import net.minecraft.world.World;
+
+public class EnvironmentAPI 
+{
+    private static HashMap<UUID, Integer> thirst;
+    private static HashMap<UUID, Integer> energy;
+    private static HashMap<UUID, Integer> cold;
+    private static HashMap<UUID, Integer> mana;
+    
+    public static void initStatusAPI()
+    {
+        thirst = new HashMap<>();
+        energy = new HashMap<>();
+        cold = new HashMap<>();
+        mana = new HashMap<>();
+    }
+
+    // ---------------------------------
+    // Allgemein
+    // ---------------------------------
+    
+    private static void changeStat(HashMap<UUID, Integer> map, int limit, EntityPlayer p, int amount)
+    {
+        Integer i = map.get(p.getUniqueID());
+        if(i == null)
+        {
+            i = limit;
+        }
+        i += amount;
+        if(i < 0)
+        {
+            i = 0;
+        }
+        else if(i > limit)
+        {
+            i = limit;
+        }
+        map.put(p.getUniqueID(), i);
+    }
+    
+    private static void resetStat(HashMap<UUID, Integer> map, int limit, EntityPlayer p)
+    {
+        map.put(p.getUniqueID(), limit);
+    }
+    
+    private static int getStat(HashMap<UUID, Integer> map, int limit, EntityPlayer p)
+    {
+        Integer i = map.get(p.getUniqueID());
+        if(i == null)
+        {
+            map.put(p.getUniqueID(), limit);
+            return limit;
+        }
+        return i;
+    }
+    
+    // ---------------------------------
+    // Durst
+    // ---------------------------------
+    
+    private final static int THIRST = 10000;
+    
+    public static void changeThirst(EntityPlayer p, int amount)
+    {
+        if(amount < 0)
+        {
+            amount /= EffectUtils.getEffectLevel(p, Effect.LESS_THIRST) + 1;
+        }
+        changeStat(thirst, THIRST, p, amount);
+    }
+    
+    public static void resetThirst(EntityPlayer p)
+    {
+        resetStat(thirst, THIRST, p);
+    }
+    
+    public static int getThirst(EntityPlayer p)
+    {
+        return getStat(thirst, THIRST, p);
+    }
+    
+    // ---------------------------------
+    // Energie
+    // ---------------------------------
+    
+    private final static int ENERGY = 10000;
+    
+    public static void changeEnergy(EntityPlayer p, int amount)
+    {
+        if(amount < 0)
+        {
+            amount /= EffectUtils.getEffectLevel(p, Effect.LESS_ENERGY_USE) + 1;
+        }
+        changeStat(energy, ENERGY, p, amount);
+    }
+    
+    public static void resetEnergy(EntityPlayer p)
+    {
+        resetStat(energy, ENERGY, p);
+    }
+    
+    public static int getEnergy(EntityPlayer p)
+    {
+        return getStat(energy, ENERGY, p);
+    }
+    
+    // ---------------------------------
+    // Kälte
+    // ---------------------------------
+    
+    private final static int COLD = 100;
+    
+    public static void changeCold(EntityPlayer p, int amount)
+    {
+        if(amount < 0)
+        {
+            amount += EffectUtils.getEffectLevel(p, Effect.LESS_COLD) * 2;
+        }
+        changeStat(cold, COLD, p, amount);
+    }
+    
+    public static void resetCold(EntityPlayer p)
+    {
+        resetStat(cold, COLD, p);
+    }
+    
+    public static int getCold(EntityPlayer p)
+    {
+        return getStat(cold, COLD, p);
+    }
+    
+    // ---------------------------------
+    // Mana
+    // ---------------------------------
+    
+    private final static int MANA = 100;
+    
+    public static void changeMana(EntityPlayer p, int amount)
+    {
+        if(amount > 0)
+        {
+            amount += EffectUtils.getEffectLevel(p, Effect.FASTER_MANA) * 2;
+        }
+        changeStat(mana, MANA, p, amount);
+    }
+    
+    public static void resetMana(EntityPlayer p)
+    {
+        resetStat(mana, MANA, p);
+    }
+    
+    public static int getMana(EntityPlayer p)
+    {
+        return getStat(mana, MANA, p);
+    }
+    
+    // ---------------------------------
+    // Temperatur
+    // ---------------------------------
+    
+    public static int getTemperature(World w, BlockPos pos)
+    {
+        double d = w.getBiome(pos).getTemperature();
+        d -= (((pos.getY() - 65) * 0.05) / 30) + 0.3;
+        d += (w.getLightFromNeighbors(pos) * 0.3) / 15;
+        try
+        {
+            d += (w.getLightFor(EnumSkyBlock.BLOCK, pos) * 0.3) / 15;      
+        }
+        catch(Exception ex)
+        {           
+        }
+        return (int) (-7.08578 * Math.pow(d, 2) + 37.50072 * d - 5.46568);
+    }
+}

+ 137 - 0
src/main/java/me/km/environment/EnvironmentEvents.java

@@ -0,0 +1,137 @@
+package me.km.environment;
+
+import me.km.KajetansMod;
+import me.km.api.Module;
+import me.km.api.ModuleListener;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.util.EnumHand;
+import net.minecraft.world.World;
+import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent;
+import net.minecraftforge.event.entity.player.AttackEntityEvent;
+import net.minecraftforge.event.entity.player.PlayerInteractEvent;
+import net.minecraftforge.event.world.BlockEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+import net.minecraftforge.fml.common.gameevent.PlayerEvent;
+
+public class EnvironmentEvents extends ModuleListener
+{    
+    public EnvironmentEvents(Module m)
+    {
+        super(m);
+        EnvironmentAPI.initStatusAPI();
+        KajetansMod.scheduler.scheduleRepeatingTask(new EnvironmentTick(), 40, 30);
+    }    
+    
+    @SubscribeEvent
+    public void onRespawn(PlayerEvent.PlayerRespawnEvent e)
+    {       
+        EntityPlayer p = e.player;
+        EnvironmentAPI.resetThirst(p);
+        EnvironmentAPI.resetEnergy(p);
+        EnvironmentAPI.resetCold(p);
+        EnvironmentAPI.resetMana(p);
+    }
+    
+    @SubscribeEvent
+    public void onInteract(AttackEntityEvent e)
+    {       
+        EntityPlayer p = e.getEntityPlayer();
+        if(KajetansMod.worldManager.getWorldPreferences(p.getEntityWorld()).statusEffects && 
+            !(p.isCreative() || p.isSpectator()))
+        {
+            EnvironmentAPI.changeThirst(p, -40);
+            EnvironmentAPI.changeEnergy(p, -20);  
+        }
+    }
+    
+    @SubscribeEvent
+    public void onBedClick(PlayerInteractEvent.RightClickBlock e)
+    {       
+        if(e.getHand() != EnumHand.MAIN_HAND || 
+            !KajetansMod.worldManager.getWorldPreferences(e.getWorld()).statusEffects ||
+            e.getWorld().getBlockState(e.getPos()).getBlock() != Blocks.BED)
+        {
+            return;
+        }
+        EntityPlayer p = e.getEntityPlayer();
+        if(!(p.isCreative() || p.isSpectator()))
+        {
+            EnvironmentAPI.resetEnergy(p);
+        }
+    }
+    
+    @SubscribeEvent(receiveCanceled = false)
+    public void onBlockBreak(BlockEvent.BreakEvent e)
+    {
+        if(KajetansMod.worldManager.getWorldPreferences(e.getWorld()).statusEffects)
+        {
+            EntityPlayer p = e.getPlayer();
+            if(!(p.isCreative() || p.isSpectator()))
+            {
+                EnvironmentAPI.changeThirst(p, -20);
+                EnvironmentAPI.changeEnergy(p, -10);
+            }
+        }
+    }
+    
+    @SubscribeEvent(receiveCanceled = false)
+    public void onBlockPlace(BlockEvent.PlaceEvent e)
+    {
+        if(KajetansMod.worldManager.getWorldPreferences(e.getWorld()).statusEffects)
+        {
+            EntityPlayer p = e.getPlayer();
+            if(!(p.isCreative() || p.isSpectator()))
+            {
+                EnvironmentAPI.changeThirst(p, -20);
+                EnvironmentAPI.changeEnergy(p, -10);
+            }
+        }   
+    }
+    
+    @SubscribeEvent(receiveCanceled = false)
+    public void onWaterConsume(LivingEntityUseItemEvent.Finish e)
+    {
+        if(e.getItem().getItem() == Items.POTIONITEM)
+        {
+            if(e.getEntityLiving() instanceof EntityPlayer)
+            {
+                EntityPlayer p = (EntityPlayer) e.getEntityLiving();
+                if(KajetansMod.worldManager.getWorldPreferences(p.getEntityWorld()).statusEffects)
+                {
+                    EnvironmentAPI.resetThirst(p);
+                }
+            } 
+        }  
+    }
+    
+    @SubscribeEvent(priority = EventPriority.HIGH, receiveCanceled = false)
+    public void onCauldronClick(PlayerInteractEvent.RightClickBlock e)
+    {       
+        if(e.getHand() != EnumHand.MAIN_HAND ||
+            !KajetansMod.worldManager.getWorldPreferences(e.getWorld()).statusEffects)
+        {
+            return;
+        }
+        EntityPlayer p = e.getEntityPlayer();
+        if(p.getHeldItemMainhand().getItem() == Items.POTIONITEM)
+        {
+            return;
+        }
+        World w = e.getWorld();
+        IBlockState state = w.getBlockState(e.getPos());
+        if(state.getBlock() == Blocks.CAULDRON)
+        {
+            int meta = Blocks.CAULDRON.getMetaFromState(state) - 1;
+            if(meta < 0)
+            {
+                return;
+            }
+            Blocks.CAULDRON.setWaterLevel(w, e.getPos(), state, meta);
+            EnvironmentAPI.resetThirst(p);        
+        }
+    }  
+}

+ 97 - 0
src/main/java/me/km/environment/EnvironmentTick.java

@@ -0,0 +1,97 @@
+package me.km.environment;
+
+import java.util.Arrays;
+import me.km.KajetansMod;
+import me.km.effects.Effect;
+import me.km.effects.EffectUtils;
+import net.minecraft.init.MobEffects;
+import net.minecraft.util.DamageSource;
+
+public class EnvironmentTick implements Runnable
+{
+    @Override
+    public void run() 
+    {        
+        Arrays.stream(KajetansMod.server.worlds).filter(w -> KajetansMod.worldManager.getWorldPreferences(w).statusEffects).forEach(w -> 
+            {
+                w.playerEntities.stream()
+                        .filter(p -> !(p.isCreative() || p.isSpectator()))
+                        .forEach(p -> 
+                {
+                    int i = -12;
+                    float damage = 0;
+                    // Durst    
+                    if(p.isInWater())
+                    {
+                        if(p.isSprinting())
+                        {
+                            i -= 12;
+                        }
+                        EnvironmentAPI.changeThirst(p, i);
+                        if(EnvironmentAPI.getThirst(p) <= 1000)
+                        {
+                            damage += 0.5;
+                        }
+                    }
+                    else
+                    {
+                        EnvironmentAPI.resetThirst(p);
+                    }
+
+                    // Energie
+                    i = -6;
+                    if(p.isSprinting())
+                    {
+                        i -= 6; 
+                    } 
+                    EnvironmentAPI.changeEnergy(p, i);    
+                    int energy = EnvironmentAPI.getEnergy(p) - 3000;
+                    if(energy < 0)
+                    {                
+                        energy /= -1000;
+                        EffectUtils.addPotionTo(p, MobEffects.SLOWNESS, 800, energy);
+                        EffectUtils.addPotionTo(p, MobEffects.MINING_FATIGUE, 800, energy);
+                        EffectUtils.addPotionTo(p, MobEffects.WEAKNESS, 800, energy);
+                    }
+
+                    // Kälte
+                    i = EnvironmentAPI.getTemperature(w, p.getPosition());
+                    i = (i - 10) / 2;
+                    //System.out.println(p.getName() + "  " + i);
+                    EnvironmentAPI.changeCold(p, i);
+
+                    if(EnvironmentAPI.getCold(p) <= 10)
+                    {
+                        damage += 0.5;
+                    }
+                    if(damage != 0)
+                    {
+                        p.attackEntityFrom(DamageSource.WITHER, damage);
+                    }
+                    
+                    // Hunger
+                    int hunger = EffectUtils.getEffectLevel(p, Effect.LESS_HUNGER);
+                    if(hunger > 0)
+                    {
+                        float f = p.getFoodStats().getSaturationLevel();
+                        f += hunger / 16f;
+                        if(f < 15)
+                        {
+                            p.getFoodStats().setFoodSaturationLevel(f);
+                        }
+                    }
+                });
+            });   
+        
+        Arrays.stream(KajetansMod.server.worlds).filter(w -> KajetansMod.worldManager.getWorldPreferences(w).statusEffects).forEach(w -> 
+            {
+                w.playerEntities.stream()
+                        .filter(p -> !(p.isCreative() || p.isSpectator()))
+                        .forEach(p -> 
+                {
+                    // Mana
+                    EnvironmentAPI.changeMana(p, 6);
+                });
+            });
+    }
+}

+ 7 - 3
src/main/java/me/km/items/ModItems.java

@@ -6,6 +6,7 @@ import net.minecraft.init.SoundEvents;
 import net.minecraft.inventory.EntityEquipmentSlot;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemArmor.ArmorMaterial;
+import net.minecraft.item.ItemStack;
 import net.minecraftforge.common.util.EnumHelper;
 import net.minecraftforge.fml.common.registry.GameRegistry;
 
@@ -57,9 +58,6 @@ public class ModItems
 	copperIngot = register(new ItemBase("copper_ingot", "ingotCopper").setCreativeTab(CreativeTabs.MATERIALS));
         copperNugget = register(new ItemBase("copper_nugget", "copperNugget").setCreativeTab(CreativeTabs.MATERIALS));
         
-        TOOL_COPPER.setRepairItem(copperIngot.getDefaultInstance());
-        ARMOR_COPPER.setRepairItem(copperIngot.getDefaultInstance());
-        
         copperSword =  register(new ItemSword(TOOL_COPPER, "copper_sword", "swordCopper"));
         copperShovel = register(new ItemSpade(TOOL_COPPER, "copper_shovel", "shovelCopper"));
         copperPickaxe = register(new ItemPickaxe(TOOL_COPPER, "copper_pickaxe", "pickaxeCopper"));
@@ -71,6 +69,12 @@ public class ModItems
         copperLeggings = register(new ItemArmor(ARMOR_COPPER, EntityEquipmentSlot.LEGS, "copper_leggings", "leggingsCopper"));
         copperBoots = register(new ItemArmor(ARMOR_COPPER, EntityEquipmentSlot.FEET, "copper_boots", "bootsCopper"));
     }
+    
+    public static void lateInit() 
+    {
+        TOOL_COPPER.setRepairItem(new ItemStack(copperIngot));
+        ARMOR_COPPER.setRepairItem(new ItemStack(copperIngot));
+    }
 	
     private static <T extends Item> T register(T item) 
     {

+ 1 - 89
src/main/java/me/km/nms/NmsUtilities.java

@@ -2,18 +2,14 @@ package me.km.nms;
 
 import java.util.List;
 import me.km.api.Location;
-import me.km.exception.IllegalItemStackStringException;
 import me.km.exception.IllegalStringException;
 import net.minecraft.block.Block;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityLiving;
-import net.minecraft.entity.ai.attributes.AttributeModifier;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.init.Blocks;
-import net.minecraft.inventory.EntityEquipmentSlot;
 import net.minecraft.inventory.IInventory;
-import net.minecraft.item.ItemStack;
 import net.minecraft.nbt.JsonToNBT;
 import net.minecraft.nbt.NBTException;
 import net.minecraft.nbt.NBTTagCompound;
@@ -137,91 +133,7 @@ public class NmsUtilities
             w.notifyNeighborsRespectDebug(pos, iblockdata.getBlock(), false);
         }
     }
-   
-    // -------------------------------------------------------------------------
-    // ItemStack Tools
-    // -------------------------------------------------------------------------
-    
-    public enum Attribute
-    {
-        /**
-         * Wert von 0 bis 30;
-         */
-        ARMOR("generic.armor"),
-        /**
-         * Wert von 0 bis 20;
-         */
-        ARMOR_TOUGHNESS("generic.armorToughness"),
-        /**
-         * Wert von 0 bis 1.7E308;
-         */
-        ATTACK_DAMAGE("generic.attackDamage"),
-        /**
-         * Wert von 0 bis 1;
-         */
-        KNOCKBACK_RESISTANCE("generic.knockbackResistance"),
-        /**
-         * Wert von 0 bis 1.7E308;
-         */
-        MAX_HEALTH("generic.maxHealth"),
-        /**
-         * Wert von 0 bis 1.7E308;
-         */
-        MOVEMENT_SPEED("generic.movementSpeed"),
-        /**
-         * Wert von 0 bis 1024;
-         */
-        ATTACK_SPEED("generic.attackSpeed"),
-        /**
-         * Wert von -1024 bis 1024;
-         */
-        LUCK("generic.luck");
-        
-        private final String name;
-        
-        Attribute(String name)
-        {
-            this.name = name;
-        } 
-        
-        public String getName()
-        {
-            return name;
-        }
-    }
-    
-    public enum Operation
-    {
-        ADD, MUL, MUL_CHANGED
-    }
-    
-    public static void addAttribute(ItemStack stack, Attribute a, EntityEquipmentSlot slot, double amount, Operation op)
-    {
-        stack.addAttributeModifier(a.getName(), new AttributeModifier("modifier", amount, op.ordinal()), slot);      
-    }
-    
-    public static String getNbtString(ItemStack stack)
-    {
-        if(stack == null)
-        {
-            return "null";
-        }
-        return stack.writeToNBT(new NBTTagCompound()).toString();
-    }
-    
-    public static ItemStack getStackFromNbtString(String s) throws IllegalItemStackStringException
-    {
-        try
-        {
-            NBTTagCompound c = JsonToNBT.getTagFromJson(s);
-            return new ItemStack(c);
-        }
-        catch(NBTException ex)
-        {
-            throw new IllegalItemStackStringException(s);
-        }
-    }
-    
+
     // -------------------------------------------------------------------------
     // NBT Tools
     // -------------------------------------------------------------------------  

+ 15 - 3
src/main/java/me/km/permissions/Permissions.java

@@ -11,11 +11,23 @@ public enum Permissions
     POSITION, SEEN, TIME, TOP, TP_POS, USER, WARP, BOOK, GROW, ENCHANT, SPEED,
     TELEPORT_ACCEPT, 
     
-    // ChatManager
+    // Chat-Manager
     COLOR, USE_COLOR, NICKNAME, FAKERANK, WORLD,
     
-    // BlockProtections
-    BLOCK_BYPASS, BLOCK, BLOCK_ALL, BLOCK_OTHER, BLOCK_CLEAR
+    // Block-Protections
+    BLOCK_BYPASS, BLOCK, BLOCK_ALL, BLOCK_OTHER, BLOCK_CLEAR,
+    
+    // AFK-Manager
+    AFK, AFK_OTHER,
+    
+    // Data-Tools
+    DATATOOLS, VILLAGER,
+    
+    // Effects
+    WAND,
+    
+    // Environment
+    HEAL_STATS, TEMPERATURE
     
     // Special
 }

+ 52 - 0
src/main/java/me/km/skills/Skill.java

@@ -0,0 +1,52 @@
+package me.km.skills;
+
+import me.km.api.Utils;
+import me.km.effects.Effect;
+import me.km.utils.ItemStackBuilder;
+import me.km.utils.ItemStackUtils;
+import me.km.utils.ItemStackUtils.ItemFlag;
+import net.minecraft.item.ItemStack;
+
+public class Skill 
+{ 
+    private final ItemStack stack;
+    private final Effect effect;
+    private final String name;
+    
+    public Skill(ItemStack stack, Effect eff, String name, String explanation)
+    {
+        ItemStackUtils.addItemFlag(stack, ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_UNBREAKABLE);
+        ItemStackUtils.setUnbreakable(stack);
+        stack.setStackDisplayName("§6" + name);
+        ItemStackUtils.setLore(stack, Utils.buildLimitedLore(explanation, "§7"));
+        this.stack = stack;
+        this.effect = eff;
+        this.name = name;
+    }
+
+    public ItemStack getItemStack(int amount)
+    {
+        int mana = effect.getManaCost(amount);
+        stack.setCount(amount);
+        if(mana == 0)
+        {
+            return stack.copy();
+        }
+        return new ItemStackBuilder(stack, amount).addToName(" §3(" + mana +")").build();
+    }
+    
+    public boolean isActive()
+    {
+        return effect.isActive();
+    }
+    
+    public Effect getEffect()
+    {
+        return effect;
+    }
+    
+    public String getName()
+    {
+        return name;
+    }
+}

+ 20 - 0
src/main/java/me/km/utils/EntityInventory.java

@@ -0,0 +1,20 @@
+package me.km.utils;
+
+import net.minecraft.entity.Entity;
+import net.minecraft.inventory.InventoryBasic;
+
+public class EntityInventory extends InventoryBasic
+{
+    private final Entity ent;
+    
+    public EntityInventory(String title, int slotCount, Entity ent) 
+    {
+        super(title, true, slotCount);
+        this.ent = ent;
+    }
+    
+    public Entity getEntity()
+    {
+        return ent;
+    }
+}

+ 31 - 0
src/main/java/me/km/utils/InventoryUtils.java

@@ -0,0 +1,31 @@
+package me.km.utils;
+
+import net.minecraft.entity.passive.EntityVillager;
+import net.minecraft.inventory.InventoryBasic;
+
+public class InventoryUtils
+{       
+    public static InventoryBasic getInventory(EntityVillager v)
+    {
+        EntityInventory real = new EntityInventory("Villager", 9, v);
+        InventoryBasic old = v.getVillagerInventory();
+        for(int i = 0; i < 9; i++)
+        {
+            real.setInventorySlotContents(i, old.getStackInSlot(i).copy());
+        }
+        return real;
+    }
+    
+    public static void setInventory(EntityInventory inv)
+    {
+        if(inv.getEntity() instanceof EntityVillager)
+        {
+            EntityVillager v = (EntityVillager) inv.getEntity();
+            InventoryBasic vInv = v.getVillagerInventory();
+            for(int i = 0; i < 9; i++)
+            {
+                vInv.setInventorySlotContents(i, inv.getStackInSlot(i).copy());
+            }
+        }
+    }
+}

+ 1 - 1
src/main/java/me/km/api/ItemStackBuilder.java → src/main/java/me/km/utils/ItemStackBuilder.java

@@ -1,4 +1,4 @@
-package me.km.api;
+package me.km.utils;
 
 import net.minecraft.block.Block;
 import net.minecraft.item.Item;

+ 195 - 0
src/main/java/me/km/utils/ItemStackUtils.java

@@ -0,0 +1,195 @@
+package me.km.utils;
+
+import java.util.ArrayList;
+import me.km.exception.IllegalItemStackStringException;
+import net.minecraft.entity.ai.attributes.AttributeModifier;
+import net.minecraft.inventory.EntityEquipmentSlot;
+import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.JsonToNBT;
+import net.minecraft.nbt.NBTException;
+import net.minecraft.nbt.NBTTagCompound;
+
+public class ItemStackUtils 
+{
+    // -----------------------------------------------------------------------------------
+    // Attribute
+    // -----------------------------------------------------------------------------------
+    
+    public enum Attribute
+    {
+        /**
+         * value from 0 to 30;
+         */
+        ARMOR("generic.armor"),
+        /**
+         * value from 0 to 20;
+         */
+        ARMOR_TOUGHNESS("generic.armorToughness"),
+        /**
+         * value from 0 to 1.7E308;
+         */
+        ATTACK_DAMAGE("generic.attackDamage"),
+        /**
+         * value from 0 to 1;
+         */
+        KNOCKBACK_RESISTANCE("generic.knockbackResistance"),
+        /**
+         * value from 0 to 1.7E308;
+         */
+        MAX_HEALTH("generic.maxHealth"),
+        /**
+         * value from 0 to 1.7E308;
+         */
+        MOVEMENT_SPEED("generic.movementSpeed"),
+        /**
+         * value from 0 to 1024;
+         */
+        ATTACK_SPEED("generic.attackSpeed"),
+        /**
+         * value from -1024 to 1024;
+         */
+        LUCK("generic.luck");
+        
+        private final String name;
+        
+        Attribute(String name)
+        {
+            this.name = name;
+        } 
+        
+        public String getName()
+        {
+            return name;
+        }
+    }
+    
+    public enum Operation
+    {
+        ADD, MUL, MUL_CHANGED
+    }
+    
+    public static void addAttribute(ItemStack stack, Attribute a, EntityEquipmentSlot slot, double amount, Operation op)
+    {
+        stack.addAttributeModifier(a.getName(), new AttributeModifier("modifier", amount, op.ordinal()), slot);   
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Item-Flags
+    // -----------------------------------------------------------------------------------
+    
+    public enum ItemFlag
+    {
+        /**
+        * Setting to show/hide enchants
+        */
+        HIDE_ENCHANTS,
+        /**
+        * Setting to show/hide Attributes like Damage
+        */
+        HIDE_ATTRIBUTES,
+        /**
+        * Setting to show/hide the unbreakable State
+        */
+        HIDE_UNBREAKABLE,
+        /**
+        * Setting to show/hide what the ItemStack can break/destroy
+        */
+        HIDE_DESTROYS,
+        /**
+        * Setting to show/hide where this ItemStack can be build/placed on
+        */
+        HIDE_PLACED_ON,
+        /**
+        * Setting to show/hide potion effects on this ItemStack
+        */
+        HIDE_POTION_EFFECTS;
+        
+        public byte getBit()
+        {
+            return (byte) (1 << this.ordinal());
+        }
+    }
+
+    public static void addItemFlag(ItemStack stack, ItemFlag... flags)
+    {
+        NBTTagCompound com = stack.hasTagCompound() ? stack.getTagCompound() : new NBTTagCompound();
+        if(com == null) // this will never happen, but the compiler wants it
+        {
+            return;
+        }
+        int i = com.getInteger("HideFlags");
+        for (ItemFlag f : flags) 
+        {
+            i |= f.getBit(); // bitwise 'or'
+        }
+        com.setInteger("HideFlags", i);
+        stack.setTagCompound(com);
+    }
+    
+    public static void removeItemFlags(ItemStack stack, ItemFlag... flags) 
+    {
+        NBTTagCompound com = stack.hasTagCompound() ? stack.getTagCompound() : new NBTTagCompound();
+        if(com == null) // this will never happen, but the compiler wants it
+        {
+            return;
+        }
+        int i = com.getInteger("HideFlags");
+        for (ItemFlag f : flags) 
+        {
+            i &= ~f.getBit(); // bitwise 'and' with inversed bits
+        }
+        com.setInteger("HideFlags", i);
+        stack.setTagCompound(com);
+    }
+    
+    public static boolean hasItemFlag(ItemStack stack, ItemFlag flag) 
+    {
+        if(!stack.hasTagCompound())
+        {
+            return false;
+        }
+        NBTTagCompound com = stack.getTagCompound();
+        if(com == null) // this will never happen, but the compiler wants it
+        {
+            return false;
+        }
+        byte b = flag.getBit();
+        return (com.getInteger("HideFlags") & b) == b;
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Converter
+    // -----------------------------------------------------------------------------------
+    
+    public static String getNbtString(ItemStack stack)
+    {
+        return stack.writeToNBT(new NBTTagCompound()).toString();
+    }
+    
+    public static ItemStack getStackFromNbtString(String s) throws IllegalItemStackStringException
+    {
+        try
+        {
+            NBTTagCompound c = JsonToNBT.getTagFromJson(s);
+            return new ItemStack(c);
+        }
+        catch(NBTException ex)
+        {
+            throw new IllegalItemStackStringException(s);
+        }
+    }
+    
+    // -----------------------------------------------------------------------------------
+    // Misc
+    // -----------------------------------------------------------------------------------
+    
+    public static void setUnbreakable(ItemStack stack) 
+    {
+        // TODO
+    }
+    
+    public static void setLore(ItemStack stack, ArrayList<String> list) 
+    {
+        // TODO
+    }
+}

+ 30 - 0
src/main/java/me/km/utils/ReflectionUtils.java

@@ -0,0 +1,30 @@
+package me.km.utils;
+
+import java.lang.reflect.Field;
+import net.minecraft.entity.passive.EntityVillager;
+
+public class ReflectionUtils 
+{    
+    public static void setCareerLevel(EntityVillager v, int level)
+    {
+        try
+        {
+            Field f = EntityVillager.class.getDeclaredField("careerLevel");
+            {
+                try
+                {
+                    f.setAccessible(true);
+                    f.setInt(v, level);
+                }
+                catch(SecurityException | IllegalArgumentException | IllegalAccessException ex)
+                {
+                    System.out.println("setCareerLevel - " + ex);
+                }
+            }
+        }
+        catch(NoSuchFieldException | SecurityException ex)
+        {
+            System.out.println("setCareerLevel - " + ex);
+        }
+    }
+}

BIN
src/main/resources/assets/km/textures/blocks/real_hay_block_side.png


BIN
src/main/resources/assets/km/textures/blocks/real_hay_block_top.png