Classic branch.

This commit is contained in:
MobiusDev
2017-05-01 10:49:52 +00:00
parent 304ca84360
commit 23c1374047
19872 changed files with 3745265 additions and 0 deletions

View File

@ -0,0 +1,325 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.AirShipTeleportList;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.VehiclePathPoint;
import com.l2jmobius.gameserver.model.actor.instance.L2AirShipInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2ControllableAirShipInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2CharTemplate;
import com.l2jmobius.gameserver.network.serverpackets.ExAirShipTeleportList;
public class AirShipManager
{
private static final Logger LOGGER = Logger.getLogger(AirShipManager.class.getName());
private static final String LOAD_DB = "SELECT * FROM airships";
private static final String ADD_DB = "INSERT INTO airships (owner_id,fuel) VALUES (?,?)";
private static final String UPDATE_DB = "UPDATE airships SET fuel=? WHERE owner_id=?";
private L2CharTemplate _airShipTemplate = null;
private final Map<Integer, StatsSet> _airShipsInfo = new HashMap<>();
private final Map<Integer, L2AirShipInstance> _airShips = new HashMap<>();
private final Map<Integer, AirShipTeleportList> _teleports = new HashMap<>();
protected AirShipManager()
{
final StatsSet npcDat = new StatsSet();
npcDat.set("npcId", 9);
npcDat.set("level", 0);
npcDat.set("jClass", "boat");
npcDat.set("baseSTR", 0);
npcDat.set("baseCON", 0);
npcDat.set("baseDEX", 0);
npcDat.set("baseINT", 0);
npcDat.set("baseWIT", 0);
npcDat.set("baseMEN", 0);
npcDat.set("baseShldDef", 0);
npcDat.set("baseShldRate", 0);
npcDat.set("baseAccCombat", 38);
npcDat.set("baseEvasRate", 38);
npcDat.set("baseCritRate", 38);
npcDat.set("collision_radius", 0);
npcDat.set("collision_height", 0);
npcDat.set("sex", "male");
npcDat.set("type", "");
npcDat.set("baseAtkRange", 0);
npcDat.set("baseMpMax", 0);
npcDat.set("baseCpMax", 0);
npcDat.set("rewardExp", 0);
npcDat.set("rewardSp", 0);
npcDat.set("basePAtk", 0);
npcDat.set("baseMAtk", 0);
npcDat.set("basePAtkSpd", 0);
npcDat.set("aggroRange", 0);
npcDat.set("baseMAtkSpd", 0);
npcDat.set("rhand", 0);
npcDat.set("lhand", 0);
npcDat.set("armor", 0);
npcDat.set("baseWalkSpd", 0);
npcDat.set("baseRunSpd", 0);
npcDat.set("name", "AirShip");
npcDat.set("baseHpMax", 50000);
npcDat.set("baseHpReg", 3.e-3f);
npcDat.set("baseMpReg", 3.e-3f);
npcDat.set("basePDef", 100);
npcDat.set("baseMDef", 100);
_airShipTemplate = new L2CharTemplate(npcDat);
load();
}
public L2AirShipInstance getNewAirShip(int x, int y, int z, int heading)
{
final L2AirShipInstance airShip = new L2AirShipInstance(_airShipTemplate);
airShip.setHeading(heading);
airShip.setXYZInvisible(x, y, z);
airShip.spawnMe();
airShip.getStat().setMoveSpeed(280);
airShip.getStat().setRotationSpeed(2000);
return airShip;
}
public L2AirShipInstance getNewAirShip(int x, int y, int z, int heading, int ownerId)
{
final StatsSet info = _airShipsInfo.get(ownerId);
if (info == null)
{
return null;
}
final L2AirShipInstance airShip;
if (_airShips.containsKey(ownerId))
{
airShip = _airShips.get(ownerId);
airShip.refreshID();
}
else
{
airShip = new L2ControllableAirShipInstance(_airShipTemplate, ownerId);
_airShips.put(ownerId, airShip);
airShip.setMaxFuel(600);
airShip.setFuel(info.getInt("fuel"));
airShip.getStat().setMoveSpeed(280);
airShip.getStat().setRotationSpeed(2000);
}
airShip.setHeading(heading);
airShip.setXYZInvisible(x, y, z);
airShip.spawnMe();
return airShip;
}
public void removeAirShip(L2AirShipInstance ship)
{
if (ship.getOwnerId() != 0)
{
storeInDb(ship.getOwnerId());
final StatsSet info = _airShipsInfo.get(ship.getOwnerId());
if (info != null)
{
info.set("fuel", ship.getFuel());
}
}
}
public boolean hasAirShipLicense(int ownerId)
{
return _airShipsInfo.containsKey(ownerId);
}
public void registerLicense(int ownerId)
{
if (!_airShipsInfo.containsKey(ownerId))
{
final StatsSet info = new StatsSet();
info.set("fuel", 600);
_airShipsInfo.put(ownerId, info);
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(ADD_DB))
{
ps.setInt(1, ownerId);
ps.setInt(2, info.getInt("fuel"));
ps.executeUpdate();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not add new airship license: ", e);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while initializing: ", e);
}
}
}
public boolean hasAirShip(int ownerId)
{
final L2AirShipInstance ship = _airShips.get(ownerId);
if ((ship == null) || !(ship.isSpawned() || ship.isTeleporting()))
{
return false;
}
return true;
}
public void registerAirShipTeleportList(int dockId, int locationId, VehiclePathPoint[][] tp, int[] fuelConsumption)
{
if (tp.length != fuelConsumption.length)
{
return;
}
_teleports.put(dockId, new AirShipTeleportList(locationId, fuelConsumption, tp));
}
public void sendAirShipTeleportList(L2PcInstance player)
{
if ((player == null) || !player.isInAirShip())
{
return;
}
final L2AirShipInstance ship = player.getAirShip();
if (!ship.isCaptain(player) || !ship.isInDock() || ship.isMoving())
{
return;
}
final int dockId = ship.getDockId();
if (!_teleports.containsKey(dockId))
{
return;
}
final AirShipTeleportList all = _teleports.get(dockId);
player.sendPacket(new ExAirShipTeleportList(all.getLocation(), all.getRoute(), all.getFuel()));
}
public VehiclePathPoint[] getTeleportDestination(int dockId, int index)
{
final AirShipTeleportList all = _teleports.get(dockId);
if (all == null)
{
return null;
}
if ((index < -1) || (index >= all.getRoute().length))
{
return null;
}
return all.getRoute()[index + 1];
}
public int getFuelConsumption(int dockId, int index)
{
final AirShipTeleportList all = _teleports.get(dockId);
if (all == null)
{
return 0;
}
if ((index < -1) || (index >= all.getFuel().length))
{
return 0;
}
return all.getFuel()[index + 1];
}
private void load()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery(LOAD_DB))
{
StatsSet info;
while (rs.next())
{
info = new StatsSet();
info.set("fuel", rs.getInt("fuel"));
_airShipsInfo.put(rs.getInt("owner_id"), info);
}
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not load airships table: ", e);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while initializing: ", e);
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _airShipsInfo.size() + " private airships");
}
private void storeInDb(int ownerId)
{
final StatsSet info = _airShipsInfo.get(ownerId);
if (info == null)
{
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(UPDATE_DB))
{
ps.setInt(1, info.getInt("fuel"));
ps.setInt(2, ownerId);
ps.executeUpdate();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not update airships table: ", e);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while save: ", e);
}
}
public static AirShipManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final AirShipManager _instance = new AirShipManager();
}
}

View File

@ -0,0 +1,278 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
public final class AntiFeedManager
{
public static final int GAME_ID = 0;
public static final int OLYMPIAD_ID = 1;
public static final int TVT_ID = 2;
public static final int L2EVENT_ID = 3;
private final Map<Integer, Long> _lastDeathTimes = new ConcurrentHashMap<>();
private final Map<Integer, Map<Integer, AtomicInteger>> _eventIPs = new ConcurrentHashMap<>();
protected AntiFeedManager()
{
}
/**
* Set time of the last player's death to current
* @param objectId Player's objectId
*/
public final void setLastDeathTime(int objectId)
{
_lastDeathTimes.put(objectId, System.currentTimeMillis());
}
/**
* Check if current kill should be counted as non-feeded.
* @param attacker Attacker character
* @param target Target character
* @return True if kill is non-feeded.
*/
public final boolean check(L2Character attacker, L2Character target)
{
if (!Config.ANTIFEED_ENABLE)
{
return true;
}
if (target == null)
{
return false;
}
final L2PcInstance targetPlayer = target.getActingPlayer();
if (targetPlayer == null)
{
return false;
}
if ((Config.ANTIFEED_INTERVAL > 0) && _lastDeathTimes.containsKey(targetPlayer.getObjectId()))
{
if ((System.currentTimeMillis() - _lastDeathTimes.get(targetPlayer.getObjectId())) < Config.ANTIFEED_INTERVAL)
{
return false;
}
}
if (Config.ANTIFEED_DUALBOX && (attacker != null))
{
final L2PcInstance attackerPlayer = attacker.getActingPlayer();
if (attackerPlayer == null)
{
return false;
}
final L2GameClient targetClient = targetPlayer.getClient();
final L2GameClient attackerClient = attackerPlayer.getClient();
if ((targetClient == null) || (attackerClient == null) || targetClient.isDetached() || attackerClient.isDetached())
{
// unable to check ip address
return !Config.ANTIFEED_DISCONNECTED_AS_DUALBOX;
}
return !targetClient.getConnectionAddress().equals(attackerClient.getConnectionAddress());
}
return true;
}
/**
* Clears all timestamps
*/
public final void clear()
{
_lastDeathTimes.clear();
}
/**
* Register new event for dualbox check. Should be called only once.
* @param eventId
*/
public final void registerEvent(int eventId)
{
_eventIPs.putIfAbsent(eventId, new ConcurrentHashMap<>());
}
/**
* @param eventId
* @param player
* @param max
* @return If number of all simultaneous connections from player's IP address lower than max then increment connection count and return true.<br>
* False if number of all simultaneous connections from player's IP address higher than max.
*/
public final boolean tryAddPlayer(int eventId, L2PcInstance player, int max)
{
return tryAddClient(eventId, player.getClient(), max);
}
/**
* @param eventId
* @param client
* @param max
* @return If number of all simultaneous connections from player's IP address lower than max then increment connection count and return true.<br>
* False if number of all simultaneous connections from player's IP address higher than max.
*/
public final boolean tryAddClient(int eventId, L2GameClient client, int max)
{
if (client == null)
{
return false; // unable to determine IP address
}
final Map<Integer, AtomicInteger> event = _eventIPs.get(eventId);
if (event == null)
{
return false; // no such event registered
}
final Integer addrHash = Integer.valueOf(client.getConnectionAddress().hashCode());
final AtomicInteger connectionCount = event.computeIfAbsent(addrHash, k -> new AtomicInteger());
if ((connectionCount.get() + 1) <= (max + Config.DUALBOX_CHECK_WHITELIST.getOrDefault(addrHash, 0)))
{
connectionCount.incrementAndGet();
return true;
}
return false;
}
/**
* Decreasing number of active connection from player's IP address
* @param eventId
* @param player
* @return true if success and false if any problem detected.
*/
public final boolean removePlayer(int eventId, L2PcInstance player)
{
return removeClient(eventId, player.getClient());
}
/**
* Decreasing number of active connection from player's IP address
* @param eventId
* @param client
* @return true if success and false if any problem detected.
*/
public final boolean removeClient(int eventId, L2GameClient client)
{
if (client == null)
{
return false; // unable to determine IP address
}
final Map<Integer, AtomicInteger> event = _eventIPs.get(eventId);
if (event == null)
{
return false; // no such event registered
}
final Integer addrHash = Integer.valueOf(client.getConnectionAddress().hashCode());
return event.computeIfPresent(addrHash, (k, v) ->
{
if ((v == null) || (v.decrementAndGet() == 0))
{
return null;
}
return v;
}) != null;
}
/**
* Remove player connection IP address from all registered events lists.
* @param client
*/
public final void onDisconnect(L2GameClient client)
{
if ((client == null) || client.isDetached())
{
return;
}
_eventIPs.forEach((k, v) ->
{
removeClient(k, client);
});
}
/**
* Clear all entries for this eventId.
* @param eventId
*/
public final void clear(int eventId)
{
final Map<Integer, AtomicInteger> event = _eventIPs.get(eventId);
if (event != null)
{
event.clear();
}
}
/**
* @param player
* @param max
* @return maximum number of allowed connections (whitelist + max)
*/
public final int getLimit(L2PcInstance player, int max)
{
return getLimit(player.getClient(), max);
}
/**
* @param client
* @param max
* @return maximum number of allowed connections (whitelist + max)
*/
public final int getLimit(L2GameClient client, int max)
{
if (client == null)
{
return max;
}
final Integer addrHash = Integer.valueOf(client.getConnectionAddress().hashCode());
int limit = max;
if (Config.DUALBOX_CHECK_WHITELIST.containsKey(addrHash))
{
limit += Config.DUALBOX_CHECK_WHITELIST.get(addrHash);
}
return limit;
}
public static AntiFeedManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final AntiFeedManager _instance = new AntiFeedManager();
}
}

View File

@ -0,0 +1,208 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.HashMap;
import java.util.Map;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.VehiclePathPoint;
import com.l2jmobius.gameserver.model.actor.instance.L2BoatInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2CharTemplate;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
public class BoatManager
{
private final Map<Integer, L2BoatInstance> _boats = new HashMap<>();
private final boolean[] _docksBusy = new boolean[3];
public static final int TALKING_ISLAND = 1;
public static final int GLUDIN_HARBOR = 2;
public static final int RUNE_HARBOR = 3;
public static BoatManager getInstance()
{
return SingletonHolder._instance;
}
protected BoatManager()
{
for (int i = 0; i < _docksBusy.length; i++)
{
_docksBusy[i] = false;
}
}
public L2BoatInstance getNewBoat(int boatId, int x, int y, int z, int heading)
{
if (!Config.ALLOW_BOAT)
{
return null;
}
final StatsSet npcDat = new StatsSet();
npcDat.set("npcId", boatId);
npcDat.set("level", 0);
npcDat.set("jClass", "boat");
npcDat.set("baseSTR", 0);
npcDat.set("baseCON", 0);
npcDat.set("baseDEX", 0);
npcDat.set("baseINT", 0);
npcDat.set("baseWIT", 0);
npcDat.set("baseMEN", 0);
npcDat.set("baseShldDef", 0);
npcDat.set("baseShldRate", 0);
npcDat.set("baseAccCombat", 38);
npcDat.set("baseEvasRate", 38);
npcDat.set("baseCritRate", 38);
// npcDat.set("name", "");
npcDat.set("collision_radius", 0);
npcDat.set("collision_height", 0);
npcDat.set("sex", "male");
npcDat.set("type", "");
npcDat.set("baseAtkRange", 0);
npcDat.set("baseMpMax", 0);
npcDat.set("baseCpMax", 0);
npcDat.set("rewardExp", 0);
npcDat.set("rewardSp", 0);
npcDat.set("basePAtk", 0);
npcDat.set("baseMAtk", 0);
npcDat.set("basePAtkSpd", 0);
npcDat.set("aggroRange", 0);
npcDat.set("baseMAtkSpd", 0);
npcDat.set("rhand", 0);
npcDat.set("lhand", 0);
npcDat.set("armor", 0);
npcDat.set("baseWalkSpd", 0);
npcDat.set("baseRunSpd", 0);
npcDat.set("baseHpMax", 50000);
npcDat.set("baseHpReg", 3.e-3f);
npcDat.set("baseMpReg", 3.e-3f);
npcDat.set("basePDef", 100);
npcDat.set("baseMDef", 100);
final L2CharTemplate template = new L2CharTemplate(npcDat);
final L2BoatInstance boat = new L2BoatInstance(template);
_boats.put(boat.getObjectId(), boat);
boat.setHeading(heading);
boat.setXYZInvisible(x, y, z);
boat.spawnMe();
return boat;
}
/**
* @param boatId
* @return
*/
public L2BoatInstance getBoat(int boatId)
{
return _boats.get(boatId);
}
/**
* Lock/unlock dock so only one ship can be docked
* @param h Dock Id
* @param value True if dock is locked
*/
public void dockShip(int h, boolean value)
{
try
{
_docksBusy[h] = value;
}
catch (ArrayIndexOutOfBoundsException e)
{
}
}
/**
* Check if dock is busy
* @param h Dock Id
* @return Trye if dock is locked
*/
public boolean dockBusy(int h)
{
try
{
return _docksBusy[h];
}
catch (ArrayIndexOutOfBoundsException e)
{
return false;
}
}
/**
* Broadcast one packet in both path points
* @param point1
* @param point2
* @param packet
*/
public void broadcastPacket(VehiclePathPoint point1, VehiclePathPoint point2, IClientOutgoingPacket packet)
{
broadcastPacketsToPlayers(point1, point2, packet);
}
/**
* Broadcast several packets in both path points
* @param point1
* @param point2
* @param packets
*/
public void broadcastPackets(VehiclePathPoint point1, VehiclePathPoint point2, IClientOutgoingPacket... packets)
{
broadcastPacketsToPlayers(point1, point2, packets);
}
private void broadcastPacketsToPlayers(VehiclePathPoint point1, VehiclePathPoint point2, IClientOutgoingPacket... packets)
{
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
double dx = (double) player.getX() - point1.getX();
double dy = (double) player.getY() - point1.getY();
if (Math.sqrt((dx * dx) + (dy * dy)) < Config.BOAT_BROADCAST_RADIUS)
{
for (IClientOutgoingPacket p : packets)
{
player.sendPacket(p);
}
}
else
{
dx = (double) player.getX() - point2.getX();
dy = (double) player.getY() - point2.getY();
if (Math.sqrt((dx * dx) + (dy * dy)) < Config.BOAT_BROADCAST_RADIUS)
{
for (IClientOutgoingPacket p : packets)
{
player.sendPacket(p);
}
}
}
}
}
private static class SingletonHolder
{
protected static final BoatManager _instance = new BoatManager();
}
}

View File

@ -0,0 +1,276 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.InstanceListManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Castle;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
public final class CastleManager implements InstanceListManager
{
private static final Logger LOGGER = Logger.getLogger(CastleManager.class.getName());
private final Map<Integer, Castle> _castles = new ConcurrentSkipListMap<>();
private final Map<Integer, Long> _castleSiegeDate = new ConcurrentHashMap<>();
private static final int _castleCirclets[] =
{
0,
6838,
6835,
6839,
6837,
6840,
6834,
6836,
8182,
8183
};
public final Castle findNearestCastle(L2Object obj)
{
return findNearestCastle(obj, Long.MAX_VALUE);
}
public final Castle findNearestCastle(L2Object obj, long maxDistance)
{
Castle nearestCastle = getCastle(obj);
if (nearestCastle == null)
{
double distance;
for (Castle castle : getCastles())
{
distance = castle.getDistance(obj);
if (maxDistance > distance)
{
maxDistance = (long) distance;
nearestCastle = castle;
}
}
}
return nearestCastle;
}
public final Castle getCastleById(int castleId)
{
return _castles.get(castleId);
}
public final Castle getCastleByOwner(L2Clan clan)
{
for (Castle temp : getCastles())
{
if (temp.getOwnerId() == clan.getId())
{
return temp;
}
}
return null;
}
public final Castle getCastle(String name)
{
for (Castle temp : getCastles())
{
if (temp.getName().equalsIgnoreCase(name.trim()))
{
return temp;
}
}
return null;
}
public final Castle getCastle(int x, int y, int z)
{
for (Castle temp : getCastles())
{
if (temp.checkIfInZone(x, y, z))
{
return temp;
}
}
return null;
}
public final Castle getCastle(L2Object activeObject)
{
return getCastle(activeObject.getX(), activeObject.getY(), activeObject.getZ());
}
public final Collection<Castle> getCastles()
{
return _castles.values();
}
public boolean hasOwnedCastle()
{
boolean hasOwnedCastle = false;
for (Castle castle : getCastles())
{
if (castle.getOwnerId() > 0)
{
hasOwnedCastle = true;
break;
}
}
return hasOwnedCastle;
}
public int getCircletByCastleId(int castleId)
{
if ((castleId > 0) && (castleId < 10))
{
return _castleCirclets[castleId];
}
return 0;
}
// remove this castle's circlets from the clan
public void removeCirclet(L2Clan clan, int castleId)
{
for (L2ClanMember member : clan.getMembers())
{
removeCirclet(member, castleId);
}
}
public void removeCirclet(L2ClanMember member, int castleId)
{
if (member == null)
{
return;
}
final L2PcInstance player = member.getPlayerInstance();
final int circletId = getCircletByCastleId(castleId);
if (circletId != 0)
{
// online-player circlet removal
if (player != null)
{
try
{
final L2ItemInstance circlet = player.getInventory().getItemByItemId(circletId);
if (circlet != null)
{
if (circlet.isEquipped())
{
player.getInventory().unEquipItemInSlot(circlet.getLocationSlot());
}
player.destroyItemByItemId("CastleCircletRemoval", circletId, 1, player, true);
}
return;
}
catch (NullPointerException e)
{
// continue removing offline
}
}
// else offline-player circlet removal
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM items WHERE owner_id = ? and item_id = ?"))
{
ps.setInt(1, member.getObjectId());
ps.setInt(2, circletId);
ps.execute();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Failed to remove castle circlets offline for player " + member.getName() + ": ", e);
}
}
}
@Override
public void loadInstances()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT id FROM castle ORDER BY id"))
{
while (rs.next())
{
final int castleId = rs.getInt("id");
_castles.put(castleId, new Castle(castleId));
}
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + getCastles().size() + " castles.");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Exception: loadCastleData():", e);
}
}
@Override
public void updateReferences()
{
}
@Override
public void activateInstances()
{
for (Castle castle : getCastles())
{
castle.activateInstance();
}
}
public void registerSiegeDate(int castleId, long siegeDate)
{
_castleSiegeDate.put(castleId, siegeDate);
}
public int getSiegeDates(long siegeDate)
{
int count = 0;
for (long date : _castleSiegeDate.values())
{
if (Math.abs(date - siegeDate) < 1000)
{
count++;
}
}
return count;
}
public static CastleManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final CastleManager _instance = new CastleManager();
}
}

View File

@ -0,0 +1,824 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.ManorMode;
import com.l2jmobius.gameserver.model.CropProcure;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
import com.l2jmobius.gameserver.model.L2Seed;
import com.l2jmobius.gameserver.model.SeedProduction;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.entity.Castle;
import com.l2jmobius.gameserver.model.interfaces.IStorable;
import com.l2jmobius.gameserver.model.itemcontainer.ItemContainer;
import com.l2jmobius.gameserver.network.SystemMessageId;
/**
* Castle manor system.
* @author malyelfik
*/
public final class CastleManorManager implements IGameXmlReader, IStorable
{
private static final Logger LOGGER = Logger.getLogger(CastleManorManager.class.getName());
// SQL queries
private static final String INSERT_PRODUCT = "INSERT INTO castle_manor_production VALUES (?, ?, ?, ?, ?, ?)";
private static final String INSERT_CROP = "INSERT INTO castle_manor_procure VALUES (?, ?, ?, ?, ?, ?, ?)";
// Current manor status
private ManorMode _mode = ManorMode.APPROVED;
// Temporary date
private Calendar _nextModeChange = null;
// Seeds holder
private static final Map<Integer, L2Seed> _seeds = new HashMap<>();
// Manor period settings
private final Map<Integer, List<CropProcure>> _procure = new HashMap<>();
private final Map<Integer, List<CropProcure>> _procureNext = new HashMap<>();
private final Map<Integer, List<SeedProduction>> _production = new HashMap<>();
private final Map<Integer, List<SeedProduction>> _productionNext = new HashMap<>();
public CastleManorManager()
{
if (Config.ALLOW_MANOR)
{
load(); // Load seed data (XML)
loadDb(); // Load castle manor data (DB)
// Set mode and start timer
final Calendar currentTime = Calendar.getInstance();
final int hour = currentTime.get(Calendar.HOUR_OF_DAY);
final int min = currentTime.get(Calendar.MINUTE);
final int maintenanceMin = Config.ALT_MANOR_REFRESH_MIN + Config.ALT_MANOR_MAINTENANCE_MIN;
if (((hour >= Config.ALT_MANOR_REFRESH_TIME) && (min >= maintenanceMin)) || (hour < Config.ALT_MANOR_APPROVE_TIME) || ((hour == Config.ALT_MANOR_APPROVE_TIME) && (min <= Config.ALT_MANOR_APPROVE_MIN)))
{
_mode = ManorMode.MODIFIABLE;
}
else if ((hour == Config.ALT_MANOR_REFRESH_TIME) && ((min >= Config.ALT_MANOR_REFRESH_MIN) && (min < maintenanceMin)))
{
_mode = ManorMode.MAINTENANCE;
}
// Schedule mode change
scheduleModeChange();
// Schedule autosave
if (!Config.ALT_MANOR_SAVE_ALL_ACTIONS)
{
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(this::storeMe, Config.ALT_MANOR_SAVE_PERIOD_RATE, Config.ALT_MANOR_SAVE_PERIOD_RATE, TimeUnit.HOURS);
}
// Send debug message
if (Config.DEBUG)
{
LOGGER.info(getClass().getSimpleName() + ": Current mode " + _mode);
}
}
else
{
_mode = ManorMode.DISABLED;
LOGGER.info(getClass().getSimpleName() + ": Manor system is deactivated.");
}
}
@Override
public final void load()
{
parseDatapackFile("data/Seeds.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _seeds.size() + " seeds.");
}
@Override
public final void parseDocument(Document doc, File f)
{
StatsSet set;
NamedNodeMap attrs;
Node att;
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("castle".equalsIgnoreCase(d.getNodeName()))
{
final int castleId = parseInteger(d.getAttributes(), "id");
for (Node c = d.getFirstChild(); c != null; c = c.getNextSibling())
{
if ("crop".equalsIgnoreCase(c.getNodeName()))
{
set = new StatsSet();
set.set("castleId", castleId);
attrs = c.getAttributes();
for (int i = 0; i < attrs.getLength(); i++)
{
att = attrs.item(i);
set.set(att.getNodeName(), att.getNodeValue());
}
_seeds.put(set.getInt("seedId"), new L2Seed(set));
}
}
}
}
}
}
}
private void loadDb()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement stProduction = con.prepareStatement("SELECT * FROM castle_manor_production WHERE castle_id=?");
PreparedStatement stProcure = con.prepareStatement("SELECT * FROM castle_manor_procure WHERE castle_id=?"))
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
final int castleId = castle.getResidenceId();
// Clear params
stProduction.clearParameters();
stProcure.clearParameters();
// Seed production
final List<SeedProduction> pCurrent = new ArrayList<>();
final List<SeedProduction> pNext = new ArrayList<>();
stProduction.setInt(1, castleId);
try (ResultSet rs = stProduction.executeQuery())
{
while (rs.next())
{
final int seedId = rs.getInt("seed_id");
if (_seeds.containsKey(seedId)) // Don't load unknown seeds
{
final SeedProduction sp = new SeedProduction(seedId, rs.getLong("amount"), rs.getLong("price"), rs.getInt("start_amount"));
if (rs.getBoolean("next_period"))
{
pNext.add(sp);
}
else
{
pCurrent.add(sp);
}
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Unknown seed id: " + seedId + "!");
}
}
}
_production.put(castleId, pCurrent);
_productionNext.put(castleId, pNext);
// Seed procure
final List<CropProcure> current = new ArrayList<>();
final List<CropProcure> next = new ArrayList<>();
stProcure.setInt(1, castleId);
try (ResultSet rs = stProcure.executeQuery())
{
final Set<Integer> cropIds = getCropIds();
while (rs.next())
{
final int cropId = rs.getInt("crop_id");
if (cropIds.contains(cropId)) // Don't load unknown crops
{
final CropProcure cp = new CropProcure(cropId, rs.getLong("amount"), rs.getInt("reward_type"), rs.getLong("start_amount"), rs.getLong("price"));
if (rs.getBoolean("next_period"))
{
next.add(cp);
}
else
{
current.add(cp);
}
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Unknown crop id: " + cropId + "!");
}
}
}
_procure.put(castleId, current);
_procureNext.put(castleId, next);
}
LOGGER.info(getClass().getSimpleName() + ": Manor data loaded.");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Unable to load manor data! ", e);
}
}
// -------------------------------------------------------
// Manor methods
// -------------------------------------------------------
private void scheduleModeChange()
{
// Calculate next mode change
_nextModeChange = Calendar.getInstance();
_nextModeChange.set(Calendar.SECOND, 0);
switch (_mode)
{
case MODIFIABLE:
_nextModeChange.set(Calendar.HOUR_OF_DAY, Config.ALT_MANOR_APPROVE_TIME);
_nextModeChange.set(Calendar.MINUTE, Config.ALT_MANOR_APPROVE_MIN);
if (_nextModeChange.before(Calendar.getInstance()))
{
_nextModeChange.add(Calendar.DATE, 1);
}
break;
case MAINTENANCE:
_nextModeChange.set(Calendar.HOUR_OF_DAY, Config.ALT_MANOR_REFRESH_TIME);
_nextModeChange.set(Calendar.MINUTE, Config.ALT_MANOR_REFRESH_MIN + Config.ALT_MANOR_MAINTENANCE_MIN);
break;
case APPROVED:
_nextModeChange.set(Calendar.HOUR_OF_DAY, Config.ALT_MANOR_REFRESH_TIME);
_nextModeChange.set(Calendar.MINUTE, Config.ALT_MANOR_REFRESH_MIN);
break;
}
// Schedule mode change
ThreadPoolManager.getInstance().scheduleGeneral(this::changeMode, (_nextModeChange.getTimeInMillis() - System.currentTimeMillis()));
}
public final void changeMode()
{
switch (_mode)
{
case APPROVED:
{
// Change mode
_mode = ManorMode.MAINTENANCE;
// Update manor period
for (Castle castle : CastleManager.getInstance().getCastles())
{
final L2Clan owner = castle.getOwner();
if (owner == null)
{
continue;
}
final int castleId = castle.getResidenceId();
final ItemContainer cwh = owner.getWarehouse();
for (CropProcure crop : _procure.get(castleId))
{
if (crop.getStartAmount() > 0)
{
// Adding bought crops to clan warehouse
if (crop.getStartAmount() != crop.getAmount())
{
long count = (long) ((crop.getStartAmount() - crop.getAmount()) * 0.9);
if ((count < 1) && (Rnd.nextInt(99) < 90))
{
count = 1;
}
if (count > 0)
{
cwh.addItem("Manor", getSeedByCrop(crop.getId()).getMatureId(), count, null, null);
}
}
// Reserved and not used money giving back to treasury
if (crop.getAmount() > 0)
{
castle.addToTreasuryNoTax(crop.getAmount() * crop.getPrice());
}
}
}
// Change next period to current and prepare next period data
final List<SeedProduction> _nextProduction = _productionNext.get(castleId);
final List<CropProcure> _nextProcure = _procureNext.get(castleId);
_production.put(castleId, _nextProduction);
_procure.put(castleId, _nextProcure);
if (castle.getTreasury() < getManorCost(castleId, false))
{
_productionNext.put(castleId, Collections.emptyList());
_procureNext.put(castleId, Collections.emptyList());
}
else
{
final List<SeedProduction> production = new ArrayList<>(_nextProduction);
for (SeedProduction s : production)
{
s.setAmount(s.getStartAmount());
}
_productionNext.put(castleId, production);
final List<CropProcure> procure = new ArrayList<>(_nextProcure);
for (CropProcure cr : procure)
{
cr.setAmount(cr.getStartAmount());
}
_procureNext.put(castleId, procure);
}
}
// Save changes
storeMe();
break;
}
case MAINTENANCE:
{
// Notify clan leader about manor mode change
for (Castle castle : CastleManager.getInstance().getCastles())
{
final L2Clan owner = castle.getOwner();
if (owner != null)
{
final L2ClanMember clanLeader = owner.getLeader();
if ((clanLeader != null) && clanLeader.isOnline())
{
clanLeader.getPlayerInstance().sendPacket(SystemMessageId.THE_MANOR_INFORMATION_HAS_BEEN_UPDATED);
}
}
}
_mode = ManorMode.MODIFIABLE;
break;
}
case MODIFIABLE:
{
_mode = ManorMode.APPROVED;
for (Castle castle : CastleManager.getInstance().getCastles())
{
final L2Clan owner = castle.getOwner();
if (owner == null)
{
continue;
}
int slots = 0;
final int castleId = castle.getResidenceId();
final ItemContainer cwh = owner.getWarehouse();
for (CropProcure crop : _procureNext.get(castleId))
{
if ((crop.getStartAmount() > 0) && (cwh.getItemsByItemId(getSeedByCrop(crop.getId()).getMatureId()) == null))
{
slots++;
}
}
final long manorCost = getManorCost(castleId, true);
if (!cwh.validateCapacity(slots) && (castle.getTreasury() < manorCost))
{
_productionNext.get(castleId).clear();
_procureNext.get(castleId).clear();
// Notify clan leader
final L2ClanMember clanLeader = owner.getLeader();
if ((clanLeader != null) && clanLeader.isOnline())
{
clanLeader.getPlayerInstance().sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_FUNDS_IN_THE_CLAN_WAREHOUSE_FOR_THE_MANOR_TO_OPERATE);
}
}
else
{
castle.addToTreasuryNoTax(-manorCost);
}
}
// Store changes
if (Config.ALT_MANOR_SAVE_ALL_ACTIONS)
{
storeMe();
}
break;
}
}
scheduleModeChange();
if (Config.DEBUG)
{
LOGGER.info(getClass().getSimpleName() + ": Manor mode changed to " + _mode + "!");
}
}
public final void setNextSeedProduction(List<SeedProduction> list, int castleId)
{
_productionNext.put(castleId, list);
if (Config.ALT_MANOR_SAVE_ALL_ACTIONS)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement dps = con.prepareStatement("DELETE FROM castle_manor_production WHERE castle_id = ? AND next_period = 1");
PreparedStatement ips = con.prepareStatement(INSERT_PRODUCT))
{
// Delete old data
dps.setInt(1, castleId);
dps.executeUpdate();
// Insert new data
if (!list.isEmpty())
{
for (SeedProduction sp : list)
{
ips.setInt(1, castleId);
ips.setInt(2, sp.getId());
ips.setLong(3, sp.getAmount());
ips.setLong(4, sp.getStartAmount());
ips.setLong(5, sp.getPrice());
ips.setBoolean(6, true);
ips.addBatch();
}
ips.executeBatch();
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Unable to store manor data!", e);
}
}
}
public final void setNextCropProcure(List<CropProcure> list, int castleId)
{
_procureNext.put(castleId, list);
if (Config.ALT_MANOR_SAVE_ALL_ACTIONS)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement dps = con.prepareStatement("DELETE FROM castle_manor_procure WHERE castle_id = ? AND next_period = 1");
PreparedStatement ips = con.prepareStatement(INSERT_CROP))
{
// Delete old data
dps.setInt(1, castleId);
dps.executeUpdate();
// Insert new data
if (!list.isEmpty())
{
for (CropProcure cp : list)
{
ips.setInt(1, castleId);
ips.setInt(2, cp.getId());
ips.setLong(3, cp.getAmount());
ips.setLong(4, cp.getStartAmount());
ips.setLong(5, cp.getPrice());
ips.setInt(6, cp.getReward());
ips.setBoolean(7, true);
ips.addBatch();
}
ips.executeBatch();
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Unable to store manor data!", e);
}
}
}
public final void updateCurrentProduction(int castleId, Collection<SeedProduction> items)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE castle_manor_production SET amount = ? WHERE castle_id = ? AND seed_id = ? AND next_period = 0"))
{
for (SeedProduction sp : items)
{
ps.setLong(1, sp.getAmount());
ps.setInt(2, castleId);
ps.setInt(3, sp.getId());
ps.addBatch();
}
ps.executeBatch();
}
catch (Exception e)
{
LOGGER.log(Level.INFO, getClass().getSimpleName() + ": Unable to store manor data!", e);
}
}
public final void updateCurrentProcure(int castleId, Collection<CropProcure> items)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE castle_manor_procure SET amount = ? WHERE castle_id = ? AND crop_id = ? AND next_period = 0"))
{
for (CropProcure sp : items)
{
ps.setLong(1, sp.getAmount());
ps.setInt(2, castleId);
ps.setInt(3, sp.getId());
ps.addBatch();
}
ps.executeBatch();
}
catch (Exception e)
{
LOGGER.log(Level.INFO, getClass().getSimpleName() + ": Unable to store manor data!", e);
}
}
public final List<SeedProduction> getSeedProduction(int castleId, boolean nextPeriod)
{
return (nextPeriod) ? _productionNext.get(castleId) : _production.get(castleId);
}
public final SeedProduction getSeedProduct(int castleId, int seedId, boolean nextPeriod)
{
for (SeedProduction sp : getSeedProduction(castleId, nextPeriod))
{
if (sp.getId() == seedId)
{
return sp;
}
}
return null;
}
public final List<CropProcure> getCropProcure(int castleId, boolean nextPeriod)
{
return (nextPeriod) ? _procureNext.get(castleId) : _procure.get(castleId);
}
public final CropProcure getCropProcure(int castleId, int cropId, boolean nextPeriod)
{
for (CropProcure cp : getCropProcure(castleId, nextPeriod))
{
if (cp.getId() == cropId)
{
return cp;
}
}
return null;
}
public final long getManorCost(int castleId, boolean nextPeriod)
{
final List<CropProcure> procure = getCropProcure(castleId, nextPeriod);
final List<SeedProduction> production = getSeedProduction(castleId, nextPeriod);
long total = 0;
for (SeedProduction seed : production)
{
final L2Seed s = getSeed(seed.getId());
total += (s == null) ? 1 : (s.getSeedReferencePrice() * seed.getStartAmount());
}
for (CropProcure crop : procure)
{
total += (crop.getPrice() * crop.getStartAmount());
}
return total;
}
@Override
public final boolean storeMe()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ds = con.prepareStatement("DELETE FROM castle_manor_production");
PreparedStatement is = con.prepareStatement(INSERT_PRODUCT);
PreparedStatement dp = con.prepareStatement("DELETE FROM castle_manor_procure");
PreparedStatement ip = con.prepareStatement(INSERT_CROP))
{
// Delete old seeds
ds.executeUpdate();
// Current production
for (Map.Entry<Integer, List<SeedProduction>> entry : _production.entrySet())
{
for (SeedProduction sp : entry.getValue())
{
is.setInt(1, entry.getKey());
is.setInt(2, sp.getId());
is.setLong(3, sp.getAmount());
is.setLong(4, sp.getStartAmount());
is.setLong(5, sp.getPrice());
is.setBoolean(6, false);
is.addBatch();
}
}
// Next production
for (Map.Entry<Integer, List<SeedProduction>> entry : _productionNext.entrySet())
{
for (SeedProduction sp : entry.getValue())
{
is.setInt(1, entry.getKey());
is.setInt(2, sp.getId());
is.setLong(3, sp.getAmount());
is.setLong(4, sp.getStartAmount());
is.setLong(5, sp.getPrice());
is.setBoolean(6, true);
is.addBatch();
}
}
// Execute production batch
is.executeBatch();
// Delete old procure
dp.executeUpdate();
// Current procure
for (Map.Entry<Integer, List<CropProcure>> entry : _procure.entrySet())
{
for (CropProcure cp : entry.getValue())
{
ip.setInt(1, entry.getKey());
ip.setInt(2, cp.getId());
ip.setLong(3, cp.getAmount());
ip.setLong(4, cp.getStartAmount());
ip.setLong(5, cp.getPrice());
ip.setInt(6, cp.getReward());
ip.setBoolean(7, false);
ip.addBatch();
}
}
// Next procure
for (Map.Entry<Integer, List<CropProcure>> entry : _procureNext.entrySet())
{
for (CropProcure cp : entry.getValue())
{
ip.setInt(1, entry.getKey());
ip.setInt(2, cp.getId());
ip.setLong(3, cp.getAmount());
ip.setLong(4, cp.getStartAmount());
ip.setLong(5, cp.getPrice());
ip.setInt(6, cp.getReward());
ip.setBoolean(7, true);
ip.addBatch();
}
}
// Execute procure batch
ip.executeBatch();
return true;
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Unable to store manor data! ", e);
return false;
}
}
public final void resetManorData(int castleId)
{
_procure.get(castleId).clear();
_procureNext.get(castleId).clear();
_production.get(castleId).clear();
_productionNext.get(castleId).clear();
if (Config.ALT_MANOR_SAVE_ALL_ACTIONS)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ds = con.prepareStatement("DELETE FROM castle_manor_production WHERE castle_id = ?");
PreparedStatement dc = con.prepareStatement("DELETE FROM castle_manor_procure WHERE castle_id = ?"))
{
// Delete seeds
ds.setInt(1, castleId);
ds.executeUpdate();
// Delete procure
dc.setInt(1, castleId);
dc.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Unable to store manor data!", e);
}
}
}
public final boolean isUnderMaintenance()
{
return _mode.equals(ManorMode.MAINTENANCE);
}
public final boolean isManorApproved()
{
return _mode.equals(ManorMode.APPROVED);
}
public final boolean isModifiablePeriod()
{
return _mode.equals(ManorMode.MODIFIABLE);
}
public final String getCurrentModeName()
{
return _mode.toString();
}
public final String getNextModeChange()
{
return new SimpleDateFormat("dd/MM HH:mm:ss").format(_nextModeChange.getTime());
}
// -------------------------------------------------------
// Seed methods
// -------------------------------------------------------
public final List<L2Seed> getCrops()
{
final List<L2Seed> seeds = new ArrayList<>();
final List<Integer> cropIds = new ArrayList<>();
for (L2Seed seed : _seeds.values())
{
if (!cropIds.contains(seed.getCropId()))
{
seeds.add(seed);
cropIds.add(seed.getCropId());
}
}
cropIds.clear();
return seeds;
}
public final Set<L2Seed> getSeedsForCastle(int castleId)
{
return _seeds.values().stream().filter(s -> s.getCastleId() == castleId).collect(Collectors.toSet());
}
public final Set<Integer> getSeedIds()
{
return _seeds.keySet();
}
public final Set<Integer> getCropIds()
{
return _seeds.values().stream().map(L2Seed::getCropId).collect(Collectors.toSet());
}
public final L2Seed getSeed(int seedId)
{
return _seeds.get(seedId);
}
public final L2Seed getSeedByCrop(int cropId, int castleId)
{
for (L2Seed s : getSeedsForCastle(castleId))
{
if (s.getCropId() == cropId)
{
return s;
}
}
return null;
}
public final L2Seed getSeedByCrop(int cropId)
{
for (L2Seed s : _seeds.values())
{
if (s.getCropId() == cropId)
{
return s;
}
}
return null;
}
// -------------------------------------------------------
// Static methods
// -------------------------------------------------------
public static CastleManorManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final CastleManorManager _instance = new CastleManorManager();
}
}

