Bladeren bron

new hash based plot system

Kajetan Johannes Hammerle 4 jaren geleden
bovenliggende
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
     public void test(net.minecraftforge.eventbus.api.Event e)
     {
         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);
     }*/
 }

+ 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.PlayerBank;
 import me.km.playerbank.PlayerManager;
-import me.km.plots.DummyProtection;
-import me.km.plots.ProtectionBank;
 import me.km.plots.ProtectionEvents;
+import me.km.plots.WorldPlotMap;
 import me.km.scheduler.SnuviScheduler;
 import me.km.snuviscript.SnuviLogger;
 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.OnlyIn;
 import net.minecraftforge.common.MinecraftForge;
-import me.km.plots.IProtection;
 import me.km.snuviscript.CommandGiveUp;
 import me.km.snuviscript.CommandScript;
 import me.km.snuviscript.DummyScriptBank;
@@ -102,22 +100,20 @@ public class Server
         databank.startReconnecting(scheduler);
         
         // protections / block protections / player manager
-        IProtection protection;
+        WorldPlotMap plotMap = new WorldPlotMap();
         IBlockProtection blockProtection;
         IPlayerBank playerBank;
         if(databank.isDummyDatabank())
         {
-            protection = new DummyProtection(); 
             blockProtection = new DummyBlockProtection();
             playerBank = new DummyPlayerBank();
         }
         else
         {
-            protection = new ProtectionBank(databank); 
             blockProtection = new BlockProtectionBank(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));
         
         PlayerManager playerManager = new PlayerManager(logger, playerBank);
@@ -138,7 +134,7 @@ public class Server
         }
         MinecraftFunctions.registerFunctions(
                 scripts.getScriptManager(), scripts, perms, scheduler, server, playerBank, 
-                customEventCaller, scriptBank, databank, blockProtection, protection);
+                customEventCaller, scriptBank, databank, blockProtection, plotMap);
         
         MinecraftForge.EVENT_BUS.register(new WorldEvents());
         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) 
     {
+        if(perm.equals("plot.bypass"))
+        {
+            return false;
+        }
         if(debug)
         {
             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.entity.Entity;
 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.world.dimension.DimensionType;
 import net.minecraftforge.event.entity.EntityJoinWorldEvent;
@@ -22,43 +24,52 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
 
 public class ProtectionEvents
 {
-    private final static String PLOT_BYPASS = "plot.bypass";
-    
-    private final IProtection bank;
+    private final WorldPlotMap plots;
     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;
     }
     
+    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)
     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)
     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);
         }  
     }
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void WitherDragonProtection(EntityJoinWorldEvent e)
+    public void onBossSpawn(EntityJoinWorldEvent e)
     {
         EntityType type = e.getEntity().getType();
         if(type == EntityType.WITHER && e.getWorld().getDimension().getType() != DimensionType.THE_NETHER)
@@ -74,114 +85,78 @@ public class ProtectionEvents
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     public void onBucketFill(FillBucketEvent e)
     {
-        ModEntityPlayerMP p = (ModEntityPlayerMP) e.getEntityPlayer(); 
         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;
         }
-        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);
         }
     }
-    
-    // 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)
     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);
             }
         }
     }
-    
+
     @SubscribeEvent
     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
-    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)
@@ -193,13 +168,13 @@ public class ProtectionEvents
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     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;
         }  
         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);
         }
@@ -208,31 +183,25 @@ public class ProtectionEvents
     @SubscribeEvent(priority = EventPriority.HIGHEST)
     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);
-        }
+        }    
     }
     
     @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);
         }
     }
     
     @SubscribeEvent(priority = EventPriority.HIGHEST)
-    public void protectFromInteract(BlockEvent.FarmlandTrampleEvent e)
+    public void onFarmlandTrample(BlockEvent.FarmlandTrampleEvent e)
     {      
         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.permissions.PermissionManager;
 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.utils.Mapper;
 import me.km.utils.TableUtils;
@@ -151,7 +152,7 @@ public class MinecraftFunctions
             PermissionManager perms, SnuviScheduler scheduler, MinecraftServer server, 
             IPlayerBank playerBank, CustomEventCaller cec,
             IScriptBank scriptBank, DataBank dataBank, IBlockProtection blockProtection,
-            IProtection protection)
+            WorldPlotMap plots)
     {
         // ---------------------------------------------------------------------
         // Command-library  
@@ -1802,17 +1803,50 @@ public class MinecraftFunctions
         // ---------------------------------------------------------------------  
         // Plot-library   
         // ---------------------------------------------------------------------  
-        sm.registerFunction("plot.getids", (sc, in) -> 
+        sm.registerFunction("plot.get", (sc, in) -> 
         {  
             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);
-            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