Browse Source

Fertigstellung des WorldLoaders und ChatManagers, Fixes, PlayerTarget nun mit RayTrace

Kajetan Johannes Hammerle 8 years ago
parent
commit
d693369a94
34 changed files with 1457 additions and 191 deletions
  1. 12 8
      src/main/java/me/km/KajetansMod.java
  2. 5 0
      src/main/java/me/km/api/GlobalText.java
  3. 7 19
      src/main/java/me/km/api/Location.java
  4. 13 5
      src/main/java/me/km/api/MessageSender.java
  5. 2 1
      src/main/java/me/km/api/SimpleConfig.java
  6. 54 42
      src/main/java/me/km/api/Utils.java
  7. 132 0
      src/main/java/me/km/blockprotections/BlockProtection.java
  8. 266 0
      src/main/java/me/km/blockprotections/BlockProtectionBank.java
  9. 252 0
      src/main/java/me/km/blockprotections/CommandBlock.java
  10. 46 0
      src/main/java/me/km/blockprotections/SemiProtections.java
  11. 9 13
      src/main/java/me/km/chatmanager/ChatListener.java
  12. 78 37
      src/main/java/me/km/chatmanager/ChatManager.java
  13. 18 17
      src/main/java/me/km/chatmanager/CommandFakeRank.java
  14. 17 20
      src/main/java/me/km/chatmanager/CommandNickName.java
  15. 8 8
      src/main/java/me/km/chatmanager/Rank.java
  16. 3 5
      src/main/java/me/km/commands/CommandBack.java
  17. 3 0
      src/main/java/me/km/commands/CommandCoords.java
  18. 2 1
      src/main/java/me/km/commands/CommandList.java
  19. 3 2
      src/main/java/me/km/commands/CommandMsg.java
  20. 0 2
      src/main/java/me/km/commands/CommandSpawner.java
  21. 7 6
      src/main/java/me/km/commands/CommandTest.java
  22. 0 1
      src/main/java/me/km/commands/CommandTop.java
  23. 237 0
      src/main/java/me/km/dimensions/CommandWorld.java
  24. 15 0
      src/main/java/me/km/dimensions/CustomWorldProviderEnd.java
  25. 15 0
      src/main/java/me/km/dimensions/CustomWorldProviderHell.java
  26. 15 0
      src/main/java/me/km/dimensions/CustomWorldProviderSurface.java
  27. 132 0
      src/main/java/me/km/dimensions/ModDimensions.java
  28. 39 0
      src/main/java/me/km/dimensions/ModTeleporter.java
  29. 29 0
      src/main/java/me/km/dimensions/WorldData.java
  30. 25 0
      src/main/java/me/km/dimensions/WorldPreferences.java
  31. 10 1
      src/main/java/me/km/permissions/Permissions.java
  32. 2 2
      src/main/java/me/km/scheduler/SnuviTask.java
  33. 1 1
      src/main/java/me/km/scheduler/TaskTicker.java
  34. 0 0
      src/main/resources/assets/km/lang/en_US.lang

+ 12 - 8
src/main/java/me/km/KajetansMod.java

@@ -2,9 +2,12 @@ package me.km;
 
 import me.km.api.Module;
 import me.km.api.SimpleConfig;
+import me.km.blockprotections.BlockProtectionBank;
 import me.km.blocks.ModBlocks;
 import me.km.chatmanager.ChatManager;
 import me.km.databank.DataBank;
+import me.km.dimensions.ModDimensions;
+import me.km.dimensions.WorldData;
 import me.km.entities.ModEntities;
 import me.km.fluids.ModFluids;
 import me.km.items.ModItems;
@@ -35,9 +38,9 @@ public class KajetansMod
     public static ChatManager chatManager;
     //public static Module afkManager;
     //public static Module plots;
-    //public static Module blocks;
+    public static Module blocks;
     //public static Module datatools;
-    //public static WorldData worldManager;
+    public static WorldData worldManager;
     //public static Module environment;
     //public static QuestAPI quest;
     //public static JobAPI jobs;
@@ -115,10 +118,10 @@ public class KajetansMod
         plots.registerEvents("me.kt.plots");*/
         
         // Chests- und Co-Protections
-        /*blocks = new Module("BlockProtections", "Blocks", TextFormatting.BLUE);
+        blocks = new Module("BlockProtections", "Blocks", TextFormatting.BLUE);
         blocks.setDataBank(new BlockProtectionBank(blocks, databank.getConnection()));
-        blocks.registerCommands(e, "me.kt.blockprotections");          
-        blocks.registerEvents("me.kt.blockprotections");*/
+        blocks.registerCommands(e, "me.km.blockprotections");          
+        blocks.registerEvents("me.km.blockprotections");
         
         // DataTools
         /*datatools = new Module("DataTools", "DataTools", TextFormatting.GRAY);
@@ -126,9 +129,9 @@ public class KajetansMod
         datatools.registerEvents("me.kt.datatools");*/
 
         // Worldmanager
