Browse Source

Bugfixes, , GuildBlock, Command-Overloader (Vanilla + Worldedit), Honey, Poison, Fluid-Improvements, World-Provider-Registry, improved ReflectionUtils, Custom-Commands for SnuviScript

Kajetan Johannes Hammerle 7 years ago
parent
commit
67c9562128
82 changed files with 2031 additions and 962 deletions
  1. 2 9
      build.gradle
  2. 1 1
      src/main/java/me/km/CommonProxy.java
  3. 119 85
      src/main/java/me/km/KajetansMod.java
  4. 12 3
      src/main/java/me/km/api/CommandOverloader.java
  5. 8 0
      src/main/java/me/km/api/Location.java
  6. 2 0
      src/main/java/me/km/api/Module.java
  7. 20 2
      src/main/java/me/km/api/ModuleCommand.java
  8. 3 2
      src/main/java/me/km/api/ModuleTabCommand.java
  9. 12 0
      src/main/java/me/km/api/SimpleConfig.java
  10. 24 33
      src/main/java/me/km/api/Utils.java
  11. 15 0
      src/main/java/me/km/api/VanillaModuleCommand.java
  12. 49 0
      src/main/java/me/km/api/WorldEditCommand.java
  13. 5 4
      src/main/java/me/km/blockprotections/BlockProtectionBank.java
  14. 46 25
      src/main/java/me/km/blockprotections/CommandBlock.java
  15. 20 0
      src/main/java/me/km/blocks/BlockBase.java
  16. 20 7
      src/main/java/me/km/blocks/ModBlocks.java
  17. 2 1
      src/main/java/me/km/chatmanager/ChatManager.java
  18. 8 6
      src/main/java/me/km/commands/CommandBack.java
  19. 41 25
      src/main/java/me/km/commands/CommandBook.java
  20. 6 4
      src/main/java/me/km/commands/CommandFly.java
  21. 16 16
      src/main/java/me/km/commands/CommandGrow.java
  22. 10 17
      src/main/java/me/km/commands/CommandHome.java
  23. 5 15
      src/main/java/me/km/commands/CommandPotion.java
  24. 3 3
      src/main/java/me/km/commands/CommandSign.java
  25. 5 1
      src/main/java/me/km/commands/CommandSpawn.java
  26. 6 4
      src/main/java/me/km/commands/CommandSpeed.java
  27. 2 2
      src/main/java/me/km/commands/CommandTeleport.java
  28. 23 6
      src/main/java/me/km/commands/CommandTest.java
  29. 14 2
      src/main/java/me/km/commands/CommandWarp.java
  30. 8 4
      src/main/java/me/km/databank/DataBank.java
  31. 3 2
      src/main/java/me/km/datatools/CommandVillager.java
  32. 21 12
      src/main/java/me/km/dimensions/ChangeWorldEvent.java
  33. 3 3
      src/main/java/me/km/dimensions/CommandWorld.java
  34. 0 15
      src/main/java/me/km/dimensions/CustomWorldProviderEnd.java
  35. 0 15
      src/main/java/me/km/dimensions/CustomWorldProviderHell.java
  36. 0 15
      src/main/java/me/km/dimensions/CustomWorldProviderSurface.java
  37. 73 14
      src/main/java/me/km/dimensions/ModDimensions.java
  38. 3 1
      src/main/java/me/km/dimensions/ModTeleporter.java
  39. 12 0
      src/main/java/me/km/dimensions/ModWorldProvider.java
  40. 43 69
      src/main/java/me/km/effects/passive/Mugging.java
  41. 2 1
      src/main/java/me/km/entities/EntityItemProjectile.java
  42. 0 229
      src/main/java/me/km/events/ModDedicatedPlayerList.java
  43. 2 0
      src/main/java/me/km/events/PlayerHurtEvent.java
  44. 2 0
      src/main/java/me/km/events/PlayerJoinMessageEvent.java
  45. 2 0
      src/main/java/me/km/events/PlayerLeaveMessageEvent.java
  46. 66 0
      src/main/java/me/km/events/PlayerRespawnAtEvent.java
  47. 1 1
      src/main/java/me/km/exception/PlayerNotFoundException.java
  48. 188 1
      src/main/java/me/km/fluids/BlockFluidBase.java
  49. 63 0
      src/main/java/me/km/fluids/BlockFluidHoney.java
  50. 64 0
      src/main/java/me/km/fluids/BlockFluidPoison.java
  51. 3 1
      src/main/java/me/km/fluids/ModFluids.java
  52. 108 30
      src/main/java/me/km/inventory/InventoryUtils.java
  53. 18 7
      src/main/java/me/km/nms/NmsUtilities.java
  54. 0 27
      src/main/java/me/km/permissions/PermissionListener.java
  55. 1 1
      src/main/java/me/km/permissions/PermissionManager.java
  56. 3 3
      src/main/java/me/km/permissions/Permissions.java
  57. 342 0
      src/main/java/me/km/playerbank/ModDedicatedPlayerList.java
  58. 98 0
      src/main/java/me/km/playerbank/ModNetHandlerPlayServer.java
  59. 17 4
      src/main/java/me/km/playerbank/PlayerLogInOut.java
  60. 22 12
      src/main/java/me/km/plots/CommandPlot.java
  61. 0 1
      src/main/java/me/km/plots/ProtectionMarkPlot.java
  62. 32 1
      src/main/java/me/km/scheduler/SnuviScheduler.java
  63. 4 4
      src/main/java/me/km/scoreboard/ScoreBoardLeave.java
  64. 3 3
      src/main/java/me/km/scrolls/CommandScroll.java
  65. 1 1
      src/main/java/me/km/skills/SkillManager.java
  66. 28 0
      src/main/java/me/km/snuviscript/ScriptAPI.java
  67. 65 30
      src/main/java/me/km/snuviscript/ScriptEvents.java
  68. 43 83
      src/main/java/me/km/snuviscript/ScriptUtils.java
  69. 0 6
      src/main/java/me/km/snuviscript/ScriptVars.java
  70. 52 46
      src/main/java/me/km/snuviscript/SnuviParser.java
  71. 77 47
      src/main/java/me/km/utils/ReflectionUtils.java
  72. 29 0
      src/main/java/me/km/utils/SpecialBlockUtils.java
  73. 7 0
      src/main/resources/assets/km/blockstates/fluids.json
  74. 5 0
      src/main/resources/assets/km/blockstates/guild_block.json
  75. 4 0
      src/main/resources/assets/km/lang/en_US.lang
  76. 6 0
      src/main/resources/assets/km/models/block/guild_block.json
  77. BIN
      src/main/resources/assets/km/textures/blocks/guild_block.png
  78. BIN
      src/main/resources/assets/km/textures/blocks/honey_flow.png
  79. 3 0
      src/main/resources/assets/km/textures/blocks/honey_flow.png.mcmeta
  80. BIN
      src/main/resources/assets/km/textures/blocks/honey_overlay.png
  81. BIN
      src/main/resources/assets/km/textures/blocks/honey_still.png
  82. 5 0
      src/main/resources/assets/km/textures/blocks/honey_still.png.mcmeta

+ 2 - 9
build.gradle

@@ -5,6 +5,7 @@ buildscript {
     }
     dependencies {
         classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
+        classpath 'mysql:mysql-connector-java:5.1.42'
     }
 }
 apply plugin: 'net.minecraftforge.gradle.forge'
@@ -55,7 +56,7 @@ dependencies {
     // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
     // http://www.gradle.org/docs/current/userguide/dependency_management.html
     
-    compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.42'
+    compile 'mysql:mysql-connector-java:5.1.42'
 }
 
 processResources {
@@ -75,12 +76,4 @@ processResources {
     from(sourceSets.main.resources.srcDirs) {
         exclude 'mcmod.info'
     }
-    
-    //rename '(.+_at.cfg)', 'META-INF/$1'
 }
-/*
-jar {
-    manifest {
-        attributes 'FMLAT': 'km_at.cfg'
-    }
-}*/

+ 1 - 1
src/main/java/me/km/CommonProxy.java

@@ -1,7 +1,7 @@
 package me.km;
 
 import me.km.entities.ModEntities;
-import me.km.events.ModDedicatedPlayerList;
+import me.km.playerbank.ModDedicatedPlayerList;
 import net.minecraft.client.renderer.entity.Render;
 import net.minecraft.entity.Entity;
 import net.minecraft.item.Item;

+ 119 - 85
src/main/java/me/km/KajetansMod.java

@@ -2,7 +2,7 @@ package me.km;
 
 import me.km.api.Module;
 import me.km.api.SimpleConfig;
-import me.km.api.VanillaCommandOverloader;
+import me.km.api.CommandOverloader;
 import me.km.blockprotections.BlockProtectionBank;
 import me.km.blocks.ModBlocks;
 import me.km.chatmanager.ChatManager;
@@ -32,9 +32,7 @@ import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
 import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
 import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent;
 import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
-// event classes
-//import net.minecraftforge.common.ForgeHooks;
-//import net.minecraftforge.event.ForgeEventFactory;
+import net.minecraftforge.fml.common.event.FMLServerStartedEvent;
 
 @Mod(modid = KajetansMod.MODID, version = KajetansMod.VERSION, name = KajetansMod.NAME)
 public class KajetansMod
@@ -66,7 +64,7 @@ public class KajetansMod
 
     public static final String MODID = "km";
     public static final String NAME = "Kajetans Mod";
-    public static final String VERSION = "0.0.1";
+    public static final String VERSION = "0.0.2";
 
     @Mod.Instance(MODID)
     public static KajetansMod instance;
@@ -74,6 +72,7 @@ public class KajetansMod
     public static MinecraftServer server;
     
     public static boolean debugMode;
+    public static boolean singlePlayer;
 
     @Mod.EventHandler
     public void preInit(FMLPreInitializationEvent event) 
@@ -92,9 +91,14 @@ public class KajetansMod
         proxy.overloadPlayerList(server);
     }
     
+    private FMLServerStartingEvent event;
+    
     @Mod.EventHandler
     public void serverStarting(FMLServerStartingEvent e) 
     {
+        singlePlayer = e.getServer().isSinglePlayer();
+        // Workaround
+        event = e;
         // Konfiguration und Error-Dummy
         error = new Module("ERROR", "ERROR", TextFormatting.RED);
         conf = new SimpleConfig(error, "config", true);
@@ -112,105 +116,135 @@ public class KajetansMod
             System.out.println("------------------------------------------------");
         }
         
-        // Datenbankverbindung
-        databank = new DataBank("DataBank", "DataBank", TextFormatting.RED);
-        if(!databank.openDataBankConnection(conf.getString("user", "root"), conf.getString("password", "")))
+        if(!singlePlayer)
         {
-            return;
+            // Datenbankverbindung
+            databank = new DataBank("DataBank", "DataBank", TextFormatting.RED, conf.getString("user", "root"), conf.getString("password", ""));
+            if(!databank.openDataBankConnection())
+            {
+                return;
+            }
         }
         
         // Scheduler
         scheduler = new SnuviScheduler("Scheduler", "Scheduler", TextFormatting.GREEN);
         scheduler.registerEvents("me.km.scheduler");
-                
-        // Spielerdatenbank
-        playerbank = new PlayerManager("PlayerBank", "PlayerBank", TextFormatting.RED);
-        playerbank.setDataBank(new PlayerBank(playerbank, databank.getConnection()));
-        playerbank.registerEvents("me.km.playerbank");
+
+        if(!singlePlayer)
+        {
+            // Spielerdatenbank
+            playerbank = new PlayerManager("PlayerBank", "PlayerBank", TextFormatting.RED);
+            playerbank.setDataBank(new PlayerBank(playerbank, databank.getConnection()));
+            playerbank.registerEvents("me.km.playerbank");
+        }
         
         // Grundlegende Commands
         generalCommands = new Module("GeneralCommands", "Commands", TextFormatting.GOLD);
         generalCommands.registerCommands(e, "me.km.commands");
-        VanillaCommandOverloader.overloadVanillaCommands(e, generalCommands);
-        
-        // Chatmanager
-        chatManager = new ChatManager("ChatManager", "Chat", TextFormatting.BLUE);
-        chatManager.registerCommands(e, "me.km.chatmanager");
-        chatManager.registerEvents("me.km.chatmanager");
-        
-        // AFK-Manager
-        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);
-        plots.setDataBank(new ProtectionBank(plots, databank.getConnection()));
-        plots.registerCommands(e, "me.km.plots");          
-        plots.registerEvents("me.km.plots");
-        
-        // Chests- und Co-Protections
-        blocks = new Module("BlockProtections", "Blocks", TextFormatting.BLUE);
-        blocks.setDataBank(new BlockProtectionBank(blocks, databank.getConnection()));
-        blocks.registerCommands(e, "me.km.blockprotections");          
-        blocks.registerEvents("me.km.blockprotections");
-        
-        // 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);
-        worldManager.registerCommands(e, "me.km.dimensions");          
-        worldManager.registerEvents("me.km.dimensions");
-        
-        // Scriptsystem
-        scripts = new ScriptAPI("Quests", "Quests", TextFormatting.LIGHT_PURPLE);
-        scripts.registerPrefix("Scripts", TextFormatting.LIGHT_PURPLE);
-        scripts.setDataBank(new ScriptBank(scripts, databank.getConnection()));
-        scripts.registerCommands(e, "me.km.snuviscript");          
-        scripts.registerEvents("me.km.snuviscript");
-        
-        // Jobsystem
-        jobs = new JobAPI("JobSystem", "Jobs", TextFormatting.GREEN);
-        // databank is initialized in JobAPI in order to have a reference
-        jobs.registerCommands(e, "me.km.jobsystem");      
-        jobs.registerEvents("me.km.jobsystem"); 
-        
-        // Effectsystem
-        effects = new EffectUtils("Effects", "Effects", TextFormatting.BLUE);
-        effects.registerCommands(e, "me.km.effects"); 
-        effects.registerEvents("me.km.effects.passive"); 
-        
-        // Skills
-        skills = new SkillManager("SkillSystem", "Skills", TextFormatting.BLUE);
-        skills.registerCommands(e, "me.km.skills"); 
-        skills.registerEvents("me.km.skills");
-        
-        // Scrollsystem
-        scrolls = new Module("Scrolls", "Scrolls", TextFormatting.BLUE);
-        scrolls.registerCommands(e, "me.km.scrolls"); 
-        
-        // Environment
-        environment = new Module("Environment", "Environment", TextFormatting.GREEN);
-        environment.registerCommands(e, "me.km.environment");      
-        environment.registerEvents("me.km.environment");
-        
-        // Scoreboard
-        scoreboard = new ScoreboardAPI("Scoreboard", "Scoreboard", TextFormatting.GOLD);
-        scoreboard.registerEvents("me.km.scoreboard");
         
+        if(!singlePlayer)
+        {     
+            // Chatmanager
+            chatManager = new ChatManager("ChatManager", "Chat", TextFormatting.BLUE);
+            chatManager.registerCommands(e, "me.km.chatmanager");
+            chatManager.registerEvents("me.km.chatmanager");
+
+            // AFK-Manager
+            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);
+            plots.setDataBank(new ProtectionBank(plots, databank.getConnection()));
+            plots.registerCommands(e, "me.km.plots");          
+            plots.registerEvents("me.km.plots");
+
+            // Chests- und Co-Protections
+            blocks = new Module("BlockProtections", "Blocks", TextFormatting.BLUE);
+            blocks.setDataBank(new BlockProtectionBank(blocks, databank.getConnection()));
+            blocks.registerCommands(e, "me.km.blockprotections");          
+            blocks.registerEvents("me.km.blockprotections");
+
+            // 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);
+            worldManager.registerCommands(e, "me.km.dimensions");          
+            worldManager.registerEvents("me.km.dimensions");
+
+            // Scriptsystem
+            scripts = new ScriptAPI("Scripts", "Quests", TextFormatting.LIGHT_PURPLE);
+            scripts.registerPrefix("Scripts", TextFormatting.LIGHT_PURPLE);
+            scripts.setDataBank(new ScriptBank(scripts, databank.getConnection()));
+            scripts.registerCommands(e, "me.km.snuviscript");          
+            scripts.registerEvents("me.km.snuviscript");
+
+            // Jobsystem
+            jobs = new JobAPI("JobSystem", "Jobs", TextFormatting.GREEN);
+            // databank is initialized in JobAPI in order to have a reference
+            jobs.registerCommands(e, "me.km.jobsystem");      
+            jobs.registerEvents("me.km.jobsystem"); 
+
+            // Effectsystem
+            effects = new EffectUtils("Effects", "Effects", TextFormatting.BLUE);
+            effects.registerCommands(e, "me.km.effects"); 
+            effects.registerEvents("me.km.effects.passive"); 
+
+            // Skills
+            skills = new SkillManager("SkillSystem", "Skills", TextFormatting.BLUE);
+            skills.registerCommands(e, "me.km.skills"); 
+            skills.registerEvents("me.km.skills");
+
+            // Scrollsystem
+            scrolls = new Module("Scrolls", "Scrolls", TextFormatting.BLUE);
+            scrolls.registerCommands(e, "me.km.scrolls"); 
+
+            // Environment
+            environment = new Module("Environment", "Environment", TextFormatting.GREEN);
+            environment.registerCommands(e, "me.km.environment");      
+            environment.registerEvents("me.km.environment");
+
+            // Scoreboard
+            scoreboard = new ScoreboardAPI("Scoreboard", "Scoreboard", TextFormatting.GOLD);
+            scoreboard.registerEvents("me.km.scoreboard");
+        }
         // Permissions
         perms = new PermissionManager("Permissions", "Perms", TextFormatting.DARK_PURPLE);
         perms.registerEvents("me.km.permissions");
 
+        if(singlePlayer)
+        {
+            return;
+        }       
         scripts.startScript(server, "startscript");
     }
     
     @Mod.EventHandler
-    public void serverStarting(FMLServerStoppingEvent e) 
+    public void overwriteCommandsOnFullStart(FMLServerStartedEvent e) 
     {
+        if(singlePlayer)
+        {
+            return;
+        }
+        // Workaround
+        KajetansMod.scheduler.scheduleTask(() -> 
+        {
+            CommandOverloader.overloadCommands(event, generalCommands);
+            event = null;
+        }, 60);
+    }
+    
+    @Mod.EventHandler
+    public void onServerStop(FMLServerStoppingEvent e) 
+    {
+        if(singlePlayer)
+        {
+            return;
+        }
         databank.closeDataBankConnection();
     }
 
@@ -226,7 +260,7 @@ public class KajetansMod
     {
         ModItems.lateInit();
     }
