Renamed trunk folder.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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.client.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.L2JMOD_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)
|
||||
{
|
||||
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.L2JMOD_DUALBOX_CHECK_WHITELIST.containsKey(addrHash))
|
||||
{
|
||||
limit += Config.L2JMOD_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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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.toString());
|
||||
}
|
||||
}
|
||||
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.toString() + "!");
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
* 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.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)
|
||||
private 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)
|
||||
private void OnPlayerLogin(OnPlayerLogin event)
|
||||
{
|
||||
if (getState() == CeremonyOfChaosState.REGISTRATION)
|
||||
{
|
||||
final L2PcInstance player = event.getActiveChar();
|
||||
if (canRegister(player, false))
|
||||
{
|
||||
player.sendPacket(ExCuriousHouseState.REGISTRATION_PACKET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterEvent(EventType.ON_PLAYER_LOGOUT)
|
||||
@RegisterType(ListenerRegisterType.GLOBAL_PLAYERS)
|
||||
private 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* 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 = ? 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")));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
return _waitingList.put(playerId, info) != null;
|
||||
}
|
||||
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.executeUpdate();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
return _clanList.put(clanId, info) != null;
|
||||
}
|
||||
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.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();
|
||||
}
|
||||
}
|
||||
@@ -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 final ClanHallAuctionManager getInstance()
|
||||
{
|
||||
return SingletonHolder.INSTANCE;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final ClanHallAuctionManager INSTANCE = new ClanHallAuctionManager();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
* 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()
|
||||
{
|
||||
_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().getSpawns(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();
|
||||
if (!_spawns.containsKey(npcId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnTable.getInstance().deleteSpawn(spawn, false);
|
||||
_spawns.remove(npcId);
|
||||
|
||||
if (_npcs.containsKey(npcId))
|
||||
{
|
||||
_npcs.remove(npcId);
|
||||
}
|
||||
|
||||
if (_schedules.containsKey(npcId))
|
||||
{
|
||||
final ScheduledFuture<?> f = _schedules.remove(npcId);
|
||||
f.cancel(true);
|
||||
}
|
||||
|
||||
if (_storedInfo.containsKey(npcId))
|
||||
{
|
||||
_storedInfo.remove(npcId);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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.Calendar;
|
||||
|
||||
import com.l2jmobius.Config;
|
||||
import com.l2jmobius.commons.database.DatabaseFactory;
|
||||
import com.l2jmobius.gameserver.model.L2World;
|
||||
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
|
||||
|
||||
/**
|
||||
* @author Mobius
|
||||
*/
|
||||
public class PremiumManager
|
||||
{
|
||||
private long endDate = 0;
|
||||
|
||||
public long getPremiumEndDate(String accountName)
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection())
|
||||
{
|
||||
final PreparedStatement statement = con.prepareStatement("SELECT premium_service,enddate FROM account_premium WHERE account_name=?");
|
||||
statement.setString(1, accountName);
|
||||
final ResultSet rset = statement.executeQuery();
|
||||
while (rset.next())
|
||||
{
|
||||
if (Config.PREMIUM_SYSTEM_ENABLED)
|
||||
{
|
||||
endDate = rset.getLong("enddate");
|
||||
if (endDate <= System.currentTimeMillis())
|
||||
{
|
||||
endDate = 0;
|
||||
removePremiumStatus(accountName);
|
||||
}
|
||||
}
|
||||
}
|
||||
statement.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void updatePremiumData(int months, String accountName)
|
||||
{
|
||||
long remainingTime = getPremiumEndDate(accountName);
|
||||
if (remainingTime > 0)
|
||||
{
|
||||
remainingTime -= System.currentTimeMillis();
|
||||
}
|
||||
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection())
|
||||
{
|
||||
final Calendar endDate = Calendar.getInstance();
|
||||
endDate.setTimeInMillis(System.currentTimeMillis() + remainingTime);
|
||||
endDate.set(Calendar.SECOND, 0);
|
||||
endDate.add(Calendar.MONTH, months);
|
||||
|
||||
final PreparedStatement statement = con.prepareStatement("UPDATE account_premium SET premium_service=?,enddate=? WHERE account_name=?");
|
||||
statement.setInt(1, 1);
|
||||
statement.setLong(2, endDate.getTimeInMillis());
|
||||
statement.setString(3, accountName);
|
||||
statement.execute();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
}
|
||||
|
||||
for (L2PcInstance player : L2World.getInstance().getPlayers())
|
||||
{
|
||||
if (player.getAccountNamePlayer().equalsIgnoreCase(accountName))
|
||||
{
|
||||
player.setPremiumStatus(getPremiumEndDate(accountName) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removePremiumStatus(String accountName)
|
||||
{
|
||||
// TODO: Add check if account exists. XD
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection())
|
||||
{
|
||||
final PreparedStatement statement = con.prepareStatement("INSERT INTO account_premium (account_name,premium_service,enddate) values(?,?,?) ON DUPLICATE KEY UPDATE premium_service = ?, enddate = ?");
|
||||
statement.setString(1, accountName);
|
||||
statement.setInt(2, 0);
|
||||
statement.setLong(3, 0);
|
||||
statement.setInt(4, 0);
|
||||
statement.setLong(5, 0);
|
||||
statement.execute();
|
||||
statement.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
}
|
||||
|
||||
for (L2PcInstance player : L2World.getInstance().getPlayers())
|
||||
{
|
||||
if (player.getAccountNamePlayer().equalsIgnoreCase(accountName))
|
||||
{
|
||||
player.setPremiumStatus(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static PremiumManager getInstance()
|
||||
{
|
||||
return SingletonHolder._instance;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final PremiumManager _instance = new PremiumManager();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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 final SellBuffsManager getInstance()
|
||||
{
|
||||
return SingletonHolder._instance;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final SellBuffsManager _instance = new SellBuffsManager();
|
||||
}
|
||||
}
|
||||
@@ -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().toString() + ".");
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,495 @@
|
||||
/*
|
||||
* 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:
|
||||
// 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 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();
|
||||
byte repeatType;
|
||||
if (repeatStyle.equalsIgnoreCase("back"))
|
||||
{
|
||||
repeatType = REPEAT_GO_BACK;
|
||||
}
|
||||
else if (repeatStyle.equalsIgnoreCase("cycle"))
|
||||
{
|
||||
repeatType = REPEAT_GO_FIRST;
|
||||
}
|
||||
else if (repeatStyle.equalsIgnoreCase("conveyor"))
|
||||
{
|
||||
repeatType = REPEAT_TELE_FIRST;
|
||||
}
|
||||
else if (repeatStyle.equalsIgnoreCase("random"))
|
||||
{
|
||||
repeatType = REPEAT_RANDOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
repeatType = -1;
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
if (!walk.calculateNextNode(npc))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
if (_activeRoutes.containsKey(npc.getObjectId()))
|
||||
{
|
||||
if (node.getDelay() > 0)
|
||||
{
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new ArrivedTask(npc, walk), node.getDelay() * 1000L);
|
||||
}
|
||||
else
|
||||
{
|
||||
walk.setBlocked(false);
|
||||
WalkingManager.getInstance().startMoving(npc, walk.getRoute().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,574 @@
|
||||
/*
|
||||
* 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.games;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Calendar;
|
||||
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.model.items.instance.L2ItemInstance;
|
||||
import com.l2jmobius.gameserver.network.SystemMessageId;
|
||||
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
|
||||
import com.l2jmobius.gameserver.util.Broadcast;
|
||||
|
||||
public class Lottery
|
||||
{
|
||||
public static final long SECOND = 1000;
|
||||
public static final long MINUTE = 60000;
|
||||
|
||||
protected static final Logger _log = Logger.getLogger(Lottery.class.getName());
|
||||
|
||||
private static final String INSERT_LOTTERY = "INSERT INTO games(id, idnr, enddate, prize, newprize) VALUES (?, ?, ?, ?, ?)";
|
||||
private static final String UPDATE_PRICE = "UPDATE games SET prize=?, newprize=? WHERE id = 1 AND idnr = ?";
|
||||
private static final String UPDATE_LOTTERY = "UPDATE games SET finished=1, prize=?, newprize=?, number1=?, number2=?, prize1=?, prize2=?, prize3=? WHERE id=1 AND idnr=?";
|
||||
private static final String SELECT_LAST_LOTTERY = "SELECT idnr, prize, newprize, enddate, finished FROM games WHERE id = 1 ORDER BY idnr DESC LIMIT 1";
|
||||
private static final String SELECT_LOTTERY_ITEM = "SELECT enchant_level, custom_type2 FROM items WHERE item_id = 4442 AND custom_type1 = ?";
|
||||
private static final String SELECT_LOTTERY_TICKET = "SELECT number1, number2, prize1, prize2, prize3 FROM games WHERE id = 1 and idnr = ?";
|
||||
|
||||
protected int _number;
|
||||
protected long _prize;
|
||||
protected boolean _isSellingTickets;
|
||||
protected boolean _isStarted;
|
||||
protected long _enddate;
|
||||
|
||||
protected Lottery()
|
||||
{
|
||||
_number = 1;
|
||||
_prize = Config.ALT_LOTTERY_PRIZE;
|
||||
_isSellingTickets = false;
|
||||
_isStarted = false;
|
||||
_enddate = System.currentTimeMillis();
|
||||
|
||||
if (Config.ALLOW_LOTTERY)
|
||||
{
|
||||
(new startLottery()).run();
|
||||
}
|
||||
}
|
||||
|
||||
public static Lottery getInstance()
|
||||
{
|
||||
return SingletonHolder._instance;
|
||||
}
|
||||
|
||||
public int getId()
|
||||
{
|
||||
return _number;
|
||||
}
|
||||
|
||||
public long getPrize()
|
||||
{
|
||||
return _prize;
|
||||
}
|
||||
|
||||
public long getEndDate()
|
||||
{
|
||||
return _enddate;
|
||||
}
|
||||
|
||||
public void increasePrize(long count)
|
||||
{
|
||||
_prize += count;
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement(UPDATE_PRICE))
|
||||
{
|
||||
ps.setLong(1, getPrize());
|
||||
ps.setLong(2, getPrize());
|
||||
ps.setInt(3, getId());
|
||||
ps.execute();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
_log.log(Level.WARNING, "Lottery: Could not increase current lottery prize: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSellableTickets()
|
||||
{
|
||||
return _isSellingTickets;
|
||||
}
|
||||
|
||||
public boolean isStarted()
|
||||
{
|
||||
return _isStarted;
|
||||
}
|
||||
|
||||
private class startLottery implements Runnable
|
||||
{
|
||||
protected startLottery()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
Statement statement = con.createStatement();
|
||||
ResultSet rset = statement.executeQuery(SELECT_LAST_LOTTERY))
|
||||
{
|
||||
if (rset.next())
|
||||
{
|
||||
_number = rset.getInt("idnr");
|
||||
|
||||
if (rset.getInt("finished") == 1)
|
||||
{
|
||||
_number++;
|
||||
_prize = rset.getLong("newprize");
|
||||
}
|
||||
else
|
||||
{
|
||||
_prize = rset.getLong("prize");
|
||||
_enddate = rset.getLong("enddate");
|
||||
|
||||
if (_enddate <= (System.currentTimeMillis() + (2 * MINUTE)))
|
||||
{
|
||||
(new finishLottery()).run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_enddate > System.currentTimeMillis())
|
||||
{
|
||||
_isStarted = true;
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new finishLottery(), _enddate - System.currentTimeMillis());
|
||||
|
||||
if (_enddate > (System.currentTimeMillis() + (12 * MINUTE)))
|
||||
{
|
||||
_isSellingTickets = true;
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new stopSellingTickets(), _enddate - System.currentTimeMillis() - (10 * MINUTE));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
_log.log(Level.WARNING, "Lottery: Could not restore lottery data: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: Starting ticket sell for lottery #" + getId() + ".");
|
||||
}
|
||||
_isSellingTickets = true;
|
||||
_isStarted = true;
|
||||
|
||||
Broadcast.toAllOnlinePlayers("Lottery tickets are now available for Lucky Lottery #" + getId() + ".");
|
||||
final Calendar finishtime = Calendar.getInstance();
|
||||
finishtime.setTimeInMillis(_enddate);
|
||||
finishtime.set(Calendar.MINUTE, 0);
|
||||
finishtime.set(Calendar.SECOND, 0);
|
||||
|
||||
if (finishtime.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
|
||||
{
|
||||
finishtime.set(Calendar.HOUR_OF_DAY, 19);
|
||||
_enddate = finishtime.getTimeInMillis();
|
||||
_enddate += 604800000;
|
||||
}
|
||||
else
|
||||
{
|
||||
finishtime.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
|
||||
finishtime.set(Calendar.HOUR_OF_DAY, 19);
|
||||
_enddate = finishtime.getTimeInMillis();
|
||||
}
|
||||
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new stopSellingTickets(), _enddate - System.currentTimeMillis() - (10 * MINUTE));
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new finishLottery(), _enddate - System.currentTimeMillis());
|
||||
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement(INSERT_LOTTERY))
|
||||
{
|
||||
ps.setInt(1, 1);
|
||||
ps.setInt(2, getId());
|
||||
ps.setLong(3, getEndDate());
|
||||
ps.setLong(4, getPrize());
|
||||
ps.setLong(5, getPrize());
|
||||
ps.execute();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
_log.log(Level.WARNING, "Lottery: Could not store new lottery data: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class stopSellingTickets implements Runnable
|
||||
{
|
||||
protected stopSellingTickets()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: Stopping ticket sell for lottery #" + getId() + ".");
|
||||
}
|
||||
_isSellingTickets = false;
|
||||
|
||||
Broadcast.toAllOnlinePlayers(SystemMessage.getSystemMessage(SystemMessageId.LOTTERY_TICKET_SALES_HAVE_BEEN_TEMPORARILY_SUSPENDED));
|
||||
}
|
||||
}
|
||||
|
||||
private class finishLottery implements Runnable
|
||||
{
|
||||
protected finishLottery()
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: Ending lottery #" + getId() + ".");
|
||||
}
|
||||
|
||||
final int[] luckynums = new int[5];
|
||||
int luckynum = 0;
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
boolean found = true;
|
||||
|
||||
while (found)
|
||||
{
|
||||
luckynum = Rnd.get(20) + 1;
|
||||
found = false;
|
||||
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
if (luckynums[j] == luckynum)
|
||||
{
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
luckynums[i] = luckynum;
|
||||
}
|
||||
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: The lucky numbers are " + luckynums[0] + ", " + luckynums[1] + ", " + luckynums[2] + ", " + luckynums[3] + ", " + luckynums[4] + ".");
|
||||
}
|
||||
|
||||
int enchant = 0;
|
||||
int type2 = 0;
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (luckynums[i] < 17)
|
||||
{
|
||||
enchant += Math.pow(2, luckynums[i] - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
type2 += Math.pow(2, luckynums[i] - 17);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: Encoded lucky numbers are " + enchant + ", " + type2);
|
||||
}
|
||||
|
||||
int count1 = 0;
|
||||
int count2 = 0;
|
||||
int count3 = 0;
|
||||
int count4 = 0;
|
||||
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement(SELECT_LOTTERY_ITEM))
|
||||
{
|
||||
ps.setInt(1, getId());
|
||||
try (ResultSet rset = ps.executeQuery())
|
||||
{
|
||||
while (rset.next())
|
||||
{
|
||||
int curenchant = rset.getInt("enchant_level") & enchant;
|
||||
int curtype2 = rset.getInt("custom_type2") & type2;
|
||||
|
||||
if ((curenchant == 0) && (curtype2 == 0))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 1; i <= 16; i++)
|
||||
{
|
||||
final int val = curenchant / 2;
|
||||
|
||||
if (val != Math.round((double) curenchant / 2))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
final int val2 = curtype2 / 2;
|
||||
|
||||
if (val2 != ((double) curtype2 / 2))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
curenchant = val;
|
||||
curtype2 = val2;
|
||||
}
|
||||
|
||||
if (count == 5)
|
||||
{
|
||||
count1++;
|
||||
}
|
||||
else if (count == 4)
|
||||
{
|
||||
count2++;
|
||||
}
|
||||
else if (count == 3)
|
||||
{
|
||||
count3++;
|
||||
}
|
||||
else if (count > 0)
|
||||
{
|
||||
count4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
_log.log(Level.WARNING, "Lottery: Could restore lottery data: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
final long prize4 = count4 * Config.ALT_LOTTERY_2_AND_1_NUMBER_PRIZE;
|
||||
long prize1 = 0;
|
||||
long prize2 = 0;
|
||||
long prize3 = 0;
|
||||
|
||||
if (count1 > 0)
|
||||
{
|
||||
prize1 = (long) (((getPrize() - prize4) * Config.ALT_LOTTERY_5_NUMBER_RATE) / count1);
|
||||
}
|
||||
|
||||
if (count2 > 0)
|
||||
{
|
||||
prize2 = (long) (((getPrize() - prize4) * Config.ALT_LOTTERY_4_NUMBER_RATE) / count2);
|
||||
}
|
||||
|
||||
if (count3 > 0)
|
||||
{
|
||||
prize3 = (long) (((getPrize() - prize4) * Config.ALT_LOTTERY_3_NUMBER_RATE) / count3);
|
||||
}
|
||||
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: " + count1 + " players with all FIVE numbers each win " + prize1 + ".");
|
||||
_log.info("Lottery: " + count2 + " players with FOUR numbers each win " + prize2 + ".");
|
||||
_log.info("Lottery: " + count3 + " players with THREE numbers each win " + prize3 + ".");
|
||||
_log.info("Lottery: " + count4 + " players with ONE or TWO numbers each win " + prize4 + ".");
|
||||
}
|
||||
|
||||
final long newprize = getPrize() - (prize1 + prize2 + prize3 + prize4);
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.info("Lottery: Jackpot for next lottery is " + newprize + ".");
|
||||
}
|
||||
|
||||
SystemMessage sm;
|
||||
if (count1 > 0)
|
||||
{
|
||||
// There are winners.
|
||||
sm = SystemMessage.getSystemMessage(SystemMessageId.THE_PRIZE_AMOUNT_FOR_THE_WINNER_OF_LOTTERY_S1_IS_S2_ADENA_WE_HAVE_S3_FIRST_PRIZE_WINNERS);
|
||||
sm.addInt(getId());
|
||||
sm.addLong(getPrize());
|
||||
sm.addLong(count1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are no winners.
|
||||
sm = SystemMessage.getSystemMessage(SystemMessageId.THE_PRIZE_AMOUNT_FOR_LUCKY_LOTTERY_S1_IS_S2_ADENA_THERE_WAS_NO_FIRST_PRIZE_WINNER_IN_THIS_DRAWING_THEREFORE_THE_JACKPOT_WILL_BE_ADDED_TO_THE_NEXT_DRAWING);
|
||||
sm.addInt(getId());
|
||||
sm.addLong(getPrize());
|
||||
}
|
||||
Broadcast.toAllOnlinePlayers(sm);
|
||||
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement(UPDATE_LOTTERY))
|
||||
{
|
||||
ps.setLong(1, getPrize());
|
||||
ps.setLong(2, newprize);
|
||||
ps.setInt(3, enchant);
|
||||
ps.setInt(4, type2);
|
||||
ps.setLong(5, prize1);
|
||||
ps.setLong(6, prize2);
|
||||
ps.setLong(7, prize3);
|
||||
ps.setInt(8, getId());
|
||||
ps.execute();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
_log.log(Level.WARNING, "Lottery: Could not store finished lottery data: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
ThreadPoolManager.getInstance().scheduleGeneral(new startLottery(), MINUTE);
|
||||
_number++;
|
||||
|
||||
_isStarted = false;
|
||||
}
|
||||
}
|
||||
|
||||
public int[] decodeNumbers(int enchant, int type2)
|
||||
{
|
||||
final int res[] = new int[5];
|
||||
int id = 0;
|
||||
int nr = 1;
|
||||
|
||||
while (enchant > 0)
|
||||
{
|
||||
final int val = enchant / 2;
|
||||
if (val != Math.round((double) enchant / 2))
|
||||
{
|
||||
res[id++] = nr;
|
||||
}
|
||||
enchant /= 2;
|
||||
nr++;
|
||||
}
|
||||
|
||||
nr = 17;
|
||||
|
||||
while (type2 > 0)
|
||||
{
|
||||
final int val = type2 / 2;
|
||||
if (val != ((double) type2 / 2))
|
||||
{
|
||||
res[id++] = nr;
|
||||
}
|
||||
type2 /= 2;
|
||||
nr++;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public long[] checkTicket(L2ItemInstance item)
|
||||
{
|
||||
return checkTicket(item.getCustomType1(), item.getEnchantLevel(), item.getCustomType2());
|
||||
}
|
||||
|
||||
public long[] checkTicket(int id, int enchant, int type2)
|
||||
{
|
||||
final long res[] =
|
||||
{
|
||||
0,
|
||||
0
|
||||
};
|
||||
try (Connection con = DatabaseFactory.getInstance().getConnection();
|
||||
PreparedStatement ps = con.prepareStatement(SELECT_LOTTERY_TICKET))
|
||||
{
|
||||
ps.setInt(1, id);
|
||||
try (ResultSet rs = ps.executeQuery())
|
||||
{
|
||||
if (rs.next())
|
||||
{
|
||||
int curenchant = rs.getInt("number1") & enchant;
|
||||
int curtype2 = rs.getInt("number2") & type2;
|
||||
|
||||
if ((curenchant == 0) && (curtype2 == 0))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 1; i <= 16; i++)
|
||||
{
|
||||
final int val = curenchant / 2;
|
||||
if (val != Math.round((double) curenchant / 2))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
final int val2 = curtype2 / 2;
|
||||
if (val2 != ((double) curtype2 / 2))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
curenchant = val;
|
||||
curtype2 = val2;
|
||||
}
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
res[0] = 1;
|
||||
res[1] = rs.getLong("prize1");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
res[0] = 2;
|
||||
res[1] = rs.getLong("prize2");
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
res[0] = 3;
|
||||
res[1] = rs.getLong("prize3");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
res[0] = 4;
|
||||
res[1] = 200;
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.DEBUG)
|
||||
{
|
||||
_log.warning("count: " + count + ", id: " + id + ", enchant: " + enchant + ", type2: " + type2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
_log.log(Level.WARNING, "Lottery: Could not check lottery ticket #" + id + ": " + e.getMessage(), e);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
protected static final Lottery _instance = new Lottery();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user