-        /*worldManager = new WorldData("WorldManager", "Worlds", TextFormatting.RED);
-        worldManager.registerCommands(e, "me.kt.worlds");          
-        worldManager.registerEvents("me.kt.worlds");*/
+        worldManager = new WorldData("WorldManager", "Worlds", TextFormatting.RED);
+        worldManager.registerCommands(e, "me.km.dimensions");          
+        worldManager.registerEvents("me.km.dimensions");
         
         // Questsystem
         /*quest = new QuestAPI("Quests", "Quests", TextFormatting.LIGHT_PURPLE);
@@ -189,6 +192,7 @@ public class KajetansMod
     public void init(FMLInitializationEvent event) 
     {
         ModEntities.init();
+        ModDimensions.init();
     }
 
     @Mod.EventHandler

+ 5 - 0
src/main/java/me/km/api/GlobalText.java

@@ -47,6 +47,11 @@ public class GlobalText
         return "Dieser Fehler sollte nie passieren.";
     }
     
+    public static String notImplementedYet()
+    {
+        return "Dieses Feature ist noch nicht implementiert.";
+    }
+    
     public static String Spacer()
     {
         return "§0-----------------------------------------------------";

+ 7 - 19
src/main/java/me/km/api/Location.java

@@ -1,6 +1,5 @@
 package me.km.api;
 
-import me.km.KajetansMod;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
@@ -26,9 +25,14 @@ public class Location
         this(w, pos, 0, 0);
     }
     
+    public Location(World w, BlockPos pos, float yaw, float pitch)
+    {
+        this(w, new Vec3d(pos.getX(), pos.getY(), pos.getZ()), yaw, pitch);
+    }
+    
     public Location(World w, BlockPos pos)
     {
-        this(w, new Vec3d(pos.getX(), pos.getY(), pos.getZ()));
+        this(w, pos, 0, 0);
     }
 
     public World getWorld() 
@@ -61,24 +65,8 @@ public class Location
         this.yaw = yaw;
     }
     
-    public static World getWorld(String s)
-    {
-        if(s == null)
-        {
-            return null;
-        }
-        for(World w : KajetansMod.server.worlds)
-        {
-            if(w.getWorldInfo().getWorldName().equals(s))
-            {
-                return w;
-            }
-        }
-        return null;
-    }
-    
     public static IBlockState getRelativeBlock(World w, BlockPos pos, int x, int y, int z)
     {
-        return w.getBlockState(new BlockPos(pos.getX() + x, pos.getY() + y, pos.getZ() + z));
+        return w.getBlockState(pos.add(x, y, z));
     }
 }

+ 13 - 5
src/main/java/me/km/api/MessageSender.java

@@ -6,6 +6,7 @@ import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.util.math.BlockPos;
 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;
@@ -13,10 +14,12 @@ import net.minecraft.world.World;
 public class MessageSender 
 {
     private final ArrayList<ITextComponent> prefixes;
+    private final ArrayList<TextFormatting> colors;
     
     public MessageSender()
     {
         prefixes = new ArrayList<>();
+        colors = new ArrayList<>();
     }
     
     public void registerPrefix(String name, TextFormatting color)
@@ -24,6 +27,7 @@ public class MessageSender
         TextComponentString text = new TextComponentString(name);
         text.getStyle().setColor(color);
         prefixes.add(new TextComponentString("[").appendSibling(text).appendText("] "));
+        colors.add(color);
     }
 
     public void send(ICommandSender cs, String msg, int id)
@@ -57,8 +61,10 @@ public class MessageSender
         {
             return;
         }
-        TextComponentString text = new TextComponentString(" - ");
-        text.getStyle().setColor(prefixes.get(id).getStyle().getColor());
+        TextComponentString text = new TextComponentString("");
+        TextComponentString text2 = new TextComponentString(" - ");
+        text2.getStyle().setColor(colors.get(id));
+        text.appendSibling(text2);
         cs.sendMessage(text.appendText(msg));
     }
     
@@ -73,9 +79,11 @@ public class MessageSender
         {
             return;
         }
-        TextComponentString text = new TextComponentString(" - ");
-        text.getStyle().setColor(prefixes.get(id).getStyle().getColor());
-        cs.sendMessage(text.appendText(msg + " " + msg2));
+        TextComponentString text = new TextComponentString("");
+        TextComponentString text2 = new TextComponentString(" - " + msg + " ");
+        text2.getStyle().setColor(colors.get(id));
+        text.appendSibling(text2);
+        cs.sendMessage(text.appendText(msg2));
     }
     
     public void sendHelpListElement(ICommandSender cs, String msg, String msg2)

+ 2 - 1
src/main/java/me/km/api/SimpleConfig.java

@@ -10,6 +10,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.TreeMap;
 import java.util.stream.Collectors;
+import me.km.dimensions.ModDimensions;
 import net.minecraft.util.math.Vec3d;
 
 public class SimpleConfig
@@ -134,7 +135,7 @@ public class SimpleConfig
     
     public Location getLocation(String key)
     {
-        return new Location(Location.getWorld(getString(key + ".world")), 
+        return new Location(ModDimensions.getWorldFromName(getString(key + ".world")), 
                 new Vec3d(getDouble(key + ".x", 0), getDouble(key + ".y", 0), getDouble(key + ".z", 0)),
                 getFloat(key + ".yaw", 0), getFloat(key + ".pitch", 0));
     }

+ 54 - 42
src/main/java/me/km/api/Utils.java

@@ -1,6 +1,5 @@
 package me.km.api;
 
-import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -8,6 +7,7 @@ import java.util.List;
 import java.util.Random;
 import java.util.stream.Collectors;
 import me.km.KajetansMod;
+import me.km.dimensions.ModTeleporter;
 import me.km.exception.PlayerNotFoundException;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.player.EntityPlayer;
@@ -17,6 +17,7 @@ import net.minecraft.block.BlockContainer;
 import net.minecraft.block.BlockDoor;
 import net.minecraft.block.BlockPistonMoving;
 import net.minecraft.block.BlockTrapDoor;
+import net.minecraft.block.properties.IProperty;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.init.Blocks;
@@ -30,14 +31,27 @@ import net.minecraft.item.ItemSpade;
 import net.minecraft.util.math.AxisAlignedBB;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.Vec3d;
-import net.minecraft.util.math.Vec3i;
 import net.minecraft.world.World;
 import net.minecraft.item.ItemStack;
-import net.minecraft.item.ItemSword;
+import net.minecraft.item.ItemSword; 
 import net.minecraft.potion.Potion;
+import net.minecraft.util.math.RayTraceResult;
+import net.minecraft.world.WorldServer;
 
 public class Utils 
 {    
+    public static <T extends Comparable<T>> T getStateValue(IBlockState state, IProperty<T> property)
+    {
+        try
+        {
+            return state.getValue(property);
+        }
+        catch(IllegalArgumentException ex)
+        {
+            return null;
+        }
+    }
+    
     // -------------------------------------------------------------------------
     // Potions
     // -------------------------------------------------------------------------
@@ -304,28 +318,39 @@ public class Utils
         return new Location(ent.getEntityWorld(), ent.getPositionVector(), ent.rotationYaw, ent.rotationPitch);
     }
     
-    public static BlockPos getEyeLocation(Entity ent) 
+    public static Vec3d getEyeLocation(Entity ent) 
     {
-        return ent.getPosition().add(0, ent.getEyeHeight(), 0);
+        return ent.getPositionVector().addVector(0, ent.getEyeHeight(), 0);
     }
     
     public static void teleportEntity(Entity ent, Location l)
     {
         Vec3d pos = l.getPos();
-        
+
         if(ent instanceof EntityPlayerMP)
         {
+            EntityPlayerMP p = (EntityPlayerMP) ent;
+            if(ent.dimension != l.getWorld().provider.getDimension())
+            {
+                int dim = l.getWorld().provider.getDimension();
+                KajetansMod.server.getPlayerList().transferPlayerToDimension(p, dim, new ModTeleporter(KajetansMod.server.worldServerForDimension(dim)));
+            }
             if(l.getYaw() != 0 && l.getPitch() != 0)
             {
-                ((EntityPlayerMP) ent).connection.setPlayerLocation(pos.xCoord, pos.yCoord, pos.zCoord, l.getYaw(), l.getPitch());
+                p.connection.setPlayerLocation(pos.xCoord, pos.yCoord, pos.zCoord, l.getYaw(), l.getPitch());
             }
             else
             {
-                ((EntityPlayerMP) ent).connection.setPlayerLocation(pos.xCoord, pos.yCoord, pos.zCoord, ent.rotationYaw, ent.rotationPitch);
+                p.connection.setPlayerLocation(pos.xCoord, pos.yCoord, pos.zCoord, ent.rotationYaw, ent.rotationPitch);
             }
         }
         else
         {
+            if(ent.dimension != l.getWorld().provider.getDimension())
+            {
+                WorldServer n = KajetansMod.server.worldServerForDimension(l.getWorld().provider.getDimension());
+                KajetansMod.server.getPlayerList().transferEntityToWorld(ent, ent.dimension, KajetansMod.server.worldServerForDimension(ent.dimension), n, new ModTeleporter(n));
+            }
             if(l.getYaw() != 0 && l.getPitch() != 0)
             {
                 ent.setLocationAndAngles(pos.xCoord, pos.yCoord, pos.zCoord, l.getYaw(), l.getPitch());
@@ -374,13 +399,12 @@ public class Utils
     {
         World w = p.getEntityWorld();
         BlockPos l = getPlayerTarget(p, radius);
-        BlockPos eye = getEyeLocation(p);
-        List<Entity> col = getEntitiesExcluding(p, w, eye, l);
+        Vec3d end = new Vec3d(l.getX(), l.getY(), l.getZ());
+        Vec3d eye = getEyeLocation(p);
+        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
-        Vec3d first = new Vec3d(eye.getX(), eye.getY(), eye.getZ());
-        Vec3d second = new Vec3d(l.getX(), l.getY(), l.getZ());
         col.removeIf(ent -> 
         {
             AxisAlignedBB bound = ent.getCollisionBoundingBox();
@@ -388,12 +412,12 @@ public class Utils
             {
                 return true;
             }
-            return bound.calculateIntercept(first, second) == null;
+            return bound.calculateIntercept(eye, end) == null;
         });
 
         return (T) col.stream().sorted((Entity e1, Entity e2) -> 
         {
-            return Double.compare(e1.getDistanceSq(eye), e2.getDistanceSq(eye));
+            return Double.compare(e1.getDistanceSq(eye.xCoord, eye.yCoord, eye.zCoord), e2.getDistanceSq(eye.xCoord, eye.yCoord, eye.zCoord));
         }).findFirst().orElse(null);
     }
     
@@ -406,25 +430,21 @@ public class Utils
         return w.getPlayers(EntityPlayer.class, p -> true).stream().min((p1, p2) -> Double.compare(p1.getDistanceSq(l), p2.getDistanceSq(l))).orElse(null);
     }
     
-    public static BlockPos getPlayerTarget(EntityPlayer p, int range)
+    public static BlockPos getPlayerTarget(EntityPlayer p, double range)
     {
         if(range > 64)
         {
             range = 64;
         }
         World w = p.getEntityWorld();
-        BlockPos l = getEyeLocation(p);
-        Vec3d unit2 = p.getLookVec();
-        Vec3i unit = new Vec3i(unit2.xCoord, unit2.yCoord, unit2.zCoord);
-        for(int i = 0; i < range; i++)
+        Vec3d start = getEyeLocation(p);
+        Vec3d end = start.add(p.getLookVec().scale(range));
+        RayTraceResult ray = w.rayTraceBlocks(start, end, true);
+        if(ray == null)
         {
-            l = l.add(unit);
-            if(w.isBlockFullCube(l))
-            {
-                break;
-            }
+            return new BlockPos(end);
         }
-        return l;   
+        return ray.getBlockPos();   
     }
     
     public static BlockPos getPlayerTarget(EntityPlayer p)
@@ -475,32 +495,24 @@ public class Utils
     // Blocks
     // -------------------------------------------------------------------------
     
-    public static Block getSameNearbyBlock(World w, BlockPos pos, Block b)
+    public static BlockPos getSameNearbyBlock(World w, BlockPos pos, Block b)
     {           
-        Block bcheck = Location.getRelativeBlock(w, pos, 1, 0, 0).getBlock();
-        if(bcheck == b)
+        if(Location.getRelativeBlock(w, pos, 1, 0, 0).getBlock() == b)
         {
-            return bcheck;
+            return pos.add(1, 0, 0);
         }
-        
-        bcheck = Location.getRelativeBlock(w, pos, -1, 0, 0).getBlock();
-        if(bcheck == b)
+        else if(Location.getRelativeBlock(w, pos, -1, 0, 0).getBlock() == b)
         {
-            return bcheck;
+            return pos.add(-1, 0, 0);
         }
-        
-        bcheck = Location.getRelativeBlock(w, pos, 0, 0, 1).getBlock();;  
-        if(bcheck == b)
+        else if(Location.getRelativeBlock(w, pos, 0, 0, 1).getBlock() == b)
         {
-            return bcheck;
+            return pos.add(0, 0, 1);
         }
-
-        bcheck = Location.getRelativeBlock(w, pos, 0, 0, -1).getBlock();
-        if(bcheck == b)
+        else if(Location.getRelativeBlock(w, pos, 0, 0, -1).getBlock() == b)
         {
-            return bcheck;
+            return pos.add(0, 0, -1);
         }
-        
         return null;
     }
        

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

@@ -0,0 +1,132 @@
+package me.km.blockprotections;
+
+import me.km.KajetansMod;
+import me.km.api.Utils;
+import me.km.api.Module;
+import me.km.api.ModuleListener;
+import me.km.permissions.Permission;
+import me.km.permissions.Permissions;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockContainer;
+import net.minecraft.block.BlockDoor;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.EnumHand;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+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;
+
+public class BlockProtection extends ModuleListener
+{
+    private final BlockProtectionBank bank;
+    
+    public BlockProtection(Module m) 
+    {
+        super(m);
+        bank = KajetansMod.blocks.getDataBank(BlockProtectionBank.class);
+    }
+    
+    @SubscribeEvent(priority = EventPriority.HIGHEST)
+    public void onBlockPlace(BlockEvent.PlaceEvent e)
+    {
+        if(!KajetansMod.worldManager.getWorldPreferences(e.getWorld()).blockProtection)
+        {
+            return;
+        }
+        Block b = e.getPlacedBlock().getBlock();
+        if(!Utils.shouldBeProtected(b))
+        {
+            return;
+        }     
+        EntityPlayer p = e.getPlayer();
+        World w = e.getWorld();
+        
+        // Deny placing chests near other protected chests
+        if(b == Blocks.CHEST || b == Blocks.TRAPPED_CHEST)
+        {
+            BlockPos otherChest = Utils.getSameNearbyBlock(w, e.getPos(), b);
+            if(otherChest != null && !bank.hasAccess(otherChest, w, p.getGameProfile(), true) && !Permission.hasPermission(p, Permissions.BLOCK_BYPASS))
+            {
+                this.getModule().send(p, "Du darfst diesen Block hier nicht setzen");
+                e.setCanceled(true);
+                return;
+            }        
+        } 
+        
+        // Deny placing of hoppers under blocks
+        if(b == Blocks.HOPPER)
+        {
+            BlockPos pos = e.getPos().add(0, 1, 0);
+            if(w.getBlockState(pos).getBlock() instanceof BlockContainer)
+            {
+                if(!bank.hasAccess(pos, w, p, true) && !Permission.hasPermission(p, Permissions.BLOCK_BYPASS))
+                {
+                    this.getModule().send(p, "Du darfst diesen Block hier nicht setzen");
+                    e.setCanceled(true);
+                }               
+            }            
+        }
+    }
+    
+    @SubscribeEvent(priority = EventPriority.HIGHEST)
+    public void onBlockBreak(BlockEvent.BreakEvent e)
+    {
+        if(!KajetansMod.worldManager.getWorldPreferences(e.getWorld()).blockProtection)
+        {
+            return;
+        }
+        EntityPlayer p = e.getPlayer();
+        IBlockState state = e.getState();
+        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);
+            } 
+            World w = e.getWorld();
+            if(!bank.doesExist(pos, w))
+            {
+                return;
+            }       
+            if(bank.hasAccess(pos, w, p, false) || Permission.hasPermission(p, Permissions.BLOCK_BYPASS))
+            {
+                bank.removeBlock(pos, w, p);
+                return;
+            }   
+            e.setCanceled(true);
+            this.getModule().send(p, "Du hast keinen Zugriff auf diesen Block.");
+        }             
+    }
+    
+    @SubscribeEvent(priority = EventPriority.HIGHEST)
+    public void onContainerOpen(PlayerInteractEvent.RightClickBlock e)
+    {
+        if(e.getHand() != EnumHand.MAIN_HAND || !KajetansMod.worldManager.getWorldPreferences(e.getWorld()).blockProtection)
+        {
+            return;
+        }
+        IBlockState state = e.getWorld().getBlockState(e.getPos());
+        if(!Utils.shouldBeProtected(state.getBlock()))
+        {
+            return;
+        }
+        EntityPlayer p = e.getEntityPlayer();
+        BlockPos pos = e.getPos();
+        if(Utils.getStateValue(state, BlockDoor.HALF) == BlockDoor.EnumDoorHalf.UPPER)
+        {
+            pos = pos.add(0, -1, 0);
+        }
+        if(bank.hasAccess(pos, e.getWorld(), p, true) || Permission.hasPermission(p, Permissions.BLOCK_BYPASS))
+        {
+            return;
+        }  
+        this.getModule().send(p, "Du hast keinen Zugriff auf diesen Block.");
+        e.setCanceled(true);   
+    }
+}

+ 266 - 0
src/main/java/me/km/blockprotections/BlockProtectionBank.java

@@ -0,0 +1,266 @@
+package me.km.blockprotections;
+
+import com.mojang.authlib.GameProfile;
+import me.km.KajetansMod;
+import me.km.api.GlobalText;
+import me.km.api.Module;
+import me.km.playerbank.PlayerBank;
+import me.km.databank.SimpleDataBank;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import me.km.api.Location;
+import me.km.dimensions.ModDimensions;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.world.World;
+
+public class BlockProtectionBank extends SimpleDataBank
+{  
+    public BlockProtectionBank(Module m, Connection c) 
+    {
+        super(m, c);
+    }
+    
+    @Override
+    protected void init() 
+    {
+        // BlockProtectionBank - Coords und ID
+        if(!this.doesTableExist("block"))
+        {
+            this.getModule().sendToConsole("Die Block-Protection-Bank wurde nicht gefunden, erstelle ...");
+            if(this.update("CREATE TABLE IF NOT EXISTS block ("
+                    + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
+                    + "x int(11) NOT NULL, "
+                    + "y int(11) NOT NULL, "
+                    + "z int(11) NOT NULL, "
+                    + "world_name varchar(20) NOT NULL, "
+                    + "UNIQUE KEY uniq_block_pos (world_name,x,y,z));", false))
+            {
+                this.getModule().sendToConsole("Die Block-Protection-Bank wurde erstellt.");
+            }
+        }
+        else
+        {
+            this.getModule().sendToConsole("Die Block-Protection-Bank wurde gefunden.");
+        }
+        
+        
+        // BlockProtectionDataBank - Coords und ID
+        if(!this.doesTableExist("block_grant"))
+        {
+            this.getModule().sendToConsole("Die Block-Protection-Data-Bank wurde nicht gefunden, erstelle ...");
+            if(this.update("CREATE TABLE block_grant ("
+                    + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
+                    + "block_id int(11) NOT NULL, "
+                    + "player_id int(11) NOT NULL, "
+                    + "INDEX block_id (block_id), "
+                    + "UNIQUE KEY (block_id, player_id), "
+                    + "CONSTRAINT block_grant_ibfk_1 FOREIGN KEY (block_id) REFERENCES block (id) ON DELETE CASCADE);", false))
+            {
+                this.getModule().sendToConsole("Die Block-Protection-Data-Bank wurde erstellt.");
+            }
+        }
+        else
+        {
+            this.getModule().sendToConsole("Die Block-Protection-Data-Bank wurde gefunden.");
+        }
+    }  
+    
+    //--------------------------------------------------------------------------
+    // Allgemeine Texte
+    //--------------------------------------------------------------------------
+    
+    private void printError(EntityPlayer p)
+    {
+        this.getModule().sendWarning(p, "Es ist ein Fehler aufgetreten.");
+    }
+
+    //--------------------------------------------------------------------------
+    // Block-Methoden
+    //--------------------------------------------------------------------------
+    
+    public void addBlock(BlockPos pos, World w, EntityPlayer p, String pname)
+    {
+        if(doesExist(pos, w))
+        {
+            this.getModule().send(p, "Der Block ist bereits gesichert.");
+            return;
+        }
+        Integer id;
+        pname = makeStringSafe(pname);
+        if(pname != null)
+        {
+            id = KajetansMod.playerbank.getDataBank(PlayerBank.class).getIdByName(pname);
+            if(id == null)
+            {
+                this.getModule().send(p, GlobalText.cantFindPlayer(pname));
+                return;  
+            }
+        }
+        else
+        {
+            id = KajetansMod.playerbank.getDataBank(PlayerBank.class).getIdByUUID(p.getUniqueID().toString());
+            if(id == null)
+            {
+                this.getModule().send(p, GlobalText.cantFindPlayer(pname));
+                return;  
+            }
+        }      
+
+        if(this.update("INSERT INTO block (x,y,z,world_name) "
+            + "VALUES (" + pos.getX() + "," + pos.getY() + "," + pos.getZ() + ",'" + ModDimensions.getWorldName(w) + "');", false) &&
+           this.update("INSERT INTO block_grant (block_id,player_id) VALUES (LAST_INSERT_ID(), " + id + ");", false))
+        {
+            this.getModule().send(p, "Der Block wurde gesichert.");
+            return;
+        }
+        printError(p);
+    }
+    
+    public void removeBlock(BlockPos pos, World w, EntityPlayer p)
+    {
+        if(this.update("DELETE FROM block WHERE x=" + pos.getX() + 
+                " AND y=" + pos.getY() + " AND z=" + pos.getZ() + 
+                " AND world_name='" + ModDimensions.getWorldName(w) + "';", false))
+        {
+            this.getModule().send(p, "Die Block-Sicherung wurde gelöscht.");
+            return;
+        }
+        printError(p); 
+    }
+    
+    public void addPlayer(BlockPos pos, World w, GameProfile p, EntityPlayer executor)
+    {
+        if(hasAccess(pos, w, p, false))
+        {
+            this.getModule().send(executor, "Der Spieler '" + p.getName() + "' ist bereits vorhanden.");
+            return;
+        }
+        Integer id = KajetansMod.playerbank.getDataBank(PlayerBank.class).getIdByUUID(p.getId().toString());
+        if(id == null)
+        {
+            this.getModule().send(executor, GlobalText.cantFindPlayer(p.getName()));
+            return;
+        }
+        if(this.update("INSERT INTO block_grant (block_id,player_id) "
+                + "SELECT id, " + id
+                + " FROM block WHERE world_name='" + ModDimensions.getWorldName(w) + "' AND x=" + pos.getX() + " AND y=" + pos.getY()
+                + " AND z=" + pos.getZ() + ";", false))
+        {
+            this.getModule().send(executor, "Der Spieler '" + p.getName() + "' wurde hinzugefügt.");
+            return;
+        }
+        printError(executor);
+    }
+    
+    public void removePlayer(BlockPos pos, World w, GameProfile p, EntityPlayer executor)
+    {
+        if(!hasAccess(pos, w, p, false))
+        {
+            this.getModule().send(executor, "Der Spieler '" + p.getName() + "' ist nicht vorhanden.");
+            return;
+        }
+        Integer id = KajetansMod.playerbank.getDataBank(PlayerBank.class).getIdByUUID(p.getId().toString());
+        if(id == null)
+        {
+            this.getModule().send(executor, GlobalText.cantFindPlayer(p.getName()));
+            return;
+        }
+        if(this.update(
+            "DELETE block_grant FROM block_grant " +
+            "LEFT JOIN block ON block.id = block_grant.block_id " +
+            "WHERE block_grant.player_id = " + id + " AND " +
+            "block.world_name='" + ModDimensions.getWorldName(w) + "' AND block.x=" + pos.getX() + 
+            " AND block.y=" + pos.getY() + " AND block.z=" + pos.getZ() + ";", false))
+        {
+            this.getModule().send(executor, "Der Spieler '" + p.getName() + "' wurde entfernt.");
+            return;
+        }
+        printError(executor);
+    }
+    
+    public boolean hasAccess(BlockPos pos, World w, GameProfile p, boolean check)
+    {
+        if(check && !doesExist(pos, w))
+        {
+            return true;
+        }
+        return this.getFirst(
+            "Select block_grant.id from block_grant " +
+            "LEFT JOIN players ON players.id = block_grant.player_id LEFT JOIN block ON block.id = block_grant.block_id " +
+            "WHERE players.uuid = '" + p.getId().toString() + "' AND " +
+            "block.world_name='" + ModDimensions.getWorldName(w) + "' AND block.x=" + pos.getX() +
+            " AND block.y=" + pos.getY() + " AND block.z=" + pos.getZ() + ";", Integer.class) != null; 
+    }
+    
+    public boolean hasAccess(BlockPos pos, World w, EntityPlayer p, boolean check)
+    {
+        return hasAccess(pos, w, p.getGameProfile(), check);
+    }
+    
+    public boolean doesExist(BlockPos pos, World w)
+    {
+        return this.getFirst(
+            "SELECT id FROM block WHERE world_name='" + ModDimensions.getWorldName(w) + 
+            "' AND x=" + pos.getX() + " AND y=" + pos.getY() + 
+            " AND z=" + pos.getZ() + ";", Integer.class) != null;
+    }
+    
+    public void printInfo(BlockPos pos, World w, EntityPlayer p)
+    {
+        Module m = this.getModule();
+        if(!doesExist(pos, w))
+        {
+            m.send(p, "Dieser Block ist nicht gesichert.");
+            return;
+        }
+        ArrayList<Object> list = this.getFirstColumn(
+            "Select block_grant.player_id from block_grant " +
+            "LEFT JOIN block ON block.id = block_grant.block_id " +
+            "WHERE block.world_name='" + ModDimensions.getWorldName(w) + "' AND block.x=" + pos.getX() +
+            " AND block.y=" + pos.getY() + " AND block.z=" + pos.getZ() + ";"); 
+        if(list == null)
+        {
+            printError(p);
+            return;
+        }
+        if(list.isEmpty())
+        {
+            m.send(p, "Dieser Block ist gesichert, gehört aber niemanden.");
+            return;
+        }
+        m.send(p, "Dieser Block gehört den folgenden Spielern:");
+        PlayerBank pb = KajetansMod.playerbank.getDataBank(PlayerBank.class);
+        list.stream().map(id -> pb.getNameById((int) id)).filter(name -> name != null).forEach(name ->
+        {
+            m.sendListElement(p, name);
+        });
+    }
+    
+    public List<Location> getAll()
+    {
+        return this.get("Select x,y,z,world_name from block;").stream().map(li -> 
+        {
+            try
+            {
+                return new Location(ModDimensions.getWorldFromName(li.get(3).toString()), new Vec3d((int) li.get(0), (int) li.get(1), (int) li.get(2)));
+            }
+            catch(Exception ex)
+            {
+                return null;
+            }
+        }).filter(l -> l != null && l.getWorld() != null).collect(Collectors.toList());
+    }
+    
+    private String makeStringSafe(String s)
+    {
+        if(s == null)
+        {
+            return null;
+        }    
+        return s.replace("'", "").replace("\"", "");
+    }
+}

+ 252 - 0
src/main/java/me/km/blockprotections/CommandBlock.java

@@ -0,0 +1,252 @@
+package me.km.blockprotections;
+
+import com.mojang.authlib.GameProfile;
+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.permissions.Permission;
+import me.km.permissions.Permissions;
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockDoor;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+
+public class CommandBlock extends ModuleCommand
+{
+    private final BlockProtectionBank bank;
+    //private int counter;
+    //private List<Location> locs;
+    //private final ArrayList<BlockState> blocks;
+    //private boolean checker;
+    
+    public CommandBlock(Module m) 
+    {
+        super("block", m);
+        super.setDescription("Zeigt alles für die Block-Verwaltung");
+        super.setUsage("/block für die Hilfe");
+        super.setPermission(Permissions.BLOCK);
+        
+        bank = KajetansMod.blocks.getDataBank(BlockProtectionBank.class);
+        //locs = new ArrayList<>();
+        //blocks = new ArrayList<>();
+    }
+    
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg)   
+    {
+        if(!(cs instanceof EntityPlayerMP))
+        {
+            this.getModule().send(cs, GlobalText.onlyPlayer());
+            return true;
+        }
+        Module m = this.getModule();
+        EntityPlayerMP p = (EntityPlayerMP) cs;
+        World w = p.getEntityWorld();
+        if(!KajetansMod.worldManager.getWorldPreferences(w).blockProtection && !Permission.hasPermission(cs, Permissions.BLOCK_BYPASS))
+        {
+            m.send(cs, "Du darfst hier keine Blöcke schützen.");
+            return true;
+        }
+        if(arg.length > 0)
+        {
+            BlockPos pos = Utils.getPlayerTarget(p);  
+            IBlockState state = w.getBlockState(pos);
+            Block b = state.getBlock();
+            if(!Utils.shouldBeProtected(b) && !Permission.hasPermission(cs, Permissions.BLOCK_ALL))
+            {
+                m.send(cs, "Du kannst diesen Block nicht bearbeiten.");
+                m.send(cs, "Du bist auf folgenden Block gerichtet: " + b.toString());
+                return true;
+            }                  
+            if(Utils.getStateValue(state, BlockDoor.HALF) == BlockDoor.EnumDoorHalf.UPPER)
+            {
+                pos = pos.add(0, -1, 0);
+            } 
+            switch(arg[0])
+            {
+                case "protect":  
+                {
+                    String name = null;
+                    if(arg.length >= 2 && Permission.hasPermission(cs, Permissions.BLOCK_OTHER))
+                    {
+                        name = arg[1];
+                    }
+                    bank.addBlock(pos, w, p, name);
+                    if(b != Blocks.CHEST && b != Blocks.TRAPPED_CHEST)
+                    {
+                        return true;
+                    }
+                    BlockPos otherChest = Utils.getSameNearbyBlock(w, pos, b);
+                    if(otherChest != null)
+                    {
+                        bank.addBlock(otherChest, w, p, name); 
+                    }
+                    return true;
+                }
+                case "remove":
+                {
+                    if(!bank.doesExist(pos, w))
+                    {
+                        this.getModule().send(p, "Der Block ist nicht gesichert.");
+                        return true;
+                    }
+                    if(!bank.hasAccess(pos, w, p, false) && !Permission.hasPermission(cs, Permissions.BLOCK_BYPASS))
+                    {
+                        m.send(cs, "Du hast keinen Zugriff auf diesen Block.");
+                        return true;
+                    }
+                    bank.removeBlock(pos, w, p);
+                    if(b != Blocks.CHEST && b != Blocks.TRAPPED_CHEST)
+                    {
+                        return true;
+                    }
+                    BlockPos otherChest = Utils.getSameNearbyBlock(w, pos, b);
+                    if(otherChest != null)
+                    {
+                        bank.removeBlock(otherChest, w, p); 
+                    }
+                    return true;
+                }
+                case "info":
+                {
+                    bank.printInfo(pos, w, p);
+                    return true;
+                }
+                case "share":
+                {
+                    if(arg.length >= 2)
+                    {
+                        if(!bank.doesExist(pos, w))
+                        {
+                            this.getModule().send(p, "Der Block ist nicht gesichert.");
+                            return true;
+                        }
+                        if(!bank.hasAccess(pos, w, p, false) && !Permission.hasPermission(cs, Permissions.BLOCK_BYPASS))
+                        {
+                            m.send(cs, "Du hast keinen Zugriff auf diesen Block.");
+                            return true;
+                        }
+                        GameProfile player = KajetansMod.playerbank.getDataBank().getOfflinePlayer(arg[1]);
+                        if(player == null)
+                        {
+                            m.send(cs, GlobalText.cantFindPlayer(arg[1]));
+                            return true;
+                        }
+                        bank.addPlayer(pos, w, player, p);
+                        if(b != Blocks.CHEST && b != Blocks.TRAPPED_CHEST)
+                        {
+                            return true;
+                        }
+                        BlockPos otherChest = Utils.getSameNearbyBlock(w, pos, b);
+                        if(otherChest != null)
+                        {
+                            bank.addPlayer(otherChest, w, player, p); 
+                        }
+                        return true;
+                    }
+                }
+                case "kick":
+                {
+                    if(arg.length >= 2)
+                    {
+                        if(!bank.doesExist(pos, w))
+                        {
+                            this.getModule().send(p, "Der Block ist nicht gesichert.");
+                            return true;
+                        }
+                        if(!bank.hasAccess(pos, w, p, true) && !Permission.hasPermission(cs, Permissions.BLOCK_BYPASS))
+                        {
+                            m.send(cs, "Du hast keinen Zugriff auf diesen Block.");
+                            return true;
+                        }
+                        GameProfile player = KajetansMod.playerbank.getDataBank().getOfflinePlayer(arg[1]);
+                        if(player == null)
+                        {
+                            m.send(cs, GlobalText.cantFindPlayer(arg[1]));
+                            return true;
+                        }
+                        bank.removePlayer(pos, w, player, p);
+                        if(b != Blocks.CHEST && b != Blocks.TRAPPED_CHEST)
+                        {
+                            return true;
+                        }
+                        BlockPos otherChest = Utils.getSameNearbyBlock(w, pos, b);
+                        if(otherChest != null)
+                        {
+                            bank.removePlayer(otherChest, w, player, p); 
+                        }
+                        return true;
+                    }
+                }
+                case "clear":
+                {
+                    if(Permission.hasPermission(cs, Permissions.BLOCK_CLEAR))
+                    {
+                        //TODO
+                        this.getModule().send(cs, GlobalText.notImplementedYet());
+                        /*checker = false;
+                        Bukkit.getScheduler().runTaskAsynchronously(this.getModule().getPlugin(), () -> 
+                        {
+                            counter = 0;
+                            locs = bank.getAll();
+                            checker = true;
+                        });
+                        Bukkit.getScheduler().scheduleSyncDelayedTask(this.getModule().getPlugin(), () -> 
+                        {
+                            if(!checker)
+                            {
+                                this.getModule().send(cs, "Das Abrufen aller Einträge hat zu lange gedauert.");
+                                locs.clear();
+                                blocks.clear();
+                                return;
+                            }
+                            locs.stream().forEach((l) -> 
+                            {
+                                Bukkit.getScheduler().scheduleSyncDelayedTask(this.getModule().getPlugin(), () -> 
+                                {
+                                    try
+                                    {
+                                        blocks.add(l.getBlock().getState());
+                                    }
+                                    catch(NullPointerException ex)
+                                    {
+                                    }
+                                });
+                            });
+                        }, 200);
+                        Bukkit.getScheduler().runTaskLaterAsynchronously(this.getModule().getPlugin(), () -> 
+                        {
+                            blocks.stream().filter(bl -> !Utils.shouldBeProtected(bl)).forEach(bl -> 
+                            {
+                                bank.removeBlock(bl.getLocation(), p);
+                                counter++;
+                            });
+                            this.getModule().send(cs, "Alle ungültigen Protections wurden entfernt. (" + counter + ")");
+                            locs.clear();
+                            blocks.clear();
+                        }, 400);*/
+                        return true;
+                    }
+                    break;
+                }
+            }                    
+        }
+        m.send(cs, "/block ...");
+        m.sendHelpListElement(cs, "protect [player]", "Erstellt eine Block-Protection");
+        m.sendHelpListElement(cs, "remove", "Löscht eine Block-Protection");
+        m.sendHelpListElement(cs, "info", "Gibt Information über den Block");
+        m.sendHelpListElement(cs, "share <player>", "Teilt eine Block-Protection mit einem Spieler");
+        m.sendHelpListElement(cs, "kick <player>", "Kickt einen Spieler von einer Block-Protection");
+        if(Permission.hasPermission(cs, Permissions.BLOCK_CLEAR))
+        {
+            m.sendHelpListElement(cs, "clear", "Entfernt ungültige Block-Protections auf jeden Block");
+        }
+        return true;        
+    }
+}

