Kaynağa Gözat

async worker for databank writes in snuviscript, several bugfixes, resitant grass

Kajetan Johannes Hammerle 6 yıl önce
ebeveyn
işleme
f97d8d61db
31 değiştirilmiş dosya ile 542 ekleme ve 347 silme
  1. 27 0
      src/main/java/me/km/ClientProxy.java
  2. 9 29
      src/main/java/me/km/KajetansMod.java
  3. 36 42
      src/main/java/me/km/api/Utils.java
  4. 1 17
      src/main/java/me/km/blockprotections/BlockProtectionBank.java
  5. 1 73
      src/main/java/me/km/blockprotections/CommandBlock.java
  6. 159 0
      src/main/java/me/km/blocks/BlockResistantTallGrass.java
  7. 5 0
      src/main/java/me/km/blocks/ModBlocks.java
  8. 9 46
      src/main/java/me/km/chatchannel/ChatChannel.java
  9. 1 1
      src/main/java/me/km/commands/CommandCoords.java
  10. 1 1
      src/main/java/me/km/commands/CommandGameMode.java
  11. 1 1
      src/main/java/me/km/commands/CommandSetBed.java
  12. 1 1
      src/main/java/me/km/commands/CommandSign.java
  13. 1 1
      src/main/java/me/km/commands/CommandSpawner.java
  14. 1 1
      src/main/java/me/km/commands/CommandSummon.java
  15. 3 3
      src/main/java/me/km/commands/CommandTempBan.java
  16. 0 5
      src/main/java/me/km/datatools/DataToolsEvents.java
  17. 1 1
      src/main/java/me/km/effects/active/Elevation.java
  18. 1 1
      src/main/java/me/km/effects/active/Explosion.java
  19. 1 1
      src/main/java/me/km/effects/active/Thor.java
  20. 1 1
      src/main/java/me/km/effects/active/VineTrap.java
  21. 0 20
      src/main/java/me/km/jobsystem/LimitedDataStorage.java
  22. 2 1
      src/main/java/me/km/permissions/PermissionManager.java
  23. 0 1
      src/main/java/me/km/permissions/Permissions.java
  24. 0 4
      src/main/java/me/km/playerbank/PlayerLogInOut.java
  25. 101 0
      src/main/java/me/km/scheduler/AsyncWorker.java
  26. 15 13
      src/main/java/me/km/scheduler/SnuviScheduler.java
  27. 149 80
      src/main/java/me/km/snuviscript/MinecraftFunctions.java
  28. 2 3
      src/main/java/me/km/snuviscript/ScriptEvents.java
  29. 5 0
      src/main/resources/assets/km/blockstates/rtall_grass.json
  30. 2 0
      src/main/resources/assets/km/lang/en_US.lang
  31. 6 0
      src/main/resources/assets/km/models/block/rtall_grass.json

+ 27 - 0
src/main/java/me/km/ClientProxy.java

@@ -2,6 +2,7 @@ package me.km;
 
 import java.awt.Color;
 import java.lang.reflect.Field;
+import javax.annotation.Nullable;
 import me.km.blocks.ModBlocks;
 import me.km.blocks.cauldron.TileEntityCauldron;
 import me.km.entities.ModEntities;
@@ -13,6 +14,7 @@ import me.km.items.ModelHat;
 import me.km.networking.KeyManager;
 import me.km.utils.ReflectionUtils;
 import net.minecraft.block.Block;
+import net.minecraft.block.BlockTallGrass;
 import net.minecraft.block.state.IBlockState;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.model.ModelBiped;
@@ -20,16 +22,21 @@ import net.minecraft.client.renderer.block.model.ModelBakery;
 import net.minecraft.client.renderer.block.model.ModelResourceLocation;
 import net.minecraft.client.renderer.block.statemap.StateMapperBase;
 import net.minecraft.client.renderer.color.BlockColors;
+import net.minecraft.client.renderer.color.IBlockColor;
 import net.minecraft.client.renderer.color.ItemColors;
 import net.minecraft.client.renderer.entity.Render;
 import net.minecraft.client.resources.FoliageColorReloadListener;
 import net.minecraft.client.resources.GrassColorReloadListener;
 import net.minecraft.entity.Entity;
+import net.minecraft.init.Blocks;
 import net.minecraft.item.Item;
+import net.minecraft.item.ItemBlock;
 import net.minecraft.item.ItemStack;
 import net.minecraft.util.ResourceLocation;
 import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.ColorizerGrass;
 import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.biome.BiomeColorHelper;
 import net.minecraftforge.client.model.ModelLoader;
 import net.minecraftforge.common.MinecraftForge;
 import net.minecraftforge.fluids.IFluidBlock;
@@ -94,6 +101,20 @@ public class ClientProxy extends CommonProxy
             return -16777216 | c.getRed() << 16 | c.getGreen() << 8 | c.getBlue();
         }, ModBlocks.cauldronOak, ModBlocks.cauldronAcacia, ModBlocks.cauldronBigOak, ModBlocks.cauldronBirch, ModBlocks.cauldronJungle, ModBlocks.cauldronSpruce);
 
+        IBlockColor tallGrass = (IBlockState state, IBlockAccess w, BlockPos pos, int tintIndex) ->
+        {
+            if(w != null && pos != null)
+            {
+                return BiomeColorHelper.getGrassColorAtPos(w, pos);
+            }
+            else
+            {
+                return ColorizerGrass.getGrassColor(0.5D, 1.0D);
+            }
+        };
+        
+        bColors.registerBlockColorHandler(tallGrass, ModBlocks.tallGrass);
+        
         /*bColors.registerBlockColorHandler((IBlockState state, IBlockAccess w, BlockPos pos, int ti) -> 
             w != null && pos != null ? BiomeColorHelper.getFoliageColorAtPos(w, pos) : ColorizerFoliage.getFoliageColorBasic(), 
                 Blocks.LEAVES, ModBlocks.apricotLeaves, ModBlocks.pearLeaves, ModBlocks.plumLeaves);*/
@@ -103,6 +124,12 @@ public class ClientProxy extends CommonProxy
         iColors.registerItemColorHandler((ItemStack stack, int tintIndex) -> tintIndex > 0 ? -1 : ((ItemGemStone) stack.getItem()).getColor(stack), 
                 ModItems.gemStone, ModItems.rawGemStone, ModItems.flawlessGemStone);
         
+        iColors.registerItemColorHandler((ItemStack stack, int tintIndex) -> 
+        {
+            IBlockState state = ((ItemBlock) stack.getItem()).getBlock().getStateFromMeta(stack.getMetadata());
+            return tallGrass.colorMultiplier(state, null, null, tintIndex);
+        }, ModBlocks.tallGrass);
+        
         /*iColors.registerItemColorHandler((ItemStack stack, int tintIndex) ->
         {
             IBlockState iblockstate = ((ItemBlock) stack.getItem()).getBlock().getStateFromMeta(stack.getMetadata());

+ 9 - 29
src/main/java/me/km/KajetansMod.java

@@ -3,6 +3,7 @@ package me.km;
 import me.kcm.command.ModServerCommandManager;
 import me.km.api.Module;
 import me.km.api.SimpleConfig;
+import me.km.api.Utils;
 import me.km.blockprotections.BlockProtectionBank;
 import me.km.chatmanager.ChatManager;
 import me.km.data.DataManager;
@@ -20,6 +21,8 @@ import me.km.skills.SkillManager;
 import me.km.snuviscript.ScriptModule;
 import me.km.snuviscript.ScriptBank;
 import net.minecraft.server.MinecraftServer;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.util.text.TextComponentString;
 import net.minecraft.util.text.TextFormatting;
 import net.minecraftforge.fluids.FluidRegistry;
 import net.minecraftforge.fml.common.Mod;
@@ -67,7 +70,7 @@ public class KajetansMod
 
     public static final String MODID = "km";
     public static final String NAME = "Kajetans Mod";
-    public static final String VERSION = "0.0.33";
+    public static final String VERSION = "0.0.34";
 
     @Mod.Instance(MODID)
     public static KajetansMod instance;
@@ -93,39 +96,15 @@ public class KajetansMod
         
         DamageUtils.init();
         
-        /*net.minecraftforge.common.MinecraftForge.EVENT_BUS.register(new Object()
+        net.minecraftforge.common.MinecraftForge.EVENT_BUS.register(new Object()
             {
                 @net.minecraftforge.fml.common.eventhandler.SubscribeEvent
                 public void wusi2(net.minecraftforge.event.ServerChatEvent e) 
                 {
-                    try
-                    {
-                        Field f = BlockStateContainer.class.getDeclaredField("storage");
-                        f.setAccessible(true);
-                        
-                        Field bit = BlockStateContainer.class.getDeclaredField("bits");
-                        bit.setAccessible(true);
-                        
-                        Field palette = BlockStateContainer.class.getDeclaredField("palette");
-                        palette.setAccessible(true);
-                        
-                        
-                        Chunk c = e.getPlayer().getServerWorld().getChunkFromBlockCoords(e.getPlayer().getPosition());
-                        System.out.println(c.x + " " + c.z);
-                        ExtendedBlockStorage st = c.getBlockStorageArray()[(int) (e.getPlayer().posY / 16)];
-                        BitArray array = (BitArray) f.get(st.getData());
-
-                        System.out.println(array.getBackingLongArray().length);
-                        System.out.println(array.size());
-                        System.out.println(bit.get(st.getData()));
-                        System.out.println(palette.get(st.getData()));
-                    }
-                    catch(Exception ex)
-                    {
-                        ex.printStackTrace();
-                    }
+                    BlockPos pos = Utils.getTargetBlock(e.getPlayer());
+                    e.getPlayer().sendMessage(new TextComponentString(pos.toString()));
                 }
-            });*/
+            });
     }
     
     @Mod.EventHandler