View File

@ -0,0 +1,445 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.enums.CategoryType;
import com.l2jmobius.gameserver.enums.CeremonyOfChaosState;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.ceremonyofchaos.CeremonyOfChaosEvent;
import com.l2jmobius.gameserver.model.ceremonyofchaos.CeremonyOfChaosMember;
import com.l2jmobius.gameserver.model.eventengine.AbstractEventManager;
import com.l2jmobius.gameserver.model.eventengine.ScheduleTarget;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.ListenerRegisterType;
import com.l2jmobius.gameserver.model.events.annotations.RegisterEvent;
import com.l2jmobius.gameserver.model.events.annotations.RegisterType;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerBypass;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogin;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.ceremonyofchaos.ExCuriousHouseState;
/**
* @author Sdw
*/
public class CeremonyOfChaosManager extends AbstractEventManager<CeremonyOfChaosEvent>
{
protected static final Logger LOGGER = Logger.getLogger(CeremonyOfChaosManager.class.getName());
public static final String INITIAL_BUFF_KEY = "initial_buff";
public static final String INITIAL_ITEMS_KEY = "initial_items";
public static final String MAX_PLAYERS_KEY = "max_players";
public static final String MAX_ARENAS_KEY = "max_arenas";
public static final String INSTANCE_TEMPLATES_KEY = "instance_templates";
public static final String END_BUFFS_KEYH = "end_buffs";
protected CeremonyOfChaosManager()
{
}
@Override
public void onInitialized()
{
if (getState() == null)
{
setState(CeremonyOfChaosState.SCHEDULED);
}
}
@ScheduleTarget
private void onPeriodEnd(String text)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM character_variables WHERE var = ?"))
{
ps.setString(1, PlayerVariables.CEREMONY_OF_CHAOS_PROHIBITED_PENALTIES);
ps.execute();
}
catch (Exception e)
{
LOGGER.severe(getClass().getSimpleName() + ": Could not reset Ceremony Of Chaos penalties: " + e);
}
// Update data for online players.
L2World.getInstance().getPlayers().stream().forEach(player ->
{
player.getVariables().remove(PlayerVariables.CEREMONY_OF_CHAOS_PROHIBITED_PENALTIES);
player.getVariables().storeMe();
});
LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos penalties have been reset.");
LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos period has ended!");
}
@ScheduleTarget
private void onEventStart()
{
LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos event has started!");
}
@ScheduleTarget
private void onEventEnd()
{
PunishmentManager.getInstance().stopPunishment(PunishmentAffect.CHARACTER, PunishmentType.COC_BAN);
LOGGER.info(getClass().getSimpleName() + ": Ceremony of Chaos event has ended!");
}
@ScheduleTarget
private void onRegistrationStart()
{
if (getState() != CeremonyOfChaosState.SCHEDULED)
{
return;
}
setState(CeremonyOfChaosState.REGISTRATION);
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
if (player.isOnline())
{
player.sendPacket(SystemMessageId.REGISTRATION_FOR_THE_CEREMONY_OF_CHAOS_HAS_BEGUN);
if (canRegister(player, false))
{
player.sendPacket(ExCuriousHouseState.REGISTRATION_PACKET);
}
}
}
}
@ScheduleTarget
private void onRegistrationEnd()
{
if (getState() != CeremonyOfChaosState.REGISTRATION)
{
return;
}
setState(CeremonyOfChaosState.PREPARING_FOR_TELEPORT);
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
if (player.isOnline())
{
player.sendPacket(SystemMessageId.REGISTRATION_FOR_THE_CEREMONY_OF_CHAOS_HAS_ENDED);
if (!isRegistered(player))
{
player.sendPacket(ExCuriousHouseState.IDLE_PACKET);
}
}
}
getTimers().addTimer("count_down", StatsSet.valueOf("time", 60), 60 * 1000, null, null);
}
@ScheduleTarget
private void onPrepareForFight()
{
if (getState() != CeremonyOfChaosState.PREPARING_FOR_TELEPORT)
{
return;
}
setState(CeremonyOfChaosState.PREPARING_FOR_FIGHT);
int eventId = 0;
int position = 1;
CeremonyOfChaosEvent event = null;
final List<L2PcInstance> players = getRegisteredPlayers().stream().sorted(Comparator.comparingInt(L2PcInstance::getLevel)).collect(Collectors.toList());
final int maxPlayers = getMaxPlayersInArena();
final List<Integer> templates = getVariables().getList(INSTANCE_TEMPLATES_KEY, Integer.class);
for (L2PcInstance player : players)
{
if (player.isOnline() && canRegister(player, true))
{
if ((event == null) || (event.getMembers().size() >= maxPlayers))
{
final int template = templates.get(Rnd.get(templates.size()));
event = new CeremonyOfChaosEvent(eventId++, InstanceManager.getInstance().getInstanceTemplate(template));
position = 1;
getEvents().add(event);
}
event.addMember(new CeremonyOfChaosMember(player, event, position++));
}
else
{
player.prohibiteCeremonyOfChaos();
player.sendPacket(ExCuriousHouseState.IDLE_PACKET);
}
}
// Clear previously registrated players
getRegisteredPlayers().clear();
// Prepare all event's players for start
getEvents().forEach(CeremonyOfChaosEvent::preparePlayers);
}
@ScheduleTarget
private void onStartFight()
{
if (getState() != CeremonyOfChaosState.PREPARING_FOR_FIGHT)
{
return;
}
setState(CeremonyOfChaosState.RUNNING);
getEvents().forEach(CeremonyOfChaosEvent::startFight);
}
@ScheduleTarget
private void onEndFight()
{
if (getState() != CeremonyOfChaosState.RUNNING)
{
return;
}
setState(CeremonyOfChaosState.SCHEDULED);
getEvents().forEach(CeremonyOfChaosEvent::stopFight);
getEvents().clear();
}
@Override
public void onTimerEvent(String event, StatsSet params, L2Npc npc, L2PcInstance player)
{
switch (event)
{
case "count_down":
{
final int time = params.getInt("time", 0);
final SystemMessage countdown = SystemMessage.getSystemMessage(SystemMessageId.YOU_WILL_BE_MOVED_TO_THE_ARENA_IN_S1_SECOND_S);
countdown.addByte(time);
broadcastPacket(countdown);
// Reschedule
if (time == 60)
{
getTimers().addTimer(event, params.set("time", 10), 50 * 1000, null, null);
}
else if (time == 10)
{
getTimers().addTimer(event, params.set("time", 5), 5 * 1000, null, null);
}
else if ((time > 1) && (time <= 5))
{
getTimers().addTimer(event, params.set("time", time - 1), 1000, null, null);
}
break;
}
}
}
public final void broadcastPacket(IClientOutgoingPacket... packets)
{
getRegisteredPlayers().forEach(member -> member.sendPacket(packets));
}
@Override
public boolean canRegister(L2PcInstance player, boolean sendMessage)
{
boolean canRegister = true;
final L2Clan clan = player.getClan();
SystemMessageId sm = null;
if (player.getLevel() < 85)
{
sm = SystemMessageId.ONLY_CHARACTERS_LEVEL_85_OR_ABOVE_MAY_PARTICIPATE_IN_THE_TOURNAMENT;
canRegister = false;
}
else if (player.isFlyingMounted())
{
sm = SystemMessageId.YOU_CANNOT_PARTICIPATE_IN_THE_CEREMONY_OF_CHAOS_AS_A_FLYING_TRANSFORMED_OBJECT;
canRegister = false;
}
else if (!player.isInCategory(CategoryType.AWAKEN_GROUP))
{
sm = SystemMessageId.ONLY_CHARACTERS_WHO_HAVE_COMPLETED_THE_3RD_CLASS_TRANSFER_MAY_PARTICIPATE;
canRegister = false;
}
else if (!player.isInventoryUnder80(false) || (player.getWeightPenalty() != 0))
{
sm = SystemMessageId.UNABLE_TO_PROCESS_THIS_REQUEST_UNTIL_YOUR_INVENTORY_S_WEIGHT_AND_SLOT_COUNT_ARE_LESS_THAN_80_PERCENT_OF_CAPACITY;
canRegister = false;
}
else if ((clan == null) || (clan.getLevel() < 6))
{
sm = SystemMessageId.ONLY_CHARACTERS_WHO_ARE_A_PART_OF_A_CLAN_OF_LEVEL_6_OR_ABOVE_MAY_PARTICIPATE;
canRegister = false;
}
else if (getRegisteredPlayers().size() >= (getVariables().getInt(MAX_ARENAS_KEY, 5) * getMaxPlayersInArena()))
{
sm = SystemMessageId.THERE_ARE_TOO_MANY_CHALLENGERS_YOU_CANNOT_PARTICIPATE_NOW;
canRegister = false;
}
else if (player.isCursedWeaponEquipped() || (player.getReputation() < 0))
{
sm = SystemMessageId.WAITING_LIST_REGISTRATION_IS_NOT_ALLOWED_WHILE_THE_CURSED_SWORD_IS_BEING_USED_OR_THE_STATUS_IS_IN_A_CHAOTIC_STATE;
canRegister = false;
}
else if (player.isInDuel())
{
sm = SystemMessageId.YOU_CANNOT_REGISTER_IN_THE_WAITING_LIST_DURING_A_DUEL;
canRegister = false;
}
else if (player.isInOlympiadMode() || OlympiadManager.getInstance().isRegistered(player))
{
sm = SystemMessageId.YOU_CANNOT_REGISTER_IN_THE_WAITING_LIST_WHILE_PARTICIPATING_IN_OLYMPIAD;
canRegister = false;
}
else if (player.isOnEvent(CeremonyOfChaosEvent.class) || (player.getBlockCheckerArena() > -1)) // TODO underground coliseum and kratei checks.
{
sm = SystemMessageId.YOU_CANNOT_REGISTER_FOR_THE_WAITING_LIST_WHILE_PARTICIPATING_IN_THE_BLOCK_CHECKER_COLISEUM_OLYMPIAD_KRATEI_S_CUBE_CEREMONY_OF_CHAOS;
canRegister = false;
}
else if (player.isInInstance())
{
sm = SystemMessageId.YOU_MAY_NOT_REGISTER_WHILE_USING_THE_INSTANT_ZONE;
canRegister = false;
}
else if (player.isInSiege())
{
sm = SystemMessageId.YOU_CANNOT_REGISTER_FOR_THE_WAITING_LIST_ON_THE_BATTLEFIELD_CASTLE_SIEGE_FORTRESS_SIEGE;
canRegister = false;
}
else if (player.isInsideZone(ZoneId.SIEGE))
{
sm = SystemMessageId.YOU_CANNOT_REGISTER_IN_THE_WAITING_LIST_WHILE_BEING_INSIDE_OF_A_BATTLEGROUND_CASTLE_SIEGE_FORTRESS_SIEGE;
canRegister = false;
}
else if (player.isFlyingMounted())
{
sm = SystemMessageId.YOU_CANNOT_PARTICIPATE_IN_THE_CEREMONY_OF_CHAOS_AS_A_FLYING_TRANSFORMED_OBJECT;
canRegister = false;
}
else if (player.isFishing())
{
sm = SystemMessageId.YOU_CANNOT_PARTICIPATE_IN_THE_CEREMONY_OF_CHAOS_WHILE_FISHING;
canRegister = false;
}
else if (player.isCeremonyOfChaosProhibited())
{
canRegister = false;
}
// TODO : One player can take part in 16 matches per day.
if ((sm != null) && sendMessage)
{
player.sendPacket(sm);
}
return canRegister;
}
@RegisterEvent(EventType.ON_PLAYER_BYPASS)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public TerminateReturn OnPlayerBypass(OnPlayerBypass event)
{
final L2PcInstance player = event.getActiveChar();
if (player == null)
{
return null;
}
if (event.getCommand().equalsIgnoreCase("pledgegame?command=apply"))
{
if (registerPlayer(player))
{
player.sendPacket(SystemMessageId.YOU_ARE_NOW_ON_THE_WAITING_LIST_YOU_WILL_AUTOMATICALLY_BE_TELEPORTED_WHEN_THE_TOURNAMENT_STARTS_AND_WILL_BE_REMOVED_FROM_THE_WAITING_LIST_IF_YOU_LOG_OUT_IF_YOU_CANCEL_REGISTRATION_WITHIN_THE_LAST_MINUTE_OF_ENTERING_THE_ARENA_AFTER_SIGNING_UP_30_TIMES_OR_MORE_OR_FORFEIT_AFTER_ENTERING_THE_ARENA_30_TIMES_OR_MORE_DURING_A_CYCLE_YOU_BECOME_INELIGIBLE_FOR_PARTICIPATION_IN_THE_CEREMONY_OF_CHAOS_UNTIL_THE_NEXT_CYCLE_ALL_THE_BUFFS_EXCEPT_THE_VITALITY_BUFF_WILL_BE_REMOVED_ONCE_YOU_ENTER_THE_ARENAS);
player.sendPacket(SystemMessageId.EXCEPT_THE_VITALITY_BUFF_ALL_BUFFS_INCLUDING_ART_OF_SEDUCTION_WILL_BE_DELETED);
player.sendPacket(ExCuriousHouseState.PREPARE_PACKET);
}
return new TerminateReturn(true, false, false);
}
return null;
}
@RegisterEvent(EventType.ON_PLAYER_LOGIN)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void OnPlayerLogin(OnPlayerLogin event)
{
if (Config.DISABLE_TUTORIAL)
{
return;
}
if (getState() == CeremonyOfChaosState.REGISTRATION)
{
final L2PcInstance player = event.getActiveChar();
if (canRegister(player, false))
{
player.sendPacket(ExCuriousHouseState.REGISTRATION_PACKET);
}
}
}
@Override
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
public void OnPlayerLogout(OnPlayerLogout event)
{
if (getState() == CeremonyOfChaosState.REGISTRATION)
{
final L2PcInstance player = event.getActiveChar();
if (getRegisteredPlayers().contains(player))
{
getRegisteredPlayers().remove(player);
}
}
}
// player leave clan
public int getMaxPlayersInArena()
{
return getVariables().getInt(MAX_PLAYERS_KEY, 18);
}
public static CeremonyOfChaosManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final CeremonyOfChaosManager _instance = new CeremonyOfChaosManager();
}
}

View File

@ -0,0 +1,416 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.clan.entry.PledgeApplicantInfo;
import com.l2jmobius.gameserver.model.clan.entry.PledgeRecruitInfo;
import com.l2jmobius.gameserver.model.clan.entry.PledgeWaitingInfo;
/**
* @author Sdw
*/
public class ClanEntryManager
{
protected static final Logger LOGGER = Logger.getLogger(ClanEntryManager.class.getName());
private static final Map<Integer, PledgeWaitingInfo> _waitingList = new ConcurrentHashMap<>();
private static final Map<Integer, PledgeRecruitInfo> _clanList = new ConcurrentHashMap<>();
private static final Map<Integer, Map<Integer, PledgeApplicantInfo>> _applicantList = new ConcurrentHashMap<>();
private static final Map<Integer, ScheduledFuture<?>> _clanLocked = new ConcurrentHashMap<>();
private static final Map<Integer, ScheduledFuture<?>> _playerLocked = new ConcurrentHashMap<>();
private static final String INSERT_APPLICANT = "INSERT INTO pledge_applicant VALUES (?, ?, ?, ?)";
private static final String DELETE_APPLICANT = "DELETE FROM pledge_applicant WHERE charId = ? AND clanId = ?";
private static final String INSERT_WAITING_LIST = "INSERT INTO pledge_waiting_list VALUES (?, ?)";
private static final String DELETE_WAITING_LIST = "DELETE FROM pledge_waiting_list WHERE char_id = ?";
private static final String INSERT_CLAN_RECRUIT = "INSERT INTO pledge_recruit VALUES (?, ?, ?, ?, ?, ?)";
private static final String UPDATE_CLAN_RECRUIT = "UPDATE pledge_recruit SET karma = ?, information = ?, detailed_information = ?, application_type = ?, recruit_type = ? WHERE clan_id = ?";
private static final String DELETE_CLAN_RECRUIT = "DELETE FROM pledge_recruit WHERE clan_id = ?";
//@formatter:off
private static final List<Comparator<PledgeWaitingInfo>> PLAYER_COMPARATOR = Arrays.asList(
null,
Comparator.comparing(PledgeWaitingInfo::getPlayerName),
Comparator.comparingInt(PledgeWaitingInfo::getKarma),
Comparator.comparingInt(PledgeWaitingInfo::getPlayerLvl),
Comparator.comparingInt(PledgeWaitingInfo::getPlayerClassId));
//@formatter:on
//@formatter:off
private static final List<Comparator<PledgeRecruitInfo>> CLAN_COMPARATOR = Arrays.asList(
null,
Comparator.comparing(PledgeRecruitInfo::getClanName),
Comparator.comparing(PledgeRecruitInfo::getClanLeaderName),
Comparator.comparingInt(PledgeRecruitInfo::getClanLevel),
Comparator.comparingInt(PledgeRecruitInfo::getKarma));
//@formatter:on
private static final long LOCK_TIME = TimeUnit.MINUTES.toMillis(5);
protected ClanEntryManager()
{
load();
}
private void load()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT * FROM pledge_recruit"))
{
while (rs.next())
{
_clanList.put(rs.getInt("clan_id"), new PledgeRecruitInfo(rs.getInt("clan_id"), rs.getInt("karma"), rs.getString("information"), rs.getString("detailed_information"), rs.getInt("application_type"), rs.getInt("recruit_type")));
}
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + _clanList.size() + " clan entry");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Failed to load: ", e);
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT a.char_id, a.karma, b.base_class, b.level, b.char_name FROM pledge_waiting_list as a LEFT JOIN characters as b ON a.char_id = b.charId"))
{
while (rs.next())
{
_waitingList.put(rs.getInt("char_id"), new PledgeWaitingInfo(rs.getInt("char_id"), rs.getInt("level"), rs.getInt("karma"), rs.getInt("base_class"), rs.getString("char_name")));
}
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + _waitingList.size() + " player in waiting list");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Failed to load: ", e);
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT a.charId, a.clanId, a.karma, a.message, b.base_class, b.level, b.char_name FROM pledge_applicant as a LEFT JOIN characters as b ON a.charId = b.charId"))
{
while (rs.next())
{
_applicantList.computeIfAbsent(rs.getInt("clanId"), k -> new ConcurrentHashMap<>()).put(rs.getInt("charId"), new PledgeApplicantInfo(rs.getInt("charId"), rs.getString("char_name"), rs.getInt("level"), rs.getInt("karma"), rs.getInt("clanId"), rs.getString("message")));
}
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + _applicantList.size() + " player application");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Failed to load: ", e);
}
}
public Map<Integer, PledgeWaitingInfo> getWaitingList()
{
return _waitingList;
}
public Map<Integer, PledgeRecruitInfo> getClanList()
{
return _clanList;
}
public Map<Integer, Map<Integer, PledgeApplicantInfo>> getApplicantList()
{
return _applicantList;
}
public Map<Integer, PledgeApplicantInfo> getApplicantListForClan(int clanId)
{
return _applicantList.getOrDefault(clanId, Collections.emptyMap());
}
public PledgeApplicantInfo getPlayerApplication(int clanId, int playerId)
{
return _applicantList.getOrDefault(clanId, Collections.emptyMap()).get(playerId);
}
public boolean removePlayerApplication(int clanId, int playerId)
{
final Map<Integer, PledgeApplicantInfo> clanApplicantList = _applicantList.get(clanId);
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(DELETE_APPLICANT))
{
statement.setInt(1, playerId);
statement.setInt(2, clanId);
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
return (clanApplicantList != null) && (clanApplicantList.remove(playerId) != null);
}
public boolean addPlayerApplicationToClan(int clanId, PledgeApplicantInfo info)
{
if (!_playerLocked.containsKey(info.getPlayerId()))
{
_applicantList.computeIfAbsent(clanId, k -> new ConcurrentHashMap<>()).put(info.getPlayerId(), info);
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(INSERT_APPLICANT))
{
statement.setInt(1, info.getPlayerId());
statement.setInt(2, info.getRequestClanId());
statement.setInt(3, info.getKarma());
statement.setString(4, info.getMessage());
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
return true;
}
return false;
}
public OptionalInt getClanIdForPlayerApplication(int playerId)
{
return _applicantList.entrySet().stream().filter(e -> e.getValue().containsKey(playerId)).mapToInt(e -> e.getKey()).findFirst();
}
public boolean addToWaitingList(int playerId, PledgeWaitingInfo info)
{
if (!_playerLocked.containsKey(playerId))
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(INSERT_WAITING_LIST))
{
statement.setInt(1, info.getPlayerId());
statement.setInt(2, info.getKarma());
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
_waitingList.put(playerId, info);
return true;
}
return false;
}
public boolean removeFromWaitingList(int playerId)
{
if (_waitingList.containsKey(playerId))
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(DELETE_WAITING_LIST))
{
statement.setInt(1, playerId);
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
_waitingList.remove(playerId);
lockPlayer(playerId);
return true;
}
return false;
}
public boolean addToClanList(int clanId, PledgeRecruitInfo info)
{
if (!_clanList.containsKey(clanId) && !_clanLocked.containsKey(clanId))
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(INSERT_CLAN_RECRUIT))
{
statement.setInt(1, info.getClanId());
statement.setInt(2, info.getKarma());
statement.setString(3, info.getInformation());
statement.setString(4, info.getDetailedInformation());
statement.setInt(5, info.getApplicationType());
statement.setInt(6, info.getRecruitType());
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
_clanList.put(clanId, info);
return true;
}
return false;
}
public boolean updateClanList(int clanId, PledgeRecruitInfo info)
{
if (_clanList.containsKey(clanId) && !_clanLocked.containsKey(clanId))
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(UPDATE_CLAN_RECRUIT))
{
statement.setInt(1, info.getKarma());
statement.setString(2, info.getInformation());
statement.setString(3, info.getDetailedInformation());
statement.setInt(4, info.getApplicationType());
statement.setInt(5, info.getRecruitType());
statement.setInt(6, info.getClanId());
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
return _clanList.replace(clanId, info) != null;
}
return false;
}
public boolean removeFromClanList(int clanId)
{
if (_clanList.containsKey(clanId))
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(DELETE_CLAN_RECRUIT))
{
statement.setInt(1, clanId);
statement.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
_clanList.remove(clanId);
lockClan(clanId);
return true;
}
return false;
}
public List<PledgeWaitingInfo> getSortedWaitingList(int levelMin, int levelMax, int role, int sortBy, boolean descending)
{
sortBy = CommonUtil.constrain(sortBy, 1, PLAYER_COMPARATOR.size() - 1);
// TODO: Handle Role
//@formatter:off
return _waitingList.values().stream()
.filter(p -> ((p.getPlayerLvl() >= levelMin) && (p.getPlayerLvl() <= levelMax)))
.sorted(descending ? PLAYER_COMPARATOR.get(sortBy).reversed() : PLAYER_COMPARATOR.get(sortBy))
.collect(Collectors.toList());
//@formatter:on
}
public List<PledgeWaitingInfo> queryWaitingListByName(String name)
{
return _waitingList.values().stream().filter(p -> p.getPlayerName().toLowerCase().contains(name)).collect(Collectors.toList());
}
public List<PledgeRecruitInfo> getSortedClanListByName(String query, int type)
{
return type == 1 ? _clanList.values().stream().filter(p -> p.getClanName().toLowerCase().contains(query)).collect(Collectors.toList()) : _clanList.values().stream().filter(p -> p.getClanLeaderName().toLowerCase().contains(query)).collect(Collectors.toList());
}
public PledgeRecruitInfo getClanById(int clanId)
{
return _clanList.get(clanId);
}
public boolean isClanRegistred(int clanId)
{
return _clanList.get(clanId) != null;
}
public boolean isPlayerRegistred(int playerId)
{
return _waitingList.get(playerId) != null;
}
public List<PledgeRecruitInfo> getUnSortedClanList()
{
return _clanList.values().stream().collect(Collectors.toList());
}
public List<PledgeRecruitInfo> getSortedClanList(int clanLevel, int karma, int sortBy, boolean descending)
{
sortBy = CommonUtil.constrain(sortBy, 1, CLAN_COMPARATOR.size() - 1);
//@formatter:off
return _clanList.values().stream()
.filter((p -> (((clanLevel < 0) && (karma >= 0) && (karma != p.getKarma())) || ((clanLevel >= 0) && (karma < 0) && (clanLevel != p.getClanLevel())) || ((clanLevel >= 0) && (karma >= 0) && ((clanLevel != p.getClanLevel()) || (karma != p.getKarma()))))))
.sorted(descending ? CLAN_COMPARATOR.get(sortBy).reversed() : CLAN_COMPARATOR.get(sortBy))
.collect(Collectors.toList());
//@formatter:on
}
public long getPlayerLockTime(int playerId)
{
return _playerLocked.get(playerId) == null ? 0 : _playerLocked.get(playerId).getDelay(TimeUnit.MINUTES);
}
public long getClanLockTime(int playerId)
{
return _clanLocked.get(playerId) == null ? 0 : _clanLocked.get(playerId).getDelay(TimeUnit.MINUTES);
}
private static void lockPlayer(int playerId)
{
_playerLocked.put(playerId, ThreadPoolManager.getInstance().scheduleGeneral(() ->
{
_playerLocked.remove(playerId);
}, LOCK_TIME));
}
private static void lockClan(int clanId)
{
_clanLocked.put(clanId, ThreadPoolManager.getInstance().scheduleGeneral(() ->
{
_clanLocked.remove(clanId);
}, LOCK_TIME));
}
public static ClanEntryManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final ClanEntryManager _instance = new ClanEntryManager();
}
}

View File

@ -0,0 +1,101 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.data.xml.impl.ClanHallData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.clanhallauction.ClanHallAuction;
import com.l2jmobius.gameserver.model.eventengine.AbstractEvent;
import com.l2jmobius.gameserver.model.eventengine.AbstractEventManager;
import com.l2jmobius.gameserver.model.eventengine.ScheduleTarget;
/**
* @author Sdw
*/
public class ClanHallAuctionManager extends AbstractEventManager<AbstractEvent<?>>
{
private static final Logger LOGGER = Logger.getLogger(ClanHallAuctionManager.class.getName());
private static final Map<Integer, ClanHallAuction> AUCTIONS = new HashMap<>();
protected ClanHallAuctionManager()
{
}
@ScheduleTarget
private void onEventStart()
{
LOGGER.info(getClass().getSimpleName() + ": Clan Hall Auction has started!");
AUCTIONS.clear();
//@formatter:off
ClanHallData.getInstance().getFreeAuctionableHall()
.forEach(c -> AUCTIONS.put(c.getResidenceId(), new ClanHallAuction(c.getResidenceId())));
//@formatter:on
}
@ScheduleTarget
private void onEventEnd()
{
AUCTIONS.values().forEach(ClanHallAuction::finalizeAuctions);
AUCTIONS.clear();
LOGGER.info(getClass().getSimpleName() + ": Clan Hall Auction has ended!");
}
@Override
public void onInitialized()
{
}
public ClanHallAuction getClanHallAuctionById(int clanHallId)
{
return AUCTIONS.get(clanHallId);
}
public ClanHallAuction getClanHallAuctionByClan(L2Clan clan)
{
//@formatter:off
return AUCTIONS.values().stream()
.filter(a -> a.getBids().containsKey(clan.getId()))
.findFirst()
.orElse(null);
//@formatter:on
}
public boolean checkForClanBid(int clanHallId, L2Clan clan)
{
//@formatter:off
return AUCTIONS.entrySet().stream()
.filter(a -> a.getKey() != clanHallId)
.anyMatch(a -> a.getValue().getBids().containsKey(clan.getId()));
//@formatter:on
}
public static ClanHallAuctionManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final ClanHallAuctionManager INSTANCE = new ClanHallAuctionManager();
}
}

View File