-    
+
     /*public static void main(String[] args)
     {
         // Erstellt alle Enums für die aktiven Effekte

+ 12 - 3
src/main/java/me/km/api/VanillaCommandOverloader.java → src/main/java/me/km/api/CommandOverloader.java

@@ -4,9 +4,9 @@ import me.km.KajetansMod;
 import me.km.permissions.Permissions;
 import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
 
-public class VanillaCommandOverloader 
+public class CommandOverloader 
 {
-    public static void overloadVanillaCommands(FMLServerStartingEvent e, Module m)
+    public static void overloadCommands(FMLServerStartingEvent e, Module m)
     {
         KajetansMod.server.commandManager.getCommands().values().stream()
                 // Overload only vanilla commands
@@ -18,7 +18,16 @@ public class VanillaCommandOverloader
             Permissions perm;
             try
             {
-                perm = Permissions.valueOf(command.getName());
+                if(command.getClass().getName().startsWith("com.sk89q."))
+                {
+                    m.registerCommand(e, new WorldEditCommand(command, m));
+                    m.sendToConsole(command.getName() + " wurde überschrieben.");
+                    return;
+                }
+                else
+                {
+                    perm = Permissions.valueOf(command.getName());
+                }
             }
             catch(IllegalArgumentException ex)
             {

+ 8 - 0
src/main/java/me/km/api/Location.java

@@ -1,6 +1,7 @@
 package me.km.api;
 
 import java.util.Objects;
+import me.km.dimensions.ModDimensions;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.entity.Entity;
 import net.minecraft.util.math.BlockPos;
@@ -115,4 +116,11 @@ public class Location
     {
         return w.getBlockState(pos.add(x, y, z));
     }
+
+    @Override
+    public String toString() 
+    {
+        return ModDimensions.getWorldName(w) + ":" + pos.xCoord + ":" + pos.yCoord + 
+                ":" + pos.zCoord + ":" + yaw + ":" + pitch;
+    }
 }

+ 2 - 0
src/main/java/me/km/api/Module.java

@@ -113,6 +113,8 @@ public class Module extends MessageSender
             }
             catch(NoSuchMethodException | ClassCastException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex)
             {
+                this.sendToConsole("Fehler bei " + c);
+                this.sendToConsole(ex.toString());
             }
         });
         this.sendToConsole("Alle Events wurden geladen.");

+ 20 - 2
src/main/java/me/km/api/ModuleCommand.java

@@ -3,12 +3,14 @@ package me.km.api;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import javax.annotation.Nullable;
 import me.km.KajetansMod;
 import me.km.permissions.Permissions;
 import net.minecraft.command.CommandBase;
 import net.minecraft.command.CommandException;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.BlockPos;
 
 public abstract class ModuleCommand extends CommandBase
 {   
@@ -90,9 +92,19 @@ public abstract class ModuleCommand extends CommandBase
     @Override
     public void execute(MinecraftServer server, ICommandSender cs, String[] args) throws CommandException
     {   
-        if(!execute(cs, args))
+        try
         {
-            m.send(cs, this.getUsage(cs));
+            if(!execute(cs, args))
+            {
+                m.send(cs, this.getUsage(cs));
+            }
+        }
+        catch(Exception ex)
+        {
+            if(KajetansMod.singlePlayer)
+            {
+                m.send(cs, "Dieser Command sollte nicht im SinglePlayer benutzt werden.");
+            }
         }
     }
 
@@ -101,4 +113,10 @@ public abstract class ModuleCommand extends CommandBase
     {
         return KajetansMod.perms.has(cs, perm);
     }
+    
+    @Override
+    public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, @Nullable BlockPos targetPos)
+    {
+        return getListOfStringsMatchingLastWord(args, server.getOnlinePlayerNames());
+    }
 }

+ 3 - 2
src/main/java/me/km/api/ModuleTabCommand.java

@@ -1,6 +1,5 @@
 package me.km.api;
 
-import java.util.Collections;
 import java.util.List;
 import net.minecraft.command.CommandBase;
 import net.minecraft.command.ICommandSender;
@@ -22,6 +21,8 @@ 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) : 
+                super.getTabCompletions(server, sender, args, targetPos);
     }
 }

+ 12 - 0
src/main/java/me/km/api/SimpleConfig.java

@@ -50,6 +50,9 @@ public class SimpleConfig
                 m.sendWarningToConsole("File '" + file.getPath() + "' cannot be read");
             }
         }
+        
+        //System.out.println("WUSI");
+        //conf.forEach((k, v) -> System.out.println(k + " " + v));
     }
     
     public static File[] getFiles(String path)
@@ -71,6 +74,14 @@ public class SimpleConfig
     {
         try
         {
+            if(!file.getParentFile().exists())
+            {
+                file.getParentFile().mkdirs();
+            }
+            if(!file.exists())
+            {
+                file.createNewFile();
+            }
             Files.write(Paths.get(file.toURI()), conf.entrySet().stream()
                             .map(e -> e.getKey() + "=" + e.getValue())
                             .collect(Collectors.toList()), Charset.forName("UTF-8"));
@@ -79,6 +90,7 @@ public class SimpleConfig
         catch(IOException ex)
         {
             m.sendWarningToConsole("Can't write to '" + file.getPath() + "'");
+            ex.printStackTrace();
             return false;
         }
     }

+ 24 - 33
src/main/java/me/km/api/Utils.java

@@ -31,7 +31,6 @@ import net.minecraft.entity.projectile.EntityThrowable;
 import net.minecraft.init.Blocks;
 import net.minecraft.init.Enchantments;
 import net.minecraft.init.Items;
-import net.minecraft.init.MobEffects;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemAxe;
 import net.minecraft.item.ItemHoe;
@@ -45,11 +44,13 @@ import net.minecraft.item.ItemStack;
 import net.minecraft.item.ItemSword; 
 import net.minecraft.nbt.NBTTagCompound;
 import net.minecraft.nbt.NBTUtil;
-import net.minecraft.potion.Potion;
 import net.minecraft.tileentity.TileEntitySkull;
 import net.minecraft.util.DamageSource;
 import net.minecraft.util.math.RayTraceResult;
+import net.minecraft.util.text.ITextComponent;
 import net.minecraft.world.WorldServer;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.entity.EntityTravelToDimensionEvent;
 
 public class Utils 
 {    
@@ -107,7 +108,7 @@ public class Utils
     
     public static boolean hasPlayedBefore(EntityPlayer p)
     {
-        return new File("./saves/world/playerdata/" + p.getUniqueID() + ".dat").exists();
+        return new File("./world/playerdata/" + p.getUniqueID() + ".dat").exists();
     }
     
     public static <T extends Comparable<T>> T getStateValue(IBlockState state, IProperty<T> property)
@@ -122,22 +123,6 @@ public class Utils
         }
     }
     
-    // -------------------------------------------------------------------------
-    // Potions
-    // -------------------------------------------------------------------------
-    
-    public static Potion getPotion(String name)
-    {
-        try
-        {
-            return (Potion) MobEffects.class.getField(name).get(null);
-        }
-        catch(NoSuchFieldException | SecurityException | IllegalAccessException | IllegalArgumentException ex)
-        {
-            return null;
-        }
-    }
-    
     // -------------------------------------------------------------------------
     // Befehle für Werkzeuge
     // -------------------------------------------------------------------------
@@ -404,12 +389,13 @@ public class Utils
     {
         Vec3d pos = l.getPos();
 
+        int dim = l.getWorld().provider.getDimension();
         if(ent instanceof EntityPlayerMP)
         {
             EntityPlayerMP p = (EntityPlayerMP) ent;
-            if(ent.dimension != l.getWorld().provider.getDimension())
+            KajetansMod.playerbank.saveLocation(p);
+            if(ent.dimension != dim)
             {
-                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)
@@ -423,9 +409,9 @@ public class Utils
         }
         else
         {
-            if(ent.dimension != l.getWorld().provider.getDimension())
+            if(ent.dimension != dim)
             {
-                WorldServer n = KajetansMod.server.worldServerForDimension(l.getWorld().provider.getDimension());
+                WorldServer n = KajetansMod.server.worldServerForDimension(dim);
                 KajetansMod.server.getPlayerList().transferEntityToWorld(ent, ent.dimension, KajetansMod.server.worldServerForDimension(ent.dimension), n, new ModTeleporter(n));
             }
             if(l.getYaw() != 0 && l.getPitch() != 0)
@@ -441,7 +427,7 @@ public class Utils
     
     public static void teleportEntity(Entity ent, Entity ent2)
     {
-        teleportEntity(ent, new Location(ent2.world, ent.getPositionVector(), ent2.rotationYaw, ent2.rotationPitch));
+        teleportEntity(ent, new Location(ent2.world, ent2.getPositionVector(), ent2.rotationYaw, ent2.rotationPitch));
     }
     
     // -------------------------------------------------------------------------
@@ -563,7 +549,7 @@ public class Utils
         return w.getPlayers(EntityPlayer.class, p -> true).stream().min((p1, p2) -> Double.compare(p1.getDistanceSq(v.xCoord, v.yCoord, v.zCoord), p2.getDistanceSq(v.xCoord, v.yCoord, v.zCoord))).orElse(null);
     }
     
-    public static BlockPos getPlayerTarget(EntityPlayer p, double range)
+    public static BlockPos getPlayerTarget(EntityPlayer p, double range, boolean boundingBox)
     {
         if(range > 64)
         {
@@ -572,7 +558,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, true, false);
+        RayTraceResult ray = w.rayTraceBlocks(start, end, true, !boundingBox, false);
         if(ray == null)
         {
             return new BlockPos(end);
@@ -580,6 +566,11 @@ public class Utils
         return ray.getBlockPos();   
     }
     
+    public static BlockPos getPlayerTarget(EntityPlayer p, double range)
+    {
+        return getPlayerTarget(p, range, false);  
+    }
+    
     public static BlockPos getPlayerTarget(EntityPlayer p)
     {
         return getPlayerTarget(p, 20);
@@ -592,11 +583,12 @@ public class Utils
                     .findFirst().orElseThrow(() -> new PlayerNotFoundException(name));
     }
     
-    public static EntityPlayerMP getPlayerByDisplayName(String name) throws PlayerNotFoundException
+    public static EntityPlayerMP getPlayerByDisplayName(ITextComponent name) throws PlayerNotFoundException
     {
+        String s = name.getUnformattedText();
         return KajetansMod.server.getPlayerList().getPlayers().stream()
-                    .filter(pl -> pl.getDisplayNameString().contains(name))
-                    .findFirst().orElseThrow(() -> new PlayerNotFoundException(name));
+                    .filter(pl -> pl.getDisplayName().getUnformattedText().equals(s))
+                    .findFirst().orElseThrow(() -> new PlayerNotFoundException(s));
     }
         
     // -------------------------------------------------------------------------
@@ -626,7 +618,7 @@ public class Utils
         SimpleConfig conf = new SimpleConfig(m, "warp/" + name, true);
         if(conf.exists())
         {
-            return conf.getLocation("loc");
+            return conf.getLocation("warp");
         }
         return null;
     }
@@ -658,12 +650,11 @@ public class Utils
        
     public static boolean shouldBeProtected(Block b)
     {
-        return b instanceof BlockDoor || 
-               !(b instanceof BlockPistonMoving) ||
+        return (b instanceof BlockDoor || 
                b instanceof BlockContainer ||
                b == Blocks.LEVER || 
                b instanceof BlockButton || 
-               b instanceof BlockTrapDoor;   
+               b instanceof BlockTrapDoor) && !(b instanceof BlockPistonMoving);   
     }
     
     // -------------------------------------------------------------------------

+ 15 - 0
src/main/java/me/km/api/VanillaModuleCommand.java

@@ -1,10 +1,13 @@
 package me.km.api;
 
+import java.util.List;
 import me.km.KajetansMod;
 import me.km.permissions.Permissions;
 import net.minecraft.command.CommandException;
 import net.minecraft.command.ICommand;
 import net.minecraft.command.ICommandSender;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.text.TextComponentTranslation;
 import net.minecraft.util.text.TextFormatting;
 
@@ -37,4 +40,16 @@ public class VanillaModuleCommand extends ModuleCommand
         }
         return true;
     }
+
+    @Override
+    public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) 
+    {
+        return vanillaCommand.getTabCompletions(server, sender, args, targetPos);
+    }
+
+    @Override
+    public List<String> getAliases() 
+    {
+        return vanillaCommand.getAliases();
+    }
 }

+ 49 - 0
src/main/java/me/km/api/WorldEditCommand.java

@@ -0,0 +1,49 @@
+package me.km.api;
+
+import java.util.List;
+import me.km.KajetansMod;
+import me.km.permissions.Permissions;
+import net.minecraft.command.ICommand;
+import net.minecraft.command.ICommandSender;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.BlockPos;
+
+public class WorldEditCommand extends ModuleCommand
+{
+    private final ICommand command;
+    
+    public WorldEditCommand(ICommand command, Module m) 
+    {
+        super(command.getName(), m);
+        super.setDescription("A worldedit command");
+        super.setUsage(command.getUsage(null));
+        super.setPermission(Permissions.WORLDEDIT);
+        this.command = command;
+    }
+
+    @Override
+    public boolean execute(ICommandSender cs, String[] arg) 
+    {
+        try
+        {
+            command.execute(KajetansMod.server, cs, arg);
+        }
+        catch(Exception ex)
+        {
+            this.getModule().send(cs, "WorldEdit-Error");
+        }
+        return true;
+    }
+
+    @Override
+    public List<String> getTabCompletions(MinecraftServer server, ICommandSender sender, String[] args, BlockPos targetPos) 
+    {
+        return command.getTabCompletions(server, sender, args, targetPos);
+    }
+    
+    @Override
+    public List<String> getAliases() 
+    {
+        return command.getAliases();
+    }
+}

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

@@ -240,19 +240,20 @@ public class BlockProtectionBank extends SimpleDataBank
         });
     }
     
-    public List<Location> getAll()
+    public List<BlockPos> getAllFromWorld(World w)
     {
-        return this.get("Select x,y,z,world_name from block;").stream().map(li -> 
+        String name = ModDimensions.getWorldName(w);
+        return this.get("Select x,y,z,world_name from block WHERE world_name='" + name + "';").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)));
+                return new BlockPos((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());
+        }).collect(Collectors.toList());
     }
     
     private String makeStringSafe(String s)

+ 46 - 25
src/main/java/me/km/blockprotections/CommandBlock.java

@@ -1,12 +1,15 @@
 package me.km.blockprotections;
 
 import com.mojang.authlib.GameProfile;
+import java.util.ArrayList;
+import java.util.List;
 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 me.km.scheduler.SnuviScheduler;
 import net.minecraft.block.Block;
 import net.minecraft.block.BlockDoor;
 import net.minecraft.block.state.IBlockState;
@@ -19,10 +22,11 @@ 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;
+    private int counter;
+    private int index;
+    private List<BlockPos> locs;
+    private final ArrayList<Block> blocks;
+    private boolean checker;
     
     public CommandBlock(Module m) 
     {
@@ -35,8 +39,8 @@ public class CommandBlock extends ModuleCommand
         super.addAlias("protect");
         
         bank = KajetansMod.blocks.getDataBank(BlockProtectionBank.class);
-        //locs = new ArrayList<>();
-        //blocks = new ArrayList<>();
+        locs = new ArrayList<>();
+        blocks = new ArrayList<>();
     }
     
     @Override
@@ -190,17 +194,18 @@ public class CommandBlock extends ModuleCommand
                 {
                     if(KajetansMod.perms.has(cs, Permissions.BLOCK_CLEAR))
                     {
-                        //TODO
-                        this.getModule().send(cs, GlobalText.notImplementedYet());
-                        /*checker = false;
-                        Bukkit.getScheduler().runTaskAsynchronously(this.getModule().getPlugin(), () -> 
+                        checker = false;
+                        SnuviScheduler.scheduleAsyncTask(() -> 
                         {
+                            this.getModule().send(cs, "Blöcke aus Datenbank abrufen ...");
                             counter = 0;
-                            locs = bank.getAll();
+                            locs = bank.getAllFromWorld(w);
                             checker = true;
+                            this.getModule().send(cs, "Fertig ...");
                         });
-                        Bukkit.getScheduler().scheduleSyncDelayedTask(this.getModule().getPlugin(), () -> 
+                        SnuviScheduler.scheduleAsyncTask(() -> 
                         {
+                            this.getModule().send(cs, "Schedule: Blöcke aus Welt abrufen ...");
                             if(!checker)
                             {
                                 this.getModule().send(cs, "Das Abrufen aller Einträge hat zu lange gedauert.");
@@ -208,31 +213,47 @@ public class CommandBlock extends ModuleCommand
                                 blocks.clear();
                                 return;
                             }
-                            locs.stream().forEach((l) -> 
+                            for(int i = 0; i < locs.size(); i+=50)
                             {
-                                Bukkit.getScheduler().scheduleSyncDelayedTask(this.getModule().getPlugin(), () -> 
+                                final int end = i + 50;
+                                KajetansMod.scheduler.scheduleTask(() -> 
                                 {
-                                    try
+                                    this.getModule().send(cs, "Blöcke aus Welt abrufen " + (end / 50));
+                                    for(int j = end - 50; j < locs.size() && j < end; j++)
                                     {
-                                        blocks.add(l.getBlock().getState());
+                                        try
+                                        {
+                                            blocks.add(w.getBlockState(locs.get(j)).getBlock());
+                                        }
+                                        catch(NullPointerException ex)
+                                        {
+                                            blocks.add(null);
+                                        }
                                     }
-                                    catch(NullPointerException ex)
-                                    {
-                                    }
-                                });
-                            });
+                                    this.getModule().send(cs, "Fertig ...");
+                                }, 0);
+                            }
+                            this.getModule().send(cs, "Fertig ...");
                         }, 200);
-                        Bukkit.getScheduler().runTaskLaterAsynchronously(this.getModule().getPlugin(), () -> 
+                        SnuviScheduler.scheduleAsyncTask(() -> 
                         {
-                            blocks.stream().filter(bl -> !Utils.shouldBeProtected(bl)).forEach(bl -> 
+                            this.getModule().send(cs, "Ungültige Entfernen ...");
+                            index = 0;
+                            blocks.stream().forEach(bl -> 
                             {
-                                bank.removeBlock(bl.getLocation(), p);
+                                if(Utils.shouldBeProtected(bl))
+                                {
+                                    index++;
+                                    return;
+                                }
+                                bank.removeBlock(locs.get(index), w, p);
+                                index++;
                                 counter++;
                             });
                             this.getModule().send(cs, "Alle ungültigen Protections wurden entfernt. (" + counter + ")");
                             locs.clear();
                             blocks.clear();
-                        }, 400);*/
+                        }, 400);
                         return true;
                     }
                     break;

+ 20 - 0
src/main/java/me/km/blocks/BlockBase.java

@@ -3,12 +3,17 @@ package me.km.blocks;
 import me.km.KajetansMod;
 import net.minecraft.block.*;
 import net.minecraft.block.material.Material;
+import net.minecraft.block.state.IBlockState;
 import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.entity.Entity;
 import net.minecraft.item.ItemBlock;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
 
 public class BlockBase extends Block 
 {
     protected String name;
+    private SoundType type;
 
     public BlockBase(Material material, String name, String local) 
     {
@@ -16,6 +21,8 @@ public class BlockBase extends Block
         this.name = name;
         this.setRegistryName(name);
         super.setUnlocalizedName(local);
+        super.setCreativeTab(CreativeTabs.BUILDING_BLOCKS);
+        this.type = super.getSoundType();
     }
 
     public void registerItemModel(ItemBlock itemBlock) 
@@ -29,4 +36,17 @@ public class BlockBase extends Block
         super.setCreativeTab(tab);
         return this;
     }
+
+    @Override
+    public BlockBase setSoundType(SoundType sound) 
+    {
+        this.type = sound;
+        return this;
+    }
+
+    @Override
+    public SoundType getSoundType(IBlockState state, World world, BlockPos pos, Entity entity) 
+    {
+        return type;
+    }
 }

+ 20 - 7
src/main/java/me/km/blocks/ModBlocks.java

@@ -1,11 +1,12 @@
 package me.km.blocks;
 
 import me.km.fluids.BlockFluidBase;
+import me.km.fluids.BlockFluidHoney;
+import me.km.fluids.BlockFluidPoison;
 import me.km.fluids.ModFluids;
 import net.minecraft.block.Block;
 import net.minecraft.block.material.Material;
 import net.minecraft.item.ItemBlock;
-import net.minecraftforge.fluids.BlockFluidClassic;
 import net.minecraftforge.fml.common.registry.GameRegistry;
 
 public class ModBlocks 
@@ -13,25 +14,37 @@ public class ModBlocks
     public static BlockBase copperOre;
     public static BlockBase copperBlock;
     
-    public static BlockFluidClassic poison;
+    public static BlockBase guildblock;
+    
+    public static BlockFluidPoison poison;
+    public static BlockFluidHoney honey;
     
     public static void init() 
     {
-        copperOre = register((BlockBase) new BlockBase(Material.ROCK, "copper_ore", "oreCopper").setHardness(3.0F).setResistance(5.0F));
-        copperOre = register((BlockBase) new BlockBase(Material.IRON, "copper_block", "blockCopper").setHardness(4.0F).setResistance(10.0F));
+        copperOre = register((BlockBase) new BlockBase(Material.ROCK, "copper_ore", "oreCopper")
+                .setHardness(3.0F)
+                .setResistance(5.0F));
+        copperOre = register((BlockBase) new BlockBase(Material.IRON, "copper_block", "blockCopper")
+                .setHardness(4.0F)
+                .setResistance(10.0F));
+        
+        guildblock = register((BlockBase) new BlockBase(Material.IRON, "guild_block", "blockGuild")
+                .setHardness(50.0F)
+                .setResistance(2000.0F));
     
-        poison = register(new BlockFluidBase(ModFluids.poison, Material.WATER));
+        poison = register(new BlockFluidPoison(ModFluids.poison, Material.WATER));
+        honey = register(new BlockFluidHoney(ModFluids.honey, Material.WATER));
     }
 
     private static <T extends Block> T register(T block, ItemBlock itemBlock) 
     {
         GameRegistry.register(block);
         GameRegistry.register(itemBlock);
-        if (block instanceof BlockBase) 
+        if(block instanceof BlockBase) 
         {
             ((BlockBase) block).registerItemModel(itemBlock);
         }
-        if (block instanceof BlockFluidBase) 
+        if(block instanceof BlockFluidBase) 
         {
             ((BlockFluidBase) block).registerBlockModel();
         }

+ 2 - 1
src/main/java/me/km/chatmanager/ChatManager.java

@@ -61,6 +61,7 @@ public class ChatManager extends Module
         if(set == null)
         {
             set = new HashSet<>();
+            playerRanks.put(uuid, set);
         }
         set.add(rank);
     }
@@ -82,7 +83,7 @@ public class ChatManager extends Module
                         {
                             if(pRanks.contains(r.getName()))
                             {
-                                return r.getName();
+                                return r.getText();
                             }
                         }
                         return null;

+ 8 - 6
src/main/java/me/km/commands/CommandBack.java

@@ -1,10 +1,14 @@
 package me.km.commands;
 
+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.permissions.Permissions;
 import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.player.EntityPlayer;
 
 public class CommandBack extends ModuleCommand
 {
@@ -19,21 +23,19 @@ public class CommandBack extends ModuleCommand
     @Override
     public boolean execute(ICommandSender cs, String[] arg) 
     {
-        this.getModule().send(cs, GlobalText.notImplementedYet());
-        /*if(!(cs instanceof EntityPlayer))
+        if(!(cs instanceof EntityPlayer))
         {
             this.getModule().send(cs, GlobalText.onlyPlayer());
             return true;
         }
         EntityPlayer p = (EntityPlayer) cs;    
-        Location l = KajetansTools.playerbank.getEvent(TeleportEvent.class).getLastLocation(p);
+        Location l = KajetansMod.playerbank.getLastLocation(p);
         if(l != null)
         {
-            p.getWorld().loadChunk(l.getBlockX(), l.getBlockZ());
-            p.teleport(l);
+            Utils.teleportEntity(p, 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;
     }
 }

+ 41 - 25
src/main/java/me/km/commands/CommandBook.java

@@ -3,11 +3,14 @@ package me.km.commands;
 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.permissions.Permissions;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.init.Items;
 import net.minecraft.item.ItemStack;
+import net.minecraft.nbt.NBTTagCompound;
 
 public class CommandBook extends ModuleCommand
 {
@@ -38,34 +41,47 @@ public class CommandBook extends ModuleCommand
                 m.send(cs, "Du hast kein signiertes Buch in der Hand.");
                 return true;
             }
-            m.send(cs, GlobalText.notImplementedYet());
-            // TODO
-            /*BookMeta bmeta = (BookMeta) stack.getItemMeta();
-            
-            switch(arg[0])
+            NBTTagCompound com = stack.getTagCompound();
+            if(com == null)
             {
-                case "open":
+                m.send(cs, GlobalText.shouldNotHappen());
+                return true;
+            }
+            try
+            {
+                switch(arg[0])
                 {
-                    ItemStack newItem = new ItemStack(Material.BOOK_AND_QUILL, stack.getAmount());
-                    newItem.setItemMeta(bmeta);
-                    p.getInventory().setItemInMainHand(newItem);
-                    return true;
-                }
-                case "author":
-                {       
-                    bmeta.setAuthor(ChatManager.colorMessage(Utils.connectSpaces(arg, 1), p));
-                    p.getInventory().getItemInMainHand().setItemMeta(bmeta);
-                    p.updateInventory();
-                    return true;
+                    case "open":
+                    {
+                        ItemStack newItem = new ItemStack(Items.WRITABLE_BOOK);
+                        NBTTagCompound pages = newItem.getTagCompound();
+                        if(pages == null)
+                        {
+                            pages = new NBTTagCompound();
+                        }
+                        pages.setTag("pages", com.getTagList("pages", 8).copy());
+                        newItem.setTagCompound(pages);
+                        p.entityDropItem(newItem, 0);
+                        return true;
+                    }
+                    case "author":
+                    {       
+                        com.setString("author", ChatManager.colorMessage(Utils.connectSpaces(arg, 1), p));
+                        m.send(cs, "Der neue Autor wurde gesetzt.");
+                        return true;
+                    }
+                    case "title":
+                    {       
+                        com.setString("title", ChatManager.colorMessage(Utils.connectSpaces(arg, 1), p));
+                        m.send(cs, "Der neue Autor wurde gesetzt.");
+                        return true;
+                    }
                 }
-                case "title":
-                {       
-                    bmeta.setTitle(ChatManager.colorMessage(Utils.connectSpaces(arg, 1), p));
-                    p.getInventory().getItemInMainHand().setItemMeta(bmeta);
-                    p.updateInventory();
-                    return true;
-                }
-            }*/
+            }
+            catch(Exception ex)
+            {
+                m.send(cs, "Unerwarteter Fehler: " + ex + " - " + ex.getMessage());
+            }
         }
         
         m.send(cs, "/book ...");

+ 6 - 4
src/main/java/me/km/commands/CommandFly.java