+ 46 - 0
src/main/java/me/km/blockprotections/SemiProtections.java

@@ -0,0 +1,46 @@
+package me.km.blockprotections;
+
+import me.km.KajetansMod;
+import me.km.api.Module;
+import me.km.api.ModuleListener;
+import me.km.permissions.Permission;
+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;
+
+public class SemiProtections extends ModuleListener
+{    
+    //private final BlockProtectionBank bank;
+    
+    public SemiProtections(Module m)
+    {
+        super(m);
+        //bank = KajetansMod.blocks.getDataBank(BlockProtectionBank.class);
+    }
+    
+    @SubscribeEvent
+    public void onBlockBreak(BlockEvent.BreakEvent e)
+    {
+        EntityPlayer p = e.getPlayer();
+        if(Permission.hasPermission(p, Permissions.BLOCK_BYPASS) && p.isCreative())
+        {
+            return;
+        }
+        IBlockState b = e.getState();
+        if(b.getBlock() instanceof BlockCrops)
+        {
+            // TODO
+            /*if(!bank.hasTag(e., "farm"))
+            {
+                return;
+            }*/
+            e.setCanceled(true); 
+            b.getBlock().dropBlockAsItem(e.getWorld(), e.getPos(), b, 0);
+            e.getWorld().setBlockState(e.getPos(), b.withProperty(BlockCrops.AGE, 7));
+        }
+    }
+}