@ -0,0 +1,477 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ScheduledFuture;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.ItemLocation;
import com.l2jmobius.gameserver.enums.MailType;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.CommissionManagerInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.commission.CommissionItem;
import com.l2jmobius.gameserver.model.entity.Message;
import com.l2jmobius.gameserver.model.itemcontainer.Inventory;
import com.l2jmobius.gameserver.model.itemcontainer.Mail;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionBuyItem;
import com.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionDelete;
import com.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionInfo;
import com.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionList;
import com.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionList.CommissionListReplyType;
import com.l2jmobius.gameserver.network.serverpackets.commission.ExResponseCommissionRegister;
/**
* @author NosBit
*/
public final class CommissionManager
{
private static final Logger _log = Logger.getLogger(CommissionManager.class.getName());
private static final int INTERACTION_DISTANCE = 250;
private static final int ITEMS_LIMIT_PER_REQUEST = 999;
private static final int MAX_ITEMS_REGISTRED_PER_PLAYER = 10;
private static final long MIN_REGISTRATION_AND_SALE_FEE = 1000;
private static final double REGISTRATION_FEE_PER_DAY = 0.001;
private static final double SALE_FEE_PER_DAY = 0.005;
private static final String SELECT_ALL_ITEMS = "SELECT * FROM `items` WHERE `loc` = ?";
private static final String SELECT_ALL_COMMISSION_ITEMS = "SELECT * FROM `commission_items`";
private static final String INSERT_COMMISSION_ITEM = "INSERT INTO `commission_items`(`item_object_id`, `price_per_unit`, `start_time`, `duration_in_days`) VALUES (?, ?, ?, ?)";
private static final String DELETE_COMMISSION_ITEM = "DELETE FROM `commission_items` WHERE `commission_id` = ?";
private final Map<Long, CommissionItem> _commissionItems = new ConcurrentSkipListMap<>();
protected CommissionManager()
{
final Map<Integer, L2ItemInstance> itemInstances = new HashMap<>();
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
try (PreparedStatement ps = con.prepareStatement(SELECT_ALL_ITEMS))
{
ps.setString(1, ItemLocation.COMMISSION.name());
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
final L2ItemInstance itemInstance = new L2ItemInstance(rs);
itemInstances.put(itemInstance.getObjectId(), itemInstance);
}
}
}
try (Statement st = con.createStatement();
ResultSet rs = st.executeQuery(SELECT_ALL_COMMISSION_ITEMS))
{
while (rs.next())
{
final long commissionId = rs.getLong("commission_id");
final L2ItemInstance itemInstance = itemInstances.get(rs.getInt("item_object_id"));
if (itemInstance == null)
{
_log.warning(getClass().getSimpleName() + ": Failed loading commission item with commission id " + commissionId + " because item instance does not exist or failed to load.");
continue;
}
final CommissionItem commissionItem = new CommissionItem(commissionId, itemInstance, rs.getLong("price_per_unit"), rs.getTimestamp("start_time").toInstant(), rs.getByte("duration_in_days"));
_commissionItems.put(commissionItem.getCommissionId(), commissionItem);
if (commissionItem.getEndTime().isBefore(Instant.now()))
{
expireSale(commissionItem);
}
else
{
commissionItem.setSaleEndTask(ThreadPoolManager.getInstance().scheduleGeneral(() -> expireSale(commissionItem), Duration.between(Instant.now(), commissionItem.getEndTime()).toMillis()));
}
}
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Failed loading commission items.", e);
}
}
/**
* Shows the player the auctions filtered by filter.
* @param player the player
* @param filter the filter
*/
public void showAuctions(L2PcInstance player, Predicate<L2Item> filter)
{
//@formatter:off
final List<CommissionItem> commissionItems = _commissionItems.values().stream()
.filter(c -> filter.test(c.getItemInfo().getItem()))
.limit(ITEMS_LIMIT_PER_REQUEST)
.collect(Collectors.toList());
//@formatter:on
if (commissionItems.isEmpty())
{
player.sendPacket(new ExResponseCommissionList(CommissionListReplyType.ITEM_DOES_NOT_EXIST));
return;
}
int chunks = commissionItems.size() / ExResponseCommissionList.MAX_CHUNK_SIZE;
if (commissionItems.size() > (chunks * ExResponseCommissionList.MAX_CHUNK_SIZE))
{
chunks++;
}
for (int i = chunks - 1; i >= 0; i--)
{
player.sendPacket(new ExResponseCommissionList(CommissionListReplyType.AUCTIONS, commissionItems, i, i * ExResponseCommissionList.MAX_CHUNK_SIZE));
}
}
/**
* Shows the player his auctions.
* @param player the player
*/
public void showPlayerAuctions(L2PcInstance player)
{
//@formatter:off
final List<CommissionItem> commissionItems = _commissionItems.values().stream()
.filter(c -> c.getItemInstance().getOwnerId() == player.getObjectId())
.limit(MAX_ITEMS_REGISTRED_PER_PLAYER)
.collect(Collectors.toList());
//@formatter:on
if (!commissionItems.isEmpty())
{
player.sendPacket(new ExResponseCommissionList(CommissionListReplyType.PLAYER_AUCTIONS, commissionItems));
}
else
{
player.sendPacket(new ExResponseCommissionList(CommissionListReplyType.PLAYER_AUCTIONS_EMPTY));
}
}
/**
* Registers an item for the given player.
* @param player the player
* @param itemObjectId the item object id
* @param itemCount the item count
* @param pricePerUnit the price per unit
* @param durationInDays the duration in days
*/
public void registerItem(L2PcInstance player, int itemObjectId, long itemCount, long pricePerUnit, byte durationInDays)
{
if (itemCount < 1)
{
player.sendPacket(SystemMessageId.THE_ITEM_HAS_FAILED_TO_BE_REGISTERED);
player.sendPacket(ExResponseCommissionRegister.FAILED);
return;
}
final long totalPrice = itemCount * pricePerUnit;
if (totalPrice <= MIN_REGISTRATION_AND_SALE_FEE)
{
player.sendPacket(SystemMessageId.THE_ITEM_CANNOT_BE_REGISTERED_BECAUSE_REQUIREMENTS_ARE_NOT_MET);
player.sendPacket(ExResponseCommissionRegister.FAILED);
return;
}
L2ItemInstance itemInstance = player.getInventory().getItemByObjectId(itemObjectId);
if ((itemInstance == null) || !itemInstance.isAvailable(player, false, false) || (itemInstance.getCount() < itemCount))
{
player.sendPacket(SystemMessageId.THE_ITEM_HAS_FAILED_TO_BE_REGISTERED);
player.sendPacket(ExResponseCommissionRegister.FAILED);
return;
}
synchronized (this)
{
//@formatter:off
final long playerRegisteredItems = _commissionItems.values().stream()
.filter(c -> c.getItemInstance().getOwnerId() == player.getObjectId())
.count();
//@formatter:on
if (playerRegisteredItems >= MAX_ITEMS_REGISTRED_PER_PLAYER)
{
player.sendPacket(SystemMessageId.THE_ITEM_HAS_FAILED_TO_BE_REGISTERED);
player.sendPacket(ExResponseCommissionRegister.FAILED);
return;
}
final long registrationFee = (long) Math.max(MIN_REGISTRATION_AND_SALE_FEE, (totalPrice * REGISTRATION_FEE_PER_DAY) * durationInDays);
if (!player.getInventory().reduceAdena("Commission Registration Fee", registrationFee, player, null))
{
player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA_TO_REGISTER_THE_ITEM);
player.sendPacket(ExResponseCommissionRegister.FAILED);
return;
}
itemInstance = player.getInventory().detachItem("Commission Registration", itemInstance, itemCount, ItemLocation.COMMISSION, player, null);
if (itemInstance == null)
{
player.getInventory().addAdena("Commission error refund", registrationFee, player, null);
player.sendPacket(SystemMessageId.THE_ITEM_HAS_FAILED_TO_BE_REGISTERED);
player.sendPacket(ExResponseCommissionRegister.FAILED);
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(INSERT_COMMISSION_ITEM, Statement.RETURN_GENERATED_KEYS))
{
final Instant startTime = Instant.now();
ps.setInt(1, itemInstance.getObjectId());
ps.setLong(2, pricePerUnit);
ps.setTimestamp(3, Timestamp.from(startTime));
ps.setByte(4, durationInDays);
ps.executeUpdate();
try (ResultSet rs = ps.getGeneratedKeys())
{
if (rs.next())
{
final CommissionItem commissionItem = new CommissionItem(rs.getLong(1), itemInstance, pricePerUnit, startTime, durationInDays);
final ScheduledFuture<?> saleEndTask = ThreadPoolManager.getInstance().scheduleGeneral(() -> expireSale(commissionItem), Duration.between(Instant.now(), commissionItem.getEndTime()).toMillis());
commissionItem.setSaleEndTask(saleEndTask);
_commissionItems.put(commissionItem.getCommissionId(), commissionItem);
player.getLastCommissionInfos().put(itemInstance.getId(), new ExResponseCommissionInfo(itemInstance.getId(), pricePerUnit, itemCount, (byte) ((durationInDays - 1) / 2)));
player.sendPacket(SystemMessageId.THE_ITEM_HAS_BEEN_SUCCESSFULLY_REGISTERED);
player.sendPacket(ExResponseCommissionRegister.SUCCEED);
}
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Failed inserting commission item. ItemInstance: " + itemInstance, e);
player.sendPacket(SystemMessageId.THE_ITEM_HAS_FAILED_TO_BE_REGISTERED);
player.sendPacket(ExResponseCommissionRegister.FAILED);
}
}
}
/**
* Deletes an item and returns it to the player.
* @param player the player
* @param commissionId the commission id
*/
public void deleteItem(L2PcInstance player, long commissionId)
{
final CommissionItem commissionItem = getCommissionItem(commissionId);
if (commissionItem == null)
{
player.sendPacket(SystemMessageId.CANCELLATION_OF_SALE_HAS_FAILED_BECAUSE_REQUIREMENTS_ARE_NOT_MET);
player.sendPacket(ExResponseCommissionDelete.FAILED);
return;
}
if (commissionItem.getItemInstance().getOwnerId() != player.getObjectId())
{
player.sendPacket(ExResponseCommissionDelete.FAILED);
return;
}
if (!player.isInventoryUnder80(false) || (player.getWeightPenalty() >= 3))
{
player.sendPacket(SystemMessageId.IF_THE_WEIGHT_IS_80_OR_MORE_AND_THE_INVENTORY_NUMBER_IS_90_OR_MORE_PURCHASE_CANCELLATION_IS_NOT_POSSIBLE);
player.sendPacket(SystemMessageId.CANCELLATION_OF_SALE_HAS_FAILED_BECAUSE_REQUIREMENTS_ARE_NOT_MET);
player.sendPacket(ExResponseCommissionDelete.FAILED);
return;
}
if ((_commissionItems.remove(commissionId) == null) || !commissionItem.getSaleEndTask().cancel(false))
{
player.sendPacket(SystemMessageId.CANCELLATION_OF_SALE_HAS_FAILED_BECAUSE_REQUIREMENTS_ARE_NOT_MET);
player.sendPacket(ExResponseCommissionDelete.FAILED);
return;
}
if (deleteItemFromDB(commissionId))
{
player.getInventory().addItem("Commission Cancellation", commissionItem.getItemInstance(), player, null);
player.sendPacket(SystemMessageId.CANCELLATION_OF_SALE_FOR_THE_ITEM_IS_SUCCESSFUL);
player.sendPacket(ExResponseCommissionDelete.SUCCEED);
}
else
{
player.sendPacket(SystemMessageId.CANCELLATION_OF_SALE_HAS_FAILED_BECAUSE_REQUIREMENTS_ARE_NOT_MET);
player.sendPacket(ExResponseCommissionDelete.FAILED);
}
}
/**
* Buys the item for the given player.
* @param player the player
* @param commissionId the commission id
*/
public void buyItem(L2PcInstance player, long commissionId)
{
final CommissionItem commissionItem = getCommissionItem(commissionId);
if (commissionItem == null)
{
player.sendPacket(SystemMessageId.ITEM_PURCHASE_HAS_FAILED);
player.sendPacket(ExResponseCommissionBuyItem.FAILED);
return;
}
final L2ItemInstance itemInstance = commissionItem.getItemInstance();
if (itemInstance.getOwnerId() == player.getObjectId())
{
player.sendPacket(SystemMessageId.ITEM_PURCHASE_HAS_FAILED);
player.sendPacket(ExResponseCommissionBuyItem.FAILED);
return;
}
if (!player.isInventoryUnder80(false) || (player.getWeightPenalty() >= 3))
{
player.sendPacket(SystemMessageId.IF_THE_WEIGHT_IS_80_OR_MORE_AND_THE_INVENTORY_NUMBER_IS_90_OR_MORE_PURCHASE_CANCELLATION_IS_NOT_POSSIBLE);
player.sendPacket(ExResponseCommissionBuyItem.FAILED);
return;
}
final long totalPrice = itemInstance.getCount() * commissionItem.getPricePerUnit();
if (!player.getInventory().reduceAdena("Commission Registration Fee", totalPrice, player, null))
{
player.sendPacket(SystemMessageId.YOU_DO_NOT_HAVE_ENOUGH_ADENA);
player.sendPacket(ExResponseCommissionBuyItem.FAILED);
return;
}
if ((_commissionItems.remove(commissionId) == null) || !commissionItem.getSaleEndTask().cancel(false))
{
player.getInventory().addAdena("Commission error refund", totalPrice, player, null);
player.sendPacket(SystemMessageId.ITEM_PURCHASE_HAS_FAILED);
player.sendPacket(ExResponseCommissionBuyItem.FAILED);
return;
}
if (deleteItemFromDB(commissionId))
{
final long saleFee = (long) Math.max(MIN_REGISTRATION_AND_SALE_FEE, (totalPrice * SALE_FEE_PER_DAY) * commissionItem.getDurationInDays());
final Message mail = new Message(itemInstance.getOwnerId(), itemInstance, MailType.COMMISSION_ITEM_SOLD);
final Mail attachement = mail.createAttachments();
attachement.addItem("Commission Item Sold", Inventory.ADENA_ID, totalPrice - saleFee, player, null);
MailManager.getInstance().sendMessage(mail);
player.sendPacket(new ExResponseCommissionBuyItem(commissionItem));
player.getInventory().addItem("Commission Buy Item", commissionItem.getItemInstance(), player, null);
}
else
{
player.getInventory().addAdena("Commission error refund", totalPrice, player, null);
player.sendPacket(ExResponseCommissionBuyItem.FAILED);
}
}
/**
* Deletes a commission item from database.
* @param commissionId the commission item
* @return {@code true} if the item was deleted successfully, {@code false} otherwise
*/
private boolean deleteItemFromDB(long commissionId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(DELETE_COMMISSION_ITEM))
{
ps.setLong(1, commissionId);
if (ps.executeUpdate() > 0)
{
return true;
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Failed deleting commission item. Commission ID: " + commissionId, e);
}
return false;
}
/**
* Expires the sale of a commission item and sends the item back to the player.
* @param commissionItem the comission item
*/
private void expireSale(CommissionItem commissionItem)
{
if ((_commissionItems.remove(commissionItem.getCommissionId()) != null) && deleteItemFromDB(commissionItem.getCommissionId()))
{
final Message mail = new Message(commissionItem.getItemInstance().getOwnerId(), commissionItem.getItemInstance(), MailType.COMMISSION_ITEM_RETURNED);
MailManager.getInstance().sendMessage(mail);
}
}
/**
* Gets the commission item.
* @param commissionId the commission id to get
* @return the commission item if it exists, {@code null} otherwise
*/
public CommissionItem getCommissionItem(long commissionId)
{
return _commissionItems.get(commissionId);
}
/**
* @param objectId
* @return {@code true} if player with the objectId has commission items, {@code false} otherwise
*/
public boolean hasCommissionItems(int objectId)
{
return _commissionItems.values().stream().anyMatch(item -> item.getItemInstance().getObjectId() == objectId);
}
/**
* Checks if the player is allowed to interact with commission manager.
* @param player the player
* @return {@code true} if the player is allowed to interact, {@code false} otherwise
*/
public static boolean isPlayerAllowedToInteract(L2PcInstance player)
{
final L2Npc npc = player.getLastFolkNPC();
if ((npc != null) && (npc instanceof CommissionManagerInstance))
{
return npc.calculateDistance(player, true, false) <= INTERACTION_DISTANCE;
}
return false;
}
/**
* Gets the single instance.
* @return the single instance
*/
public static CommissionManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final CommissionManager _instance = new CommissionManager();
}
}

View File

@ -0,0 +1,402 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.model.CursedWeapon;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2DefenderInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2FeedableBeastInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2FortCommanderInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2GuardInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.util.Broadcast;
/**
* UnAfraid: TODO: Rewrite with DocumentParser
* @author Micht
*/
public final class CursedWeaponsManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(CursedWeaponsManager.class.getName());
private final Map<Integer, CursedWeapon> _cursedWeapons = new HashMap<>();
protected CursedWeaponsManager()
{
load();
}
@Override
public void load()
{
if (!Config.ALLOW_CURSED_WEAPONS)
{
return;
}
parseDatapackFile("data/CursedWeapons.xml");
restore();
controlPlayers();
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + _cursedWeapons.size() + " cursed weapon(s).");
}
@Override
public void parseDocument(Document doc, File f)
{
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("item".equalsIgnoreCase(d.getNodeName()))
{
NamedNodeMap attrs = d.getAttributes();
final int id = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
final int skillId = Integer.parseInt(attrs.getNamedItem("skillId").getNodeValue());
final String name = attrs.getNamedItem("name").getNodeValue();
final CursedWeapon cw = new CursedWeapon(id, skillId, name);
int val;
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("dropRate".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
val = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
cw.setDropRate(val);
}
else if ("duration".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
val = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
cw.setDuration(val);
}
else if ("durationLost".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
val = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
cw.setDurationLost(val);
}
else if ("disapearChance".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
val = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
cw.setDisapearChance(val);
}
else if ("stageKills".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
val = Integer.parseInt(attrs.getNamedItem("val").getNodeValue());
cw.setStageKills(val);
}
}
// Store cursed weapon
_cursedWeapons.put(id, cw);
}
}
}
}
}
private void restore()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT itemId, charId, playerReputation, playerPkKills, nbKills, endTime FROM cursed_weapons"))
{
// Retrieve the L2PcInstance from the characters table of the database
CursedWeapon cw;
while (rs.next())
{
cw = _cursedWeapons.get(rs.getInt("itemId"));
cw.setPlayerId(rs.getInt("charId"));
cw.setPlayerReputation(rs.getInt("playerReputation"));
cw.setPlayerPkKills(rs.getInt("playerPkKills"));
cw.setNbKills(rs.getInt("nbKills"));
cw.setEndTime(rs.getLong("endTime"));
cw.reActivate();
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not restore CursedWeapons data: ", e);
}
}
private void controlPlayers()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT owner_id FROM items WHERE item_id=?"))
{
// TODO: See comments below...
// This entire for loop should NOT be necessary, since it is already handled by
// CursedWeapon.endOfLife(). However, if we indeed *need* to duplicate it for safety,
// then we'd better make sure that it FULLY cleans up inactive cursed weapons!
// Undesired effects result otherwise, such as player with no zariche but with karma
// or a lost-child entry in the cursed weapons table, without a corresponding one in items...
for (CursedWeapon cw : _cursedWeapons.values())
{
if (cw.isActivated())
{
continue;
}
// Do an item check to be sure that the cursed weapon isn't hold by someone
final int itemId = cw.getItemId();
ps.setInt(1, itemId);
try (ResultSet rset = ps.executeQuery())
{
if (rset.next())
{
// A player has the cursed weapon in his inventory ...
final int playerId = rset.getInt("owner_id");
LOGGER.info("PROBLEM : Player " + playerId + " owns the cursed weapon " + itemId + " but he shouldn't.");
// Delete the item
try (PreparedStatement delete = con.prepareStatement("DELETE FROM items WHERE owner_id=? AND item_id=?"))
{
delete.setInt(1, playerId);
delete.setInt(2, itemId);
if (delete.executeUpdate() != 1)
{
LOGGER.warning("Error while deleting cursed weapon " + itemId + " from userId " + playerId);
}
}
// Restore the player's old karma and pk count
try (PreparedStatement update = con.prepareStatement("UPDATE characters SET reputation=?, pkkills=? WHERE charId=?"))
{
update.setInt(1, cw.getPlayerReputation());
update.setInt(2, cw.getPlayerPkKills());
update.setInt(3, playerId);
if (update.executeUpdate() != 1)
{
LOGGER.warning("Error while updating karma & pkkills for userId " + cw.getPlayerId());
}
}
// clean up the cursed weapons table.
removeFromDb(itemId);
}
}
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Could not check CursedWeapons data: ", e);
}
}
public synchronized void checkDrop(L2Attackable attackable, L2PcInstance player)
{
if ((attackable instanceof L2DefenderInstance) || (attackable instanceof L2GuardInstance) || (attackable instanceof L2GrandBossInstance) || (attackable instanceof L2FeedableBeastInstance) || (attackable instanceof L2FortCommanderInstance))
{
return;
}
for (CursedWeapon cw : _cursedWeapons.values())
{
if (cw.isActive())
{
continue;
}
if (cw.checkDrop(attackable, player))
{
break;
}
}
}
public void activate(L2PcInstance player, L2ItemInstance item)
{
final CursedWeapon cw = _cursedWeapons.get(item.getId());
if (player.isCursedWeaponEquipped()) // cannot own 2 cursed swords
{
final CursedWeapon cw2 = _cursedWeapons.get(player.getCursedWeaponEquippedId());
// TODO: give the bonus level in a more appropriate manner.
// The following code adds "_stageKills" levels. This will also show in the char status.
// I do not have enough info to know if the bonus should be shown in the pk count, or if it
// should be a full "_stageKills" bonus or just the remaining from the current count till the of the current stage...
// This code is a TEMP fix, so that the cursed weapon's bonus level can be observed with as little change in the code as possible, until proper info arises.
cw2.setNbKills(cw2.getStageKills() - 1);
cw2.increaseKills();
// erase the newly obtained cursed weapon
cw.setPlayer(player); // NECESSARY in order to find which inventory the weapon is in!
cw.endOfLife(); // expire the weapon and clean up.
}
else
{
cw.activate(player, item);
}
}
public void drop(int itemId, L2Character killer)
{
final CursedWeapon cw = _cursedWeapons.get(itemId);
cw.dropIt(killer);
}
public void increaseKills(int itemId)
{
final CursedWeapon cw = _cursedWeapons.get(itemId);
cw.increaseKills();
}
public int getLevel(int itemId)
{
final CursedWeapon cw = _cursedWeapons.get(itemId);
return cw.getLevel();
}
public static void announce(SystemMessage sm)
{
Broadcast.toAllOnlinePlayers(sm);
}
public void checkPlayer(L2PcInstance player)
{
if (player == null)
{
return;
}
for (CursedWeapon cw : _cursedWeapons.values())
{
if (cw.isActivated() && (player.getObjectId() == cw.getPlayerId()))
{
cw.setPlayer(player);
cw.setItem(player.getInventory().getItemByItemId(cw.getItemId()));
cw.giveSkill();
player.setCursedWeaponEquippedId(cw.getItemId());
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_S2_MINUTE_S_OF_USAGE_TIME_REMAINING);
sm.addString(cw.getName());
// sm.addItemName(cw.getItemId());
sm.addInt((int) ((cw.getEndTime() - System.currentTimeMillis()) / 60000));
player.sendPacket(sm);
}
}
}
public int checkOwnsWeaponId(int ownerId)
{
for (CursedWeapon cw : _cursedWeapons.values())
{
if (cw.isActivated() && (ownerId == cw.getPlayerId()))
{
return cw.getItemId();
}
}
return -1;
}
public static void removeFromDb(int itemId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM cursed_weapons WHERE itemId = ?"))
{
ps.setInt(1, itemId);
ps.executeUpdate();
}
catch (SQLException e)
{
LOGGER.log(Level.SEVERE, "Failed to remove data: " + e.getMessage(), e);
}
}
public void saveData()
{
for (CursedWeapon cw : _cursedWeapons.values())
{
cw.saveData();
}
}
public boolean isCursed(int itemId)
{
return _cursedWeapons.containsKey(itemId);
}
public Collection<CursedWeapon> getCursedWeapons()
{
return _cursedWeapons.values();
}
public Set<Integer> getCursedWeaponsIds()
{
return _cursedWeapons.keySet();
}
public CursedWeapon getCursedWeapon(int itemId)
{
return _cursedWeapons.get(itemId);
}
public void givePassive(int itemId)
{
try
{
_cursedWeapons.get(itemId).giveSkill();
}
catch (Exception e)
{
/***/
}
}
public static CursedWeaponsManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final CursedWeaponsManager _instance = new CursedWeaponsManager();
}
}

View File

@ -0,0 +1,639 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.data.xml.impl.SpawnsData;
import com.l2jmobius.gameserver.datatables.SpawnTable;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
import com.l2jmobius.gameserver.util.Util;
/**
* Database spawn manager.
* @author godson, UnAfraid
*/
public class DBSpawnManager
{
private static final Logger LOGGER = Logger.getLogger(DBSpawnManager.class.getName());
protected final Map<Integer, L2Npc> _npcs = new ConcurrentHashMap<>();
protected final Map<Integer, L2Spawn> _spawns = new ConcurrentHashMap<>();
protected final Map<Integer, StatsSet> _storedInfo = new ConcurrentHashMap<>();
protected final Map<Integer, ScheduledFuture<?>> _schedules = new ConcurrentHashMap<>();
public static enum DBStatusType
{
ALIVE,
DEAD,
UNDEFINED
}
/**
* Instantiates a new raid npc spawn manager.
*/
protected DBSpawnManager()
{
load();
}
/**
* Load.
*/
public void load()
{
if (Config.ALT_DEV_NO_SPAWNS)
{
return;
}
_npcs.clear();
_spawns.clear();
_storedInfo.clear();
_schedules.clear();
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT * FROM npc_respawns");
ResultSet rset = statement.executeQuery())
{
while (rset.next())
{
final L2NpcTemplate template = getValidTemplate(rset.getInt("id"));
if (template != null)
{
final L2Spawn spawn = new L2Spawn(template);
spawn.setX(rset.getInt("x"));
spawn.setY(rset.getInt("y"));
spawn.setZ(rset.getInt("z"));
spawn.setAmount(1);
spawn.setHeading(rset.getInt("heading"));
final List<NpcSpawnTemplate> spawns = SpawnsData.getInstance().getNpcSpawns(npc -> (npc.getId() == template.getId()) && npc.hasDBSave());
if (spawns.isEmpty())
{
LOGGER.warning(getClass().getSimpleName() + ": Couldn't find spawn declaration for npc: " + template.getId() + " - " + template.getName());
deleteSpawn(spawn, true);
continue;
}
else if (spawns.size() > 1)
{
LOGGER.warning(getClass().getSimpleName() + ": Found multiple database spawns for npc: " + template.getId() + " - " + template.getName() + " " + spawns);
continue;
}
final NpcSpawnTemplate spawnTemplate = spawns.get(0);
spawn.setSpawnTemplate(spawnTemplate);
int respawn = 0, respawnRandom = 0;
if (spawnTemplate.getRespawnTime() != null)
{
respawn = (int) spawnTemplate.getRespawnTime().getSeconds();
}
if (spawnTemplate.getRespawnTimeRandom() != null)
{
respawnRandom = (int) spawnTemplate.getRespawnTimeRandom().getSeconds();
}
if (respawn > 0)
{
spawn.setRespawnDelay(respawn, respawnRandom);
spawn.startRespawn();
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Found database spawns without respawn for npc: " + template.getId() + " - " + template.getName() + " " + spawnTemplate);
continue;
}
addNewSpawn(spawn, rset.getLong("respawnTime"), rset.getDouble("currentHp"), rset.getDouble("currentMp"), false);
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Could not load npc #" + rset.getInt("id") + " from DB");
}
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _npcs.size() + " Instances");
LOGGER.info(getClass().getSimpleName() + ": Scheduled " + _schedules.size() + " Instances");
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldnt load npc_respawns table", e);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while initializing DBSpawnManager: ", e);
}
}
private class SpawnSchedule implements Runnable
{
private final Logger LOGGER = Logger.getLogger(SpawnSchedule.class.getName());
private final int _npcId;
/**
* Instantiates a new spawn schedule.
* @param npcId the npc id
*/
public SpawnSchedule(int npcId)
{
_npcId = npcId;
}
@Override
public void run()
{
final L2Npc npc = _spawns.get(_npcId).doSpawn();
if (npc != null)
{
npc.setDBStatus(DBStatusType.ALIVE);
final StatsSet info = new StatsSet();
info.set("currentHP", npc.getCurrentHp());
info.set("currentMP", npc.getCurrentMp());
info.set("respawnTime", 0L);
_storedInfo.put(_npcId, info);
_npcs.put(_npcId, npc);
LOGGER.info(getClass().getSimpleName() + ": Spawning NPC " + npc.getName());
}
_schedules.remove(_npcId);
}
}
/**
* Update status.
* @param npc the npc
* @param isNpcDead the is npc dead
*/
public void updateStatus(L2Npc npc, boolean isNpcDead)
{
final StatsSet info = _storedInfo.get(npc.getId());
if (info == null)
{
return;
}
if (isNpcDead)
{
npc.setDBStatus(DBStatusType.DEAD);
final int respawnMinDelay = (int) (npc.getSpawn().getRespawnMinDelay() * Config.RAID_MIN_RESPAWN_MULTIPLIER);
final int respawnMaxDelay = (int) (npc.getSpawn().getRespawnMaxDelay() * Config.RAID_MAX_RESPAWN_MULTIPLIER);
final int respawnDelay = Rnd.get(respawnMinDelay, respawnMaxDelay);
final long respawnTime = System.currentTimeMillis() + respawnDelay;
info.set("currentHP", npc.getMaxHp());
info.set("currentMP", npc.getMaxMp());
info.set("respawnTime", respawnTime);
if (!_schedules.containsKey(npc.getId()) && ((respawnMinDelay > 0) || (respawnMaxDelay > 0)))
{
LOGGER.info(getClass().getSimpleName() + ": Updated " + npc.getName() + " respawn time to " + Util.formatDate(new Date(respawnTime), "dd.MM.yyyy HH:mm"));
_schedules.put(npc.getId(), ThreadPoolManager.getInstance().scheduleGeneral(new SpawnSchedule(npc.getId()), respawnDelay));
updateDb();
}
}
else
{
npc.setDBStatus(DBStatusType.ALIVE);
info.set("currentHP", npc.getCurrentHp());
info.set("currentMP", npc.getCurrentMp());
info.set("respawnTime", 0L);
}
_storedInfo.put(npc.getId(), info);
}
/**
* Adds the new spawn.
* @param spawn the spawn dat
* @param respawnTime the respawn time
* @param currentHP the current hp
* @param currentMP the current mp
* @param storeInDb the store in db
*/
public void addNewSpawn(L2Spawn spawn, long respawnTime, double currentHP, double currentMP, boolean storeInDb)
{
if (spawn == null)
{
return;
}
if (_spawns.containsKey(spawn.getId()))
{
return;
}
final int npcId = spawn.getId();
final long time = System.currentTimeMillis();
SpawnTable.getInstance().addNewSpawn(spawn, false);
if ((respawnTime == 0L) || (time > respawnTime))
{
final L2Npc npc = spawn.doSpawn();
if (npc != null)
{
npc.setCurrentHp(currentHP);
npc.setCurrentMp(currentMP);
npc.setDBStatus(DBStatusType.ALIVE);
_npcs.put(npcId, npc);
final StatsSet info = new StatsSet();
info.set("currentHP", currentHP);
info.set("currentMP", currentMP);
info.set("respawnTime", 0L);
_storedInfo.put(npcId, info);
}
}
else
{
final long spawnTime = respawnTime - System.currentTimeMillis();
_schedules.put(npcId, ThreadPoolManager.getInstance().scheduleGeneral(new SpawnSchedule(npcId), spawnTime));
}
_spawns.put(npcId, spawn);
if (storeInDb)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO npc_respawns (id, x, y, z, heading, respawnTime, currentHp, currentMp) VALUES(?, ?, ?, ?, ?, ?, ?, ?)"))
{
statement.setInt(1, spawn.getId());
statement.setInt(2, spawn.getX());
statement.setInt(3, spawn.getY());
statement.setInt(4, spawn.getZ());
statement.setInt(5, spawn.getHeading());
statement.setLong(6, respawnTime);
statement.setDouble(7, currentHP);
statement.setDouble(8, currentMP);
statement.execute();
}
catch (Exception e)
{
// problem with storing spawn
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not store npc #" + npcId + " in the DB: ", e);
}
}
}
public void addNewSpawn(L2Spawn spawn, boolean storeInDb)
{
if (spawn == null)
{
return;
}
final int npcId = spawn.getId();
if (_spawns.containsKey(npcId))
{
return;
}
SpawnTable.getInstance().addNewSpawn(spawn, false);
final L2Npc npc = spawn.doSpawn();
if (npc == null)
{
throw new NullPointerException();
}
npc.setDBStatus(DBStatusType.ALIVE);
final StatsSet info = new StatsSet();
info.set("currentHP", npc.getMaxHp());
info.set("currentMP", npc.getMaxMp());
info.set("respawnTime", 0L);
_npcs.put(npcId, npc);
_storedInfo.put(npcId, info);
_spawns.put(npcId, spawn);
if (storeInDb)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO npc_respawns (id, x, y, z, heading, respawnTime, currentHp, currentMp) VALUES(?, ?, ?, ?, ?, ?, ?, ?)"))
{
statement.setInt(1, spawn.getId());
statement.setInt(2, spawn.getX());
statement.setInt(3, spawn.getY());
statement.setInt(4, spawn.getZ());
statement.setInt(5, spawn.getHeading());
statement.setLong(6, 0);
statement.setDouble(7, npc.getMaxHp());
statement.setDouble(8, npc.getMaxMp());
statement.execute();
}
catch (Exception e)
{
// problem with storing spawn
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not store npc #" + npcId + " in the DB: ", e);
}
}
}
/**
* Delete spawn.
* @param spawn the spawn dat
* @param updateDb the update db
*/
public void deleteSpawn(L2Spawn spawn, boolean updateDb)
{
if (spawn == null)
{
return;
}
final int npcId = spawn.getId();
_spawns.remove(npcId);
_npcs.remove(npcId);
_storedInfo.remove(npcId);
final ScheduledFuture<?> task = _schedules.remove(npcId);
if (task != null)
{
task.cancel(true);
}
if (updateDb)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM npc_respawns WHERE id = ?"))
{
ps.setInt(1, npcId);
ps.execute();
}
catch (Exception e)
{
// problem with deleting spawn
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not remove npc #" + npcId + " from DB: ", e);
}
}
SpawnTable.getInstance().deleteSpawn(spawn, false);
}
/**
* Update database.
*/
private void updateDb()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("UPDATE npc_respawns SET respawnTime = ?, currentHP = ?, currentMP = ? WHERE id = ?"))
{
for (Integer npcId : _storedInfo.keySet())
{
if (npcId == null)
{
continue;
}
final L2Npc npc = _npcs.get(npcId);
if (npc == null)
{
continue;
}
if (npc.getDBStatus().equals(DBStatusType.ALIVE))
{
updateStatus(npc, false);
}
final StatsSet info = _storedInfo.get(npcId);
if (info == null)
{
continue;
}
try
{
statement.setLong(1, info.getLong("respawnTime"));
statement.setDouble(2, info.getDouble("currentHP"));
statement.setDouble(3, info.getDouble("currentMP"));
statement.setInt(4, npcId);
statement.executeUpdate();
statement.clearParameters();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldnt update npc_respawns table ", e);
}
}
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": SQL error while updating database spawn to database: ", e);
}
}
/**
* Gets the all npc status.
* @return the all npc status
*/
public String[] getAllNpcsStatus()
{
final String[] msg = new String[(_npcs == null) ? 0 : _npcs.size()];
if (_npcs == null)
{
msg[0] = "None";
return msg;
}
int index = 0;
for (int i : _npcs.keySet())
{
final L2Npc npc = _npcs.get(i);
msg[index++] = npc.getName() + ": " + npc.getDBStatus().name();
}
return msg;
}
/**
* Gets the npc status.
* @param npcId the npc id
* @return the raid npc status
*/
public String getNpcsStatus(int npcId)
{
String msg = "NPC Status..." + Config.EOL;
if (_npcs == null)
{
msg += "None";
return msg;
}
if (_npcs.containsKey(npcId))
{
final L2Npc npc = _npcs.get(npcId);
msg += npc.getName() + ": " + npc.getDBStatus().name();
}
return msg;
}
/**
* Gets the raid npc status id.
* @param npcId the npc id
* @return the raid npc status id
*/
public DBStatusType getNpcStatusId(int npcId)
{
if (_npcs.containsKey(npcId))
{
return _npcs.get(npcId).getDBStatus();
}
else if (_schedules.containsKey(npcId))
{
return DBStatusType.DEAD;
}
else
{
return DBStatusType.UNDEFINED;
}
}
/**
* Gets the valid template.
* @param npcId the npc id
* @return the valid template
*/
public L2NpcTemplate getValidTemplate(int npcId)
{
return NpcData.getInstance().getTemplate(npcId);
}
/**
* Notify spawn night npc.
* @param npc the npc
*/
public void notifySpawnNightNpc(L2Npc npc)
{
final StatsSet info = new StatsSet();
info.set("currentHP", npc.getCurrentHp());
info.set("currentMP", npc.getCurrentMp());
info.set("respawnTime", 0L);
npc.setDBStatus(DBStatusType.ALIVE);
_storedInfo.put(npc.getId(), info);
_npcs.put(npc.getId(), npc);
}
/**
* Checks if the npc is defined.
* @param npcId the npc id
* @return {@code true} if is defined
*/
public boolean isDefined(int npcId)
{
return _spawns.containsKey(npcId);
}
/**
* Gets the npcs.
* @return the npcs
*/
public Map<Integer, L2Npc> getNpcs()
{
return _npcs;
}
/**
* Gets the spawns.
* @return the spawns
*/
public Map<Integer, L2Spawn> getSpawns()
{
return _spawns;
}
/**
* Gets the stored info.
* @return the stored info
*/
public Map<Integer, StatsSet> getStoredInfo()
{
return _storedInfo;
}
/**
* Saves and clears the raid npces status, including all schedules.
*/
public void cleanUp()
{
updateDb();
_npcs.clear();
if (_schedules != null)
{
for (Integer npcId : _schedules.keySet())
{
final ScheduledFuture<?> f = _schedules.get(npcId);
f.cancel(true);
}
_schedules.clear();
}
_storedInfo.clear();
_spawns.clear();
}
/**
* Gets the single instance of DBSpawnManager.
* @return single instance of DBSpawnManager
*/
public static DBSpawnManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final DBSpawnManager _instance = new DBSpawnManager();
}
}

View File

@ -0,0 +1,259 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
import com.l2jmobius.gameserver.data.xml.impl.DailyMissionData;
import com.l2jmobius.gameserver.model.DailyMissionDataHolder;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2ClanMember;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.stat.PcStat;
import com.l2jmobius.gameserver.model.base.SubClass;
import com.l2jmobius.gameserver.model.eventengine.AbstractEvent;
import com.l2jmobius.gameserver.model.eventengine.AbstractEventManager;
import com.l2jmobius.gameserver.model.eventengine.ScheduleTarget;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
import com.l2jmobius.gameserver.network.serverpackets.ExVoteSystemInfo;
import com.l2jmobius.gameserver.network.serverpackets.ExWorldChatCnt;
/**
* @author UnAfraid
*/
public class DailyTaskManager extends AbstractEventManager<AbstractEvent<?>>
{
private static final Logger LOGGER = Logger.getLogger(DailyTaskManager.class.getName());
protected DailyTaskManager()
{
}
@Override
public void onInitialized()
{
}
@ScheduleTarget
private void onReset()
{
resetClanBonus();
resetExtendDrop();
resetDailyMissionRewards();
resetDailySkills();
resetRecommends();
resetWorldChatPoints();
}
@ScheduleTarget
private void onSave()
{
GlobalVariablesManager.getInstance().storeMe();
if (Olympiad.getInstance().inCompPeriod())
{
Olympiad.getInstance().saveOlympiadStatus();
LOGGER.info("Olympiad System: Data updated.");
}
}
@ScheduleTarget
private void onClanLeaderApply()
{
for (L2Clan clan : ClanTable.getInstance().getClans())
{
if (clan.getNewLeaderId() != 0)
{
final L2ClanMember member = clan.getClanMember(clan.getNewLeaderId());
if (member == null)
{
continue;
}
clan.setNewLeader(member);
}
}
LOGGER.info("Clan leaders has been updated");
}
@ScheduleTarget
private void onVitalityReset()
{
for (L2PcInstance player : L2World.getInstance().getPlayers())
{
player.setVitalityPoints(PcStat.MAX_VITALITY_POINTS, false);
for (SubClass subclass : player.getSubClasses().values())
{
subclass.setVitalityPoints(PcStat.MAX_VITALITY_POINTS);
}
}
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
try (PreparedStatement st = con.prepareStatement("UPDATE character_subclasses SET vitality_points = ?"))
{
st.setInt(1, PcStat.MAX_VITALITY_POINTS);
st.execute();
}
try (PreparedStatement st = con.prepareStatement("UPDATE characters SET vitality_points = ?"))
{
st.setInt(1, PcStat.MAX_VITALITY_POINTS);
st.execute();
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error while updating vitality", e);
}
LOGGER.info("Vitality resetted");
}
private void resetClanBonus()
{
ClanTable.getInstance().getClans().forEach(L2Clan::resetClanBonus);
LOGGER.info("Daily clan bonus has been resetted.");
}
private void resetExtendDrop()
{
// Update data for offline players.
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM character_variables WHERE var = ?"))
{
ps.setString(1, PlayerVariables.EXTEND_DROP);
ps.execute();
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Could not reset extend drop : ", e);
}
// Update data for online players.
L2World.getInstance().getPlayers().stream().forEach(player ->
{
player.getVariables().set(PlayerVariables.EXTEND_DROP, "");
player.getVariables().storeMe();
});
LOGGER.info("Daily world chat points has been resetted.");
}
private void resetDailySkills()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final List<SkillHolder> dailySkills = getVariables().getList("reset_skills", SkillHolder.class, Collections.emptyList());
for (SkillHolder skill : dailySkills)
{
try (PreparedStatement ps = con.prepareStatement("DELETE FROM character_skills_save WHERE skill_id=?;"))
{
ps.setInt(1, skill.getSkillId());
ps.execute();
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Could not reset daily skill reuse: ", e);
}
LOGGER.info("Daily skill reuse cleaned.");
}
private void resetWorldChatPoints()
{
// Update data for offline players.
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE character_variables SET val = ? WHERE var = ?"))
{
ps.setInt(1, Config.WORLD_CHAT_POINTS_PER_DAY);
ps.setString(2, PlayerVariables.WORLD_CHAT_VARIABLE_NAME);
ps.executeUpdate();
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Could not reset daily world chat points: ", e);
}
// Update data for online players.
L2World.getInstance().getPlayers().stream().forEach(player ->
{
player.setWorldChatPoints(Config.WORLD_CHAT_POINTS_PER_DAY);
player.sendPacket(new ExWorldChatCnt(player));
player.getVariables().storeMe();
});
LOGGER.info("Daily world chat points has been resetted.");
}
private void resetRecommends()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
try (PreparedStatement ps = con.prepareStatement("UPDATE character_reco_bonus SET rec_left = ?, rec_have = 0 WHERE rec_have <= 20"))
{
ps.setInt(1, 0); // Rec left = 0
ps.execute();
}
try (PreparedStatement ps = con.prepareStatement("UPDATE character_reco_bonus SET rec_left = ?, rec_have = GREATEST(rec_have - 20,0) WHERE rec_have > 20"))
{
ps.setInt(1, 0); // Rec left = 0
ps.execute();
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Could not reset Recommendations System: ", e);
}
L2World.getInstance().getPlayers().stream().forEach(player ->
{
player.setRecomLeft(0);
player.setRecomHave(player.getRecomHave() - 20);
player.sendPacket(new ExVoteSystemInfo(player));
player.broadcastUserInfo();
});
}
private void resetDailyMissionRewards()
{
DailyMissionData.getInstance().getDailyMissionData().forEach(DailyMissionDataHolder::reset);
}
public static DailyTaskManager getInstance()
{
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder
{
protected static final DailyTaskManager INSTANCE = new DailyTaskManager();
}
}

View File