@@ -8,7 +8,7 @@ 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;
+import net.minecraft.entity.player.EntityPlayerMP;
 
 public class CommandFly extends ModuleCommand
 {
@@ -23,7 +23,7 @@ public class CommandFly extends ModuleCommand
     @Override
     public boolean execute(ICommandSender cs, String[] arg) 
     {
-        EntityPlayer affectedPlayer;
+        EntityPlayerMP affectedPlayer;
         try
         {
             if(arg.length >= 1 && !KajetansMod.perms.has(cs, Permissions.FLY_OTHER))
@@ -40,12 +40,12 @@ public class CommandFly extends ModuleCommand
         }
         catch(IndexOutOfBoundsException ex)
         {
-            if(!(cs instanceof EntityPlayer))
+            if(!(cs instanceof EntityPlayerMP))
             {
                 this.getModule().send(cs, GlobalText.missingParameter());
                 return true;
             }     
-            affectedPlayer = (EntityPlayer) cs;
+            affectedPlayer = (EntityPlayerMP) cs;
         }
 
         boolean fly = !affectedPlayer.capabilities.allowFlying;
@@ -62,6 +62,8 @@ public class CommandFly extends ModuleCommand
         }
 
         affectedPlayer.capabilities.allowFlying = fly;
+        affectedPlayer.capabilities.isFlying = fly;
+        affectedPlayer.sendPlayerAbilities();
         if(fly)
         {
             this.getModule().send(affectedPlayer, "Du kannst nun fliegen.");

+ 16 - 16
src/main/java/me/km/commands/CommandGrow.java

@@ -1,11 +1,16 @@
 package me.km.commands;
 
 import me.km.api.GlobalText;
+import me.km.api.Location;
 import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.permissions.Permissions;
+import net.minecraft.block.BlockCrops;
+import net.minecraft.block.state.IBlockState;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
 
 public class CommandGrow extends ModuleCommand
 {
@@ -25,32 +30,27 @@ public class CommandGrow extends ModuleCommand
             this.getModule().send(cs, GlobalText.onlyPlayer());
             return true;
         }
-        // TODO
-        /*Block l = ((EntityPlayer) cs).getLocation().getBlock();
-        Block b;
+        EntityPlayer p = (EntityPlayer) cs;
+        World w = p.world;
+        BlockPos pos = p.getPosition();
+        BlockPos relative;
+        IBlockState state;
         for(int x = -3; x < 4; x++)
         {
             for(int y = -3; y < 4; y++)
             {
                 for(int z = -3; z < 4; z++)
                 {
-                    b = l.getRelative(x, y, z);
-                    if(!(b.getState().getData() instanceof Crops))
+                    relative = pos.add(x, y, z);
+                    state = w.getBlockState(relative);
+                    if(state.getBlock() instanceof BlockCrops)
                     {
-                        continue;                  
-                    }
-                    if(((Crops) b.getState().getData()).getState() != CropState.RIPE)
-                    {
-                        BlockState state = b.getState();
-                        Crops crop = ((Crops) state.getData());
-                        crop.setState(CropState.RIPE);
-                        state.setData(crop);
-                        state.update();
-                    }                        
+                        w.setBlockState(relative, state.withProperty(BlockCrops.AGE, 7));                
+                    }                      
                 }
             }
         }
-        this.getModule().send(cs, "Die Pflanzen in deiner Umgebung sind gewachsen.");*/
+        this.getModule().send(cs, "Die Pflanzen in deiner Umgebung sind gewachsen.");
         return true;
     }
 }

+ 10 - 17
src/main/java/me/km/commands/CommandHome.java

@@ -58,7 +58,7 @@ public class CommandHome extends ModuleCommand
 
         Module m = this.getModule();
         File[] homes = SimpleConfig.getFiles("home/" + playeruuid);
-        if(homes.length == 0)
+        if(homes == null || homes.length == 0)
         {
             String name = KajetansMod.playerbank.getDataBank().getName(playeruuid);
             if(name.equals(p.getName()))
@@ -76,27 +76,20 @@ public class CommandHome extends ModuleCommand
             return true;
         }
                   
-        try
+        SimpleConfig sc = new SimpleConfig(this.getModule(), "home/" + playeruuid + "/" + homename, true);
+        Location l = sc.getLocation("home");
+        if(l == null)
         {
-            SimpleConfig sc = new SimpleConfig(this.getModule(), "home/" + playeruuid + "/" + homename, true);
-            Location l = sc.getLocation("home");
-            if(l.getWorld() == null)
-            {
-                throw new NullPointerException();
-            }    
-            Utils.teleportEntity(p, l);
-            m.send(cs, "Du wurdest zum Home-Punkt " + homename + " teleportiert.");
-        }
-        catch(IllegalArgumentException ex)
-        {
-            m.send(cs, "Der Homepunkt wurde nicht gefunden.");    
+            m.send(cs, "Der Homepunkt wurde nicht gefunden.");   
             return true;
-        }
-        catch(NullPointerException ex)
+        }   
+        if(l.getWorld() == null)
         {
             m.send(cs, "Die Welt des Homepunktes wurde nicht gefunden.");    
             return true;
-        }            
+        }    
+        Utils.teleportEntity(p, l);
+        m.send(cs, "Du wurdest zum Home-Punkt " + homename + " teleportiert.");  
         return true;
     }
 }

+ 5 - 15
src/main/java/me/km/commands/CommandPotion.java

@@ -3,15 +3,14 @@ package me.km.commands;
 import java.util.ArrayList;
 import me.km.api.GlobalText;
 import me.km.api.Module;
-import java.util.Arrays;
+import java.util.stream.Collectors;
 import me.km.api.ModuleTabCommand;
-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.Items;
 import net.minecraft.item.ItemStack;
-import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.potion.Potion;
 import net.minecraft.potion.PotionEffect;
 import net.minecraft.potion.PotionUtils;
 
@@ -19,14 +18,7 @@ public class CommandPotion extends ModuleTabCommand
 {
     public CommandPotion(Module m) 
     {
-        super("potion", m, Arrays.asList(new String[]
-        {
-            "SPEED", "SLOWNESS", "HASTE", "MINING_FATIGUE", "STRENGTH", "INSTANT_HEALTH",
-            "INSTANT_DAMAGE", "JUMP_BOOST", "NAUSEA", "REGENERATION", "RESISTANCE",
-            "FIRE_RESISTANCE", "WATER_BREATHING", "INVISIBILITY", "BLINDNESS",
-            "NIGHT_VISION", "HUNGER", "WEAKNESS" ,"POISON", "WITHER", "HEALTH_BOOST",
-            "ABSORPTION", "SATURATION", "GLOWING", "LEVITATION", "LUCK", "UNLUCK"
-        }), 0);  
+        super("potion", m, Potion.REGISTRY.getKeys().stream().map(r -> r.getResourcePath()).collect(Collectors.toList()), 0); 
         super.setDescription("Erzeugt Custom-Potions");
         super.setUsage("/potion [effect] [duration] [amplifier]");
         super.setPermission(Permissions.POTION);
@@ -56,11 +48,9 @@ public class CommandPotion extends ModuleTabCommand
 
         try
         {
-            NBTTagCompound com = hand.getTagCompound();
             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);
+            list.add(new PotionEffect(Potion.getPotionFromResourceLocation(arg[0]), Integer.parseInt(arg[1]), Integer.parseInt(arg[2])));
+            PotionUtils.appendEffects(hand, list);
             this.getModule().send(cs, "Der Effekt wurde hinzugefügt.");
         }
         catch(NumberFormatException ex)

+ 3 - 3
src/main/java/me/km/commands/CommandSign.java

@@ -6,13 +6,13 @@ import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.chatmanager.ChatManager;
 import me.km.permissions.Permissions;
+import me.km.utils.SpecialBlockUtils;
 import net.minecraft.block.Block;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.init.Blocks;
 import net.minecraft.tileentity.TileEntitySign;
 import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.text.TextComponentString;
 import net.minecraft.world.World;
 
 public class CommandSign extends ModuleCommand
@@ -39,7 +39,7 @@ public class CommandSign extends ModuleCommand
         }
         EntityPlayer p = (EntityPlayer) cs;
         World w = p.getEntityWorld();
-        BlockPos pos = Utils.getPlayerTarget(p);
+        BlockPos pos = Utils.getPlayerTarget(p, 20, true);
         Block b = w.getBlockState(pos).getBlock();
         if(b == Blocks.STANDING_SIGN || b == Blocks.WALL_SIGN)
         {
@@ -67,7 +67,7 @@ public class CommandSign extends ModuleCommand
 
             String newText = Utils.connectSpaces(arg, 1); 
             newText = ChatManager.colorMessage(newText, p);    
-            sign.signText[line] = new TextComponentString(newText);
+            SpecialBlockUtils.setSignLine(sign, line, newText);
             return true;
         } 
         this.getModule().send(cs, "Du bist nicht auf ein Schild gerichtet.");          

+ 5 - 1
src/main/java/me/km/commands/CommandSpawn.java

@@ -46,10 +46,14 @@ public class CommandSpawn extends ModuleCommand
             this.getModule().send(affectedPlayer, "Du wurdest zum Spawn teleportiert.");
         }
         Location l = Utils.getSpawn();
-        if(l.getWorld() == null)
+        if(l == null)
         {
             this.getModule().send(affectedPlayer, "Es wurde kein Spawn gesetzt.");
         }
+        else if(l.getWorld() == null)
+        {
+            this.getModule().send(affectedPlayer, "Die Welt des Spawns existiert nicht.");
+        }
         Utils.teleportEntity(affectedPlayer, l);
         return true;
     }

+ 6 - 4
src/main/java/me/km/commands/CommandSpeed.java

@@ -6,6 +6,7 @@ import me.km.api.Module;
 import me.km.api.ModuleCommand;
 import me.km.exception.PlayerNotFoundException;
 import me.km.permissions.Permissions;
+import me.km.utils.ReflectionUtils;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
 
@@ -51,8 +52,8 @@ public class CommandSpeed extends ModuleCommand
         try
         {
             affectedPlayer = Utils.getPlayerByName(arg[1]);  
-            affectedPlayer.capabilities.setFlySpeed(f);
-            affectedPlayer.capabilities.setPlayerWalkSpeed(f * 2);
+            ReflectionUtils.setFlySpeed(affectedPlayer.capabilities, f);
+            ReflectionUtils.setWalkSpeed(affectedPlayer.capabilities, f * 2);
             this.getModule().send(affectedPlayer, "Du hast nun Tempo " + i + ".");
             this.getModule().send(cs, affectedPlayer.getName() + " hat nun Tempo " + i + ".");
         }
@@ -69,10 +70,11 @@ public class CommandSpeed extends ModuleCommand
                 return true;
             }     
             affectedPlayer = (EntityPlayer) cs;
-            affectedPlayer.capabilities.setFlySpeed(f);
-            affectedPlayer.capabilities.setPlayerWalkSpeed(f * 2);
+            ReflectionUtils.setFlySpeed(affectedPlayer.capabilities, f);
+            ReflectionUtils.setWalkSpeed(affectedPlayer.capabilities, f * 2);
             this.getModule().send(affectedPlayer, "Du hast nun Tempo " + i + ".");
         } 
+        affectedPlayer.sendPlayerAbilities();
         return true;
     }
 }

+ 2 - 2
src/main/java/me/km/commands/CommandTeleport.java

@@ -13,11 +13,11 @@ public class CommandTeleport extends ModuleCommand
 {
     public CommandTeleport(Module m) 
     {
-        super("teleport", m);
+        super("tp", m);
         super.setDescription("Teleportiert einen Spieler zu einem anderen");
         super.setUsage("/tp [player] <to-player>");
         super.setPermission(Permissions.TELEPORT);
-        super.addAlias("tp");
+        super.addAlias("teleport");
     }
 
     @Override

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

@@ -1,13 +1,16 @@
 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.effects.EffectUtils;
-import me.km.entities.EntityItemProjectile;
+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;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.play.server.SPacketRespawn;
+import net.minecraft.world.WorldServer;
 
 public class CommandTest extends ModuleCommand
 {
@@ -22,13 +25,27 @@ public class CommandTest extends ModuleCommand
     @Override
     public boolean execute(ICommandSender cs, String[] arg) 
     {
-        if(!(cs instanceof EntityPlayer))
+        /*if(!(cs instanceof EntityPlayer))
         {
             this.getModule().send(cs, GlobalText.onlyPlayer());
             return true;
+        }*/
+        if(arg.length < 1)
+        {
+            return true;
+        }
+        EntityPlayerMP p;
+        try
+        {
+            p = Utils.getPlayerByName(arg[0]);    
+        }
+        catch(PlayerNotFoundException ex)
+        {
+            this.getModule().send(cs, GlobalText.cantFindPlayer(arg[0]));
+            return true;
         }
-        EntityPlayer p = (EntityPlayer) cs;
-        EffectUtils.launchProjectile(p, EntityItemProjectile.class, 1, p.getHeldItemMainhand().copy());
+        WorldServer w = p.getServerWorld();
+        KajetansMod.server.getPlayerList().updateTimeAndWeatherForPlayer(p, w);
         return true;
     }
 }

+ 14 - 2
src/main/java/me/km/commands/CommandWarp.java

@@ -1,5 +1,7 @@
 package me.km.commands;
 
+import java.io.File;
+import java.util.ArrayList;
 import java.util.Arrays;
 import me.km.api.GlobalText;
 import me.km.api.Module;
@@ -28,7 +30,12 @@ public class CommandWarp extends ModuleCommand
 
     public List<String> getWarps()
     {
-        return Arrays.stream(SimpleConfig.getFiles("warp")).map(w -> w.getName().substring(0, w.getName().length() - 6)).collect(Collectors.toList());
+        File[] files = SimpleConfig.getFiles("warp");
+        if(files == null)
+        {
+            return new ArrayList<>();
+        }
+        return Arrays.stream(files).map(w -> w.getName().substring(0, w.getName().length() - 6)).collect(Collectors.toList());
     }
     
     @Override
@@ -44,7 +51,12 @@ public class CommandWarp extends ModuleCommand
         Location l = Utils.getWarp(this.getModule(), arg[0]);
         if(l == null)
         {
-            this.getModule().send(cs, "Der Warp existiert nicht bzw. seine Welt.");
+            this.getModule().send(cs, "Der Warp existiert nicht.");
+            return true;
+        }
+        else if(l.getWorld() == null)
+        {
+            this.getModule().send(cs, "Die Welt des Warps existiert nicht.");
             return true;
         }
         

+ 8 - 4
src/main/java/me/km/databank/DataBank.java

@@ -9,13 +9,17 @@ import net.minecraft.util.text.TextFormatting;
 public class DataBank extends Module
 {
     private Connection c;
+    private final String user;
+    private final String password;
     
-    public DataBank(String mname, String prefix, TextFormatting color) 
+    public DataBank(String mname, String prefix, TextFormatting color, String user, String password) 
     {
         super(mname, prefix, color);
+        this.user = user;
+        this.password = password;
     }
     
-    public boolean openDataBankConnection(String user, String password)
+    public boolean openDataBankConnection()
     {
         c = null;
         try 
@@ -26,9 +30,9 @@ public class DataBank extends Module
             this.sendToConsole("Die Verbindung wurde erfolgreich aufgebaut.");
             return true;
         } 
-        catch(SQLException | ClassNotFoundException | InstantiationException | IllegalAccessException ex) 
+        catch(ClassNotFoundException | IllegalAccessException | InstantiationException | SQLException ex) 
         {
-            this.sendWarningToConsole(ex.getMessage());
+            this.sendWarningToConsole(ex.toString());
             return false;
         }
     }

+ 3 - 2
src/main/java/me/km/datatools/CommandVillager.java

@@ -11,6 +11,7 @@ import me.km.permissions.Permissions;
 import me.km.inventory.EntityInventory;
 import me.km.inventory.InventoryUtils;
 import net.minecraft.command.ICommandSender;
+import net.minecraft.entity.SharedMonsterAttributes;
 import net.minecraft.entity.passive.EntityVillager;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.server.MinecraftServer;
@@ -114,7 +115,7 @@ public class CommandVillager extends ModuleCommand
                             World w = p.getEntityWorld();
                             EntityVillager v = new EntityVillager(w, Integer.parseInt(arg[1]));
                             v.setPosition(p.posX, p.posY, p.posZ);       
-                            v.setAIMoveSpeed(0);
+                            v.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0);
                             w.spawnEntity(v);
                             return true;
                         }
@@ -137,7 +138,7 @@ public class CommandVillager extends ModuleCommand
                             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);
+                            v.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0);
                             w.spawnEntity(v);
                             return true;
                         }

+ 21 - 12
src/main/java/me/km/dimensions/ChangeWorldEvent.java

@@ -5,7 +5,6 @@ import me.km.api.Location;
 import me.km.api.Module;
 import me.km.api.ModuleListener;
 import me.km.api.SimpleConfig;
-import me.km.api.Utils;
 import me.km.utils.ReflectionUtils;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.inventory.InventoryEnderChest;
@@ -13,8 +12,9 @@ import net.minecraft.item.ItemStack;
 import net.minecraft.util.FoodStats;
 import net.minecraft.util.NonNullList;
 import net.minecraftforge.common.DimensionManager;
+import net.minecraftforge.event.world.WorldEvent;
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import net.minecraftforge.event.entity.EntityTravelToDimensionEvent;
+import net.minecraftforge.fml.common.gameevent.PlayerEvent;
 
 public class ChangeWorldEvent extends ModuleListener 
 {
@@ -24,19 +24,28 @@ public class ChangeWorldEvent extends ModuleListener
     }
 
     @SubscribeEvent
-    public void changeWorldEvent(EntityTravelToDimensionEvent e)
-    { 
-        if(!(e.getEntity() instanceof EntityPlayer))
+    public void onWorldUnload(WorldEvent.Unload e)
+    {
+        // doing this should be safe here
+        int i = e.getWorld().provider.getDimension();
+        if(i >= -1 && i <= 1)
         {
             return;
         }
-        EntityPlayer p = (EntityPlayer) e.getEntity();
-        int first = p.dimension;
-        int second = e.getDimension();
-        if(first >= 2 || second >= 2)
+        if(DimensionManager.isDimensionRegistered(i))
+        {
+            DimensionManager.unregisterDimension(i); 
+            ModDimensions.LOADED_DIMS.remove(i);
+        }
+    }
+
+    @SubscribeEvent
+    public void changeWorldEvent(PlayerEvent.PlayerChangedDimensionEvent e)
+    { 
+        if(e.fromDim >= 2 || e.toDim >= 2)
         {
-            savePlayerInventory(p, first);
-            loadPlayerInventory(p, second);
+            savePlayerInventory(e.player, e.fromDim);
+            loadPlayerInventory(e.player, e.toDim);
         }
     }   
     
@@ -144,7 +153,7 @@ public class ChangeWorldEvent extends ModuleListener
         p.setHealth(sp.getFloat("currenthealth", 20));    
 
         // position in world
-        Utils.teleportEntity(p, sp.getLocation("location"));
+        //Utils.teleportEntity(p, sp.getLocation("location"));      
         
         // main inventory
         int counter;

+ 3 - 3
src/main/java/me/km/dimensions/CommandWorld.java

@@ -29,12 +29,12 @@ public class CommandWorld extends ModuleCommand
 
     private boolean doesWorldExist(String name)
     {
-        return new File("./saves/" + name).isDirectory();       
+        return new File("./" + name).isDirectory();       
     }  
     
     private ArrayList<String> getAllWorlds()
     {
-        File worlds = new File("./saves/"); 
+        File worlds = new File("./"); 
         ArrayList<String> list = new ArrayList<>();
         for(File f : worlds.listFiles())
         {
@@ -136,7 +136,7 @@ public class CommandWorld extends ModuleCommand
                             m.send(cs, "Die Welt '" + arg[1] + "' wurde nicht gefunden.");
                             return true;
                         }
-                        if(ModDimensions.loadWorld(arg[1], ModDimensions.CUSTOM_OVERWORLD))
+                        if(ModDimensions.loadWorld(arg[1], ModDimensions.CUSTOM_WORLD))
                         {
                             m.send(cs, "'" + arg[1] + "' wurde geladen.");
                         }

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

@@ -1,15 +0,0 @@
-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);
-    }
-}

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

@@ -1,15 +0,0 @@
-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);
-    }
-}

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

@@ -1,15 +0,0 @@
-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);
-    }
-}

+ 73 - 14
src/main/java/me/km/dimensions/ModDimensions.java

@@ -2,7 +2,9 @@ package me.km.dimensions;
 
 import java.util.Arrays;
 import java.util.Random;
+import java.util.TreeSet;
 import me.km.KajetansMod;
+import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.server.MinecraftServer;
 import net.minecraft.world.DimensionType;
 import net.minecraft.world.ServerWorldEventHandler;
@@ -13,22 +15,45 @@ import net.minecraft.world.WorldType;
 import net.minecraft.world.storage.ISaveHandler;
 import net.minecraft.world.storage.WorldInfo;
 import net.minecraftforge.common.DimensionManager;
+import net.minecraftforge.common.network.ForgeMessage.DimensionRegisterMessage;
+import net.minecraftforge.fml.common.network.FMLEmbeddedChannel;
+import net.minecraftforge.fml.common.network.FMLOutboundHandler;
+import net.minecraftforge.fml.common.network.NetworkRegistry;
+import net.minecraftforge.fml.relauncher.Side;
 
 public class ModDimensions 
 {
-    private static int counter = 2;
+    public static final TreeSet<Integer> LOADED_DIMS = new TreeSet<>();
     
-    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 final DimensionType CUSTOM_WORLD = DimensionType.register("CUSTOM_WORLD", "_coverworld", 3, ModWorldProvider.class, false);
 
     public static String getWorldName(World ws)
     {
+        if(ws == null)
+        {
+            return "null";
+        }
         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";
+            case -1: 
+            {
+                World w = DimensionManager.getWorld(-1);
+                if(w == null)
+                {
+                    return "null_nether";
+                }
+                return w.getWorldInfo().getWorldName() + "_nether";
+            }
+            case 1: 
+            {
+                World w = DimensionManager.getWorld(1);
+                if(w == null)
+                {
+                    return "null_end";
+                }
+                return w.getWorldInfo().getWorldName() + "_end";
+            }
         }
         return ws.getWorldInfo().getWorldName();
     }
@@ -36,7 +61,7 @@ public class ModDimensions
     public static WorldServer getWorldFromName(String s)
     {
         WorldServer ws = DimensionManager.getWorld(0);
-        String normal = DimensionManager.getWorld(0).getWorldInfo().getWorldName();
+        String normal = ws.getWorldInfo().getWorldName();
         if(s.equals(normal))
         {
             return ws;
@@ -69,8 +94,9 @@ public class ModDimensions
         {
             return false;
         }
-        DimensionManager.unregisterDimension(id);
         DimensionManager.unloadWorld(id);
+        // doing this on World.Unload Event, otherwise server crashes because unloadWorld is delayed
+        // DimensionManager.unregisterDimension(id); 
         return true;
     }
     
@@ -87,20 +113,28 @@ public class ModDimensions
         {
             return false;
         }      
-        loadWorld(type, counter, name);
-        counter++;
-        if(counter == Integer.MAX_VALUE)
+        int i = 10;
+        for(int dim : LOADED_DIMS)
         {
-            counter = 2;
+            if(dim == i)
+            {
+                i++;
+            }
+            else if(dim > i)
+            {
+                break;
+            }
         }
+        loadWorld(type, i, name);
+        LOADED_DIMS.add(i);
         return true;
     }
     
-    private static void loadWorld(DimensionType type2, int dim, String name)
+    private static void loadWorld(DimensionType type, int dim, String name)
     {
         if(!DimensionManager.isDimensionRegistered(dim))
         {
-            DimensionManager.registerDimension(dim, type2);
+            DimensionManager.registerDimension(dim, type);
         }
         MinecraftServer ms = KajetansMod.server;
         ISaveHandler isavehandler = ms.getActiveAnvilConverter().getSaveLoader(name, true);
@@ -123,5 +157,30 @@ public class ModDimensions
         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));
