diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml b/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml
index 8ab41e304d..e8332bdf3a 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml
@@ -624,4 +624,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/FenceData.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/html/admin/fences.htm b/L2J_Mobius_1.0_Ertheia/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java
index bd1994f812..ffe1a87bd6 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -411,6 +412,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..db63ae149d
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.html.PageBuilder;
+import com.l2jmobius.gameserver.model.html.PageResult;
+import com.l2jmobius.gameserver.model.html.styles.ButtonsStyle;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = PageBuilder.newBuilder(FenceData.getInstance().getFences().values(), 10, "bypass -h admin_listfence").currentPage(page).style(ButtonsStyle.INSTANCE).bodyHandler((pages, fence, sb) ->
+ {
+ sb.append("
");
+ }).build();
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java
index 330ae1c73d..e14844c993 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java
@@ -64,6 +64,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -218,6 +219,7 @@ public class GameServer
MapRegionManager.getInstance();
ZoneManager.getInstance();
DoorData.getInstance();
+ FenceData.getInstance();
AnnouncementsTable.getInstance();
GlobalVariablesManager.getInstance();
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..1dd89e44b9
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.instancezone.Instance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceById(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ final int instanceId = (instance == null) ? 0 : instance.getId();
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 5343f17e51..674cf38bea 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -599,7 +600,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -669,7 +673,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -1138,6 +1145,10 @@ public class GeoEngine
{
return new GeoLocation(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instance))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1198,7 +1209,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instance))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance))
{
return new GeoLocation(gox, goy, goz);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml b/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml
index 8ab41e304d..e8332bdf3a 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml
@@ -624,4 +624,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/FenceData.xml b/L2J_Mobius_2.5_Underground/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/html/admin/fences.htm b/L2J_Mobius_2.5_Underground/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java
index 413ea22833..c3464f6cd2 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -412,6 +413,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..db63ae149d
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.html.PageBuilder;
+import com.l2jmobius.gameserver.model.html.PageResult;
+import com.l2jmobius.gameserver.model.html.styles.ButtonsStyle;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = PageBuilder.newBuilder(FenceData.getInstance().getFences().values(), 10, "bypass -h admin_listfence").currentPage(page).style(ButtonsStyle.INSTANCE).bodyHandler((pages, fence, sb) ->
+ {
+ sb.append("
");
+ }).build();
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java
index 298b937c28..b5b61f2ff8 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java
@@ -67,6 +67,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -222,6 +223,7 @@ public class GameServer
MapRegionManager.getInstance();
ZoneManager.getInstance();
DoorData.getInstance();
+ FenceData.getInstance();
AnnouncementsTable.getInstance();
GlobalVariablesManager.getInstance();
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..1dd89e44b9
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.instancezone.Instance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceById(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ final int instanceId = (instance == null) ? 0 : instance.getId();
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 5343f17e51..674cf38bea 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -599,7 +600,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -669,7 +673,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -1138,6 +1145,10 @@ public class GeoEngine
{
return new GeoLocation(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instance))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1198,7 +1209,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instance))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance))
{
return new GeoLocation(gox, goy, goz);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml b/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml
index 8ab41e304d..e8332bdf3a 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml
@@ -624,4 +624,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/FenceData.xml b/L2J_Mobius_3.0_Helios/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/html/admin/fences.htm b/L2J_Mobius_3.0_Helios/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java
index fa9c716767..27cfcd7a02 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -413,6 +414,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..db63ae149d
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.html.PageBuilder;
+import com.l2jmobius.gameserver.model.html.PageResult;
+import com.l2jmobius.gameserver.model.html.styles.ButtonsStyle;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = PageBuilder.newBuilder(FenceData.getInstance().getFences().values(), 10, "bypass -h admin_listfence").currentPage(page).style(ButtonsStyle.INSTANCE).bodyHandler((pages, fence, sb) ->
+ {
+ sb.append("
");
+ }).build();
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java
index 298b937c28..b5b61f2ff8 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java
@@ -67,6 +67,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -222,6 +223,7 @@ public class GameServer
MapRegionManager.getInstance();
ZoneManager.getInstance();
DoorData.getInstance();
+ FenceData.getInstance();
AnnouncementsTable.getInstance();
GlobalVariablesManager.getInstance();
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..1dd89e44b9
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.instancezone.Instance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceById(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ final int instanceId = (instance == null) ? 0 : instance.getId();
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 5343f17e51..674cf38bea 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -599,7 +600,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -669,7 +673,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -1138,6 +1145,10 @@ public class GeoEngine
{
return new GeoLocation(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instance))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1198,7 +1209,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instance))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance))
{
return new GeoLocation(gox, goy, goz);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml
index 8ab41e304d..e8332bdf3a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml
@@ -624,4 +624,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FenceData.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/html/admin/fences.htm b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java
index fa9c716767..27cfcd7a02 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -413,6 +414,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..db63ae149d
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.html.PageBuilder;
+import com.l2jmobius.gameserver.model.html.PageResult;
+import com.l2jmobius.gameserver.model.html.styles.ButtonsStyle;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = PageBuilder.newBuilder(FenceData.getInstance().getFences().values(), 10, "bypass -h admin_listfence").currentPage(page).style(ButtonsStyle.INSTANCE).bodyHandler((pages, fence, sb) ->
+ {
+ sb.append("
");
+ }).build();
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java
index bd228cb89d..ecefdbcc03 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java
@@ -66,6 +66,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -222,6 +223,7 @@ public class GameServer
MapRegionManager.getInstance();
ZoneManager.getInstance();
DoorData.getInstance();
+ FenceData.getInstance();
AnnouncementsTable.getInstance();
GlobalVariablesManager.getInstance();
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..1dd89e44b9
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.instancezone.Instance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceById(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ final int instanceId = (instance == null) ? 0 : instance.getId();
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 5343f17e51..674cf38bea 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -599,7 +600,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -669,7 +673,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -1138,6 +1145,10 @@ public class GeoEngine
{
return new GeoLocation(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instance))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1198,7 +1209,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instance))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance))
{
return new GeoLocation(gox, goy, goz);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/dist/db_installer/sql/game/admin_command_access_rights.sql b/L2J_Mobius_C6_Interlude/dist/db_installer/sql/game/admin_command_access_rights.sql
index 4e1a433bcb..8653ec19a8 100644
--- a/L2J_Mobius_C6_Interlude/dist/db_installer/sql/game/admin_command_access_rights.sql
+++ b/L2J_Mobius_C6_Interlude/dist/db_installer/sql/game/admin_command_access_rights.sql
@@ -628,6 +628,13 @@ INSERT IGNORE INTO `admin_command_access_rights` VALUES
('admin_zone_check','2'),
('admin_zone_reload','2'),
+-- Section: Fences
+('admin_addfence','1'),
+('admin_setfencestate','1'),
+('admin_removefence','1'),
+('admin_listfence','1'),
+('admin_gofence','1'),
+
-- Section: AIO
('admin_setaio','2'),
('admin_removeaio','2');
diff --git a/L2J_Mobius_C6_Interlude/dist/game/data/FenceData.xml b/L2J_Mobius_C6_Interlude/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/dist/game/data/html/admin/fences.htm b/L2J_Mobius_C6_Interlude/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..a22068219e
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_C6_Interlude/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java
index 4334d21cbc..b61b44c72c 100644
--- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/GameServer.java
@@ -74,6 +74,7 @@ import com.l2jmobius.gameserver.datatables.sql.SpawnTable;
import com.l2jmobius.gameserver.datatables.sql.TeleportLocationTable;
import com.l2jmobius.gameserver.datatables.xml.AugmentationData;
import com.l2jmobius.gameserver.datatables.xml.ExperienceData;
+import com.l2jmobius.gameserver.datatables.xml.FenceData;
import com.l2jmobius.gameserver.datatables.xml.ItemTable;
import com.l2jmobius.gameserver.datatables.xml.ZoneData;
import com.l2jmobius.gameserver.geodata.GeoData;
@@ -385,6 +386,7 @@ public class GameServer
Util.printSection("Doors");
DoorTable.getInstance().parseData();
+ FenceData.getInstance();
Util.printSection("Four Sepulchers");
FourSepulchersManager.getInstance();
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/xml/FenceData.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/xml/FenceData.java
new file mode 100644
index 0000000000..1061a44551
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/datatables/xml/FenceData.java
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.datatables.xml;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.Point3D;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ public void load()
+ {
+ final File xml = new File(Config.DATAPACK_ROOT, "data/FenceData.xml");
+ if (!xml.exists())
+ {
+ LOGGER.warning(getClass().getSimpleName() + ": FenceData.xml not found!");
+ return;
+ }
+
+ Document doc = null;
+ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+ factory.setIgnoringComments(true);
+ try
+ {
+ doc = factory.newDocumentBuilder().parse(xml);
+ }
+ catch (Exception e)
+ {
+ LOGGER.warning("Could not parse FenceData.xml: " + e.getMessage());
+ return;
+ }
+
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ final Node table = doc.getFirstChild();
+ for (Node fence = table.getFirstChild(); fence != null; fence = fence.getNextSibling())
+ {
+ if (fence.getNodeName().equals("fence"))
+ {
+ spawnFence(fence);
+ }
+ }
+
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final NamedNodeMap attrs = fenceNode.getAttributes();
+ final String name = attrs.getNamedItem("name").getNodeValue();
+ final int x = Integer.parseInt(attrs.getNamedItem("x").getNodeValue());
+ final int y = Integer.parseInt(attrs.getNamedItem("y").getNodeValue());
+ final int z = Integer.parseInt(attrs.getNamedItem("z").getNodeValue());
+ final int width = Integer.parseInt(attrs.getNamedItem("width").getNodeValue());
+ final int length = Integer.parseInt(attrs.getNamedItem("length").getNodeValue());
+ final int height = Integer.parseInt(attrs.getNamedItem("height").getNodeValue());
+ final FenceState state = FenceState.valueOf(attrs.getNamedItem("state").getNodeValue());
+
+ spawnFence(x, y, z, name, width, length, height, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, final String name, int width, int length, int height, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ final Point3D point = new Point3D(fence.getX(), fence.getY(), fence.getZ());
+
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(point), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final Point3D point = new Point3D(fence.getX(), fence.getY(), fence.getZ());
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(point));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ final Point3D point = new Point3D(x, y, z);
+ return _regions.getOrDefault(L2World.getInstance().getRegion(point), 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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..0eacad57c2
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/geodata/GeoData.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/geodata/GeoData.java
index 4cf0634034..adfb32b7d9 100644
--- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/geodata/GeoData.java
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/geodata/GeoData.java
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.datatables.csv.DoorTable;
+import com.l2jmobius.gameserver.datatables.xml.FenceData;
import com.l2jmobius.gameserver.geodata.geodriver.Cell;
import com.l2jmobius.gameserver.geodata.geodriver.GeoDriver;
import com.l2jmobius.gameserver.model.L2Object;
@@ -413,6 +414,10 @@ public class GeoData
{
return new Location(x, y, getHeight(x, y, z));
}
+ if (FenceData.getInstance().checkIfFenceBetween(x, y, z, tx, ty, tz))
+ {
+ return new Location(x, y, getHeight(x, y, z));
+ }
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
// first point is guaranteed to be available
@@ -474,6 +479,10 @@ public class GeoData
{
return false;
}
+ if (FenceData.getInstance().checkIfFenceBetween(fromX, fromY, fromZ, toX, toY, toZ))
+ {
+ return false;
+ }
final LinePointIterator pointIter = new LinePointIterator(geoX, geoY, tGeoX, tGeoY);
// first point is guaranteed to be available
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/AdminCommandHandler.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/AdminCommandHandler.java
index ab8fc3bc97..0504b301e6 100644
--- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/AdminCommandHandler.java
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/AdminCommandHandler.java
@@ -44,6 +44,7 @@ import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminEffects;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminEnchant;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminEventEngine;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminExpSp;
+import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminFence;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminFightCalculator;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminFortSiege;
import com.l2jmobius.gameserver.handler.admincommandhandlers.AdminGeodata;
@@ -135,6 +136,7 @@ public class AdminCommandHandler
registerAdminCommandHandler(new AdminScript());
registerAdminCommandHandler(new AdminExpSp());
registerAdminCommandHandler(new AdminEventEngine());
+ registerAdminCommandHandler(new AdminFence());
registerAdminCommandHandler(new AdminGmChat());
registerAdminCommandHandler(new AdminGmSpeed());
registerAdminCommandHandler(new AdminHide());
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/admincommandhandlers/AdminFence.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..e20f1df545
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/handler/admincommandhandlers/AdminFence.java
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.handler.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.datatables.xml.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.PageResult;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+import com.l2jmobius.gameserver.util.HtmlUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), null, width, length, height, FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getObjectId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj.getX(), obj.getY(), obj.getZ());
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = HtmlUtil.createPage(FenceData.getInstance().getFences().values(), page, 10, currentPage ->
+ {
+ return "
";
+ }, fence ->
+ {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("
");
+ sb.append(fence.getName());
+ sb.append("
");
+ sb.append("
");
+ sb.append("
");
+ sb.append("
");
+ sb.append("
");
+ sb.append("
");
+ return sb.toString();
+ });
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0);
+ html.setFile("data/html/admin/fences.htm");
+ html.replace("%pages%", result.getPagerTemplate().toString());
+ html.replace("%announcements%", result.getBodyTemplate().toString());
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/PageResult.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/PageResult.java
new file mode 100644
index 0000000000..63a208451a
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/PageResult.java
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model;
+
+/**
+ * @author UnAfraid
+ */
+public class PageResult
+{
+ private final int _pages;
+ private final StringBuilder _pagerTemplate;
+ private final StringBuilder _bodyTemplate;
+
+ public PageResult(int pages, StringBuilder pagerTemplate, StringBuilder bodyTemplate)
+ {
+ _pages = pages;
+ _pagerTemplate = pagerTemplate;
+ _bodyTemplate = bodyTemplate;
+ }
+
+ public int getPages()
+ {
+ return _pages;
+ }
+
+ public StringBuilder getPagerTemplate()
+ {
+ return _pagerTemplate;
+ }
+
+ public StringBuilder getBodyTemplate()
+ {
+ return _bodyTemplate;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..0424a6e466
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.datatables.xml.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ super.setName(name);
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ public boolean deleteMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ getKnownList().getKnownObjects().values().stream().filter(L2PcInstance.class::isInstance).map(L2PcInstance.class::cast).forEach(player ->
+ {
+ for (DeleteObject deleteObject : deleteObjects)
+ {
+ player.sendPacket(deleteObject);
+ }
+ });
+ }
+
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ getKnownList().getKnownObjects().values().stream().filter(L2PcInstance.class::isInstance).map(L2PcInstance.class::cast).forEach(this::sendInfo);
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/knownlist/PcKnownList.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/knownlist/PcKnownList.java
index 5d8deea912..4a15f7f6d0 100644
--- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/knownlist/PcKnownList.java
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/model/actor/knownlist/PcKnownList.java
@@ -23,6 +23,7 @@ import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2BoatInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -135,6 +136,10 @@ public class PcKnownList extends PlayableKnownList
active_char.sendPacket(new DoorInfo((L2DoorInstance) object, false));
active_char.sendPacket(new DoorStatusUpdate((L2DoorInstance) object));
}
+ else if (object instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) object).sendInfo(active_char);
+ }
else if (object instanceof L2BoatInstance)
{
if (!active_char.isInBoat())
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/DeleteObject.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/DeleteObject.java
index 54f2e604ae..bd25202f25 100644
--- a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/DeleteObject.java
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/DeleteObject.java
@@ -31,6 +31,11 @@ public class DeleteObject extends L2GameServerPacket
_objectId = obj.getObjectId();
}
+ public DeleteObject(int objId)
+ {
+ _objectId = objId;
+ }
+
@Override
protected final void writeImpl()
{
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..2326187b10
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo extends L2GameServerPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ protected void writeImpl()
+ {
+ writeC(0xFE);
+ writeH(0x09);
+ writeD(_objId);
+ writeD(_clientState);
+ writeD(_x);
+ writeD(_y);
+ writeD(_z);
+ writeD(_width);
+ writeD(_length);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/util/HtmlUtil.java b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/util/HtmlUtil.java
new file mode 100644
index 0000000000..f8101bc2b6
--- /dev/null
+++ b/L2J_Mobius_C6_Interlude/java/com/l2jmobius/gameserver/util/HtmlUtil.java
@@ -0,0 +1,90 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.function.Function;
+
+import com.l2jmobius.gameserver.model.PageResult;
+
+/**
+ * A class containing useful methods for constructing HTML
+ * @author NosBit
+ */
+public class HtmlUtil
+{
+ public static PageResult createPage(Collection elements, int page, int elementsPerPage, Function pagerFunction, Function bodyFunction)
+ {
+ return createPage(elements, elements.size(), page, elementsPerPage, pagerFunction, bodyFunction);
+ }
+
+ public static PageResult createPage(T[] elements, int page, int elementsPerPage, Function pagerFunction, Function bodyFunction)
+ {
+ return createPage(Arrays.asList(elements), elements.length, page, elementsPerPage, pagerFunction, bodyFunction);
+ }
+
+ public static PageResult createPage(Iterable elements, int size, int page, int elementsPerPage, Function pagerFunction, Function bodyFunction)
+ {
+ int pages = size / elementsPerPage;
+ if ((elementsPerPage * pages) < size)
+ {
+ pages++;
+ }
+
+ final StringBuilder pagerTemplate = new StringBuilder();
+ if (pages > 1)
+ {
+ int breakit = 0;
+ for (int i = 0; i < pages; i++)
+ {
+ pagerTemplate.append(pagerFunction.apply(i));
+ breakit++;
+
+ if (breakit > 5)
+ {
+ pagerTemplate.append("
");
+ breakit = 0;
+ }
+ }
+ }
+
+ if (page >= pages)
+ {
+ page = pages - 1;
+ }
+
+ final int start = page > 0 ? elementsPerPage * page : 0;
+ final StringBuilder sb = new StringBuilder();
+ int i = 0;
+ for (T element : elements)
+ {
+ if (i++ < start)
+ {
+ continue;
+ }
+
+ sb.append(bodyFunction.apply(element));
+
+ if (i >= (elementsPerPage + start))
+ {
+ break;
+ }
+ }
+ return new PageResult(pages, pagerTemplate, sb);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml
index ef98c72f77..c6be86ef6d 100644
--- a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml
@@ -621,4 +621,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FenceData.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/html/admin/fences.htm b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java
index aff2bd0ef8..28ddbdd6ca 100644
--- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java
@@ -75,6 +75,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGamePoints;
@@ -374,6 +375,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGamePoints.class,
diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..1ffa365d14
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,230 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.PageResult;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+import com.l2jmobius.gameserver.util.HtmlUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = HtmlUtil.createPage(FenceData.getInstance().getFences().values(), page, 10, currentPage ->
+ {
+ return "
";
+ }, fence ->
+ {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("
");
+ return sb.toString();
+ });
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+ html.replace("%pages%", result.getPagerTemplate().toString());
+ html.replace("%announcements%", result.getBodyTemplate().toString());
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java
index a1823ad74c..7a85ea0f07 100644
--- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java
@@ -54,6 +54,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnchantItemOptionsData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantSkillGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishData;
import com.l2jmobius.gameserver.data.xml.impl.FishingMonstersData;
import com.l2jmobius.gameserver.data.xml.impl.FishingRodsData;
@@ -292,6 +293,7 @@ public class GameServer
printSection("NPCs");
DoorData.getInstance();
+ FenceData.getInstance();
SkillLearnData.getInstance();
NpcData.getInstance();
FakePlayerData.getInstance();
diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..19cf61e60a
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceId(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, int instanceId)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 064f13410f..07f89c1609 100644
--- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -597,6 +598,10 @@ public class GeoEngine
{
return false;
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceId()))
+ {
+ return false;
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -662,6 +667,10 @@ public class GeoEngine
{
return false;
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceId()))
+ {
+ return false;
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1126,6 +1135,10 @@ public class GeoEngine
{
return new Location(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instanceId))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1186,6 +1199,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instanceId))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
// get X delta, signum and direction flag
final int dx = Math.abs(gtx - gox);
diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml
index 81e5a3094c..acf6d3c41c 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml
@@ -621,4 +621,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FenceData.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/admin/fences.htm b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java
index 0244d1f75d..76b2b567e4 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -413,6 +414,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..db63ae149d
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.html.PageBuilder;
+import com.l2jmobius.gameserver.model.html.PageResult;
+import com.l2jmobius.gameserver.model.html.styles.ButtonsStyle;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = PageBuilder.newBuilder(FenceData.getInstance().getFences().values(), 10, "bypass -h admin_listfence").currentPage(page).style(ButtonsStyle.INSTANCE).bodyHandler((pages, fence, sb) ->
+ {
+ sb.append("
");
+ }).build();
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java
index 289496a640..3f97f29899 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java
@@ -65,6 +65,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -219,6 +220,7 @@ public class GameServer
MapRegionManager.getInstance();
ZoneManager.getInstance();
DoorData.getInstance();
+ FenceData.getInstance();
AnnouncementsTable.getInstance();
GlobalVariablesManager.getInstance();
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..1dd89e44b9
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.instancezone.Instance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceById(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ final int instanceId = (instance == null) ? 0 : instance.getId();
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 5343f17e51..674cf38bea 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -599,7 +600,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -669,7 +673,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -1138,6 +1145,10 @@ public class GeoEngine
{
return new GeoLocation(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instance))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1198,7 +1209,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instance))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance))
{
return new GeoLocation(gox, goy, goz);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/AdminCommands.xml b/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/AdminCommands.xml
index 81e5a3094c..acf6d3c41c 100644
--- a/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/config/AdminCommands.xml
@@ -621,4 +621,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/FenceData.xml b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/FenceData.xml
new file mode 100644
index 0000000000..44e578b4b7
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/FenceData.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/admin/fences.htm b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/admin/fences.htm
new file mode 100644
index 0000000000..d2c27d96e8
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/html/admin/fences.htm
@@ -0,0 +1,25 @@
+
+
+ Fence List
+
+
+
+
+
+
+
+
Fence List
+
+
+
+
+
+
+
+ %fences%
+
+ %pages%
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/MasterHandler.java
index 0244d1f75d..76b2b567e4 100644
--- a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
+import handlers.admincommandhandlers.AdminFence;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -413,6 +414,7 @@ public class MasterHandler
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
+ AdminFence.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
new file mode 100644
index 0000000000..db63ae149d
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/scripts/handlers/admincommandhandlers/AdminFence.java
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package handlers.admincommandhandlers;
+
+import java.util.NoSuchElementException;
+import java.util.StringTokenizer;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.html.PageBuilder;
+import com.l2jmobius.gameserver.model.html.PageResult;
+import com.l2jmobius.gameserver.model.html.styles.ButtonsStyle;
+import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jmobius.gameserver.util.BuilderUtil;
+
+/**
+ * @author Sahar, Nik64
+ */
+public class AdminFence implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_addfence",
+ "admin_setfencestate",
+ "admin_removefence",
+ "admin_listfence",
+ "admin_gofence"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ final StringTokenizer st = new StringTokenizer(command, " ");
+ final String cmd = st.nextToken();
+ switch (cmd)
+ {
+ case "admin_addfence":
+ {
+ try
+ {
+ final int width = Integer.parseInt(st.nextToken());
+ final int length = Integer.parseInt(st.nextToken());
+ final int height = Integer.parseInt(st.nextToken());
+ if ((width < 1) || (length < 1))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Width and length values must be positive numbers.");
+ return false;
+ }
+ if ((height < 1) || (height > 3))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "The range for height can only be 1-3.");
+ return false;
+ }
+
+ FenceData.getInstance().spawnFence(activeChar.getX(), activeChar.getY(), activeChar.getZ(), width, length, height, activeChar.getInstanceId(), FenceState.CLOSED);
+ BuilderUtil.sendSysMessage(activeChar, "Fence added succesfully.");
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format must be: //addfence ");
+ }
+ break;
+ }
+ case "admin_setfencestate":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final int fenceTypeOrdinal = Integer.parseInt(st.nextToken());
+
+ if ((fenceTypeOrdinal < 0) || (fenceTypeOrdinal >= FenceState.values().length))
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Specified FenceType is out of range. Only 0-" + (FenceState.values().length - 1) + " are permitted.");
+ }
+ else
+ {
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ final L2FenceInstance fence = (L2FenceInstance) obj;
+ final FenceState state = FenceState.values()[fenceTypeOrdinal];
+ fence.setState(state);
+ BuilderUtil.sendSysMessage(activeChar, "Fence " + fence.getName() + "[" + fence.getId() + "]'s state has been changed to " + state.toString());
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ }
+ catch (NoSuchElementException | NumberFormatException e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Format mustr be: //setfencestate ");
+ }
+ break;
+ }
+ case "admin_removefence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj instanceof L2FenceInstance)
+ {
+ ((L2FenceInstance) obj).deleteMe();
+ BuilderUtil.sendSysMessage(activeChar, "Fence removed succesfully.");
+ }
+ else
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Target is not a fence.");
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ sendHtml(activeChar, 0);
+ break;
+ }
+ case "admin_listfence":
+ {
+ int page = 0;
+ if (st.hasMoreTokens())
+ {
+ page = Integer.parseInt(st.nextToken());
+ }
+ sendHtml(activeChar, page);
+ break;
+ }
+ case "admin_gofence":
+ {
+ try
+ {
+ final int objId = Integer.parseInt(st.nextToken());
+ final L2Object obj = L2World.getInstance().findObject(objId);
+ if (obj != null)
+ {
+ activeChar.teleToLocation(obj);
+ }
+ }
+ catch (Exception e)
+ {
+ BuilderUtil.sendSysMessage(activeChar, "Invalid object ID or target was not found.");
+ }
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+
+ private static void sendHtml(L2PcInstance activeChar, int page)
+ {
+ final PageResult result = PageBuilder.newBuilder(FenceData.getInstance().getFences().values(), 10, "bypass -h admin_listfence").currentPage(page).style(ButtonsStyle.INSTANCE).bodyHandler((pages, fence, sb) ->
+ {
+ sb.append("
");
+ }).build();
+
+ final NpcHtmlMessage html = new NpcHtmlMessage(0, 1);
+ html.setFile(activeChar, "data/html/admin/fences.htm");
+
+ if (result.getPages() > 0)
+ {
+ html.replace("%pages%", "
" + result.getPagerTemplate() + "
");
+ }
+ else
+ {
+ html.replace("%pages%", "");
+ }
+
+ html.replace("%fences%", result.getBodyTemplate().toString());
+ activeChar.sendPacket(html);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/xsd/FenceData.xsd b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/xsd/FenceData.xsd
new file mode 100644
index 0000000000..b2ba0a657a
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/dist/game/data/xsd/FenceData.xsd
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java
index 289496a640..3f97f29899 100644
--- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/GameServer.java
@@ -65,6 +65,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -219,6 +220,7 @@ public class GameServer
MapRegionManager.getInstance();
ZoneManager.getInstance();
DoorData.getInstance();
+ FenceData.getInstance();
AnnouncementsTable.getInstance();
GlobalVariablesManager.getInstance();
diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
new file mode 100644
index 0000000000..1dd89e44b9
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/data/xml/impl/FenceData.java
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Predicate;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.L2WorldRegion;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.model.instancezone.Instance;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class FenceData implements IGameXmlReader
+{
+ private static final Logger LOGGER = Logger.getLogger(FenceData.class.getSimpleName());
+
+ private static final int MAX_Z_DIFF = 100;
+
+ private final Map> _regions = new ConcurrentHashMap<>();
+ private final Map _fences = new ConcurrentHashMap<>();
+
+ protected FenceData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (!_fences.isEmpty())
+ {
+ // Remove old fences when reloading
+ _fences.values().forEach(this::removeFence);
+ }
+
+ parseDatapackFile("data/FenceData.xml");
+ LOGGER.info("Loaded " + _fences.size() + " Fences.");
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fence", this::spawnFence));
+ }
+
+ public int getLoadedElementsCount()
+ {
+ return _fences.size();
+ }
+
+ private void spawnFence(Node fenceNode)
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fenceNode));
+ spawnFence(set.getInt("x"), set.getInt("y"), set.getInt("z"), set.getString("name"), set.getInt("width"), set.getInt("length"), set.getInt("height"), 0, set.getEnum("state", FenceState.class, FenceState.CLOSED));
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, int width, int length, int height, int instanceId, FenceState state)
+ {
+ return spawnFence(x, y, z, null, width, length, height, instanceId, state);
+ }
+
+ public L2FenceInstance spawnFence(int x, int y, int z, String name, int width, int length, int height, int instanceId, FenceState state)
+ {
+ final L2FenceInstance fence = new L2FenceInstance(x, y, name, width, length, height, state);
+ if (instanceId > 0)
+ {
+ fence.setInstanceById(instanceId);
+ }
+ fence.spawnMe(x, y, z);
+ addFence(fence);
+
+ return fence;
+ }
+
+ private void addFence(L2FenceInstance fence)
+ {
+ _fences.put(fence.getObjectId(), fence);
+ _regions.computeIfAbsent(L2World.getInstance().getRegion(fence), key -> new ArrayList<>()).add(fence);
+ }
+
+ public void removeFence(L2FenceInstance fence)
+ {
+ _fences.remove(fence.getObjectId());
+
+ final List fencesInRegion = _regions.get(L2World.getInstance().getRegion(fence));
+ if (fencesInRegion != null)
+ {
+ fencesInRegion.remove(fence);
+ }
+ }
+
+ public Map getFences()
+ {
+ return _fences;
+ }
+
+ public L2FenceInstance getFence(int objectId)
+ {
+ return _fences.get(objectId);
+ }
+
+ public boolean checkIfFenceBetween(int x, int y, int z, int tx, int ty, int tz, Instance instance)
+ {
+ final Predicate filter = fence ->
+ {
+ // Check if fence is geodata enabled.
+ if (!fence.getState().isGeodataEnabled())
+ {
+ return false;
+ }
+
+ // Check if fence is within the instance we search for.
+ final int instanceId = (instance == null) ? 0 : instance.getId();
+ if (fence.getInstanceId() != instanceId)
+ {
+ return false;
+ }
+
+ final int xMin = fence.getXMin();
+ final int xMax = fence.getXMax();
+ final int yMin = fence.getYMin();
+ final int yMax = fence.getYMax();
+ if ((x < xMin) && (tx < xMin))
+ {
+ return false;
+ }
+ if ((x > xMax) && (tx > xMax))
+ {
+ return false;
+ }
+ if ((y < yMin) && (ty < yMin))
+ {
+ return false;
+ }
+ if ((y > yMax) && (ty > yMax))
+ {
+ return false;
+ }
+ if ((x > xMin) && (tx > xMin) && (x < xMax) && (tx < xMax))
+ {
+ if ((y > yMin) && (ty > yMin) && (y < yMax) && (ty < yMax))
+ {
+ 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))
+ {
+ if ((z > (fence.getZ() - MAX_Z_DIFF)) && (z < (fence.getZ() + MAX_Z_DIFF)))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ return _regions.getOrDefault(L2World.getInstance().getRegion(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)
+ {
+ final double[] result = intersection(x1, y1, x2, y2, x3, y3, x4, y4);
+ if (result == null)
+ {
+ return false;
+ }
+
+ final double xCross = result[0];
+ final double yCross = result[1];
+ if ((xCross <= xMax) && (xCross >= xMin))
+ {
+ return true;
+ }
+ if ((yCross <= yMax) && (yCross >= yMin))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private double[] intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
+ {
+ final double d = ((x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4));
+ if (d == 0)
+ {
+ return null;
+ }
+
+ final double xi = (((x3 - x4) * ((x1 * y2) - (y1 * x2))) - ((x1 - x2) * ((x3 * y4) - (y3 * x4)))) / d;
+ final double yi = (((y3 - y4) * ((x1 * y2) - (y1 * x2))) - ((y1 - y2) * ((x3 * y4) - (y3 * x4)))) / d;
+
+ return new double[]
+ {
+ xi,
+ yi
+ };
+ }
+
+ public static FenceData getInstance()
+ {
+ return SingletonHolder.INSTANCE;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FenceData INSTANCE = new FenceData();
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/FenceState.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/FenceState.java
new file mode 100644
index 0000000000..062bc6807f
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/enums/FenceState.java
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.enums;
+
+/**
+ * @author Nik64
+ */
+public enum FenceState
+{
+ HIDDEN(0),
+ OPENED(1),
+ CLOSED(2),
+ CLOSED_HIDDEN(0);
+
+ final int _clientId;
+
+ private FenceState(int clientId)
+ {
+ _clientId = clientId;
+ }
+
+ public int getClientId()
+ {
+ return _clientId;
+ }
+
+ public boolean isGeodataEnabled()
+ {
+ return (this == CLOSED_HIDDEN) || (this == CLOSED);
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
index 5343f17e51..674cf38bea 100644
--- a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
+++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/geoengine/GeoEngine.java
@@ -26,6 +26,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
import com.l2jmobius.gameserver.geoengine.geodata.ABlock;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplex;
import com.l2jmobius.gameserver.geoengine.geodata.BlockComplexDynamic;
@@ -599,7 +600,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -669,7 +673,10 @@ public class GeoEngine
{
return false;
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, origin.getInstanceWorld()))
+ {
+ return false;
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(ox, oy, oz), new Location(tx, ty, tz), origin.getInstanceWorld()))
{
return false;
@@ -1138,6 +1145,10 @@ public class GeoEngine
{
return new GeoLocation(ox, oy, oz);
}
+ if (FenceData.getInstance().checkIfFenceBetween(ox, oy, oz, tx, ty, tz, instance))
+ {
+ return new Location(ox, oy, oz);
+ }
// get origin and check existing geo coordinates
final int gox = getGeoX(ox);
@@ -1198,7 +1209,10 @@ public class GeoEngine
{
return new GeoLocation(gox, goy, goz);
}
-
+ if (FenceData.getInstance().checkIfFenceBetween(gox, goy, goz, gtx, gty, gtz, instance))
+ {
+ return new GeoLocation(gox, goy, goz);
+ }
if (WarpedSpaceManager.getInstance().checkForWarpedSpace(new Location(gox, goy, goz), new Location(gtx, gty, gtz), instance))
{
return new GeoLocation(gox, goy, goz);
diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
new file mode 100644
index 0000000000..70ae27a4be
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/model/actor/instance/L2FenceInstance.java
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.model.actor.instance;
+
+import com.l2jmobius.gameserver.data.xml.impl.FenceData;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.idfactory.IdFactory;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.network.serverpackets.DeleteObject;
+import com.l2jmobius.gameserver.network.serverpackets.ExColosseumFenceInfo;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public final class L2FenceInstance extends L2Object
+{
+ private final int _xMin;
+ private final int _xMax;
+ private final int _yMin;
+ private final int _yMax;
+
+ private final String _name;
+ private final int _width;
+ private final int _length;
+
+ private FenceState _state;
+ private int[] _heightFences;
+
+ public L2FenceInstance(int x, int y, String name, int width, int length, int height, FenceState state)
+ {
+ super(IdFactory.getInstance().getNextId());
+
+ _xMin = x - (width / 2);
+ _xMax = x + (width / 2);
+ _yMin = y - (length / 2);
+ _yMax = y + (length / 2);
+
+ _name = name;
+ _width = width;
+ _length = length;
+
+ _state = state;
+
+ if (height > 1)
+ {
+ _heightFences = new int[height - 1];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ _heightFences[i] = IdFactory.getInstance().getNextId();
+ }
+ }
+ }
+
+ @Override
+ public int getId()
+ {
+ return getObjectId();
+ }
+
+ @Override
+ public String getName()
+ {
+ return _name;
+ }
+
+ @Override
+ public boolean isAutoAttackable(L2Character attacker)
+ {
+ return false;
+ }
+
+ @Override
+ public void sendInfo(L2PcInstance activeChar)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(this));
+
+ if (_heightFences != null)
+ {
+ for (int objId : _heightFences)
+ {
+ activeChar.sendPacket(new ExColosseumFenceInfo(objId, getX(), getY(), getZ(), _width, _length, _state));
+ }
+ }
+ }
+
+ @Override
+ public boolean decayMe()
+ {
+ if (_heightFences != null)
+ {
+ final DeleteObject[] deleteObjects = new DeleteObject[_heightFences.length];
+ for (int i = 0; i < _heightFences.length; i++)
+ {
+ deleteObjects[i] = new DeleteObject(_heightFences[i]);
+ }
+
+ L2World.getInstance().forEachVisibleObject(this, L2PcInstance.class, player -> player.sendPacket(deleteObjects));
+ }
+
+ return super.decayMe();
+ }
+
+ public boolean deleteMe()
+ {
+ decayMe();
+
+ FenceData.getInstance().removeFence(this);
+ return false;
+ }
+
+ public FenceState getState()
+ {
+ return _state;
+ }
+
+ public void setState(FenceState type)
+ {
+ _state = type;
+
+ broadcastInfo();
+ }
+
+ public int getWidth()
+ {
+ return _width;
+ }
+
+ public int getLength()
+ {
+ return _length;
+ }
+
+ public int getXMin()
+ {
+ return _xMin;
+ }
+
+ public int getYMin()
+ {
+ return _yMin;
+ }
+
+ public int getXMax()
+ {
+ return _xMax;
+ }
+
+ public int getYMax()
+ {
+ return _yMax;
+ }
+}
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
new file mode 100644
index 0000000000..8df6017c8f
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Zaken/java/com/l2jmobius/gameserver/network/serverpackets/ExColosseumFenceInfo.java
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.enums.FenceState;
+import com.l2jmobius.gameserver.model.actor.instance.L2FenceInstance;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author HoridoJoho / FBIagent
+ */
+public class ExColosseumFenceInfo implements IClientOutgoingPacket
+{
+ private final int _objId;
+ private final int _x;
+ private final int _y;
+ private final int _z;
+ private final int _width;
+ private final int _length;
+ private final int _clientState;
+
+ public ExColosseumFenceInfo(L2FenceInstance fence)
+ {
+ this(fence.getObjectId(), fence.getX(), fence.getY(), fence.getZ(), fence.getWidth(), fence.getLength(), fence.getState());
+ }
+
+ public ExColosseumFenceInfo(int objId, double x, double y, double z, int width, int length, FenceState state)
+ {
+ _objId = objId;
+ _x = (int) x;
+ _y = (int) y;
+ _z = (int) z;
+ _width = width;
+ _length = length;
+ _clientState = state.getClientId();
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.EX_COLOSSEUM_FENCE_INFO.writeId(packet);
+
+ packet.writeD(_objId);
+ packet.writeD(_clientState);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(_width);
+ packet.writeD(_length);
+
+ return true;
+ }
+}
\ No newline at end of file