@ -0,0 +1,232 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Duel;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
public final class DuelManager
{
private static final int[] ARENAS =
{
147, // OlympiadGrassyArena.xml
148, // OlympiadThreeBridgesArena.xml
149, // OlympiadHerossVestigesArena.xml
150, // OlympiadOrbisArena.xml
};
private final Map<Integer, Duel> _duels = new ConcurrentHashMap<>();
private final AtomicInteger _currentDuelId = new AtomicInteger();
protected DuelManager()
{
}
public Duel getDuel(int duelId)
{
return _duels.get(duelId);
}
public void addDuel(L2PcInstance playerA, L2PcInstance playerB, int partyDuel)
{
if ((playerA == null) || (playerB == null))
{
return;
}
// return if a player has PvPFlag
final String engagedInPvP = "The duel was canceled because a duelist engaged in PvP combat.";
if (partyDuel == 1)
{
boolean playerInPvP = false;
for (L2PcInstance temp : playerA.getParty().getMembers())
{
if (temp.getPvpFlag() != 0)
{
playerInPvP = true;
break;
}
}
if (!playerInPvP)
{
for (L2PcInstance temp : playerB.getParty().getMembers())
{
if (temp.getPvpFlag() != 0)
{
playerInPvP = true;
break;
}
}
}
// A player has PvP flag
if (playerInPvP)
{
for (L2PcInstance temp : playerA.getParty().getMembers())
{
temp.sendMessage(engagedInPvP);
}
for (L2PcInstance temp : playerB.getParty().getMembers())
{
temp.sendMessage(engagedInPvP);
}
return;
}
}
else if ((playerA.getPvpFlag() != 0) || (playerB.getPvpFlag() != 0))
{
playerA.sendMessage(engagedInPvP);
playerB.sendMessage(engagedInPvP);
return;
}
final int duelId = _currentDuelId.incrementAndGet();
_duels.put(duelId, new Duel(playerA, playerB, partyDuel, duelId));
}
public void removeDuel(Duel duel)
{
_duels.remove(duel.getId());
}
public void doSurrender(L2PcInstance player)
{
if ((player == null) || !player.isInDuel())
{
return;
}
final Duel duel = getDuel(player.getDuelId());
duel.doSurrender(player);
}
/**
* Updates player states.
* @param player - the dying player
*/
public void onPlayerDefeat(L2PcInstance player)
{
if ((player == null) || !player.isInDuel())
{
return;
}
final Duel duel = getDuel(player.getDuelId());
if (duel != null)
{
duel.onPlayerDefeat(player);
}
}
/**
* Registers a buff which will be removed if the duel ends
* @param player
* @param buff
*/
public void onBuff(L2PcInstance player, Skill buff)
{
if ((player == null) || !player.isInDuel() || (buff == null))
{
return;
}
final Duel duel = getDuel(player.getDuelId());
if (duel != null)
{
duel.onBuff(player, buff);
}
}
/**
* Removes player from duel.
* @param player - the removed player
*/
public void onRemoveFromParty(L2PcInstance player)
{
if ((player == null) || !player.isInDuel())
{
return;
}
final Duel duel = getDuel(player.getDuelId());
if (duel != null)
{
duel.onRemoveFromParty(player);
}
}
/**
* Broadcasts a packet to the team opposing the given player.
* @param player
* @param packet
*/
public void broadcastToOppositTeam(L2PcInstance player, IClientOutgoingPacket packet)
{
if ((player == null) || !player.isInDuel())
{
return;
}
final Duel duel = getDuel(player.getDuelId());
if (duel == null)
{
return;
}
if ((duel.getPlayerA() == null) || (duel.getPlayerB() == null))
{
return;
}
if (duel.getPlayerA() == player)
{
duel.broadcastToTeam2(packet);
}
else if (duel.getPlayerB() == player)
{
duel.broadcastToTeam1(packet);
}
else if (duel.isPartyDuel())
{
if ((duel.getPlayerA().getParty() != null) && duel.getPlayerA().getParty().getMembers().contains(player))
{
duel.broadcastToTeam2(packet);
}
else if ((duel.getPlayerB().getParty() != null) && duel.getPlayerB().getParty().getMembers().contains(player))
{
duel.broadcastToTeam1(packet);
}
}
}
/**
* Gets new a random Olympiad Stadium instance name.
* @return an instance name
*/
public int getDuelArena()
{
return ARENAS[Rnd.get(ARENAS.length)];
}
public static DuelManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final DuelManager _instance = new DuelManager();
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
/**
* @author Mobius
*/
public final class EventShrineManager
{
private static boolean ENABLE_SHRINES = false;
public boolean areShrinesEnabled()
{
return ENABLE_SHRINES;
}
public void setEnabled(boolean enabled)
{
ENABLE_SHRINES = enabled;
}
public static EventShrineManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final EventShrineManager _instance = new EventShrineManager();
}
}

View File

@ -0,0 +1,115 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
/**
* Contains objectId and factionId for all players.
* @author Mobius
*/
public class FactionManager
{
private static Logger _log = Logger.getLogger(FactionManager.class.getName());
private final Map<Integer, Integer> _playerFactions = new ConcurrentHashMap<>();
protected FactionManager()
{
loadAll();
}
private void loadAll()
{
_playerFactions.clear();
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT charId, faction FROM characters"))
{
while (rs.next())
{
_playerFactions.put(rs.getInt(1), rs.getInt(2));
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Could not load character faction information: " + e.getMessage(), e);
}
_log.info(getClass().getSimpleName() + ": Loaded " + _playerFactions.size() + " character faction values.");
}
public final int getFactionByCharId(int id)
{
if (id <= 0)
{
return 0;
}
Integer factionId = _playerFactions.get(id);
if (factionId != null)
{
return factionId;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT faction FROM characters WHERE charId=?"))
{
ps.setInt(1, id);
try (ResultSet rset = ps.executeQuery())
{
if (rset.next())
{
factionId = rset.getInt(1);
_playerFactions.put(id, factionId);
return factionId;
}
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Could not check existing char id: " + e.getMessage(), e);
}
return 0; // not found
}
public final boolean isSameFaction(L2PcInstance player1, L2PcInstance player2)
{
// TODO: Maybe add support for multiple factions?
return (player1.isGood() && player2.isGood()) || (player1.isEvil() && player2.isEvil());
}
public static FactionManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final FactionManager _instance = new FactionManager();
}
}

View File

@ -0,0 +1,169 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.InstanceListManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.entity.Fort;
public final class FortManager implements InstanceListManager
{
protected static final Logger _log = Logger.getLogger(FortManager.class.getName());
private final Map<Integer, Fort> _forts = new ConcurrentSkipListMap<>();
public final Fort findNearestFort(L2Object obj)
{
return findNearestFort(obj, Long.MAX_VALUE);
}
public final Fort findNearestFort(L2Object obj, long maxDistance)
{
Fort nearestFort = getFort(obj);
if (nearestFort == null)
{
for (Fort fort : getForts())
{
final double distance = fort.getDistance(obj);
if (maxDistance > distance)
{
maxDistance = (long) distance;
nearestFort = fort;
}
}
}
return nearestFort;
}
public final Fort getFortById(int fortId)
{
for (Fort f : getForts())
{
if (f.getResidenceId() == fortId)
{
return f;
}
}
return null;
}
public final Fort getFortByOwner(L2Clan clan)
{
for (Fort f : getForts())
{
if (f.getOwnerClan() == clan)
{
return f;
}
}
return null;
}
public final Fort getFort(String name)
{
for (Fort f : getForts())
{
if (f.getName().equalsIgnoreCase(name.trim()))
{
return f;
}
}
return null;
}
public final Fort getFort(int x, int y, int z)
{
for (Fort f : getForts())
{
if (f.checkIfInZone(x, y, z))
{
return f;
}
}
return null;
}
public final Fort getFort(L2Object activeObject)
{
return getFort(activeObject.getX(), activeObject.getY(), activeObject.getZ());
}
public final Collection<Fort> getForts()
{
return _forts.values();
}
@Override
public void loadInstances()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT id FROM fort ORDER BY id"))
{
while (rs.next())
{
final int fortId = rs.getInt("id");
_forts.put(fortId, new Fort(fortId));
}
_log.info(getClass().getSimpleName() + ": Loaded: " + getForts().size() + " fortress");
for (Fort fort : getForts())
{
fort.getSiege().loadSiegeGuard();
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: loadFortData(): " + e.getMessage(), e);
}
}
@Override
public void updateReferences()
{
}
@Override
public void activateInstances()
{
for (Fort fort : getForts())
{
fort.activateInstance();
}
}
public static FortManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final FortManager _instance = new FortManager();
}
}

View File

@ -0,0 +1,359 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.CombatFlag;
import com.l2jmobius.gameserver.model.FortSiegeSpawn;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Fort;
import com.l2jmobius.gameserver.model.entity.FortSiege;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.CommonSkill;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class FortSiegeManager
{
private static final Logger _log = Logger.getLogger(FortSiegeManager.class.getName());
private int _attackerMaxClans = 500; // Max number of clans
// Fort Siege settings
private Map<Integer, List<FortSiegeSpawn>> _commanderSpawnList;
private Map<Integer, List<CombatFlag>> _flagList;
private boolean _justToTerritory = true; // Changeable in fortsiege.properties
private int _flagMaxCount = 1; // Changeable in fortsiege.properties
private int _siegeClanMinLevel = 4; // Changeable in fortsiege.properties
private int _siegeLength = 60; // Time in minute. Changeable in fortsiege.properties
private int _countDownLength = 10; // Time in minute. Changeable in fortsiege.properties
private int _suspiciousMerchantRespawnDelay = 180; // Time in minute. Changeable in fortsiege.properties
private List<FortSiege> _sieges;
protected FortSiegeManager()
{
load();
}
public final void addSiegeSkills(L2PcInstance character)
{
character.addSkill(CommonSkill.SEAL_OF_RULER.getSkill(), false);
character.addSkill(CommonSkill.BUILD_HEADQUARTERS.getSkill(), false);
}
/**
* @param clan The L2Clan of the player
* @param fortid
* @return true if the clan is registered or owner of a fort
*/
public final boolean checkIsRegistered(L2Clan clan, int fortid)
{
if (clan == null)
{
return false;
}
boolean register = false;
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT clan_id FROM fortsiege_clans where clan_id=? and fort_id=?"))
{
ps.setInt(1, clan.getId());
ps.setInt(2, fortid);
try (ResultSet rs = ps.executeQuery())
{
if (rs.next())
{
register = true;
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: checkIsRegistered(): " + e.getMessage(), e);
}
return register;
}
public final void removeSiegeSkills(L2PcInstance character)
{
character.removeSkill(CommonSkill.SEAL_OF_RULER.getSkill());
character.removeSkill(CommonSkill.BUILD_HEADQUARTERS.getSkill());
}
private void load()
{
final Properties siegeSettings = new Properties();
final File file = new File(Config.FORTSIEGE_CONFIGURATION_FILE);
try (InputStream is = new FileInputStream(file))
{
siegeSettings.load(is);
}
catch (Exception e)
{
_log.log(Level.WARNING, "Error while loading Fort Siege Manager settings!", e);
}
// Siege setting
_justToTerritory = Boolean.parseBoolean(siegeSettings.getProperty("JustToTerritory", "true"));
_attackerMaxClans = Integer.decode(siegeSettings.getProperty("AttackerMaxClans", "500"));
_flagMaxCount = Integer.decode(siegeSettings.getProperty("MaxFlags", "1"));
_siegeClanMinLevel = Integer.decode(siegeSettings.getProperty("SiegeClanMinLevel", "4"));
_siegeLength = Integer.decode(siegeSettings.getProperty("SiegeLength", "60"));
_countDownLength = Integer.decode(siegeSettings.getProperty("CountDownLength", "10"));
_suspiciousMerchantRespawnDelay = Integer.decode(siegeSettings.getProperty("SuspiciousMerchantRespawnDelay", "180"));
// Siege spawns settings
_commanderSpawnList = new ConcurrentHashMap<>();
_flagList = new ConcurrentHashMap<>();
for (Fort fort : FortManager.getInstance().getForts())
{
final List<FortSiegeSpawn> _commanderSpawns = new CopyOnWriteArrayList<>();
final List<CombatFlag> _flagSpawns = new CopyOnWriteArrayList<>();
for (int i = 1; i < 5; i++)
{
final String _spawnParams = siegeSettings.getProperty(fort.getName().replace(" ", "") + "Commander" + i, "");
if (_spawnParams.isEmpty())
{
break;
}
final StringTokenizer st = new StringTokenizer(_spawnParams.trim(), ",");
try
{
final int x = Integer.parseInt(st.nextToken());
final int y = Integer.parseInt(st.nextToken());
final int z = Integer.parseInt(st.nextToken());
final int heading = Integer.parseInt(st.nextToken());
final int npc_id = Integer.parseInt(st.nextToken());
_commanderSpawns.add(new FortSiegeSpawn(fort.getResidenceId(), x, y, z, heading, npc_id, i));
}
catch (Exception e)
{
_log.warning("Error while loading commander(s) for " + fort.getName() + " fort.");
}
}
_commanderSpawnList.put(fort.getResidenceId(), _commanderSpawns);
for (int i = 1; i < 4; i++)
{
final String _spawnParams = siegeSettings.getProperty(fort.getName().replace(" ", "") + "Flag" + i, "");
if (_spawnParams.isEmpty())
{
break;
}
final StringTokenizer st = new StringTokenizer(_spawnParams.trim(), ",");
try
{
final int x = Integer.parseInt(st.nextToken());
final int y = Integer.parseInt(st.nextToken());
final int z = Integer.parseInt(st.nextToken());
final int flag_id = Integer.parseInt(st.nextToken());
_flagSpawns.add(new CombatFlag(fort.getResidenceId(), x, y, z, 0, flag_id));
}
catch (Exception e)
{
_log.warning("Error while loading flag(s) for " + fort.getName() + " fort.");
}
}
_flagList.put(fort.getResidenceId(), _flagSpawns);
}
}
public final List<FortSiegeSpawn> getCommanderSpawnList(int _fortId)
{
return _commanderSpawnList.get(_fortId);
}
public final List<CombatFlag> getFlagList(int _fortId)
{
return _flagList.get(_fortId);
}
public final int getAttackerMaxClans()
{
return _attackerMaxClans;
}
public final int getFlagMaxCount()
{
return _flagMaxCount;
}
public final boolean canRegisterJustTerritory()
{
return _justToTerritory;
}
public final int getSuspiciousMerchantRespawnDelay()
{
return _suspiciousMerchantRespawnDelay;
}
public final FortSiege getSiege(L2Object activeObject)
{
return getSiege(activeObject.getX(), activeObject.getY(), activeObject.getZ());
}
public final FortSiege getSiege(int x, int y, int z)
{
for (Fort fort : FortManager.getInstance().getForts())
{
if (fort.getSiege().checkIfInZone(x, y, z))
{
return fort.getSiege();
}
}
return null;
}
public final int getSiegeClanMinLevel()
{
return _siegeClanMinLevel;
}
public final int getSiegeLength()
{
return _siegeLength;
}
public final int getCountDownLength()
{
return _countDownLength;
}
public final List<FortSiege> getSieges()
{
if (_sieges == null)
{
_sieges = new CopyOnWriteArrayList<>();
}
return _sieges;
}
public final void addSiege(FortSiege fortSiege)
{
getSieges().add(fortSiege);
}
public boolean isCombat(int itemId)
{
return (itemId == 9819);
}
public boolean activateCombatFlag(L2PcInstance player, L2ItemInstance item)
{
if (!checkIfCanPickup(player))
{
return false;
}
final Fort fort = FortManager.getInstance().getFort(player);
final List<CombatFlag> fcf = _flagList.get(fort.getResidenceId());
for (CombatFlag cf : fcf)
{
if (cf.getCombatFlagInstance() == item)
{
cf.activate(player, item);
}
}
return true;
}
public boolean checkIfCanPickup(L2PcInstance player)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_FORTRESS_BATTLE_OF_S1_HAS_FINISHED);
sm.addItemName(9819);
// Cannot own 2 combat flag
if (player.isCombatFlagEquipped())
{
player.sendPacket(sm);
return false;
}
// here check if is siege is in progress
// here check if is siege is attacker
final Fort fort = FortManager.getInstance().getFort(player);
if ((fort == null) || (fort.getResidenceId() <= 0))
{
player.sendPacket(sm);
return false;
}
else if (!fort.getSiege().isInProgress())
{
player.sendPacket(sm);
return false;
}
else if (fort.getSiege().getAttackerClan(player.getClan()) == null)
{
player.sendPacket(sm);
return false;
}
return true;
}
public void dropCombatFlag(L2PcInstance player, int fortId)
{
final Fort fort = FortManager.getInstance().getFortById(fortId);
final List<CombatFlag> fcf = _flagList.get(fort.getResidenceId());
for (CombatFlag cf : fcf)
{
if (cf.getPlayerObjectId() == player.getObjectId())
{
cf.dropIt();
if (fort.getSiege().isInProgress())
{
cf.spawnMe();
}
}
}
}
public static FortSiegeManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final FortSiegeManager _instance = new FortSiegeManager();
}
}

View File

@ -0,0 +1,142 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.variables.AbstractVariables;
/**
* Global Variables Manager.
* @author xban1x
*/
public final class GlobalVariablesManager extends AbstractVariables
{
private static final Logger LOGGER = Logger.getLogger(GlobalVariablesManager.class.getName());
// SQL Queries.
private static final String SELECT_QUERY = "SELECT * FROM global_variables";
private static final String DELETE_QUERY = "DELETE FROM global_variables";
private static final String INSERT_QUERY = "INSERT INTO global_variables (var, value) VALUES (?, ?)";
protected GlobalVariablesManager()
{
restoreMe();
}
@Override
public boolean restoreMe()
{
// Restore previous variables.
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement st = con.createStatement();
ResultSet rset = st.executeQuery(SELECT_QUERY))
{
while (rset.next())
{
set(rset.getString("var"), rset.getString("value"));
}
}
catch (SQLException e)
{
LOGGER.warning(getClass().getSimpleName() + ": Couldn't restore global variables");
return false;
}
finally
{
compareAndSetChanges(true, false);
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + getSet().size() + " variables.");
return true;
}
@Override
public boolean storeMe()
{
// No changes, nothing to store.
if (!hasChanges())
{
return false;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement del = con.createStatement();
PreparedStatement st = con.prepareStatement(INSERT_QUERY))
{
// Clear previous entries.
del.execute(DELETE_QUERY);
// Insert all variables.
for (Entry<String, Object> entry : getSet().entrySet())
{
st.setString(1, entry.getKey());
st.setString(2, String.valueOf(entry.getValue()));
st.addBatch();
}
st.executeBatch();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't save global variables to database.", e);
return false;
}
finally
{
compareAndSetChanges(true, false);
}
LOGGER.info(getClass().getSimpleName() + ": Stored " + getSet().size() + " variables.");
return true;
}
@Override
public boolean deleteMe()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement del = con.createStatement())
{
del.execute(DELETE_QUERY);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't delete global variables to database.", e);
return false;
}
return true;
}
/**
* Gets the single instance of {@code GlobalVariablesManager}.
* @return single instance of {@code GlobalVariablesManager}
*/
public static GlobalVariablesManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final GlobalVariablesManager _instance = new GlobalVariablesManager();
}
}

View File

@ -0,0 +1,215 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Calendar;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.instancemanager.tasks.UpdateSoDStateTask;
import com.l2jmobius.gameserver.model.quest.Quest;
public final class GraciaSeedsManager
{
private static final Logger _log = Logger.getLogger(GraciaSeedsManager.class.getName());
public static String ENERGY_SEEDS = "EnergySeeds";
private static final byte SOITYPE = 2;
private static final byte SOATYPE = 3;
// Seed of Destruction
private static final byte SODTYPE = 1;
private int _SoDTiatKilled = 0;
private int _SoDState = 1;
private final Calendar _SoDLastStateChangeDate;
protected GraciaSeedsManager()
{
_SoDLastStateChangeDate = Calendar.getInstance();
loadData();
handleSodStages();
}
public void saveData(byte seedType)
{
switch (seedType)
{
case SODTYPE:
// Seed of Destruction
GlobalVariablesManager.getInstance().set("SoDState", _SoDState);
GlobalVariablesManager.getInstance().set("SoDTiatKilled", _SoDTiatKilled);
GlobalVariablesManager.getInstance().set("SoDLSCDate", _SoDLastStateChangeDate.getTimeInMillis());
break;
case SOITYPE:
// Seed of Infinity
break;
case SOATYPE:
// Seed of Annihilation
break;
default:
_log.warning(getClass().getSimpleName() + ": Unknown SeedType in SaveData: " + seedType);
break;
}
}
public void loadData()
{
// Seed of Destruction variables
if (GlobalVariablesManager.getInstance().hasVariable("SoDState"))
{
_SoDState = GlobalVariablesManager.getInstance().getInt("SoDState");
_SoDTiatKilled = GlobalVariablesManager.getInstance().getInt("SoDTiatKilled");
_SoDLastStateChangeDate.setTimeInMillis(GlobalVariablesManager.getInstance().getLong("SoDLSCDate"));
}
else
{
// save Initial values
saveData(SODTYPE);
}
}
private void handleSodStages()
{
switch (_SoDState)
{
case 1:
// do nothing, players should kill Tiat a few times
break;
case 2:
// Conquest Complete state, if too much time is passed than change to defense state
final long timePast = System.currentTimeMillis() - _SoDLastStateChangeDate.getTimeInMillis();
if (timePast >= Config.SOD_STAGE_2_LENGTH)
{
// change to Attack state because Defend statet is not implemented
setSoDState(1, true);
}
else
{
ThreadPoolManager.getInstance().scheduleEffect(new UpdateSoDStateTask(), Config.SOD_STAGE_2_LENGTH - timePast);
}
break;
case 3:
// not implemented
setSoDState(1, true);
break;
default:
_log.warning(getClass().getSimpleName() + ": Unknown Seed of Destruction state(" + _SoDState + ")! ");
}
}
public void updateSodState()
{
final Quest quest = QuestManager.getInstance().getQuest(ENERGY_SEEDS);
if (quest == null)
{
_log.warning(getClass().getSimpleName() + ": missing EnergySeeds Quest!");
}
else
{
quest.notifyEvent("StopSoDAi", null, null);
}
}
public void increaseSoDTiatKilled()
{
if (_SoDState == 1)
{
_SoDTiatKilled++;
if (_SoDTiatKilled >= Config.SOD_TIAT_KILL_COUNT)
{
setSoDState(2, false);
}
saveData(SODTYPE);
final Quest esQuest = QuestManager.getInstance().getQuest(ENERGY_SEEDS);
if (esQuest == null)
{
_log.warning(getClass().getSimpleName() + ": missing EnergySeeds Quest!");
}
else
{
esQuest.notifyEvent("StartSoDAi", null, null);
}
}
}
public int getSoDTiatKilled()
{
return _SoDTiatKilled;
}
public void setSoDState(int value, boolean doSave)
{
_log.info(getClass().getSimpleName() + ": New Seed of Destruction state -> " + value + ".");
_SoDLastStateChangeDate.setTimeInMillis(System.currentTimeMillis());
_SoDState = value;
// reset number of Tiat kills
if (_SoDState == 1)
{
_SoDTiatKilled = 0;
}
handleSodStages();
if (doSave)
{
saveData(SODTYPE);
}
}
public long getSoDTimeForNextStateChange()
{
switch (_SoDState)
{
case 1:
return -1;
case 2:
return ((_SoDLastStateChangeDate.getTimeInMillis() + Config.SOD_STAGE_2_LENGTH) - System.currentTimeMillis());
case 3:
// not implemented yet
return -1;
default:
// this should not happen!
return -1;
}
}
public Calendar getSoDLastStateChangeDate()
{
return _SoDLastStateChangeDate;
}
public int getSoDState()
{
return _SoDState;
}
/**
* Gets the single instance of {@code GraciaSeedsManager}.
* @return single instance of {@code GraciaSeedsManager}
*/
public static GraciaSeedsManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final GraciaSeedsManager _instance = new GraciaSeedsManager();
}
}

View File

@ -0,0 +1,268 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.instancemanager.tasks.GrandBossManagerStoreTask;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.instance.L2GrandBossInstance;
import com.l2jmobius.gameserver.model.interfaces.IStorable;
/**
* Grand Boss manager.
* @author DaRkRaGe Revised by Emperorc
*/
public final class GrandBossManager implements IStorable
{
// SQL queries
private static final String UPDATE_GRAND_BOSS_DATA = "UPDATE grandboss_data set loc_x = ?, loc_y = ?, loc_z = ?, heading = ?, respawn_time = ?, currentHP = ?, currentMP = ?, status = ? where boss_id = ?";
private static final String UPDATE_GRAND_BOSS_DATA2 = "UPDATE grandboss_data set status = ? where boss_id = ?";
protected static Logger _log = Logger.getLogger(GrandBossManager.class.getName());
protected static Map<Integer, L2GrandBossInstance> _bosses = new ConcurrentHashMap<>();
protected static Map<Integer, StatsSet> _storedInfo = new HashMap<>();
private final Map<Integer, Integer> _bossStatus = new HashMap<>();
protected GrandBossManager()
{
init();
}
private void init()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement();
ResultSet rs = s.executeQuery("SELECT * from grandboss_data ORDER BY boss_id"))
{
while (rs.next())
{
// Read all info from DB, and store it for AI to read and decide what to do
// faster than accessing DB in real time
final StatsSet info = new StatsSet();
final int bossId = rs.getInt("boss_id");
info.set("loc_x", rs.getInt("loc_x"));
info.set("loc_y", rs.getInt("loc_y"));
info.set("loc_z", rs.getInt("loc_z"));
info.set("heading", rs.getInt("heading"));
info.set("respawn_time", rs.getLong("respawn_time"));
info.set("currentHP", rs.getDouble("currentHP"));
info.set("currentMP", rs.getDouble("currentMP"));
final int status = rs.getInt("status");
_bossStatus.put(bossId, status);
_storedInfo.put(bossId, info);
_log.info(getClass().getSimpleName() + ": " + NpcData.getInstance().getTemplate(bossId).getName() + "(" + bossId + ") status is " + status);
if (status > 0)
{
_log.info(getClass().getSimpleName() + ": Next spawn date of " + NpcData.getInstance().getTemplate(bossId).getName() + " is " + new Date(info.getLong("respawn_time")));
}
}
_log.info(getClass().getSimpleName() + ": Loaded " + _storedInfo.size() + " Instances.");
}
catch (SQLException e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Could not load grandboss_data table: " + e.getMessage(), e);
}
catch (Exception e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Error while initializing GrandBossManager: " + e.getMessage(), e);
}
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(new GrandBossManagerStoreTask(), 5 * 60 * 1000, 5 * 60 * 1000);
}
public int getBossStatus(int bossId)
{
return _bossStatus.get(bossId);
}
public void setBossStatus(int bossId, int status)
{
_bossStatus.put(bossId, status);
_log.info(getClass().getSimpleName() + ": Updated " + NpcData.getInstance().getTemplate(bossId).getName() + "(" + bossId + ") status to " + status);
updateDb(bossId, true);
}
/**
* Adds a L2GrandBossInstance to the list of bosses.
* @param boss
*/
public void addBoss(L2GrandBossInstance boss)
{
if (boss != null)
{
_bosses.put(boss.getId(), boss);
}
}
public L2GrandBossInstance getBoss(int bossId)
{
return _bosses.get(bossId);
}
public StatsSet getStatsSet(int bossId)
{
return _storedInfo.get(bossId);
}
public void setStatsSet(int bossId, StatsSet info)
{
_storedInfo.put(bossId, info);
updateDb(bossId, false);
}
@Override
public boolean storeMe()
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
for (Entry<Integer, StatsSet> e : _storedInfo.entrySet())
{
final L2GrandBossInstance boss = _bosses.get(e.getKey());
final StatsSet info = e.getValue();
if ((boss == null) || (info == null))
{
try (PreparedStatement update = con.prepareStatement(UPDATE_GRAND_BOSS_DATA2))
{
update.setInt(1, _bossStatus.get(e.getKey()));
update.setInt(2, e.getKey());
update.executeUpdate();
update.clearParameters();
}
}
else
{
try (PreparedStatement update = con.prepareStatement(UPDATE_GRAND_BOSS_DATA))
{
update.setInt(1, boss.getX());
update.setInt(2, boss.getY());
update.setInt(3, boss.getZ());
update.setInt(4, boss.getHeading());
update.setLong(5, info.getLong("respawn_time"));
double hp = boss.getCurrentHp();
double mp = boss.getCurrentMp();
if (boss.isDead())
{
hp = boss.getMaxHp();
mp = boss.getMaxMp();
}
update.setDouble(6, hp);
update.setDouble(7, mp);
update.setInt(8, _bossStatus.get(e.getKey()));
update.setInt(9, e.getKey());
update.executeUpdate();
update.clearParameters();
}
}
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Couldn't store grandbosses to database: " + e.getMessage(), e);
return false;
}
return true;
}
private void updateDb(int bossId, boolean statusOnly)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
final L2GrandBossInstance boss = _bosses.get(bossId);
final StatsSet info = _storedInfo.get(bossId);
if (statusOnly || (boss == null) || (info == null))
{
try (PreparedStatement ps = con.prepareStatement(UPDATE_GRAND_BOSS_DATA2))
{
ps.setInt(1, _bossStatus.get(bossId));
ps.setInt(2, bossId);
ps.executeUpdate();
}
}
else
{
try (PreparedStatement ps = con.prepareStatement(UPDATE_GRAND_BOSS_DATA))
{
ps.setInt(1, boss.getX());
ps.setInt(2, boss.getY());
ps.setInt(3, boss.getZ());
ps.setInt(4, boss.getHeading());
ps.setLong(5, info.getLong("respawn_time"));
double hp = boss.getCurrentHp();
double mp = boss.getCurrentMp();
if (boss.isDead())
{
hp = boss.getMaxHp();
mp = boss.getMaxMp();
}
ps.setDouble(6, hp);
ps.setDouble(7, mp);
ps.setInt(8, _bossStatus.get(bossId));
ps.setInt(9, bossId);
ps.executeUpdate();
}
}
}
catch (SQLException e)
{
_log.log(Level.WARNING, "Couldn't update grandbosses to database:" + e.getMessage(), e);
}
}
/**
* Saves all Grand Boss info and then clears all info from memory, including all schedules.
*/
public void cleanUp()
{
storeMe();
_bosses.clear();
_storedInfo.clear();
_bossStatus.clear();
}
/**
* Gets the single instance of {@code GrandBossManager}.
* @return single instance of {@code GrandBossManager}
*/
public static GrandBossManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final GrandBossManager _instance = new GrandBossManager();
}
}

View File

@ -0,0 +1,383 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.Team;
import com.l2jmobius.gameserver.instancemanager.tasks.PenaltyRemoveTask;
import com.l2jmobius.gameserver.model.ArenaParticipantsHolder;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.itemcontainer.PcInventory;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExCubeGameAddPlayer;
import com.l2jmobius.gameserver.network.serverpackets.ExCubeGameChangeTeam;
import com.l2jmobius.gameserver.network.serverpackets.ExCubeGameRemovePlayer;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class manage the player add/remove, team change and event arena status,<br>
* as the clearance of the participants list or liberate the arena.
* @author BiggBoss
*/
public final class HandysBlockCheckerManager
{
// All the participants and their team classified by arena
private static final ArenaParticipantsHolder[] _arenaPlayers = new ArenaParticipantsHolder[4];
// Arena votes to start the game
private static final Map<Integer, Integer> _arenaVotes = new HashMap<>();
// Arena Status, True = is being used, otherwise, False
private static final Map<Integer, Boolean> _arenaStatus = new HashMap<>();
// Registration request penalty (10 seconds)
protected static Set<Integer> _registrationPenalty = Collections.synchronizedSet(new HashSet<>());
/**
* Return the number of event-start votes for the specified arena id
* @param arenaId
* @return int (number of votes)
*/
public synchronized int getArenaVotes(int arenaId)
{
return _arenaVotes.get(arenaId);
}
/**
* Add a new vote to start the event for the specified arena id
* @param arena
*/
public synchronized void increaseArenaVotes(int arena)
{
final int newVotes = _arenaVotes.get(arena) + 1;
final ArenaParticipantsHolder holder = _arenaPlayers[arena];
if ((newVotes > (holder.getAllPlayers().size() / 2)) && !holder.getEvent().isStarted())
{
clearArenaVotes(arena);
if ((holder.getBlueTeamSize() == 0) || (holder.getRedTeamSize() == 0))
{
return;
}
if (Config.HBCE_FAIR_PLAY)
{
holder.checkAndShuffle();
}
ThreadPoolManager.getInstance().executeGeneral(holder.getEvent().new StartEvent());
}
else
{
_arenaVotes.put(arena, newVotes);
}
}
/**
* Will clear the votes queue (of event start) for the specified arena id
* @param arena
*/
public synchronized void clearArenaVotes(int arena)
{
_arenaVotes.put(arena, 0);
}
protected HandysBlockCheckerManager()
{
// Initialize arena status
_arenaStatus.put(0, false);
_arenaStatus.put(1, false);
_arenaStatus.put(2, false);
_arenaStatus.put(3, false);
// Initialize arena votes
_arenaVotes.put(0, 0);
_arenaVotes.put(1, 0);
_arenaVotes.put(2, 0);
_arenaVotes.put(3, 0);
}
/**
* Returns the players holder
* @param arena
* @return ArenaParticipantsHolder
*/
public ArenaParticipantsHolder getHolder(int arena)
{
return _arenaPlayers[arena];
}
/**
* Initializes the participants holder
*/
public void startUpParticipantsQueue()
{
for (int i = 0; i < 4; ++i)
{
_arenaPlayers[i] = new ArenaParticipantsHolder(i);
}
}
/**
* Add the player to the specified arena (through the specified arena manager) and send the needed server -> client packets
* @param player
* @param arenaId
* @return
*/
public boolean addPlayerToArena(L2PcInstance player, int arenaId)
{
final ArenaParticipantsHolder holder = _arenaPlayers[arenaId];
synchronized (holder)
{
boolean isRed;
for (int i = 0; i < 4; i++)
{
if (_arenaPlayers[i].getAllPlayers().contains(player))
{
final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ALREADY_REGISTERED_ON_THE_MATCH_WAITING_LIST);
msg.addCharName(player);
player.sendPacket(msg);
return false;
}
}
if (player.isCursedWeaponEquipped())
{
player.sendPacket(SystemMessageId.YOU_CANNOT_REGISTER_WHILE_IN_POSSESSION_OF_A_CURSED_WEAPON);
return false;
}
if (player.isOnEvent() || player.isInOlympiadMode())
{
player.sendMessage("Couldnt register you due other event participation");
return false;
}
if (OlympiadManager.getInstance().isRegistered(player))
{
OlympiadManager.getInstance().unRegisterNoble(player);
player.sendPacket(SystemMessageId.APPLICANTS_FOR_THE_OLYMPIAD_UNDERGROUND_COLISEUM_OR_KRATEI_S_CUBE_MATCHES_CANNOT_REGISTER);
}
// if(UnderGroundColiseum.getInstance().isRegisteredPlayer(player))
// {
// UngerGroundColiseum.getInstance().removeParticipant(player);
// player.sendPacket(SystemMessageId.APPLICANTS_FOR_THE_OLYMPIAD_UNDERGROUND_COLISEUM_OR_KRATEI_S_CUBE_MATCHES_CANNOT_REGISTER));
// }
// if(KrateiCubeManager.getInstance().isRegisteredPlayer(player))
// {
// KrateiCubeManager.getInstance().removeParticipant(player);
// player.sendPacket(SystemMessageId.APPLICANTS_FOR_THE_OLYMPIAD_UNDERGROUND_COLISEUM_OR_KRATEI_S_CUBE_MATCHES_CANNOT_REGISTER));
// }
if (_registrationPenalty.contains(player.getObjectId()))
{
player.sendPacket(SystemMessageId.YOU_MUST_WAIT_10_SECONDS_BEFORE_ATTEMPTING_TO_REGISTER_AGAIN);
return false;
}
if (holder.getBlueTeamSize() < holder.getRedTeamSize())
{
holder.addPlayer(player, 1);
isRed = false;
}
else
{
holder.addPlayer(player, 0);
isRed = true;
}
holder.broadCastPacketToTeam(new ExCubeGameAddPlayer(player, isRed));
return true;
}
}
/**
* Will remove the specified player from the specified team and arena and will send the needed packet to all his team mates / enemy team mates
* @param player
* @param arenaId
* @param team
*/
public void removePlayer(L2PcInstance player, int arenaId, int team)
{
final ArenaParticipantsHolder holder = _arenaPlayers[arenaId];
synchronized (holder)
{
final boolean isRed = team == 0;
holder.removePlayer(player, team);
holder.broadCastPacketToTeam(new ExCubeGameRemovePlayer(player, isRed));
// End event if theres an empty team
final int teamSize = isRed ? holder.getRedTeamSize() : holder.getBlueTeamSize();
if (teamSize == 0)
{
holder.getEvent().endEventAbnormally();
}
_registrationPenalty.add(player.getObjectId());
schedulePenaltyRemoval(player.getObjectId());
}
}
/**
* Will change the player from one team to other (if possible) and will send the needed packets
* @param player
* @param arena
* @param team
*/
public void changePlayerToTeam(L2PcInstance player, int arena, int team)
{
final ArenaParticipantsHolder holder = _arenaPlayers[arena];
synchronized (holder)
{
final boolean isFromRed = holder.getRedPlayers().contains(player);
if (isFromRed && (holder.getBlueTeamSize() == 6))
{
player.sendMessage("The team is full");
return;
}
else if (!isFromRed && (holder.getRedTeamSize() == 6))
{
player.sendMessage("The team is full");
return;
}
final int futureTeam = isFromRed ? 1 : 0;
holder.addPlayer(player, futureTeam);
if (isFromRed)
{
holder.removePlayer(player, 0);
}
else
{
holder.removePlayer(player, 1);
}
holder.broadCastPacketToTeam(new ExCubeGameChangeTeam(player, isFromRed));
}
}
/**
* Will erase all participants from the specified holder
* @param arenaId
*/
public synchronized void clearPaticipantQueueByArenaId(int arenaId)
{
_arenaPlayers[arenaId].clearPlayers();
}
/**
* Returns true if arena is holding an event at this momment
* @param arenaId
* @return boolean
*/
public boolean arenaIsBeingUsed(int arenaId)
{
if ((arenaId < 0) || (arenaId > 3))
{
return false;
}
return _arenaStatus.get(arenaId);
}
/**
* Set the specified arena as being used
* @param arenaId
*/
public void setArenaBeingUsed(int arenaId)
{
_arenaStatus.put(arenaId, true);
}
/**
* Set as free the specified arena for future events
* @param arenaId
*/
public void setArenaFree(int arenaId)
{
_arenaStatus.put(arenaId, false);
}
/**
* Called when played logs out while participating in Block Checker Event
* @param player
*/
public void onDisconnect(L2PcInstance player)
{
final int arena = player.getBlockCheckerArena();
final int team = getHolder(arena).getPlayerTeam(player);
HandysBlockCheckerManager.getInstance().removePlayer(player, arena, team);
if (player.getTeam() != Team.NONE)
{
player.stopAllEffects();
// Remove team aura
player.setTeam(Team.NONE);
// Remove the event items
final PcInventory inv = player.getInventory();
if (inv.getItemByItemId(13787) != null)
{
final long count = inv.getInventoryItemCount(13787, 0);
inv.destroyItemByItemId("Handys Block Checker", 13787, count, player, player);
}
if (inv.getItemByItemId(13788) != null)
{
final long count = inv.getInventoryItemCount(13788, 0);
inv.destroyItemByItemId("Handys Block Checker", 13788, count, player, player);
}
player.setInsideZone(ZoneId.PVP, false);
// Teleport Back
player.teleToLocation(-57478, -60367, -2370);
}
}
public void removePenalty(int objectId)
{
_registrationPenalty.remove(objectId);
}
private void schedulePenaltyRemoval(int objId)
{
ThreadPoolManager.getInstance().scheduleGeneral(new PenaltyRemoveTask(objId), 10000);
}
/**
* Gets the single instance of {@code HandysBlockCheckerManager}.
* @return single instance of {@code HandysBlockCheckerManager}
*/
public static HandysBlockCheckerManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final HandysBlockCheckerManager _instance = new HandysBlockCheckerManager();
}
}