+        
+        // Copied from com.forgeessentials.multiworld.MultiworldManager; Thank you guys.
+        // Tell everyone about the new dim
+        sendNotificationForDimension(dim);
+    }
+    
+    private static void sendNotificationForDimension(int dim)
+    {
+        FMLEmbeddedChannel channel = NetworkRegistry.INSTANCE.getChannel("FORGE", Side.SERVER);
+        DimensionRegisterMessage msg = new DimensionRegisterMessage(dim, "OVERWORLD");
+        channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.ALL);
+        channel.writeOutbound(msg);
+    }
+    
+    // used on player connection in ModDedicatedPlayerList
+    public static void sendNotificationsForDimensions(EntityPlayerMP p)
+    {
+        FMLEmbeddedChannel channel = NetworkRegistry.INSTANCE.getChannel("FORGE", Side.SERVER);
+        LOADED_DIMS.forEach(i -> 
+        {
+            DimensionRegisterMessage msg = new DimensionRegisterMessage(i, "OVERWORLD");
+            channel.attr(FMLOutboundHandler.FML_MESSAGETARGET).set(FMLOutboundHandler.OutboundTarget.PLAYER);
+            channel.attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(p);
+            channel.writeOutbound(msg);
+        });
     }
 }

+ 3 - 1
src/main/java/me/km/dimensions/ModTeleporter.java

@@ -17,7 +17,9 @@ public class ModTeleporter extends Teleporter
     @Override
     public void placeInPortal(Entity ent, float rotationYaw)
     {
-        //Utils.teleportEntity(ent, new Location(ws, ws.getSpawnPoint(), rotationYaw, ent.rotationPitch));
+        ent.motionX = 0.0d;
+        ent.motionY = 0.0d;
+        ent.motionZ = 0.0d;
     }
 
     @Override

+ 12 - 0
src/main/java/me/km/dimensions/ModWorldProvider.java

@@ -0,0 +1,12 @@
+package me.km.dimensions;
+
+import net.minecraft.world.WorldProviderSurface;
+
+public class ModWorldProvider extends WorldProviderSurface
+{
+    @Override
+    public String getSaveFolder() 
+    {
+        return null;
+    }
+}

+ 43 - 69
src/main/java/me/km/effects/passive/Mugging.java

@@ -1,5 +1,7 @@
 package me.km.effects.passive;
 
+import java.util.ArrayList;
+import java.util.stream.Collectors;
 import me.km.KajetansMod;
 import me.km.api.Module;
 import me.km.api.ModuleListener;
@@ -10,9 +12,15 @@ import me.km.inventory.InventoryUtils;
 import me.km.items.ItemDagger;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.monster.EntityMob;
+import net.minecraft.entity.passive.EntityVillager;
 import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Items;
 import net.minecraft.init.MobEffects;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.DamageSource;
 import net.minecraft.util.EnumHand;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.village.MerchantRecipeList;
 import net.minecraftforge.event.entity.player.PlayerInteractEvent;
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 
@@ -26,7 +34,7 @@ public class Mugging extends ModuleListener
     @SubscribeEvent(receiveCanceled = false)
     public void mugging(PlayerInteractEvent.EntityInteract e)
     {
-        /*if(e.getHand() == EnumHand.OFF_HAND || !KajetansMod.worldManager.getWorldPreferences(e.getWorld()).skills)
+        if(e.getHand() == EnumHand.OFF_HAND || !KajetansMod.worldManager.getWorldPreferences(e.getWorld()).skills)
         {
             return;
         }
@@ -44,7 +52,7 @@ public class Mugging extends ModuleListener
         Entity ent = e.getTarget();          
         if(ent instanceof EntityMob)
         {
-            if(InventoryUtils.getFirstEmptySlot(p.inventory) == -1)
+            if(InventoryUtils.getFirstEmptyStack(p.inventory) == -1)
             {
                 this.getModule().send(p, "Dein Inventar ist zu voll für einen Diebstahl.");
                 return;
@@ -57,96 +65,62 @@ public class Mugging extends ModuleListener
                 {
                     m.setAttackTarget(p);
                 }
-                //CustomItemUtils.lowerDurability(p, 15);
+                p.getHeldItemMainhand().damageItem(15, p);
                 return;
             }
-            ArrayList<Integer> loot = new ArrayList<>();
-            EntityEquipment equ = m.getEquipment();
-            if(equ.getHelmet().getType() != Material.AIR)
+            boolean b = true;
+            for(ItemStack stack : m.getArmorInventoryList())
             {
-                loot.add(0);
-            }
-            if(equ.getChestplate().getType() != Material.AIR)
-            {
-                loot.add(1);
-            }
-            if(equ.getLeggings().getType() != Material.AIR)
-            {
-                loot.add(2);
+                if(!stack.isEmpty())
+                {
+                    b = false;
+                    if(Utils.randomInt(1, 5) <= mugging)
+                    {
+                        m.entityDropItem(stack, 0);
+                    }
+                }
             }
-            if(equ.getBoots().getType() != Material.AIR)
-            {
-                loot.add(3);
-            }   
-            if(equ.getItemInMainHand().getType() != Material.AIR)
-            {
-                loot.add(4);
-            } 
-            if(equ.getItemInOffHand().getType() != Material.AIR)
-            {
-                loot.add(5);
-            } 
-            
-            if(loot.isEmpty())
+            if(b)
             {
                 this.getModule().send(p, "Hier gibt es nichts zum stehlen.");
                 return;
             }
-            
-            switch(loot.get(Utils.randomInt(0, loot.size() - 1)))
-            {
-                case 0:
-                    p.getInventory().addItem(equ.getHelmet());
-                    equ.setHelmet(new ItemStack(Material.AIR));
-                    break;
-                case 1:
-                    p.getInventory().addItem(equ.getChestplate());
-                    equ.setChestplate(new ItemStack(Material.AIR));
-                    break;
-                case 2:
-                    p.getInventory().addItem(equ.getLeggings());
-                    equ.setLeggings(new ItemStack(Material.AIR));
-                    break;
-                case 3:
-                    p.getInventory().addItem(equ.getBoots());
-                    equ.setBoots(new ItemStack(Material.AIR));
-                    break;
-                case 4:
-                    p.getInventory().addItem(equ.getItemInMainHand());
-                    equ.setItemInMainHand(new ItemStack(Material.AIR));
-                    break;
-                case 5:
-                    p.getInventory().addItem(equ.getItemInOffHand());
-                    equ.setItemInOffHand(new ItemStack(Material.AIR));
-                    break;
-            }
             this.getModule().send(p, "Der Diebstahl war erfolgreich.");
         }      
-        else if(ent instanceof Villager)
+        else if(ent instanceof EntityVillager)
         {           
-            if(p.getInventory().firstEmpty() == -1)
+            if(InventoryUtils.getFirstEmptyStack(p.inventory) == -1)
             {
                 this.getModule().send(p, "Dein Inventar ist zu voll für einen Diebstahl.");
                 return;
             }
-            Villager v = (Villager) ent;
+            EntityVillager v = (EntityVillager) ent;
             if(mugging < Utils.randomInt(1, 5))
             {
                 this.getModule().send(p, "Der Diebstahl hat fehlgeschlagen.");
-                Utils.damageItemInHand(p, 15);
-                if(!p.hasPotionEffect(PotionEffectType.INVISIBILITY))
+                p.getHeldItemMainhand().damageItem(15, p);
+                if(!p.isPotionActive(MobEffects.INVISIBILITY))
                 {
-                    p.sendMessage("§7[§c" + v.getName() + "§7] §rWas machst du da?");
-                    p.damage(Utils.randomInt(6, 12), v);
+                    p.sendMessage(new TextComponentString("§7[§c" + v.getName() + "§7] §rWas machst du da?"));
+                    p.attackEntityFrom(DamageSource.causeMobDamage(v), Utils.randomInt(6, 12));
                     return;
                 }
-                p.sendMessage("§7[§c" + v.getName() + "§7] §rHuch, was war das?");
+                p.sendMessage(new TextComponentString("§7[§c" + v.getName() + "§7] §rHuch, was war das?"));
                 return;
             }
-            ArrayList<ItemStack> loot = new ArrayList<>(v.getRecipes().stream().map(r -> r.getResult()).collect(Collectors.toList()));
-            loot.add(new ItemStack(Material.BREAD));
-            p.getInventory().addItem(loot.get(Utils.randomInt(0, loot.size() - 1)));
+            MerchantRecipeList list = v.getRecipes(p);
+            ArrayList<ItemStack> loot;
+            if(list != null)
+            {
+                loot = new ArrayList<>(list.stream().map(r -> r.getItemToBuy()).collect(Collectors.toList()));
+            }
+            else
+            {
+                loot = new ArrayList<>();
+            }
+            loot.add(new ItemStack(Items.BREAD));
+            v.entityDropItem(loot.get(Utils.randomInt(0, loot.size() - 1)).copy(), 0);
             this.getModule().send(p, "Der Diebstahl war erfolgreich.");
-        } */
+        }
     }
 }

+ 2 - 1
src/main/java/me/km/entities/EntityItemProjectile.java

@@ -3,6 +3,7 @@ package me.km.entities;
 import java.util.List;
 import me.km.KajetansMod;
 import me.km.snuviscript.ScriptEvents;
+import me.km.utils.ReflectionUtils;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityLivingBase;
 import net.minecraft.entity.IProjectile;
@@ -142,7 +143,7 @@ public class EntityItemProjectile extends EntityItem implements IProjectile
             Vec3d newV = new Vec3d(newX, newY, newZ);
             list.removeIf(ent -> 
             {
-                if(ent == thrower && this.getAge() < 5)
+                if(ent == thrower && ReflectionUtils.getAge(this) < 5)
                 {
                     return true;
                 }

+ 0 - 229
src/main/java/me/km/events/ModDedicatedPlayerList.java

@@ -1,229 +0,0 @@
-package me.km.events;
-
-import com.mojang.authlib.GameProfile;
-import io.netty.buffer.Unpooled;
-import java.util.UUID;
-import me.km.KajetansMod;
-import me.km.api.GlobalText;
-import me.km.api.Utils;
-import net.minecraft.entity.Entity;
-import net.minecraft.entity.player.EntityPlayer;
-import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.nbt.NBTTagCompound;
-import net.minecraft.network.NetHandlerPlayServer;
-import net.minecraft.network.NetworkManager;
-import net.minecraft.network.PacketBuffer;
-import net.minecraft.network.play.server.SPacketCustomPayload;
-import net.minecraft.network.play.server.SPacketEntityEffect;
-import net.minecraft.network.play.server.SPacketHeldItemChange;
-import net.minecraft.network.play.server.SPacketJoinGame;
-import net.minecraft.network.play.server.SPacketPlayerAbilities;
-import net.minecraft.network.play.server.SPacketServerDifficulty;
-import net.minecraft.scoreboard.ServerScoreboard;
-import net.minecraft.server.dedicated.DedicatedPlayerList;
-import net.minecraft.server.dedicated.DedicatedServer;
-import net.minecraft.server.management.PlayerProfileCache;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.util.text.ITextComponent;
-import net.minecraft.util.text.TextComponentString;
-import net.minecraft.util.text.TextComponentTranslation;
-import net.minecraft.world.World;
-import net.minecraft.world.WorldServer;
-import net.minecraft.world.chunk.storage.AnvilChunkLoader;
-import net.minecraft.world.storage.WorldInfo;
-import net.minecraftforge.common.MinecraftForge;
-import net.minecraftforge.fml.relauncher.Side;
-import net.minecraftforge.fml.relauncher.SideOnly;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-@SideOnly(Side.SERVER)
-public class ModDedicatedPlayerList extends DedicatedPlayerList
-{
-    private final DedicatedServer mcServer;
-    private static final Logger LOG = LogManager.getLogger();
-    
-    public ModDedicatedPlayerList(DedicatedServer server) 
-    {
-        super(server);
-        this.mcServer = server;
-    }
-    
-    // copied from net.minecraft.server.management.PlayerList
-    private void setPlayerGameTypeBasedOnOther(EntityPlayerMP target, EntityPlayerMP source, World worldIn)
-    {
-        /*if (source != null)
-        {
-            target.interactionManager.setGameType(source.interactionManager.getGameType());
-        }
-        else if (this.gameType != null)
-        {
-            target.interactionManager.setGameType(this.gameType);
-        }*/
-
-        target.interactionManager.initializeGameType(worldIn.getWorldInfo().getGameType());
-    }
-    
-    // copied from net.minecraft.server.management.PlayerList
-    @Override
-    public void initializeConnectionToPlayer(NetworkManager netManager, EntityPlayerMP playerIn, NetHandlerPlayServer nethandlerplayserver)
-    {
-        GameProfile gameprofile = playerIn.getGameProfile();
-        PlayerProfileCache playerprofilecache = this.mcServer.getPlayerProfileCache();
-        GameProfile gameprofile1 = playerprofilecache.getProfileByUUID(gameprofile.getId());
-        String s = gameprofile1 == null ? gameprofile.getName() : gameprofile1.getName();
-        playerprofilecache.addEntry(gameprofile);
-        NBTTagCompound nbttagcompound = this.readPlayerDataFromFile(playerIn);
-        playerIn.setWorld(this.mcServer.worldServerForDimension(playerIn.dimension));
-
-        World playerWorld = this.mcServer.worldServerForDimension(playerIn.dimension);
-        if (playerWorld == null)
-        {
-            playerIn.dimension = 0;
-            playerWorld = this.mcServer.worldServerForDimension(0);
-            BlockPos spawnPoint = playerWorld.provider.getRandomizedSpawnPoint();
-            playerIn.setPosition(spawnPoint.getX(), spawnPoint.getY(), spawnPoint.getZ());
-        }
-
-        playerIn.setWorld(playerWorld);
-        playerIn.interactionManager.setWorld((WorldServer)playerIn.world);
-        String s1 = "local";
-
-        if (netManager.getRemoteAddress() != null)
-        {
-            s1 = netManager.getRemoteAddress().toString();
-        }
-
-        LOG.info("{}[{}] logged in with entity id {} at ({}, {}, {})", new Object[] {playerIn.getName(), s1, playerIn.getEntityId(), playerIn.posX, playerIn.posY, playerIn.posZ});
-        WorldServer worldserver = this.mcServer.worldServerForDimension(playerIn.dimension);
-        WorldInfo worldinfo = worldserver.getWorldInfo();
-        this.setPlayerGameTypeBasedOnOther(playerIn, null, worldserver);
-        playerIn.connection = nethandlerplayserver;
-        nethandlerplayserver.sendPacket(new SPacketJoinGame(playerIn.getEntityId(), playerIn.interactionManager.getGameType(), worldinfo.isHardcoreModeEnabled(), worldserver.provider.getDimension(), worldserver.getDifficulty(), this.getMaxPlayers(), worldinfo.getTerrainType(), worldserver.getGameRules().getBoolean("reducedDebugInfo")));
-        nethandlerplayserver.sendPacket(new SPacketCustomPayload("MC|Brand", (new PacketBuffer(Unpooled.buffer())).writeString(this.getServerInstance().getServerModName())));
-        nethandlerplayserver.sendPacket(new SPacketServerDifficulty(worldinfo.getDifficulty(), worldinfo.isDifficultyLocked()));
-        nethandlerplayserver.sendPacket(new SPacketPlayerAbilities(playerIn.capabilities));
-        nethandlerplayserver.sendPacket(new SPacketHeldItemChange(playerIn.inventory.currentItem));
-        this.updatePermissionLevel(playerIn);
-        playerIn.getStatFile().markAllDirty();
-        playerIn.getStatFile().sendAchievements(playerIn);
-        this.sendScoreboard((ServerScoreboard)worldserver.getScoreboard(), playerIn);
-        this.mcServer.refreshStatusNextTick();
-        // Custom Join Message - Start
-        //TextComponentTranslation textcomponenttranslation;
-        
-        PlayerJoinMessageEvent event;
-        if (playerIn.getName().equalsIgnoreCase(s))
-        {
-            //textcomponenttranslation = new TextComponentTranslation("multiplayer.player.joined", new Object[] {playerIn.getDisplayName()});
-            event = new PlayerJoinMessageEvent(playerIn, false, "No message was set.");
-        }
-        else
-        {
-            //textcomponenttranslation = new TextComponentTranslation("multiplayer.player.joined.renamed", new Object[] {playerIn.getDisplayName(), s});
-            event = new PlayerJoinMessageEvent(playerIn, true, "No message was set.");
-        }
-
-        //textcomponenttranslation.getStyle().setColor(TextFormatting.YELLOW);
-        //this.sendMessage(textcomponenttranslation);
-        if(!MinecraftForge.EVENT_BUS.post(event))
-        {
-            this.sendMessage(new TextComponentString(event.getMessage()));
-        }
-        // Custom Join Message - End
-        this.playerLoggedIn(playerIn);
-        nethandlerplayserver.setPlayerLocation(playerIn.posX, playerIn.posY, playerIn.posZ, playerIn.rotationYaw, playerIn.rotationPitch);
-        this.updateTimeAndWeatherForPlayer(playerIn, worldserver);
-
-        if (!this.mcServer.getResourcePackUrl().isEmpty())
-        {
-            playerIn.loadResourcePack(this.mcServer.getResourcePackUrl(), this.mcServer.getResourcePackHash());
-        }
-
-        playerIn.getActivePotionEffects().stream().forEach((potioneffect) -> 
-        {
-            nethandlerplayserver.sendPacket(new SPacketEntityEffect(playerIn.getEntityId(), potioneffect));
-        });
-
-        if (nbttagcompound != null && nbttagcompound.hasKey("RootVehicle", 10))
-        {
-            NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("RootVehicle");
-            Entity entity1 = AnvilChunkLoader.readWorldEntity(nbttagcompound1.getCompoundTag("Entity"), worldserver, true);
-
-            if (entity1 != null)
-            {
-                UUID uuid = nbttagcompound1.getUniqueId("Attach");
-
-                if (entity1.getUniqueID().equals(uuid))
-                {
-                    playerIn.startRiding(entity1, true);
-                }
-                else
-                {
-                    for (Entity entity : entity1.getRecursivePassengers())
-                    {
-                        if (entity.getUniqueID().equals(uuid))
-                        {
-                            playerIn.startRiding(entity, true);
-                            break;
-                        }
-                    }
-                }
-
-                if (!playerIn.isRiding())
-                {
-                    LOG.warn("Couldn\'t reattach entity to player");
-                    worldserver.removeEntityDangerously(entity1);
-
-                    entity1.getRecursivePassengers().stream().forEach((entity2) -> 
-                    {
-                        worldserver.removeEntityDangerously(entity2);
-                    });
-                }
-            }
-        }
-
-        playerIn.addSelfToInternalCraftingInventory();
-        net.minecraftforge.fml.common.FMLCommonHandler.instance().firePlayerLoggedIn(playerIn);
-    }
-    
-    // workaround handler for leave message
-    @Override
-    public void sendMessage(ITextComponent component)
-    {
-        // Custom Leave Message - Start
-        if(component instanceof TextComponentTranslation)
-        {
-            TextComponentTranslation trans = (TextComponentTranslation) component;
-            switch(trans.getKey())
-            {
-                case "multiplayer.player.left":
-                {
-                    // trying to get a player
-                    Object[] o = trans.getFormatArgs();
-                    if(o.length >= 1)
-                    {
-                        EntityPlayer p = Utils.getPlayerByDisplayName(o[0].toString());
-                        if(p == null)
-                        {
-                            KajetansMod.error.sendToConsole(GlobalText.shouldNotHappen());
-                            return;
-                        }
-                        PlayerLeaveMessageEvent event = new PlayerLeaveMessageEvent(p, "No message was set.");;
-                        if(!MinecraftForge.EVENT_BUS.post(event))
-                        {
-                            this.sendMessage(new TextComponentString(event.getMessage()), true);
-                        }
-                    }
-                    else
-                    {
-                        KajetansMod.error.sendToConsole(GlobalText.shouldNotHappen());
-                    }
-                    return;
-                }
-            }   
-        }
-        // Custom Leave Message - End
-        this.sendMessage(component, true);
-    }
-}

+ 2 - 0
src/main/java/me/km/events/PlayerHurtEvent.java

@@ -3,7 +3,9 @@ package me.km.events;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.util.DamageSource;
 import net.minecraftforge.event.entity.living.LivingHurtEvent;
+import net.minecraftforge.fml.common.eventhandler.Cancelable;
 
+@Cancelable
 public class PlayerHurtEvent extends LivingHurtEvent
 {
     private final EntityPlayerMP p;

+ 2 - 0
src/main/java/me/km/events/PlayerJoinMessageEvent.java

@@ -2,7 +2,9 @@ package me.km.events;
 
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraftforge.event.entity.player.PlayerEvent;
+import net.minecraftforge.fml.common.eventhandler.Cancelable;
 
+@Cancelable
 public class PlayerJoinMessageEvent extends PlayerEvent
 {
     private String message;

+ 2 - 0
src/main/java/me/km/events/PlayerLeaveMessageEvent.java

@@ -2,7 +2,9 @@ package me.km.events;
 
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraftforge.event.entity.player.PlayerEvent;
+import net.minecraftforge.fml.common.eventhandler.Cancelable;
 
+@Cancelable
 public class PlayerLeaveMessageEvent extends PlayerEvent
 {
     private String message;

+ 66 - 0
src/main/java/me/km/events/PlayerRespawnAtEvent.java

@@ -0,0 +1,66 @@
+package me.km.events;
+
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.world.WorldServer;
+import net.minecraftforge.event.entity.player.PlayerEvent;
+
+public class PlayerRespawnAtEvent extends PlayerEvent
+{
+    private WorldServer w;
+    private Vec3d v;
+    private boolean force;
+    private boolean forceKeepInventory;
+    
+    public PlayerRespawnAtEvent(EntityPlayer player, WorldServer w, double x, double y, double z) 
+    {
+        super(player);
+        this.w = w;
+        this.v = new Vec3d(x, y, z);
+        this.force = false;
+        this.forceKeepInventory = false;
+    }
+    
+    public WorldServer getWorld()
+    {
+        return w;
+    }
+    
+    public void setWorld(WorldServer w)
+    {
+        if(this.w != w)
+        {
+            this.force = true;
+        }
+        this.w = w;
+    }
+    
+    public Vec3d getRespawnLoc()
+    {
+        return v;
+    }
+    
+    public void setRespawnLoc(Vec3d v)
+    {
+        if(this.v != v)
+        {
+            this.force = true;
+        }
+        this.v = v;
+    }
+    
+    public boolean isForced()
+    {
+        return force;
+    }
+    
+    public void setForcedInventoryKeeping(boolean b)
+    {
+        this.forceKeepInventory = b;
+    }
+    
+    public boolean isInventoryKeepingForced()
+    {
+        return forceKeepInventory;
+    }
+}

+ 1 - 1
src/main/java/me/km/exception/PlayerNotFoundException.java

@@ -5,5 +5,5 @@ public class PlayerNotFoundException extends IllegalStringException
     public PlayerNotFoundException(String s) 
     {
         super(s);
-    }   
+    }  
 }

+ 188 - 1
src/main/java/me/km/fluids/BlockFluidBase.java

@@ -1,21 +1,208 @@
 package me.km.fluids;
 
+import java.util.Random;
+import javax.annotation.Nonnull;
 import me.km.KajetansMod;
+import me.km.utils.ReflectionUtils;
+import net.minecraft.block.Block;
 import net.minecraft.block.material.Material;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.SoundEvents;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.EnumParticleTypes;
+import net.minecraft.util.SoundCategory;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
 import net.minecraftforge.fluids.BlockFluidClassic;
 import net.minecraftforge.fluids.Fluid;
 
-public class BlockFluidBase extends BlockFluidClassic
+public abstract class BlockFluidBase extends BlockFluidClassic
 {
     public BlockFluidBase(Fluid fluid, Material material) 
     {
         super(fluid, material);
         this.setRegistryName(fluid.getName());
         super.setUnlocalizedName(fluid.getUnlocalizedName());
+        super.setCreativeTab(CreativeTabs.BUILDING_BLOCKS);
     }
     
     public void registerBlockModel() 
     {
         KajetansMod.proxy.registerFluidModel(this);
+    }   
+
+    @Override
+    public void updateTick(@Nonnull World w, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Random rand)
+    {
+        if(!isSourceBlock(w, pos))
+        {
+            int adjacentSourceBlocks =
+                    (isSourceBlock(w, pos.north()) ? 1 : 0) +
+                    (isSourceBlock(w, pos.south()) ? 1 : 0) +
+                    (isSourceBlock(w, pos.east()) ? 1 : 0) +
+                    (isSourceBlock(w, pos.west()) ? 1 : 0);
+            if (adjacentSourceBlocks >= 2 && (w.getBlockState(pos.up(densityDir)).getMaterial().isSolid() || isSourceBlock(w, pos.up(densityDir))))
+            {
+                w.setBlockState(pos, state.withProperty(LEVEL, 0));
+            }
+        }
+
+        int quantaRemaining = quantaPerBlock - state.getValue(LEVEL);
+        int expQuanta;
+
+        // check adjacent block levels if non-source
+        if(quantaRemaining < quantaPerBlock)
+        {
+            if (w.getBlockState(pos.add( 0, -densityDir,  0)).getBlock() == this ||
+                w.getBlockState(pos.add(-1, -densityDir,  0)).getBlock() == this ||
+                w.getBlockState(pos.add( 1, -densityDir,  0)).getBlock() == this ||
+                w.getBlockState(pos.add( 0, -densityDir, -1)).getBlock() == this ||
+                w.getBlockState(pos.add( 0, -densityDir,  1)).getBlock() == this)
+            {
+                expQuanta = quantaPerBlock - 1;
+            }
+            else
+            {
+                int maxQuanta = -100;
+                maxQuanta = getLargerQuanta(w, pos.add(-1, 0,  0), maxQuanta);
+                maxQuanta = getLargerQuanta(w, pos.add( 1, 0,  0), maxQuanta);
+                maxQuanta = getLargerQuanta(w, pos.add( 0, 0, -1), maxQuanta);
+                maxQuanta = getLargerQuanta(w, pos.add( 0, 0,  1), maxQuanta);
+
+                expQuanta = maxQuanta - 1;
+            }
+
+            // decay calculation
+            if(expQuanta != quantaRemaining)
+            {
+                quantaRemaining = expQuanta;
+
+                if(expQuanta <= 0)
+                {
+                    w.setBlockToAir(pos);
+                }
+                else
+                {
+                    w.setBlockState(pos, state.withProperty(LEVEL, quantaPerBlock - expQuanta), 2);
+                    w.scheduleUpdate(pos, this, tickRate);
+                    w.notifyNeighborsOfStateChange(pos, this, false);
+                }
+            }
+        }
+        // This is a "source" block, set meta to zero, and send a server only update
+        else if(quantaRemaining >= quantaPerBlock)
+        {
+            w.setBlockState(pos, this.getDefaultState(), 2);
+        }
+
+        // Flow vertically if possible
+        if(canDisplace(w, pos.up(densityDir)))
+        {
+            BlockPos bpos = pos.up(densityDir);
+            Block b = w.getBlockState(bpos).getBlock();
+            if(b == Blocks.LAVA || b == Blocks.WATER || b == Blocks.FLOWING_LAVA || b == Blocks.FLOWING_WATER ||
+                (b != this && b instanceof net.minecraftforge.fluids.BlockFluidBase))
+            {
+                w.setBlockState(bpos, getFlownOnMixingBlock(b, ReflectionUtils.getBlockMaterial(b)));
+                this.triggerMixEffects(w, bpos);
+                return;
+            }
+            flowIntoBlock(w, pos.up(densityDir), 1);
+            return;
+        }
+
+        // Flow outward if possible
+        int flowMeta = quantaPerBlock - quantaRemaining + 1;
+        if(flowMeta >= quantaPerBlock)
+        {
+            return;
+        }
+
+        if(isSourceBlock(w, pos) || !isFlowingVertically(w, pos))
+        {
+            if(w.getBlockState(pos.down(densityDir)).getBlock() == this)
+            {
+                flowMeta = 1;
+            }
+            boolean flowTo[] = getOptimalFlowDirections(w, pos);
+
+            if(flowTo[0]) flowIntoBlock(w, pos.add(-1, 0,  0), flowMeta);
+            if(flowTo[1]) flowIntoBlock(w, pos.add( 1, 0,  0), flowMeta);
+            if(flowTo[2]) flowIntoBlock(w, pos.add( 0, 0, -1), flowMeta);
+            if(flowTo[3]) flowIntoBlock(w, pos.add( 0, 0,  1), flowMeta);
+        }
+    }
+    
+    @Override
+    public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state)
+    {
+        checkForMixing(worldIn, pos, state);
+        super.onBlockAdded(worldIn, pos, state);
+    }
+
+    @Override
+    public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos)
+    {
+        checkForMixing(worldIn, pos, state);
+        super.neighborChanged(state, worldIn, pos, blockIn, fromPos);
+    }
+    
+    private boolean checkForMixing(World worldIn, BlockPos pos, IBlockState state)
+    {
+        boolean flag = false;
+        Block b = null;
+        for (EnumFacing enumfacing : EnumFacing.values())
+        {
+            if (enumfacing != EnumFacing.DOWN)
+            {
+                b = worldIn.getBlockState(pos.offset(enumfacing)).getBlock();
+                if(b == Blocks.LAVA || b == Blocks.WATER || b == Blocks.FLOWING_LAVA || b == Blocks.FLOWING_WATER ||
+                    (b != this && b instanceof net.minecraftforge.fluids.BlockFluidBase))
+                {
+                    flag = true;
+                    break;
+                }
+            }
+        }
+        if(flag)
+        {
+            Integer integer = state.getValue(LEVEL);
+            if (integer == 0)
+            {
+                worldIn.setBlockState(pos, getStrongMixingBlock(b, ReflectionUtils.getBlockMaterial(b)));
+                this.triggerMixEffects(worldIn, pos);
+                return true;
+            }
+            else
+            {
+                worldIn.setBlockState(pos, getWeakMixingBlock(b, ReflectionUtils.getBlockMaterial(b)));
+                this.triggerMixEffects(worldIn, pos);
+                return true;
+            }
+        }
+
+        return false;
+    }
+    
+    protected abstract IBlockState getStrongMixingBlock(Block b, Material m);
+    
+    protected abstract IBlockState getWeakMixingBlock(Block b, Material m);
+    
+    protected abstract IBlockState getFlownOnMixingBlock(Block b, Material m);
+    
+    protected void triggerMixEffects(World worldIn, BlockPos pos)
+    {
+        double d0 = pos.getX();
+        double d1 = pos.getY();
+        double d2 = pos.getZ();
+        
+        worldIn.playSound(null, pos, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 0.5F, 2.6F + (worldIn.rand.nextFloat() - worldIn.rand.nextFloat()) * 0.8F);
+
+        for (int i = 0; i < 8; ++i)
+        {
+            worldIn.spawnParticle(EnumParticleTypes.SMOKE_LARGE, d0 + Math.random(), d1 + 1.2d, d2 + Math.random(), 0, 0, 0, new int[0]);
+        }
     }
 }

+ 63 - 0
src/main/java/me/km/fluids/BlockFluidHoney.java

@@ -0,0 +1,63 @@
+package me.km.fluids;
+
+import net.minecraft.block.Block;
+import static net.minecraft.block.BlockColored.COLOR;
+import net.minecraft.block.material.Material;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.MobEffects;
+import net.minecraft.item.EnumDyeColor;
+import net.minecraft.potion.PotionEffect;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+import net.minecraftforge.fluids.Fluid;
+
+public class BlockFluidHoney extends BlockFluidBase
+{
+    public BlockFluidHoney(Fluid fluid, Material material) 
+    {
+        super(fluid, material);
+    }
+
+    @Override
+    public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) 
+    {
+        super.onEntityCollidedWithBlock(worldIn, pos, state, entityIn);
+        if(entityIn instanceof EntityLivingBase)
+        {
+            ((EntityLivingBase) entityIn).addPotionEffect(new PotionEffect(MobEffects.REGENERATION, 100, 1));
+        }
+    }
+
+    @Override
+    protected IBlockState getStrongMixingBlock(Block b, Material m) 
+    {
+        if(m == Material.LAVA)
+        {
+            return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.BROWN);
+        }
+        return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.YELLOW);
+    }
+
+    @Override
+    protected IBlockState getWeakMixingBlock(Block b, Material m) 
+    {
+        if(m == Material.LAVA)
+        {
+            return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.BROWN);
+        }
+        return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.YELLOW);
+    }
+    
+    @Override
+    protected IBlockState getFlownOnMixingBlock(Block b, Material m) 
+    {
+        if(m == Material.LAVA)
+        {
+            return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.BROWN);
+        }
+        return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.YELLOW);
+    }
+}

