Browse Source

new hash based plot system

Kajetan Johannes Hammerle 5 years ago
parent
commit
569b5737c3

+ 42 - 21
src/main/java/me/km/CommonEvents.java

@@ -15,39 +15,60 @@ public class CommonEvents
         }
         }
     }
     }
 
 
-    /*private static class Data
+    /*private static final java.util.HashSet<Class> test = new java.util.HashSet<>();
+    
+    static
     {
     {
-        private long[] time = new long[10];
-        private int index = 0;
+        test.add(net.minecraftforge.event.world.ChunkDataEvent.class);
+        test.add(net.minecraftforge.event.TickEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingSpawnEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingEvent.class);
+        test.add(net.minecraftforge.event.TickEvent.class);
+        test.add(net.minecraftforge.event.AttachCapabilitiesEvent.class);
+        test.add(net.minecraftforge.event.entity.EntityMobGriefingEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingDestroyBlockEvent.class);
+        test.add(net.minecraftforge.event.entity.PlaySoundAtEntityEvent.class);
+        test.add(net.minecraftforge.event.entity.EntityEvent.class);
+        test.add(net.minecraftforge.event.LootTableLoadEvent.class);
+        test.add(net.minecraftforge.event.world.ChunkEvent.class);
+        test.add(net.minecraftforge.event.world.WorldEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingFallEvent.class);
+        test.add(net.minecraftforge.event.entity.player.PlayerEvent.class);
+        test.add(net.minecraftforge.event.world.ChunkWatchEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingEntityUseItemEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent.class);
+        test.add(net.minecraftforge.event.entity.EntityJoinWorldEvent.class);
+        test.add(net.minecraftforge.event.entity.living.LivingPackSizeEvent.class);
     }
     }
     
     
-    private static java.util.HashMap<Class, Data> testMap = new java.util.HashMap<>();
+    @SubscribeEvent
+    public void onChat(net.minecraftforge.event.ServerChatEvent e)
+    {
+        try
+        {
+            Class c = Class.forName(e.getMessage());
+            if(!test.add(c))
+            {
+                test.remove(c);
+            }
+        }
+        catch(Exception ex)
+        {
+        }
+    }
     
     
     @SubscribeEvent
     @SubscribeEvent
     public void test(net.minecraftforge.eventbus.api.Event e)
     public void test(net.minecraftforge.eventbus.api.Event e)
     {
     {
         Class c = e.getClass();
         Class c = e.getClass();
-        Data data = testMap.get(c);
-        if(data != null && data.index >= 10)
+        if(c.getEnclosingClass() != null)
         {
         {
-            if(data.time[9] - data.time[0] < 1_000_000_000)
-            {
-                return;
-            }
-            else
-            {
-                data.index = 0;
-            }
+            c = c.getEnclosingClass();
         }
         }
-        
-        if(data == null)
+        if(test.contains(c))
         {
         {
-            data = new Data();
-            testMap.put(c, data);
+            return;
         }
         }
-        
-        data.time[data.index] = System.nanoTime();
-        data.index++;
         org.apache.logging.log4j.LogManager.getLogger().warn(c);
         org.apache.logging.log4j.LogManager.getLogger().warn(c);
     }*/
     }*/
 }
 }

+ 4 - 8
src/main/java/me/km/Server.java

@@ -16,9 +16,8 @@ import me.km.playerbank.DummyPlayerBank;
 import me.km.playerbank.IPlayerBank;
 import me.km.playerbank.IPlayerBank;
 import me.km.playerbank.PlayerBank;
 import me.km.playerbank.PlayerBank;
 import me.km.playerbank.PlayerManager;
 import me.km.playerbank.PlayerManager;
-import me.km.plots.DummyProtection;
-import me.km.plots.ProtectionBank;
 import me.km.plots.ProtectionEvents;
 import me.km.plots.ProtectionEvents;
+import me.km.plots.WorldPlotMap;
 import me.km.scheduler.SnuviScheduler;
 import me.km.scheduler.SnuviScheduler;
 import me.km.snuviscript.SnuviLogger;
 import me.km.snuviscript.SnuviLogger;
 import me.km.utils.ReflectionUtils;
 import me.km.utils.ReflectionUtils;
@@ -26,7 +25,6 @@ import net.minecraft.server.dedicated.DedicatedServer;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.Dist;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import net.minecraftforge.api.distmarker.OnlyIn;
 import net.minecraftforge.common.MinecraftForge;
 import net.minecraftforge.common.MinecraftForge;
-import me.km.plots.IProtection;
 import me.km.snuviscript.CommandGiveUp;
 import me.km.snuviscript.CommandGiveUp;
 import me.km.snuviscript.CommandScript;
 import me.km.snuviscript.CommandScript;
 import me.km.snuviscript.DummyScriptBank;
 import me.km.snuviscript.DummyScriptBank;
@@ -102,22 +100,20 @@ public class Server
         databank.startReconnecting(scheduler);
         databank.startReconnecting(scheduler);
         
         
         // protections / block protections / player manager
         // protections / block protections / player manager