View File

@ -0,0 +1,678 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.lang.reflect.Constructor;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.time.DayOfWeek;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.commons.util.IXmlReader;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.SpawnsData;
import com.l2jmobius.gameserver.enums.InstanceReenterType;
import com.l2jmobius.gameserver.enums.InstanceRemoveBuffType;
import com.l2jmobius.gameserver.enums.InstanceTeleportType;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2DoorTemplate;
import com.l2jmobius.gameserver.model.holders.InstanceReenterTimeHolder;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.model.instancezone.InstanceTemplate;
import com.l2jmobius.gameserver.model.instancezone.conditions.Condition;
import com.l2jmobius.gameserver.model.spawns.SpawnTemplate;
/**
* Instance manager.
* @author evill33t, GodKratos, malyelfik
*/
public final class InstanceManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(InstanceManager.class.getName());
// Database query
private static final String DELETE_INSTANCE_TIME = "DELETE FROM character_instance_time WHERE charId=? AND instanceId=?";
// Client instance names
private final Map<Integer, String> _instanceNames = new HashMap<>();
// Instance templates holder
private final Map<Integer, InstanceTemplate> _instanceTemplates = new HashMap<>();
// Created instance worlds
private int _currentInstanceId = 0;
private final Map<Integer, Instance> _instanceWorlds = new ConcurrentHashMap<>();
// Player reenter times
private final Map<Integer, Map<Integer, Long>> _playerInstanceTimes = new ConcurrentHashMap<>();
protected InstanceManager()
{
load();
}
// --------------------------------------------------------------------
// Instance data loader
// --------------------------------------------------------------------
@Override
public void load()
{
// Load instance names
_instanceNames.clear();
parseDatapackFile("data/InstanceNames.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _instanceNames.size() + " instance names.");
// Load instance templates
_instanceTemplates.clear();
parseDatapackDirectory("data/instances", true);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _instanceTemplates.size() + " instance templates.");
// Load player's reenter data
_playerInstanceTimes.clear();
restoreInstanceTimes();
LOGGER.info(getClass().getSimpleName() + ": Loaded instance reenter times for " + _playerInstanceTimes.size() + " players.");
}
@Override
public void parseDocument(Document doc, File f)
{
forEach(doc, IXmlReader::isNode, listNode ->
{
switch (listNode.getNodeName())
{
case "list":
{
parseInstanceName(listNode);
break;
}
case "instance":
{
parseInstanceTemplate(listNode, f);
break;
}
}
});
}
/**
* Read instance names from XML file.
* @param n starting XML tag
*/
private void parseInstanceName(Node n)
{
forEach(n, "instance", instanceNode ->
{
final NamedNodeMap attrs = instanceNode.getAttributes();
_instanceNames.put(parseInteger(attrs, "id"), parseString(attrs, "name"));
});
}
/**
* Parse instance template from XML file.
* @param instanceNode start XML tag
* @param file currently parsed file
*/
private void parseInstanceTemplate(Node instanceNode, File file)
{
// Parse "instance" node
final int id = parseInteger(instanceNode.getAttributes(), "id");
if (_instanceTemplates.containsKey(id))
{
LOGGER.warning(getClass().getSimpleName() + ": Instance template with ID " + id + " already exists");
return;
}
final InstanceTemplate template = new InstanceTemplate(new StatsSet(parseAttributes(instanceNode)));
// Update name if wasn't provided
if (template.getName() == null)
{
template.setName(_instanceNames.get(id));
}
// Parse "instance" node children
forEach(instanceNode, IXmlReader::isNode, innerNode ->
{
switch (innerNode.getNodeName())
{
case "time":
{
final NamedNodeMap attrs = innerNode.getAttributes();
template.setDuration(parseInteger(attrs, "duration", -1));
template.setEmptyDestroyTime(parseInteger(attrs, "empty", -1));
template.setEjectTime(parseInteger(attrs, "eject", -1));
break;
}
case "misc":
{
final NamedNodeMap attrs = innerNode.getAttributes();
template.allowPlayerSummon(parseBoolean(attrs, "allowPlayerSummon", false));
template.setIsPvP(parseBoolean(attrs, "isPvP", false));
break;
}
case "rates":
{
final NamedNodeMap attrs = innerNode.getAttributes();
template.setExpRate(parseFloat(attrs, "exp", Config.RATE_INSTANCE_XP));
template.setSPRate(parseFloat(attrs, "sp", Config.RATE_INSTANCE_SP));
template.setExpPartyRate(parseFloat(attrs, "partyExp", Config.RATE_INSTANCE_PARTY_XP));
template.setSPPartyRate(parseFloat(attrs, "partySp", Config.RATE_INSTANCE_PARTY_SP));
break;
}
case "locations":
{
forEach(innerNode, IXmlReader::isNode, locationsNode ->
{
switch (locationsNode.getNodeName())
{
case "enter":
{
final InstanceTeleportType type = parseEnum(locationsNode.getAttributes(), InstanceTeleportType.class, "type");
final List<Location> locations = new ArrayList<>();
forEach(locationsNode, "location", locationNode -> locations.add(parseLocation(locationNode)));
template.setEnterLocation(type, locations);
break;
}
case "exit":
{
final InstanceTeleportType type = parseEnum(locationsNode.getAttributes(), InstanceTeleportType.class, "type");
if (type.equals(InstanceTeleportType.ORIGIN))
{
template.setExitLocation(type, null);
}
else
{
final List<Location> locations = new ArrayList<>();
forEach(locationsNode, "location", locationNode -> locations.add(parseLocation(locationNode)));
if (locations.isEmpty())
{
LOGGER.warning(getClass().getSimpleName() + ": Missing exit location data for instance " + template.getName() + " (" + template.getId() + ")!");
}
else
{
template.setExitLocation(type, locations);
}
}
break;
}
}
});
break;
}
case "spawnlist":
{
final List<SpawnTemplate> spawns = new ArrayList<>();
SpawnsData.getInstance().parseSpawn(innerNode, file, spawns);
template.addSpawns(spawns);
break;
}
case "doorlist":
{
for (Node doorNode = innerNode.getFirstChild(); doorNode != null; doorNode = doorNode.getNextSibling())
{
if (doorNode.getNodeName().equals("door"))
{
final StatsSet parsedSet = DoorData.getInstance().parseDoor(doorNode);
final StatsSet mergedSet = new StatsSet();
final int doorId = parsedSet.getInt("id");
final StatsSet templateSet = DoorData.getInstance().getDoorTemplate(doorId);
if (templateSet != null)
{
mergedSet.merge(templateSet);
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": Cannot find template for door: " + doorId + ", instance: " + template.getName() + " (" + template.getId() + ")");
}
mergedSet.merge(parsedSet);
try
{
template.addDoor(doorId, new L2DoorTemplate(mergedSet));
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Cannot initialize template for door: " + doorId + ", instance: " + template.getName() + " (" + template.getId() + ")", e);
}
}
}
break;
}
case "removeBuffs":
{
final InstanceRemoveBuffType removeBuffType = parseEnum(innerNode.getAttributes(), InstanceRemoveBuffType.class, "type");
final List<Integer> exceptionBuffList = new ArrayList<>();
for (Node e = innerNode.getFirstChild(); e != null; e = e.getNextSibling())
{
if (e.getNodeName().equals("skill"))
{
exceptionBuffList.add(parseInteger(e.getAttributes(), "id"));
}
}
template.setRemoveBuff(removeBuffType, exceptionBuffList);
break;
}
case "reenter":
{
final InstanceReenterType type = parseEnum(innerNode.getAttributes(), InstanceReenterType.class, "apply", InstanceReenterType.NONE);
final List<InstanceReenterTimeHolder> data = new ArrayList<>();
for (Node e = innerNode.getFirstChild(); e != null; e = e.getNextSibling())
{
if (e.getNodeName().equals("reset"))
{
final NamedNodeMap attrs = e.getAttributes();
final int time = parseInteger(attrs, "time", -1);
if (time > 0)
{
data.add(new InstanceReenterTimeHolder(time));
}
else
{
final DayOfWeek day = parseEnum(attrs, DayOfWeek.class, "day");
final int hour = parseInteger(attrs, "hour", -1);
final int minute = parseInteger(attrs, "minute", -1);
data.add(new InstanceReenterTimeHolder(day, hour, minute));
}
}
}
template.setReenterData(type, data);
break;
}
case "parameters":
{
template.setParameters(parseParameters(innerNode));
break;
}
case "conditions":
{
final List<Condition> conditions = new ArrayList<>();
for (Node conditionNode = innerNode.getFirstChild(); conditionNode != null; conditionNode = conditionNode.getNextSibling())
{
if (conditionNode.getNodeName().equals("condition"))
{
final NamedNodeMap attrs = conditionNode.getAttributes();
final String type = parseString(attrs, "type");
final boolean onlyLeader = parseBoolean(attrs, "onlyLeader", false);
final boolean showMessageAndHtml = parseBoolean(attrs, "showMessageAndHtml", false);
// Load parameters
StatsSet params = null;
for (Node f = conditionNode.getFirstChild(); f != null; f = f.getNextSibling())
{
if (f.getNodeName().equals("param"))
{
if (params == null)
{
params = new StatsSet();
}
params.set(parseString(f.getAttributes(), "name"), parseString(f.getAttributes(), "value"));
}
}
// If none parameters found then set empty StatSet
if (params == null)
{
params = StatsSet.EMPTY_STATSET;
}
// Now when everything is loaded register condition to template
try
{
final Class<?> clazz = Class.forName("com.l2jmobius.gameserver.model.instancezone.conditions.Condition" + type);
final Constructor<?> constructor = clazz.getConstructor(InstanceTemplate.class, StatsSet.class, boolean.class, boolean.class);
conditions.add((Condition) constructor.newInstance(template, params, onlyLeader, showMessageAndHtml));
}
catch (Exception ex)
{
LOGGER.warning(getClass().getSimpleName() + ": Unknown condition type " + type + " for instance " + template.getName() + " (" + id + ")!");
}
}
}
template.setConditions(conditions);
break;
}
}
});
// Save template
_instanceTemplates.put(id, template);
}
// --------------------------------------------------------------------
// Instance data loader - END
// --------------------------------------------------------------------
/**
* Create new instance with default template.
* @return newly created default instance.
*/
public Instance createInstance()
{
return new Instance(getNewInstanceId(), new InstanceTemplate(StatsSet.EMPTY_STATSET), null);
}
/**
* Create new instance from given template.
* @param template template used for instance creation
* @param player player who create instance.
* @return newly created instance if success, otherwise {@code null}
*/
public Instance createInstance(InstanceTemplate template, L2PcInstance player)
{
return (template != null) ? new Instance(getNewInstanceId(), template, player) : null;
}
/**
* Create new instance with template defined in datapack.
* @param id template id of instance
* @param player player who create instance
* @return newly created instance if template was found, otherwise {@code null}
*/
public Instance createInstance(int id, L2PcInstance player)
{
if (!_instanceTemplates.containsKey(id))
{
LOGGER.warning(getClass().getSimpleName() + ": Missing template for instance with id " + id + "!");
return null;
}
return new Instance(getNewInstanceId(), _instanceTemplates.get(id), player);
}
/**
* Get instance world with given ID.
* @param instanceId ID of instance
* @return instance itself if found, otherwise {@code null}
*/
public Instance getInstance(int instanceId)
{
return _instanceWorlds.get(instanceId);
}
/**
* Get all active instances.
* @return Collection of all instances
*/
public Collection<Instance> getInstances()
{
return _instanceWorlds.values();
}
/**
* Get instance world for player.
* @param player player who wants to get instance world
* @param isInside when {@code true} find world where player is currently located, otherwise find world where player can enter
* @return instance if found, otherwise {@code null}
*/
public Instance getPlayerInstance(L2PcInstance player, boolean isInside)
{
return _instanceWorlds.values().stream().filter(i -> (isInside) ? i.containsPlayer(player) : i.isAllowed(player)).findFirst().orElse(null);
}
/**
* Get ID for newly created instance.
* @return instance id
*/
private synchronized int getNewInstanceId()
{
do
{
if (_currentInstanceId == Integer.MAX_VALUE)
{
if (Config.DEBUG_INSTANCES)
{
LOGGER.info(getClass().getSimpleName() + ": Instance id owerflow, starting from zero.");
}
_currentInstanceId = 0;
}
_currentInstanceId++;
}
while (_instanceWorlds.containsKey(_currentInstanceId));
return _currentInstanceId;
}
/**
* Register instance world.<br>
* @param instance instance which should be registered
*/
public void register(Instance instance)
{
final int instanceId = instance.getId();
if (!_instanceWorlds.containsKey(instanceId))
{
_instanceWorlds.put(instanceId, instance);
}
}
/**
* Unregister instance world.<br>
* <b><font color=red>To remove instance world properly use {@link Instance#destroy()}.</font></b>
* @param instanceId ID of instance to unregister
*/
public void unregister(int instanceId)
{
if (_instanceWorlds.containsKey(instanceId))
{
_instanceWorlds.remove(instanceId);
}
}
/**
* Get instance name from file "InstanceNames.xml"
* @param templateId template ID of instance
* @return name of instance if found, otherwise {@code null}
*/
public String getInstanceName(int templateId)
{
return _instanceNames.get(templateId);
}
/**
* Restore instance reenter data for all players.
*/
private void restoreInstanceTimes()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement ps = con.createStatement();
ResultSet rs = ps.executeQuery("SELECT * FROM character_instance_time ORDER BY charId"))
{
while (rs.next())
{
// Check if instance penalty passed
final long time = rs.getLong("time");
if (time > System.currentTimeMillis())
{
// Load params
final int charId = rs.getInt("charId");
final int instanceId = rs.getInt("instanceId");
// Set penalty
setReenterPenalty(charId, instanceId, time);
}
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Cannot restore players instance reenter data: ", e);
}
}
/**
* Get all instance re-enter times for specified player.<br>
* This method also removes the penalties that have already expired.
* @param player instance of player who wants to get re-enter data
* @return map in form templateId, penaltyEndTime
*/
public Map<Integer, Long> getAllInstanceTimes(L2PcInstance player)
{
// When player don't have any instance penalty
final Map<Integer, Long> instanceTimes = _playerInstanceTimes.get(player.getObjectId());
if ((instanceTimes == null) || instanceTimes.isEmpty())
{
return Collections.emptyMap();
}
// Find passed penalty
final List<Integer> invalidPenalty = new ArrayList<>(instanceTimes.size());
for (Entry<Integer, Long> entry : instanceTimes.entrySet())
{
if (entry.getValue() <= System.currentTimeMillis())
{
invalidPenalty.add(entry.getKey());
}
}
// Remove them
if (!invalidPenalty.isEmpty())
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(DELETE_INSTANCE_TIME))
{
for (Integer id : invalidPenalty)
{
ps.setInt(1, player.getObjectId());
ps.setInt(2, id);
ps.addBatch();
}
ps.executeBatch();
invalidPenalty.forEach(instanceTimes::remove);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Cannot delete instance character reenter data: ", e);
}
}
return instanceTimes;
}
/**
* Set re-enter penalty for specified player.<br>
* <font color=red><b>This method store penalty into memory only. Use {@link Instance#setReenterTime} to set instance penalty properly.</b></font>
* @param objectId object ID of player
* @param id instance template id
* @param time penalty time
*/
public void setReenterPenalty(int objectId, int id, long time)
{
_playerInstanceTimes.computeIfAbsent(objectId, k -> new ConcurrentHashMap<>()).put(id, time);
}
/**
* Get re-enter time to instance (by template ID) for player.<br>
* This method also removes penalty if expired.
* @param player player who wants to get re-enter time
* @param id template ID of instance
* @return penalty end time if penalty is found, otherwise -1
*/
public long getInstanceTime(L2PcInstance player, int id)
{
// Check if exists reenter data for player
final Map<Integer, Long> playerData = _playerInstanceTimes.get(player.getObjectId());
if ((playerData == null) || !playerData.containsKey(id))
{
return -1;
}
// If reenter time is higher then current, delete it
final long time = playerData.get(id);
if (time <= System.currentTimeMillis())
{
deleteInstanceTime(player, id);
return -1;
}
return time;
}
/**
* Remove re-enter penalty for specified instance from player.
* @param player player who wants to delete penalty
* @param id template id of instance world
*/
public void deleteInstanceTime(L2PcInstance player, int id)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(DELETE_INSTANCE_TIME))
{
ps.setInt(1, player.getObjectId());
ps.setInt(2, id);
ps.execute();
_playerInstanceTimes.get(player.getObjectId()).remove(id);
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not delete character instance reenter data: ", e);
}
}
/**
* Get instance template by template ID.
* @param id template id of instance
* @return instance template if found, otherwise {@code null}
*/
public InstanceTemplate getInstanceTemplate(int id)
{
return _instanceTemplates.get(id);
}
/**
* Get all instances template.
* @return Collection of all instance templates
*/
public Collection<InstanceTemplate> getInstanceTemplates()
{
return _instanceTemplates.values();
}
/**
* Get count of created instance worlds with same template ID.
* @param templateId template id of instance
* @return count of created instances
*/
public long getWorldCount(int templateId)
{
return _instanceWorlds.values().stream().filter(i -> i.getTemplateId() == templateId).count();
}
/**
* Gets the single instance of {@code InstanceManager}.
* @return single instance of {@code InstanceManager}
*/
public static InstanceManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final InstanceManager _instance = new InstanceManager();
}
}

View File

@ -0,0 +1,170 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.model.itemauction.ItemAuctionInstance;
/**
* @author Forsaiken
*/
public final class ItemAuctionManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(ItemAuctionManager.class.getName());
private final Map<Integer, ItemAuctionInstance> _managerInstances = new HashMap<>();
private final AtomicInteger _auctionIds = new AtomicInteger(1);
protected ItemAuctionManager()
{
if (!Config.ALT_ITEM_AUCTION_ENABLED)
{
LOGGER.info("Disabled by config.");
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement statement = con.createStatement();
ResultSet rset = statement.executeQuery("SELECT auctionId FROM item_auction ORDER BY auctionId DESC LIMIT 0, 1"))
{
if (rset.next())
{
_auctionIds.set(rset.getInt(1) + 1);
}
}
catch (SQLException e)
{
LOGGER.log(Level.SEVERE, "Failed loading auctions.", e);
}
load();
}
@Override
public void load()
{
_managerInstances.clear();
parseDatapackFile("data/ItemAuctions.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _managerInstances.size() + " instance(s).");
}
@Override
public void parseDocument(Document doc, File f)
{
try
{
for (Node na = doc.getFirstChild(); na != null; na = na.getNextSibling())
{
if ("list".equalsIgnoreCase(na.getNodeName()))
{
for (Node nb = na.getFirstChild(); nb != null; nb = nb.getNextSibling())
{
if ("instance".equalsIgnoreCase(nb.getNodeName()))
{
final NamedNodeMap nab = nb.getAttributes();
final int instanceId = Integer.parseInt(nab.getNamedItem("id").getNodeValue());
if (_managerInstances.containsKey(instanceId))
{
throw new Exception("Dublicated instanceId " + instanceId);
}
final ItemAuctionInstance instance = new ItemAuctionInstance(instanceId, _auctionIds, nb);
_managerInstances.put(instanceId, instance);
}
}
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, getClass().getSimpleName() + ": Failed loading auctions from xml.", e);
}
}
public final void shutdown()
{
for (ItemAuctionInstance instance : _managerInstances.values())
{
instance.shutdown();
}
}
public final ItemAuctionInstance getManagerInstance(int instanceId)
{
return _managerInstances.get(instanceId);
}
public final int getNextAuctionId()
{
return _auctionIds.getAndIncrement();
}
public static void deleteAuction(int auctionId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection())
{
try (PreparedStatement statement = con.prepareStatement("DELETE FROM item_auction WHERE auctionId=?"))
{
statement.setInt(1, auctionId);
statement.execute();
}
try (PreparedStatement statement = con.prepareStatement("DELETE FROM item_auction_bid WHERE auctionId=?"))
{
statement.setInt(1, auctionId);
statement.execute();
}
}
catch (SQLException e)
{
LOGGER.log(Level.SEVERE, "L2ItemAuctionManagerInstance: Failed deleting auction: " + auctionId, e);
}
}
/**
* Gets the single instance of {@code ItemAuctionManager}.
* @return single instance of {@code ItemAuctionManager}
*/
public static ItemAuctionManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final ItemAuctionManager _instance = new ItemAuctionManager();
}
}

View File

@ -0,0 +1,261 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.ItemsAutoDestroy;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
/**
* This class manage all items on ground.
* @author Enforcer
*/
public final class ItemsOnGroundManager implements Runnable
{
private static final Logger _log = Logger.getLogger(ItemsOnGroundManager.class.getName());
private final Set<L2ItemInstance> _items = ConcurrentHashMap.newKeySet();
protected ItemsOnGroundManager()
{
if (Config.SAVE_DROPPED_ITEM_INTERVAL > 0)
{
ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(this, Config.SAVE_DROPPED_ITEM_INTERVAL, Config.SAVE_DROPPED_ITEM_INTERVAL);
}
load();
}
private void load()
{
// If SaveDroppedItem is false, may want to delete all items previously stored to avoid add old items on reactivate
if (!Config.SAVE_DROPPED_ITEM && Config.CLEAR_DROPPED_ITEM_TABLE)
{
emptyTable();
}
if (!Config.SAVE_DROPPED_ITEM)
{
return;
}
// if DestroyPlayerDroppedItem was previously false, items currently protected will be added to ItemsAutoDestroy
if (Config.DESTROY_DROPPED_PLAYER_ITEM)
{
String str = null;
if (!Config.DESTROY_EQUIPABLE_PLAYER_ITEM)
{
// Recycle misc. items only
str = "UPDATE itemsonground SET drop_time = ? WHERE drop_time = -1 AND equipable = 0";
}
else if (Config.DESTROY_EQUIPABLE_PLAYER_ITEM)
{
// Recycle all items including equip-able
str = "UPDATE itemsonground SET drop_time = ? WHERE drop_time = -1";
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement(str))
{
ps.setLong(1, System.currentTimeMillis());
ps.execute();
}
catch (Exception e)
{
_log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while updating table ItemsOnGround " + e.getMessage(), e);
}
}
// Add items to world
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT object_id,item_id,count,enchant_level,x,y,z,drop_time,equipable FROM itemsonground"))
{
int count = 0;
try (ResultSet rs = ps.executeQuery())
{
L2ItemInstance item;
while (rs.next())
{
item = new L2ItemInstance(rs.getInt(1), rs.getInt(2));
L2World.getInstance().storeObject(item);
// this check and..
if (item.isStackable() && (rs.getInt(3) > 1))
{
item.setCount(rs.getInt(3));
}
// this, are really necessary?
if (rs.getInt(4) > 0)
{
item.setEnchantLevel(rs.getInt(4));
}
item.setXYZ(rs.getInt(5), rs.getInt(6), rs.getInt(7));
item.setWorldRegion(L2World.getInstance().getRegion(item.getLocation()));
item.getWorldRegion().addVisibleObject(item);
final long dropTime = rs.getLong(8);
item.setDropTime(dropTime);
item.setProtected(dropTime == -1);
item.setSpawned(true);
L2World.getInstance().addVisibleObject(item, item.getWorldRegion());
_items.add(item);
count++;
// add to ItemsAutoDestroy only items not protected
if (!Config.LIST_PROTECTED_ITEMS.contains(item.getId()))
{
if (dropTime > -1)
{
if (((Config.AUTODESTROY_ITEM_AFTER > 0) && !item.getItem().hasExImmediateEffect()) || ((Config.HERB_AUTO_DESTROY_TIME > 0) && item.getItem().hasExImmediateEffect()))
{
ItemsAutoDestroy.getInstance().addItem(item);
}
}
}
}
}
_log.info(getClass().getSimpleName() + ": Loaded " + count + " items.");
}
catch (Exception e)
{
_log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while loading ItemsOnGround " + e.getMessage(), e);
}
if (Config.EMPTY_DROPPED_ITEM_TABLE_AFTER_LOAD)
{
emptyTable();
}
}
public void save(L2ItemInstance item)
{
if (Config.SAVE_DROPPED_ITEM)
{
_items.add(item);
}
}
public void removeObject(L2ItemInstance item)
{
if (Config.SAVE_DROPPED_ITEM)
{
_items.remove(item);
}
}
public void saveInDb()
{
run();
}
public void cleanUp()
{
_items.clear();
}
public void emptyTable()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement s = con.createStatement())
{
s.executeUpdate("DELETE FROM itemsonground");
}
catch (Exception e1)
{
_log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while cleaning table ItemsOnGround " + e1.getMessage(), e1);
}
}
@Override
public synchronized void run()
{
if (!Config.SAVE_DROPPED_ITEM)
{
return;
}
emptyTable();
if (_items.isEmpty())
{
return;
}
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("INSERT INTO itemsonground(object_id,item_id,count,enchant_level,x,y,z,drop_time,equipable) VALUES(?,?,?,?,?,?,?,?,?)"))
{
for (L2ItemInstance item : _items)
{
if (item == null)
{
continue;
}
if (CursedWeaponsManager.getInstance().isCursed(item.getId()))
{
continue; // Cursed Items not saved to ground, prevent double save
}
try
{
statement.setInt(1, item.getObjectId());
statement.setInt(2, item.getId());
statement.setLong(3, item.getCount());
statement.setInt(4, item.getEnchantLevel());
statement.setInt(5, item.getX());
statement.setInt(6, item.getY());
statement.setInt(7, item.getZ());
statement.setLong(8, (item.isProtected() ? -1 : item.getDropTime())); // item is protected or AutoDestroyed
statement.setLong(9, (item.isEquipable() ? 1 : 0)); // set equip-able
statement.execute();
statement.clearParameters();
}
catch (Exception e)
{
_log.log(Level.SEVERE, getClass().getSimpleName() + ": Error while inserting into table ItemsOnGround: " + e.getMessage(), e);
}
}
}
catch (SQLException e)
{
_log.log(Level.SEVERE, getClass().getSimpleName() + ": SQL error while storing items on ground: " + e.getMessage(), e);
}
}
/**
* Gets the single instance of {@code ItemsOnGroundManager}.
* @return single instance of {@code ItemsOnGroundManager}
*/
public static ItemsOnGroundManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final ItemsOnGroundManager _instance = new ItemsOnGroundManager();
}
}

View File

@ -0,0 +1,301 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.MailType;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.tasks.MessageDeletionTask;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Message;
import com.l2jmobius.gameserver.network.serverpackets.ExNoticePostArrived;
import com.l2jmobius.gameserver.network.serverpackets.ExUnReadMailCount;
/**
* @author Migi, DS
*/
public final class MailManager
{
private static final Logger LOGGER = Logger.getLogger(MailManager.class.getName());
private final Map<Integer, Message> _messages = new ConcurrentHashMap<>();
protected MailManager()
{
load();
}
private void load()
{
int count = 0;
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement ps = con.createStatement();
ResultSet rs = ps.executeQuery("SELECT * FROM messages ORDER BY expiration"))
{
while (rs.next())
{
final Message msg = new Message(rs);
final int msgId = msg.getId();
_messages.put(msgId, msg);
count++;
final long expiration = msg.getExpiration();
if (expiration < System.currentTimeMillis())
{
ThreadPoolManager.getInstance().scheduleGeneral(new MessageDeletionTask(msgId), 10000);
}
else
{
ThreadPoolManager.getInstance().scheduleGeneral(new MessageDeletionTask(msgId), expiration - System.currentTimeMillis());
}
}
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error loading from database:", e);
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + count + " messages.");
}
public final Message getMessage(int msgId)
{
return _messages.get(msgId);
}
public final Collection<Message> getMessages()
{
return _messages.values();
}
public final boolean hasUnreadPost(L2PcInstance player)
{
final int objectId = player.getObjectId();
for (Message msg : getMessages())
{
if ((msg != null) && (msg.getReceiverId() == objectId) && msg.isUnread())
{
return true;
}
}
return false;
}
public final int getInboxSize(int objectId)
{
int size = 0;
for (Message msg : getMessages())
{
if ((msg != null) && (msg.getReceiverId() == objectId) && !msg.isDeletedByReceiver())
{
size++;
}
}
return size;
}
public final int getOutboxSize(int objectId)
{
int size = 0;
for (Message msg : getMessages())
{
if ((msg != null) && (msg.getSenderId() == objectId) && !msg.isDeletedBySender())
{
size++;
}
}
return size;
}
public final List<Message> getInbox(int objectId)
{
final List<Message> inbox = new LinkedList<>();
for (Message msg : getMessages())
{
if ((msg != null) && (msg.getReceiverId() == objectId) && !msg.isDeletedByReceiver())
{
inbox.add(msg);
}
}
return inbox;
}
public final long getUnreadCount(L2PcInstance player)
{
return getInbox(player.getObjectId()).stream().filter(Message::isUnread).count();
}
public int getMailsInProgress(int objectId)
{
int count = 0;
for (Message msg : getMessages())
{
if ((msg != null) && (msg.getMailType() == MailType.REGULAR))
{
if ((msg.getReceiverId() == objectId) && !msg.isDeletedByReceiver() && !msg.isReturned() && msg.hasAttachments())
{
count++;
}
else if ((msg.getSenderId() == objectId) && !msg.isDeletedBySender() && !msg.isReturned() && msg.hasAttachments())
{
count++;
}
}
}
return count;
}
public final List<Message> getOutbox(int objectId)
{
final List<Message> outbox = new LinkedList<>();
for (Message msg : getMessages())
{
if ((msg != null) && (msg.getSenderId() == objectId) && !msg.isDeletedBySender())
{
outbox.add(msg);
}
}
return outbox;
}
public void sendMessage(Message msg)
{
_messages.put(msg.getId(), msg);
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = Message.getStatement(msg, con))
{
ps.execute();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error saving message:", e);
}
final L2PcInstance receiver = L2World.getInstance().getPlayer(msg.getReceiverId());
if (receiver != null)
{
receiver.sendPacket(ExNoticePostArrived.valueOf(true));
receiver.sendPacket(new ExUnReadMailCount(receiver));
}
ThreadPoolManager.getInstance().scheduleGeneral(new MessageDeletionTask(msg.getId()), msg.getExpiration() - System.currentTimeMillis());
}
public final void markAsReadInDb(int msgId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE messages SET isUnread = 'false' WHERE messageId = ?"))
{
ps.setInt(1, msgId);
ps.execute();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error marking as read message:", e);
}
}
public final void markAsDeletedBySenderInDb(int msgId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE messages SET isDeletedBySender = 'true' WHERE messageId = ?"))
{
ps.setInt(1, msgId);
ps.execute();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error marking as deleted by sender message:", e);
}
}
public final void markAsDeletedByReceiverInDb(int msgId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE messages SET isDeletedByReceiver = 'true' WHERE messageId = ?"))
{
ps.setInt(1, msgId);
ps.execute();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error marking as deleted by receiver message:", e);
}
}
public final void removeAttachmentsInDb(int msgId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE messages SET hasAttachments = 'false' WHERE messageId = ?"))
{
ps.setInt(1, msgId);
ps.execute();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error removing attachments in message:", e);
}
}
public final void deleteMessageInDb(int msgId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM messages WHERE messageId = ?"))
{
ps.setInt(1, msgId);
ps.execute();
}
catch (SQLException e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error deleting message:", e);
}
_messages.remove(msgId);
IdFactory.getInstance().releaseId(msgId);
}
/**
* Gets the single instance of {@code MailManager}.
* @return single instance of {@code MailManager}
*/
public static MailManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final MailManager _instance = new MailManager();
}
}

View File