+ 64 - 0
src/main/java/me/km/fluids/BlockFluidPoison.java

@@ -0,0 +1,64 @@
+package me.km.fluids;
+
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockColored;
+import static net.minecraft.block.BlockColored.COLOR;
+import net.minecraft.block.material.Material;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.EntityLivingBase;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.MobEffects;
+import net.minecraft.item.EnumDyeColor;
+import net.minecraft.potion.PotionEffect;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
+import net.minecraftforge.fluids.Fluid;
+
+public class BlockFluidPoison extends BlockFluidBase
+{
+    public BlockFluidPoison(Fluid fluid, Material material) 
+    {
+        super(fluid, material);
+    }
+
+    @Override
+    public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, IBlockState state, Entity entityIn) 
+    {
+        super.onEntityCollidedWithBlock(worldIn, pos, state, entityIn);
+        if(entityIn instanceof EntityLivingBase)
+        {
+            ((EntityLivingBase) entityIn).addPotionEffect(new PotionEffect(MobEffects.POISON, 100, 1));
+        }
+    }
+
+    @Override
+    protected IBlockState getStrongMixingBlock(Block b, Material m) 
+    {
+        if(m == Material.LAVA)
+        {
+            return Blocks.COBBLESTONE.getDefaultState();
+        }
+        return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.PURPLE);
+    }
+
+    @Override
+    protected IBlockState getWeakMixingBlock(Block b, Material m) 
+    {
+        if(m == Material.LAVA)
+        {
+            return Blocks.COBBLESTONE.getDefaultState();
+        }
+        return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.PURPLE);
+    }
+    
+    @Override
+    protected IBlockState getFlownOnMixingBlock(Block b, Material m) 
+    {
+        if(m == Material.LAVA)
+        {
+            return Blocks.COBBLESTONE.getDefaultState();
+        }
+        return Blocks.STAINED_HARDENED_CLAY.getDefaultState().withProperty(COLOR, EnumDyeColor.PURPLE);
+    }
+}

+ 3 - 1
src/main/java/me/km/fluids/ModFluids.java

@@ -8,10 +8,12 @@ import net.minecraftforge.fluids.FluidRegistry;
 public class ModFluids 
 {
     public static Fluid poison;
+    public static Fluid honey;
     
     public static void init() 
     {
-        poison = register("poison");
+        poison = register("poison").setViscosity(2000);
+        honey = register("honey").setViscosity(4000);
     }
 
     private static Fluid register(String name) 

+ 108 - 30
src/main/java/me/km/inventory/InventoryUtils.java

@@ -31,18 +31,13 @@ public class InventoryUtils
             }
         }
     }