-        IProtection protection;
+        WorldPlotMap plotMap = new WorldPlotMap();
         IBlockProtection blockProtection;
         IBlockProtection blockProtection;
         IPlayerBank playerBank;
         IPlayerBank playerBank;
         if(databank.isDummyDatabank())
         if(databank.isDummyDatabank())
         {
         {
-            protection = new DummyProtection(); 
             blockProtection = new DummyBlockProtection();
             blockProtection = new DummyBlockProtection();
             playerBank = new DummyPlayerBank();
             playerBank = new DummyPlayerBank();
         }
         }
         else
         else
         {
         {
-            protection = new ProtectionBank(databank); 
             blockProtection = new BlockProtectionBank(databank);
             blockProtection = new BlockProtectionBank(databank);
             playerBank = new PlayerBank(databank);
             playerBank = new PlayerBank(databank);
         }
         }
-        MinecraftForge.EVENT_BUS.register(new ProtectionEvents(protection, perms));
+        MinecraftForge.EVENT_BUS.register(new ProtectionEvents(plotMap, perms));
         MinecraftForge.EVENT_BUS.register(new BlockProtectionEvents(blockProtection, perms));
         MinecraftForge.EVENT_BUS.register(new BlockProtectionEvents(blockProtection, perms));
         
         
         PlayerManager playerManager = new PlayerManager(logger, playerBank);
         PlayerManager playerManager = new PlayerManager(logger, playerBank);
@@ -138,7 +134,7 @@ public class Server
         }
         }
         MinecraftFunctions.registerFunctions(
         MinecraftFunctions.registerFunctions(
                 scripts.getScriptManager(), scripts, perms, scheduler, server, playerBank, 
                 scripts.getScriptManager(), scripts, perms, scheduler, server, playerBank, 
-                customEventCaller, scriptBank, databank, blockProtection, protection);
+                customEventCaller, scriptBank, databank, blockProtection, plotMap);
         
         
         MinecraftForge.EVENT_BUS.register(new WorldEvents());
         MinecraftForge.EVENT_BUS.register(new WorldEvents());
         scripts.startScript("startscript");
         scripts.startScript("startscript");

+ 4 - 0
src/main/java/me/km/permissions/PermissionManager.java