+ 9 - 13
src/main/java/me/km/chatmanager/ChatListener.java

@@ -1,13 +1,11 @@
 package me.km.chatmanager;
 
-import me.kt.KajetansTools;
-import me.kt.api.Module;
-import me.kt.api.ModuleListener;
-import org.bukkit.ChatColor;
-import org.bukkit.entity.Player;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.player.AsyncPlayerChatEvent;
+import me.km.KajetansMod;
+import me.km.api.Module;
+import me.km.api.ModuleListener;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraftforge.event.ServerChatEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 
 public class ChatListener extends ModuleListener
 {
@@ -16,11 +14,9 @@ public class ChatListener extends ModuleListener
         super(m);
     }
     
-    @EventHandler(priority = EventPriority.LOW)
-    public void onChatEvent(AsyncPlayerChatEvent e)
+    @SubscribeEvent
+    public void onChatEvent(ServerChatEvent e)
     {
-        Player p = e.getPlayer();
-        e.setMessage(ChatColor.RESET + ChatManager.colorMessage(e.getMessage(), p));
-        e.setFormat(KajetansTools.chatManager.getFullName(p) + ChatColor.DARK_BLUE + " | " + "%2$s");    
+        e.setComponent(new TextComponentString(KajetansMod.chatManager.getFullName(e.getPlayer()) + "§1 | §r"  + ChatManager.colorMessage(e.getMessage(), e.getPlayer())));
     }
 }