@ -0,0 +1,484 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.data.xml.impl.ClanHallData;
import com.l2jmobius.gameserver.model.L2MapRegion;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.TeleportWhereType;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Castle;
import com.l2jmobius.gameserver.model.entity.ClanHall;
import com.l2jmobius.gameserver.model.entity.Fort;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.model.zone.type.L2RespawnZone;
/**
* Map Region Manager.
* @author Nyaran
*/
public final class MapRegionManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(MapRegionManager.class.getName());
private final Map<String, L2MapRegion> _regions = new HashMap<>();
private final String defaultRespawn = "talking_island_town";
protected MapRegionManager()
{
load();
}
@Override
public void load()
{
_regions.clear();
parseDatapackDirectory("data/mapregion", false);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _regions.size() + " map regions.");
}
@Override
public void parseDocument(Document doc, File f)
{
NamedNodeMap attrs;
String name;
String town;
int locId;
int castle;
int bbs;
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("region".equalsIgnoreCase(d.getNodeName()))
{
attrs = d.getAttributes();
name = attrs.getNamedItem("name").getNodeValue();
town = attrs.getNamedItem("town").getNodeValue();
locId = parseInteger(attrs, "locId");
castle = parseInteger(attrs, "castle");
bbs = parseInteger(attrs, "bbs");
final L2MapRegion region = new L2MapRegion(name, town, locId, castle, bbs);
for (Node c = d.getFirstChild(); c != null; c = c.getNextSibling())
{
attrs = c.getAttributes();
if ("respawnPoint".equalsIgnoreCase(c.getNodeName()))
{
final int spawnX = parseInteger(attrs, "X");
final int spawnY = parseInteger(attrs, "Y");
final int spawnZ = parseInteger(attrs, "Z");
final boolean other = parseBoolean(attrs, "isOther", false);
final boolean chaotic = parseBoolean(attrs, "isChaotic", false);
final boolean banish = parseBoolean(attrs, "isBanish", false);
if (other)
{
region.addOtherSpawn(spawnX, spawnY, spawnZ);
}
else if (chaotic)
{
region.addChaoticSpawn(spawnX, spawnY, spawnZ);
}
else if (banish)
{
region.addBanishSpawn(spawnX, spawnY, spawnZ);
}
else
{
region.addSpawn(spawnX, spawnY, spawnZ);
}
}
else if ("map".equalsIgnoreCase(c.getNodeName()))
{
region.addMap(parseInteger(attrs, "X"), parseInteger(attrs, "Y"));
}
else if ("banned".equalsIgnoreCase(c.getNodeName()))
{
region.addBannedRace(attrs.getNamedItem("race").getNodeValue(), attrs.getNamedItem("point").getNodeValue());
}
}
_regions.put(name, region);
}
}
}
}
}
/**
* @param locX
* @param locY
* @return
*/
public final L2MapRegion getMapRegion(int locX, int locY)
{
for (L2MapRegion region : _regions.values())
{
if (region.isZoneInRegion(getMapRegionX(locX), getMapRegionY(locY)))
{
return region;
}
}
return null;
}
/**
* @param locX
* @param locY
* @return
*/
public final int getMapRegionLocId(int locX, int locY)
{
final L2MapRegion region = getMapRegion(locX, locY);
if (region != null)
{
return region.getLocId();
}
return 0;
}
/**
* @param obj
* @return
*/
public final L2MapRegion getMapRegion(L2Object obj)
{
return getMapRegion(obj.getX(), obj.getY());
}
/**
* @param obj
* @return
*/
public final int getMapRegionLocId(L2Object obj)
{
return getMapRegionLocId(obj.getX(), obj.getY());
}
/**
* @param posX
* @return
*/
public final int getMapRegionX(int posX)
{
return (posX >> 15) + 9 + 11; // + centerTileX;
}
/**
* @param posY
* @return
*/
public final int getMapRegionY(int posY)
{
return (posY >> 15) + 10 + 8; // + centerTileX;
}
/**
* Get town name by character position
* @param activeChar
* @return
*/
public String getClosestTownName(L2Character activeChar)
{
final L2MapRegion region = getMapRegion(activeChar);
if (region == null)
{
return "Aden Castle Town";
}
return region.getTown();
}
/**
* @param activeChar
* @return
*/
public int getAreaCastle(L2Character activeChar)
{
final L2MapRegion region = getMapRegion(activeChar);
if (region == null)
{
return 0;
}
return region.getCastle();
}
/**
* @param activeChar
* @param teleportWhere
* @return
*/
public Location getTeleToLocation(L2Character activeChar, TeleportWhereType teleportWhere)
{
if (activeChar.isPlayer())
{
final L2PcInstance player = activeChar.getActingPlayer();
Castle castle = null;
Fort fort = null;
ClanHall clanhall = null;
if ((player.getClan() != null) && !player.isFlyingMounted() && !player.isFlying()) // flying players in gracia cant use teleports to aden continent
{
// If teleport to clan hall
if (teleportWhere == TeleportWhereType.CLANHALL)
{
clanhall = ClanHallData.getInstance().getClanHallByClan(player.getClan());
if ((clanhall != null) && !player.isFlyingMounted())
{
return clanhall.getOwnerLocation();
}
}
// If teleport to castle
if (teleportWhere == TeleportWhereType.CASTLE)
{
castle = CastleManager.getInstance().getCastleByOwner(player.getClan());
// Otherwise check if player is on castle or fortress ground
// and player's clan is defender
if (castle == null)
{
castle = CastleManager.getInstance().getCastle(player);
if (!((castle != null) && castle.getSiege().isInProgress() && (castle.getSiege().getDefenderClan(player.getClan()) != null)))
{
castle = null;
}
}
if ((castle != null) && (castle.getResidenceId() > 0))
{
if (player.getReputation() < 0)
{
return castle.getResidenceZone().getChaoticSpawnLoc();
}
return castle.getResidenceZone().getSpawnLoc();
}
}
// If teleport to fortress
if (teleportWhere == TeleportWhereType.FORTRESS)
{
fort = FortManager.getInstance().getFortByOwner(player.getClan());
// Otherwise check if player is on castle or fortress ground
// and player's clan is defender
if (fort == null)
{
fort = FortManager.getInstance().getFort(player);
if (!((fort != null) && fort.getSiege().isInProgress() && (fort.getOwnerClan() == player.getClan())))
{
fort = null;
}
}
if ((fort != null) && (fort.getResidenceId() > 0))
{
if (player.getReputation() < 0)
{
return fort.getResidenceZone().getChaoticSpawnLoc();
}
return fort.getResidenceZone().getSpawnLoc();
}
}
// If teleport to SiegeHQ
if (teleportWhere == TeleportWhereType.SIEGEFLAG)
{
castle = CastleManager.getInstance().getCastle(player);
fort = FortManager.getInstance().getFort(player);
if (castle != null)
{
if (castle.getSiege().isInProgress())
{
// Check if player's clan is attacker
final Set<L2Npc> flags = castle.getSiege().getFlag(player.getClan());
if ((flags != null) && !flags.isEmpty())
{
// Spawn to flag - Need more work to get player to the nearest flag
return flags.stream().findAny().get().getLocation();
}
}
}
else if (fort != null)
{
if (fort.getSiege().isInProgress())
{
// Check if player's clan is attacker
final Set<L2Npc> flags = fort.getSiege().getFlag(player.getClan());
if ((flags != null) && !flags.isEmpty())
{
// Spawn to flag - Need more work to get player to the nearest flag
return flags.stream().findAny().get().getLocation();
}
}
}
}
}
// Karma player land out of city
if (player.getReputation() < 0)
{
try
{
final L2RespawnZone zone = ZoneManager.getInstance().getZone(player, L2RespawnZone.class);
if (zone != null)
{
return getRestartRegion(activeChar, zone.getRespawnPoint((L2PcInstance) activeChar)).getChaoticSpawnLoc();
}
return getMapRegion(activeChar).getChaoticSpawnLoc();
}
catch (Exception e)
{
if (player.isFlyingMounted())
{
return _regions.get("union_base_of_kserth").getChaoticSpawnLoc();
}
return _regions.get(defaultRespawn).getChaoticSpawnLoc();
}
}
// Checking if needed to be respawned in "far" town from the castle;
castle = CastleManager.getInstance().getCastle(player);
if (castle != null)
{
if (castle.getSiege().isInProgress())
{
// Check if player's clan is participating
if ((castle.getSiege().checkIsDefender(player.getClan()) || castle.getSiege().checkIsAttacker(player.getClan())))
{
return castle.getResidenceZone().getOtherSpawnLoc();
}
}
}
// Checking if in an instance
final Instance inst = player.getInstanceWorld();
if (inst != null)
{
final Location loc = inst.getExitLocation(player);
if (loc != null)
{
return loc;
}
}
}
if (Config.FACTION_SYSTEM_ENABLED && Config.FACTION_RESPAWN_AT_BASE)
{
if (activeChar.getActingPlayer().isGood())
{
return Config.FACTION_GOOD_BASE_LOCATION;
}
if (activeChar.getActingPlayer().isEvil())
{
return Config.FACTION_EVIL_BASE_LOCATION;
}
}
// Get the nearest town
try
{
final L2RespawnZone zone = ZoneManager.getInstance().getZone(activeChar, L2RespawnZone.class);
if (zone != null)
{
return getRestartRegion(activeChar, zone.getRespawnPoint((L2PcInstance) activeChar)).getSpawnLoc();
}
return getMapRegion(activeChar).getSpawnLoc();
}
catch (Exception e)
{
// Port to the default respawn if no closest town found.
return _regions.get(defaultRespawn).getSpawnLoc();
}
}
/**
* @param activeChar
* @param point
* @return
*/
public L2MapRegion getRestartRegion(L2Character activeChar, String point)
{
try
{
final L2PcInstance player = ((L2PcInstance) activeChar);
final L2MapRegion region = _regions.get(point);
if (region.getBannedRace().containsKey(player.getRace()))
{
getRestartRegion(player, region.getBannedRace().get(player.getRace()));
}
return region;
}
catch (Exception e)
{
return _regions.get(defaultRespawn);
}
}
/**
* @param regionName the map region name.
* @return if exists the map region identified by that name, null otherwise.
*/
public L2MapRegion getMapRegionByName(String regionName)
{
return _regions.get(regionName);
}
public int getBBs(ILocational loc)
{
final L2MapRegion region = getMapRegion(loc.getX(), loc.getY());
return region != null ? region.getBbs() : _regions.get(defaultRespawn).getBbs();
}
/**
* Gets the single instance of {@code MapRegionManager}.
* @return single instance of {@code MapRegionManager}
*/
public static MapRegionManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final MapRegionManager _instance = new MapRegionManager();
}
}

View File

@ -0,0 +1,145 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import com.l2jmobius.gameserver.enums.MatchingRoomType;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.model.matching.MatchingRoom;
/**
* @author Sdw
*/
public class MatchingRoomManager
{
private volatile Set<L2PcInstance> _waitingList;
private static final Map<MatchingRoomType, Map<Integer, MatchingRoom>> _rooms = new ConcurrentHashMap<>(2);
private final AtomicInteger _id = new AtomicInteger(0);
public void addToWaitingList(L2PcInstance player)
{
if (_waitingList == null)
{
synchronized (this)
{
if (_waitingList == null)
{
_waitingList = ConcurrentHashMap.newKeySet(1);
}
}
}
_waitingList.add(player);
}
public void removeFromWaitingList(L2PcInstance player)
{
getPlayerInWaitingList().remove(player);
}
public Set<L2PcInstance> getPlayerInWaitingList()
{
return _waitingList == null ? Collections.emptySet() : _waitingList;
}
public List<L2PcInstance> getPlayerInWaitingList(int minLevel, int maxLevel, List<ClassId> classIds, String query)
{
return _waitingList == null ? Collections.emptyList() : _waitingList.stream().filter(p -> (p.getLevel() >= minLevel) && (p.getLevel() <= maxLevel)).filter(p -> (classIds == null) || classIds.contains(p.getClassId())).filter(p -> query.isEmpty() || p.getName().toLowerCase().contains(query)).collect(Collectors.toList());
}
public int addMatchingRoom(MatchingRoom room)
{
final int roomId = _id.incrementAndGet();
_rooms.computeIfAbsent(room.getRoomType(), k -> new ConcurrentHashMap<>()).put(roomId, room);
return roomId;
}
public void removeMatchingRoom(MatchingRoom room)
{
_rooms.getOrDefault(room.getRoomType(), Collections.emptyMap()).remove(room.getId());
}
public Map<Integer, MatchingRoom> getPartyMathchingRooms()
{
return _rooms.get(MatchingRoomType.PARTY);
}
public List<MatchingRoom> getPartyMathchingRooms(int location, int level)
{
//@formatter:off
return _rooms.getOrDefault(MatchingRoomType.PARTY, Collections.emptyMap()).values().stream()
.filter(r -> (location < 0) || (r.getLocation() == location))
.filter(r -> (r.getMinLvl() <= level) && (r.getMaxLvl() >= level))
.collect(Collectors.toList());
//@formatter:on
}
public Map<Integer, MatchingRoom> getCCMathchingRooms()
{
return _rooms.get(MatchingRoomType.COMMAND_CHANNEL);
}
public List<MatchingRoom> getCCMathchingRooms(int location, int level)
{
//@formatter:off
return _rooms.getOrDefault(MatchingRoomType.COMMAND_CHANNEL, Collections.emptyMap()).values().stream()
.filter(r -> r.getLocation() == location)
.filter(r -> (r.getMinLvl() <= level) && (r.getMaxLvl() >= level))
.collect(Collectors.toList());
//@formatter:on
}
public MatchingRoom getCCMatchingRoom(int roomId)
{
return _rooms.getOrDefault(MatchingRoomType.COMMAND_CHANNEL, Collections.emptyMap()).get(roomId);
}
public MatchingRoom getPartyMathchingRoom(int location, int level)
{
//@formatter:off
return _rooms.getOrDefault(MatchingRoomType.PARTY, Collections.emptyMap()).values().stream()
.filter(r -> r.getLocation() == location)
.filter(r -> (r.getMinLvl() <= level) && (r.getMaxLvl() >= level))
.findFirst()
.orElse(null);
//@formatter:on
}
public MatchingRoom getPartyMathchingRoom(int roomId)
{
return _rooms.getOrDefault(MatchingRoomType.PARTY, Collections.emptyMap()).get(roomId);
}
public static MatchingRoomManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final MatchingRoomManager _instance = new MatchingRoomManager();
}
}

View File

@ -0,0 +1,268 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.L2Mentee;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.BuffInfo;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.variables.PlayerVariables;
/**
* @author UnAfraid
*/
public class MentorManager
{
private static final Logger _log = Logger.getLogger(MentorManager.class.getName());
private final Map<Integer, Map<Integer, L2Mentee>> _menteeData = new ConcurrentHashMap<>();
private final Map<Integer, L2Mentee> _mentors = new ConcurrentHashMap<>();
protected MentorManager()
{
load();
}
private void load()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement statement = con.createStatement();
ResultSet rset = statement.executeQuery("SELECT * FROM character_mentees"))
{
while (rset.next())
{
addMentor(rset.getInt("mentorId"), rset.getInt("charId"));
}
}
catch (Exception e)
{
_log.log(Level.WARNING, e.getMessage(), e);
}
}
/**
* Removes mentee for current L2PcInstance
* @param mentorId
* @param menteeId
*/
public void deleteMentee(int mentorId, int menteeId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM character_mentees WHERE mentorId = ? AND charId = ?"))
{
statement.setInt(1, mentorId);
statement.setInt(2, menteeId);
statement.execute();
}
catch (Exception e)
{
_log.log(Level.WARNING, e.getMessage(), e);
}
}
/**
* @param mentorId
* @param menteeId
*/
public void deleteMentor(int mentorId, int menteeId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("DELETE FROM character_mentees WHERE mentorId = ? AND charId = ?"))
{
statement.setInt(1, mentorId);
statement.setInt(2, menteeId);
statement.execute();
}
catch (Exception e)
{
_log.log(Level.WARNING, e.getMessage(), e);
}
finally
{
removeMentor(mentorId, menteeId);
}
}
public boolean isMentor(int objectId)
{
return _menteeData.containsKey(objectId);
}
public boolean isMentee(int objectId)
{
return _menteeData.values().stream().anyMatch(map -> map.containsKey(objectId));
}
public Map<Integer, Map<Integer, L2Mentee>> getMentorData()
{
return _menteeData;
}
public void cancelAllMentoringBuffs(L2PcInstance player)
{
if (player == null)
{
return;
}
//@formatter:off
player.getEffectList().getEffects()
.stream()
.map(BuffInfo::getSkill)
.filter(Skill::isMentoring)
.forEach(player::stopSkillEffects);
//@formatter:on
}
public void setPenalty(int mentorId, long penalty)
{
final L2PcInstance player = L2World.getInstance().getPlayer(mentorId);
final PlayerVariables vars = player != null ? player.getVariables() : new PlayerVariables(mentorId);
vars.set("Mentor-Penalty-" + mentorId, String.valueOf(System.currentTimeMillis() + penalty));
}
public long getMentorPenalty(int mentorId)
{
final L2PcInstance player = L2World.getInstance().getPlayer(mentorId);
final PlayerVariables vars = player != null ? player.getVariables() : new PlayerVariables(mentorId);
return vars.getLong("Mentor-Penalty-" + mentorId, 0);
}
/**
* @param mentorId
* @param menteeId
*/
public void addMentor(int mentorId, int menteeId)
{
final Map<Integer, L2Mentee> mentees = _menteeData.computeIfAbsent(mentorId, map -> new ConcurrentHashMap<>());
if (mentees.containsKey(menteeId))
{
mentees.get(menteeId).load(); // Just reloading data if is already there
}
else
{
mentees.put(menteeId, new L2Mentee(menteeId));
}
}
/**
* @param mentorId
* @param menteeId
*/
public void removeMentor(int mentorId, int menteeId)
{
if (_menteeData.containsKey(mentorId))
{
_menteeData.get(mentorId).remove(menteeId);
if (_menteeData.get(mentorId).isEmpty())
{
_menteeData.remove(mentorId);
_mentors.remove(mentorId);
}
}
}
/**
* @param menteeId
* @return
*/
public L2Mentee getMentor(int menteeId)
{
for (Entry<Integer, Map<Integer, L2Mentee>> map : _menteeData.entrySet())
{
if (map.getValue().containsKey(menteeId))
{
if (!_mentors.containsKey(map.getKey()))
{
_mentors.put(map.getKey(), new L2Mentee(map.getKey()));
}
return _mentors.get(map.getKey());
}
}
return null;
}
public Collection<L2Mentee> getMentees(int mentorId)
{
if (_menteeData.containsKey(mentorId))
{
return _menteeData.get(mentorId).values();
}
return Collections.emptyList();
}
/**
* @param mentorId
* @param menteeId
* @return
*/
public L2Mentee getMentee(int mentorId, int menteeId)
{
if (_menteeData.containsKey(mentorId))
{
return _menteeData.get(mentorId).get(menteeId);
}
return null;
}
public boolean isAllMenteesOffline(int menteorId, int menteeId)
{
boolean isAllMenteesOffline = true;
for (L2Mentee men : getMentees(menteorId))
{
if (men.isOnline() && (men.getObjectId() != menteeId))
{
if (isAllMenteesOffline)
{
isAllMenteesOffline = false;
break;
}
}
}
return isAllMenteesOffline;
}
public boolean hasOnlineMentees(int menteorId)
{
return getMentees(menteorId).stream().filter(Objects::nonNull).filter(L2Mentee::isOnline).count() > 0;
}
public static MentorManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final MentorManager _instance = new MentorManager();
}
}

View File

@ -0,0 +1,99 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExPCCafePointInfo;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class PcCafePointsManager
{
public void givePcCafePoint(L2PcInstance player, long exp)
{
if (!Config.PC_CAFE_ENABLED || player.isInsideZone(ZoneId.PEACE) || player.isInsideZone(ZoneId.PVP) || player.isInsideZone(ZoneId.SIEGE) || (player.isOnlineInt() == 0) || player.isJailed())
{
return;
}
// PC-points only premium accounts
if (Config.PC_CAFE_ONLY_PREMIUM && !player.hasPremiumStatus())
{
return;
}
if (player.getPcCafePoints() >= Config.PC_CAFE_MAX_POINTS)
{
final SystemMessage message = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_EARNED_THE_MAXIMUM_NUMBER_OF_PC_POINTS);
player.sendPacket(message);
return;
}
int points = (int) (exp * 0.0001 * Config.PC_CAFE_POINT_RATE);
if (Config.PC_CAFE_RANDOM_POINT)
{
points = Rnd.get(points / 2, points);
}
if ((points == 0) && (exp > 0) && Config.PC_CAFE_REWARD_LOW_EXP_KILLS && (Rnd.get(100) < Config.PC_CAFE_LOW_EXP_KILLS_CHANCE))
{
points = 1; // minimum points
}
if (points <= 0)
{
return;
}
SystemMessage message = null;
if (Config.PC_CAFE_ENABLE_DOUBLE_POINTS && (Rnd.get(100) < Config.PC_CAFE_DOUBLE_POINTS_CHANCE))
{
points *= 2;
message = SystemMessage.getSystemMessage(SystemMessageId.DOUBLE_POINTS_YOU_EARNED_S1_PC_POINT_S);
}
else
{
message = SystemMessage.getSystemMessage(SystemMessageId.YOU_EARNED_S1_PC_POINT_S);
}
if ((player.getPcCafePoints() + points) > Config.PC_CAFE_MAX_POINTS)
{
points = Config.PC_CAFE_MAX_POINTS - player.getPcCafePoints();
}
message.addLong(points);
player.sendPacket(message);
player.setPcCafePoints(player.getPcCafePoints() + points);
player.sendPacket(new ExPCCafePointInfo(player.getPcCafePoints(), points, 1));
}
/**
* Gets the single instance of {@code PcCafePointsManager}.
* @return single instance of {@code PcCafePointsManager}
*/
public static PcCafePointsManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final PcCafePointsManager _instance = new PcCafePointsManager();
}
}

View File

@ -0,0 +1,471 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.enums.PetitionState;
import com.l2jmobius.gameserver.model.Petition;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* Petition Manager
* @author Tempy
*/
public final class PetitionManager
{
protected static final Logger _log = Logger.getLogger(PetitionManager.class.getName());
private final Map<Integer, Petition> _pendingPetitions;
private final Map<Integer, Petition> _completedPetitions;
protected PetitionManager()
{
_pendingPetitions = new HashMap<>();
_completedPetitions = new HashMap<>();
}
public void clearCompletedPetitions()
{
final int numPetitions = getPendingPetitionCount();
getCompletedPetitions().clear();
_log.info(getClass().getSimpleName() + ": Completed petition data cleared. " + numPetitions + " petition(s) removed.");
}
public void clearPendingPetitions()
{
final int numPetitions = getPendingPetitionCount();
getPendingPetitions().clear();
_log.info(getClass().getSimpleName() + ": Pending petition queue cleared. " + numPetitions + " petition(s) removed.");
}
public boolean acceptPetition(L2PcInstance respondingAdmin, int petitionId)
{
if (!isValidPetition(petitionId))
{
return false;
}
final Petition currPetition = getPendingPetitions().get(petitionId);
if (currPetition.getResponder() != null)
{
return false;
}
currPetition.setResponder(respondingAdmin);
currPetition.setState(PetitionState.IN_PROCESS);
// Petition application accepted. (Send to Petitioner)
currPetition.sendPetitionerPacket(SystemMessage.getSystemMessage(SystemMessageId.PETITION_APPLICATION_ACCEPTED));
// Petition application accepted. Reciept No. is <ID>
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOUR_PETITION_APPLICATION_HAS_BEEN_ACCEPTED_NRECEIPT_NO_IS_S1);
sm.addInt(currPetition.getId());
currPetition.sendResponderPacket(sm);
// Petition consultation with <Player> underway.
sm = SystemMessage.getSystemMessage(SystemMessageId.STARTING_PETITION_CONSULTATION_WITH_C1);
sm.addString(currPetition.getPetitioner().getName());
currPetition.sendResponderPacket(sm);
// Set responder name on petitioner instance
currPetition.getPetitioner().setLastPetitionGmName(currPetition.getResponder().getName());
return true;
}
public boolean cancelActivePetition(L2PcInstance player)
{
for (Petition currPetition : getPendingPetitions().values())
{
if ((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == player.getObjectId()))
{
return (currPetition.endPetitionConsultation(PetitionState.PETITIONER_CANCEL));
}
if ((currPetition.getResponder() != null) && (currPetition.getResponder().getObjectId() == player.getObjectId()))
{
return (currPetition.endPetitionConsultation(PetitionState.RESPONDER_CANCEL));
}
}
return false;
}
public void checkPetitionMessages(L2PcInstance petitioner)
{
if (petitioner != null)
{
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if ((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == petitioner.getObjectId()))
{
for (CreatureSay logMessage : currPetition.getLogMessages())
{
petitioner.sendPacket(logMessage);
}
return;
}
}
}
}
public boolean endActivePetition(L2PcInstance player)
{
if (!player.isGM())
{
return false;
}
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if ((currPetition.getResponder() != null) && (currPetition.getResponder().getObjectId() == player.getObjectId()))
{
return (currPetition.endPetitionConsultation(PetitionState.COMPLETED));
}
}
return false;
}
public Map<Integer, Petition> getCompletedPetitions()
{
return _completedPetitions;
}
public Map<Integer, Petition> getPendingPetitions()
{
return _pendingPetitions;
}
public int getPendingPetitionCount()
{
return getPendingPetitions().size();
}
public int getPlayerTotalPetitionCount(L2PcInstance player)
{
if (player == null)
{
return 0;
}
int petitionCount = 0;
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if ((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == player.getObjectId()))
{
petitionCount++;
}
}
for (Petition currPetition : getCompletedPetitions().values())
{
if (currPetition == null)
{
continue;
}
if ((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == player.getObjectId()))
{
petitionCount++;
}
}
return petitionCount;
}
public boolean isPetitionInProcess()
{
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if (currPetition.getState() == PetitionState.IN_PROCESS)
{
return true;
}
}
return false;
}
public boolean isPetitionInProcess(int petitionId)
{
if (!isValidPetition(petitionId))
{
return false;
}
final Petition currPetition = getPendingPetitions().get(petitionId);
return (currPetition.getState() == PetitionState.IN_PROCESS);
}
public boolean isPlayerInConsultation(L2PcInstance player)
{
if (player != null)
{
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if (currPetition.getState() != PetitionState.IN_PROCESS)
{
continue;
}
if (((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == player.getObjectId())) || ((currPetition.getResponder() != null) && (currPetition.getResponder().getObjectId() == player.getObjectId())))
{
return true;
}
}
}
return false;
}
public boolean isPetitioningAllowed()
{
return Config.PETITIONING_ALLOWED;
}
public boolean isPlayerPetitionPending(L2PcInstance petitioner)
{
if (petitioner != null)
{
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if ((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == petitioner.getObjectId()))
{
return true;
}
}
}
return false;
}
private boolean isValidPetition(int petitionId)
{
return getPendingPetitions().containsKey(petitionId);
}
public boolean rejectPetition(L2PcInstance respondingAdmin, int petitionId)
{
if (!isValidPetition(petitionId))
{
return false;
}
final Petition currPetition = getPendingPetitions().get(petitionId);
if (currPetition.getResponder() != null)
{
return false;
}
currPetition.setResponder(respondingAdmin);
return (currPetition.endPetitionConsultation(PetitionState.RESPONDER_REJECT));
}
public boolean sendActivePetitionMessage(L2PcInstance player, String messageText)
{
// if (!isPlayerInConsultation(player))
// return false;
CreatureSay cs;
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
if ((currPetition.getPetitioner() != null) && (currPetition.getPetitioner().getObjectId() == player.getObjectId()))
{
cs = new CreatureSay(player.getObjectId(), ChatType.PETITION_PLAYER, player.getName(), messageText);
currPetition.addLogMessage(cs);
currPetition.sendResponderPacket(cs);
currPetition.sendPetitionerPacket(cs);
return true;
}
if ((currPetition.getResponder() != null) && (currPetition.getResponder().getObjectId() == player.getObjectId()))
{
cs = new CreatureSay(player.getObjectId(), ChatType.PETITION_GM, player.getName(), messageText);
currPetition.addLogMessage(cs);
currPetition.sendResponderPacket(cs);
currPetition.sendPetitionerPacket(cs);
return true;
}
}
return false;
}
public void sendPendingPetitionList(L2PcInstance activeChar)
{
final StringBuilder htmlContent = new StringBuilder(600 + (getPendingPetitionCount() * 300));
htmlContent.append("<html><body><center><table width=270><tr><td width=45><button value=\"Main\" action=\"bypass -h admin_admin\" width=45 height=21 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td><td width=180><center>Petition Menu</center></td><td width=45><button value=\"Back\" action=\"bypass -h admin_admin7\" width=45 height=21 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr></table><br><table width=\"270\"><tr><td><table width=\"270\"><tr><td><button value=\"Reset\" action=\"bypass -h admin_reset_petitions\" width=\"80\" height=\"21\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td><td align=right><button value=\"Refresh\" action=\"bypass -h admin_view_petitions\" width=\"80\" height=\"21\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr></table><br></td></tr>");
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
if (getPendingPetitionCount() == 0)
{
htmlContent.append("<tr><td>There are no currently pending petitions.</td></tr>");
}
else
{
htmlContent.append("<tr><td><font color=\"LEVEL\">Current Petitions:</font><br></td></tr>");
}
boolean color = true;
int petcount = 0;
for (Petition currPetition : getPendingPetitions().values())
{
if (currPetition == null)
{
continue;
}
htmlContent.append("<tr><td width=\"270\"><table width=\"270\" cellpadding=\"2\" bgcolor=" + (color ? "131210" : "444444") + "><tr><td width=\"130\">" + dateFormat.format(new Date(currPetition.getSubmitTime())));
htmlContent.append("</td><td width=\"140\" align=right><font color=\"" + (currPetition.getPetitioner().isOnline() ? "00FF00" : "999999") + "\">" + currPetition.getPetitioner().getName() + "</font></td></tr>");
htmlContent.append("<tr><td width=\"130\">");
if (currPetition.getState() != PetitionState.IN_PROCESS)
{
htmlContent.append("<table width=\"130\" cellpadding=\"2\"><tr><td><button value=\"View\" action=\"bypass -h admin_view_petition " + currPetition.getId() + "\" width=\"50\" height=\"21\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td><td><button value=\"Reject\" action=\"bypass -h admin_reject_petition " + currPetition.getId() + "\" width=\"50\" height=\"21\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td></tr></table>");
}
else
{
htmlContent.append("<font color=\"" + (currPetition.getResponder().isOnline() ? "00FF00" : "999999") + "\">" + currPetition.getResponder().getName() + "</font>");
}
htmlContent.append("</td>" + currPetition.getTypeAsString() + "<td width=\"140\" align=right>" + currPetition.getTypeAsString() + "</td></tr></table></td></tr>");
color = !color;
petcount++;
if (petcount > 10)
{
htmlContent.append("<tr><td><font color=\"LEVEL\">There is more pending petition...</font><br></td></tr>");
break;
}
}
htmlContent.append("</table></center></body></html>");
final NpcHtmlMessage htmlMsg = new NpcHtmlMessage();
htmlMsg.setHtml(htmlContent.toString());
activeChar.sendPacket(htmlMsg);
}
public int submitPetition(L2PcInstance petitioner, String petitionText, int petitionType)
{
// Create a new petition instance and add it to the list of pending petitions.
final Petition newPetition = new Petition(petitioner, petitionText, petitionType);
final int newPetitionId = newPetition.getId();
getPendingPetitions().put(newPetitionId, newPetition);
// Notify all GMs that a new petition has been submitted.
final String msgContent = petitioner.getName() + " has submitted a new petition."; // (ID: " + newPetitionId + ").";
AdminData.getInstance().broadcastToGMs(new CreatureSay(petitioner.getObjectId(), ChatType.HERO_VOICE, "Petition System", msgContent));
return newPetitionId;
}
public void viewPetition(L2PcInstance activeChar, int petitionId)
{
if (!activeChar.isGM())
{
return;
}
if (!isValidPetition(petitionId))
{
return;
}
final Petition currPetition = getPendingPetitions().get(petitionId);
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
final NpcHtmlMessage html = new NpcHtmlMessage();
html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/petition.htm");
html.replace("%petition%", String.valueOf(currPetition.getId()));
html.replace("%time%", dateFormat.format(new Date(currPetition.getSubmitTime())));
html.replace("%type%", currPetition.getTypeAsString());
html.replace("%petitioner%", currPetition.getPetitioner().getName());
html.replace("%online%", (currPetition.getPetitioner().isOnline() ? "00FF00" : "999999"));
html.replace("%text%", currPetition.getContent());
activeChar.sendPacket(html);
}
/**
* Gets the single instance of {@code PetitionManager}.
* @return single instance of {@code PetitionManager}
*/
public static PetitionManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final PetitionManager _instance = new PetitionManager();
}
}

View File

@ -0,0 +1,233 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.Containers;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.ListenersContainer;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogin;
import com.l2jmobius.gameserver.model.events.impl.character.player.OnPlayerLogout;
import com.l2jmobius.gameserver.model.events.listeners.ConsumerEventListener;
import com.l2jmobius.gameserver.network.serverpackets.ExBrPremiumState;
/**
* @author Mobius
*/
public class PremiumManager
{
private final static Logger LOGGER = Logger.getLogger(PremiumManager.class.getName());
// SQL Statement
private final static String LOAD_SQL = "SELECT account_name,enddate FROM account_premium";
private final static String UPDATE_SQL = "UPDATE account_premium SET enddate = ? WHERE account_name = ?";
private final static String ADD_SQL = "INSERT INTO account_premium (enddate,account_name) VALUE (?,?)";
class PremiumExpireTask implements Runnable
{
final L2PcInstance player;
PremiumExpireTask(L2PcInstance player)
{
this.player = player;
}
@Override
public void run()
{
player.setPremiumStatus(false);
player.sendPacket(new ExBrPremiumState(player));
}
}
// Data Cache
private final Map<String, Long> premiumData = new HashMap<>();
// expireTasks
private final Map<String, ScheduledFuture<?>> expiretasks = new HashMap<>();
// Listeners
private final ListenersContainer listenerContainer = Containers.Players();
private final Consumer<OnPlayerLogin> playerLoginEvent = (event) ->
{
final L2PcInstance player = event.getActiveChar();
final String accountName = player.getAccountName();
final long now = System.currentTimeMillis();
final long premiumExpiration = getPremiumExpiration(accountName);
player.setPremiumStatus(premiumExpiration > now);
player.sendPacket(new ExBrPremiumState(player));
if (player.hasPremiumStatus())
{
startExpireTask(player, premiumExpiration - now);
}
};
private final Consumer<OnPlayerLogout> playerLogoutEvent = (event) ->
{
L2PcInstance player = event.getActiveChar();
stopExpireTask(player);
};
protected PremiumManager()
{
loadPremiumData();
listenerContainer.addListener(new ConsumerEventListener(listenerContainer, EventType.ON_PLAYER_LOGIN, playerLoginEvent, this));
listenerContainer.addListener(new ConsumerEventListener(listenerContainer, EventType.ON_PLAYER_LOGOUT, playerLogoutEvent, this));
}
/**
* @param player
* @param delay
*/
private void startExpireTask(L2PcInstance player, long delay)
{
ScheduledFuture<?> task = ThreadPoolManager.getInstance().scheduleEvent(new PremiumExpireTask(player), delay);
expiretasks.put(player.getAccountName(), task);
}
/**
* @param player
*/
private void stopExpireTask(L2PcInstance player)
{
ScheduledFuture<?> task = expiretasks.remove(player.getAccountName());
if (task != null)
{
task.cancel(false);
task = null;
}
}
private void loadPremiumData()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement(LOAD_SQL);
ResultSet rset = statement.executeQuery())
{
while (rset.next())
{
premiumData.put(rset.getString(1), rset.getLong(2));
}
}
catch (SQLException e)
{
e.printStackTrace();
}
long expiredData = premiumData.values().stream().filter(d -> d < System.currentTimeMillis()).count();
LOGGER.info(getClass().getSimpleName() + ": Loaded " + premiumData.size() + " premium data (" + expiredData + " have expired)");
}
public long getPremiumExpiration(String accountName)
{
return premiumData.getOrDefault(accountName, 0L);
}
public void addPremiumTime(String accountName, int timeValue, TimeUnit timeUnit)
{
long addTime = timeUnit.toMillis(timeValue);
long now = System.currentTimeMillis();
// new premium task at least from now
long oldPremiumExpiration = Math.max(now, getPremiumExpiration(accountName));
long newPremiumExpiration = oldPremiumExpiration + addTime;
String sqlCmd = premiumData.containsKey(accountName) ? UPDATE_SQL : ADD_SQL;
// UPDATE DATABASE
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement stmt = con.prepareStatement(sqlCmd))
{
stmt.setLong(1, newPremiumExpiration);
stmt.setString(2, accountName);
stmt.execute();
}
catch (SQLException e)
{
e.printStackTrace();
}
// UPDATE CACHE
premiumData.put(accountName, newPremiumExpiration);
// UPDATE PlAYER PREMIUMSTATUS
L2PcInstance playerOnline = L2World.getInstance().getPlayers().stream().filter(p -> accountName.equals(p.getAccountName())).findFirst().orElse(null);
if (playerOnline != null)
{
stopExpireTask(playerOnline);
startExpireTask(playerOnline, newPremiumExpiration - now);
if (!playerOnline.hasPremiumStatus())
{
playerOnline.setPremiumStatus(true);
playerOnline.sendPacket(new ExBrPremiumState(playerOnline));
}
}
}
public void removePremiumStatus(String accountName)
{
L2PcInstance playerOnline = L2World.getInstance().getPlayers().stream().filter(p -> accountName.equals(p.getAccountName())).findFirst().orElse(null);
if ((playerOnline != null) && playerOnline.hasPremiumStatus())
{
playerOnline.setPremiumStatus(false);
playerOnline.sendPacket(new ExBrPremiumState(playerOnline));
stopExpireTask(playerOnline);
}
// UPDATE CACHE
premiumData.remove(accountName);
// UPDATE DATABASE
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement stmt = con.prepareStatement(UPDATE_SQL))
{
stmt.setLong(1, 0L);
stmt.setString(2, accountName);
stmt.execute();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public static PremiumManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final PremiumManager _instance = new PremiumManager();
}
}

View File

@ -0,0 +1,147 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.model.holders.PunishmentHolder;
import com.l2jmobius.gameserver.model.punishment.PunishmentAffect;
import com.l2jmobius.gameserver.model.punishment.PunishmentTask;
import com.l2jmobius.gameserver.model.punishment.PunishmentType;
/**
* @author UnAfraid
*/
public final class PunishmentManager
{
private static final Logger LOGGER = Logger.getLogger(PunishmentManager.class.getName());
private final Map<PunishmentAffect, PunishmentHolder> _tasks = new ConcurrentHashMap<>();
protected PunishmentManager()
{
load();
}
private void load()
{
// Initiate task holders.
for (PunishmentAffect affect : PunishmentAffect.values())
{
_tasks.put(affect, new PunishmentHolder());
}
int initiated = 0;
int expired = 0;
// Load punishments.
try (Connection con = DatabaseFactory.getInstance().getConnection();
Statement st = con.createStatement();
ResultSet rset = st.executeQuery("SELECT * FROM punishments"))
{
while (rset.next())
{
final int id = rset.getInt("id");
final String key = rset.getString("key");
final PunishmentAffect affect = PunishmentAffect.getByName(rset.getString("affect"));
final PunishmentType type = PunishmentType.getByName(rset.getString("type"));
final long expirationTime = rset.getLong("expiration");
final String reason = rset.getString("reason");
final String punishedBy = rset.getString("punishedBy");
if ((type != null) && (affect != null))
{
if ((expirationTime > 0) && (System.currentTimeMillis() > expirationTime)) // expired task.
{
expired++;
}
else
{
initiated++;
_tasks.get(affect).addPunishment(new PunishmentTask(id, key, affect, type, expirationTime, reason, punishedBy, true));
}
}
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Error while loading punishments: ", e);
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + initiated + " active and " + expired + " expired punishments.");
}
public void startPunishment(PunishmentTask task)
{
_tasks.get(task.getAffect()).addPunishment(task);
}
public void stopPunishment(PunishmentAffect affect, PunishmentType type)
{
final PunishmentHolder holder = _tasks.get(affect);
if (holder != null)
{
holder.stopPunishment(type);
}
}
public void stopPunishment(Object key, PunishmentAffect affect, PunishmentType type)
{
final PunishmentTask task = getPunishment(key, affect, type);
if (task != null)
{
_tasks.get(affect).stopPunishment(task);
}
}
public boolean hasPunishment(Object key, PunishmentAffect affect, PunishmentType type)
{
final PunishmentHolder holder = _tasks.get(affect);
return holder.hasPunishment(String.valueOf(key), type);
}
public long getPunishmentExpiration(Object key, PunishmentAffect affect, PunishmentType type)
{
final PunishmentTask p = getPunishment(key, affect, type);
return p != null ? p.getExpirationTime() : 0;
}
private PunishmentTask getPunishment(Object key, PunishmentAffect affect, PunishmentType type)
{
return _tasks.get(affect).getPunishment(String.valueOf(key), type);
}
/**
* Gets the single instance of {@code PunishmentManager}.
* @return single instance of {@code PunishmentManager}
*/
public static PunishmentManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final PunishmentManager _instance = new PunishmentManager();
}
}

View File