@@ -283,6 +262,7 @@ public class KajetansMod
         }
         scripts.startScript("endscript");
         databank.closeDataBankConnection();
+        scheduler.getWorker().stop();
     }
 
     /*public static void main(String[] args)

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

@@ -47,7 +47,6 @@ import net.minecraft.util.math.Vec3d;
 import net.minecraft.world.World;
 import net.minecraft.item.ItemStack;
 import net.minecraft.item.ItemSword; 
-import net.minecraft.item.ItemTool;
 import net.minecraft.nbt.NBTTagCompound;
 import net.minecraft.nbt.NBTUtil;
 import net.minecraft.network.play.server.SPacketEntityVelocity;
@@ -382,12 +381,7 @@ public class Utils
     // -------------------------------------------------------------------------
     // Entities
     // -------------------------------------------------------------------------
-    
-    public static Vec3d getEyeLocation(Entity ent) 
-    {
-        return ent.getPositionVector().addVector(0, ent.getEyeHeight(), 0);
-    }
-    
+       
     public static void teleportEntity(Entity ent, Location l)
     {
         int dim = l.getWorld().provider.getDimension();
@@ -526,21 +520,31 @@ public class Utils
         return Math.max(Math.max(lowerX, lowerY), lowerZ) < Math.min(Math.min(upperX, upperY), upperZ);
     }
     
-    @SuppressWarnings("unchecked")
-    public static <T extends Entity> T getTargetedEntity(EntityPlayer p, 
-            double radius, double mX, double mY, double mZ, Class<T> type)
+    public static Vec3d getTargetVector(Entity ent, double range)
     {
-        World w = p.getEntityWorld();
-        Vec3d l = getPlayerTargetVector(p, radius, false);
-        Vec3d eye = getEyeLocation(p);
-        if(mX != 0 || mY != 0 || mZ != 0)
+        if(range > 128)
         {
-            Random r = p.getRNG();
-            mX *= r.nextDouble();
-            mY *= r.nextDouble();
-            mZ *= r.nextDouble();
+            range = 128;
+        }
+        World w = ent.getEntityWorld();
+        Vec3d start = ent.getPositionEyes(1.0f);
+        Vec3d look = ent.getLookVec();
+        Vec3d end = start.addVector(look.x * range, look.y * range, look.z * range);   
+        RayTraceResult ray = w.rayTraceBlocks(start, end, false, true, true);
+        if(ray == null || ray.hitVec == null)
+        {
+            return end;
         }
-        Vec3d unit = new Vec3d(l.x - eye.x + mX, l.y - eye.y + mY, l.z - eye.z + mZ);
+        return ray.hitVec;   
+    }
+    
+    @SuppressWarnings("unchecked")
+    public static <T extends Entity> T getTargetedEntity(EntityPlayer p, double radius, Class<T> type)
+    {
+        World w = p.getEntityWorld();
+        Vec3d l = getTargetVector(p, radius);
+        Vec3d eye = p.getPositionEyes(1.0f);
+        Vec3d unit = new Vec3d(l.x - eye.x, l.y - eye.y, l.z - eye.z);
         
         List<Entity> col = getEntitiesExcluding(p, w, eye.x, eye.y, eye.z, l.x, l.y, l.z);
         col.removeIf(ent -> !type.isAssignableFrom(ent.getClass()));
@@ -553,12 +557,6 @@ public class Utils
         }).findFirst().orElse(null);
     }
     
-    @SuppressWarnings("unchecked")
-    public static <T extends Entity> T getTargetedEntity(EntityPlayer p, double radius, Class<T> type)
-    {
-        return getTargetedEntity(p, radius, 0, 0, 0, type);
-    }
-    
     // -------------------------------------------------------------------------
     // Player-Tools
     // -------------------------------------------------------------------------
@@ -568,36 +566,32 @@ public class Utils
         return w.playerEntities.stream().min((p1, p2) -> Double.compare(p1.getDistanceSq(v.x, v.y, v.z), p2.getDistanceSq(v.x, v.y, v.z))).orElse(null);
     }
     
-    public static Vec3d getPlayerTargetVector(EntityPlayer p, double range, boolean boundingBox)
+    public static BlockPos getTargetBlock(Entity ent, double range, boolean boundingBox)
     {
         if(range > 128)
         {
             range = 128;
         }
-        World w = p.getEntityWorld();
-        Vec3d start = getEyeLocation(p);
-        Vec3d end = start.add(p.getLookVec().scale(range));
-        RayTraceResult ray = w.rayTraceBlocks(start, end, true, !boundingBox, false);
-        if(ray == null)
+        World w = ent.getEntityWorld();
+        Vec3d start = ent.getPositionEyes(1.0f);
+        Vec3d look = ent.getLookVec();
+        Vec3d end = start.addVector(look.x * range, look.y * range, look.z * range);   
+        RayTraceResult ray = w.rayTraceBlocks(start, end, false, !boundingBox, true);
+        if(ray == null || ray.getBlockPos() == null)
         {
-            return end;
+            return new BlockPos(end);
         }
-        return ray.hitVec;   
-    }
-    
-    public static BlockPos getPlayerTarget(EntityPlayer p, double range, boolean boundingBox)
-    {
-        return new BlockPos(getPlayerTargetVector(p, range, boundingBox));
+        return ray.getBlockPos();   
     }
     
-    public static BlockPos getPlayerTarget(EntityPlayer p, double range)
+    public static BlockPos getTargetBlock(Entity ent, double range)
     {
-        return getPlayerTarget(p, range, false);  
+        return getTargetBlock(ent, range, false);  
     }
     
-    public static BlockPos getPlayerTarget(EntityPlayer p)
+    public static BlockPos getTargetBlock(Entity ent)
     {
-        return getPlayerTarget(p, 20);
+        return getTargetBlock(ent, 20);
     }  
     
     public static EntityPlayerMP getPlayerByName(String name) throws PlayerNotFoundException

+ 1 - 17
src/main/java/me/km/blockprotections/BlockProtectionBank.java

@@ -232,23 +232,7 @@ public class BlockProtectionBank extends SimpleDataBank
         {
             m.sendListElement(p, name);
         });
-    }
-    
-    public List<BlockPos> getAllFromWorld(World w)
-    {
-        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 BlockPos((int) li.get(0), (int) li.get(1), (int) li.get(2));
-            }
-            catch(Exception ex)
-            {
-                return null;
-            }
-        }).collect(Collectors.toList());
-    }
+    }   
     
     private String makeStringSafe(String s)
     {

+ 1 - 73
src/main/java/me/km/blockprotections/CommandBlock.java

@@ -61,7 +61,7 @@ public class CommandBlock extends ModuleCommand
         }
         if(arg.length > 0)
         {
-            BlockPos pos = Utils.getPlayerTarget(p);  
+            BlockPos pos = Utils.getTargetBlock(p);  
             IBlockState state = w.getBlockState(pos);
             Block b = state.getBlock();
             if(!Utils.shouldBeProtected(b) && !KajetansMod.perms.hasPermission(cs, Permissions.BLOCK_ALL))
@@ -190,74 +190,6 @@ public class CommandBlock extends ModuleCommand
                         return true;
                     }
                 }
-                case "clear":
-                {
-                    if(KajetansMod.perms.hasPermission(cs, Permissions.BLOCK_CLEAR))
-                    {
-                        checker = false;
-                        SnuviScheduler.scheduleAsyncTask(() -> 
-                        {
-                            this.getModule().send(cs, "Blöcke aus Datenbank abrufen ...");
-                            counter = 0;
-                            locs = bank.getAllFromWorld(w);
-                            checker = true;
-                            this.getModule().send(cs, "Fertig ...");
-                        });
-                        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.");
-                                locs.clear();
-                                blocks.clear();
-                                return;
-                            }
-                            for(int i = 0; i < locs.size(); i+=50)
-                            {
-                                final int end = i + 50;
-                                KajetansMod.scheduler.scheduleTask(() -> 
-                                {
-                                    this.getModule().send(cs, "Blöcke aus Welt abrufen " + (end / 50));
-                                    for(int j = end - 50; j < locs.size() && j < end; j++)
-                                    {
-                                        try
-                                        {
-                                            blocks.add(w.getBlockState(locs.get(j)).getBlock());
-                                        }
-                                        catch(NullPointerException ex)
-                                        {
-                                            blocks.add(null);
-                                        }
-                                    }
-                                    this.getModule().send(cs, "Fertig ...");
-                                }, 0);
-                            }
-                            this.getModule().send(cs, "Fertig ...");
-                        }, 200);
-                        SnuviScheduler.scheduleAsyncTask(() -> 
-                        {
-                            this.getModule().send(cs, "Ungültige Entfernen ...");
-                            index = 0;
-                            blocks.stream().forEach(bl -> 
-                            {
-                                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);
-                        return true;
-                    }
-                    break;
-                }
             }                    
         }
         m.send(cs, "/block ...");
@@ -266,10 +198,6 @@ public class CommandBlock extends ModuleCommand
         m.sendHelpListElement(cs, "info", "Gibt Information über den Block");
         m.sendHelpListElement(cs, "share <player>", "Teilt eine Block-Protection mit einem Spieler");
         m.sendHelpListElement(cs, "kick <player>", "Kickt einen Spieler von einer Block-Protection");
-        if(KajetansMod.perms.hasPermission(cs, Permissions.BLOCK_CLEAR))
-        {
-            m.sendHelpListElement(cs, "clear", "Entfernt ungültige Block-Protections auf jeden Block");
-        }
         return true;        
     }
 }

+ 159 - 0
src/main/java/me/km/blocks/BlockResistantTallGrass.java

@@ -0,0 +1,159 @@
+package me.km.blocks;
+
+import java.util.Random;
+import javax.annotation.Nullable;
+import me.km.items.ModItems;
+import static net.minecraft.block.Block.NULL_AABB;
+import net.minecraft.block.SoundType;
+import net.minecraft.block.material.Material;
+import net.minecraft.block.state.BlockFaceShape;
+import net.minecraft.block.state.IBlockState;
+import net.minecraft.creativetab.CreativeTabs;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.init.Items;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.stats.StatList;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.BlockRenderLayer;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.NonNullList;
+import net.minecraft.util.math.AxisAlignedBB;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.IBlockAccess;
+import net.minecraft.world.World;
+import net.minecraftforge.common.IShearable;
+import net.minecraftforge.fml.relauncher.Side;
+import net.minecraftforge.fml.relauncher.SideOnly;
+
+public class BlockResistantTallGrass extends BlockBase implements net.minecraftforge.common.IPlantable, IShearable
+{
+    protected static final AxisAlignedBB TALL_GRASS_AABB = new AxisAlignedBB(0.1d, 0.0d, 0.1d, 0.9d, 0.8d, 0.9d);
+    
+    public BlockResistantTallGrass(String name, String local) 
+    {
+        super(Material.VINE, name, local);
+        super.setCreativeTab(CreativeTabs.DECORATIONS);
+        super.setSoundType(SoundType.PLANT);
+        super.setHardness(0);
+    }
+
+    @Override
+    public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos)
+    {
+        return TALL_GRASS_AABB;
+    }
+
+    @Nullable
+    @Override
+    public AxisAlignedBB getCollisionBoundingBox(IBlockState blockState, IBlockAccess worldIn, BlockPos pos)
+    {
+        return NULL_AABB;
+    }
+
+    @Override
+    public boolean isOpaqueCube(IBlockState state)
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isFullCube(IBlockState state)
+    {
+        return false;
+    }
+
+    @Override
+    public net.minecraftforge.common.EnumPlantType getPlantType(IBlockAccess world, BlockPos pos)
+    {
+        return net.minecraftforge.common.EnumPlantType.Plains;
+    }
+
+    @Override
+    public IBlockState getPlant(net.minecraft.world.IBlockAccess world, BlockPos pos)
+    {
+        IBlockState state = world.getBlockState(pos);
+        if(state.getBlock() != this) 
+        {
+            return getDefaultState();
+        }
+        return state;
+    }
+
+    @SideOnly(Side.CLIENT)
+    @Override
+    public BlockRenderLayer getBlockLayer()
+    {
+        return BlockRenderLayer.CUTOUT;
+    }
+
+    @Override
+    public BlockFaceShape getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face)
+    {
+        return BlockFaceShape.UNDEFINED;
+    }
+
+    @Override
+    public boolean isReplaceable(IBlockAccess worldIn, BlockPos pos)
+    {
+        return true;
+    }
+
+    @Override
+    public Item getItemDropped(IBlockState state, Random rand, int fortune)
+    {
+        return null;
+    }
+
+    @Override
+    public int quantityDroppedWithBonus(int fortune, Random random)
+    {
+        return 1 + random.nextInt(fortune * 2 + 1);
+    }
+
+    @Override
+    public void harvestBlock(World w, EntityPlayer p, BlockPos pos, IBlockState state, TileEntity te, ItemStack stack)
+    {
+        if(!w.isRemote && stack.getItem() == Items.SHEARS)
+        {
+            p.addStat(StatList.getBlockStats(this));
+            spawnAsEntity(w, pos, new ItemStack(ModBlocks.tallGrass, 1));
+        }
+        else
+        {
+            super.harvestBlock(w, p, pos, state, te, stack);
+        }
+    }
+
+    @Override 
+    public boolean isShearable(ItemStack item, IBlockAccess world, BlockPos pos)
+    {
+        return true; 
+    }
+    
+    @Override
+    public NonNullList<ItemStack> onSheared(ItemStack item, IBlockAccess world, BlockPos pos, int fortune)
+    {
+        return NonNullList.withSize(1, new ItemStack(ModBlocks.tallGrass, 1));
+    }
+    
+    @Override
+    public NonNullList<ItemStack> getDrops(IBlockAccess w, BlockPos pos, IBlockState state, int fortune)
+    {
+        int rand = RANDOM.nextInt(8);
+        if(rand <= 3)
+        {
+            return NonNullList.withSize(1, new ItemStack(ModItems.hayBundle));
+        }
+        else if(RANDOM.nextInt(8) == 4) 
+        {
+            ItemStack seed = net.minecraftforge.common.ForgeHooks.getGrassSeed(RANDOM, fortune);
+            if(!seed.isEmpty())
+            {
+                return NonNullList.withSize(1, seed);
+            }
+        }
+        return NonNullList.create();
+    }
+}

+ 5 - 0
src/main/java/me/km/blocks/ModBlocks.java

@@ -69,6 +69,8 @@ public class ModBlocks
     
     public static BlockLantern lantern;
     
+    public static BlockResistantTallGrass tallGrass;
+    
     // traps
     public static BlockSpikeTrap spikes;
     
@@ -143,6 +145,8 @@ public class ModBlocks
         
         lantern = register(r, new BlockLantern("lantern", "lantern"));
         
+        tallGrass = register(r, new BlockResistantTallGrass("rtall_grass", "rtallGrass"));
+        
         // traps
         spikes = register(r, new BlockSpikeTrap(Material.IRON, "spikes", "spikes"));
     
@@ -208,6 +212,7 @@ public class ModBlocks
         register(r, barrelSpruce, getItemBlock(barrelSpruce));
         
         register(r, lantern, getItemBlock(lantern));
+        register(r, tallGrass, getItemBlock(tallGrass));
         
         // traps
         register(r, spikes, getItemMetal(spikes));

+ 9 - 46
src/main/java/me/km/chatchannel/ChatChannel.java

@@ -1,11 +1,11 @@
 package me.km.chatchannel;
 
-import java.util.HashSet;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 import me.km.KajetansMod;
 import me.km.permissions.Permissions;
-import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
 import net.minecraft.util.text.TextComponentString;
 
 public class ChatChannel 
@@ -23,62 +23,25 @@ public class ChatChannel
             (cc, s) -> 
             {
                 TextComponentString text = new TextComponentString(s);
-                cc.receivers.forEach(p -> p.sendMessage(text));
-            },
-            (cc, p) -> 
-            {
-                if(KajetansMod.perms.hasPermission(p, Permissions.SCRIPT_ERROR))
-                {
-                    cc.addPlayer(p);
-                }
-            }, 
-            (cc, p) -> 
-            {
-                cc.removePlayer(p);
-            });   
-    
-    public static void onPlayerLogIn(EntityPlayer p)
-    {
-        DEV_CHANNEL.onLogin.accept(DEV_CHANNEL, p);
-    }
-    
-    public static void onPlayerLogOut(EntityPlayer p)
-    {
-        DEV_CHANNEL.onLogout.accept(DEV_CHANNEL, p);
-    }
+                cc.forEach(p -> p.sendMessage(text));
+            }, p -> KajetansMod.perms.hasPermission(p, Permissions.SCRIPT_ERROR));   
     
     // -------------------------------------------------------------------------
     // chat channels
     // -------------------------------------------------------------------------
     
-    private final HashSet<EntityPlayer> receivers;
+    private final Predicate<EntityPlayerMP> filter;
     private final String prefix;
     private final String list;
     private final BiConsumer<ChatChannel, String> onSend;
-    private final BiConsumer<ChatChannel, EntityPlayer> onLogin;
-    private final BiConsumer<ChatChannel, EntityPlayer> onLogout;
     
     private ChatChannel(String name, TextColor tc,
-            BiConsumer<ChatChannel, String> onSend,
-            BiConsumer<ChatChannel, EntityPlayer> onLogin,
-            BiConsumer<ChatChannel, EntityPlayer> onLogout)
+            BiConsumer<ChatChannel, String> onSend, Predicate<EntityPlayerMP> filter)
     {
-        receivers = new HashSet<>();
+        this.filter = filter;
         this.prefix = "[" + tc + name + TextColor.RESET + "] ";
         this.list = tc + " - ";
         this.onSend = onSend;
-        this.onLogin = onLogin;
-        this.onLogout = onLogout;
-    }
-    
-    public void addPlayer(EntityPlayer p)
-    {
-        receivers.add(p);
-    }
-    
-    public void removePlayer(EntityPlayer p)
-    {
-        receivers.remove(p);
     }
     
     public void send(String msg)
@@ -101,8 +64,8 @@ public class ChatChannel
         onSend.accept(this, list + msg + TextColor.RESET + " " + msg2);
     }
     
-    public void forEach(Consumer<EntityPlayer> c)
+    public void forEach(Consumer<EntityPlayerMP> c)
     {
-        receivers.forEach(c);
+        KajetansMod.server.getPlayerList().getPlayers().stream().filter(filter).forEach(c);
     }
 }

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

@@ -33,7 +33,7 @@ public class CommandCoords extends ModuleCommand
         }
         EntityPlayer p = (EntityPlayer) cs;
         World w = cs.getEntityWorld();
-        BlockPos pos = Utils.getPlayerTarget(p);
+        BlockPos pos = Utils.getTargetBlock(p);
         if(w.isAirBlock(pos))
         {
             this.getModule().send(cs, "Du musst auf einen Block gerichtet sein.");

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

@@ -76,7 +76,7 @@ public class CommandGameMode extends ModuleCommand
                 affectedPlayer.setGameType(GameType.ADVENTURE);
                 mode = "Adventure";
                 break;
-            case "specator":         
+            case "spectator":         
             case "w":         
             case "3":  
                 affectedPlayer.setGameType(GameType.SPECTATOR);

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

@@ -29,7 +29,7 @@ public class CommandSetBed extends ModuleCommand
             return true;
         }
         EntityPlayer p = (EntityPlayer) cs;
-        BlockPos pos = Utils.getPlayerTarget(p);
+        BlockPos pos = Utils.getTargetBlock(p);
         if(p.world.getBlockState(pos).getBlock() != Blocks.BED)
         {
             this.getModule().send(cs, "Du musst auf ein Bett gerichtet sein.");

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

@@ -39,7 +39,7 @@ public class CommandSign extends ModuleCommand
         }
         EntityPlayer p = (EntityPlayer) cs;
         World w = p.getEntityWorld();
-        BlockPos pos = Utils.getPlayerTarget(p, 20, true);
+        BlockPos pos = Utils.getTargetBlock(p, 20, true);
         Block b = w.getBlockState(pos).getBlock();
         if(b == Blocks.STANDING_SIGN || b == Blocks.WALL_SIGN)
         {

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

@@ -47,7 +47,7 @@ public class CommandSpawner extends ModuleCommand
         }
         
         EntityPlayer p = (EntityPlayer) cs;
-        BlockPos pos = Utils.getPlayerTarget(p);
+        BlockPos pos = Utils.getTargetBlock(p);
         TileEntity tile = p.world.getTileEntity(pos);
         if(!(tile instanceof TileEntityMobSpawner))
         {

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

@@ -56,7 +56,7 @@ public class CommandSummon extends ModuleCommand
             {
             }
         }
-        BlockPos target = Utils.getPlayerTarget(p).add(0, 1, 0);
+        BlockPos target = Utils.getTargetBlock(p).add(0, 1, 0);
 
         String s = arg[0];
         double d0 = target.getX();

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

@@ -33,9 +33,9 @@ public class CommandTempBan extends ModuleCommand
         Date date = new Date(System.currentTimeMillis());
         try
         {
-            long days = Integer.parseInt(arg[1]) * 86400000;
-            long hours = Integer.parseInt(arg[2]) * 3600000;
-            long minutes = Integer.parseInt(arg[3]) * 60000;
+            long days = Integer.parseInt(arg[1]) * 86400000l;
+            long hours = Integer.parseInt(arg[2]) * 3600000l;
+            long minutes = Integer.parseInt(arg[3]) * 60000l;
             if(days < 0 || hours < 0 || minutes < 0)
             {
                 throw new NumberFormatException();

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

@@ -84,11 +84,6 @@ public class DataToolsEvents extends ModuleListener
             if(dim >= 2)
             {
                 ReflectionUtils.setCareerLevel(v, 10);
-                MerchantRecipeList list = v.getRecipes(null);
-                if(list != null)
-                {
-                    list.clear();
-                }
             }
         }
     }

+ 1 - 1
src/main/java/me/km/effects/active/Elevation.java

@@ -15,7 +15,7 @@ public class Elevation extends ActiveEffectBase
     @Override
     protected boolean executeEffect(EntityPlayerMP p, int power) 
     {
-        BlockPos target = Utils.getPlayerTarget(p, power + 3).up();    
+        BlockPos target = Utils.getTargetBlock(p, power + 3).up();    
         EffectUtils.playSound(p, SoundEvents.ENTITY_FIREWORK_TWINKLE_FAR);
         EffectUtils.spawnSpell(p, power); 
         Collection<EntityLivingBase> list = EffectUtils.getEntsOfNotGuild(p, p.world, target.getX(), target.getY(), target.getZ(), 3);

+ 1 - 1
src/main/java/me/km/effects/active/Explosion.java

@@ -11,7 +11,7 @@ public class Explosion extends ActiveEffectBase
     @Override
     protected boolean executeEffect(EntityPlayerMP p, int power) 
     {
-        BlockPos target = Utils.getPlayerTarget(p, power + 3).up();
+        BlockPos target = Utils.getTargetBlock(p, power + 3).up();
         WorldServer w = p.getServerWorld();
         w.createExplosion(null, target.getX(), target.getY(), target.getZ(), power / 4f, true);
         return true;

+ 1 - 1
src/main/java/me/km/effects/active/Thor.java

@@ -12,7 +12,7 @@ public class Thor extends ActiveEffectBase
     @Override
     protected boolean executeEffect(EntityPlayerMP p, int power) 
     {
-        BlockPos pos = Utils.getPlayerTarget(p, power + 3).up();
+        BlockPos pos = Utils.getTargetBlock(p, power + 3).up();
         WorldServer w = p.getServerWorld();
         w.addWeatherEffect(new EntityLightningBolt(w, pos.getX(), pos.getY(), pos.getZ(), false));
         return true;

+ 1 - 1
src/main/java/me/km/effects/active/VineTrap.java

@@ -15,7 +15,7 @@ public class VineTrap extends ActiveEffectBase
     @Override
     protected boolean executeEffect(EntityPlayerMP p, int power) 
     {
-        BlockPos l = Utils.getPlayerTarget(p, power + 7).add(0, 1, 0);
+        BlockPos l = Utils.getTargetBlock(p, power + 7).add(0, 1, 0);
         EffectBlockChanger list = new EffectBlockChanger(p.world);
         list.addBlock(l, Blocks.LOG, 1);
         list.addBlock(l.add(1, 0, 0), Blocks.VINE, 4);

+ 0 - 20
src/main/java/me/km/jobsystem/LimitedDataStorage.java

@@ -1,20 +0,0 @@
-package me.km.jobsystem;
-
-import java.util.LinkedHashSet;
-
-public class LimitedDataStorage<E> extends LinkedHashSet<E>
-{
-    public void addLimited(E e)
-    {
-        this.add(e);
-        
-        if(this.size() > 999)
-        {
-            E remove = this.stream().findFirst().orElse(null);
-            if(remove != null)
-            {
-                this.remove(remove);
-            }
-        }
-    }
-}

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

@@ -12,6 +12,7 @@ import net.minecraft.command.ICommand;
 import net.minecraft.command.ICommandSender;
 import net.minecraft.entity.player.EntityPlayer;
 import net.minecraft.server.MinecraftServer;
+import net.minecraft.tileentity.CommandBlockBaseLogic;
 import net.minecraft.util.text.TextComponentString;
 import net.minecraft.util.text.TextFormatting;
 import net.minecraftforge.fml.relauncher.Side;
@@ -74,7 +75,7 @@ public class PermissionManager extends Module implements ICommandManager
             // check for valid group id is done at the registry
             return groups.stream().anyMatch(i -> stringGroupPerms.get(i).contains(perm));
         }
-        return cs instanceof MinecraftServer;
+        return cs instanceof MinecraftServer || cs instanceof CommandBlockBaseLogic;
     }
 
     // -------------------------------------------------------------------------

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

@@ -11,7 +11,6 @@ public class Permissions
     public final static String BLOCK = "block";
     public final static String BLOCK_ALL = "block.all";
     public final static String BLOCK_OTHER = "block.other";
-    public final static String BLOCK_CLEAR = "block.clear";
 
     // Chat-Manager
     public final static String COLOR = "color";

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

@@ -53,8 +53,6 @@ public class PlayerLogInOut extends ModuleListener
                 pb.changeName(p);
             }
         }      
-        
-        ChatChannel.onPlayerLogIn(p);
     }
     
     @SubscribeEvent(priority = EventPriority.LOW)
@@ -63,8 +61,6 @@ public class PlayerLogInOut extends ModuleListener
         EntityPlayer p = e.player;
         KajetansMod.generalCommands.getCommand(CommandTeleportAccept.class).tpaccept.remove(p.getUniqueID());
         KajetansMod.scoreboard.removeScoreboard(p.getUniqueID());
-        
-        ChatChannel.onPlayerLogOut(p);
     }
     
     @SubscribeEvent

+ 101 - 0
src/main/java/me/km/scheduler/AsyncWorker.java

@@ -0,0 +1,101 @@
+package me.km.scheduler;
+
+import java.util.LinkedList;
+
+public class AsyncWorker
+{
+    private final LinkedList<Runnable> tasks = new LinkedList<>();
+    private final Thread worker;
+    
+    public AsyncWorker()
+    {
+        worker = new Thread(() -> run());
+    }
+    
+    public void start()
+    {
+        worker.start();
+    }
+    
+    public void stop()
+    {
+        while(worker.isAlive())
+        {
+            synchronized(worker)
+            {
+                worker.interrupt();
+            }
+            try
+            {
+                worker.join(100);
+            }
+            catch(InterruptedException ex)
+            {   
+            }
+        }
+    }
+    
+    private void run()
+    {
+        while(true)
+        {
+            synchronized(worker)
+            {
+                try
+                {
+                    worker.wait();
+                }
+                catch(InterruptedException ex)
+                {
+                    break;
+                }
+            }
+            
+            while(true)
+            {
+                Runnable r;
+                synchronized(tasks)
+                {
+                    if(tasks.isEmpty())
+                    {
+                        break;
+                    }
+                    r = tasks.removeFirst();
+                }
+                try
+                {
+                    r.run();
+                }
+                catch(Exception ex)
+                {
+                    System.out.println("A worker task has thrown an exception:");
+                    ex.printStackTrace();
+                }
+            }
+        }
+    }
+    
+    public void add(Runnable r)
+    {
+        synchronized(tasks)
+        {
+            tasks.add(r);
+        }
+    }
+    
+    public void doWork()
+    {
+        synchronized(worker)
+        {
+            worker.notify();
+        }
+    }
+    
+    public boolean hasWork()
+    {
+        synchronized(tasks)
+        {
+            return !tasks.isEmpty();
+        }
+    }
+}

+ 15 - 13
src/main/java/me/km/scheduler/SnuviScheduler.java

@@ -3,9 +3,6 @@ package me.km.scheduler;
 import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.LinkedList;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 import me.hammerle.snuviscript.code.ISnuviScheduler;
 import me.km.api.Module;
 import net.minecraft.util.text.TextFormatting;
@@ -20,6 +17,7 @@ public class SnuviScheduler extends Module implements ISnuviScheduler
     private final LinkedList<SnuviTask> addQueue;
     private final LinkedList<Integer> removeQueue;
     private final HashMap<Integer, SnuviTask> tasks;
+    private final AsyncWorker worker = new AsyncWorker();
     
     public SnuviScheduler(String mname, String prefix, TextFormatting color)
     {
@@ -28,6 +26,7 @@ public class SnuviScheduler extends Module implements ISnuviScheduler
         tasks = new HashMap<>();
         addQueue = new LinkedList<>();
         removeQueue = new LinkedList<>();
+        worker.start();
     }
     
     public void cancelTask(int id)
@@ -56,6 +55,7 @@ public class SnuviScheduler extends Module implements ISnuviScheduler
     
     public void tick()
     {
+        worker.doWork();
         try
         {
             if(!removeQueue.isEmpty())
@@ -82,7 +82,16 @@ public class SnuviScheduler extends Module implements ISnuviScheduler
                     this.sendWarningToConsole("Der Scheduler ist länger als 25 ms gelaufen.");
                     return false;
                 }
-                return task.tick();
+                try
+                {
+                    return task.tick();
+                }
+                catch(Exception ex)
+                {
+                    this.sendWarningToConsole("Scheduler-Exception - Task wird entfernt.");
+                    ex.printStackTrace();
+                    return true;
+                }
             });
         }
         catch(ConcurrentModificationException ex)
@@ -91,15 +100,8 @@ public class SnuviScheduler extends Module implements ISnuviScheduler
         }
     }
     
-    public static void scheduleAsyncTask(Runnable r)
-    {
-        scheduleAsyncTask(r, 1);
-    }
-    
-    public static void scheduleAsyncTask(Runnable r, long ticks)
+    public AsyncWorker getWorker()
     {
-        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();  
-        executor.schedule(r, ticks * 50, TimeUnit.MILLISECONDS);
-        executor.shutdown();
+        return worker;
     }
 }

+ 149 - 80
src/main/java/me/km/snuviscript/MinecraftFunctions.java

@@ -93,7 +93,7 @@ public class MinecraftFunctions
     public static void registerFunctions(SnuviParser parser)
     {
         // ---------------------------------------------------------------------
-        // Command-Bibliothek  
+        // Command-library  
         // ---------------------------------------------------------------------
         parser.registerFunction("command.add", (sc, in) -> 
         {
@@ -113,7 +113,7 @@ public class MinecraftFunctions
         }); 
         
         // ---------------------------------------------------------------------
-        // Permission-Bibliothek  
+        // Permission-library  
         // ---------------------------------------------------------------------
         parser.registerFunction("perm.clear", (sc, in) -> 
         {
@@ -127,14 +127,14 @@ public class MinecraftFunctions
         }); 
         parser.registerFunction("perm.registerplayer", (sc, in) -> 
         {
-            KajetansMod.perms.registerPlayerGroup(UUID.fromString(in[0].getString(sc)), in[1].getInt(sc));
+            KajetansMod.perms.registerPlayerGroup(getUUID(in[0].get(sc)), in[1].getInt(sc));
             return Void.TYPE;
         }); 
-        parser.registerFunction("perm.unregisterplayer", (sc, in) -> KajetansMod.perms.unregisterPlayer(UUID.fromString(in[0].getString(sc)), in[1].getInt(sc))); 
+        parser.registerFunction("perm.unregisterplayer", (sc, in) -> KajetansMod.perms.unregisterPlayer(getUUID(in[0].get(sc)), in[1].getInt(sc))); 
         parser.registerFunction("perm.has", (sc, in) -> KajetansMod.perms.hasPermission((ICommandSender) in[0].get(sc), in[1].getString(sc))); 
         
         // ---------------------------------------------------------------------
-        // Title-Bibliothek  
+        // Title-library  
         // ---------------------------------------------------------------------
         parser.registerFunction("title.settime", (sc, in) -> 
         {
@@ -163,7 +163,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------
-        // Villager-Bibliothek  
+        // Villager-library  
         // ---------------------------------------------------------------------
         parser.registerFunction("villager.showtrades", (sc, in) -> 
         { 
@@ -172,7 +172,7 @@ public class MinecraftFunctions
         });
        
         // ---------------------------------------------------------------------    
-        // Player-Bibliothek
+        // Player-library
         // ---------------------------------------------------------------------  
         parser.registerFunction("player.getitemamount", (sc, in) -> (double) InventoryUtils.searchInventoryFor(((EntityPlayer) in[0].get(sc)).inventory, (ItemStack) in[2].get(sc), in[1].getBoolean(sc)));                
         parser.registerFunction("player.removeitem", (sc, in) -> 
@@ -190,11 +190,12 @@ public class MinecraftFunctions
         parser.registerFunction("player.shootprojectile", (sc, in) -> EffectUtils.launchProjectile((EntityPlayer) in[0].get(sc), getClass(in[1].getString(sc)), in[2].getDouble(sc), in[3].get(sc)));
         parser.registerFunction("player.respawn", (sc, in) -> 
         {
+            final EntityPlayerMP p = ((EntityPlayerMP) in[0].get(sc));
             KajetansMod.scheduler.scheduleTask(() ->
             {
                 try
                 {
-                    ((EntityPlayerMP) in[0].get(sc)).connection.processClientStatus(new CPacketClientStatus(CPacketClientStatus.State.PERFORM_RESPAWN));
+                    p.connection.processClientStatus(new CPacketClientStatus(CPacketClientStatus.State.PERFORM_RESPAWN));
                 }
                 catch(ThreadQuickExitException ex)
                 {
@@ -264,9 +265,13 @@ public class MinecraftFunctions
             Object o = in[0].get(sc);
             if(o instanceof EntityPlayer)
             {
-                return ((EntityPlayer) o).getUniqueID().toString();
+                return ((EntityPlayer) o).getUniqueID();
             }
-            return KajetansMod.playerbank.getDataBank().getUUID(o.toString());
+            return UUID.fromString(KajetansMod.playerbank.getDataBank().getUUID(o.toString()));
+        });
+        parser.registerFunction("player.get", (sc, in) -> 
+        { 
+            return KajetansMod.server.getPlayerList().getPlayerByUUID(getUUID(in[0].get(sc)));
         });
         parser.registerFunction("player.getip", (sc, in) -> ((EntityPlayerMP) in[0].get(sc)).connection.netManager.getRemoteAddress().toString());
         parser.registerFunction("player.iscreative", (sc, in) -> ((EntityPlayer) in[0].get(sc)).isCreative());
@@ -298,7 +303,7 @@ public class MinecraftFunctions
                 case "2":  
                     p.setGameType(GameType.ADVENTURE);
                     break;
-                case "specator":         
+                case "spectator":         
                 case "w":         
                 case "3":  
                     p.setGameType(GameType.SPECTATOR);
@@ -368,9 +373,9 @@ public class MinecraftFunctions
             if(in.length > 2)
             {
                 return new Location(((EntityPlayer) in[0].get(sc)).world, 
-                        Utils.getPlayerTarget((EntityPlayer) in[0].get(sc), in[1].getInt(sc), in[2].getBoolean(sc)));
+                        Utils.getTargetBlock((EntityPlayer) in[0].get(sc), in[1].getInt(sc), in[2].getBoolean(sc)));
             }
-            return new Location(((EntityPlayer) in[0].get(sc)).world, Utils.getPlayerTarget((EntityPlayer) in[0].get(sc), in[1].getInt(sc)));
+            return new Location(((EntityPlayer) in[0].get(sc)).world, Utils.getTargetBlock((EntityPlayer) in[0].get(sc), in[1].getInt(sc)));
         });
                 
         parser.registerFunction("player.gettargetentity", (sc, in) -> Utils.getTargetedEntity((EntityPlayer) in[0].get(sc), in[1].getDouble(sc), getClass(in[2].getString(sc))));
@@ -409,7 +414,7 @@ public class MinecraftFunctions
         parser.registerFunction("player.silentjoin", (sc, in) -> KajetansMod.perms.hasPermission((EntityPlayer) in[0].get(sc), Permissions.SILENT) && KajetansMod.generalCommands.getCommand(CommandSilent.class).silentjoin);
         
         // ---------------------------------------------------------------------    
-        // Players-Bibliothek
+        // Players-library
         // --------------------------------------------------------------------- 
         parser.registerFunction("players.getamount", (sc, in) -> (double) KajetansMod.server.getCurrentPlayerCount());
         parser.registerFunction("players.tolist", (sc, in) -> 
@@ -430,7 +435,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------    
-        // Rank-Bibliothek
+        // Rank-library
         // ---------------------------------------------------------------------  
         parser.registerFunction("rank.get", (sc, in) -> 
         { 
@@ -444,7 +449,7 @@ public class MinecraftFunctions
         });
         parser.registerFunction("rank.player", (sc, in) -> 
         { 
-            KajetansMod.chatManager.registerPlayerRank(UUID.fromString(in[0].getString(sc)), in[1].getString(sc));
+            KajetansMod.chatManager.registerPlayerRank(getUUID(in[0].get(sc)), in[1].getString(sc));
             return Void.TYPE; 
         });
         parser.registerFunction("rank.clear", (sc, in) -> 
@@ -454,7 +459,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------    
-        // Custom-Bibliothek
+        // Custom-library
         // ---------------------------------------------------------------------
         /*parser.registerFunction("custom.registershapelessrecipe", (sc, in) -> 
         { 
@@ -500,7 +505,7 @@ public class MinecraftFunctions
         
         
         // ---------------------------------------------------------------------    
-        // World-Bibliothek
+        // World-library
         // ---------------------------------------------------------------------
         
         parser.registerAlias("players.toworldlist", "world.getplayers");
@@ -545,7 +550,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------    
-        // Item-Bibliothek   
+        // Item-library   
         // ---------------------------------------------------------------------   
         parser.registerFunction("item.drop", (sc, in) -> 
         {       
@@ -612,7 +617,7 @@ public class MinecraftFunctions
         parser.registerFunction("item.gettooltype", (sc, in) -> Utils.getToolType((ItemStack) in[0].get(sc)));
 
         // ---------------------------------------------------------------------    
-        // Location-Bibliothek
+        // Location-library
         // ---------------------------------------------------------------------  
         parser.registerFunction("loc.new", (sc, in) -> 
         { 
@@ -708,7 +713,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------    
-        // Block-Bibliothek
+        // Block-library
         // ---------------------------------------------------------------------    
         parser.registerFunction("block.gettype", (sc, in) -> 
         {
@@ -817,19 +822,19 @@ public class MinecraftFunctions
             TileEntityChest chest = (TileEntityChest) te;
             if(chest.adjacentChestXNeg != null)
             {
-                return chest.adjacentChestXNeg.getPos();
+                return new Location(l.getWorld(), chest.adjacentChestXNeg.getPos());
             }
             if(chest.adjacentChestXPos != null)
             {
-                return chest.adjacentChestXPos.getPos();
+                return new Location(l.getWorld(), chest.adjacentChestXPos.getPos());
             }
             if(chest.adjacentChestZNeg != null)
             {
-                return chest.adjacentChestZNeg.getPos();
+                return new Location(l.getWorld(), chest.adjacentChestZNeg.getPos());
             }
             if(chest.adjacentChestZPos != null)
             {
-                return chest.adjacentChestZPos.getPos();
+                return new Location(l.getWorld(), chest.adjacentChestZPos.getPos());
             }
             return null;
         });
@@ -899,7 +904,7 @@ public class MinecraftFunctions
         });  
 
         // ---------------------------------------------------------------------    
-        // Event-Bibliothek 
+        // Event-library 
         // ---------------------------------------------------------------------  
         parser.registerFunction("event.addmovedata", (sc, in) -> (double) CustomEventCaller.registerMoveData(new PlayerMoveData(
                 sc, (Location) in[0].get(sc), (Location) in[1].get(sc), in[2].getInt(sc), in[3].getInt(sc))));
@@ -910,7 +915,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------    
-        // Skill-Bibliothek 
+        // Skill-library 
         // --------------------------------------------------------------------- 
         parser.registerFunction("skill.register", (sc, in) -> 
         { 
@@ -948,7 +953,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------    
-        // Job-Bibliothek 
+        // Job-library 
         // ---------------------------------------------------------------------  
         parser.registerFunction("job.getlevel", (sc, in) -> (double) KajetansMod.jobs.getLevel((EntityPlayer) in[0].get(sc), in[1].getByte(sc)));
         parser.registerFunction("job.addlevel", (sc, in) -> 
@@ -1280,7 +1285,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------
-        // Status-Bibliothek
+        // Status-library
         // ---------------------------------------------------------------------  
         parser.registerFunction("status.getmana", (sc, in) -> (double) EnvironmentAPI.getMana(((EntityPlayer) in[0].get(sc))));
         parser.registerFunction("status.getcold", (sc, in) -> (double) EnvironmentAPI.getCold(((EntityPlayer) in[0].get(sc))));
@@ -1333,21 +1338,36 @@ public class MinecraftFunctions
         });    
         
         // ---------------------------------------------------------------------  
-        // GMap-Bibliothek   
+        // GMap-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("gmap.removeall", (sc, in) -> 
         {    
-            KajetansMod.scripts.getDataBank(ScriptBank.class).removeMap(in[0].getString(sc)); 
+            final String map = in[0].getString(sc);
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).removeMap(map); 
+            });
             return Void.TYPE; 
         });
         parser.registerFunction("gmap.add", (sc, in) -> 
         {    
-            KajetansMod.scripts.getDataBank(ScriptBank.class).addMapElement(in[0].getString(sc), in[1].getString(sc), in[2].getString(sc)); 
+            final String map = in[0].getString(sc);
+            final String key = in[1].getString(sc);
+            final String value = in[2].getString(sc);
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).addMapElement(map, key, value); 
+            });
             return Void.TYPE; 
         });
         parser.registerFunction("gmap.remove", (sc, in) -> 
         {    
-            KajetansMod.scripts.getDataBank(ScriptBank.class).removeMapElement(in[0].getString(sc), in[1].getString(sc)); 
+            final String map = in[0].getString(sc);
+            final String key = in[1].getString(sc);
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).removeMapElement(map, key); 
+            });
             return Void.TYPE; 
         });
         parser.registerFunction("gmap.totable", (sc, in) -> 
@@ -1367,28 +1387,50 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------  
-        // GDMap-Bibliothek   
+        // GDMap-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("gdmap.removeall", (sc, in) -> 
         {    
             if(in.length >= 2)
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).removeDualMapElement(in[0].getString(sc), in[1].getString(sc)); 
+                final String map = in[0].getString(sc);
+                final String key = in[1].getString(sc);
+                KajetansMod.scheduler.getWorker().add(() -> 
+                {
+                    KajetansMod.scripts.getDataBank(ScriptBank.class).removeDualMapElement(map, key); 
+                });
             }
             else
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).removeDualMap(in[0].getString(sc)); 
+                final String map = in[0].getString(sc);
+                KajetansMod.scheduler.getWorker().add(() -> 
+                {
+                    KajetansMod.scripts.getDataBank(ScriptBank.class).removeDualMap(map); 
+                });
             }
             return Void.TYPE; 
         });
         parser.registerFunction("gdmap.add", (sc, in) -> 
         {    
-            KajetansMod.scripts.getDataBank(ScriptBank.class).addDualMapElement(in[0].getString(sc), in[1].getString(sc), in[2].getString(sc), in[3].getString(sc)); 
+            final String map = in[0].getString(sc);
+            final String key1 = in[1].getString(sc);
+            final String key2 = in[2].getString(sc);
+            final String value = in[3].getString(sc);
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).addDualMapElement(map, key1, key2, value);  
+            });
             return Void.TYPE; 
         });
         parser.registerFunction("gdmap.remove", (sc, in) -> 
         {    
-            KajetansMod.scripts.getDataBank(ScriptBank.class).removeDualMapElement(in[0].getString(sc), in[1].getString(sc), in[2].getString(sc)); 
+            final String map = in[0].getString(sc);
+            final String key1 = in[1].getString(sc);
+            final String key2 = in[2].getString(sc);
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).removeDualMapElement(map, key1, key2); 
+            });
             return Void.TYPE; 
         });
         parser.registerFunction("gdmap.totable", (sc, in) -> 
@@ -1411,7 +1453,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------  
-        // Table-Bibliothek   
+        // Table-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("table.print", (sc, in) -> 
         {   
@@ -1486,22 +1528,25 @@ public class MinecraftFunctions
         parser.registerFunction("table.getsize", (sc, in) -> (double) ((Table) in[0].get(sc)).getSize());
 
         // ---------------------------------------------------------------------  
-        // Plot-Bibliothek   
+        // Plot-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("plot.hastag", (sc, in) -> KajetansMod.plots.getDataBank(ProtectionBank.class).hasTag(((Location) in[0].get(sc)).getWorld(), ((Location) in[0].get(sc)).getBlockPos(), in[1].getString(sc))); 
         parser.registerFunction("plot.add", (sc, in) -> 
         {    
-            Location l1 = (Location) in[0].get(sc);
-            Location l2 = (Location) in[1].get(sc);
-            BlockPos pos1 = l1.getBlockPos();
-            BlockPos pos2 = l2.getBlockPos();
-            KajetansMod.plots.getDataBank(ProtectionBank.class).addPlot(Math.min(pos1.getX(), pos2.getX()),
-                        Math.min(pos1.getY(), pos2.getY()),
-                        Math.min(pos1.getZ(), pos2.getZ()),
-                        Math.max(pos1.getX(), pos2.getX()),
-                        Math.max(pos1.getY(), pos2.getY()),
-                        Math.max(pos1.getZ(), pos2.getZ()),
-                        ModDimensions.getWorldName(l1.getWorld()), null, in[2].getString(sc)); 
+            final Location l1 = (Location) in[0].get(sc);
+            final Location l2 = (Location) in[1].get(sc);
+            final BlockPos pos1 = l1.getBlockPos();
+            final BlockPos pos2 = l2.getBlockPos();
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.plots.getDataBank(ProtectionBank.class).addPlot(Math.min(pos1.getX(), pos2.getX()),
+                            Math.min(pos1.getY(), pos2.getY()),
+                            Math.min(pos1.getZ(), pos2.getZ()),
+                            Math.max(pos1.getX(), pos2.getX()),
+                            Math.max(pos1.getY(), pos2.getY()),
+                            Math.max(pos1.getZ(), pos2.getZ()),
+                            ModDimensions.getWorldName(l1.getWorld()), null, in[2].getString(sc)); 
+            });
             return Void.TYPE;
         });
         parser.registerFunction("plot.getids", (sc, in) -> 
@@ -1536,7 +1581,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------  
-        // Script-Bibliothek   
+        // Script-library   
         // ---------------------------------------------------------------------    
         parser.registerFunction("script.playerstolist", (sc, in) -> 
         {  
@@ -1579,7 +1624,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------  
-        // Scoreboard-Bibliothek   
+        // Scoreboard-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("sb.add", (sc, in) -> 
         {  
@@ -1601,7 +1646,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------  
-        // Display-Bibliothek   
+        // Display-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("display.add", (sc, in) -> 
         {  
@@ -1623,7 +1668,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------  
-        // ItemStack-Display-Bibliothek   
+        // ItemStack-Display-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("stacks.set", (sc, in) -> 
         {  
@@ -1660,7 +1705,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------  
-        // Head-Bibliothek   
+        // Head-library   
         // ---------------------------------------------------------------------  
         parser.registerFunction("head.add", (sc, in) -> 
         {  
@@ -1685,7 +1730,7 @@ public class MinecraftFunctions
         });
         
         // ---------------------------------------------------------------------  
-        // Effect-Bibliothek   
+        // Effect-library   
         // --------------------------------------------------------------------- 
         parser.registerFunction("effect.playsound", (sc, in) -> 
         { 
@@ -1702,7 +1747,7 @@ public class MinecraftFunctions
         });
 
         // ---------------------------------------------------------------------  
-        // Inventory-Bibliothek   
+        // Inventory-library   
         // ---------------------------------------------------------------------
         parser.registerFunction("inv.new", (sc, in) -> 
         { 
@@ -1776,7 +1821,7 @@ public class MinecraftFunctions
         }); 
 
         // ---------------------------------------------------------------------  
-        // Read-Bibliothek   
+        // Read-library   
         // ---------------------------------------------------------------------
         parser.registerFunction("read.player", (sc, in) -> 
         {
@@ -1822,7 +1867,7 @@ public class MinecraftFunctions
         parser.registerFunction("read.spawnmob", (sc, in) -> NBTUtils.fromString(SnuviUtils.connect(sc, in, 1).replace('\'', '"'), (Location) in[0].get(sc)));
 
         // ---------------------------------------------------------------------  
-        // Text-Bibliothek   
+        // Text-library   
         // ---------------------------------------------------------------------
         parser.registerFunction("text.location", (sc, in) -> ((Location) in[0].get(sc)).toString());
         parser.registerFunction("text.locationblock", (sc, in) -> ((Location) in[0].get(sc)).toBlockString());
@@ -1831,7 +1876,12 @@ public class MinecraftFunctions
         parser.registerFunction("text.hover", (sc, in) -> NBTUtils.getHoverable(in[0].get(sc), in[1].getString(sc)));
 
         // ---------------------------------------------------------------------    
-        // Ohne Bibliothek
+        // worker library
+        // ---------------------------------------------------------------------  
+        parser.registerFunction("worker.haswork", (sc, in) -> KajetansMod.scheduler.getWorker().hasWork());
+        
+        // ---------------------------------------------------------------------    
+        // Ohne library
         // ---------------------------------------------------------------------   
         parser.registerFunction("getglobalvar", (sc, in) -> 
         {         
@@ -1840,7 +1890,7 @@ public class MinecraftFunctions
             {
                 if(o instanceof EntityPlayer)
                 {
-                    return KajetansMod.scripts.getDataBank(ScriptBank.class).getVar(in[1].getString(sc), ((EntityPlayer) o).getUniqueID().toString());
+                    return KajetansMod.scripts.getDataBank(ScriptBank.class).getVar(in[1].getString(sc), ((EntityPlayer) o).getCachedUniqueIdString());
                 }
                 else if(o.equals("SERVER"))
                 {
@@ -1850,7 +1900,7 @@ public class MinecraftFunctions
             }
             if(o instanceof EntityPlayer)
             {
-                return KajetansMod.scripts.getDataBank(ScriptBank.class).getVar(in[1].getString(sc), ((EntityPlayer) o).getUniqueID().toString(), in[2].get(sc));
+                return KajetansMod.scripts.getDataBank(ScriptBank.class).getVar(in[1].getString(sc), ((EntityPlayer) o).getCachedUniqueIdString(), in[2].get(sc));
             }
             else if(o.equals("SERVER"))
             {
@@ -1861,37 +1911,50 @@ public class MinecraftFunctions
         parser.registerAlias("getglobalvar", "ggv");
         parser.registerFunction("setglobalvar", (sc, in) -> 
         { 
-            Object o = in[0].get(sc);
+            final Object o = in[0].get(sc);
+            final String value = in[2].getString(sc);
+            final String var = in[1].getString(sc);
+            String uuid;
             if(o instanceof EntityPlayer)
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).setVar(in[2].getString(sc), in[1].getString(sc), ((EntityPlayer) o).getUniqueID().toString());
+                uuid = ((EntityPlayer) o).getCachedUniqueIdString();
             }
             else if(o.equals("SERVER"))
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).setVar(in[2].getString(sc), in[1].getString(sc), "-1");
+                uuid = "-1";
             }
             else
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).setVar(in[2].getString(sc), in[1].getString(sc), o.toString());
+                uuid = o.toString();
             }
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).setVar(value, var, uuid);
+            });
             return Void.TYPE; 
         });                          
         parser.registerAlias("setglobalvar", "sgv");
         parser.registerFunction("delglobalvar", (sc, in) -> 
         { 
-            Object o = in[0].get(sc);
+            final Object o = in[0].get(sc);
+            final String var = in[1].getString(sc);
+            String uuid;
             if(o instanceof EntityPlayer)
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).deleteVar(in[1].getString(sc), ((EntityPlayer) o).getUniqueID().toString());
+                uuid = ((EntityPlayer) o).getCachedUniqueIdString();
             }
             else if(o.equals("SERVER"))
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).deleteVar(in[1].getString(sc), "-1");
+                uuid = "-1";
             }
             else
             {
-                KajetansMod.scripts.getDataBank(ScriptBank.class).deleteVar(in[1].getString(sc), o.toString());
+                uuid = o.toString();
             }
+            KajetansMod.scheduler.getWorker().add(() -> 
+            {
+                KajetansMod.scripts.getDataBank(ScriptBank.class).deleteVar(var, uuid);
+            });
             return Void.TYPE; 
         }); 
         parser.registerAlias("delglobalvar", "dgv");
@@ -1915,7 +1978,8 @@ public class MinecraftFunctions
         });
         parser.registerFunction("command", (sc, in) -> 
         { 
-            KajetansMod.scheduler.scheduleTask(() -> KajetansMod.server.commandManager.executeCommand(KajetansMod.server, SnuviUtils.connect(sc, in, 0))); 
+            final String s = SnuviUtils.connect(sc, in, 0);
+            KajetansMod.scheduler.scheduleTask(() -> KajetansMod.server.commandManager.executeCommand(KajetansMod.server, s)); 
             return Void.TYPE;
         });
     }
@@ -1932,19 +1996,24 @@ public class MinecraftFunctions
         }
     }
     
-    // ---------------------------------------------------------------------------------    
-    // Block
-    // --------------------------------------------------------------------------------- 
-
     private static IBlockState getBlockState(Location l)
     {
         return l.getWorld().getBlockState(l.getBlockPos());
     }
 
-    // ---------------------------------------------------------------------------------    
-    // Gruppen-Handler
-    // --------------------------------------------------------------------------------- 
-
+    private static UUID getUUID(Object o)
+    {
+        if(o instanceof EntityPlayer)
+        {
+            return ((EntityPlayer) o).getUniqueID();
+        }
+        else if(o instanceof UUID)
+        {
+            return (UUID) o;
+        }
+        return UUID.fromString(o.toString());
+    }
+    
     public static void doForGroup(Object group, Script sc, Consumer<ICommandSender> c)
     {
         if(group instanceof String)

+ 2 - 3
src/main/java/me/km/snuviscript/ScriptEvents.java

@@ -44,7 +44,6 @@ import net.minecraftforge.event.world.BlockEvent;
 import net.minecraftforge.fml.common.eventhandler.Event;
 import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
 import net.minecraftforge.fml.common.gameevent.PlayerEvent;
-import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent;
 
 public class ScriptEvents extends ModuleListener
 {               
@@ -144,7 +143,7 @@ public class ScriptEvents extends ModuleListener
     }
     
     @SubscribeEvent
-    public void onPlayerPostRespawn(PlayerRespawnEvent e)
+    public void onPlayerPostRespawn(PlayerEvent.PlayerRespawnEvent e)
     {
         handleEvent(e.player, "player_post_respawn", sc -> {});
     }
@@ -473,7 +472,7 @@ public class ScriptEvents extends ModuleListener
     public void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent e)
     {    
         EntityPlayer p = e.player;
-        if(p == null)
+        if(p == null || e.player.ticksExisted < 20)
         {
             return;
         }

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

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

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

@@ -82,6 +82,8 @@ item.campFire.name=Camp Fire
 
 tile.lantern.name=Lantern
 
+tile.rtallGrass.name=Resistant Grass
+
 tile.fluid.poison.name=Poison
 tile.fluid.honey.name=Honey
 fluid.poison=Poison

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

@@ -0,0 +1,6 @@
+{
+    "parent": "block/tinted_cross",
+    "textures": {
+        "cross": "blocks/tallgrass"
+    }
+}