+ 78 - 37
src/main/java/me/km/chatmanager/ChatManager.java

@@ -2,9 +2,8 @@ package me.km.chatmanager;
 
 import me.km.api.Module;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.List;
+import java.util.HashSet;
 import java.util.UUID;
 import java.util.stream.Collectors;
 import me.km.permissions.Permission;
@@ -15,75 +14,117 @@ import net.minecraft.util.text.TextFormatting;
 
 public class ChatManager extends Module
 {    
-    private final ArrayList<List<Rank>> ranks;
+    private final HashMap<Integer, ArrayList<Rank>> ranks;
     private final HashMap<UUID, String> fakeRank;
+    private final String fallback;
+    private final HashMap<UUID, HashSet<String>> playerRanks;
 
     public ChatManager(String mname, String prefix, TextFormatting color) 
     {
         super(mname, prefix, color);
-        ranks = new ArrayList<>();
-        ranks.add(Arrays.asList(new Rank("geist", "§8Geist")));
+        ranks = new HashMap<>();
         fakeRank = new HashMap<>(); 
+        fallback = "§8Geist";
+        playerRanks = new HashMap<>();
     }
 
-    // -------------------------------------------------------------------------
-    // Ränge registrieren und abrufen
-    // -------------------------------------------------------------------------
-    
-    public void registerRank(String perm, int group, String name)
+    // -----------------------------------------------------------------------------------
+    // Rank-Handling
+    // -----------------------------------------------------------------------------------
+
+    /** Registers a rank by its permission, group and name. The idea is that ranks in the 
+     * same group overwrite themselves by picking the first match in the list.
+     *
+     * @param name the name of the rank to identify it
+     * @param group the id of the rank group
+     * @param text the text, which will be shown for the rank
+     */
+    public void registerRank(String name, int group, String text)
     {
-        List<Rank> list;
-        if(ranks.size() > group)
+        ArrayList<Rank> list = ranks.get(group);
+        if(list == null)
         {
-            list = ranks.get(group);
+            list = new ArrayList<>();
+            ranks.put(group, list);
         }
-        else
+        list.add(new Rank(name, text));
+    }
+    
+    /** Registers a rank for a players uuid
+     *
+     * @param uuid a uuid of a player
+     * @param rank the rank, which should be registered
+     */
+    public void registerPlayerRank(UUID uuid, String rank)
+    {
+        HashSet<String> set = playerRanks.get(uuid);
+        if(set == null)
         {
-            list = new ArrayList<>();
-            ranks.add(list);
+            set = new HashSet<>();
         }
-        list.add(new Rank(perm, name));
+        set.add(rank);
     }
     
+    /** Gets all texts of the players ranks
+     *
+     * @param p a player
+     * @return rank texts as list, the list will never be empty due to  fallback
+     */
     public ArrayList<String> getRanks(EntityPlayer p)
     {
-        // TODO
-        /*ArrayList<String> list = ranks.stream().skip(1)
-                .map(l -> 
-                {
-                    for(Rank r : l)
+        HashSet<String> pRanks = playerRanks.get(p.getUniqueID());
+        if(pRanks != null)
+        {
+            ArrayList<String> list = ranks.values().stream()
+                    .map(l ->
                     {
-                        if(false)
+                        for(Rank r : l)
                         {
-                            return r.getName();
+                            if(pRanks.contains(r.getName()))
+                            {
+                                return r.getName();
+                            }
                         }
-                    }
-                    return null;
-                })
-                .filter(s -> s != null)
-                .collect(Collectors.toCollection(ArrayList::new));
-        if(list.isEmpty())
+                        return null;
+                    })
+                    .filter(s -> s != null)
+                    .collect(Collectors.toCollection(ArrayList::new));
+            if(list.isEmpty())
+            {
+                list.add(fallback);        
+            }
+            return list;
+        }
+        else
         {
-            list.add(ranks.get(0).get(0).getName());        
+            ArrayList<String> list = new ArrayList<>();
+            list.add(fallback);
+            return list;
         }
-        return list;*/
-        return new ArrayList<>();
     }
     
+    /** Removes all ranks and their player registry from the cache
+     *
+     */
     public void clearRanks()
     {
         ranks.clear();
-        ranks.add(Arrays.asList(new Rank("geist", "§8Geist")));
+        playerRanks.clear();
     }
     
+    /** Gets the players display name and its ranks
+     *
+     * @param p a player
+     * @return players display name and ranks collected with specific format
+     */
     public String getFullName(EntityPlayer p)
     {
         String fake = fakeRank.get(p.getUniqueID());
         if(fake != null)
         {
-            return fake + " " + p.getDisplayName();
+            return fake + " " + p.getDisplayNameString();
         }
-        return getRanks(p).stream().collect(Collectors.joining("§r][", "[", "§r] " + p.getDisplayName()));
+        return getRanks(p).stream().collect(Collectors.joining("§r][", "[", "§r] " + p.getDisplayNameString()));
     }
     
     // -------------------------------------------------------------------------
@@ -106,7 +147,7 @@ public class ChatManager extends Module
     }
     
     // -------------------------------------------------------------------------
-    // Text färben
+    // Text-Coloring-Helper
     // -------------------------------------------------------------------------
     
     public static String colorMessage(String text, ICommandSender cs) 

+ 18 - 17
src/main/java/me/km/chatmanager/CommandFakeRank.java

@@ -1,32 +1,33 @@
 package me.km.chatmanager;
 