@ -0,0 +1,276 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.model.quest.Quest;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
/**
* Quests and scripts manager.
* @author Zoey76
*/
public final class QuestManager
{
protected static final Logger LOGGER = Logger.getLogger(QuestManager.class.getName());
/** Map containing all the quests. */
private final Map<String, Quest> _quests = new ConcurrentHashMap<>();
/** Map containing all the scripts. */
private final Map<String, Quest> _scripts = new ConcurrentHashMap<>();
protected QuestManager()
{
}
public boolean reload(String questFolder)
{
final Quest q = getQuest(questFolder);
if (q == null)
{
return false;
}
return q.reload();
}
/**
* Reloads a the quest by ID.
* @param questId the ID of the quest to be reloaded
* @return {@code true} if reload was successful, {@code false} otherwise
*/
public boolean reload(int questId)
{
final Quest q = getQuest(questId);
if (q == null)
{
return false;
}
return q.reload();
}
/**
* Reload all quests and scripts.<br>
* Unload all quests and scripts and load scripts.cfg.
*/
public void reloadAllScripts()
{
LOGGER.info("Reloading all server scripts.");
// Unload quests.
for (Quest quest : _quests.values())
{
if (quest != null)
{
quest.unload(false);
}
}
_quests.clear();
// Unload scripts.
for (Quest script : _scripts.values())
{
if (script != null)
{
script.unload(false);
}
}
_scripts.clear();
try
{
ScriptEngineManager.getInstance().executeScriptList();
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Failed loading scripts.cfg, no script going to be loaded!", e);
}
QuestManager.getInstance().report();
}
/**
* Logs how many quests and scripts are loaded.
*/
public void report()
{
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + _quests.size() + " quests.");
LOGGER.info(getClass().getSimpleName() + ": Loaded: " + _scripts.size() + " scripts.");
}
/**
* Calls {@link Quest#onSave()} in all quests and scripts.
*/
public void save()
{
// Save quests.
for (Quest quest : _quests.values())
{
quest.onSave();
}
// Save scripts.
for (Quest script : _scripts.values())
{
script.onSave();
}
}
/**
* Gets a quest by name.<br>
* <i>For backwards compatibility, verifies scripts with the given name if the quest is not found.</i>
* @param name the quest name
* @return the quest
*/
public Quest getQuest(String name)
{
if (_quests.containsKey(name))
{
return _quests.get(name);
}
return _scripts.get(name);
}
/**
* Gets a quest by ID.
* @param questId the ID of the quest to get
* @return if found, the quest, {@code null} otherwise
*/
public Quest getQuest(int questId)
{
for (Quest q : _quests.values())
{
if (q.getId() == questId)
{
return q;
}
}
return null;
}
/**
* Adds a new quest.
* @param quest the quest to be added
*/
public void addQuest(Quest quest)
{
if (quest == null)
{
throw new IllegalArgumentException("Quest argument cannot be null");
}
// FIXME: unloading the old quest at this point is a tad too late.
// the new quest has already initialized itself and read the data, starting
// an unpredictable number of tasks with that data. The old quest will now
// save data which will never be read.
// However, requesting the newQuest to re-read the data is not necessarily a
// good option, since the newQuest may have already started timers, spawned NPCs
// or taken any other action which it might re-take by re-reading the data.
// the current solution properly closes the running tasks of the old quest but
// ignores the data; perhaps the least of all evils...
final Quest old = _quests.put(quest.getName(), quest);
if (old != null)
{
old.unload();
LOGGER.info("Replaced quest " + old.getName() + " (" + old.getId() + ") with a new version!");
}
if (Config.ALT_DEV_SHOW_QUESTS_LOAD_IN_LOGS)
{
final String questName = quest.getName().contains("_") ? quest.getName().substring(quest.getName().indexOf('_') + 1) : quest.getName();
LOGGER.info("Loaded quest " + CommonUtil.splitWords(questName) + ".");
}
}
/**
* Removes a script.
* @param script the script to remove
* @return {@code true} if the script was removed, {@code false} otherwise
*/
public boolean removeScript(Quest script)
{
if (_quests.containsKey(script.getName()))
{
_quests.remove(script.getName());
return true;
}
else if (_scripts.containsKey(script.getName()))
{
_scripts.remove(script.getName());
return true;
}
return false;
}
public Map<String, Quest> getQuests()
{
return _quests;
}
public boolean unload(Quest ms)
{
ms.onSave();
return removeScript(ms);
}
/**
* Gets all the registered scripts.
* @return all the scripts
*/
public Map<String, Quest> getScripts()
{
return _scripts;
}
/**
* Adds a script.
* @param script the script to be added
*/
public void addScript(Quest script)
{
final Quest old = _scripts.put(script.getClass().getSimpleName(), script);
if (old != null)
{
old.unload();
LOGGER.info("Replaced script " + old.getName() + " with a new version!");
}
if (Config.ALT_DEV_SHOW_SCRIPTS_LOAD_IN_LOGS)
{
LOGGER.info("Loaded script " + CommonUtil.splitWords(script.getClass().getSimpleName()) + ".");
}
}
/**
* Gets the single instance of {@code QuestManager}.
* @return single instance of {@code QuestManager}
*/
public static QuestManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final QuestManager _instance = new QuestManager();
}
}

View File