-    
-    public static boolean doItemStacksMatch(ItemStack first, ItemStack second)
-    {
-        int count = first.getCount();
-        first.setCount(second.getCount());
-        boolean b = ItemStack.areItemStacksEqual(first, second);
-        first.setCount(count);
-        return b;
-    }
 
     public static int searchInventoryFor(IInventory inv, ItemStack searchfor, boolean useData)
     {
+        if(searchfor.isEmpty())
+        {
+            return 0;
+        }
         int counter = 0;
         if(useData)
         {
@@ -51,7 +46,7 @@ public class InventoryUtils
             for(int i = 0; i < size; i++)
             {
                 stack = inv.getStackInSlot(i);
-                if(doItemStacksMatch(stack, searchfor))
+                if(stackEqualExact(stack, searchfor))
                 {
                     counter += stack.getCount();
                 }
@@ -74,15 +69,19 @@ public class InventoryUtils
         return counter;
     }
     
-    public static int removeFromInventory(IInventory inv, ItemStack searchfor)
+    public static int removeFromInventory(IInventory inv, ItemStack remove)
     {
+        if(remove.isEmpty())
+        {
+            return 0;
+        }
         ItemStack stack;
         int sub;
-        int amount = searchfor.getCount();
+        int amount = remove.getCount();
         for(int i = 0; i < inv.getSizeInventory(); i++)
         {
             stack = inv.getStackInSlot(i);
-            if(doItemStacksMatch(stack, searchfor))
+            if(stackEqualExact(stack, remove))
             {
                 sub = stack.getCount();
                 if(amount > sub)
@@ -106,33 +105,112 @@ public class InventoryUtils
     }
     
     public static int addToInventory(IInventory inv, ItemStack add)
-    {
-        ItemStack stack;
-        int sub;
-        int amount = add.getCount();
-        int max = Math.min(add.getMaxStackSize(), inv.getInventoryStackLimit());
-        for(int i = 0; i < inv.getSizeInventory(); i++)
+    {    
+        if(add.isEmpty())
         {
-            stack = inv.getStackInSlot(i);
-            if(doItemStacksMatch(stack, add))
+            return 0;
+        }
+        else
+        {
+            if(add.isItemDamaged())
             {
-                sub = stack.getCount();
-                if(max - sub >= amount)
+                int j = getFirstEmptyStack(inv);
+                if(j >= 0)
                 {
-                    stack.setCount(amount + stack.getCount());
+                    inv.setInventorySlotContents(j, add.copy());
+                    inv.getStackInSlot(j).setAnimationsToGo(5);
+                    return 0;
                 }
-                else if(sub < max)
+                return add.getCount();
+            }
+            else
+            {
+                ItemStack copy = add.copy();
+                int i;
+                while(true)
                 {
-                    amount -= max - sub;
-                    stack.setCount(max);
-                    return 0;
+                    i = copy.getCount();
+                    copy.setCount(storePartialItemStack(inv, copy));
+                    if(copy.isEmpty() || copy.getCount() >= i)
+                    {
+                        break;
+                    }
                 }
+                return copy.getCount();
             }
         }
-        return amount;
     }
     
-    public static int getFirstEmptySlot(IInventory inv)
+    private static int storePartialItemStack(IInventory inv, ItemStack add)
+    {
+        int i = add.getCount();
+        int j = storeItemStack(inv, add);
+        if(j == -1)
+        {
+            j = getFirstEmptyStack(inv);
+        }
+        if (j == -1)
+        {
+            return i;
+        }
+        ItemStack stack = inv.getStackInSlot(j);
+        if(stack.isEmpty())
+        {
+            stack = add.copy();
+            stack.setCount(0);
+            if(add.hasTagCompound())
+            {
+                stack.setTagCompound(add.getTagCompound().copy());
+            }
+            inv.setInventorySlotContents(j, stack);
+        }
+
+        int k = i;
+        if(i > stack.getMaxStackSize() - stack.getCount())
+        {
+            k = stack.getMaxStackSize() - stack.getCount();
+        }
+        if(k > inv.getInventoryStackLimit() - stack.getCount())
+        {
+            k = inv.getInventoryStackLimit() - stack.getCount();
+        }
+
+        if(k == 0)
+        {
+            return i;
+        }
+        else
+        {
+            i -= k;
+            stack.grow(k);
+            stack.setAnimationsToGo(5);
+            return i;
+        }
+    }
+    
+    private static int storeItemStack(IInventory inv, ItemStack add)
+    {
+        for (int i = 0; i < inv.getSizeInventory(); i++)
+        {
+            if(canMergeStacks(inv, inv.getStackInSlot(i), add))
+            {
+                return i;
+            }
+        }
+        return -1;
+    }
+    
+    private static boolean canMergeStacks(IInventory inv, ItemStack first, ItemStack sec)
+    {
+        return !first.isEmpty() && stackEqualExact(first, sec) && first.isStackable() && first.getCount() < first.getMaxStackSize() && first.getCount() < inv.getInventoryStackLimit();
+    }
+    
+    public static boolean stackEqualExact(ItemStack first, ItemStack sec)
+    {
+        return first.getItem() == sec.getItem() && (!first.getHasSubtypes() || first.getMetadata() == sec.getMetadata()) && ItemStack.areItemStackTagsEqual(first, sec);
+    }
+    
+    public static int getFirstEmptyStack(IInventory inv)
     {
         for(int i = 0; i < inv.getSizeInventory(); i++)
         {

+ 18 - 7
src/main/java/me/km/nms/NmsUtilities.java

@@ -229,17 +229,28 @@ public class NmsUtilities
     
     public static void sendCopyableText(EntityPlayer p, String s)
     {
-        s = s.replaceAll("\\{", "(");
-        s = s.replaceAll("\\}", ")");
-        s = s.replaceAll(" ", "%20");
-        s = s.replaceAll("\"", "'");
-        TextComponentString text = new TextComponentString("Hier drücken zum Kopieren.");
+        s = s.replace('{', 'Ɛ');
+        s = s.replace('}', 'Ƒ');
+        s = s.replace('[', 'ƒ');
+        s = s.replace(']', 'Ɠ');
+        s = s.replace('(', 'ƕ');
+        s = s.replace(')', 'Ɩ');
+        s = s.replace(" ", "%20");
+        s = s.replace('\'', 'Ɩ');
+        s = s.replace('"', 'Ɩ');
+        s = s.replace("\\", "");
+        sendLink(p, "Hier drücken zum Kopieren.", "http://minecraft.hammerle.me/showtext.php/?text=" + s);
+    } 
+    
+    private static void sendLink(EntityPlayer p, String s, String link)
+    {
+        TextComponentString text = new TextComponentString(s);
         Style style = text.getStyle();
         style.setColor(TextFormatting.RED);
         style.setBold(true);
-        style.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "http://minecraft.hammerle.me/showtext.php/?text=" + s));
+        style.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, link));
         p.sendMessage(text);
-    } 
+    }
     
     // -------------------------------------------------------------------------
     // Action-Bar

+ 0 - 27
src/main/java/me/km/permissions/PermissionListener.java

@@ -1,27 +0,0 @@
-package me.km.permissions;
-
-import me.km.KajetansMod;
-import me.km.api.Module;
-import me.km.api.ModuleCommand;
-import me.km.api.ModuleListener;
-import net.minecraft.command.ICommand;
-import net.minecraftforge.event.CommandEvent;
-import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-
-public class PermissionListener extends ModuleListener
-{
-    public PermissionListener(Module m) 
-    {
-        super(m);
-    }
-    
-    @SubscribeEvent
-    public void onCommandUse(CommandEvent e)
-    {       
-        ICommand command = e.getCommand();
-        if(!(command instanceof ModuleCommand) && !KajetansMod.perms.has(e.getSender(), command.getName()))
-        {
-            e.setCanceled(true);
-        }
-    }
-}

+ 1 - 1
src/main/java/me/km/permissions/PermissionManager.java

@@ -97,7 +97,7 @@ public class PermissionManager extends Module
     
     public void registerPlayerGroup(UUID uuid, int id)
     {
-        if(id < 0 || id >= playerGroups.size())
+        if(id < 0 || id >= stringGroupPerms.size())
         {
             throw new IllegalArgumentException("'" + id + "' is no valid group id");
         }

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

@@ -9,10 +9,10 @@ public enum Permissions
     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, 
+    TELEPORT_ACCEPT, WORLD,
     
     // Chat-Manager
-    COLOR, USE_COLOR, NICKNAME, FAKERANK, WORLD,
+    COLOR, USE_COLOR, NICKNAME, FAKERANK, 
     
     // Block-Protections
     BLOCK_BYPASS, BLOCK, BLOCK_ALL, BLOCK_OTHER, BLOCK_CLEAR,
@@ -42,5 +42,5 @@ public enum Permissions
     QUEST, SCRIPT, QUESTINFO, GIVEUP, SCRIPT_ERROR,
     
     // Special
-    VANILLA
+    VANILLA, WORLDEDIT
 }

+ 342 - 0
src/main/java/me/km/playerbank/ModDedicatedPlayerList.java

@@ -0,0 +1,342 @@
+package me.km.playerbank;
+
+import com.mojang.authlib.GameProfile;
+import io.netty.buffer.Unpooled;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import me.km.KajetansMod;
+import me.km.dimensions.ModDimensions;
+import me.km.events.PlayerJoinMessageEvent;
+import me.km.events.PlayerRespawnAtEvent;
+import me.km.utils.ReflectionUtils;
+import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.nbt.NBTTagCompound;
+import net.minecraft.network.NetHandlerPlayServer;
+import net.minecraft.network.NetworkManager;
+import net.minecraft.network.PacketBuffer;
+import net.minecraft.network.play.server.SPacketChangeGameState;
+import net.minecraft.network.play.server.SPacketCustomPayload;
+import net.minecraft.network.play.server.SPacketEntityEffect;
+import net.minecraft.network.play.server.SPacketHeldItemChange;
+import net.minecraft.network.play.server.SPacketJoinGame;
+import net.minecraft.network.play.server.SPacketPlayerAbilities;
+import net.minecraft.network.play.server.SPacketRespawn;
+import net.minecraft.network.play.server.SPacketServerDifficulty;
+import net.minecraft.network.play.server.SPacketSetExperience;
+import net.minecraft.network.play.server.SPacketSpawnPosition;
+import net.minecraft.scoreboard.ServerScoreboard;
+import net.minecraft.server.dedicated.DedicatedPlayerList;
+import net.minecraft.server.dedicated.DedicatedServer;
+import net.minecraft.server.management.PlayerInteractionManager;
+import net.minecraft.server.management.PlayerProfileCache;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.math.Vec3d;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.world.GameRules;
+import net.minecraft.world.World;
+import net.minecraft.world.WorldServer;
+import net.minecraft.world.chunk.storage.AnvilChunkLoader;
+import net.minecraft.world.demo.DemoWorldManager;
+import net.minecraft.world.storage.WorldInfo;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.relauncher.Side;
+import net.minecraftforge.fml.relauncher.SideOnly;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+@SideOnly(Side.SERVER)
+public class ModDedicatedPlayerList extends DedicatedPlayerList
+{
+    private final DedicatedServer mcServer;
+    private static final Logger LOG = LogManager.getLogger();
+    private final List<EntityPlayerMP> playerEntityList;
+    private final Map<UUID, EntityPlayerMP> uuidToPlayerMap;
+    
+    public ModDedicatedPlayerList(DedicatedServer server) 
+    {
+        super(server);
+        this.mcServer = server;
+        this.playerEntityList = super.getPlayers();
+        this.uuidToPlayerMap = ReflectionUtils.getUuidToPlayerMap(this);
+    }
+    
+    // copied from net.minecraft.server.management.PlayerList
+    private void setPlayerGameTypeBasedOnOther(EntityPlayerMP target, EntityPlayerMP source, World worldIn)
+    {
+        if (source != null)
+        {
+            target.interactionManager.setGameType(source.interactionManager.getGameType());
+        }
+        /*else if(this.gameType != null)
+        {
+            target.interactionManager.setGameType(this.gameType);
+        }*/
+        target.interactionManager.initializeGameType(worldIn.getWorldInfo().getGameType());
+    }
+    
+    // copied from net.minecraft.server.management.PlayerList
+    @Override
+    public void initializeConnectionToPlayer(NetworkManager netManager, EntityPlayerMP p, NetHandlerPlayServer nethandlerplayserver)
+    {
+        // get name for old / new name comparing
+        GameProfile gameprofile = p.getGameProfile();
+        PlayerProfileCache cache = this.mcServer.getPlayerProfileCache();
+        GameProfile gameprofile1 = cache.getProfileByUUID(gameprofile.getId());
+        String playerName = gameprofile1 == null ? gameprofile.getName() : gameprofile1.getName();
+        cache.addEntry(gameprofile);
+        
+        // read data
+        NBTTagCompound nbttagcompound = this.readPlayerDataFromFile(p);
+        
+        WorldServer playerWorld = this.mcServer.worldServerForDimension(p.dimension);
+        if(playerWorld == null)
+        {
+            p.dimension = 0;
+            playerWorld = this.mcServer.worldServerForDimension(0);
+            BlockPos spawnPoint = playerWorld.provider.getRandomizedSpawnPoint();
+            p.setPosition(spawnPoint.getX(), spawnPoint.getY(), spawnPoint.getZ());
+        }
+        p.setWorld(playerWorld);
+        p.interactionManager.setWorld(playerWorld);
+        
+        String s = "local";
+        if(netManager.getRemoteAddress() != null)
+        {
+            s = netManager.getRemoteAddress().toString();
+        }
+
+        LOG.info("{}[{}] logged in with entity id {} at ({}, {}, {})", new Object[] {p.getName(), s, p.getEntityId(), p.posX, p.posY, p.posZ});
+        WorldInfo worldinfo = playerWorld.getWorldInfo();
+        this.setPlayerGameTypeBasedOnOther(p, null, playerWorld);
+        p.connection = nethandlerplayserver;
+        nethandlerplayserver.sendPacket(new SPacketJoinGame(p.getEntityId(), p.interactionManager.getGameType(), worldinfo.isHardcoreModeEnabled(), p.dimension, playerWorld.getDifficulty(), this.getMaxPlayers(), worldinfo.getTerrainType(), playerWorld.getGameRules().getBoolean("reducedDebugInfo")));
+        nethandlerplayserver.sendPacket(new SPacketCustomPayload("MC|Brand", (new PacketBuffer(Unpooled.buffer())).writeString(this.getServerInstance().getServerModName())));
+        nethandlerplayserver.sendPacket(new SPacketServerDifficulty(worldinfo.getDifficulty(), worldinfo.isDifficultyLocked()));
+        nethandlerplayserver.sendPacket(new SPacketPlayerAbilities(p.capabilities));
+        nethandlerplayserver.sendPacket(new SPacketHeldItemChange(p.inventory.currentItem));
+        this.updatePermissionLevel(p);
+        p.getStatFile().markAllDirty();
+        p.getStatFile().sendAchievements(p);
+        this.sendScoreboard((ServerScoreboard) playerWorld.getScoreboard(), p);
+        this.mcServer.refreshStatusNextTick();
+        // Custom Join Message - Start
+        //TextComponentTranslation textcomponenttranslation;
+        
+        PlayerJoinMessageEvent event;
+        if (p.getName().equalsIgnoreCase(playerName))
+        {
+            //textcomponenttranslation = new TextComponentTranslation("multiplayer.player.joined", new Object[] {playerIn.getDisplayName()});
+            event = new PlayerJoinMessageEvent(p, false, "No message was set.");
+        }
+        else
+        {
+            //textcomponenttranslation = new TextComponentTranslation("multiplayer.player.joined.renamed", new Object[] {playerIn.getDisplayName(), s});
+            event = new PlayerJoinMessageEvent(p, true, "No message was set.");
+        }
+
+        //textcomponenttranslation.getStyle().setColor(TextFormatting.YELLOW);
+        //this.sendMessage(textcomponenttranslation);
+        if(!MinecraftForge.EVENT_BUS.post(event))
+        {
+            KajetansMod.scheduler.scheduleTask(() -> this.sendMessage(new TextComponentString(event.getMessage())), 2);
+        }
+        // Custom Join Message - End
+        this.playerLoggedIn(p);
+        nethandlerplayserver.setPlayerLocation(p.posX, p.posY, p.posZ, p.rotationYaw, p.rotationPitch);
+        this.updateTimeAndWeatherForPlayer(p, playerWorld);
+
+        if (!this.mcServer.getResourcePackUrl().isEmpty())
+        {
+            p.loadResourcePack(this.mcServer.getResourcePackUrl(), this.mcServer.getResourcePackHash());
+        }
+
+        p.getActivePotionEffects().stream().forEach((potioneffect) -> 
+        {
+            nethandlerplayserver.sendPacket(new SPacketEntityEffect(p.getEntityId(), potioneffect));
+        });
+
+        if (nbttagcompound != null && nbttagcompound.hasKey("RootVehicle", 10))
+        {
+            NBTTagCompound nbttagcompound1 = nbttagcompound.getCompoundTag("RootVehicle");
+            Entity entity1 = AnvilChunkLoader.readWorldEntity(nbttagcompound1.getCompoundTag("Entity"), playerWorld, true);
+
+            if (entity1 != null)
+            {
+                UUID uuid = nbttagcompound1.getUniqueId("Attach");
+
+                if (entity1.getUniqueID().equals(uuid))
+                {
+                    p.startRiding(entity1, true);
+                }
+                else
+                {
+                    for (Entity entity : entity1.getRecursivePassengers())
+                    {
+                        if (entity.getUniqueID().equals(uuid))
+                        {
+                            p.startRiding(entity, true);
+                            break;
+                        }
+                    }
+                }
+
+                if (!p.isRiding())
+                {
+                    LOG.warn("Couldn\'t reattach entity to player");
+                    playerWorld.removeEntityDangerously(entity1);
+
+                    for(Entity entity2 : entity1.getRecursivePassengers())
+                    {
+                        playerWorld.removeEntityDangerously(entity2);
+                    }
+                }
+            }
+        }
+
+        p.addSelfToInternalCraftingInventory();
+        
+        // send custom loaded dimensions to the player
+        ModDimensions.sendNotificationsForDimensions(p);
+        
+        net.minecraftforge.fml.common.FMLCommonHandler.instance().firePlayerLoggedIn(p);
+    }
+    
+    // copied from net.minecraft.server.management.PlayerList
+    @Override
+    public EntityPlayerMP recreatePlayerEntity(EntityPlayerMP p, int dim, boolean conqueredEnd)
+    {
+        dim = p.dimension;
+        WorldServer w = mcServer.worldServerForDimension(dim);
+        if(w == null)
+        {
+            dim = p.getSpawnDimension();
+        }
+        else if(!w.provider.canRespawnHere())
+        {
+            dim = w.provider.getRespawnDimension(p);
+        }
+        if(mcServer.worldServerForDimension(dim) == null)
+        {
+            dim = 0;
+        }
+
+        WorldServer pw = p.getServerWorld();
+        pw.getEntityTracker().removePlayerFromTrackers(p);
+        pw.getEntityTracker().untrack(p);
+        pw.getPlayerChunkMap().removePlayer(p);
+        this.playerEntityList.remove(p);
+        pw.removeEntityDangerously(p);
+        
+        // start of event handling
+        // determine would-be spawn
+        w = mcServer.worldServerForDimension(dim);
+        p.dimension = dim;
+
+        PlayerInteractionManager pManager;
+        // keep this demo shit for fucks sake
+        if(this.mcServer.isDemo())
+        {
+            pManager = new DemoWorldManager(w);
+        }
+        else
+        {
+            pManager = new PlayerInteractionManager(w);
+        }
+        EntityPlayerMP newP = new EntityPlayerMP(this.mcServer, w, p.getGameProfile(), pManager);
+        newP.connection = p.connection;
+        newP.setEntityId(p.getEntityId());
+        newP.setCommandStats(p);
+        newP.setPrimaryHand(p.getPrimaryHand());
+        newP.dimension = dim;
+        
+        boolean spawnInBed = false;
+        boolean errorIfNoForce = false;
+        PlayerRespawnAtEvent event;
+        
+        BlockPos bed = p.getBedLocation(dim);
+        if(bed != null)
+        {
+            BlockPos validBed = EntityPlayer.getBedSpawnLocation(w, bed, p.isSpawnForced(dim));
+           if (validBed != null)
+            {
+                spawnInBed = true;
+                event = new PlayerRespawnAtEvent(newP, w, validBed.getX() + 0.5f, validBed.getY() + 0.1f, validBed.getZ() + 0.5f);
+            }
+            else
+            {
+                errorIfNoForce = true;
+                event = new PlayerRespawnAtEvent(newP, w, newP.posX, newP.posY, newP.posZ);
+            }
+        }
+        else
+        {
+            event = new PlayerRespawnAtEvent(newP, w, newP.posX, newP.posY, newP.posZ);
+        }
+        MinecraftForge.EVENT_BUS.post(event);
+        Vec3d v = event.getRespawnLoc();
+        // only change when there is an actual change       
+        if(event.isForced())
+        {
+            w = event.getWorld();
+            newP.world = w;
+            newP.dimension = w.provider.getDimension();
+            p.dimension = newP.dimension;
+            newP.setPosition(v.xCoord, v.yCoord, v.zCoord);
+        }
+        else
+        {
+            if(spawnInBed)
+            {
+                newP.setLocationAndAngles(v.xCoord, v.yCoord, v.zCoord, 0, 0);
+                newP.setSpawnPoint(bed, p.isSpawnForced(dim));
+            }
+            else if(errorIfNoForce)
+            {
+                newP.connection.sendPacket(new SPacketChangeGameState(0, 0));
+            }
+        }
+        
+        if(event.isInventoryKeepingForced() && !conqueredEnd)
+        {
+            GameRules rules = w.getGameRules();
+            boolean keep = rules.getBoolean("keepInventory");
+            rules.setOrCreateGameRule("keepInventory", "true");
+            newP.clonePlayer(p, conqueredEnd);
+            rules.setOrCreateGameRule("keepInventory", String.valueOf(keep));
+        }
+        else
+        {
+            newP.clonePlayer(p, conqueredEnd);
+        }
+
+        // end of event handling
+        
+        p.getTags().stream().forEach(s -> newP.addTag(s));
+        this.setPlayerGameTypeBasedOnOther(newP, p, w);
+        
+        w.getChunkProvider().provideChunk((int) newP.posX >> 4, (int) newP.posZ >> 4);
+
+        while(!w.getCollisionBoxes(newP, newP.getEntityBoundingBox()).isEmpty() && newP.posY < 256.0D)
+        {
+            newP.setPosition(newP.posX, newP.posY + 1.0D, newP.posZ);
+        }
+
+        newP.connection.sendPacket(new SPacketRespawn(newP.dimension, newP.world.getDifficulty(), w.getWorldInfo().getTerrainType(), newP.interactionManager.getGameType()));
+        newP.connection.setPlayerLocation(newP.posX, newP.posY, newP.posZ, newP.rotationYaw, newP.rotationPitch);
+        newP.connection.sendPacket(new SPacketSpawnPosition(w.getSpawnPoint()));
+        newP.connection.sendPacket(new SPacketSetExperience(newP.experience, newP.experienceTotal, newP.experienceLevel));
+        this.updateTimeAndWeatherForPlayer(newP, w);
+        this.updatePermissionLevel(newP);
+        w.getPlayerChunkMap().addPlayer(newP);
+        w.spawnEntity(newP);
+        this.playerEntityList.add(newP);
+        this.uuidToPlayerMap.put(newP.getUniqueID(), newP);
+        newP.addSelfToInternalCraftingInventory();
+        newP.setHealth(newP.getHealth());
+        net.minecraftforge.fml.common.FMLCommonHandler.instance().firePlayerRespawnEvent(newP, conqueredEnd);
+        return newP;
+    }
+}

+ 98 - 0
src/main/java/me/km/playerbank/ModNetHandlerPlayServer.java

@@ -0,0 +1,98 @@
+package me.km.playerbank;
+
+import me.km.KajetansMod;
+import me.km.events.PlayerLeaveMessageEvent;
+import me.km.snuviscript.ScriptEvents;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.NetHandlerPlayServer;
+import net.minecraft.network.NetworkManager;
+import net.minecraft.network.play.client.CPacketChatMessage;
+import net.minecraft.network.play.server.SPacketChat;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.text.ITextComponent;
+import net.minecraft.util.text.TextComponentString;
+import net.minecraft.util.text.TextComponentTranslation;
+import net.minecraft.util.text.TextFormatting;
+import net.minecraftforge.common.MinecraftForge;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class ModNetHandlerPlayServer extends NetHandlerPlayServer
+{
+    private static final Logger LOGGER = LogManager.getLogger();
+    private final MinecraftServer serverController;
+    private final ScriptEvents scriptEvents;
+
+    public ModNetHandlerPlayServer(MinecraftServer server, NetworkManager nm, EntityPlayerMP p) 
+    {
+        super(server, nm, p);
+        serverController = server;
+        scriptEvents = KajetansMod.scripts.getEvent(ScriptEvents.class);
+    }
+    
+    @Override
+    public void processChatMessage(CPacketChatMessage packetIn) 
+    {
+        if(packetIn.getMessage().startsWith("/"))
+        {
+            String s = packetIn.getMessage();
+            int i = s.indexOf(" ");
+            String command;
+            String left;
+            if(i == -1)
+            {
+                command = s.substring(1).toLowerCase();
+                left = "";
+            }   
+            else
+            {
+                command = s.substring(1, i).toLowerCase();
+                left = s.substring(i);
+            }
+            if(KajetansMod.scripts.isRegisteredScriptCommand(command))
+            {
+                if (this.player.getChatVisibility() == EntityPlayer.EnumChatVisibility.HIDDEN)
+                {
+                    TextComponentTranslation trans = new TextComponentTranslation("chat.cannotSend", new Object[0]);
+                    trans.getStyle().setColor(TextFormatting.RED);
+                    this.sendPacket(new SPacketChat(trans));
+                }
+                else
+                {
+                    this.player.markPlayerActive();
+                    scriptEvents.onCustomCommand(this.player, command, left);
+                }
+            }
+            else
+            {
+                super.processChatMessage(new CPacketChatMessage("/" + command + left));
+            }
+            return;
+        }
+        super.processChatMessage(packetIn);
+    }
+    
+    @Override
+    public void onDisconnect(ITextComponent reason)
+    {
+        LOGGER.info("{} lost connection: {}", new Object[] {this.player.getName(), reason});
+        this.serverController.refreshStatusNextTick();        
+        // Custom Leave Message - Start
+        PlayerLeaveMessageEvent event = new PlayerLeaveMessageEvent(this.player, "No message was set.");
+        if(!MinecraftForge.EVENT_BUS.post(event))
+        {
+            TextComponentString text = new TextComponentString(event.getMessage());
+            this.serverController.getPlayerList().sendMessage(text);
+        }
+        // Custom Leave Message - End
+        this.player.mountEntityAndWakeUp();
+        this.serverController.getPlayerList().playerLoggedOut(this.player);
+
+        if (this.serverController.isSinglePlayer() && this.player.getName().equals(this.serverController.getServerOwner()))
+        {
+            LOGGER.info("Stopping singleplayer server as player logged out");
+            this.serverController.initiateShutdown();
+        }
+    }
+}

+ 17 - 4
src/main/java/me/km/playerbank/PlayerLogInOut.java

@@ -7,8 +7,10 @@ import me.km.api.Utils;
 import me.km.commands.CommandSilent;
 import me.km.commands.CommandTeleportAccept;
 import me.km.events.PlayerJoinMessageEvent;
+import me.km.events.PlayerLeaveMessageEvent;
 import me.km.permissions.Permissions;
 import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraftforge.fml.common.eventhandler.EventPriority;
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 import net.minecraftforge.fml.common.gameevent.PlayerEvent;
@@ -21,9 +23,9 @@ public class PlayerLogInOut extends ModuleListener
     }
     
     @SubscribeEvent(priority = EventPriority.HIGH)
-    public void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent e)
+    public void onPlayerJoin(PlayerJoinMessageEvent e)
     {
-        EntityPlayer p = e.player;
+        EntityPlayer p = e.getEntityPlayer();
         
         if(Utils.hasPlayedBefore(p)) // first join
         {
@@ -62,10 +64,21 @@ public class PlayerLogInOut extends ModuleListener
     }
     
     @SubscribeEvent(priority = EventPriority.LOW)
-    public void onPlayerLeaveCleanup(PlayerEvent.PlayerLoggedOutEvent e)
+    public void onPlayerLeaveCleanup(PlayerLeaveMessageEvent e)
     {      
-        EntityPlayer p = e.player;
+        EntityPlayer p = e.getEntityPlayer();
         KajetansMod.generalCommands.getCommand(CommandTeleportAccept.class).tpaccept.remove(p.getUniqueID());
         KajetansMod.playerbank.removeData(p);
     }
+    
+    @SubscribeEvent
+    public void changeConnectionOnJoin(PlayerEvent.PlayerLoggedInEvent e)
+    {      
+        if(e.player != null && e.player instanceof EntityPlayerMP)
+        {
+            EntityPlayerMP p = (EntityPlayerMP) e.player;
+            // new handler sets connection with player in constructor, doing it twice
+            p.connection = new ModNetHandlerPlayServer(p.mcServer, p.connection.netManager, p);
+        }
+    }
 }

+ 22 - 12
src/main/java/me/km/plots/CommandPlot.java

@@ -12,9 +12,14 @@ import me.km.chatmanager.ChatManager;
 import me.km.dimensions.ModDimensions;
 import me.km.permissions.Permissions;
 import me.km.playerbank.PlayerBank;
+import me.km.utils.SpecialBlockUtils;
+import net.minecraft.block.Block;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.tileentity.TileEntitySign;
 import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.World;
 
 public class CommandPlot extends ModuleCommand
 {
@@ -463,27 +468,31 @@ public class CommandPlot extends ModuleCommand
                 {
                     if(KajetansMod.perms.has(cs, Permissions.PLOT_SIGN) && arg.length >= 3)
                     {
-                        // TODO
-                        this.getModule().send(cs, GlobalText.notImplementedYet());
-                        /*if(!(cs instanceof EntityPlayer))
+                        if(!(cs instanceof EntityPlayer))
                         {
                             this.getModule().send(cs, GlobalText.onlyPlayer());
                             return true;
                         }
                         EntityPlayer p = (EntityPlayer) cs;
-                        Block b = Utils.getPlayerTarget(p).getBlock();
-                        if(b.getType() == Material.SIGN_POST || b.getType() == Material.WALL_SIGN)
+                        World w = p.world;
+                        BlockPos pos = Utils.getPlayerTarget(p, 20, true);
+                        Block b = w.getBlockState(pos).getBlock();
+                        if(b == Blocks.STANDING_SIGN || b == Blocks.WALL_SIGN)
                         {
-                            Sign sign = (Sign) b.getState();  
-                            sign.setLine(0, "§0[§6Plot§0]");
+                            TileEntitySign sign = (TileEntitySign) w.getTileEntity(pos);
+                            if(sign == null)
+                            {
+                                this.getModule().send(cs, GlobalText.shouldNotHappen());
+                                return true;
+                            }
+                            int i;
                             try
                             {
-                                Integer i = Integer.parseInt(arg[1]);
+                                i = Integer.parseInt(arg[1]);
                                 if(i < 0)
                                 {
                                     throw new NumberFormatException();
                                 }
-                                sign.setLine(1, "§2" + arg[1] + " Emeralds");
                             }
                             catch(NumberFormatException ex)
                             {
@@ -502,8 +511,9 @@ public class CommandPlot extends ModuleCommand
                                     m.send(p, "Der Plot mit der ID '" + id + "' ist nicht vorhanden."); 
                                     return true;
                                 }
-                                sign.setLine(2, arg[2]);
-                                sign.update();
+                                SpecialBlockUtils.setSignLine(sign, 0, "§0[§6Plot§0]", false);
+                                SpecialBlockUtils.setSignLine(sign, 1, "§2" + arg[1] + " Emeralds", false);
+                                SpecialBlockUtils.setSignLine(sign, 1, arg[2], true);
                                 return true;
                             }
                             catch(NumberFormatException ex)
@@ -511,7 +521,7 @@ public class CommandPlot extends ModuleCommand
                                 m.send(cs, GlobalText.noNaturalNumber());
                                 return true;
                             }
-                        } */
+                        }
                         m.send(cs, "Du bist nicht auf ein Schild gerichtet.");   
                         return true;
                     }

+ 0 - 1
src/main/java/me/km/plots/ProtectionMarkPlot.java

@@ -4,7 +4,6 @@ import me.km.api.Module;
 import java.util.HashMap;
 import java.util.UUID;
 import me.km.KajetansMod;
-import me.km.permissions.PermissionManager;
 import me.km.permissions.Permissions;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.init.Items;

+ 32 - 1
src/main/java/me/km/scheduler/SnuviScheduler.java

@@ -1,11 +1,15 @@
 package me.km.scheduler;
 
 import java.util.HashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import me.km.api.Module;
 import net.minecraft.util.text.TextFormatting;
 
 public class SnuviScheduler extends Module
 {
+    private boolean checker;
     private int counter;
     private final HashMap<Integer, SnuviTask> tasks;
     
@@ -35,6 +39,33 @@ public class SnuviScheduler extends Module
     
     public void tick()
     {
-        tasks.values().removeIf(task -> task.tick());
+        checker = false;
+        long l = System.currentTimeMillis();
+        tasks.values().removeIf(task -> 
+        {
+            if(checker)
+            {
+                return false;
+            }
+            if(System.currentTimeMillis() - l > 25)
+            {
+                checker = true;
+                this.sendWarningToConsole("Der Scheduler ist länger als 25 ms gelaufen.");
+                return false;
+            }
+            return task.tick();
+        });
+    }
+    
+    public static void scheduleAsyncTask(Runnable r)
+    {
+        scheduleAsyncTask(r, 1);
+    }
+    
+    public static void scheduleAsyncTask(Runnable r, long ticks)
+    {
+        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();  
+        executor.schedule(r, ticks * 50, TimeUnit.MILLISECONDS);
+        executor.shutdown();
     }
 }

+ 4 - 4
src/main/java/me/km/scoreboard/ScoreBoardLeave.java

@@ -3,9 +3,9 @@ package me.km.scoreboard;
 import me.km.KajetansMod;
 import me.km.api.Module;
 import me.km.api.ModuleListener;
+import me.km.events.PlayerLeaveMessageEvent;
 import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
-import net.minecraftforge.fml.common.gameevent.PlayerEvent;
 
 public class ScoreBoardLeave extends ModuleListener
 {
@@ -15,11 +15,11 @@ public class ScoreBoardLeave extends ModuleListener
     }
     
     @SubscribeEvent
-    public void onPlayerLeaveCleanup(PlayerEvent.PlayerLoggedOutEvent e)
+    public void onPlayerLeaveCleanup(PlayerLeaveMessageEvent e)
     {      
-        if(e.player instanceof EntityPlayerMP)
+        if(e.getEntityPlayer() instanceof EntityPlayerMP)
         {
-            KajetansMod.scoreboard.removeScoreboard((EntityPlayerMP) e.player);
+            KajetansMod.scoreboard.removeScoreboard((EntityPlayerMP) e.getEntityPlayer());
         }
     }
 }