-import me.kt.KajetansTools;
-import me.kt.api.GlobalText;
-import me.kt.api.Module;
-import me.kt.api.ModuleCommand;
-import me.kt.api.Utils;
-import me.kt.exceptions.PlayerNotFoundException;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
+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.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
 
 public class CommandFakeRank extends ModuleCommand
 {
     public CommandFakeRank(Module m) 
     {
         super("fakerank", m);
-        this.setDescription("Gibt einem Spieler einen falschen Rang");
-        this.setUsage("/fakerank <rank/clear> [player]");
-        this.setPermission("kt.fakerank");
+        super.setDescription("Gibt einem Spieler einen falschen Rang");
+        super.setUsage("/fakerank <rank/clear> [player]");
+        super.setPermission(Permissions.FAKERANK);
     }
 
     @Override
-    public boolean execute(CommandSender cs, String string, String[] arg) 
+    public boolean execute(ICommandSender cs, String[] arg) 
     {
         if(arg.length < 1)
         {
             return false;
         }
-        Player affectedPlayer;
+        EntityPlayer affectedPlayer;
         try
         {
             affectedPlayer = Utils.getPlayerByName(arg[1]);                   
@@ -38,17 +39,17 @@ public class CommandFakeRank extends ModuleCommand
         }
         catch(IndexOutOfBoundsException ex)
         {
-            if(!(cs instanceof Player))
+            if(!(cs instanceof EntityPlayer))
             {
                 this.getModule().send(cs, GlobalText.missingParameter());
                 return true;
             }
-            affectedPlayer = (Player) cs;
+            affectedPlayer = (EntityPlayer) cs;
         }
         
         if(arg[0].equals("clear"))
         {
-            KajetansTools.chatManager.removeFakeRank(affectedPlayer);
+            KajetansMod.chatManager.removeFakeRank(affectedPlayer);
             this.getModule().send(affectedPlayer, "Du hast keinen falschen Rang mehr.");
             if(!cs.equals(affectedPlayer))
             {
@@ -57,7 +58,7 @@ public class CommandFakeRank extends ModuleCommand
             return true;
         }
         String rank = ChatManager.colorMessage(arg[0], cs);
-        KajetansTools.chatManager.addFakeRank(affectedPlayer, rank);
+        KajetansMod.chatManager.addFakeRank(affectedPlayer, rank);
         this.getModule().send(affectedPlayer, "Du hast nun den falschen Rang '" + rank + "§r'.");
         if(!cs.equals(affectedPlayer))
         {

+ 17 - 20
src/main/java/me/km/chatmanager/CommandNickName.java

@@ -1,31 +1,32 @@
 package me.km.chatmanager;
 
-import me.kt.api.GlobalText;
-import me.kt.api.Module;
-import me.kt.api.ModuleCommand;
-import me.kt.api.Utils;
-import me.kt.exceptions.PlayerNotFoundException;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
+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.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayerMP;
 
 public class CommandNickName extends ModuleCommand
 {
     public CommandNickName(Module m) 
     {
         super("nickname", m);
-        this.setDescription("Gibt einem Spieler einen Nickname");
-        this.setUsage("/nickname <nick/clear> [player]");
-        this.setPermission("kt.nickname");
+        super.setDescription("Gibt einem Spieler einen Nickname");
+        super.setUsage("/nickname <nick/clear> [player]");
+        super.setPermission(Permissions.NICKNAME);
     }
 
     @Override
-    public boolean execute(CommandSender cs, String string, String[] arg) 
+    public boolean execute(ICommandSender cs, String[] arg) 
     {
         if(arg.length < 1)
         {
             return false;
         }
-        Player affectedPlayer;
+        EntityPlayerMP affectedPlayer;
         try
         {
             affectedPlayer = Utils.getPlayerByName(arg[1]);                   
@@ -37,19 +38,17 @@ public class CommandNickName extends ModuleCommand
         }
         catch(IndexOutOfBoundsException ex)
         {
-            if(!(cs instanceof Player))
+            if(!(cs instanceof EntityPlayerMP))
             {
                 this.getModule().send(cs, GlobalText.missingParameter());
                 return true;
             }
-            affectedPlayer = (Player) cs;
+            affectedPlayer = (EntityPlayerMP) cs;
         }
         
         if(arg[0].equals("clear") || arg[0].equals("off"))
         {
-            affectedPlayer.setDisplayName(affectedPlayer.getName());
-            affectedPlayer.setPlayerListName(affectedPlayer.getName());
-            affectedPlayer.setCustomName(affectedPlayer.getName());
+            affectedPlayer.setCustomNameTag(null);
             this.getModule().send(affectedPlayer, "Du hast keinen Nicknamen mehr.");
             if(!cs.equals(affectedPlayer))
             {
@@ -57,9 +56,7 @@ public class CommandNickName extends ModuleCommand
             }
             return true;
         }
-        affectedPlayer.setDisplayName(arg[0]);
-        affectedPlayer.setPlayerListName(arg[0]);
-        affectedPlayer.setCustomName(arg[0]);
+        affectedPlayer.setCustomNameTag(arg[0]);
         this.getModule().send(affectedPlayer, "Du hast nun den Nicknamen '" + arg[0] + "'.");
         if(!cs.equals(affectedPlayer))
         {

+ 8 - 8
src/main/java/me/km/chatmanager/Rank.java

@@ -2,28 +2,28 @@ package me.km.chatmanager;
 
 public class Rank 
 {
-    private final String perm;
     private final String name;
+    private final String text;
     
-    public Rank(String perm, String name)
+    public Rank(String name, String text)
     {
-        this.perm = perm;
         this.name = name;
+        this.text = text;
     }
     
-    public String getPermission()
+    public String getName()
     {
-        return "kt.rank." + perm;
+        return name;
     }
     
-    public String getName()
+    public String getText()
     {
-        return name;
+        return text;
     }
 
     @Override
     public String toString() 
     {
-        return "[perm: " + perm + ", name: " + name + "]";
+        return "[name: " + name + ", text: " + text + "]";
     }
 }

+ 3 - 5
src/main/java/me/km/commands/CommandBack.java

@@ -1,13 +1,10 @@
 package me.km.commands;
 
-import me.km.KajetansMod;
 import me.km.api.GlobalText;
 import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.permissions.Permissions;
-import me.km.playerbank.TeleportEvent;
 import net.minecraft.command.ICommandSender;
-import net.minecraft.entity.player.EntityPlayer;
 
 public class CommandBack extends ModuleCommand
 {
@@ -22,7 +19,8 @@ public class CommandBack extends ModuleCommand
     @Override
     public boolean execute(ICommandSender cs, String[] arg) 
     {
-        if(!(cs instanceof EntityPlayer))
+        this.getModule().send(cs, GlobalText.notImplementedYet());
+        /*if(!(cs instanceof EntityPlayer))
         {
             this.getModule().send(cs, GlobalText.onlyPlayer());
             return true;
@@ -35,7 +33,7 @@ public class CommandBack extends ModuleCommand
             p.teleport(l);
             return true;
         }
-        this.getModule().send(cs, "Es gibt noch keinen Ort, wo du zurückkehren könntest.");
+        this.getModule().send(cs, "Es gibt noch keinen Ort, wo du zurückkehren könntest.");*/
         return true;
     }
 }

+ 3 - 0
src/main/java/me/km/commands/CommandCoords.java

@@ -10,6 +10,7 @@ import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.text.TextComponentString;
 import net.minecraft.world.World;
+import net.minecraftforge.common.DimensionManager;
 
 public class CommandCoords extends ModuleCommand
 {
@@ -41,6 +42,8 @@ public class CommandCoords extends ModuleCommand
         cs.sendMessage(new TextComponentString(GlobalText.Spacer()));
         m.send(cs, "Block: " + w.getBlockState(pos).getBlock());
         m.send(cs, "Welt: " + w.getWorldInfo().getWorldName());
+        m.send(cs, "Dimension: " + p.dimension);
+        m.send(cs, "Dimension: " + DimensionManager.getProviderType(p.dimension).getName());
         m.send(cs, "Koordinaten: " + pos.getX() + " | " + pos.getY() + " | " + pos.getZ());
         m.send(cs, "Material-Data: " + w.getBlockState(pos));
         return true;

+ 2 - 1
src/main/java/me/km/commands/CommandList.java

@@ -9,6 +9,7 @@ import java.util.stream.Collectors;
 import me.km.permissions.Permissions;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.util.text.TextComponentString;
 
 public class CommandList extends ModuleCommand
 {
@@ -42,7 +43,7 @@ public class CommandList extends ModuleCommand
         ChatManager man = KajetansMod.chatManager;
         if(number > 0)
         {
-            cs.sendMessage(players.stream().map(p -> man.getFullName(p)).collect(Collectors.joining("§7, §r")));
+            cs.sendMessage(new TextComponentString(players.stream().map(p -> man.getFullName(p)).collect(Collectors.joining("§7, §r"))));
         }
         return true;
     }

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

@@ -30,7 +30,8 @@ public class CommandMsg extends ModuleCommand
     @Override
     public boolean execute(ICommandSender cs, String[] arg) 
     {
-        if(!string.equalsIgnoreCase("r"))
+        this.getModule().send(cs, GlobalText.notImplementedYet());
+        /*if(!string.equalsIgnoreCase("r"))
         {
             if(arg.length <= 1)
             {
@@ -85,7 +86,7 @@ public class CommandMsg extends ModuleCommand
         cs.sendMessage(new TextComponentString("§6[ -> §c" + previous.getName()+ "§6] §r" + message));
         previous.sendMessage(new TextComponentString("§6[§c" + cs.getName()+ "§6] §r" + message));
         answer.put(cs.getName(), previous.getName());
-        answer.put(previous.getName(), cs.getName());
+        answer.put(previous.getName(), cs.getName());*/
         return true;  
     }
 }

+ 0 - 2
src/main/java/me/km/commands/CommandSpawner.java

@@ -5,12 +5,10 @@ import me.km.api.GlobalText;
 import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.permissions.Permissions;
-import net.minecraft.block.Block;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityList;
 import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.init.Blocks;
 import net.minecraft.tileentity.TileEntity;
 import net.minecraft.tileentity.TileEntityMobSpawner;
 import net.minecraft.util.math.BlockPos;

+ 7 - 6
src/main/java/me/km/commands/CommandTest.java

@@ -1,12 +1,14 @@
 package me.km.commands;
 
-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.permissions.Permissions;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.util.math.BlockPos;
 
 public class CommandTest extends ModuleCommand
 {
@@ -26,11 +28,10 @@ public class CommandTest extends ModuleCommand
             this.getModule().send(cs, GlobalText.onlyPlayer());
             return true;
         }
-        this.getModule().send(cs, "Das ist ein Test.");
-        KajetansMod.scheduler.scheduleTask(() -> 
-        {
-            this.getModule().send(cs, "TIMERTEST");
-        }, 100);
+        EntityPlayer p = (EntityPlayer) cs;
+        BlockPos pos = Utils.getPlayerTarget(p);
+        p.getEntityWorld().setBlockState(pos, Blocks.REDSTONE_BLOCK.getDefaultState());
+        //this.getModule().send(cs, "Es passiert nichts.");
         return true;
     }
 }

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

@@ -5,7 +5,6 @@ import me.km.api.GlobalText;
 import me.km.api.Location;
 import me.km.api.Module;
 import me.km.api.ModuleCommand;
-import me.km.playerbank.PlayerBank;
 import me.km.exception.PlayerNotFoundException;
 import me.km.permissions.Permissions;
 import net.minecraft.command.ICommandSender;

+ 237 - 0
src/main/java/me/km/dimensions/CommandWorld.java

@@ -0,0 +1,237 @@
+package me.km.dimensions;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import me.km.KajetansMod;
+import me.km.api.GlobalText;
+import me.km.api.Location;
+import me.km.api.Module;
+import me.km.api.ModuleCommand;
+import me.km.api.Utils;
+import me.km.exception.PlayerNotFoundException;
+import me.km.permissions.Permissions;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.EnumDifficulty;
+import net.minecraft.world.WorldServer;
+
+public class CommandWorld extends ModuleCommand
+{
+    public CommandWorld(Module m) 
+    {
+        super("world", m);
+        super.setDescription("Befehle für die Verwaltung der Welten");
+        super.setUsage("/world für die Hilfe");
+        super.setPermission(Permissions.WORLD);
+    }
+
+    private boolean doesWorldExist(String name)
+    {
+        return new File("./saves/" + name).isDirectory();       
+    }  
+    
+    private ArrayList<String> getAllWorlds()
+    {
+        File worlds = new File("./saves/"); 
+        ArrayList<String> list = new ArrayList<>();
+        for(File f : worlds.listFiles())
+        {
+            if(!f.isDirectory())
+            {
+                continue;
+            }
+            if(new File(f, "level.dat").exists())
+            {
+                list.add(f.getName());
+            }
+        }
+        return list;       
+    }
+    
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        Module m = this.getModule();
+        if(arg.length >= 1)
+        {
+            switch(arg[0].toLowerCase())
+            {
+                case "tp":
+                {
+                    if(arg.length >= 2)
+                    {
+                        WorldServer w = ModDimensions.getWorldFromName(arg[1]);
+                        if(w == null)
+                        {
+                            m.send(cs, "Die Welt '" + arg[1] + "' wurde nicht gefunden.");
+                            return true;
+                        }
+                        EntityPlayerMP affectedEntityPlayerMP;
+                        try
+                        {
+                            affectedEntityPlayerMP = Utils.getPlayerByName(arg[2]);
+                        }
+                        catch(PlayerNotFoundException ex)
+                        {
+                            m.send(cs, GlobalText.cantFindPlayer(arg[2]));
+                            return true;
+                        }
+                        catch(IndexOutOfBoundsException ex)
+                        {
+                            if(!(cs instanceof EntityPlayerMP))
+                            {
+                                m.send(cs, GlobalText.missingParameter());
+                                return true;
+                            }
+                            affectedEntityPlayerMP = (EntityPlayerMP) cs;
+                        }
+                        BlockPos pos = w.getSpawnPoint();
+                        while(pos.getY() <= 255 && !w.isAirBlock(pos))
+                        {
+                            pos = pos.add(0, 1, 0);
+                        }
+                        Utils.teleportEntity(affectedEntityPlayerMP, new Location(w, pos));
+                        return true;
+                    }
+                    break;
+                }
+                case "setspawn":
+                {
+                    if(!(cs instanceof EntityPlayerMP))
+                    {
+                        m.send(cs, GlobalText.onlyPlayer());
+                        return true;
+                    }
+                    EntityPlayerMP p = (EntityPlayerMP) cs;
+                    p.getEntityWorld().setSpawnPoint(p.getPosition());
+                    m.send(cs, "Der Spawn der Welt '" + p.getEntityWorld().getWorldInfo().getWorldName() + "' wurde gesetzt.");
+                    return true;
+                }
+                case "list":
+                {
+                    m.send(cs, "Folgende Welten sind geladen:");
+                    Arrays.stream(KajetansMod.server.worlds).forEach((w) -> 
+                    {
+                        m.sendListElement(cs, ModDimensions.getWorldName(w));
+                    });
+                    return true;
+                }
+                case "listall":
+                {
+                    m.send(cs, "Folgende Welten sind verfügbar:");
+                    getAllWorlds().stream().forEach((s) -> 
+                    {
+                        m.sendListElement(cs, s);
+                    });
+                    return true;
+                }
+                case "load":
+                {
+                    if(arg.length >= 2)
+                    {                       
+                        if(!doesWorldExist(arg[1]))
+                        {
+                            m.send(cs, "Die Welt '" + arg[1] + "' wurde nicht gefunden.");
+                            return true;
+                        }
+                        if(ModDimensions.loadWorld(arg[1], ModDimensions.CUSTOM_OVERWORLD))
+                        {
+                            m.send(cs, "'" + arg[1] + "' wurde geladen.");
+                        }
+                        else
+                        {
+                            m.send(cs, "'" + arg[1] + "' ist bereits geladen.");
+                        }
+                        return true;
+                    }
+                    break;
+                }
+                case "unload":
+                {
+                    if(arg.length >= 2)
+                    {                       
+                        if(ModDimensions.unloadWorld(arg[1]))
+                        {
+                            m.send(cs, "'" + arg[1] + "' wurde aus dem Speicher entfernt.");
+                            return true;
+                        }
+                        m.send(cs, "'" + arg[1] + "' kann nicht entfernt werden.");
+                        return true;
+                    }
+                    break;
+                }
+                case "diffi":
+                {
+                    if(arg[0].equals("diffi") && arg.length >= 3)
+                    {
+                        WorldServer w = ModDimensions.getWorldFromName(arg[1]);
+                        if(w == null)
+                        {
+                            m.send(cs, "Die Welt '" + arg[1] + "' wurde nicht gefunden.");
+                            return true;
+                        }
+                        try
+                        {
+                            EnumDifficulty diffi = EnumDifficulty.valueOf(arg[2].toUpperCase());
+                            w.getWorldInfo().setDifficulty(diffi);
+                            m.send(cs, "Schwierigkeit in der Welt '" + arg[1] + "' ist nun '" + Utils.formatString(diffi.name()) + "'.");
+                            return true;
+                        }
+                        catch(IllegalArgumentException ex)
+                        {
+                            m.send(cs, "Diese Schwierigkeitsstufe gibt es nicht.");
+                            return true;
+                        }                                         
+                    }
+                    break;
+                }
+                case "info":
+                {
+                    if(arg.length >= 2)
+                    {
+                        WorldServer w = ModDimensions.getWorldFromName(arg[1]);
+                        if(w == null)
+                        {
+                            m.send(cs, "Die Welt '" + arg[1] + "' wurde nicht gefunden.");
+                            return true;
+                        }                          
+                        m.send(cs, "Infos zur Welt '" + arg[1] + "'");
+                        for(String rule : w.getGameRules().getRules())
+                        {
+                            m.sendListElement(cs, rule + " = " + w.getGameRules().getString(rule));
+                        }                     
+                        m.sendListElement(cs, "Zeit = " + w.getWorldInfo().getWorldTime());
+                        m.sendListElement(cs, "Schwierigkeit = " + Utils.formatString(w.getDifficulty().name()));  
+                        
+                        WorldPreferences wp = KajetansMod.worldManager.getWorldPreferences(w);
+                        
+                        m.sendListElement(cs, "Block-Protection = " + wp.blockProtection);    
+                        m.sendListElement(cs, "Default-Enchanting = " + wp.defaultEnchanting);    
+                        m.sendListElement(cs, "PVP-Protection = " + wp.pvpProtection);    
+                        m.sendListElement(cs, "Skills = " + wp.skills);   
+                        m.sendListElement(cs, "Statuseffekte = " + wp.statusEffects);  
+                        m.sendListElement(cs, "Schriftrollen = " + wp.scrolls);  
+                        m.sendListElement(cs, "Standard-Craften = " + wp.defaultProducing);  
+                        m.sendListElement(cs, "Manabar = " + wp.manabar);  
+                        return true;
+                    }
+                    break;
+                }
+            }
+        }            
+        
+        // Help Menu
+        m.send(cs, "/world ...");
+        m.sendHelpListElement(cs, "info <world>", "Gibt Infos über die Welt");
+        m.sendHelpListElement(cs, "tp <id> [player]", "Bringt den Spieler in eine andere Welt");
+        m.sendHelpListElement(cs, "list", "Zeigt alle geladenen Welten");
+        m.sendHelpListElement(cs, "listall", "Zeigt alle Welten");
+        m.sendHelpListElement(cs, "load <world>", "Lädt eine Welt");
+        m.sendHelpListElement(cs, "unload <world>", "Entfernt die Welt aus dem Speicher");
+        m.sendHelpListElement(cs, "setspawn", "Setzt den Welten-Spawn");
+        m.sendHelpListElement(cs, "diffi <world> <diffi>", "Setzt die Schwierigkeit");
+        return true;
+    }
+}

+ 15 - 0
src/main/java/me/km/dimensions/CustomWorldProviderEnd.java

@@ -0,0 +1,15 @@
+package me.km.dimensions;
+
+import net.minecraft.world.WorldProviderEnd;
+
+public class CustomWorldProviderEnd extends WorldProviderEnd
+{
+    @Override
+    public String getSaveFolder() 
+    {
+        int id = this.getDimension() + 1;
+        id = id % 3;
+        id--;
+        return (id == 0 ? null : "DIM" + id);
+    }
+}

+ 15 - 0
src/main/java/me/km/dimensions/CustomWorldProviderHell.java

@@ -0,0 +1,15 @@
+package me.km.dimensions;
+
+import net.minecraft.world.WorldProviderHell;
+
+public class CustomWorldProviderHell extends WorldProviderHell
+{
+    @Override
+    public String getSaveFolder() 
+    {
+        int id = this.getDimension() + 1;
+        id = id % 3;
+        id--;
+        return (id == 0 ? null : "DIM" + id);
+    }
+}

+ 15 - 0
src/main/java/me/km/dimensions/CustomWorldProviderSurface.java

@@ -0,0 +1,15 @@
+package me.km.dimensions;
+
+import net.minecraft.world.WorldProviderSurface;
+
+public class CustomWorldProviderSurface extends WorldProviderSurface
+{
+    @Override
+    public String getSaveFolder() 
+    {
+        int id = this.getDimension() + 1;
+        id = id % 3;
+        id--;
+        return (id == 0 ? null : "DIM" + id);
+    }
+}

+ 132 - 0
src/main/java/me/km/dimensions/ModDimensions.java

@@ -0,0 +1,132 @@
+package me.km.dimensions;
+
+import java.util.Arrays;
+import java.util.Random;
+import me.km.KajetansMod;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.world.DimensionType;
+import net.minecraft.world.ServerWorldEventHandler;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.WorldSettings;
+import net.minecraft.world.WorldType;
+import net.minecraft.world.storage.ISaveHandler;
+import net.minecraft.world.storage.WorldInfo;
+import net.minecraftforge.common.DimensionManager;
+
+public class ModDimensions 
+{
+    private static int counter = 2;
+    
+    public static final DimensionType CUSTOM_OVERWORLD = DimensionType.register("CUSTOM_OVERWORLD", "_coverworld", 3, CustomWorldProviderSurface.class, false);
+    public static final DimensionType CUSTOM_NETHER = DimensionType.register("CUSTOM_NETHER", "_cnether", 2, CustomWorldProviderHell.class, false);      
+    public static final DimensionType CUSTOM_THE_END = DimensionType.register("CUSTOM_THE_END", "_cend", 4, CustomWorldProviderEnd.class, false);
+
+    public static void init() 
+    {
+        
+    }
+
+    public static String getWorldName(World ws)
+    {
+        int dim = ws.provider.getDimension();
+        switch(dim)
+        {
+            case -1: return DimensionManager.getWorld(-1).getWorldInfo().getWorldName() + "_nether";
+            case 1: return DimensionManager.getWorld(-1).getWorldInfo().getWorldName() + "_end";
+        }
+        return ws.getWorldInfo().getWorldName();
+    }
+    
+    public static WorldServer getWorldFromName(String s)
+    {
+        WorldServer ws = DimensionManager.getWorld(0);
+        String normal = DimensionManager.getWorld(0).getWorldInfo().getWorldName();
+        if(s.equals(normal))
+        {
+            return ws;
+        }
+        else if(s.equals(normal + "_nether"))
+        {
+            return DimensionManager.getWorld(-1);
+        }
+        else if(s.equals(normal + "_end"))
+        {
+            return DimensionManager.getWorld(1);
+        }
+        return Arrays.stream(DimensionManager.getWorlds()).filter(w -> w.getWorldInfo().getWorldName().equals(s)).findAny().orElse(null);
+    }
+    
+    /** Unloads a world by its name.
+     *
+     * @param name the name of the world
+     * @return false, if world does not exist or cannot be unloaded
+     */
+    public static boolean unloadWorld(String name)
+    {
+        WorldServer ws = getWorldFromName(name);
+        if(ws == null)
+        {
+            return false;
+        }
+        int id = ws.provider.getDimension();
+        if(id >= -1 && id <= 1)
+        {
+            return false;
+        }
+        DimensionManager.unregisterDimension(id);
+        DimensionManager.unloadWorld(id);
+        return true;
+    }
+    
+    /** Loads a world by its name.
+     *
+     * @param name the name of the world
+     * @param type a custom dimension type
+     * @return false, if the world is already loaded
+     */
+    public static boolean loadWorld(String name, DimensionType type)
+    {
+        WorldServer ws = getWorldFromName(name);
+        if(ws != null)
+        {
+            return false;
+        }      
+        loadWorld(type, counter, name);
+        counter++;
+        if(counter == Integer.MAX_VALUE)
+        {
+            counter = 2;
+        }
+        return true;
+    }
+    
+    private static void loadWorld(DimensionType type2, int dim, String name)
+    {
+        if(!DimensionManager.isDimensionRegistered(dim))
+        {
+            DimensionManager.registerDimension(dim, type2);
+        }
+        MinecraftServer ms = KajetansMod.server;
+        ISaveHandler isavehandler = ms.getActiveAnvilConverter().getSaveLoader(name, true);
+        WorldInfo worldinfo = isavehandler.loadWorldInfo();
+        WorldSettings worldsettings;
+        if (worldinfo == null)
+        {
+            worldsettings = new WorldSettings((new Random()).nextLong(), ms.getGameType(), ms.canStructuresSpawn(), ms.isHardcore(), WorldType.DEFAULT);
+            worldsettings.setGeneratorOptions("");
+            worldinfo = new WorldInfo(worldsettings, name);
+        }
+        else
+        {
+            worldinfo.setWorldName(name);
+            worldsettings = new WorldSettings(worldinfo);
+        }
+
+        WorldServer overWorld = (WorldServer) new WorldServer(ms, isavehandler, worldinfo, dim, ms.theProfiler).init();
+        overWorld.initialize(worldsettings);
+        overWorld.addEventListener(new ServerWorldEventHandler(ms, overWorld));
+        overWorld.getWorldInfo().setGameType(ms.getGameType());
+        //net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Load(world));
+    }
+}

+ 39 - 0
src/main/java/me/km/dimensions/ModTeleporter.java

@@ -0,0 +1,39 @@
+package me.km.dimensions;
+
+import net.minecraft.entity.Entity;
+import net.minecraft.world.Teleporter;
+import net.minecraft.world.WorldServer;
+
+public class ModTeleporter extends Teleporter
+{
+    private final WorldServer ws;
+ 
+    public ModTeleporter(WorldServer ws) 
+    {
+        super(ws);
+        this.ws = ws;
+    }
+    
+    @Override
+    public void placeInPortal(Entity ent, float rotationYaw)
+    {
+        //Utils.teleportEntity(ent, new Location(ws, ws.getSpawnPoint(), rotationYaw, ent.rotationPitch));
+    }
+
+    @Override
+    public boolean placeInExistingPortal(Entity entityIn, float rotationYaw)
+    {
+        return false;
+    }
+
+    @Override
+    public boolean makePortal(Entity entityIn)
+    {
+        return true;
+    }
+
+    @Override
+    public void removeStalePortalLocations(long worldTime)
+    {       
+    }
+}

+ 29 - 0
src/main/java/me/km/dimensions/WorldData.java

@@ -0,0 +1,29 @@
+package me.km.dimensions;
+
+import me.km.api.Module;
+import java.util.HashMap;
+import net.minecraft.util.text.TextFormatting;
+import net.minecraft.world.World;
+
+public class WorldData extends Module
+{
+    private final HashMap<Integer, WorldPreferences> worlds;
+    
+    public WorldData(String mname, String prefix, TextFormatting color)
+    {
+        super(mname, prefix, color);
+        worlds = new HashMap<>();
+    }
+    
+    public WorldPreferences getWorldPreferences(World w)
+    {
+        WorldPreferences wp = worlds.get(w.getWorldType().getWorldTypeID());
+        if(wp != null)
+        {
+            return wp;
+        }
+        wp = new WorldPreferences();
+        worlds.put(w.getWorldType().getWorldTypeID(), wp);
+        return wp;
+    }
+}

+ 25 - 0
src/main/java/me/km/dimensions/WorldPreferences.java

@@ -0,0 +1,25 @@
+package me.km.dimensions;
+
+public class WorldPreferences 
+{
+    public boolean skills;
+    public boolean defaultProducing;
+    public boolean blockProtection;
+    public boolean defaultEnchanting;
+    public boolean manabar;
+    public boolean statusEffects;
+    public boolean pvpProtection;
+    public boolean scrolls;
+    
+    public WorldPreferences()
+    {
+        skills = false;
+        scrolls = false;
+        blockProtection = true;
+        defaultProducing = true;
+        defaultEnchanting = true;
+        manabar = false;
+        statusEffects = false;
+        pvpProtection = true;
+    }
+}

+ 10 - 1
src/main/java/me/km/permissions/Permissions.java

@@ -2,11 +2,20 @@ package me.km.permissions;
 
 public enum Permissions 
 {
+    // Commands
     TEST, SPAWN, SET_SPAWN, HEAL, SET_BED, TEMP_BAN, TELEPORT, SPAWNER, SUMMON, SKULL,
     SILENT, SIGN, SET_WARP, DEL_WARP, FLY, FLY_OTHER, GAMEMODE, GAMEMODE_OTHER, GOD, MORE,
     LASTSEEN, HOME, HOME_OTHER, DEL_HOME, KILL, KILL_OTHER, HAT, LIST, REPAIR, PVP,
     PVP_OTHER, LIGHTUPDATE, LAG, COORDS, INVSEE, SET_HOME, KICK, ADD_USER, ENDERCHEST,
     EXP, SAY, BAN, BACK, BED, BED_OTHER, POTION, MSG, ANSWER, ITEMINFO, FEED, MEMORY,
     POSITION, SEEN, TIME, TOP, TP_POS, USER, WARP, BOOK, GROW, ENCHANT, SPEED,
-    TELEPORT_ACCEPT, COLOR, USE_COLOR
+    TELEPORT_ACCEPT, 
+    
+    // ChatManager
+    COLOR, USE_COLOR, NICKNAME, FAKERANK, WORLD,
+    
+    // BlockProtections
+    BLOCK_BYPASS, BLOCK, BLOCK_ALL, BLOCK_OTHER, BLOCK_CLEAR
+    
+    // Special
 }

+ 2 - 2
src/main/java/me/km/scheduler/SnuviTask.java

@@ -8,8 +8,8 @@ public class SnuviTask
     
     public SnuviTask(Runnable r, long delay, long rtimer)
     {
-        this.rtimer = rtimer;
-        this.timer = delay;
+        this.rtimer = rtimer << 1; // server ticks seems to be 1/40 of a second
+        this.timer = delay << 1;
         this.r = r;
     }
     

+ 1 - 1
src/main/java/me/km/scheduler/TaskTicker.java

@@ -14,7 +14,7 @@ public class TaskTicker extends ModuleListener
     }
 
     @SubscribeEvent
-    public void tickServer(TickEvent.ServerTickEvent event) 
+    public void tickServer(TickEvent.ServerTickEvent e) 
     {
         KajetansMod.scheduler.tick();
     }

+ 0 - 0
src/main/resources/assets/km/lang/en_us.lang → src/main/resources/assets/km/lang/en_US.lang