Store fence objects in regions.

This commit is contained in:
MobiusDevelopment 2021-03-14 22:03:28 +00:00
parent 031006131b
commit a8c77b8795
92 changed files with 1570 additions and 652 deletions

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
@ -33,7 +30,6 @@ import org.w3c.dom.Node;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.gameserver.enums.FenceState; import org.l2jmobius.gameserver.enums.FenceState;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World; import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldRegion; import org.l2jmobius.gameserver.model.WorldRegion;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance; import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
@ -47,7 +43,6 @@ public class FenceData
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -126,21 +121,12 @@ public class FenceData
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
final Location point = new Location(fence.getX(), fence.getY(), fence.getZ());
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(point), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final Location point = new Location(fence.getX(), fence.getY(), fence.getZ());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(point));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -155,12 +141,19 @@ public class FenceData
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -169,40 +162,30 @@ public class FenceData
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) continue;
{
return false;
}
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
if (crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax))
{ {
if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) return true;
{
return true;
}
} }
}
return false; return false;
};
return _regions.getOrDefault(World.getInstance().getRegion(new Location(x, y, z)), Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -460,6 +460,11 @@ public abstract class WorldObject
return false; return false;
} }
public boolean isFence()
{
return false;
}
public boolean isBoat() public boolean isBoat()
{ {
return false; return false;

View File

@ -31,6 +31,7 @@ import org.l2jmobius.gameserver.data.sql.SpawnTable;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance; import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
import org.l2jmobius.gameserver.model.spawn.Spawn; import org.l2jmobius.gameserver.model.spawn.Spawn;
import org.l2jmobius.gameserver.model.zone.ZoneManager; import org.l2jmobius.gameserver.model.zone.ZoneManager;
@ -45,6 +46,7 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
private final List<FenceInstance> _fences = new ArrayList<>(1);
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
private final int _regionY; private final int _regionY;
@ -241,7 +243,7 @@ public class WorldRegion
_active = value; _active = value;
// turn the AI on or off to match the region's activation. // Turn the AI on or off to match the region's activation.
switchAI(value); switchAI(value);
} }
@ -305,8 +307,7 @@ public class WorldRegion
/** /**
* Add the WorldObject in the WorldObjectHashSet(WorldObject) _visibleObjects containing WorldObject visible in this WorldRegion<br> * Add the WorldObject in the WorldObjectHashSet(WorldObject) _visibleObjects containing WorldObject visible in this WorldRegion<br>
* If WorldObject is a PlayerInstance, Add the PlayerInstance in the WorldObjectHashSet(PlayerInstance) _allPlayable containing PlayerInstance of all player in game in this WorldRegion<br> * If WorldObject is a PlayerInstance, Add the PlayerInstance in the WorldObjectHashSet(PlayerInstance) _allPlayable containing PlayerInstance of all player in game in this WorldRegion
* Assert : object.getCurrentWorldRegion() == this
* @param object * @param object
*/ */
public void addVisibleObject(WorldObject object) public void addVisibleObject(WorldObject object)
@ -325,6 +326,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -334,9 +342,7 @@ public class WorldRegion
} }
/** /**
* Remove the WorldObject from the WorldObjectHashSet(WorldObject) _visibleObjects in this WorldRegion<br> * Remove the WorldObject from the WorldObjectHashSet(WorldObject) _visibleObjects in this WorldRegion. If WorldObject is a PlayerInstance, remove it from the WorldObjectHashSet(PlayerInstance) _allPlayable of this WorldRegion
* If WorldObject is a PlayerInstance, remove it from the WorldObjectHashSet(PlayerInstance) _allPlayable of this WorldRegion<br>
* Assert : object.getCurrentWorldRegion() == this || object.getCurrentWorldRegion() == null
* @param object * @param object
*/ */
public void removeVisibleObject(WorldObject object) public void removeVisibleObject(WorldObject object)
@ -357,7 +363,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -414,6 +427,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public String getName() public String getName()
{ {
return "(" + _regionX + ", " + _regionY + ")"; return "(" + _regionX + ", " + _regionY + ")";

View File

@ -153,4 +153,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
@ -33,7 +30,6 @@ import org.w3c.dom.Node;
import org.l2jmobius.Config; import org.l2jmobius.Config;
import org.l2jmobius.gameserver.enums.FenceState; import org.l2jmobius.gameserver.enums.FenceState;
import org.l2jmobius.gameserver.model.Location;
import org.l2jmobius.gameserver.model.World; import org.l2jmobius.gameserver.model.World;
import org.l2jmobius.gameserver.model.WorldRegion; import org.l2jmobius.gameserver.model.WorldRegion;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance; import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
@ -47,7 +43,6 @@ public class FenceData
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -126,21 +121,12 @@ public class FenceData
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
final Location point = new Location(fence.getX(), fence.getY(), fence.getZ());
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(point), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final Location point = new Location(fence.getX(), fence.getY(), fence.getZ());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(point));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -155,12 +141,19 @@ public class FenceData
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -169,40 +162,30 @@ public class FenceData
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) continue;
{
return false;
}
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
if (crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax))
{ {
if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) return true;
{
return true;
}
} }
}
return false; return false;
};
return _regions.getOrDefault(World.getInstance().getRegion(new Location(x, y, z)), Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -460,6 +460,11 @@ public abstract class WorldObject
return false; return false;
} }
public boolean isFence()
{
return false;
}
public boolean isBoat() public boolean isBoat()
{ {
return false; return false;

View File

@ -31,6 +31,7 @@ import org.l2jmobius.gameserver.data.sql.SpawnTable;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Creature;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.model.actor.instance.NpcInstance; import org.l2jmobius.gameserver.model.actor.instance.NpcInstance;
import org.l2jmobius.gameserver.model.spawn.Spawn; import org.l2jmobius.gameserver.model.spawn.Spawn;
import org.l2jmobius.gameserver.model.zone.ZoneManager; import org.l2jmobius.gameserver.model.zone.ZoneManager;
@ -45,6 +46,7 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
private final List<FenceInstance> _fences = new ArrayList<>(1);
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
private final int _regionY; private final int _regionY;
@ -241,7 +243,7 @@ public class WorldRegion
_active = value; _active = value;
// turn the AI on or off to match the region's activation. // Turn the AI on or off to match the region's activation.
switchAI(value); switchAI(value);
} }
@ -305,8 +307,7 @@ public class WorldRegion
/** /**
* Add the WorldObject in the WorldObjectHashSet(WorldObject) _visibleObjects containing WorldObject visible in this WorldRegion<br> * Add the WorldObject in the WorldObjectHashSet(WorldObject) _visibleObjects containing WorldObject visible in this WorldRegion<br>
* If WorldObject is a PlayerInstance, Add the PlayerInstance in the WorldObjectHashSet(PlayerInstance) _allPlayable containing PlayerInstance of all player in game in this WorldRegion<br> * If WorldObject is a PlayerInstance, Add the PlayerInstance in the WorldObjectHashSet(PlayerInstance) _allPlayable containing PlayerInstance of all player in game in this WorldRegion
* Assert : object.getCurrentWorldRegion() == this
* @param object * @param object
*/ */
public void addVisibleObject(WorldObject object) public void addVisibleObject(WorldObject object)
@ -325,6 +326,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -334,9 +342,7 @@ public class WorldRegion
} }
/** /**
* Remove the WorldObject from the WorldObjectHashSet(WorldObject) _visibleObjects in this WorldRegion<br> * Remove the WorldObject from the WorldObjectHashSet(WorldObject) _visibleObjects in this WorldRegion. If WorldObject is a PlayerInstance, remove it from the WorldObjectHashSet(PlayerInstance) _allPlayable of this WorldRegion
* If WorldObject is a PlayerInstance, remove it from the WorldObjectHashSet(PlayerInstance) _allPlayable of this WorldRegion<br>
* Assert : object.getCurrentWorldRegion() == this || object.getCurrentWorldRegion() == null
* @param object * @param object
*/ */
public void removeVisibleObject(WorldObject object) public void removeVisibleObject(WorldObject object)
@ -357,7 +363,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -414,6 +427,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public String getName() public String getName()
{ {
return "(" + _regionX + ", " + _regionY + ")"; return "(" + _regionX + ", " + _regionY + ")";

View File

@ -153,4 +153,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -44,7 +41,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -103,18 +99,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -129,18 +118,25 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, int instanceId) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, int instanceId)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -149,41 +145,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) continue;
{
return false;
}
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
if (crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax))
{ {
if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) return true;
{
return true;
}
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return region == null ? false : _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -415,6 +415,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
/** /**
* @return {@code true} if object Can be targeted * @return {@code true} if object Can be targeted
*/ */

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -44,7 +41,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -103,18 +99,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -129,18 +118,25 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, int instanceId) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, int instanceId)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -149,41 +145,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) continue;
{
return false;
}
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
if (crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax))
{ {
if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) return true;
{
return true;
}
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return region == null ? false : _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -415,6 +415,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
/** /**
* @return {@code true} if object Can be targeted * @return {@code true} if object Can be targeted
*/ */

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }

View File

@ -17,12 +17,9 @@
package org.l2jmobius.gameserver.data.xml; package org.l2jmobius.gameserver.data.xml;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -45,7 +42,6 @@ public class FenceData implements IXmlReader
private static final int MAX_Z_DIFF = 100; private static final int MAX_Z_DIFF = 100;
private final Map<WorldRegion, List<FenceInstance>> _regions = new ConcurrentHashMap<>();
private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>(); private final Map<Integer, FenceInstance> _fences = new ConcurrentHashMap<>();
protected FenceData() protected FenceData()
@ -104,18 +100,11 @@ public class FenceData implements IXmlReader
private void addFence(FenceInstance fence) private void addFence(FenceInstance fence)
{ {
_fences.put(fence.getObjectId(), fence); _fences.put(fence.getObjectId(), fence);
_regions.computeIfAbsent(World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
} }
public void removeFence(FenceInstance fence) public void removeFence(FenceInstance fence)
{ {
_fences.remove(fence.getObjectId()); _fences.remove(fence.getObjectId());
final List<FenceInstance> fencesInRegion = _regions.get(World.getInstance().getRegion(fence));
if (fencesInRegion != null)
{
fencesInRegion.remove(fence);
}
} }
public Map<Integer, FenceInstance> getFences() public Map<Integer, FenceInstance> getFences()
@ -130,19 +119,26 @@ public class FenceData implements IXmlReader
public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance) public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
{ {
final Predicate<FenceInstance> filter = fence -> final WorldRegion region = World.getInstance().getRegion(x, y);
final List<FenceInstance> fences = region != null ? region.getFences() : null;
if ((fences == null) || fences.isEmpty())
{
return false;
}
for (FenceInstance fence : fences)
{ {
// Check if fence is geodata enabled. // Check if fence is geodata enabled.
if (!fence.getState().isGeodataEnabled()) if (!fence.getState().isGeodataEnabled())
{ {
return false; continue;
} }
// Check if fence is within the instance we search for. // Check if fence is within the instance we search for.
final int instanceId = (instance == null) ? 0 : instance.getId(); final int instanceId = (instance == null) ? 0 : instance.getId();
if (fence.getInstanceId() != instanceId) if (fence.getInstanceId() != instanceId)
{ {
return false; continue;
} }
final int xMin = fence.getXMin(); final int xMin = fence.getXMin();
@ -151,34 +147,30 @@ public class FenceData implements IXmlReader
final int yMax = fence.getYMax(); final int yMax = fence.getYMax();
if ((x < xMin) && (tx < xMin)) if ((x < xMin) && (tx < xMin))
{ {
return false; continue;
} }
if ((x > xMax) && (tx > xMax)) if ((x > xMax) && (tx > xMax))
{ {
return false; continue;
} }
if ((y < yMin) && (ty < yMin)) if ((y < yMin) && (ty < yMin))
{ {
return false; continue;
} }
if ((y > yMax) && (ty > yMax)) if ((y > yMax) && (ty > yMax))
{ {
return false; continue;
} }
if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax)) if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax) && (y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
{ {
return false; continue;
} }
if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF))) if ((crossLinePart(xMin, yMin, xMax, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMin, xMax, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMax, yMax, xMin, yMax, x, y, tx, ty, xMin, yMin, xMax, yMax) || crossLinePart(xMin, yMax, xMin, yMin, x, y, tx, ty, xMin, yMin, xMax, yMax)) && (z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
{ {
return true; return true;
} }
}
return false; return false;
};
final WorldRegion region = World.getInstance().getRegion(x, y); // Should never be null.
return (region != null) && _regions.getOrDefault(region, Collections.emptyList()).stream().anyMatch(filter);
} }
private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax) private boolean crossLinePart(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, double xMin, double yMin, double xMax, double yMax)