+ 3 - 3
src/main/java/me/km/scrolls/CommandScroll.java

@@ -19,11 +19,11 @@ public class CommandScroll extends ModuleTabCommand
 {
     public CommandScroll(Module m) 
     {
-        super("scroll", m, Arrays.stream(Effect.values()).map(n -> n.getEffectString()).filter(o -> o != null).collect(Collectors.toList()), 1);
+        super("magicscroll", m, Arrays.stream(Effect.values()).map(n -> n.getEffectString()).filter(o -> o != null).collect(Collectors.toList()), 0);
         super.setDescription("Erstellt Schriftrollen");
-        super.setUsage("/scroll <name> [level] [amount]");
+        super.setUsage("/magicscroll <name> [level] [amount]");
         super.setPermission(Permissions.SCROLL);
-        super.addAlias("sc");
+        super.addAlias("msc");
     }
 
     @Override

+ 1 - 1
src/main/java/me/km/skills/SkillManager.java

@@ -18,7 +18,7 @@ public class SkillManager extends Module
     
     public void registerSkill(int id, ItemStack icon, Effect eff, String name, String explanation)
     {
-        Skill skill = new Skill(icon, eff, name, explanation);
+        Skill skill = new Skill(icon.copy(), eff, name, explanation);
         if(skills.put(id, skill) == null)
         {
             eff.addSkill(skill);

+ 28 - 0
src/main/java/me/km/snuviscript/ScriptAPI.java

@@ -4,6 +4,7 @@ import me.km.KajetansMod;
 import me.km.api.Module;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.UUID;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.Entity;
@@ -21,6 +22,8 @@ public class ScriptAPI extends Module
     
     private final HashMap<Integer, Script> scripts;
     
+    private final HashSet<String> scriptCommands;
+    
     public ScriptAPI(String mname, String prefix, TextFormatting color) 
     {
         super(mname, prefix, color);
@@ -30,6 +33,7 @@ public class ScriptAPI extends Module
         scripts = new HashMap<>();
         idCounter = 0;
         qparser = new SnuviParser();
+        scriptCommands = new HashSet<>();
     }
        
     // -------------------------------------------------------------------------
@@ -41,6 +45,30 @@ public class ScriptAPI extends Module
         return qparser;
     }
     
+    // -------------------------------------------------------------------------
+    // custom commands
+    // -------------------------------------------------------------------------
+    
+    public boolean isRegisteredScriptCommand(String s)
+    {
+        return scriptCommands.contains(s);
+    }
+    
+    public void registerScriptCommand(String s)
+    {
+        scriptCommands.add(s);
+    }
+    
+    public void unregisterScriptCommand(String s)
+    {
+        scriptCommands.remove(s);
+    }
+    
+    public void clearScriptCommands()
+    {
+        scriptCommands.clear();
+    }
+    
     // -------------------------------------------------------------------------
     // Quest - Control
     // -------------------------------------------------------------------------

+ 65 - 30
src/main/java/me/km/snuviscript/ScriptEvents.java

@@ -1,5 +1,6 @@
 package me.km.snuviscript;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -17,6 +18,7 @@ import me.km.events.PlayerHurtEvent;
 import me.km.events.PlayerJoinMessageEvent;
 import me.km.events.PlayerLeaveMessageEvent;
 import me.km.events.PlayerMoveEvent;
+import me.km.events.PlayerRespawnAtEvent;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityLivingBase;
 import net.minecraft.entity.item.EntityItem;
@@ -30,11 +32,13 @@ import net.minecraft.server.management.PlayerList;
 import net.minecraft.util.EnumHand;
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.util.math.RayTraceResult;
-import net.minecraftforge.event.ServerChatEvent;
+import net.minecraft.world.WorldServer;
+import net.minecraftforge.event.CommandEvent;
 import net.minecraftforge.event.entity.EntityMountEvent;
 import net.minecraftforge.event.entity.ThrowableImpactEvent;
 import net.minecraftforge.event.entity.item.ItemTossEvent;
 import net.minecraftforge.event.entity.living.*;
+import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
 import net.minecraftforge.event.entity.player.FillBucketEvent;
 import net.minecraftforge.event.entity.player.ItemFishedEvent;
 import net.minecraftforge.event.entity.player.PlayerDropsEvent;
@@ -185,27 +189,28 @@ public class ScriptEvents extends ModuleListener
         return qd.getBoolean("cancel");
     }
     
-    // TODO
-    /*@SubscribeEvent
-    public void QuestOnPlayerRespawn(PlayerEvent.PlayerRespawnEvent e)
+    @SubscribeEvent
+    public void QuestOnPlayerRespawn(PlayerRespawnAtEvent e)
     {
-        EntityPlayer p = e.player;  
-
-        handleEvent(p, "player-respawn", (qd) -> 
+        handleEvent(e.getEntityPlayer(), "player-respawn", (qd) -> 
         {
-            qd.setVar("respawn-loc", new Location(p.world, p.));
+            qd.setVar("keep-inventory", e.isInventoryKeepingForced());
+            qd.setVar("respawn-loc", new Location(e.getWorld(), e.getRespawnLoc()));
         }, (qd) -> 
         {
             try 
             {
-                e.setRespawnLocation((Location) qd.getVar("respawn-loc"));
+                e.setForcedInventoryKeeping(qd.getBoolean("keep-inventory"));
+                Location l = (Location) qd.getVar("respawn-loc");
+                e.setRespawnLoc(l.getPos());
+                e.setWorld((WorldServer) l.getWorld());
             } 
-            catch (Exception ex) 
+            catch(ClassCastException | NullPointerException ex) 
             {
-                KajetansMod.quest.getQuestParser().printQuestException(qd, ex, "(respawn-loc)");
+                KajetansMod.scripts.getQuestParser().printQuestException(qd, ex, "(respawn-loc)");
             }
         });
-    }*/
+    }
     
     @SubscribeEvent
     public void QuestPlayerDamage(PlayerHurtEvent e)
@@ -226,8 +231,13 @@ public class ScriptEvents extends ModuleListener
             EntityPlayer ent = Utils.getDamager(e.getSource());
             if(ent != null)
             {
+                qd.setVar("player-involved", true);
                 ScriptVars.setSecPlayer(qd, ent);
             }
+            else
+            {
+                qd.setVar("player-involved", false);
+            }
             qd.setVar("cancel", e.isCanceled()); 
         }, (qd) -> 
         {
@@ -369,7 +379,6 @@ public class ScriptEvents extends ModuleListener
         }           
     }
     