@ -0,0 +1,454 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.cache.HtmCache;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.handler.CommunityBoardHandler;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.SellBuffHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.olympiad.OlympiadManager;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.serverpackets.ExPrivateStoreSetWholeMsg;
import com.l2jmobius.gameserver.util.HtmlUtil;
import com.l2jmobius.gameserver.util.Util;
/**
* Sell Buffs Manager
* @author St3eT
*/
public final class SellBuffsManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(SellBuffsManager.class.getName());
private static final List<Integer> ALLOWED_BUFFS = new ArrayList<>();
private static final String htmlFolder = "data/html/mods/SellBuffs/";
protected SellBuffsManager()
{
load();
}
@Override
public void load()
{
if (Config.SELLBUFF_ENABLED)
{
ALLOWED_BUFFS.clear();
parseDatapackFile("data/SellBuffData.xml");
LOGGER.info(": Loaded " + ALLOWED_BUFFS.size() + " allowed buffs.");
}
}
@Override
public void parseDocument(Document doc, File f)
{
final NodeList node = doc.getDocumentElement().getElementsByTagName("skill");
for (int i = 0; i < node.getLength(); ++i)
{
final Element elem = (Element) node.item(i);
final int skillId = Integer.parseInt(elem.getAttribute("id"));
if (!ALLOWED_BUFFS.contains(skillId))
{
ALLOWED_BUFFS.add(skillId);
}
}
}
public void sendSellMenu(L2PcInstance player)
{
final String html = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), htmlFolder + (player.isSellingBuffs() ? "BuffMenu_already.html" : "BuffMenu.html"));
CommunityBoardHandler.separateAndSend(html, player);
}
public void sendBuffChoiceMenu(L2PcInstance player, int index)
{
String html = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), htmlFolder + "BuffChoice.html");
html = html.replace("%list%", buildSkillMenu(player, index));
CommunityBoardHandler.separateAndSend(html, player);
}
public void sendBuffEditMenu(L2PcInstance player)
{
String html = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), htmlFolder + "BuffChoice.html");
html = html.replace("%list%", buildEditMenu(player));
CommunityBoardHandler.separateAndSend(html, player);
}
public void sendBuffMenu(L2PcInstance player, L2PcInstance seller, int index)
{
if (!seller.isSellingBuffs() || seller.getSellingBuffs().isEmpty())
{
return;
}
String html = HtmCache.getInstance().getHtm(player.getHtmlPrefix(), htmlFolder + "BuffBuyMenu.html");
html = html.replace("%list%", buildBuffMenu(player, seller, index));
CommunityBoardHandler.separateAndSend(html, player);
}
public void startSellBuffs(L2PcInstance player, String title)
{
player.sitDown();
player.setIsSellingBuffs(true);
player.setPrivateStoreType(PrivateStoreType.PACKAGE_SELL);
player.getSellList().setTitle(title);
player.getSellList().setPackaged(true);
player.broadcastUserInfo();
player.broadcastPacket(new ExPrivateStoreSetWholeMsg(player));
sendSellMenu(player);
}
public void stopSellBuffs(L2PcInstance player)
{
player.setIsSellingBuffs(false);
player.setPrivateStoreType(PrivateStoreType.NONE);
player.standUp();
player.broadcastUserInfo();
sendSellMenu(player);
}
private String buildBuffMenu(L2PcInstance player, L2PcInstance seller, int index)
{
final int ceiling = index + 10;
int nextIndex = -1;
int previousIndex = -1;
int emptyFields = 0;
final StringBuilder sb = new StringBuilder();
final List<SellBuffHolder> sellList = new ArrayList<>();
int count = 0;
for (SellBuffHolder holder : seller.getSellingBuffs())
{
count++;
if ((count > index) && (count <= ceiling))
{
sellList.add(holder);
}
}
if (count > 10)
{
if (count > (index + 10))
{
nextIndex = index + 10;
}
}
if (index >= 10)
{
previousIndex = index - 10;
}
emptyFields = ceiling - sellList.size();
sb.append("<br>");
sb.append(HtmlUtil.getMpGauge(250, (long) seller.getCurrentMp(), seller.getMaxMp(), false));
sb.append("<br>");
sb.append("<table border=0 cellpadding=0 cellspacing=0 background=\"L2UI_CH3.refinewnd_back_Pattern\">");
sb.append("<tr><td><br><br><br></td></tr>");
sb.append("<tr>");
sb.append("<td fixwidth=\"10\"></td>");
sb.append("<td> <button action=\"\" value=\"Icon\" width=75 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Icon
sb.append("<td> <button action=\"\" value=\"Name\" width=175 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Name
sb.append("<td> <button action=\"\" value=\"Level\" width=85 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Leve
sb.append("<td> <button action=\"\" value=\"MP Cost\" width=100 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Price
sb.append("<td> <button action=\"\" value=\"Price\" width=200 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Price
sb.append("<td> <button action=\"\" value=\"Action\" width=100 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Action
sb.append("<td fixwidth=\"20\"></td>");
sb.append("</tr>");
for (SellBuffHolder holder : sellList)
{
final Skill skill = seller.getKnownSkill(holder.getSkillId());
if (skill == null)
{
emptyFields++;
continue;
}
final L2Item item = ItemTable.getInstance().getTemplate(Config.SELLBUFF_PAYMENT_ID);
sb.append("<tr>");
sb.append("<td fixwidth=\"20\"></td>");
sb.append("<td align=center><img src=\"" + skill.getIcon() + "\" width=\"32\" height=\"32\"></td>");
sb.append("<td align=left>" + skill.getName() + (skill.getLevel() > 100 ? "<font color=\"LEVEL\"> + " + (skill.getLevel() % 100) + "</font></td>" : "</td>"));
sb.append("<td align=center>" + ((skill.getLevel() > 100) ? SkillData.getInstance().getMaxLevel(skill.getId()) : skill.getLevel()) + "</td>");
sb.append("<td align=center> <font color=\"1E90FF\">" + (skill.getMpConsume() * Config.SELLBUFF_MP_MULTIPLER) + "</font></td>");
sb.append("<td align=center> " + Util.formatAdena(holder.getPrice()) + " <font color=\"LEVEL\"> " + (item != null ? item.getName() : "") + "</font> </td>");
sb.append("<td align=center fixwidth=\"50\"><button value=\"Buy Buff\" action=\"bypass -h sellbuffbuyskill " + seller.getObjectId() + " " + skill.getId() + " " + index + "\" width=\"85\" height=\"26\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
sb.append("</tr>");
sb.append("<tr><td><br><br></td></tr>");
}
for (int i = 0; i < emptyFields; i++)
{
sb.append("<tr>");
sb.append("<td fixwidth=\"20\"></td>");
sb.append("<td align=center></td>");
sb.append("<td align=left></td>");
sb.append("<td align=center></td>");
sb.append("<td align=center></font></td>");
sb.append("<td align=center></td>");
sb.append("<td align=center fixwidth=\"50\"></td>");
sb.append("</tr>");
sb.append("<tr><td><br><br></td></tr>");
}
sb.append("</table>");
sb.append("<table width=\"250\" border=\"0\">");
sb.append("<tr>");
if (previousIndex > -1)
{
sb.append("<td align=left><button value=\"Previous Page\" action=\"bypass -h sellbuffbuymenu " + seller.getObjectId() + " " + previousIndex + "\" width=\"100\" height=\"30\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
if (nextIndex > -1)
{
sb.append("<td align=right><button value=\"Next Page\" action=\"bypass -h sellbuffbuymenu " + seller.getObjectId() + " " + nextIndex + "\" width=\"100\" height=\"30\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
sb.append("</tr>");
sb.append("</table>");
return sb.toString();
}
private String buildEditMenu(L2PcInstance player)
{
final StringBuilder sb = new StringBuilder();
sb.append("<table border=0 cellpadding=0 cellspacing=0 background=\"L2UI_CH3.refinewnd_back_Pattern\">");
sb.append("<tr><td><br><br><br></td></tr>");
sb.append("<tr>");
sb.append("<td fixwidth=\"10\"></td>");
sb.append("<td> <button action=\"\" value=\"Icon\" width=75 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Icon
sb.append("<td> <button action=\"\" value=\"Name\" width=150 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Name
sb.append("<td> <button action=\"\" value=\"Level\" width=75 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Level
sb.append("<td> <button action=\"\" value=\"Old Price\" width=100 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Old price
sb.append("<td> <button action=\"\" value=\"New Price\" width=125 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // New price
sb.append("<td> <button action=\"\" value=\"Action\" width=125 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Change Price
sb.append("<td> <button action=\"\" value=\"Remove\" width=85 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Remove Buff
sb.append("<td fixwidth=\"20\"></td>");
sb.append("</tr>");
if (player.getSellingBuffs().isEmpty())
{
sb.append("</table>");
sb.append("<br><br><br>");
sb.append("You don't have added any buffs yet!");
}
else
{
for (SellBuffHolder holder : player.getSellingBuffs())
{
final Skill skill = player.getKnownSkill(holder.getSkillId());
if (skill == null)
{
continue;
}
sb.append("<tr>");
sb.append("<td fixwidth=\"20\"></td>");
sb.append("<td align=center><img src=\"" + skill.getIcon() + "\" width=\"32\" height=\"32\"></td>"); // Icon
sb.append("<td align=left>" + skill.getName() + (skill.getLevel() > 100 ? "<font color=\"LEVEL\"> + " + (skill.getLevel() % 100) + "</font></td>" : "</td>")); // Name + enchant
sb.append("<td align=center>" + ((skill.getLevel() > 100) ? SkillData.getInstance().getMaxLevel(skill.getId()) : skill.getLevel()) + "</td>"); // Level
sb.append("<td align=center> " + Util.formatAdena(holder.getPrice()) + " </td>"); // Price show
sb.append("<td align=center><edit var=\"price_" + skill.getId() + "\" width=120 type=\"number\"></td>"); // Price edit
sb.append("<td align=center><button value=\"Edit\" action=\"bypass -h sellbuffchangeprice " + skill.getId() + " $price_" + skill.getId() + "\" width=\"85\" height=\"26\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
sb.append("<td align=center><button value=\" X \" action=\"bypass -h sellbuffremove " + skill.getId() + "\" width=\"26\" height=\"26\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
sb.append("</tr>");
sb.append("<tr><td><br><br></td></tr>");
}
sb.append("</table>");
}
return sb.toString();
}
private String buildSkillMenu(L2PcInstance player, int index)
{
final int ceiling = index + 10;
int nextIndex = -1;
int previousIndex = -1;
final StringBuilder sb = new StringBuilder();
final List<Skill> skillList = new ArrayList<>();
int count = 0;
for (Skill skill : player.getAllSkills())
{
if (ALLOWED_BUFFS.contains(skill.getId()) && !isInSellList(player, skill))
{
count++;
if ((count > index) && (count <= ceiling))
{
skillList.add(skill);
}
}
}
if (count > 10)
{
if (count > (index + 10))
{
nextIndex = index + 10;
}
}
if (index >= 10)
{
previousIndex = index - 10;
}
sb.append("<table border=0 cellpadding=0 cellspacing=0 background=\"L2UI_CH3.refinewnd_back_Pattern\">");
sb.append("<tr><td><br><br><br></td></tr>");
sb.append("<tr>");
sb.append("<td fixwidth=\"10\"></td>");
sb.append("<td> <button action=\"\" value=\"Icon\" width=100 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Icon
sb.append("<td> <button action=\"\" value=\"Name\" width=175 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Name
sb.append("<td> <button action=\"\" value=\"Level\" width=150 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Leve
sb.append("<td> <button action=\"\" value=\"Price\" width=150 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Price
sb.append("<td> <button action=\"\" value=\"Action\" width=125 height=23 back=\"L2UI_CT1.OlympiadWnd_DF_Watch_Down\" fore=\"L2UI_CT1.OlympiadWnd_DF_Watch\"> </td>"); // Action
sb.append("<td fixwidth=\"20\"></td>");
sb.append("</tr>");
if (skillList.isEmpty())
{
sb.append("</table>");
sb.append("<br><br><br>");
sb.append("At this moment you cant add any buffs!");
}
else
{
for (Skill skill : skillList)
{
sb.append("<tr>");
sb.append("<td fixwidth=\"20\"></td>");
sb.append("<td align=center><img src=\"" + skill.getIcon() + "\" width=\"32\" height=\"32\"></td>");
sb.append("<td align=left>" + skill.getName() + (skill.getLevel() > 100 ? "<font color=\"LEVEL\"> + " + (skill.getLevel() % 100) + "</font></td>" : "</td>"));
sb.append("<td align=center>" + ((skill.getLevel() > 100) ? SkillData.getInstance().getMaxLevel(skill.getId()) : skill.getLevel()) + "</td>");
sb.append("<td align=center><edit var=\"price_" + skill.getId() + "\" width=120 type=\"number\"></td>");
sb.append("<td align=center fixwidth=\"50\"><button value=\"Add Buff\" action=\"bypass -h sellbuffaddskill " + skill.getId() + " $price_" + skill.getId() + "\" width=\"85\" height=\"26\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
sb.append("</tr>");
sb.append("<tr><td><br><br></td></tr>");
}
sb.append("</table>");
}
sb.append("<table width=\"250\" border=\"0\">");
sb.append("<tr>");
if (previousIndex > -1)
{
sb.append("<td align=left><button value=\"Previous Page\" action=\"bypass -h sellbuffadd " + previousIndex + "\" width=\"100\" height=\"30\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
if (nextIndex > -1)
{
sb.append("<td align=right><button value=\"Next Page\" action=\"bypass -h sellbuffadd " + nextIndex + "\" width=\"100\" height=\"30\" back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"></td>");
}
sb.append("</tr>");
sb.append("</table>");
return sb.toString();
}
public boolean isInSellList(L2PcInstance player, Skill skill)
{
return player.getSellingBuffs().stream().filter(h -> (h.getSkillId() == skill.getId())).findFirst().orElse(null) != null;
}
public boolean canStartSellBuffs(L2PcInstance player)
{
if (player.isAlikeDead())
{
player.sendMessage("You can't sell buffs in fake death!");
return false;
}
else if (player.isInOlympiadMode() || OlympiadManager.getInstance().isRegistered(player))
{
player.sendMessage("You can't sell buffs with Olympiad status!");
return false;
}
else if (CeremonyOfChaosManager.getInstance().isRegistered(player))
{
player.sendMessage("You can't sell buffs with Ceremony of Chaos status!");
return false;
}
else if (player.isCursedWeaponEquipped() || (player.getReputation() < 0))
{
player.sendMessage("You can't sell buffs in Chaotic state!");
return false;
}
else if (player.isInDuel())
{
player.sendMessage("You can't sell buffs in Duel state!");
return false;
}
else if (player.isFishing())
{
player.sendMessage("You can't sell buffs while fishing.");
return false;
}
else if (player.isMounted() || player.isFlyingMounted() || player.isFlying())
{
player.sendMessage("You can't sell buffs in Mounth state!");
return false;
}
else if (player.isTransformed())
{
player.sendMessage("You can't sell buffs in Transform state!");
return false;
}
else if (player.isInsideZone(ZoneId.NO_STORE) || !player.isInsideZone(ZoneId.PEACE) || player.isJailed())
{
player.sendMessage("You can't sell buffs here!");
return false;
}
return true;
}
/**
* Gets the single instance of {@code SellBuffsManager}.
* @return single instance of {@code SellBuffsManager}
*/
public static SellBuffsManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final SellBuffsManager _instance = new SellBuffsManager();
}
}

View File

@ -0,0 +1,107 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.Shutdown;
import com.l2jmobius.gameserver.ThreadPoolManager;
/**
* @author Gigi
*/
public class ServerRestartManager
{
static final Logger _log = Logger.getLogger(ServerRestartManager.class.getName());
private String nextRestartTime = "unknown";
protected ServerRestartManager()
{
try
{
final Calendar currentTime = Calendar.getInstance();
final Calendar restartTime = Calendar.getInstance();
Calendar lastRestart = null;
long delay = 0;
long lastDelay = 0;
for (String scheduledTime : Config.SERVER_RESTART_SCHEDULE)
{
final String[] splitTime = scheduledTime.trim().split(":");
restartTime.set(Calendar.HOUR_OF_DAY, Integer.parseInt(splitTime[0]));
restartTime.set(Calendar.MINUTE, Integer.parseInt(splitTime[1]));
restartTime.set(Calendar.SECOND, 00);
if (restartTime.getTimeInMillis() < currentTime.getTimeInMillis())
{
restartTime.add(Calendar.DAY_OF_MONTH, 1);
}
delay = restartTime.getTimeInMillis() - currentTime.getTimeInMillis();
if (lastDelay == 0)
{
lastDelay = delay;
lastRestart = restartTime;
}
if (delay < lastDelay)
{
lastDelay = delay;
lastRestart = restartTime;
}
}
if (lastRestart != null)
{
nextRestartTime = new SimpleDateFormat("HH:mm").format(lastRestart.getTime());
ThreadPoolManager.getInstance().scheduleGeneral(new ServerRestartTask(), lastDelay - (Config.SERVER_RESTART_SCHEDULE_COUNTDOWN * 1000));
_log.info("Scheduled server restart at " + lastRestart.getTime() + ".");
}
}
catch (Exception e)
{
_log.info("The scheduled server restart config is not set properly, please correct it!");
}
}
public String getNextRestartTime()
{
return nextRestartTime;
}
class ServerRestartTask implements Runnable
{
@Override
public void run()
{
Shutdown.getInstance().startShutdown(null, Config.SERVER_RESTART_SCHEDULE_COUNTDOWN, true);
}
}
public static ServerRestartManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final ServerRestartManager _instance = new ServerRestartManager();
}
}

View File

@ -0,0 +1,393 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.data.xml.impl.CastleData;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.enums.ItemLocation;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2DefenderInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
import com.l2jmobius.gameserver.model.entity.Castle;
import com.l2jmobius.gameserver.model.holders.SiegeGuardHolder;
import com.l2jmobius.gameserver.model.interfaces.IPositionable;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
/**
* Siege Guard Manager.
* @author St3eT
*/
public final class SiegeGuardManager
{
private static final Logger LOGGER = Logger.getLogger(SiegeGuardManager.class.getName());
private static final Set<L2ItemInstance> _droppedTickets = ConcurrentHashMap.newKeySet();
private static final Map<Integer, Set<L2Spawn>> _siegeGuardSpawn = new ConcurrentHashMap<>();
protected SiegeGuardManager()
{
_droppedTickets.clear();
load();
}
private void load()
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
ResultSet rs = con.createStatement().executeQuery("SELECT * FROM castle_siege_guards Where isHired = 1"))
{
while (rs.next())
{
final int npcId = rs.getInt("npcId");
final int x = rs.getInt("x");
final int y = rs.getInt("y");
final int z = rs.getInt("z");
final Castle castle = CastleManager.getInstance().getCastle(x, y, z);
if (castle == null)
{
LOGGER.warning("Siege guard ticket cannot be placed! Castle is null at X: " + x + ", Y: " + y + ", Z: " + z);
continue;
}
final SiegeGuardHolder holder = getSiegeGuardByNpc(castle.getResidenceId(), npcId);
if ((holder != null) && !castle.getSiege().isInProgress())
{
final L2ItemInstance dropticket = new L2ItemInstance(holder.getItemId());
dropticket.setItemLocation(ItemLocation.VOID);
dropticket.dropMe(null, x, y, z);
L2World.getInstance().storeObject(dropticket);
_droppedTickets.add(dropticket);
}
}
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _droppedTickets.size() + " siege guards tickets.");
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
}
/**
* Finds {@code SiegeGuardHolder} equals to castle id and npc id.
* @param castleId the ID of the castle
* @param itemId the ID of the item
* @return the {@code SiegeGuardHolder} for this castle ID and item ID if any, otherwise {@code null}
*/
public SiegeGuardHolder getSiegeGuardByItem(int castleId, int itemId)
{
return CastleData.getInstance().getSiegeGuardsForCastle(castleId).stream().filter(g -> (g.getItemId() == itemId)).findFirst().orElse(null);
}
/**
* Finds {@code SiegeGuardHolder} equals to castle id and npc id.
* @param castleId the ID of the castle
* @param npcId the ID of the npc
* @return the {@code SiegeGuardHolder} for this castle ID and npc ID if any, otherwise {@code null}
*/
public SiegeGuardHolder getSiegeGuardByNpc(int castleId, int npcId)
{
return CastleData.getInstance().getSiegeGuardsForCastle(castleId).stream().filter(g -> (g.getNpcId() == npcId)).findFirst().orElse(null);
}
/**
* Checks if {@code PlayerInstance} is too much close to another ticket.
* @param player the PlayerInstance
* @return {@code true} if {@code PlayerInstance} is too much close to another ticket, {@code false} otherwise
*/
public boolean isTooCloseToAnotherTicket(L2PcInstance player)
{
return _droppedTickets.stream().filter(g -> g.calculateDistance(player, true, false) < 25).findFirst().orElse(null) != null;
}
/**
* Checks if castle is under npc limit.
* @param castleId the ID of the castle
* @param itemId the ID of the item
* @return {@code true} if castle is under npc limit, {@code false} otherwise
*/
public boolean isAtNpcLimit(int castleId, int itemId)
{
final long count = _droppedTickets.stream().filter(i -> i.getId() == itemId).count();
final SiegeGuardHolder holder = getSiegeGuardByItem(castleId, itemId);
return count >= holder.getMaxNpcAmout();
}
/**
* Adds ticket in current world.
* @param itemId the ID of the item
* @param player the PlayerInstance
*/
public void addTicket(int itemId, L2PcInstance player)
{
final Castle castle = CastleManager.getInstance().getCastle(player);
if (castle == null)
{
return;
}
if (isAtNpcLimit(castle.getResidenceId(), itemId))
{
return;
}
final SiegeGuardHolder holder = getSiegeGuardByItem(castle.getResidenceId(), itemId);
if (holder != null)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("Insert Into castle_siege_guards (castleId, npcId, x, y, z, heading, respawnDelay, isHired) Values (?, ?, ?, ?, ?, ?, ?, ?)"))
{
statement.setInt(1, castle.getResidenceId());
statement.setInt(2, holder.getNpcId());
statement.setInt(3, player.getX());
statement.setInt(4, player.getY());
statement.setInt(5, player.getZ());
statement.setInt(6, player.getHeading());
statement.setInt(7, 0);
statement.setInt(8, 1);
statement.execute();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error adding siege guard for castle " + castle.getName() + ": " + e.getMessage(), e);
}
spawnMercenary(player, holder);
final L2ItemInstance dropticket = new L2ItemInstance(itemId);
dropticket.setItemLocation(ItemLocation.VOID);
dropticket.dropMe(null, player.getX(), player.getY(), player.getZ());
L2World.getInstance().storeObject(dropticket);
_droppedTickets.add(dropticket);
}
}
/**
* Spawns Siege Guard in current world.
* @param pos the object containing the spawn location coordinates
* @param holder SiegeGuardHolder holder
*/
private void spawnMercenary(IPositionable pos, SiegeGuardHolder holder)
{
final L2NpcTemplate template = NpcData.getInstance().getTemplate(holder.getNpcId());
if (template != null)
{
final L2DefenderInstance npc = new L2DefenderInstance(template);
npc.setCurrentHpMp(npc.getMaxHp(), npc.getMaxMp());
npc.setDecayed(false);
npc.setHeading(pos.getHeading());
npc.spawnMe(pos.getX(), pos.getY(), (pos.getZ() + 20));
npc.scheduleDespawn(3000);
npc.setIsImmobilized(holder.isStationary());
}
}
/**
* Delete all tickets from a castle.
* @param castleId the ID of the castle
*/
public void deleteTickets(int castleId)
{
for (L2ItemInstance ticket : _droppedTickets)
{
if ((ticket != null) && (getSiegeGuardByItem(castleId, ticket.getId()) != null))
{
ticket.decayMe();
_droppedTickets.remove(ticket);
}
}
}
/**
* remove a single ticket and its associated spawn from the world (used when the castle lord picks up a ticket, for example).
* @param item the item ID
*/
public void removeTicket(L2ItemInstance item)
{
final Castle castle = CastleManager.getInstance().getCastle(item);
if (castle == null)
{
return;
}
final SiegeGuardHolder holder = getSiegeGuardByItem(castle.getResidenceId(), item.getId());
if (holder == null)
{
return;
}
removeSiegeGuard(holder.getNpcId(), item);
_droppedTickets.remove(item);
}
/**
* Loads all siege guards for castle.
* @param castle the castle instance
*/
private void loadSiegeGuard(Castle castle)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM castle_siege_guards Where castleId = ? And isHired = ?"))
{
ps.setInt(1, castle.getResidenceId());
ps.setInt(2, castle.getOwnerId() > 0 ? 1 : 0);
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
final L2Spawn spawn = new L2Spawn(rs.getInt("npcId"));
spawn.setAmount(1);
spawn.setX(rs.getInt("x"));
spawn.setY(rs.getInt("y"));
spawn.setZ(rs.getInt("z"));
spawn.setHeading(rs.getInt("heading"));
spawn.setRespawnDelay(rs.getInt("respawnDelay"));
spawn.setLocationId(0);
getSpawnedGuards(castle.getResidenceId()).add(spawn);
}
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error loading siege guard for castle " + castle.getName() + ": " + e.getMessage(), e);
}
}
/**
* Remove single siege guard.
* @param npcId the ID of NPC
* @param pos
*/
public void removeSiegeGuard(int npcId, IPositionable pos)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("Delete From castle_siege_guards Where npcId = ? And x = ? AND y = ? AND z = ? AND isHired = 1"))
{
ps.setInt(1, npcId);
ps.setInt(2, pos.getX());
ps.setInt(3, pos.getY());
ps.setInt(4, pos.getZ());
ps.execute();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error deleting hired siege guard at " + pos + " : " + e.getMessage(), e);
}
}
/**
* Remove all siege guards for castle.
* @param castle the castle instance
*/
public void removeSiegeGuards(Castle castle)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("Delete From castle_siege_guards Where castleId = ? And isHired = 1"))
{
ps.setInt(1, castle.getResidenceId());
ps.execute();
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, "Error deleting hired siege guard for castle " + castle.getName() + ": " + e.getMessage(), e);
}
}
/**
* Spawn all siege guards for castle.
* @param castle the castle instance
*/
public void spawnSiegeGuard(Castle castle)
{
try
{
final boolean isHired = (castle.getOwnerId() > 0);
loadSiegeGuard(castle);
for (L2Spawn spawn : getSpawnedGuards(castle.getResidenceId()))
{
if (spawn != null)
{
spawn.init();
if (isHired)
{
spawn.stopRespawn();
}
final SiegeGuardHolder holder = getSiegeGuardByNpc(castle.getResidenceId(), spawn.getLastSpawn().getId());
if (holder == null)
{
continue;
}
spawn.getLastSpawn().setIsImmobilized(holder.isStationary());
}
}
}
catch (Exception e)
{
LOGGER.log(Level.SEVERE, "Error spawning siege guards for castle " + castle.getName(), e);
}
}
/**
* Unspawn all siege guards for castle.
* @param castle the castle instance
*/
public void unspawnSiegeGuard(Castle castle)
{
for (L2Spawn spawn : getSpawnedGuards(castle.getResidenceId()))
{
if ((spawn != null) && (spawn.getLastSpawn() != null))
{
spawn.stopRespawn();
spawn.getLastSpawn().doDie(spawn.getLastSpawn());
}
}
getSpawnedGuards(castle.getResidenceId()).clear();
}
public Set<L2Spawn> getSpawnedGuards(int castleId)
{
return _siegeGuardSpawn.computeIfAbsent(castleId, key -> ConcurrentHashMap.newKeySet());
}
/**
* Gets the single instance of {@code MercTicketManager}.
* @return single instance of {@code MercTicketManager}
*/
public static SiegeGuardManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final SiegeGuardManager _instance = new SiegeGuardManager();
}
}

View File

@ -0,0 +1,305 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.commons.util.PropertiesParser;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.TowerSpawn;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Castle;
import com.l2jmobius.gameserver.model.entity.Siege;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.model.skills.Skill;
public final class SiegeManager
{
private static final Logger _log = Logger.getLogger(SiegeManager.class.getName());
private final Map<Integer, List<TowerSpawn>> _controlTowers = new HashMap<>();
private final Map<Integer, List<TowerSpawn>> _flameTowers = new HashMap<>();
private int _attackerMaxClans = 500; // Max number of clans
private int _attackerRespawnDelay = 0; // Time in ms. Changeable in siege.config
private int _defenderMaxClans = 500; // Max number of clans
private int _flagMaxCount = 1; // Changeable in siege.config
private int _siegeClanMinLevel = 5; // Changeable in siege.config
private int _siegeLength = 120; // Time in minute. Changeable in siege.config
private int _bloodAllianceReward = 0; // Number of Blood Alliance items reward for successful castle defending
protected SiegeManager()
{
load();
}
public final void addSiegeSkills(L2PcInstance character)
{
for (Skill sk : SkillData.getInstance().getSiegeSkills(character.isNoble(), character.getClan().getCastleId() > 0))
{
character.addSkill(sk, false);
}
}
/**
* @param clan The L2Clan of the player
* @param castleid
* @return true if the clan is registered or owner of a castle
*/
public final boolean checkIsRegistered(L2Clan clan, int castleid)
{
if (clan == null)
{
return false;
}
if (clan.getCastleId() > 0)
{
return true;
}
boolean register = false;
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement statement = con.prepareStatement("SELECT clan_id FROM siege_clans where clan_id=? and castle_id=?"))
{
statement.setInt(1, clan.getId());
statement.setInt(2, castleid);
try (ResultSet rs = statement.executeQuery())
{
if (rs.next())
{
register = true;
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Exception: checkIsRegistered(): " + e.getMessage(), e);
}
return register;
}
public final void removeSiegeSkills(L2PcInstance character)
{
for (Skill sk : SkillData.getInstance().getSiegeSkills(character.isNoble(), character.getClan().getCastleId() > 0))
{
character.removeSkill(sk);
}
}
private void load()
{
final PropertiesParser siegeSettings = new PropertiesParser(Config.SIEGE_CONFIGURATION_FILE);
// Siege setting
_attackerMaxClans = siegeSettings.getInt("AttackerMaxClans", 500);
_attackerRespawnDelay = siegeSettings.getInt("AttackerRespawn", 0);
_defenderMaxClans = siegeSettings.getInt("DefenderMaxClans", 500);
_flagMaxCount = siegeSettings.getInt("MaxFlags", 1);
_siegeClanMinLevel = siegeSettings.getInt("SiegeClanMinLevel", 5);
_siegeLength = siegeSettings.getInt("SiegeLength", 120);
_bloodAllianceReward = siegeSettings.getInt("BloodAllianceReward", 1);
for (Castle castle : CastleManager.getInstance().getCastles())
{
final List<TowerSpawn> controlTowers = new ArrayList<>();
for (int i = 1; i < 0xFF; i++)
{
final String settingsKeyName = castle.getName() + "ControlTower" + i;
if (!siegeSettings.containskey(settingsKeyName))
{
break;
}
final StringTokenizer st = new StringTokenizer(siegeSettings.getString(settingsKeyName, ""), ",");
try
{
final int x = Integer.parseInt(st.nextToken());
final int y = Integer.parseInt(st.nextToken());
final int z = Integer.parseInt(st.nextToken());
final int npcId = Integer.parseInt(st.nextToken());
controlTowers.add(new TowerSpawn(npcId, new Location(x, y, z)));
}
catch (Exception e)
{
_log.warning(getClass().getSimpleName() + ": Error while loading control tower(s) for " + castle.getName() + " castle.");
}
}
final List<TowerSpawn> flameTowers = new ArrayList<>();
for (int i = 1; i < 0xFF; i++)
{
final String settingsKeyName = castle.getName() + "FlameTower" + i;
if (!siegeSettings.containskey(settingsKeyName))
{
break;
}
final StringTokenizer st = new StringTokenizer(siegeSettings.getString(settingsKeyName, ""), ",");
try
{
final int x = Integer.parseInt(st.nextToken());
final int y = Integer.parseInt(st.nextToken());
final int z = Integer.parseInt(st.nextToken());
final int npcId = Integer.parseInt(st.nextToken());
final List<Integer> zoneList = new ArrayList<>();
while (st.hasMoreTokens())
{
zoneList.add(Integer.parseInt(st.nextToken()));
}
flameTowers.add(new TowerSpawn(npcId, new Location(x, y, z), zoneList));
}
catch (Exception e)
{
_log.warning(getClass().getSimpleName() + ": Error while loading flame tower(s) for " + castle.getName() + " castle.");
}
}
_controlTowers.put(castle.getResidenceId(), controlTowers);
_flameTowers.put(castle.getResidenceId(), flameTowers);
if (castle.getOwnerId() != 0)
{
loadTrapUpgrade(castle.getResidenceId());
}
}
}
public final List<TowerSpawn> getControlTowers(int castleId)
{
return _controlTowers.get(castleId);
}
public final List<TowerSpawn> getFlameTowers(int castleId)
{
return _flameTowers.get(castleId);
}
public final int getAttackerMaxClans()
{
return _attackerMaxClans;
}
public final int getAttackerRespawnDelay()
{
return _attackerRespawnDelay;
}
public final int getDefenderMaxClans()
{
return _defenderMaxClans;
}
public final int getFlagMaxCount()
{
return _flagMaxCount;
}
public final Siege getSiege(ILocational loc)
{
return getSiege(loc.getX(), loc.getY(), loc.getZ());
}
public final Siege getSiege(L2Object activeObject)
{
return getSiege(activeObject.getX(), activeObject.getY(), activeObject.getZ());
}
public final Siege getSiege(int x, int y, int z)
{
for (Castle castle : CastleManager.getInstance().getCastles())
{
if (castle.getSiege().checkIfInZone(x, y, z))
{
return castle.getSiege();
}
}
return null;
}
public final int getSiegeClanMinLevel()
{
return _siegeClanMinLevel;
}
public final int getSiegeLength()
{
return _siegeLength;
}
public final int getBloodAllianceReward()
{
return _bloodAllianceReward;
}
public final List<Siege> getSieges()
{
final List<Siege> sieges = new LinkedList<>();
for (Castle castle : CastleManager.getInstance().getCastles())
{
sieges.add(castle.getSiege());
}
return sieges;
}
private void loadTrapUpgrade(int castleId)
{
try (Connection con = DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM castle_trapupgrade WHERE castleId=?"))
{
ps.setInt(1, castleId);
try (ResultSet rs = ps.executeQuery())
{
while (rs.next())
{
_flameTowers.get(castleId).get(rs.getInt("towerIndex")).setUpgradeLevel(rs.getInt("level"));
}
}
}
catch (Exception e)
{
_log.log(Level.WARNING, "Exception: loadTrapUpgrade(): " + e.getMessage(), e);
}
}
public static SiegeManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final SiegeManager _instance = new SiegeManager();
}
}

View File

@ -0,0 +1,67 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.timers.TimerHolder;
/**
* @author UnAfraid
*/
public class TimersManager
{
private final Map<Integer, Set<TimerHolder<?>>> _timers = new ConcurrentHashMap<>();
public void registerTimer(TimerHolder<?> timer)
{
final L2Npc npc = timer.getNpc();
if (npc != null)
{
_timers.computeIfAbsent(npc.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer);
}
final L2PcInstance player = timer.getPlayer();
if (player != null)
{
_timers.computeIfAbsent(player.getObjectId(), key -> ConcurrentHashMap.newKeySet()).add(timer);
}
}
public void cancelTimers(int objectId)
{
final Set<TimerHolder<?>> timers = _timers.remove(objectId);
if (timers != null)
{
timers.forEach(TimerHolder::cancelTimer);
}
}
public static TimersManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final TimersManager _instance = new TimersManager();
}
}

View File

@ -0,0 +1,101 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import com.l2jmobius.gameserver.model.entity.Castle;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.type.L2TownZone;
public final class TownManager
{
public static int getTownCastle(int townId)
{
switch (townId)
{
case 912:
return 1;
case 916:
return 2;
case 918:
return 3;
case 922:
return 4;
case 924:
return 5;
case 926:
return 6;
case 1538:
return 7;
case 1537:
return 8;
case 1714:
return 9;
default:
return 0;
}
}
public static boolean townHasCastleInSiege(int townId)
{
final int castleId = getTownCastle(townId);
if (castleId > 0)
{
final Castle castle = CastleManager.getInstance().getCastleById(castleId);
if (castle != null)
{
return castle.getSiege().isInProgress();
}
}
return false;
}
public static boolean townHasCastleInSiege(int x, int y)
{
return townHasCastleInSiege(MapRegionManager.getInstance().getMapRegionLocId(x, y));
}
public static L2TownZone getTown(int townId)
{
for (L2TownZone temp : ZoneManager.getInstance().getAllZones(L2TownZone.class))
{
if (temp.getTownId() == townId)
{
return temp;
}
}
return null;
}
/**
* Returns the town at that position (if any)
* @param x
* @param y
* @param z
* @return
*/
public static L2TownZone getTown(int x, int y, int z)
{
for (L2ZoneType temp : ZoneManager.getInstance().getZones(x, y, z))
{
if (temp instanceof L2TownZone)
{
return (L2TownZone) temp;
}
}
return null;
}
}

View File

@ -0,0 +1,490 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.tasks.StartMovingTask;
import com.l2jmobius.gameserver.model.L2NpcWalkerNode;
import com.l2jmobius.gameserver.model.L2WalkRoute;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.WalkInfo;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2MonsterInstance;
import com.l2jmobius.gameserver.model.actor.tasks.npc.walker.ArrivedTask;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnNpcMoveNodeArrived;
import com.l2jmobius.gameserver.model.holders.NpcRoutesHolder;
import com.l2jmobius.gameserver.network.NpcStringId;
/**
* This class manages walking monsters.
* @author GKR
*/
public final class WalkingManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(WalkingManager.class.getName());
// Repeat style:
// -1 - no repeat
// 0 - go back
// 1 - go to first point (circle style)
// 2 - teleport to first point (conveyor style)
// 3 - random walking between points.
public static final byte NO_REPEAT = -1;
public static final byte REPEAT_GO_BACK = 0;
public static final byte REPEAT_GO_FIRST = 1;
public static final byte REPEAT_TELE_FIRST = 2;
public static final byte REPEAT_RANDOM = 3;
private final Map<String, L2WalkRoute> _routes = new HashMap<>(); // all available routes
private final Map<Integer, WalkInfo> _activeRoutes = new HashMap<>(); // each record represents NPC, moving by predefined route from _routes, and moving progress
private final Map<Integer, NpcRoutesHolder> _routesToAttach = new HashMap<>(); // each record represents NPC and all available routes for it
protected WalkingManager()
{
load();
}
@Override
public final void load()
{
parseDatapackFile("data/Routes.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _routes.size() + " walking routes.");
}
@Override
public void parseDocument(Document doc, File f)
{
final Node n = doc.getFirstChild();
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if (d.getNodeName().equals("route"))
{
final String routeName = parseString(d.getAttributes(), "name");
final boolean repeat = parseBoolean(d.getAttributes(), "repeat");
final String repeatStyle = d.getAttributes().getNamedItem("repeatStyle").getNodeValue().toLowerCase();
final byte repeatType;
switch (repeatStyle)
{
case "back":
{
repeatType = REPEAT_GO_BACK;
break;
}
case "cycle":
{
repeatType = REPEAT_GO_FIRST;
break;
}
case "conveyor":
{
repeatType = REPEAT_TELE_FIRST;
break;
}
case "random":
{
repeatType = REPEAT_RANDOM;
break;
}
default:
{
repeatType = NO_REPEAT;
break;
}
}
final List<L2NpcWalkerNode> list = new ArrayList<>();
for (Node r = d.getFirstChild(); r != null; r = r.getNextSibling())
{
if (r.getNodeName().equals("point"))
{
final NamedNodeMap attrs = r.getAttributes();
final int x = parseInteger(attrs, "X");
final int y = parseInteger(attrs, "Y");
final int z = parseInteger(attrs, "Z");
final int delay = parseInteger(attrs, "delay");
final boolean run = parseBoolean(attrs, "run");
NpcStringId npcString = null;
String chatString = null;
Node node = attrs.getNamedItem("string");
if (node != null)
{
chatString = node.getNodeValue();
}
else
{
node = attrs.getNamedItem("npcString");
if (node != null)
{
npcString = NpcStringId.getNpcStringId(node.getNodeValue());
if (npcString == null)
{
LOGGER.warning(getClass().getSimpleName() + ": Unknown npcString '" + node.getNodeValue() + "' for route '" + routeName + "'");
continue;
}
}
else
{
node = attrs.getNamedItem("npcStringId");
if (node != null)
{
npcString = NpcStringId.getNpcStringId(Integer.parseInt(node.getNodeValue()));
if (npcString == null)
{
LOGGER.warning(getClass().getSimpleName() + ": Unknown npcString '" + node.getNodeValue() + "' for route '" + routeName + "'");
continue;
}
}
}
}
list.add(new L2NpcWalkerNode(x, y, z, delay, run, npcString, chatString));
}
else if (r.getNodeName().equals("target"))
{
final NamedNodeMap attrs = r.getAttributes();
try
{
final int npcId = Integer.parseInt(attrs.getNamedItem("id").getNodeValue());
final int x = Integer.parseInt(attrs.getNamedItem("spawnX").getNodeValue());
final int y = Integer.parseInt(attrs.getNamedItem("spawnY").getNodeValue());
final int z = Integer.parseInt(attrs.getNamedItem("spawnZ").getNodeValue());
final NpcRoutesHolder holder = _routesToAttach.containsKey(npcId) ? _routesToAttach.get(npcId) : new NpcRoutesHolder();
holder.addRoute(routeName, new Location(x, y, z));
_routesToAttach.put(npcId, holder);
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": Error in target definition for route '" + routeName + "'");
}
}
}
_routes.put(routeName, new L2WalkRoute(routeName, list, repeat, false, repeatType));
}
}
}
/**
* @param npc NPC to check
* @return {@code true} if given NPC, or its leader is controlled by Walking Manager and moves currently.
*/
public boolean isOnWalk(L2Npc npc)
{
L2MonsterInstance monster = null;
if (npc.isMonster())
{
if (((L2MonsterInstance) npc).getLeader() == null)
{
monster = (L2MonsterInstance) npc;
}
else
{
monster = ((L2MonsterInstance) npc).getLeader();
}
}
if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc))
{
return false;
}
final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId());
if (walk.isStoppedByAttack() || walk.isSuspended())
{
return false;
}
return true;
}
public L2WalkRoute getRoute(String route)
{
return _routes.get(route);
}
/**
* @param npc NPC to check
* @return {@code true} if given NPC controlled by Walking Manager.
*/
public boolean isRegistered(L2Npc npc)
{
return _activeRoutes.containsKey(npc.getObjectId());
}
/**
* @param npc
* @return name of route
*/
public String getRouteName(L2Npc npc)
{
return _activeRoutes.containsKey(npc.getObjectId()) ? _activeRoutes.get(npc.getObjectId()).getRoute().getName() : "";
}
/**
* Start to move given NPC by given route
* @param npc NPC to move
* @param routeName name of route to move by
*/
public void startMoving(L2Npc npc, String routeName)
{
if (_routes.containsKey(routeName) && (npc != null) && !npc.isDead()) // check, if these route and NPC present
{
if (!_activeRoutes.containsKey(npc.getObjectId())) // new walk task
{
// only if not already moved / not engaged in battle... should not happens if called on spawn
if ((npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE) || (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE))
{
final WalkInfo walk = new WalkInfo(routeName);
if (npc.isDebug())
{
walk.setLastAction(System.currentTimeMillis());
}
L2NpcWalkerNode node = walk.getCurrentNode();
// adjust next waypoint, if NPC spawns at first waypoint
if ((npc.getX() == node.getX()) && (npc.getY() == node.getY()))
{
walk.calculateNextNode(npc);
node = walk.getCurrentNode();
npc.sendDebugMessage("Route '" + routeName + "': spawn point is same with first waypoint, adjusted to next");
}
if (!npc.isInsideRadius(node, 3000, true, false))
{
final String message = "Route '" + routeName + "': NPC (id=" + npc.getId() + ", x=" + npc.getX() + ", y=" + npc.getY() + ", z=" + npc.getZ() + ") is too far from starting point (node x=" + node.getX() + ", y=" + node.getY() + ", z=" + node.getZ() + ", range=" + npc.calculateDistance(node, true, true) + "), walking will not start";
LOGGER.warning(message);
npc.sendDebugMessage(message);
return;
}
npc.sendDebugMessage("Starting to move at route '" + routeName + "'");
npc.setIsRunning(node.runToLocation());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, node);
walk.setWalkCheckTask(ThreadPoolManager.getInstance().scheduleAiAtFixedRate(new StartMovingTask(npc, routeName), 60000, 60000)); // start walk check task, for resuming walk after fight
_activeRoutes.put(npc.getObjectId(), walk); // register route
}
else
{
npc.sendDebugMessage("Failed to start moving along route '" + routeName + "', scheduled");
ThreadPoolManager.getInstance().scheduleGeneral(new StartMovingTask(npc, routeName), 60000);
}
}
else
// walk was stopped due to some reason (arrived to node, script action, fight or something else), resume it
{
if (_activeRoutes.containsKey(npc.getObjectId()) && ((npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_ACTIVE) || (npc.getAI().getIntention() == CtrlIntention.AI_INTENTION_IDLE)))
{
final WalkInfo walk = _activeRoutes.get(npc.getObjectId());
if (walk == null)
{
return;
}
// Prevent call simultaneously from scheduled task and onArrived() or temporarily stop walking for resuming in future
if (walk.isBlocked() || walk.isSuspended())
{
npc.sendDebugMessage("Failed to continue moving along route '" + routeName + "' (operation is blocked)");
return;
}
walk.setBlocked(true);
final L2NpcWalkerNode node = walk.getCurrentNode();
npc.sendDebugMessage("Route '" + routeName + "', continuing to node " + walk.getCurrentNodeId());
npc.setIsRunning(node.runToLocation());
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, node);
walk.setBlocked(false);
walk.setStoppedByAttack(false);
}
else
{
npc.sendDebugMessage("Failed to continue moving along route '" + routeName + "' (wrong AI state - " + npc.getAI().getIntention() + ")");
}
}
}
}
/**
* Cancel NPC moving permanently
* @param npc NPC to cancel
*/
public synchronized void cancelMoving(L2Npc npc)
{
final WalkInfo walk = _activeRoutes.remove(npc.getObjectId());
if (walk != null)
{
walk.getWalkCheckTask().cancel(true);
}
}
/**
* Resumes previously stopped moving
* @param npc NPC to resume
*/
public void resumeMoving(L2Npc npc)
{
final WalkInfo walk = _activeRoutes.get(npc.getObjectId());
if (walk != null)
{
walk.setSuspended(false);
walk.setStoppedByAttack(false);
startMoving(npc, walk.getRoute().getName());
}
}
/**
* Pause NPC moving until it will be resumed
* @param npc NPC to pause moving
* @param suspend {@code true} if moving was temporarily suspended for some reasons of AI-controlling script
* @param stoppedByAttack {@code true} if moving was suspended because of NPC was attacked or desired to attack
*/
public void stopMoving(L2Npc npc, boolean suspend, boolean stoppedByAttack)
{
L2MonsterInstance monster = null;
if (npc.isMonster())
{
if (((L2MonsterInstance) npc).getLeader() == null)
{
monster = (L2MonsterInstance) npc;
}
else
{
monster = ((L2MonsterInstance) npc).getLeader();
}
}
if (((monster != null) && !isRegistered(monster)) || !isRegistered(npc))
{
return;
}
final WalkInfo walk = monster != null ? _activeRoutes.get(monster.getObjectId()) : _activeRoutes.get(npc.getObjectId());
walk.setSuspended(suspend);
walk.setStoppedByAttack(stoppedByAttack);
if (monster != null)
{
monster.stopMove(null);
monster.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
}
else
{
npc.stopMove(null);
npc.getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
}
}
/**
* Manage "node arriving"-related tasks: schedule move to next node; send ON_NODE_ARRIVED event to Quest script
* @param npc NPC to manage
*/
public void onArrived(L2Npc npc)
{
if (_activeRoutes.containsKey(npc.getObjectId()))
{
// Notify quest
EventDispatcher.getInstance().notifyEventAsync(new OnNpcMoveNodeArrived(npc), npc);
final WalkInfo walk = _activeRoutes.get(npc.getObjectId());
// Opposite should not happen... but happens sometime
if ((walk.getCurrentNodeId() >= 0) && (walk.getCurrentNodeId() < walk.getRoute().getNodesCount()))
{
final L2NpcWalkerNode node = walk.getRoute().getNodeList().get(walk.getCurrentNodeId());
if (npc.isInsideRadius(node, 10, false, false))
{
npc.sendDebugMessage("Route '" + walk.getRoute().getName() + "', arrived to node " + walk.getCurrentNodeId());
npc.sendDebugMessage("Done in " + ((System.currentTimeMillis() - walk.getLastAction()) / 1000) + " s");
walk.calculateNextNode(npc);
walk.setBlocked(true); // prevents to be ran from walk check task, if there is delay in this node.
if (node.getNpcString() != null)
{
npc.broadcastSay(ChatType.NPC_GENERAL, node.getNpcString());
}
else if (!node.getChatText().isEmpty())
{
npc.broadcastSay(ChatType.NPC_GENERAL, node.getChatText());
}
if (npc.isDebug())
{
walk.setLastAction(System.currentTimeMillis());
}
ThreadPoolManager.getInstance().scheduleGeneral(new ArrivedTask(npc, walk), 100 + (node.getDelay() * 1000L));
}
}
}
}
/**
* Manage "on death"-related tasks: permanently cancel moving of died NPC
* @param npc NPC to manage
*/
public void onDeath(L2Npc npc)
{
cancelMoving(npc);
}
/**
* Manage "on spawn"-related tasks: start NPC moving, if there is route attached to its spawn point
* @param npc NPC to manage
*/
public void onSpawn(L2Npc npc)
{
if (_routesToAttach.containsKey(npc.getId()))
{
final String routeName = _routesToAttach.get(npc.getId()).getRouteName(npc);
if (!routeName.isEmpty())
{
startMoving(npc, routeName);
}
}
}
public static WalkingManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final WalkingManager _instance = new WalkingManager();
}
}

View File

@ -0,0 +1,89 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.util.concurrent.ConcurrentHashMap;
import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.holders.WarpedSpaceHolder;
import com.l2jmobius.gameserver.model.instancezone.Instance;
import com.l2jmobius.gameserver.pathfinding.AbstractNodeLoc;
import com.l2jmobius.gameserver.util.Util;
/**
* @author Sdw
*/
public class WarpedSpaceManager
{
private volatile ConcurrentHashMap<L2Character, WarpedSpaceHolder> _warpedSpace = null;
public void addWarpedSpace(L2Character creature, int radius)
{
if (_warpedSpace == null)
{
synchronized (this)
{
if (_warpedSpace == null)
{
_warpedSpace = new ConcurrentHashMap<>();
}
}
}
_warpedSpace.put(creature, new WarpedSpaceHolder(creature, radius));
}
public void removeWarpedSpace(L2Character creature)
{
_warpedSpace.remove(creature);
}
public boolean checkForWarpedSpace(AbstractNodeLoc start, AbstractNodeLoc end, Instance instance)
{
return checkForWarpedSpace(new Location(start.getX(), start.getY(), start.getZ()), new Location(end.getX(), end.getY(), end.getZ()), instance);
}
public boolean checkForWarpedSpace(Location origin, Location destination, Instance instance)
{
if (_warpedSpace != null)
{
for (WarpedSpaceHolder holder : _warpedSpace.values())
{
final L2Character creature = holder.getCreature();
if (creature.getInstanceWorld() != instance)
{
continue;
}
final int radius = creature.getTemplate().getCollisionRadius();
final boolean originInRange = Util.calculateDistance(creature, origin, false, false) <= (holder.getRange() + radius);
final boolean destinationInRange = Util.calculateDistance(creature, destination, false, false) <= (holder.getRange() + radius);
return destinationInRange ? !originInRange : originInRange;
}
}
return false;
}
public static WarpedSpaceManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final WarpedSpaceManager _instance = new WarpedSpaceManager();
}
}

View File

@ -0,0 +1,757 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.OptionalInt;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.zone.AbstractZoneSettings;
import com.l2jmobius.gameserver.model.zone.L2ZoneForm;
import com.l2jmobius.gameserver.model.zone.L2ZoneRespawn;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneRegion;
import com.l2jmobius.gameserver.model.zone.form.ZoneCuboid;
import com.l2jmobius.gameserver.model.zone.form.ZoneCylinder;
import com.l2jmobius.gameserver.model.zone.form.ZoneNPoly;
import com.l2jmobius.gameserver.model.zone.type.L2ArenaZone;
import com.l2jmobius.gameserver.model.zone.type.L2OlympiadStadiumZone;
import com.l2jmobius.gameserver.model.zone.type.L2RespawnZone;
import com.l2jmobius.gameserver.model.zone.type.L2SpawnTerritory;
/**
* This class manages the zones
* @author durgus
*/
public final class ZoneManager implements IGameXmlReader
{
private static final Logger LOGGER = Logger.getLogger(ZoneManager.class.getName());
private static final Map<String, AbstractZoneSettings> SETTINGS = new HashMap<>();
public static final int SHIFT_BY = 15;
public static final int OFFSET_X = Math.abs(L2World.MAP_MIN_X >> SHIFT_BY);
public static final int OFFSET_Y = Math.abs(L2World.MAP_MIN_Y >> SHIFT_BY);
private final Map<Class<? extends L2ZoneType>, Map<Integer, ? extends L2ZoneType>> _classZones = new HashMap<>();
private final Map<String, L2SpawnTerritory> _spawnTerritories = new HashMap<>();
private int _lastDynamicId = 300000;
private List<L2ItemInstance> _debugItems;
private final ZoneRegion[][] _zoneRegions = new ZoneRegion[(L2World.MAP_MAX_X >> SHIFT_BY) + OFFSET_X + 1][(L2World.MAP_MAX_Y >> SHIFT_BY) + OFFSET_Y + 1];
/**
* Instantiates a new zone manager.
*/
protected ZoneManager()
{
for (int x = 0; x < _zoneRegions.length; x++)
{
for (int y = 0; y < _zoneRegions[x].length; y++)
{
_zoneRegions[x][y] = new ZoneRegion(x, y);
}
}
LOGGER.info(getClass().getSimpleName() + " " + _zoneRegions.length + " by " + _zoneRegions[0].length + " Zone Region Grid set up.");
load();
}
/**
* Reload.
*/
public void reload()
{
// Get the world regions
int count = 0;
// Backup old zone settings
for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
{
for (L2ZoneType zone : map.values())
{
if (zone.getSettings() != null)
{
SETTINGS.put(zone.getName(), zone.getSettings());
}
}
}
// Clear zones
for (ZoneRegion[] zoneRegions : _zoneRegions)
{
for (ZoneRegion zoneRegion : zoneRegions)
{
zoneRegion.getZones().clear();
count++;
}
}
LOGGER.info(getClass().getSimpleName() + ": Removed zones in " + count + " regions.");
// Load the zones
load();
// Re-validate all characters in zones
for (L2Object obj : L2World.getInstance().getVisibleObjects())
{
if (obj instanceof L2Character)
{
((L2Character) obj).revalidateZone(true);
}
}
SETTINGS.clear();
}
@Override
public void parseDocument(Document doc, File f)
{
NamedNodeMap attrs;
Node attribute;
String zoneName;
int[][] coords;
int zoneId, minZ, maxZ;
String zoneType, zoneShape;
final List<int[]> rs = new ArrayList<>();
for (Node n = doc.getFirstChild(); n != null; n = n.getNextSibling())
{
if ("list".equalsIgnoreCase(n.getNodeName()))
{
attrs = n.getAttributes();
attribute = attrs.getNamedItem("enabled");
if ((attribute != null) && !Boolean.parseBoolean(attribute.getNodeValue()))
{
continue;
}
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("zone".equalsIgnoreCase(d.getNodeName()))
{
attrs = d.getAttributes();
attribute = attrs.getNamedItem("type");
if (attribute != null)
{
zoneType = attribute.getNodeValue();
}
else
{
LOGGER.warning("ZoneData: Missing type for zone in file: " + f.getName());
continue;
}
attribute = attrs.getNamedItem("id");
if (attribute != null)
{
zoneId = Integer.parseInt(attribute.getNodeValue());
}
else
{
zoneId = zoneType.equalsIgnoreCase("NpcSpawnTerritory") ? 0 : _lastDynamicId++;
}
attribute = attrs.getNamedItem("name");
if (attribute != null)
{
zoneName = attribute.getNodeValue();
}
else
{
zoneName = null;
}
// Check zone name for NpcSpawnTerritory. Must exist and to be unique
if (zoneType.equalsIgnoreCase("NpcSpawnTerritory"))
{
if (zoneName == null)
{
LOGGER.warning("ZoneData: Missing name for NpcSpawnTerritory in file: " + f.getName() + ", skipping zone");
continue;
}
else if (_spawnTerritories.containsKey(zoneName))
{
LOGGER.warning("ZoneData: Name " + zoneName + " already used for another zone, check file: " + f.getName() + ". Skipping zone");
continue;
}
}
minZ = parseInteger(attrs, "minZ");
maxZ = parseInteger(attrs, "maxZ");
zoneType = parseString(attrs, "type");
zoneShape = parseString(attrs, "shape");
// Get the zone shape from xml
L2ZoneForm zoneForm = null;
try
{
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("node".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
final int[] point = new int[2];
point[0] = parseInteger(attrs, "X");
point[1] = parseInteger(attrs, "Y");
rs.add(point);
}
}
coords = rs.toArray(new int[rs.size()][2]);
rs.clear();
if ((coords == null) || (coords.length == 0))
{
LOGGER.warning(getClass().getSimpleName() + ": ZoneData: missing data for zone: " + zoneId + " XML file: " + f.getName());
continue;
}
// Create this zone. Parsing for cuboids is a bit different than for other polygons cuboids need exactly 2 points to be defined.
// Other polygons need at least 3 (one per vertex)
if (zoneShape.equalsIgnoreCase("Cuboid"))
{
if (coords.length == 2)
{
zoneForm = new ZoneCuboid(coords[0][0], coords[1][0], coords[0][1], coords[1][1], minZ, maxZ);
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": ZoneData: Missing cuboid vertex data for zone: " + zoneId + " in file: " + f.getName());
continue;
}
}
else if (zoneShape.equalsIgnoreCase("NPoly"))
{
// nPoly needs to have at least 3 vertices
if (coords.length > 2)
{
final int[] aX = new int[coords.length];
final int[] aY = new int[coords.length];
for (int i = 0; i < coords.length; i++)
{
aX[i] = coords[i][0];
aY[i] = coords[i][1];
}
zoneForm = new ZoneNPoly(aX, aY, minZ, maxZ);
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": ZoneData: Bad data for zone: " + zoneId + " in file: " + f.getName());
continue;
}
}
else if (zoneShape.equalsIgnoreCase("Cylinder"))
{
// A Cylinder zone requires a center point
// at x,y and a radius
attrs = d.getAttributes();
final int zoneRad = Integer.parseInt(attrs.getNamedItem("rad").getNodeValue());
if ((coords.length == 1) && (zoneRad > 0))
{
zoneForm = new ZoneCylinder(coords[0][0], coords[0][1], minZ, maxZ, zoneRad);
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": ZoneData: Bad data for zone: " + zoneId + " in file: " + f.getName());
continue;
}
}
else
{
LOGGER.warning(getClass().getSimpleName() + ": ZoneData: Unknown shape: \"" + zoneShape + "\" for zone: " + zoneId + " in file: " + f.getName());
continue;
}
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": ZoneData: Failed to load zone " + zoneId + " coordinates: " + e.getMessage(), e);
}
// No further parameters needed, if NpcSpawnTerritory is loading
if (zoneType.equalsIgnoreCase("NpcSpawnTerritory"))
{
_spawnTerritories.put(zoneName, new L2SpawnTerritory(zoneName, zoneForm));
continue;
}
// Create the zone
Class<?> newZone = null;
Constructor<?> zoneConstructor = null;
L2ZoneType temp;
try
{
newZone = Class.forName("com.l2jmobius.gameserver.model.zone.type.L2" + zoneType);
zoneConstructor = newZone.getConstructor(int.class);
temp = (L2ZoneType) zoneConstructor.newInstance(zoneId);
temp.setZone(zoneForm);
}
catch (Exception e)
{
LOGGER.warning(getClass().getSimpleName() + ": ZoneData: No such zone type: " + zoneType + " in file: " + f.getName());
continue;
}
// Check for additional parameters
for (Node cd = d.getFirstChild(); cd != null; cd = cd.getNextSibling())
{
if ("stat".equalsIgnoreCase(cd.getNodeName()))
{
attrs = cd.getAttributes();
final String name = attrs.getNamedItem("name").getNodeValue();
final String val = attrs.getNamedItem("val").getNodeValue();
temp.setParameter(name, val);
}
else if ("spawn".equalsIgnoreCase(cd.getNodeName()) && (temp instanceof L2ZoneRespawn))
{
attrs = cd.getAttributes();
final int spawnX = Integer.parseInt(attrs.getNamedItem("X").getNodeValue());
final int spawnY = Integer.parseInt(attrs.getNamedItem("Y").getNodeValue());
final int spawnZ = Integer.parseInt(attrs.getNamedItem("Z").getNodeValue());
final Node val = attrs.getNamedItem("type");
((L2ZoneRespawn) temp).parseLoc(spawnX, spawnY, spawnZ, val == null ? null : val.getNodeValue());
}
else if ("race".equalsIgnoreCase(cd.getNodeName()) && (temp instanceof L2RespawnZone))
{
attrs = cd.getAttributes();
final String race = attrs.getNamedItem("name").getNodeValue();
final String point = attrs.getNamedItem("point").getNodeValue();
((L2RespawnZone) temp).addRaceRespawnPoint(race, point);
}
}
if (checkId(zoneId))
{
LOGGER.info(getClass().getSimpleName() + ": Caution: Zone (" + zoneId + ") from file: " + f.getName() + " overrides previos definition.");
}
if ((zoneName != null) && !zoneName.isEmpty())
{
temp.setName(zoneName);
}
addZone(zoneId, temp);
// Register the zone into any world region it
// intersects with...
// currently 11136 test for each zone :>
for (int x = 0; x < _zoneRegions.length; x++)
{
for (int y = 0; y < _zoneRegions[x].length; y++)
{
final int ax = (x - OFFSET_X) << SHIFT_BY;
final int bx = ((x + 1) - OFFSET_X) << SHIFT_BY;
final int ay = (y - OFFSET_Y) << SHIFT_BY;
final int by = ((y + 1) - OFFSET_Y) << SHIFT_BY;
if (temp.getZone().intersectsRectangle(ax, bx, ay, by))
{
_zoneRegions[x][y].getZones().put(temp.getId(), temp);
}
}
}
}
}
}
}
}
@Override
public final void load()
{
_classZones.clear();
_spawnTerritories.clear();
parseDatapackDirectory("data/zones", false);
parseDatapackDirectory("data/zones/spawnZones", false);
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _classZones.size() + " zone classes and " + getSize() + " zones.");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + _spawnTerritories.size() + " NPC spawn territoriers.");
final OptionalInt maxId = _classZones.values().stream().flatMap(map -> map.keySet().stream()).mapToInt(Integer.class::cast).filter(value -> value < 300000).max();
LOGGER.info(getClass().getSimpleName() + ": Last static id: " + maxId.getAsInt());
}
/**
* Gets the size.
* @return the size
*/
public int getSize()
{
int i = 0;
for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
{
i += map.size();
}
return i;
}
/**
* Check id.
* @param id the id
* @return true, if successful
*/
public boolean checkId(int id)
{
for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
{
if (map.containsKey(id))
{
return true;
}
}
return false;
}
/**
* Add new zone.
* @param <T> the generic type
* @param id the id
* @param zone the zone
*/
@SuppressWarnings("unchecked")
public <T extends L2ZoneType> void addZone(Integer id, T zone)
{
Map<Integer, T> map = (Map<Integer, T>) _classZones.get(zone.getClass());
if (map == null)
{
map = new HashMap<>();
map.put(id, zone);
_classZones.put(zone.getClass(), map);
}
else
{
map.put(id, zone);
}
}
/**
* Return all zones by class type.
* @param <T> the generic type
* @param zoneType Zone class
* @return Collection of zones
*/
@SuppressWarnings("unchecked")
public <T extends L2ZoneType> Collection<T> getAllZones(Class<T> zoneType)
{
return (Collection<T>) _classZones.get(zoneType).values();
}
/**
* Get zone by ID.
* @param id the id
* @return the zone by id
* @see #getZoneById(int, Class)
*/
public L2ZoneType getZoneById(int id)
{
for (Map<Integer, ? extends L2ZoneType> map : _classZones.values())
{
if (map.containsKey(id))
{
return map.get(id);
}
}
return null;
}
/**
* Get zone by ID and zone class.
* @param <T> the generic type
* @param id the id
* @param zoneType the zone type
* @return zone
*/
@SuppressWarnings("unchecked")
public <T extends L2ZoneType> T getZoneById(int id, Class<T> zoneType)
{
return (T) _classZones.get(zoneType).get(id);
}
/**
* Returns all zones from where the object is located.
* @param locational the locational
* @return zones
*/
public List<L2ZoneType> getZones(ILocational locational)
{
return getZones(locational.getX(), locational.getY(), locational.getZ());
}
/**
* Gets the zone.
* @param <T> the generic type
* @param locational the locational
* @param type the type
* @return zone from where the object is located by type
*/
public <T extends L2ZoneType> T getZone(ILocational locational, Class<T> type)
{
if (locational == null)
{
return null;
}
return getZone(locational.getX(), locational.getY(), locational.getZ(), type);
}
/**
* Returns all zones from given coordinates (plane).
* @param x the x
* @param y the y
* @return zones
*/
public List<L2ZoneType> getZones(int x, int y)
{
final List<L2ZoneType> temp = new ArrayList<>();
for (L2ZoneType zone : getRegion(x, y).getZones().values())
{
if (zone.isInsideZone(x, y))
{
temp.add(zone);
}
}
return temp;
}
/**
* Returns all zones from given coordinates.
* @param x the x
* @param y the y
* @param z the z
* @return zones
*/
public List<L2ZoneType> getZones(int x, int y, int z)
{
final List<L2ZoneType> temp = new ArrayList<>();
for (L2ZoneType zone : getRegion(x, y).getZones().values())
{
if (zone.isInsideZone(x, y, z))
{
temp.add(zone);
}
}
return temp;
}
/**
* Gets the zone.
* @param <T> the generic type
* @param x the x
* @param y the y
* @param z the z
* @param type the type
* @return zone from given coordinates
*/
@SuppressWarnings("unchecked")
public <T extends L2ZoneType> T getZone(int x, int y, int z, Class<T> type)
{
for (L2ZoneType zone : getRegion(x, y).getZones().values())
{
if (zone.isInsideZone(x, y, z) && type.isInstance(zone))
{
return (T) zone;
}
}
return null;
}
/**
* Get spawm territory by name
* @param name name of territory to search
* @return link to zone form
*/
public L2SpawnTerritory getSpawnTerritory(String name)
{
return _spawnTerritories.containsKey(name) ? _spawnTerritories.get(name) : null;
}
/**
* Returns all spawm territories from where the object is located
* @param object
* @return zones
*/
public List<L2SpawnTerritory> getSpawnTerritories(L2Object object)
{
final List<L2SpawnTerritory> temp = new ArrayList<>();
for (L2SpawnTerritory territory : _spawnTerritories.values())
{
if (territory.isInsideZone(object.getX(), object.getY(), object.getZ()))
{
temp.add(territory);
}
}
return temp;
}
/**
* Gets the arena.
* @param character the character
* @return the arena
*/
public final L2ArenaZone getArena(L2Character character)
{
if (character == null)
{
return null;
}
for (L2ZoneType temp : ZoneManager.getInstance().getZones(character.getX(), character.getY(), character.getZ()))
{
if ((temp instanceof L2ArenaZone) && temp.isCharacterInZone(character))
{
return ((L2ArenaZone) temp);
}
}
return null;
}
/**
* Gets the olympiad stadium.
* @param character the character
* @return the olympiad stadium
*/
public final L2OlympiadStadiumZone getOlympiadStadium(L2Character character)
{
if (character == null)
{
return null;
}
for (L2ZoneType temp : ZoneManager.getInstance().getZones(character.getX(), character.getY(), character.getZ()))
{
if ((temp instanceof L2OlympiadStadiumZone) && temp.isCharacterInZone(character))
{
return ((L2OlympiadStadiumZone) temp);
}
}
return null;
}
/**
* For testing purposes only.
* @param <T> the generic type
* @param obj the obj
* @param type the type
* @return the closest zone
*/
@SuppressWarnings("unchecked")
public <T extends L2ZoneType> T getClosestZone(L2Object obj, Class<T> type)
{
T zone = getZone(obj, type);
if (zone == null)
{
double closestdis = Double.MAX_VALUE;
for (T temp : (Collection<T>) _classZones.get(type).values())
{
final double distance = temp.getDistanceToZone(obj);
if (distance < closestdis)
{
closestdis = distance;
zone = temp;
}
}
}
return zone;
}
/**
* General storage for debug items used for visualizing zones.
* @return list of items
*/
public List<L2ItemInstance> getDebugItems()
{
if (_debugItems == null)
{
_debugItems = new ArrayList<>();
}
return _debugItems;
}
/**
* Remove all debug items from l2world.
*/
public void clearDebugItems()
{
if (_debugItems != null)
{
final Iterator<L2ItemInstance> it = _debugItems.iterator();
while (it.hasNext())
{
final L2ItemInstance item = it.next();
if (item != null)
{
item.decayMe();
}
it.remove();
}
}
}
public ZoneRegion getRegion(int x, int y)
{
return _zoneRegions[(x >> SHIFT_BY) + OFFSET_X][(y >> SHIFT_BY) + OFFSET_Y];
}
public ZoneRegion getRegion(ILocational point)
{
return getRegion(point.getX(), point.getY());
}
/**
* Gets the settings.
* @param name the name
* @return the settings
*/
public static AbstractZoneSettings getSettings(String name)
{
return SETTINGS.get(name);
}
/**
* Gets the single instance of ZoneManager.
* @return single instance of ZoneManager
*/
public static ZoneManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final ZoneManager _instance = new ZoneManager();
}
}

View File

@ -0,0 +1,31 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager.tasks;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
/**
* @author xban1x
*/
public class GrandBossManagerStoreTask implements Runnable
{
@Override
public void run()
{
GrandBossManager.getInstance().storeMe();
}
}

View File

@ -0,0 +1,86 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager.tasks;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.entity.Message;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* Message deletion task.
* @author xban1x
*/
public final class MessageDeletionTask implements Runnable
{
private static final Logger _log = Logger.getLogger(MessageDeletionTask.class.getName());
final int _msgId;
public MessageDeletionTask(int msgId)
{
_msgId = msgId;
}
@Override
public void run()
{
final Message msg = MailManager.getInstance().getMessage(_msgId);
if (msg == null)
{
return;
}
if (msg.hasAttachments())
{
try
{
final L2PcInstance sender = L2World.getInstance().getPlayer(msg.getSenderId());
if (sender != null)
{
msg.getAttachments().returnToWh(sender.getWarehouse());
sender.sendPacket(SystemMessageId.THE_MAIL_WAS_RETURNED_DUE_TO_THE_EXCEEDED_WAITING_TIME);
}
else
{
msg.getAttachments().returnToWh(null);
}
msg.getAttachments().deleteMe();
msg.removeAttachments();
final L2PcInstance receiver = L2World.getInstance().getPlayer(msg.getReceiverId());
if (receiver != null)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.THE_MAIL_WAS_RETURNED_DUE_TO_THE_EXCEEDED_WAITING_TIME);
// sm.addString(msg.getReceiverName());
receiver.sendPacket(sm);
}
}
catch (Exception e)
{
_log.log(Level.WARNING, getClass().getSimpleName() + ": Error returning items:" + e.getMessage(), e);
}
}
MailManager.getInstance().deleteMessageInDb(msg.getId());
}
}

View File

@ -0,0 +1,39 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager.tasks;
import com.l2jmobius.gameserver.instancemanager.HandysBlockCheckerManager;
/**
* Handys Block Checker penalty remove.
* @author xban1x
*/
public final class PenaltyRemoveTask implements Runnable
{
private final int _objectId;
public PenaltyRemoveTask(int id)
{
_objectId = id;
}
@Override
public void run()
{
HandysBlockCheckerManager.getInstance().removePenalty(_objectId);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager.tasks;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.model.actor.L2Npc;
/**
* Task which starts npc movement.
* @author xban1x
*/
public final class StartMovingTask implements Runnable
{
final L2Npc _npc;
final String _routeName;
public StartMovingTask(L2Npc npc, String routeName)
{
_npc = npc;
_routeName = routeName;
}
@Override
public void run()
{
if (_npc != null)
{
WalkingManager.getInstance().startMoving(_npc, _routeName);
}
}
}

View File

@ -0,0 +1,34 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager.tasks;
import com.l2jmobius.gameserver.instancemanager.GraciaSeedsManager;
/**
* Task which updates Seed of Destruction state.
* @author xban1x
*/
public final class UpdateSoDStateTask implements Runnable
{
@Override
public void run()
{
final GraciaSeedsManager manager = GraciaSeedsManager.getInstance();
manager.setSoDState(1, true);
manager.updateSodState();
}
}