@@ -55,6 +55,10 @@ public class PermissionManager
     
     
     public boolean hasPermission(UUID uuid, String perm) 
     public boolean hasPermission(UUID uuid, String perm) 
     {
     {
+        if(perm.equals("plot.bypass"))
+        {
+            return false;
+        }
         if(debug)
         if(debug)
         {
         {
             return true;
             return true;

+ 0 - 41
src/main/java/me/km/plots/DummyProtection.java

@@ -1,41 +0,0 @@
-package me.km.plots;
-
-import java.util.ArrayList;
-import me.km.overrides.ModEntityPlayerMP;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.IWorld;
-
-public class DummyProtection implements IProtection
-{
-    private final ArrayList<Double> list = new ArrayList<>();
-    
-    @Override
-    public ArrayList<Double> getIds(int x, int y, int z, String worldName)
-    {
-        return list;
-    }
-
-    @Override
-    public boolean canBuild(int x, int y, int z, String worldName, int playerId)
-    {
-        return true;
-    }
-
-    @Override
-    public boolean canBuild(IWorld w, BlockPos pos, ModEntityPlayerMP p)
-    {
-        return true;
-    }
-
-    @Override
-    public boolean hasPlots(int x, int y, int z, String worldName)
-    {
-        return false;
-    }
-
-    @Override
-    public boolean hasPlots(IWorld w, BlockPos pos)
-    {
-        return false;
-    }
-}

+ 0 - 15
src/main/java/me/km/plots/IProtection.java

@@ -1,15 +0,0 @@
-package me.km.plots;
-
-import java.util.ArrayList;
-import me.km.overrides.ModEntityPlayerMP;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.IWorld;
-
-public interface IProtection
-{
-    public boolean hasPlots(int x, int y, int z, String worldName);
-    public boolean hasPlots(IWorld w, BlockPos pos);
-    public ArrayList<Double> getIds(int x, int y, int z, String worldName);
-    public boolean canBuild(int x, int y, int z, String worldName, int playerId);
-    public boolean canBuild(IWorld w, BlockPos pos, ModEntityPlayerMP p);
-}

+ 322 - 0
src/main/java/me/km/plots/PlotMap.java

@@ -0,0 +1,322 @@
+package me.km.plots;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public class PlotMap
+{
+    public static class Plot
+    {
+        private Plot previous = null;
+        private Plot next = null;
+        
+        private final int id;
+        private final int minX;
+        private final int minY;
+        private final int minZ;
+        private final int maxX;
+        private final int maxY;
+        private final int maxZ;
+        
+        private final ArrayList<UUID> owners = new ArrayList<>(1);
+        private int flags = 0;
+        
+        private String name = "";
+
+        public Plot(int id, int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
+        {
+            this.id = id;
+            if(minX < maxX)
+            {
+                this.minX = minX;
+                this.maxX = maxX;
+            }
+            else
+            {
+                this.minX = maxX;
+                this.maxX = minX;
+            }
+
+            if(minY < maxY)
+            {
+                this.minY = minY;
+                this.maxY = maxY;
+            }
+            else
+            {
+                this.minY = maxY;
+                this.maxY = minY;
+            }
+
+            if(minZ < maxZ)
+            {
+                this.minZ = minZ;
+                this.maxZ = maxZ;
+            }
+            else
+            {
+                this.minZ = maxZ;
+                this.maxZ = minZ;
+            }
+        }
+
+        private boolean isInside(int x, int y, int z)
+        {
+            return minX <= x && x <= maxX && minY <= y && y <= maxY && minZ <= z && z <= maxZ;
+        }
+
+        public int getMinX()
+        {
+            return minX;
+        }
+
+        public int getMinY()
+        {
+            return minY;
+        }
+
+        public int getMinZ()
+        {
+            return minZ;
+        }
+
+        public int getMaxX()
+        {
+            return maxX;
+        }
+
+        public int getMaxY()
+        {
+            return maxY;
+        }
+
+        public int getMaxZ()
+        {
+            return maxZ;
+        }
+        
+        public int getFlags()
+        {
+            return flags;
+        }
+        
+        public boolean hasFlags(int flags)
+        {
+            return (flags & this.flags) == flags;
+        }
+        
+        public void setFlag(int flags, boolean b)
+        {
+            if(b)
+            {
+                this.flags |= flags;
+            }
+            else
+            {
+                this.flags &= ~flags;
+            }
+        }
+        
+        public ArrayList<UUID> getOwners()
+        {
+            return owners;
+        }
+        
+        public void setName(String s)
+        {
+            name = s;
+        }
+
+        public String getName()
+        {
+            return name;
+        }
+
+        public int getId()
+        {
+            return id;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("Plot(%d, %d, %d, %d, %d, %d)", minX, minY, minZ, maxX, maxY, maxZ);
+        }
+    }
+    
+    private static int idCounter = 0;
+
+    private static final int SIZE_FACTOR = 64;
+    private final static int[] PRIMES = 
+    {
+        17, 37, 79, 163, 331, 673, 1361, 2729, 5471, 10949, 21911, 43853, 87719, 
+        175447, 350899, 701819, 1403641, 2807303, 5614657, 11229331, 22458671,
+        44917381, 89834777, 179669557, 359339171, 718678369
+    };
+    
+    private int primeIndex = 0;
+    private int size = 0;
+    private ArrayList<Plot>[] plots = new ArrayList[PRIMES[primeIndex]];
+    private Plot last = null;
+    
+    public PlotMap()
+    {
+    }
+    
+    private int hash(int x, int z, int arrayLength)
+    {
+        int h = (x + z * 12195263) % arrayLength;
+        if(h < 0)
+        {
+            return h + arrayLength;
+        }
+        return h;
+    }
+    
+    private void rehash()
+    {
+        // load factor 0.75
+        if(size < (plots.length * 3 / 4) || primeIndex + 1 >= PRIMES.length)
+        {
+            return;
+        }
+        primeIndex++;
+        ArrayList<Plot>[] newPlots = new ArrayList[PRIMES[primeIndex]];
+        Plot p = last;
+        while(p != null)
+        {
+            addIntern(newPlots, p, newPlots.length);
+            p = p.previous;
+        }
+        plots = newPlots;
+    }
+    
+    private void addIntern(ArrayList<Plot>[] data, Plot p, int arrayLength)
+    {
+        int startX = Math.floorDiv(p.minX, SIZE_FACTOR);
+        int startZ = Math.floorDiv(p.minZ, SIZE_FACTOR);
+        int endX = Math.floorDiv(p.maxX, SIZE_FACTOR);
+        int endZ = Math.floorDiv(p.maxZ, SIZE_FACTOR);
+
+        for(int x = startX; x <= endX; x++)
+        {
+            for(int z = startZ; z <= endZ; z++)
+            {
+                int hash = hash(x, z, arrayLength);
+                if(data[hash] == null)
+                {
+                    data[hash] = new ArrayList<>();
+                }
+                data[hash].add(p);
+            }
+        }
+    }
+    
+    public Plot add(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, int id)
+    {
+        if(id >= idCounter)
+        {
+            idCounter = id + 1;
+        }
+        
+        Plot p = new Plot(id, minX, minY, minZ, maxX, maxY, maxZ);
+        
+        if(last == null)
+        {
+            last = p;
+        }
+        else
+        {
+            last.next = p;
+            p.previous = last;
+            last = p;
+        }
+        
+        size++;
+        rehash();
+        
+        addIntern(plots, p, plots.length);
+        return p;
+    }
+    
+    public Plot add(int minX, int minY, int minZ, int maxX, int maxY, int maxZ)
+    {
+        return add(minX, minY, minZ, maxX, maxY, maxZ, idCounter);
+    }
+    
+    public List<Plot> getPlotAt(int x, int y, int z)
+    {
+        ArrayList<Plot> list = plots[hash(x / SIZE_FACTOR, z / SIZE_FACTOR, plots.length)];
+        if(list == null)
+        {
+            return new ArrayList<>();
+        }
+        return list.stream().filter(p -> p.isInside(x, y, z)).collect(Collectors.toList());
+    }
+    
+    public boolean anyPlotMatches(int x, int y, int z, boolean empty, Predicate<Plot> pred)
+    {
+        ArrayList<Plot> list = plots[hash(x / SIZE_FACTOR, z / SIZE_FACTOR, plots.length)];
+        if(list == null)
+        {
+            return empty;
+        }
+        boolean r = empty;
+        for(Plot p : list)
+        {
+            if(p.isInside(x, y, z))
+            {
+                if(pred.test(p))
+                {
+                    return true;
+                }
+                r = false;
+            }
+        }
+        return r;
+    }
+    
+    public void remove(Plot p)
+    {
+        if(last == p)
+        {
+            last = last.previous;
+            if(last != null)
+            {
+                last.next = null;
+            }
+        }
+        else
+        {
+            if(p.previous != null)
+            {
+                p.previous.next = p.next;
+            }
+            if(p.next != null)
+            {
+                p.next.previous = p.previous;
+            }
+        }
+        
+        int startX = Math.floorDiv(p.minX, SIZE_FACTOR);
+        int startZ = Math.floorDiv(p.minZ, SIZE_FACTOR);
+        int endX = Math.floorDiv(p.maxX, SIZE_FACTOR);
+        int endZ = Math.floorDiv(p.maxZ, SIZE_FACTOR);
+
+        for(int x = startX; x <= endX; x++)
+        {
+            for(int z = startZ; z <= endZ; z++)
+            {
+                int hash = hash(x, z, plots.length);
+                if(plots[hash] == null)
+                {
+                    throw new NullPointerException("plot without list at location");
+                }
+                plots[hash].remove(p);
+            }
+        }
+    }
+}

+ 0 - 153
src/main/java/me/km/plots/ProtectionBank.java

@@ -1,153 +0,0 @@
-package me.km.plots;
-
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import me.km.databank.DataBank;
-import me.km.overrides.ModEntityPlayerMP;
-import me.km.world.WorldManager;
-import net.minecraft.util.math.BlockPos;
-import net.minecraft.world.IWorld;
-
-public class ProtectionBank implements IProtection
-{
-    private final PreparedStatement getIds;
-    private final PreparedStatement canBuild;
-    
-    public ProtectionBank(DataBank databank) 
-    {
-        databank.execute("CREATE TABLE IF NOT EXISTS plots ("
-                    + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
-                    + "x1 int(11) NOT NULL, "
-                    + "y1 int(11) NOT NULL, "
-                    + "z1 int(11) NOT NULL, "
-                    + "x2 int(11) NOT NULL, "
-                    + "y2 int(11) NOT NULL, "
-                    + "z2 int(11) NOT NULL, "
-                    + "world_name varchar(20) NOT NULL, "
-                    + "name varchar(50) NOT NULL, "
-                    + "INDEX (x1, x2), "
-                    + "INDEX (y1, y2), "
-                    + "INDEX (z1, z2), "
-                    + "INDEX (world_name));");
-        
-        databank.execute("CREATE TABLE IF NOT EXISTS plot_grant ("
-                    + "id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, "
-                    + "plot_id int(11) NOT NULL, "
-                    + "player_id int(11) NOT NULL, "
-                    + "INDEX plot_id (plot_id), "
-                    + "UNIQUE KEY (plot_id, player_id), "
-                    + "CONSTRAINT plot_grant_ibfk_1 FOREIGN KEY (plot_id) REFERENCES plots (id) ON DELETE CASCADE);");
-        
-        getIds = databank.prepareStatement("SELECT id FROM plots WHERE x1<=? AND x2>=? AND y1<=? AND y2>=? AND z1<=? AND z2>=? AND world_name=?;");
-        canBuild = databank.prepareStatement("SELECT id FROM plot_grant WHERE plot_id=? AND player_id=?;");
-    }
-    
-    @Override
-    public ArrayList<Double> getIds(int x, int y, int z, String worldName)
-    {
-        ArrayList<Double> list = new ArrayList<>();
-        try
-        {
-            getIds.setInt(1, x);
-            getIds.setInt(2, x);
-            getIds.setInt(3, y);
-            getIds.setInt(4, y);
-            getIds.setInt(5, z);
-            getIds.setInt(6, z);
-            getIds.setString(7, worldName);
-            try(ResultSet rs = getIds.executeQuery())
-            {
-                while(rs.next())
-                {
-                    list.add((double) rs.getInt(1));
-                }
-            }
-            catch(SQLException ex)
-            {
-                ex.printStackTrace();
-            }
-        }
-        catch(SQLException ex)
-        {
-            ex.printStackTrace();
-        }
-        return list;
-    }
-    
-    @Override
-    public boolean hasPlots(int x, int y, int z, String worldName)
-    {
-        try
-        {
-            getIds.setInt(1, x);
-            getIds.setInt(2, x);
-            getIds.setInt(3, y);
-            getIds.setInt(4, y);
-            getIds.setInt(5, z);
-            getIds.setInt(6, z);
-            getIds.setString(7, worldName);
-            try(ResultSet rs = getIds.executeQuery())
-            {
-                return rs.next();
-            }
-            catch(SQLException ex)
-            {
-                ex.printStackTrace();
-            }
-        }
-        catch(SQLException ex)
-        {
-            ex.printStackTrace();
-        }
-        return false;
-    }
-    
-    
-    @Override
-    public boolean hasPlots(IWorld w, BlockPos pos)
-    {
-        return hasPlots(pos.getX(), pos.getY(), pos.getZ(), WorldManager.getName(w));
-    }
-    
-    @Override
-    public boolean canBuild(int x, int y, int z, String worldName, int playerId)
-    {
-        ArrayList<Double> ids = getIds(x, y, z, worldName);
-        if(ids.isEmpty())
-        {
-            return true;
-        }
-        for(double plotId : ids)
-        {
-            try
-            {
-                canBuild.setInt(1, (int) plotId);
-                canBuild.setInt(2, playerId);
-                try(ResultSet rs = canBuild.executeQuery())
-                {
-                    if(rs.next())
-                    {
-                        return true;
-                    }
-                }
-                catch(SQLException ex)
-                {
-                    ex.printStackTrace();
-                }
-            }
-            catch(SQLException ex)
-            {
-                ex.printStackTrace();
-            }
-        }
-        return false;
-    }
-    
-    @Override
-    public boolean canBuild(IWorld w, BlockPos pos, ModEntityPlayerMP p)
-    {
-        return canBuild(pos.getX(), pos.getY(), pos.getZ(), WorldManager.getName(w), p.getId());
-    }
-}

+ 78 - 109
src/main/java/me/km/plots/ProtectionEvents.java

@@ -6,7 +6,9 @@ import net.minecraft.block.Block;
 import net.minecraft.block.Blocks;
 import net.minecraft.block.Blocks;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.Entity;
 import net.minecraft.entity.EntityType;
 import net.minecraft.entity.EntityType;
-import net.minecraft.util.math.BlockPos;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.util.math.BlockRayTraceResult;
+import net.minecraft.util.math.EntityRayTraceResult;
 import net.minecraft.util.math.RayTraceResult;
 import net.minecraft.util.math.RayTraceResult;
 import net.minecraft.world.dimension.DimensionType;
 import net.minecraft.world.dimension.DimensionType;
 import net.minecraftforge.event.entity.EntityJoinWorldEvent;
 import net.minecraftforge.event.entity.EntityJoinWorldEvent;
@@ -22,43 +24,52 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
 
 
 public class ProtectionEvents
 public class ProtectionEvents
 {
 {
-    private final static String PLOT_BYPASS = "plot.bypass";
-    
-    private final IProtection bank;
+    private final WorldPlotMap plots;
     private final PermissionManager perms;
     private final PermissionManager perms;
     
     
-    public ProtectionEvents(IProtection bank, PermissionManager perms)
+    public ProtectionEvents(WorldPlotMap plotMap, PermissionManager perms)
     {
     {
-        this.bank = bank;
+        this.plots = plotMap;
         this.perms = perms;
         this.perms = perms;
     }
     }
     
     
+    private boolean canBypass(PlayerEntity p)
+    {
+        return perms.hasPermission(p, "plot.bypass");
+    }
+    
+    private boolean shouldBeProtected(Entity ent)
+    {
+        EntityType type = ent.getType();
+        return type == EntityType.ITEM_FRAME || type == EntityType.PAINTING || type == EntityType.ARMOR_STAND;
+    }
+    
+    
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onBlockPlace(BlockEvent.EntityPlaceEvent e)
     public void onBlockPlace(BlockEvent.EntityPlaceEvent e)
     {
     {
-        if(!(e.getEntity() instanceof ModEntityPlayerMP))
+        if(e.getEntity() instanceof PlayerEntity)
         {
         {
-            return;
-        }
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntity();
-        if(!perms.hasPermission(p, PLOT_BYPASS) && !bank.canBuild(e.getWorld(), e.getPos(), p))
-        {
-            e.setCanceled(true);
-        }        
+            PlayerEntity p = (PlayerEntity) e.getEntity();
+            if(!canBypass(p) && !plots.canPlaceBlock(e.getWorld(), e.getPos(), p))
+            {
+                e.setCanceled(true);
+            }  
+        }   
     }
     }
     
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onBlockBreak(BlockEvent.BreakEvent e)
     public void onBlockBreak(BlockEvent.BreakEvent e)
     {
     {
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getPlayer();
-        if(!perms.hasPermission(p, PLOT_BYPASS) && !bank.canBuild(e.getWorld(), e.getPos(), p))
+        PlayerEntity p = e.getPlayer();
+        if(!canBypass(p) && !plots.canBreakBlock(e.getWorld(), e.getPos(), p))
         {
         {
             e.setCanceled(true);
             e.setCanceled(true);
         }  
         }  
     }
     }
     
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void WitherDragonProtection(EntityJoinWorldEvent e)
+    public void onBossSpawn(EntityJoinWorldEvent e)
     {
     {
         EntityType type = e.getEntity().getType();
         EntityType type = e.getEntity().getType();
         if(type == EntityType.WITHER && e.getWorld().getDimension().getType() != DimensionType.THE_NETHER)
         if(type == EntityType.WITHER && e.getWorld().getDimension().getType() != DimensionType.THE_NETHER)
@@ -74,114 +85,78 @@ public class ProtectionEvents
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onBucketFill(FillBucketEvent e)
     public void onBucketFill(FillBucketEvent e)
     {
     {
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntityPlayer(); 
         RayTraceResult ray = e.getTarget();
         RayTraceResult ray = e.getTarget();
-        if(ray == null || ray.hitInfo == null || ray.getType() != RayTraceResult.Type.BLOCK || perms.hasPermission(p, PLOT_BYPASS))
+        if(ray == null || ray.getType() != RayTraceResult.Type.BLOCK || canBypass(e.getPlayer()))
         {
         {
             return;
             return;
         }
         }
-        BlockPos pos = new BlockPos(ray.getHitVec());
-        if(!bank.canBuild(e.getWorld(), pos, p))
+        if(!plots.canUseBucket(e.getWorld(), ((BlockRayTraceResult) ray).getPos(), e.getPlayer()))
         {
         {
             e.setCanceled(true);
             e.setCanceled(true);
         }
         }
     }
     }
-    
-    // TODO:protection / entity with uuids
-    /*@SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void EntityProtection(LivingAttackEvent e)
-    {  
-        e.getEntity().getUniqueID()
-        EntityLivingBase ent = e.getEntityLiving();
-        if(!this.getProtectionBank().isProtected(ent.getClass()))
-        {
-            return;
-        }
-        World w = ent.world;
-        BlockPos pos = ent.getPosition();
-        if(!this.getProtectionBank().hasProtection(w, pos) || 
-            (ent instanceof EntityAnimal && this.getProtectionBank().hasTag(w, pos, "animal")))
-        {
-            return;
-        } 
-        
-        if(e.getSource().getImmediateSource() != null)
-        {
-            EntityPlayer p = Utils.getDamager(e.getSource());
-            if(p != null)
-            {
-                if(perms.hasPermission(p, Permissions.PLOT_BYPASS) || this.getProtectionBank().canBuild(w, pos, p))
-                {
-                    return;
-                }
-                e.setCanceled(true);
-            }
-        }   
-        e.setCanceled(true);
-    }
-    
-    @SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void EntityProtectionPotion(ThrowableImpactEvent e)
-    {
-        if(e.getEntityThrowable() instanceof EntityPotion)
-        {
-            EntityPotion potion = (EntityPotion) e.getEntityThrowable();
-            EntityLivingBase ent = potion.getThrower();
-            if(ent instanceof EntityPlayer && !perms.hasPermission(ent, Permissions.PLOT_BYPASS) &&
-                !this.getProtectionBank().canBuild(potion.world, potion.getPosition(), (EntityPlayer) ent))
-            {
-                e.setCanceled(true);
-            }
-        }
-    }*/
-    
+
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onEntityHit(AttackEntityEvent e)
     public void onEntityHit(AttackEntityEvent e)
     {
     {
-        EntityType type = e.getTarget().getType();
-        if(type == EntityType.ITEM_FRAME || type == EntityType.PAINTING || type == EntityType.ARMOR_STAND)
+        if(shouldBeProtected(e.getTarget()))
         {
         {
-            ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntityPlayer();
-            if(!perms.hasPermission(p, PLOT_BYPASS) && 
-                !bank.canBuild(p.world, e.getTarget().getPosition(), p))
+            PlayerEntity p = e.getPlayer();
+            if(!canBypass(p) && !plots.canHitAmbientEntity(p.world, e.getTarget().getPosition(), p))
             {
             {
                 e.setCanceled(true);
                 e.setCanceled(true);
             }
             }
         }
         }
     }
     }
-    
+
     @SubscribeEvent
     @SubscribeEvent
     public void onThrowableImpace(ProjectileImpactEvent.Throwable e)
     public void onThrowableImpace(ProjectileImpactEvent.Throwable e)
     {
     {
-        Entity ent = e.getThrowable().getThrower();
-        if(ent == null || !(ent instanceof ModEntityPlayerMP))
+        if(e.getRayTraceResult().getType() == RayTraceResult.Type.ENTITY)
         {
         {
-            if(bank.hasPlots(0, 0, 0, PLOT_BYPASS))
+            EntityRayTraceResult result = (EntityRayTraceResult) e.getRayTraceResult();
+            if(shouldBeProtected(result.getEntity()))
             {
             {
-                e.setCanceled(true);
+                Entity thrower = e.getThrowable().getThrower();
+                if(thrower != null && (thrower instanceof PlayerEntity))
+                {
+                    PlayerEntity p = (PlayerEntity) thrower;
+                    if(!canBypass(p) && !plots.canHitAmbientEntity(p.world, e.getThrowable().getPosition(), p))
+                    {
+                        e.setCanceled(true);
+                    }
+                }
+                else
+                {
+                    e.setCanceled(true);
+                }
             }
             }
         }
         }
-        else if(!perms.hasPermission(ent, PLOT_BYPASS) && !bank.canBuild(ent.world, ent.getPosition(), (ModEntityPlayerMP) ent))
-        {
-            e.setCanceled(true);
-        }
     }
     }
     
     
     @SubscribeEvent
     @SubscribeEvent
-    public void onThrowableImpace(ProjectileImpactEvent.Arrow e)
+    public void onThrowableImpact(ProjectileImpactEvent.Arrow e)
     {
     {
-        Entity ent = e.getArrow().getShooter();
-        if(ent == null || !(ent instanceof ModEntityPlayerMP))
+        if(e.getRayTraceResult().getType() == RayTraceResult.Type.ENTITY)
         {
         {
-            if(bank.hasPlots(0, 0, 0, PLOT_BYPASS))
+            EntityRayTraceResult result = (EntityRayTraceResult) e.getRayTraceResult();
+            if(shouldBeProtected(result.getEntity()))
             {
             {
-                e.setCanceled(true);
+                Entity shooter = e.getArrow().getShooter();
+                if(shooter != null && (shooter instanceof ModEntityPlayerMP))
+                {
+                    PlayerEntity p = (PlayerEntity) shooter;
+                    if(!canBypass(p) && !plots.canHitAmbientEntity(p.world, e.getArrow().getPosition(), p))
+                    {
+                        e.setCanceled(true);
+                    }
+                }
+                else
+                {
+                    e.setCanceled(true);
+                }
             }
             }
         }
         }
-        else if(!perms.hasPermission(ent, PLOT_BYPASS) && !bank.canBuild(ent.world, ent.getPosition(), (ModEntityPlayerMP) ent))
-        {
-            e.setCanceled(true);
-        }
     }
     }
     
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
@@ -193,13 +168,13 @@ public class ProtectionEvents
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onPlayerInteract(PlayerInteractEvent.LeftClickBlock e) 
     public void onPlayerInteract(PlayerInteractEvent.LeftClickBlock e) 
     {
     {
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntityPlayer();
-        if(perms.hasPermission(p, PLOT_BYPASS))
+        PlayerEntity p = e.getPlayer();
+        if(canBypass(p))
         {
         {
             return;
             return;
         }  
         }  
         Block b = e.getWorld().getBlockState(e.getPos()).getBlock();
         Block b = e.getWorld().getBlockState(e.getPos()).getBlock();
-        if(b == Blocks.FIRE && !bank.canBuild(e.getWorld(), e.getPos(), p)) 
+        if(b == Blocks.FIRE && !plots.canBreakBlock(e.getWorld(), e.getPos(), p)) 
         {
         {
             e.setCanceled(true);
             e.setCanceled(true);
         }
         }
@@ -208,31 +183,25 @@ public class ProtectionEvents
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onPlayerInteract(PlayerInteractEvent.RightClickBlock e) 
     public void onPlayerInteract(PlayerInteractEvent.RightClickBlock e) 
     {
     {
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntityPlayer();
-        if(perms.hasPermission(p, PLOT_BYPASS))
-        {
-            return;
-        }    
-        Block b = e.getWorld().getBlockState(e.getPos()).getBlock();
-        if(!bank.canBuild(e.getWorld(), e.getPos(), p))
+        PlayerEntity p = e.getPlayer();
+        if(!canBypass(p) && !plots.canInteractWithBlock(e.getWorld(), e.getPos(), p))
         {
         {
             e.setCanceled(true);
             e.setCanceled(true);
-        }
+        }    
     }
     }
     
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void protectFromInteract(PlayerInteractEvent.EntityInteract e)
+    public void onPlayerEntityInteract(PlayerInteractEvent.EntityInteract e)
     {      
     {      
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntityPlayer();
-        if(!perms.hasPermission(p, PLOT_BYPASS) && 
-            !bank.canBuild(e.getWorld(), e.getTarget().getPosition(), p))
+        PlayerEntity p = e.getPlayer();
+        if(!canBypass(p) && !plots.canInteractWithEntity(e.getWorld(), e.getTarget().getPosition(), p))
         {
         {
             e.setCanceled(true);
             e.setCanceled(true);
         }
         }
     }
     }
     
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     @SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void protectFromInteract(BlockEvent.FarmlandTrampleEvent e)
+    public void onFarmlandTrample(BlockEvent.FarmlandTrampleEvent e)
     {      
     {      
         e.setCanceled(true);
         e.setCanceled(true);
     }
     }

+ 98 - 0
src/main/java/me/km/plots/WorldPlotMap.java

@@ -0,0 +1,98 @@
+package me.km.plots;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import me.km.plots.PlotMap.Plot;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.IWorld;
+
+public class WorldPlotMap
+{
+    private final HashMap<IWorld, PlotMap> maps = new HashMap<>();
+    
+    private final static int PLACE_FLAG = (1 << 0);
+    private final static int BREAK_FLAG = (1 << 1);
+    private final static int BUCKET_FLAG = (1 << 2);
+    private final static int HIT_AMBIENT_FLAG = (1 << 3);
+    private final static int BLOCK_INTERACT_FLAG = (1 << 4);
+    private final static int ENTITY_INTERACT_FLAG = (1 << 5);
+    
+    public boolean canDoSomething(IWorld w, BlockPos pos, PlayerEntity p, int flag, boolean empty)
+    {
+        PlotMap map = maps.get(w);
+        if(map == null)
+        {
+            return empty;
+        }
+        if(p == null)
+        {
+            return map.anyPlotMatches(pos.getX(), pos.getY(), pos.getZ(), empty, plot -> plot.hasFlags(flag));
+        }
+        UUID uuid = p.getUniqueID();
+        return map.anyPlotMatches(pos.getX(), pos.getY(), pos.getZ(), empty, 
+                plot -> plot.hasFlags(flag) || plot.getOwners().contains(uuid));
+    }
+    
+    public boolean canPlaceBlock(IWorld w, BlockPos pos, PlayerEntity p)
+    {
+        return canDoSomething(w, pos, p, PLACE_FLAG, true);
+    }
+    
+    public boolean canBreakBlock(IWorld w, BlockPos pos, PlayerEntity p)
+    {
+        return canDoSomething(w, pos, p, BREAK_FLAG, true);
+    }
+    
+    public boolean canUseBucket(IWorld w, BlockPos pos, PlayerEntity p)
+    {
+        return canDoSomething(w, pos, p, BUCKET_FLAG, true);
+    }
+    
+    public boolean canHitAmbientEntity(IWorld w, BlockPos pos, PlayerEntity p)
+    {
+        return canDoSomething(w, pos, p, HIT_AMBIENT_FLAG, true);
+    }
+    
+    public boolean canInteractWithBlock(IWorld w, BlockPos pos, PlayerEntity p)
+    {
+        return canDoSomething(w, pos, p, BLOCK_INTERACT_FLAG, true);
+    }
+    
+    public boolean canInteractWithEntity(IWorld w, BlockPos pos, PlayerEntity p)
+    {
+        return canDoSomething(w, pos, p, ENTITY_INTERACT_FLAG, true);
+    }
+    
+    public List<PlotMap.Plot> getPlots(IWorld w, BlockPos pos)
+    {
+        PlotMap map = maps.get(w);
+        if(map == null)
+        {
+            return new ArrayList<>();
+        }
+        return map.getPlotAt(pos.getX(), pos.getY(), pos.getZ());
+    }
+    
+    public Plot add(IWorld w, BlockPos pos1, BlockPos pos2)
+    {
+        PlotMap map = maps.get(w);
+        if(map == null)
+        {
+            map = new PlotMap();
+            maps.put(w, map);
+        }
+        return map.add(pos1.getX(), pos1.getY(), pos1.getZ(), pos2.getX(), pos2.getY(), pos2.getZ());
+    }
+    
+    public void remove(IWorld w, Plot p)
+    {
+        PlotMap map = maps.get(w);
+        if(map != null)
+        {
+            map.remove(p);
+        }
+    }
+}

+ 41 - 7
src/main/java/me/km/snuviscript/MinecraftFunctions.java

@@ -48,7 +48,8 @@ import me.km.networking.ModPacketHandler;
 import me.km.overrides.ModEntityPlayerMP;
 import me.km.overrides.ModEntityPlayerMP;
 import me.km.permissions.PermissionManager;
 import me.km.permissions.PermissionManager;
 import me.km.playerbank.IPlayerBank;
 import me.km.playerbank.IPlayerBank;
-import me.km.plots.IProtection;
+import me.km.plots.PlotMap.Plot;
+import me.km.plots.WorldPlotMap;
 import me.km.scheduler.SnuviScheduler;
 import me.km.scheduler.SnuviScheduler;
 import me.km.utils.Mapper;
 import me.km.utils.Mapper;
 import me.km.utils.TableUtils;
 import me.km.utils.TableUtils;
@@ -151,7 +152,7 @@ public class MinecraftFunctions
             PermissionManager perms, SnuviScheduler scheduler, MinecraftServer server, 
             PermissionManager perms, SnuviScheduler scheduler, MinecraftServer server, 
             IPlayerBank playerBank, CustomEventCaller cec,
             IPlayerBank playerBank, CustomEventCaller cec,
             IScriptBank scriptBank, DataBank dataBank, IBlockProtection blockProtection,
             IScriptBank scriptBank, DataBank dataBank, IBlockProtection blockProtection,
-            IProtection protection)
+            WorldPlotMap plots)
     {
     {
         // ---------------------------------------------------------------------
         // ---------------------------------------------------------------------
         // Command-library  
         // Command-library  
@@ -1802,17 +1803,50 @@ public class MinecraftFunctions
         // ---------------------------------------------------------------------  
         // ---------------------------------------------------------------------  
         // Plot-library   
         // Plot-library   
         // ---------------------------------------------------------------------  
         // ---------------------------------------------------------------------  
-        sm.registerFunction("plot.getids", (sc, in) -> 
+        sm.registerFunction("plot.get", (sc, in) -> 
         {  
         {  
             Location l = (Location) in[0].get(sc);
             Location l = (Location) in[0].get(sc);
-            BlockPos pos = l.getBlockPos();
-            return protection.getIds(pos.getX(), pos.getY(), pos.getZ(), WorldManager.getName(l.getWorld())); 
+            return plots.getPlots(l.getWorld(), l.getBlockPos()); 
         });
         });
-        sm.registerFunction("plot.canbuild", (sc, in) -> 
+        sm.registerFunction("plot.check", (sc, in) -> 
         {    
         {    
             Location l = (Location) in[0].get(sc);
             Location l = (Location) in[0].get(sc);
-            return protection.canBuild(l.getWorld(), l.getBlockPos(), (ModEntityPlayerMP) in[1].get(sc));
+            ModEntityPlayerMP p = (ModEntityPlayerMP) in[1].get(sc);
+            int flags = in[2].getInt(sc);
+            boolean empty = in[3].getBoolean(sc);
+            return plots.canDoSomething(l.getWorld(), l.getBlockPos(), p, flags, empty);
+        });
+        sm.registerFunction("plot.setflags", (sc, in) -> 
+        {    
+            Plot p = (Plot) in[0].get(sc);
+            p.setFlag(in[1].getInt(sc), in[2].getBoolean(sc));
+            return Void.TYPE;
+        });
+        sm.registerFunction("plot.hasflags", (sc, in) -> ((Plot) in[0].get(sc)).hasFlags(in[1].getInt(sc)));
+        sm.registerFunction("plot.getflags", (sc, in) -> (double) ((Plot) in[0].get(sc)).getFlags());
+        sm.registerFunction("plot.getowners", (sc, in) -> ((Plot) in[0].get(sc)).getOwners());
+        sm.registerFunction("plot.add", (sc, in) -> 
+        {    
+            Location l1 = (Location) in[0].get(sc);
+            Location l2 = (Location) in[1].get(sc);
+            if(l1.getWorld() != l2.getWorld())
+            {
+                throw new IllegalArgumentException("worlds not equal for locations");
+            }
+            return plots.add(l1.getWorld(), l1.getBlockPos(), l2.getBlockPos());
+        });
+        sm.registerFunction("plot.remove", (sc, in) -> 
+        {    
+            plots.remove((IWorld) in[1].get(sc), (Plot) in[0].get(sc));
+            return Void.TYPE;
+        });
+        sm.registerFunction("plot.getname", (sc, in) -> ((Plot) in[0].get(sc)).getName());
+        sm.registerFunction("plot.setname", (sc, in) -> 
+        {    
+            ((Plot) in[0].get(sc)).setName(in[1].getString(sc));
+            return Void.TYPE;
         });
         });
+        sm.registerFunction("plot.getid", (sc, in) -> (double) ((Plot) in[0].get(sc)).getId());
         
         
         // ---------------------------------------------------------------------  
         // ---------------------------------------------------------------------  
         // block protection library   
         // block protection library