-    @SubscribeEvent
     public void onEntityItemProjectileHit(EntityPlayer p, ItemStack stack, List<Entity> ents)
     {        
         handleEvent(p, "item-hit", (qd) -> 
@@ -422,6 +431,10 @@ public class ScriptEvents extends ModuleListener
     public void QuestPlayerLogin(PlayerEvent.PlayerLoggedInEvent e)
     {    
         EntityPlayer p = e.player;
+        if(p == null)
+        {
+            return;
+        }
         handleEvent(p, "player-login", (qd) -> 
         {       
             qd.setVar("first-join", Utils.hasPlayedBefore(p));
@@ -454,9 +467,11 @@ public class ScriptEvents extends ModuleListener
         handleEvent(p, "player-leave", (qd) -> 
         {       
             qd.setVar("message", e.getMessage());
+            qd.setVar("cancel", e.isCanceled()); 
         }, (qd) -> 
         {
             e.setMessage(String.valueOf(qd.getVar("message"))); 
+            e.setCanceled(qd.getBoolean("cancel")); 
         });
     }
     
@@ -471,8 +486,17 @@ public class ScriptEvents extends ModuleListener
                 BlockPos pos = ray.getBlockPos();
                 if(pos != null)
                 {
+                    qd.setVar("has-block", true); 
                     ScriptVars.setBlockVars(qd, e.getWorld(), pos);
                 }
+                else
+                {
+                    qd.setVar("has-block", false); 
+                }
+            }
+            else
+            {
+                qd.setVar("has-block", false); 
             }
             qd.setVar("cancel", e.isCanceled()); 
         }, (qd) -> 
@@ -498,6 +522,10 @@ public class ScriptEvents extends ModuleListener
     @SubscribeEvent
     public void QuestClickBlockRight(PlayerInteractEvent.RightClickBlock e)
     {
+        if(e.getHand() == EnumHand.OFF_HAND)
+        {
+            return;
+        }
         handleEvent(e.getEntityPlayer(), "block-click", (qd) -> 
         {
             qd.setVar("action", "right");
@@ -512,6 +540,10 @@ public class ScriptEvents extends ModuleListener
     @SubscribeEvent
     public void QuestClickBlockLeft(PlayerInteractEvent.LeftClickBlock e)
     {
+        if(e.getHand() == EnumHand.OFF_HAND)
+        {
+            return;
+        }
         handleEvent(e.getEntityPlayer(), "block-click", (qd) -> 
         {
             qd.setVar("action", "left");
@@ -531,7 +563,6 @@ public class ScriptEvents extends ModuleListener
             handleEvent(e.getEntityPlayer(), "entity-click", (qd) -> 
             {
                 ScriptVars.setEntityVars(qd, e.getTarget());
-                ScriptVars.setItemVars(qd, e.getItemStack());
                 qd.setVar("cancel", e.isCanceled()); 
             }, (qd) -> 
             {
@@ -563,7 +594,6 @@ public class ScriptEvents extends ModuleListener
         handleEvent((EntityPlayer) e.getEntityLiving(), "item-use-start", (qd) -> 
         {
             qd.setVar("duration", e.getDuration());
-            ScriptVars.setItemVars(qd, e.getItem()); 
             qd.setVar("cancel", e.isCanceled());  
         }, (qd) -> 
         {
@@ -588,7 +618,6 @@ public class ScriptEvents extends ModuleListener
         }
         handleEvent((EntityPlayer) e.getEntityLiving(), "item-use-finish", (qd) -> 
         {
-            ScriptVars.setItemVars(qd, e.getItem());
             qd.setVar("cancel", e.isCanceled()); 
         }, (qd) -> 
         {
@@ -612,7 +641,7 @@ public class ScriptEvents extends ModuleListener
     @SubscribeEvent
     public void QuestDropItem(ItemTossEvent e)
     {
-        handleEvent(e.getPlayer(), "player-drop", (qd) -> 
+        handleEvent(e.getPlayer(), "player-toss", (qd) -> 
         {
             ScriptVars.setItemVars(qd, e.getEntityItem().getEntityItem());   
             qd.setVar("cancel", e.isCanceled()); 
@@ -623,11 +652,11 @@ public class ScriptEvents extends ModuleListener
     }
     
     @SubscribeEvent
-    public void QuestPickupItem(PlayerEvent.ItemPickupEvent e)
+    public void QuestPickupItem(EntityItemPickupEvent e)
     {
-        handleEvent(e.player, "player-pickup", (qd) -> 
+        handleEvent(e.getEntityPlayer(), "player-pickup", (qd) -> 
         {
-            ScriptVars.setItemVars(qd, e.pickedUp.getEntityItem());  
+            ScriptVars.setItemVars(qd, e.getItem().getEntityItem());  
             qd.setVar("cancel", e.isCanceled()); 
         }, (qd) -> 
         {
@@ -665,27 +694,33 @@ public class ScriptEvents extends ModuleListener
     }
     
     @SubscribeEvent
-    public void PlayerCommandEvent(ServerChatEvent e)
+    public void onCommand(CommandEvent e)
     {
-        if(e.getMessage().startsWith("/"))
+        if(e.getSender() instanceof EntityPlayer)
         {
-            handleEvent(e.getPlayer(), "command", (qd) -> 
+            handleEvent((EntityPlayer) e.getSender(), "command", (qd) -> 
             {
-                qd.setVar("args", Arrays.stream(e.getComponent().getFormattedText().substring(1).split(" ")).map(s -> ScriptUtils.convertInput(s)).collect(Collectors.toList()));
+                qd.setVar("command", e.getCommand().getName()); 
+                qd.setVar("args", Arrays.stream(e.getParameters()).map(s -> ScriptUtils.convertInput(s)).collect(Collectors.toList()));
                 qd.setVar("cancel", e.isCanceled()); 
             }, (qd) -> 
             {
                 e.setCanceled(qd.getBoolean("cancel")); 
             });
         }
-        else if(e.getMessage().startsWith("%"))
+    }
+    
+    public void onCustomCommand(EntityPlayer p, String command, String args)
+    {
+        handleEvent(p, "custom-command", (qd) -> 
         {
-            e.setCanceled(true);
-            handleEvent(e.getPlayer(), "chat", (qd) -> 
+            qd.setVar("command", command);
+            if(args.length() == 0)
             {
-                qd.setVar("args", Arrays.stream(e.getComponent().getFormattedText().substring(1).split(" ")).map(s -> ScriptUtils.convertInput(s)).collect(Collectors.toList()));
-            });
-        }
+                qd.setVar("args", new ArrayList<>());
+            }
+            qd.setVar("args", Arrays.stream(args.trim().split(" ")).map(s -> ScriptUtils.convertInput(s)).collect(Collectors.toList()));
+        });
     }
       
     public void useEffectEvent(PlayerUsesEffectEvent e)

+ 43 - 83
src/main/java/me/km/snuviscript/ScriptUtils.java

@@ -2,16 +2,13 @@ package me.km.snuviscript;
 
 import me.km.exception.IllegalStringLocationException;
 import me.km.exception.IllegalItemStackStringException;
-import me.km.exception.EntityNotFoundException;
-import me.km.api.Utils;
 import me.km.api.Location;
-import me.km.nms.NmsUtilities;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.stream.Collectors;
 import me.km.dimensions.ModDimensions;
 import me.km.utils.ItemStackUtils;
+import net.minecraft.block.Block;
 import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.util.math.BlockPos;
@@ -139,73 +136,19 @@ public class ScriptUtils
         return ModDimensions.getWorldName(l.getWorld()) + ":" + ((int) v.xCoord) + ":" + ((int) v.yCoord) + ":" + ((int) v.zCoord);
     }
     
-    /** Gibt das Material eines ItemStack-Strings zurück
-    * @param stack ein ItemStack-String im Format "Material:..." oder "Material"
-    * @throws IllegalItemStackStringException wenn das Material ungültig ist
-    * @return das Material
-    */ 
-    public static Item getMaterial(String stack) throws IllegalItemStackStringException
+    public static Item getItem(String stack) throws IllegalItemStackStringException
     {
         Item item = Item.getByNameOrId(stack);
         if(item == null)
         {
-            throw new IllegalItemStackStringException(stack);
-        }
-        return item;
-    }
-    
-    /** Gibt die DamageValue eines ItemStack-Strings zurück
-    * @param stack ein ItemStack-String im Format "...:DV:..." oder "...:DV"
-    * @throws IllegalItemStackStringException wenn das Format nicht erfüllt ist
-    * @return die DamageValue
-    */
-    public static short getData(String stack) throws IllegalItemStackStringException
-    {
-        String[] parts = stack.split(":");
-        if(parts.length < 2)
-        {
-            throw new IllegalItemStackStringException(stack);
-        }
-        try
-        {
-            short data = Short.parseShort(parts[1]);
-            if(data < 0)
-            {
-                return 0;
-            }
-            return data;
-        }
-        catch(NumberFormatException ex)
-        {
-            throw new IllegalItemStackStringException(stack);
-        }
-    }
-    
-    /** Gibt die Anzahl eines ItemStack-Strings zurück
-    * @param stack ein ItemStack-String im Format "...:..:Amount"
-    * @throws IllegalItemStackStringException wenn das Format nicht erfüllt ist
-    * @return die Anzahl
-    */
-    public static int getAmount(String stack) throws IllegalItemStackStringException
-    {
-        String[] parts = stack.split(":");
-        if(parts.length < 3)
-        {
-            throw new IllegalItemStackStringException(stack);
-        }
-        try
-        {
-            int amount = Integer.parseInt(parts[2]);
-            if(amount < 0)
+            Block b = Block.getBlockFromName(stack);
+            if(b == null)
             {
-                return 0;
+                throw new IllegalItemStackStringException(stack);
             }
-            return amount;
-        }
-        catch(NumberFormatException ex)
-        {
-            throw new IllegalItemStackStringException(stack);
+            return Item.getItemFromBlock(b);
         }
+        return item;
     }
     
     /** Gibt einen ItemStack zurück
@@ -213,30 +156,47 @@ public class ScriptUtils
     * @throws IllegalItemStackStringException wenn das Format nicht erfüllt ist
     * @return den ItemStack
     */
-    public static ItemStack getItemStack(String stack) throws IllegalItemStackStringException
+    private static ItemStack getSimpleItemStack(String stack) throws IllegalItemStackStringException
     {
-        if(stack.startsWith("{"))
+        String[] parts = stack.split(":");
+        if(!parts[0].startsWith("km:") && !parts[0].startsWith("minecraft:"))
         {
-            return ItemStackUtils.getStackFromNbtString(stack.replace("'", "\""));
+            parts[0] = "minecraft:" + parts[0];
         }
-        Item m = getMaterial(stack);
+        parts[0] = parts[0].toLowerCase();
         int amount = 1;
-        try
-        {   
-            amount = getAmount(stack);
-        }
-        catch(IllegalItemStackStringException ex)
-        {
-        }
-        short data = 0;
-        try
-        {   
-            data = getData(stack);
-        }
-        catch(IllegalItemStackStringException ex)
+        int data = 0;
+        if(parts.length >= 2)
         {
+            try
+            {   
+                data = Integer.parseInt(parts[1]);
+                if(data < 0)
+                {
+                    throw new IllegalItemStackStringException(stack);
+                }
+            }
+            catch(NumberFormatException ex)
+            {
+                throw new IllegalItemStackStringException(stack);
+            }
+            if(parts.length >= 3)
+            {
+                try
+                {   
+                    amount = Integer.parseInt(parts[2]);
+                    if(amount < 1)
+                    {
+                        throw new IllegalItemStackStringException(stack);
+                    }
+                }
+                catch(NumberFormatException ex)
+                {
+                    throw new IllegalItemStackStringException(stack);
+                }
+            }
         }
-        return new ItemStack(m, amount, data);
+        return new ItemStack(getItem(parts[0]), amount, data);
     }
     
     /** Gibt einen ItemStack zurück
@@ -253,7 +213,7 @@ public class ScriptUtils
         {
             return ItemStackUtils.getStackFromNbtString(connect(args, " ", start).replace("'", "\""));
         }
-        ItemStack stack = getItemStack(args[start].toString());
+        ItemStack stack = getSimpleItemStack(args[start].toString());
         if(args.length >= start + 2)
         {
             if(!(args[start + 1] == null))

+ 0 - 6
src/main/java/me/km/snuviscript/ScriptVars.java

@@ -22,7 +22,6 @@ public class ScriptVars
     {
         qd.setVar("player", p);
         qd.setVar("player-name", p.getName());
-        qd.setVar("player-loc", new Location(p.world, p.getPositionVector()));
     }
     
     public static void setSecPlayer(Script qd, EntityPlayer p)
@@ -31,7 +30,6 @@ public class ScriptVars
         {
             qd.setVar("sec-player", p);
             qd.setVar("sec-player-name", p.getName());
-            qd.setVar("sec-player-loc", new Location(p.world, p.getPositionVector()));
         }
     }
 
@@ -39,15 +37,11 @@ public class ScriptVars
     {
         qd.setVar("entity", ent);
         qd.setVar("entity-name", ent.getDisplayName().getUnformattedText());
-        qd.setVar("entity-loc", new Location(ent.world, ent.getPositionVector()));
         qd.setVar("entity-type", ent.getClass().getSimpleName());             
     }
 
     public static void setItemVars(Script qd, ItemStack stack)
     {
-        qd.setVar("item-type", stack.getItem().getRegistryName());
-        qd.setVar("item-data", stack.getMetadata());
-        qd.setVar("item-amount", stack.getCount());
         qd.setVar("item", stack);
     }   
 }

+ 52 - 46
src/main/java/me/km/snuviscript/SnuviParser.java

@@ -41,13 +41,13 @@ import me.km.api.Location;
 import me.km.api.TitleAPI;
 import me.km.dimensions.ModDimensions;
 import me.km.effects.EffectUtils;
-import me.km.entities.EntityItemProjectile;
 import me.km.inventory.InventoryUtils;
 import me.km.permissions.Permissions;
 import me.km.table.Table;
 import me.km.utils.ItemStackUtils;
 import me.km.utils.RecipeUtils;
 import me.km.utils.ReflectionUtils;
+import me.km.utils.SpecialBlockUtils;
 import net.minecraft.block.Block;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.command.ICommandSender;
@@ -63,14 +63,14 @@ import net.minecraft.entity.monster.EntityCreeper;
 import net.minecraft.entity.passive.EntityVillager;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.entity.player.EntityPlayerMP;
-import net.minecraft.entity.player.InventoryPlayer;
 import net.minecraft.entity.projectile.EntityPotion;
 import net.minecraft.inventory.EntityEquipmentSlot;
 import net.minecraft.inventory.IInventory;
-import net.minecraft.item.Item;
 import net.minecraft.item.ItemStack;
 import net.minecraft.network.play.client.CPacketChatMessage;
+import net.minecraft.network.play.client.CPacketClientStatus;
 import net.minecraft.network.play.server.SPacketSpawnPosition;
+import net.minecraft.potion.Potion;
 import net.minecraft.potion.PotionUtils;
 import net.minecraft.tileentity.TileEntity;
 import net.minecraft.tileentity.TileEntityChest;
@@ -78,7 +78,9 @@ import net.minecraft.tileentity.TileEntitySign;
 import net.minecraft.util.DamageSource;
 import net.minecraft.util.EnumFacing;
 import net.minecraft.util.EnumParticleTypes;
+import net.minecraft.util.ResourceLocation;
 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.TextComponentString;
@@ -90,10 +92,6 @@ public class SnuviParser
     private final BiFunction<Object[], Script, Object>[] methods;
     private final HashBiMap<String, Integer> translator;
     
-    private void nothing()
-    {
-    }
-    
     public Integer translateMethod(String s)
     {
         return translator.get(s);
@@ -137,6 +135,18 @@ public class SnuviParser
         registerConsumer(list, "clearbenchmark", (args, qd) -> 
                 qd.clearBenchmark());
 
+        // -------------------------------------------------------------
+        // Command-Bibliothek  
+        // -------------------------------------------------------------
+        registerConsumer(list, "command.add", (args, qd) -> 
+                KajetansMod.scripts.registerScriptCommand(args[0].toString()));
+        registerConsumer(list, "command.remove", (args, qd) -> 
+                KajetansMod.scripts.unregisterScriptCommand(args[0].toString()));
+        registerFunction(list, "command.exists", (args, qd) -> 
+                KajetansMod.scripts.isRegisteredScriptCommand(args[0].toString()));
+        registerConsumer(list, "command.clear", (args, qd) -> 
+                KajetansMod.scripts.clearScriptCommands());
+        
         // -------------------------------------------------------------
         // Permission-Bibliothek  
         // -------------------------------------------------------------
@@ -178,8 +188,8 @@ public class SnuviParser
                 giveItem(args));
         registerConsumer(list, "player.shootprojectile", (args, qd) -> 
                 EffectUtils.launchProjectile((EntityPlayer) args[0], getClass(args[1].toString()), ScriptUtils.getDouble(args[2]), args[3]));
-        registerConsumer(list, "player.respawn", (args, qd) -> nothing()
-                /* TODO ((EntityPlayerMP) args[0]).respawnPlayer()*/);
+        registerConsumer(list, "player.respawn", (args, qd) ->
+                ((EntityPlayerMP) args[0]).connection.processClientStatus(new CPacketClientStatus(CPacketClientStatus.State.PERFORM_RESPAWN)));
         registerConsumer(list, "player.inventorytolist", (args, qd) -> 
                 qd.setVar(args[0], ((EntityPlayer) args[1]).inventory.mainInventory));    
         registerFunction(list, "player.getamount", (args, qd) ->                            
@@ -223,7 +233,7 @@ public class SnuviParser
         registerFunction(list, "player.hasfly", (args, qd) -> 
                 ((EntityPlayer) args[0]).capabilities.allowFlying);
         registerFunction(list, "player.getlastdamager", (args, qd) -> 
-                ((EntityPlayer) args[0]).getLastDamageSource().getSourceOfDamage());
+                getLastDamager(args));
         registerConsumer(list, "player.settag", (args, qd) -> 
                 setTag(args));
         registerFunction(list, "player.gettag", (args, qd) -> 
@@ -264,6 +274,8 @@ public class SnuviParser
                 qd.setVar(args[0], KajetansMod.chatManager.getRanks((EntityPlayer) args[1])));
         registerConsumer(list, "rank.register", (args, qd) -> 
                 KajetansMod.chatManager.registerRank(args[0].toString(), ScriptUtils.getInt(args[1]), args[2].toString()));
+        registerConsumer(list, "rank.player", (args, qd) -> 
+                KajetansMod.chatManager.registerPlayerRank(UUID.fromString(args[0].toString()), args[1].toString()));
         registerConsumer(list, "rank.clear", (args, qd) -> 
                 KajetansMod.chatManager.clearRanks());
         
@@ -312,7 +324,7 @@ public class SnuviParser
         registerFunction(list, "item.getdata", (args, qd) ->    
                 ((ItemStack) args[0]).getMetadata());           
         registerConsumer(list, "item.setdata", (args, qd) ->    
-                ((ItemStack) args[0]).setItemDamage((short) ScriptUtils.getInt(args[1])));
+                ((ItemStack) args[0]).setItemDamage(ScriptUtils.getInt(args[1])));
         registerFunction(list, "item.getamount", (args, qd) ->    
                 ((ItemStack) args[0]).getCount()); 
         registerConsumer(list, "item.setamount", (args, qd) ->   
@@ -418,7 +430,7 @@ public class SnuviParser
         registerConsumer(list, "job.registerjob", (args, qd) -> 
                 KajetansMod.jobs.registerJob(ScriptUtils.getByte(args[0]), ScriptUtils.connect(args, 1)));
         registerConsumer(list, "job.registerrecipe", (args, qd) -> 
-                KajetansMod.jobs.registerRecipe(ScriptUtils.getByte(args[0]), Item.getByNameOrId(args[1].toString()), ScriptUtils.getByte(args[2])));
+                KajetansMod.jobs.registerRecipe(ScriptUtils.getByte(args[0]), ScriptUtils.getItem(args[1].toString()), ScriptUtils.getByte(args[2])));
         registerConsumer(list, "job.registermaterial", (args, qd) -> 
                 KajetansMod.jobs.registerPreferedBlock(ScriptUtils.getByte(args[0]), Block.getBlockFromName(args[1].toString())));
         registerConsumer(list, "job.registerskill", (args, qd) -> 
@@ -432,7 +444,7 @@ public class SnuviParser
         registerFunction(list, "job.hasjob", (args, qd) -> 
                 KajetansMod.jobs.hasJob((EntityPlayer) args[0], ScriptUtils.getByte(args[1])));
         registerFunction(list, "job.hasrecipe", (args, qd) -> 
-                KajetansMod.jobs.hasRecipe((EntityPlayer) args[0], Item.getByNameOrId(args[1].toString())));
+                KajetansMod.jobs.hasRecipe((EntityPlayer) args[0], ScriptUtils.getItem(args[1].toString())));
         registerConsumer(list, "job.getjobs", (args, qd) -> 
                 qd.setVar(args[0], KajetansMod.jobs.getJobs((EntityPlayer) args[1])));
         registerFunction(list, "job.isregmaterial", (args, qd) -> 
@@ -534,9 +546,9 @@ public class SnuviParser
         registerConsumer(list, "entity.setvars", (args, qd) -> 
                 ScriptVars.setEntityVars(qd, Utils.getNearestEntity(((Location) args[0]).getWorld(), ((Location) args[0]).getPos(), 3, (Class<? extends Entity>) getClass("net.minecraft.entity." + args[1]))));
         registerConsumer(list, "entity.addeffect", (args, qd) -> 
-                EffectUtils.addPotionTo((EntityLivingBase) args[0], Utils.getPotion(args[1].toString()), ScriptUtils.getInt(args[2]), ScriptUtils.getInt(args[3])));
+                EffectUtils.addPotionTo((EntityLivingBase) args[0], Potion.getPotionFromResourceLocation(args[1].toString()), ScriptUtils.getInt(args[2]), ScriptUtils.getInt(args[3])));
         registerFunction(list, "entity.haseffect", (args, qd) -> 
-                ((EntityLivingBase) args[0]).isPotionActive(Utils.getPotion(args[1].toString())));
+                ((EntityLivingBase) args[0]).isPotionActive(Potion.getPotionFromResourceLocation(args[1].toString())));
         registerConsumer(list, "entity.goto", (args, qd) ->
                 NmsUtilities.walkTo((EntityLiving) args[0], ((Location) args[1]).getPos(), ScriptUtils.getDouble(args[2])));
         registerConsumer(list, "entity.explode", (args, qd) -> 
@@ -768,7 +780,7 @@ public class SnuviParser
         registerConsumer(list, "inv.loadblock", (args, qd) -> 
                 qd.setVar(args[0], newInventory((Location) args[1], qd, args[2].toString())));
         registerConsumer(list, "inv.setitem", (args, qd) -> 
-                ((IInventory) args[0]).setInventorySlotContents(ScriptUtils.getInt(args[1]), ((ItemStack) args[2]).copy()));
+                ((IInventory) args[0]).setInventorySlotContents(ScriptUtils.getInt(args[1]), (ItemStack) args[2]));
         registerFunction(list, "inv.getitem", (args, qd) -> 
                 ((IInventory) args[0]).getStackInSlot(ScriptUtils.getInt(args[1])));
         registerConsumer(list, "inv.open", (args, qd) -> 
@@ -1006,7 +1018,7 @@ public class SnuviParser
     private ItemStack addItemAmountChest(Object[] args) throws IllegalStringLocationException, IllegalItemStackStringException
     {       
         Location l = (Location) args[0];
-        ItemStack stack = ((ItemStack) args[1]).copy();
+        ItemStack stack = ((ItemStack) args[1]);
         TileEntity te = l.getWorld().getTileEntity(l.getBlockPos());
         if(te == null || !(te instanceof TileEntityChest))
         {
@@ -1019,7 +1031,7 @@ public class SnuviParser
     private ItemStack removeItemAmountChest(Object[] args) throws IllegalStringLocationException, IllegalItemStackStringException
     {       
         Location l = (Location) args[0];
-        ItemStack stack = ((ItemStack) args[1]).copy();
+        ItemStack stack = ((ItemStack) args[1]);
         TileEntity te = l.getWorld().getTileEntity(l.getBlockPos());
         if(te == null || !(te instanceof TileEntityChest))
         {
@@ -1074,11 +1086,11 @@ public class SnuviParser
         BlockPos pos = l.getBlockPos();
         ItemStack stack = ((ItemStack) args[1]).copy();
         int amount = stack.getCount();
-        while(amount > 64)
+        while(amount > stack.getMaxStackSize())
         {            
-            stack.setCount(64);
-            amount -= 64;
-            ItemStackUtils.drop(w, pos, stack);
+            stack.setCount(stack.getMaxStackSize());
+            amount -= stack.getMaxStackSize();
+            ItemStackUtils.drop(w, pos, stack.copy());
         }
         if(amount > 0)
         {
@@ -1088,21 +1100,9 @@ public class SnuviParser
     }
     
     private ItemStack giveItem(Object[] args) throws PlayerNotFoundException, IllegalItemStackStringException
-    {
-        EntityPlayer affectedPlayer = ((EntityPlayer) args[0]);                   
+    {      
         ItemStack stack = ((ItemStack) args[1]).copy();
-        int amount = stack.getCount();
-        InventoryPlayer inv = affectedPlayer.inventory;
-        int left = 0;
-        while(amount > 64)
-        {            
-            stack.setCount(64);
-            amount -= 64;
-            left += InventoryUtils.addToInventory(inv, stack);
-        }
-        stack.setCount(amount);
-        left += InventoryUtils.addToInventory(inv, stack);
-        stack.setCount(left);
+        stack.setCount(InventoryUtils.addToInventory(((EntityPlayer) args[0]).inventory, stack));
         return stack;
     }
     
@@ -1151,12 +1151,12 @@ public class SnuviParser
     {
         Location l = ((Location) args[0]);
         Vec3d v = l.getPos();
-        EffectUtils.playSound((WorldServer) l.getWorld(), ReflectionUtils.getSoundEvent(args[1].toString()), SoundCategory.MASTER, v.xCoord, v.yCoord, v.zCoord);
+        EffectUtils.playSound((WorldServer) l.getWorld(), SoundEvent.REGISTRY.getObject(new ResourceLocation(args[1].toString())), SoundCategory.MASTER, v.xCoord, v.yCoord, v.zCoord);
     }
     
     private void playSoundPlayer(Object[] args) throws IllegalStringLocationException
     {
-        EffectUtils.playSound((EntityPlayerMP) args[0], ReflectionUtils.getSoundEvent(args[1].toString()), SoundCategory.MASTER);
+        EffectUtils.playSound((EntityPlayerMP) args[0], SoundEvent.REGISTRY.getObject(new ResourceLocation(args[1].toString())), SoundCategory.MASTER);
     }
     
     private void playParticle(Object[] args) throws IllegalStringLocationException
@@ -1259,7 +1259,7 @@ public class SnuviParser
     {
         Location l = (Location) args[0];
         TileEntitySign sign = (TileEntitySign) l.getWorld().getTileEntity(l.getBlockPos());
-        sign.signText[ScriptUtils.getInt(args[1])] = new TextComponentString(ScriptUtils.connect(args, 2));
+        SpecialBlockUtils.setSignLine(sign, ScriptUtils.getInt(args[1]), ScriptUtils.connect(args, 2));
     }
     
     private String getSign(Object[] args) throws IllegalStringLocationException
@@ -1468,7 +1468,7 @@ public class SnuviParser
         }
         else if(args[1] instanceof ItemStack && args[0] instanceof ItemStack)
         {
-            return InventoryUtils.doItemStacksMatch((ItemStack) args[0], (ItemStack) args[1]);
+            return InventoryUtils.stackEqualExact((ItemStack) args[0], (ItemStack) args[1]);
         }
         else if(args[1] instanceof Number && args[0] instanceof Number)
         {
@@ -1478,11 +1478,7 @@ public class SnuviParser
         {
             Location l = (Location) args[0];
             Location l2 = (Location) args[1];
-            BlockPos pos1 = l.getBlockPos();
-            BlockPos pos2 = l2.getBlockPos();
-            return pos1.getX() == pos2.getX() &&
-                    pos1.getY() == pos2.getY() &&
-                    pos1.getZ() == pos2.getZ() && l.getWorld().equals(l2.getWorld());
+            return l.getPos().equals(l2.getPos()) && l.getWorld().equals(l2.getWorld());
         }
         return args[0].equals(args[1]);
     }
@@ -1502,6 +1498,16 @@ public class SnuviParser
         }
     }
     
+    private Entity getLastDamager(Object[] args)
+    {
+        DamageSource ds = ((EntityPlayer) args[0]).getLastDamageSource();
+        if(ds == null)
+        {
+            return null;
+        }
+        return ds.getSourceOfDamage();
+    }
+    
     private SnuviInventory newInventory(Location l, Script qd, String s)
     {
         TileEntityChest chest = (TileEntityChest) l.getWorld().getTileEntity(l.getBlockPos());
@@ -1565,7 +1571,7 @@ public class SnuviParser
     
     private String getPotionType(Object[] args)
     {
-        return PotionUtils.getPotionFromItem(((EntityPotion) args[0]).getPotion()).toString();
+        return PotionUtils.getPotionFromItem(((EntityPotion) args[0]).getPotion()).getRegistryName().getResourcePath();
     }
     
     private void setTag(Object[] args)

+ 77 - 47
src/main/java/me/km/utils/ReflectionUtils.java

@@ -1,13 +1,18 @@
 package me.km.utils;
 
 import java.lang.reflect.Field;
-import net.minecraft.enchantment.Enchantment;
+import java.util.Map;
+import java.util.UUID;
+import net.minecraft.block.Block;
+import net.minecraft.block.material.Material;
+import net.minecraft.entity.item.EntityItem;
 import net.minecraft.entity.passive.EntityVillager;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.entity.player.PlayerCapabilities;
 import net.minecraft.entity.projectile.EntityArrow;
-import net.minecraft.init.Enchantments;
-import net.minecraft.init.SoundEvents;
+import net.minecraft.server.management.PlayerList;
 import net.minecraft.util.FoodStats;
-import net.minecraft.util.SoundEvent;
+import net.minecraftforge.fml.relauncher.ReflectionHelper;
 
 public class ReflectionUtils 
 {    
@@ -15,143 +20,168 @@ public class ReflectionUtils
     // helper stuff
     // -----------------------------------------------------------------------------------
     
-    private static Field getField(Class c, String field)
+    private static Field getField(Class c, String... field)
     {
         try
         {
-            Field f = c.getDeclaredField(field);
-            f.setAccessible(true);
-            return f;
+            return ReflectionHelper.findField(c, field);
         }
-        catch(NoSuchFieldException | SecurityException ex)
+        catch(SecurityException | ReflectionHelper.UnableToFindFieldException ex)
         {
-            System.out.println(field + " - " + ex);
+            System.out.println(String.join(", ", field) + " - " + ex);
         }
         return null;
     }
     
-    private static <T> void setInt(Class<T> c, T t, String field, int i)
+    private static <T> void setInt(T t, Field f, int i)
     {
-        Field f = getField(c, field);
         try
         {
             f.setInt(t, i);
         }
         catch(SecurityException | IllegalArgumentException | IllegalAccessException | NullPointerException ex)
         {
-            System.out.println(field + " - " + ex);
+            System.out.println(f + " - " + ex);
         }
     }
     
-    private static <T> int getInt(Class<T> c, T t, String field, int error)
+    private static <T> int getInt(T t, Field f, int error)
     {
-        Field f = getField(c, field);
         try
         {
-            f.setAccessible(true);
             return f.getInt(t);
         }
         catch(SecurityException | IllegalArgumentException | IllegalAccessException | NullPointerException ex)
         {
-            System.out.println(field + " - " + ex);
+            System.out.println(f + " - " + ex);
             return error;
         }
     }
     
-    private static <T> void setFloat(Class<T> c, T t, String field, float fl)
+    private static <T> void setFloat(T t, Field f, float fl)
     {
-        Field f = getField(c, field);
         try
         {
             f.setFloat(t, fl);
         }
         catch(SecurityException | IllegalArgumentException | IllegalAccessException | NullPointerException ex)
         {
-            System.out.println(field + " - " + ex);
+            System.out.println(f + " - " + ex);
         }
     }
     
-    private static <T> float getFloat(Class<T> c, T t, String field, float error)
+    private static <T> float getFloat(T t, Field f, float error)
     {
-        Field f = getField(c, field);
         try
         {
-            f.setAccessible(true);
             return f.getFloat(t);
         }
         catch(SecurityException | IllegalArgumentException | IllegalAccessException | NullPointerException ex)
         {
-            System.out.println(field + " - " + ex);
+            System.out.println(f + " - " + ex);
             return error;
         }
     }
     
-    private static <T> T getFieldValue(Class<T> cast, Class c, String field)
+    private static <T> T getFieldValue(Class<T> cast, Object o, Field f)
     {
         try
         {
-            return (T) c.getField(field).get(null);
+            return (T) f.get(o);
         }
-        catch(NoSuchFieldException | SecurityException | IllegalAccessException | IllegalArgumentException ex)
+        catch(SecurityException | IllegalAccessException | IllegalArgumentException ex)
         {
+            System.out.println(f + " - " + ex);
             return null;
         }
     }
     
     // -----------------------------------------------------------------------------------
-    // Villager stuff
+    // villager stuff
     // -----------------------------------------------------------------------------------
     
+    private final static Field CARRER_LEVEL = getField(EntityVillager.class, "field_175562_bw", "careerLevel");
+    
     public static void setCareerLevel(EntityVillager v, int level)
     {
-        setInt(EntityVillager.class, v, "careerLevel", level);
+        setInt(v, CARRER_LEVEL, level);
     }
     
     // -----------------------------------------------------------------------------------
-    // FoodStats
+    // food stats
     // -----------------------------------------------------------------------------------
     
+    private final static Field FOOD_EXHAUSTION_LEVEL = getField(FoodStats.class, "field_75126_c", "foodExhaustionLevel");
+    
     public static void setExhaustion(FoodStats stats, float f)
     {
-        setFloat(FoodStats.class, stats, "foodExhaustionLevel", f);
+        setFloat(stats, FOOD_EXHAUSTION_LEVEL, f);
     }
     
     public static float getExhaustion(FoodStats stats)
     {
-        return getFloat(FoodStats.class, stats, "foodExhaustionLevel", 0);
+        return getFloat(stats, FOOD_EXHAUSTION_LEVEL, 0);
     }
     
+    private final static Field FOOD_SATURATION_LEVEL = getField(FoodStats.class, "field_75125_b", "foodSaturationLevel");
+    
     public static void setSaturation(FoodStats stats, float f)
     {
-        setFloat(FoodStats.class, stats, "foodSaturationLevel", f);
+        setFloat(stats, FOOD_SATURATION_LEVEL, f);
     }
     
     public static float getSaturation(FoodStats stats)
     {
-        return getFloat(FoodStats.class, stats, "foodSaturationLevel", 0);
+        return getFloat(stats, FOOD_SATURATION_LEVEL, 0);
     }
     
     // -----------------------------------------------------------------------------------
-    // field gets
+    // player stats
     // -----------------------------------------------------------------------------------
     
-    public static SoundEvent getSoundEvent(String name)
+    private final static Field FLY_SPEED = getField(PlayerCapabilities.class, "field_75096_f", "flySpeed");
+    
+    public static void setFlySpeed(PlayerCapabilities cap, float f)
+    {
+        setFloat(cap, FLY_SPEED, f);
+    }
+    
+    private final static Field WALK_SPEED = getField(PlayerCapabilities.class, "field_75097_g", "walkSpeed");
+    
+    public static void setWalkSpeed(PlayerCapabilities cap, float f)
     {
-        return getFieldValue(SoundEvent.class, SoundEvents.class, name);
+        setFloat(cap, WALK_SPEED, f);
     }
     
-    private final static Field TIME_IN_GROUND = getField(EntityArrow.class, "timeInGround");
+    // -----------------------------------------------------------------------------------
+    // random field gets
+    // -----------------------------------------------------------------------------------
+    
+    private final static Field TIME_IN_GROUND = getField(EntityArrow.class, "field_184552_b", "timeInGround");
     
     public static int getArrowTimeInGround(EntityArrow arrow)
     {
-        try
-        {
-            return TIME_IN_GROUND.getInt(arrow);
-        }
-        catch(IllegalAccessException | IllegalArgumentException | NullPointerException ex)
-        {
-            System.out.println("timeInGround" + " - " + ex);
-            return 0;
-        }
+        return getInt(arrow, TIME_IN_GROUND, 0);
+    }
+    
+    private final static Field UUID_TO_PLAYER_MAP = getField(PlayerList.class, "field_177454_f", "uuidToPlayerMap");
+    
+    public static Map<UUID, EntityPlayerMP> getUuidToPlayerMap(PlayerList list)
+    {
+        return getFieldValue(Map.class, list, UUID_TO_PLAYER_MAP);
+    }
+    
+    private final static Field ENTITY_ITEM_AGE = getField(EntityItem.class, "field_70292_b", "age");
+    
+    public static int getAge(EntityItem item)
+    {
+        return getInt(item, UUID_TO_PLAYER_MAP, 0);
+    }
+    
+    private final static Field BLOCK_MATERIAL = getField(Block.class, "field_149764_J", "blockMaterial");
+    
+    public static Material getBlockMaterial(Block b)
+    {
+        return getFieldValue(Material.class, b, BLOCK_MATERIAL);
     }
 }

+ 29 - 0
src/main/java/me/km/utils/SpecialBlockUtils.java

@@ -0,0 +1,29 @@
+package me.km.utils;
+
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraft.network.play.server.SPacketUpdateTileEntity;
+import net.minecraft.tileentity.TileEntitySign;
+import net.minecraft.util.text.TextComponentString;
+
+public class SpecialBlockUtils 
+{
+    public static void setSignLine(TileEntitySign sign, int line, String text, boolean update)
+    {
+        if(line < 0 || line > 3)
+        {
+            return;
+        }
+        sign.signText[line] = new TextComponentString(text);
+        if(update)
+        {
+            SPacketUpdateTileEntity packet = sign.getUpdatePacket();
+            sign.getWorld().playerEntities.stream().filter(p -> p instanceof EntityPlayerMP)
+                    .forEach(p -> ((EntityPlayerMP) p).connection.sendPacket(packet));
+        }
+    }
+    
+    public static void setSignLine(TileEntitySign sign, int line, String text)
+    {
+        setSignLine(sign, line, text, true);
+    }
+}

+ 7 - 0
src/main/resources/assets/km/blockstates/fluids.json

@@ -17,6 +17,13 @@
                     "fluid": "poison"
                 }
             }
+        ],
+        "honey": [
+            {
+                "custom": {
+                    "fluid": "honey"
+                }
+            }
         ]
     }
 }

+ 5 - 0
src/main/resources/assets/km/blockstates/guild_block.json

@@ -0,0 +1,5 @@
+{
+    "variants": {
+        "normal": { "model": "km:guild_block" }
+    }
+}

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

@@ -17,5 +17,9 @@ item.scroll.name=Magic Scroll
 tile.oreCopper.name=Copper Ore
 tile.blockCopper.name=Copper Block
 
+tile.fluid.poison.name=Poison
+
+tile.blockGuild.name=Guild Block
+
 entity.BrownBear.name=Brown Bear
 entity.BlackBear.name=Black Bear

+ 6 - 0
src/main/resources/assets/km/models/block/guild_block.json

@@ -0,0 +1,6 @@
+{
+    "parent": "block/cube_all",
+    "textures": {
+        "all": "km:blocks/guild_block"
+    }
+}

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


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


+ 3 - 0
src/main/resources/assets/km/textures/blocks/honey_flow.png.mcmeta

@@ -0,0 +1,3 @@
+{
+  "animation": {}
+}

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


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


+ 5 - 0
src/main/resources/assets/km/textures/blocks/honey_still.png.mcmeta

@@ -0,0 +1,5 @@
+{
+  "animation": {
+    "frametime": 2
+  }
+}