View File

@ -412,6 +412,15 @@ public abstract class WorldObject extends ListenersContainer implements IIdentif
return false; return false;
} }
/**
* Verifies if this object is a fence.
* @return {@code true} if object is Fence, {@code false} otherwise
*/
public boolean isFence()
{
return false;
}
public void setTargetable(boolean targetable) public void setTargetable(boolean targetable)
{ {
if (_isTargetable != targetable) if (_isTargetable != targetable)

View File

@ -25,6 +25,7 @@ import org.l2jmobius.commons.concurrent.ThreadPool;
import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Attackable;
import org.l2jmobius.gameserver.model.actor.Npc; import org.l2jmobius.gameserver.model.actor.Npc;
import org.l2jmobius.gameserver.model.actor.instance.DoorInstance; import org.l2jmobius.gameserver.model.actor.instance.DoorInstance;
import org.l2jmobius.gameserver.model.actor.instance.FenceInstance;
import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager; import org.l2jmobius.gameserver.taskmanager.RandomAnimationTaskManager;
import org.l2jmobius.gameserver.util.UnboundArrayList; import org.l2jmobius.gameserver.util.UnboundArrayList;
@ -34,6 +35,8 @@ public class WorldRegion
private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>(); private final UnboundArrayList<WorldObject> _visibleObjects = new UnboundArrayList<>();
/** List containing doors in this world region. */ /** List containing doors in this world region. */
private final List<DoorInstance> _doors = new ArrayList<>(1); private final List<DoorInstance> _doors = new ArrayList<>(1);
/** List containing fences in this world region. */
private final List<FenceInstance> _fences = new ArrayList<>(1);
/** Array containing nearby regions forming this world region's effective area. */ /** Array containing nearby regions forming this world region's effective area. */
private WorldRegion[] _surroundingRegions; private WorldRegion[] _surroundingRegions;
private final int _regionX; private final int _regionX;
@ -241,6 +244,13 @@ public class WorldRegion
_surroundingRegions[i].addDoor((DoorInstance) object); _surroundingRegions[i].addDoor((DoorInstance) object);
} }
} }
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].addFence((FenceInstance) object);
}
}
// If this is the first player to enter the region, activate self and neighbors. // If this is the first player to enter the region, activate self and neighbors.
if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON) if (object.isPlayable() && !_active && !Config.GRIDS_ALWAYS_ON)
@ -271,7 +281,14 @@ public class WorldRegion
{ {
for (int i = 0; i < _surroundingRegions.length; i++) for (int i = 0; i < _surroundingRegions.length; i++)
{ {
removeDoor((DoorInstance) object); _surroundingRegions[i].removeDoor((DoorInstance) object);
}
}
else if (object.isFence())
{
for (int i = 0; i < _surroundingRegions.length; i++)
{
_surroundingRegions[i].removeFence((FenceInstance) object);
} }
} }
@ -304,6 +321,24 @@ public class WorldRegion
return _doors; return _doors;
} }
public synchronized void addFence(FenceInstance fence)
{
if (!_fences.contains(fence))
{
_fences.add(fence);
}
}
private synchronized void removeFence(FenceInstance fence)
{
_fences.remove(fence);
}
public List<FenceInstance> getFences()
{
return _fences;
}
public void setSurroundingRegions(WorldRegion[] regions) public void setSurroundingRegions(WorldRegion[] regions)
{ {
_surroundingRegions = regions; _surroundingRegions = regions;

View File

@ -160,4 +160,10 @@ public class FenceInstance extends WorldObject
{ {
return _yMax; return _yMax;
} }
@Override
public boolean isFence()
{
return true;
}
} }