테스트

aion-server 4.8

Gitteol
최고관리자 · 1 · 💬 0 클론/새로받기
 4.8 61f661d · 1 commits 새로받기(Pull)
game-server/src/com/aionemu/gameserver/services/SiegeService.java
package com.aionemu.gameserver.services;

import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.stream.Collectors;

import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aionemu.commons.services.CronService;
import com.aionemu.gameserver.configs.main.SiegeConfig;
import com.aionemu.gameserver.configs.schedule.SiegeSchedules;
import com.aionemu.gameserver.dao.SiegeDAO;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.gameobjects.siege.SiegeNpc;
import com.aionemu.gameserver.model.siege.*;
import com.aionemu.gameserver.model.templates.siegelocation.DoorRepairData;
import com.aionemu.gameserver.model.templates.siegelocation.DoorRepairStone;
import com.aionemu.gameserver.model.templates.spawns.SpawnGroup;
import com.aionemu.gameserver.model.templates.spawns.SpawnTemplate;
import com.aionemu.gameserver.model.templates.spawns.siegespawns.SiegeSpawnTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.*;
import com.aionemu.gameserver.services.panesterra.PanesterraService;
import com.aionemu.gameserver.services.siege.*;
import com.aionemu.gameserver.spawnengine.SpawnEngine;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.World;
import com.aionemu.gameserver.world.WorldType;

/**
 * 3.0 siege update (<a href="https://docs.google.com/document/d/1HVOw8-w9AlRp4ci0ei4iAzNaSKzAHj_xORu-qIQJFmc/edit#">3.0 Siege Docs</a>)
 *
 * @author SoulKeeper, Source, Neon, Estrayl
 */
public class SiegeService {

	private static final Logger log = LoggerFactory.getLogger("SIEGE_LOG");

	/**
	 * We should broadcast fortress status every hour Actually only an influence packet must be sent, but that doesn't matter
	 */
	private static final CronExpression SIEGE_LOCATION_STATUS_BROADCAST_SCHEDULE;

	static {
		try {
			SIEGE_LOCATION_STATUS_BROADCAST_SCHEDULE = new CronExpression("0 0 * ? * *");
		} catch (ParseException e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	/**
	 * Singleton that is loaded on the class initialization. Guys, we really do not SingletonHolder classes
	 */
	private static final SiegeService instance = new SiegeService();
	/**
	 * Map that holds fortressId to Siege. We can easily know what fortresses are under siege ATM :)
	 */
	private final Map<Integer, Siege<? extends SiegeLocation>> activeSieges = new ConcurrentHashMap<>();

	// Player list on RVR Event.
	private final AtomicBoolean isInitialized = new AtomicBoolean();
	private final Map<Integer, ArtifactLocation> artifacts;
	private final Map<Integer, FortressLocation> fortresses;
	private final Map<Integer, OutpostLocation> outposts;
	private final Map<Integer, SiegeLocation> locations;
	private AgentLocation agent;
	private Date nextStateUpdateTime;
	private Set<Player> rvrEventPlayers = new HashSet<>();

	public static SiegeService getInstance() {
		return instance;
	}

	private SiegeService() {
		if (SiegeConfig.SIEGE_ENABLED) {
			log.info("Initializing sieges...");

			// initialize current siege locations
			artifacts = DataManager.SIEGE_LOCATION_DATA.getArtifacts();
			fortresses = DataManager.SIEGE_LOCATION_DATA.getFortress();
			outposts = DataManager.SIEGE_LOCATION_DATA.getOutpost();
			locations = DataManager.SIEGE_LOCATION_DATA.getSiegeLocations();
			agent = DataManager.SIEGE_LOCATION_DATA.getAgentLoc();
			SiegeDAO.loadSiegeLocations(locations);
		} else {
			artifacts = Collections.emptyMap();
			fortresses = Collections.emptyMap();
			outposts = Collections.emptyMap();
			locations = Collections.emptyMap();
			log.info("Sieges are disabled in config.");
		}
	}

	private void updateNextStateUpdateTime() {
		nextStateUpdateTime = SIEGE_LOCATION_STATUS_BROADCAST_SCHEDULE.getTimeAfter(new Date());
	}

	public void initSieges() {
		if (!isInitialized.compareAndSet(false, true) || !SiegeConfig.SIEGE_ENABLED)
			return;

		// despawn all NPCs spawned by spawn engine.
		// Siege spawns should be controlled by siege service
		for (Integer i : getSiegeLocations().keySet()) {
			deSpawnNpcs(i);
		}

		// spawn fortress common npcs
		for (FortressLocation f : getFortresses().values()) {
			spawnNpcs(f.getLocationId(), f.getRace(), SiegeModType.PEACE);
		}

		// spawn outpost protectors...
		for (OutpostLocation o : getOutposts().values()) {
			spawnNpcs(o.getLocationId(), o.getRace(), SiegeModType.PEACE);
		}

		// spawn artifacts
		for (ArtifactLocation a : getStandaloneArtifacts()) {
			spawnNpcs(a.getLocationId(), a.getRace(), SiegeModType.PEACE);
		}

		// initialize siege schedule
		SiegeSchedules siegeSchedules = SiegeSchedules.load();

		// Schedule fortresses sieges protector spawn
		for (SiegeSchedules.Fortress f : siegeSchedules.getFortresses()) {
			for (String siegeTime : f.getSiegeTimes()) {
				String preparationCron = getPreparationCronString(siegeTime, f.getId());
				CronService.getInstance().schedule(new SiegeStartRunnable(f.getId()), preparationCron);
				log.debug("Scheduled siege of fortressID {} based on cron expression: {}", f.getId(), preparationCron);
			}
		}

		// Schedule agent fights
		for (SiegeSchedules.AgentFight a : siegeSchedules.getAgentFights()) {
			for (String siegeTime : a.getSiegeTimes()) {
				CronService.getInstance().schedule(new SiegeStartRunnable(a.getId()), siegeTime);
				log.debug("Scheduled agent fight based on cron expression: {}", siegeTime);
			}
		}

		// Start siege of artifacts
		for (ArtifactLocation artifact : artifacts.values()) {
			if (artifact.isStandAlone()) {
				log.debug("Starting siege of artifact #" + artifact.getLocationId());
				startSiege(artifact.getLocationId());
			} else {
				log.debug("Artifact #{} siege was not started, it belongs to fortress", artifact.getLocationId());
			}
		}

		// We should set valid next state for fortress on startup. No need to broadcast state here, no players @ server ATM
		updateNextStateUpdateTime();
		updateFortressNextState();

		// Schedule siege status broadcast (every hour)
		CronService.getInstance().schedule(() -> {
			updateNextStateUpdateTime();
			updateFortressNextState();
			World.getInstance().forEachPlayer(player -> {
				for (FortressLocation fortress : getFortresses().values())
					PacketSendUtility.sendPacket(player, new SM_FORTRESS_INFO(fortress.getLocationId(), false));

				PacketSendUtility.sendPacket(player, new SM_FORTRESS_STATUS());

				for (FortressLocation fortress : getFortresses().values())
					PacketSendUtility.sendPacket(player, new SM_FORTRESS_INFO(fortress.getLocationId(), true));
			});
		}, SIEGE_LOCATION_STATUS_BROADCAST_SCHEDULE);
		log.debug("Broadcasting Siege Location status based on expression: {}", SIEGE_LOCATION_STATUS_BROADCAST_SCHEDULE);
	}

	public void checkSiegeStart(final int locationId) {
		if (agent.getLocationId() == locationId)
			startSiege(locationId);
		else
			startPreparations(locationId);
	}

	private void startPreparations(final int locationId) {
		log.debug("Starting preparations of siege Location:{}", locationId);
		FortressLocation loc = getFortress(locationId);
		// Set siege start timer..
		ThreadPoolManager.getInstance().schedule(() -> startSiege(locationId), 300 * 1000);
		if (loc.getTemplate().getMaxOccupyCount() > 0 && loc.getOccupiedCount() >= loc.getTemplate().getMaxOccupyCount()
			&& !loc.getRace().equals(SiegeRace.BALAUR)) {
			log.debug("Resetting fortress to balaur control due to exceeded occupy count! locId:{}", locationId);
			resetSiegeLocation(loc);
		}
		// TODO:
		if (locationId > 10000) { // Panesterra
			PanesterraService.getInstance().prepareFortressSiege(loc);
		}
	}

	public synchronized void startSiege(final int siegeLocationId) {
		log.debug("Starting siege of siege location: " + siegeLocationId);

		// Siege should not be started two times
		if (activeSieges.containsKey(siegeLocationId)) {
			log.error("Attempt to start siege twice for siege location: " + siegeLocationId, new Exception());
			return;
		}
		Siege<? extends SiegeLocation> siege = newSiege(siegeLocationId);
		activeSieges.put(siegeLocationId, siege);

		siege.startSiege();

		// certain sieges are endless
		// should end only manually on siege boss death
		if (siege.isEndless())
			return;

		// schedule siege end
		ThreadPoolManager.getInstance().schedule(() -> stopSiege(siegeLocationId), siege.getSiegeLocation().getSiegeDuration() * 1000L);
	}

	public synchronized void stopSiege(int siegeLocationId) {
		log.debug("Stopping siege of siege location: {}", siegeLocationId);

		Siege<? extends SiegeLocation> siege = activeSieges.remove(siegeLocationId);
		if (siege == null) {
			log.debug("Siege of siege location {} is not in progress, it was captured earlier?", siegeLocationId);
			return;
		}
		if (siege.isFinished())
			return;
		siege.stopSiege();
	}

	/**
	 * Used to capture fortresses or artifacts without regular siege
	 */
	public synchronized void captureSiege(SiegeRace sr, int legionId, int locId) {
		SiegeLocation loc = getSiegeLocation(locId);
		Siege<?> s = getSiege(locId);
		if (s != null) {
			s.getSiegeCounter().addRaceDamage(sr, s.getBoss().getLifeStats().getMaxHp() + 1);
			s.setBossKilled(true);
			stopSiege(locId);
			loc.setLegionId(legionId);
		} else {
			deSpawnNpcs(locId);
			loc.setVulnerable(false);
			loc.setUnderShield(false);
			loc.setRace(sr);
			loc.setLegionId(legionId);
			spawnNpcs(locId, sr, SiegeModType.PEACE);
			SiegeDAO.updateSiegeLocation(loc);
			switch (locId) {
				case 2011:
				case 2021:
				case 3011:
				case 3021:
					updateOutpostSiegeState((FortressLocation) loc);
					break;
			}
		}
		broadcastUpdate(loc);
	}

	/*
	 * Return location to balaur control
	 */
	private synchronized void resetSiegeLocation(SiegeLocation loc) {
		// Despawn old npc
		deSpawnNpcs(loc.getLocationId());
		loc.clearLocation(); // remove all players
		// Store old owner for msg
		int oldOwnerRaceId = loc.getRace().getRaceId();
		int legionId = loc.getLegionId();
		String legionName = legionId != 0 ? LegionService.getInstance().getLegion(legionId).getName() : "";
		String locL10n = loc.getTemplate().getL10n();

		// Reset owner
		loc.setRace(SiegeRace.BALAUR);
		loc.setLegionId(0);

		if (loc instanceof FortressLocation) {
			ArtifactLocation artifact = getFortressArtifact(loc.getLocationId());
			if (artifact != null) {
				artifact.setRace(SiegeRace.BALAUR);
				artifact.setLegionId(0);
			}
		}
		loc.setOccupiedCount(0);

		// On start preparations msg
		World.getInstance().forEachPlayer(player -> {
			if (legionId != 0 && player.getRace().getRaceId() == oldOwnerRaceId)
				PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_ABYSS_GUILD_CASTLE_TAKEN(legionName, locL10n));
			PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_ABYSS_WIN_CASTLE(loc.getRace().getL10n(), locL10n));
			PacketSendUtility.sendPacket(player, new SM_SIEGE_LOCATION_INFO(loc));
		});

		broadcastUpdate(loc);

		// Spawn new npc
		spawnNpcs(loc.getLocationId(), SiegeRace.BALAUR, SiegeModType.PEACE);

		SiegeDAO.updateSiegeLocation(loc);
	}

	/**
	 * Updates next state for fortresses
	 */
	private void updateFortressNextState() {
		Map<Integer, Date> startDatesByLocId = collectNextSiegeStartDates();
		// update each fortress next state
		for (Map.Entry<Integer, Date> entry : startDatesByLocId.entrySet()) {
			// update fortress state that will be valid within the next hour
			SiegeLocation fortress = getSiegeLocation(entry.getKey());
			if (!entry.getValue().after(nextStateUpdateTime)) // date is > now and <= next update time (this check also accounts for the preparation time)
				fortress.setNextState(SiegeLocation.STATE_VULNERABLE);
			else
				fortress.setNextState(SiegeLocation.STATE_INVULNERABLE);
		}
	}

	private Map<Integer, Date> collectNextSiegeStartDates() {
		Map<SiegeStartRunnable, Date> dates = CronService.getInstance().findNextFireTimes(SiegeStartRunnable.class, true);
		Map<Integer, Date> nextSiegeStartDates = new HashMap<>(dates.size());
		for (Map.Entry<SiegeStartRunnable, Date> entry : dates.entrySet()) {
			nextSiegeStartDates.compute(entry.getKey().getLocationId(), (k, oldDate) -> {
				Date date = entry.getValue();
				if (oldDate == null || oldDate.after(date))
					return date;
				return oldDate;
			});
		}
		return nextSiegeStartDates;
	}

	/**
	 * @return Number of seconds until fortress.getNextState() will be the current state (max. 3600 since states update every hour).
	 */
	public int getSecondsUntilNextFortressState() {
		if (nextStateUpdateTime == null) // null if siege service is deactivated
			return 0;
		return (int) (nextStateUpdateTime.getTime() - System.currentTimeMillis()) / 1000;
	}

	public int getRemainingSiegeTimeInSeconds(int siegeLocationId) {
		Siege<? extends SiegeLocation> siege = getSiege(siegeLocationId);
		if (siege == null || siege.isFinished() || !siege.isStarted())
			return 0;

		long endTime = siege.getStartTime() / 1000 + siege.getSiegeLocation().getSiegeDuration();
		int secondsLeft = (int) (endTime - System.currentTimeMillis() / 1000);

		return Math.max(secondsLeft, 0);
	}

	public Siege<? extends SiegeLocation> getSiege(SiegeLocation loc) {
		return getSiege(loc.getLocationId());
	}

	public Siege<? extends SiegeLocation> getSiege(int siegeLocationId) {
		return activeSieges.get(siegeLocationId);
	}

	public boolean isSiegeInProgress(int fortressId) {
		return activeSieges.containsKey(fortressId);
	}

	public Map<Integer, OutpostLocation> getOutposts() {
		return outposts;
	}

	public OutpostLocation getOutpost(int id) {
		return outposts.get(id);
	}

	public Map<Integer, FortressLocation> getFortresses() {
		return fortresses;
	}

	public FortressLocation getFortress(int id) {
		return fortresses.get(id);
	}

	public Map<Integer, ArtifactLocation> getArtifacts() {
		return artifacts;
	}

	public ArtifactLocation getArtifact(int id) {
		return getArtifacts().get(id);
	}

	public List<ArtifactLocation> getStandaloneArtifacts() {
		return artifacts.values().stream().filter(ArtifactLocation::isStandAlone).collect(Collectors.toList());
	}

	public ArtifactLocation getFortressArtifact(int siegeLocId) {
		ArtifactLocation loc = getArtifact(siegeLocId);
		return loc == null || loc.getOwningFortress() == null ? null : loc;
	}

	public DoorRepairData getDoorRepairData(int siegeId) {
		FortressLocation fortressLocation = getFortress(siegeId);
		if (fortressLocation == null)
			return null;
		return fortressLocation.getTemplate().getDoorRepairData();
	}

	public DoorRepairStone getRepairStone(int siegeId, int repairStoneStaticId) {
		DoorRepairData doorRepairData = getDoorRepairData(siegeId);
		if (doorRepairData == null)
			return null;
		return doorRepairData.getRepairStone(repairStoneStaticId);
	}

	public Map<Integer, SiegeLocation> getSiegeLocations() {
		return locations;
	}

	public SiegeLocation getSiegeLocation(int id) {
		return locations.get(id);
	}

	public Map<Integer, SiegeLocation> getSiegeLocations(int worldId) {
		Map<Integer, SiegeLocation> mapLocations = new LinkedHashMap<>();
		for (SiegeLocation location : getSiegeLocations().values())
			if (location.getWorldId() == worldId)
				mapLocations.put(location.getLocationId(), location);

		return mapLocations;
	}

	public AgentLocation getAgentLocation() {
		return agent;
	}

	private Siege<? extends SiegeLocation> newSiege(int siegeLocationId) {
		if (fortresses.containsKey(siegeLocationId))
			return new FortressSiege(fortresses.get(siegeLocationId));
		else if (outposts.containsKey(siegeLocationId))
			return new OutpostSiege(outposts.get(siegeLocationId));
		else if (artifacts.containsKey(siegeLocationId))
			return new ArtifactSiege(artifacts.get(siegeLocationId));
		else if (agent != null && agent.getLocationId() == siegeLocationId)
			return new AgentSiege(agent);
		else
			throw new SiegeException("Unknown siege handler for siege location: " + siegeLocationId);
	}

	public void cleanLegionId(int legionId) {
		for (SiegeLocation loc : getSiegeLocations().values()) {
			if (loc.getLegionId() == legionId) {
				loc.setLegionId(0);
				SiegeDAO.updateSiegeLocation(loc);
			}
		}
	}

	public synchronized void updateOutpostSiegeState(FortressLocation fortressLoc) {
		for (OutpostLocation outpost : getOutposts().values()) {
			List<Integer> dependencies = outpost.getFortressDependency();
			if (!dependencies.contains(fortressLoc.getLocationId()))
				continue;
			if (dependencies.stream().anyMatch(dependency -> getSiegeLocation(dependency).isVulnerable()))
				break;

			SiegeRace validRaceForSiege = outpost.getLocationId() == 2111 ? SiegeRace.ASMODIANS : SiegeRace.ELYOS;
			boolean isSiegeAllowed = true;

			for (Integer fortressId : dependencies) {
				SiegeRace dependencyFortressRace = getFortresses().get(fortressId).getRace();
				if (validRaceForSiege != dependencyFortressRace) {
					isSiegeAllowed = false;
					break;
				}
			}

			stopSiege(outpost.getLocationId());
			deSpawnNpcs(outpost.getLocationId());

			// broadcast to all new Silentera infiltration route state
			broadcastStatusAndUpdate(outpost, outpost.isSilenteraAllowed());

			// spawn NPC's or sieges
			if (isSiegeAllowed)
				startSiege(outpost.getLocationId());
			else
				spawnNpcs(outpost.getLocationId(), outpost.getRace(), SiegeModType.PEACE);
		}
	}

	public void spawnNpcs(int siegeLocationId, SiegeRace race, SiegeModType type) {
		List<SpawnGroup> siegeSpawns = DataManager.SPAWNS_DATA.getSiegeSpawnsByLocId(siegeLocationId);
		if (siegeSpawns == null)
			return;
		for (SpawnGroup group : siegeSpawns) {
			for (SpawnTemplate template : group.getSpawnTemplates()) {
				SiegeSpawnTemplate siegetemplate = (SiegeSpawnTemplate) template;
				if (siegetemplate.getSiegeRace() == race && siegetemplate.getSiegeModType() == type) {
					SpawnEngine.spawnObject(siegetemplate, 1);
				}
			}
		}
	}

	public void deSpawnNpcs(int siegeLocationId) {
		// iterate over an array copy, since onDelete directly modifies the underlying collection
		for (Object siegeNpc : World.getInstance().getLocalSiegeNpcs(siegeLocationId).toArray())
			((SiegeNpc) siegeNpc).getController().delete();
	}

	public boolean isRespawnAllowed(Npc npc) {
		if (npc instanceof SiegeNpc) {
			FortressLocation fort = getFortress(((SiegeNpc) npc).getSiegeId());
			if (fort != null) {
				if (fort.isVulnerable())
					return false;
				else if (fort.getNextState() == SiegeLocation.STATE_VULNERABLE)
					return npc.getSpawn().getRespawnTime() < getSecondsUntilNextFortressState();
			}
		}
		return true;
	}

	public void broadcastUpdate(SiegeLocation loc) {
		Influence.getInstance().recalculateInfluence();
		SM_SIEGE_LOCATION_INFO pkt1 = new SM_SIEGE_LOCATION_INFO(loc);
		SM_INFLUENCE_RATIO pkt2 = new SM_INFLUENCE_RATIO();
		World.getInstance().forEachPlayer(player -> {
			PacketSendUtility.sendPacket(player, pkt1);
			PacketSendUtility.sendPacket(player, pkt2);
		});
	}

	public void broadcastStatusAndUpdate(OutpostLocation outpost, boolean oldSilentraState) {
		SM_SYSTEM_MESSAGE info = null;
		if (oldSilentraState != outpost.isSilenteraAllowed()) {
			if (outpost.isSilenteraAllowed())
				info = outpost.getLocationId() == 2111 ? SM_SYSTEM_MESSAGE.STR_FIELDABYSS_LIGHTUNDERPASS_SPAWN()
					: SM_SYSTEM_MESSAGE.STR_FIELDABYSS_DARKUNDERPASS_SPAWN();
			else
				info = outpost.getLocationId() == 2111 ? SM_SYSTEM_MESSAGE.STR_FIELDABYSS_LIGHTUNDERPASS_DESPAWN()
					: SM_SYSTEM_MESSAGE.STR_FIELDABYSS_DARKUNDERPASS_DESPAWN();
		}

		broadcast(new SM_RIFT_ANNOUNCE(getOutpost(3111).isSilenteraAllowed(), getOutpost(2111).isSilenteraAllowed()), info);
	}

	private void broadcast(final SM_RIFT_ANNOUNCE rift, final SM_SYSTEM_MESSAGE info) {
		World.getInstance().forEachPlayer(new Consumer<Player>() {

			@Override
			public void accept(Player player) {
				PacketSendUtility.sendPacket(player, rift);
				if (info != null && player.getWorldType().equals(WorldType.BALAUREA))
					PacketSendUtility.sendPacket(player, info);
			}

		});
	}

	public FortressLocation findFortress(int worldId, float x, float y, float z) {
		for (FortressLocation fortress : getFortresses().values()) {
			if (fortress.getWorldId() == worldId && fortress.isInsideLocation(x, y, z))
				return fortress;
		}
		return null;
	}

	public void onPlayerLogin(final Player player) {
		// not on login
		// PacketSendUtility.sendPacket(player, new SM_ABYSS_ARTIFACT_INFO(getSiegeLocations().values()));
		// PacketSendUtility.sendPacket(player, new SM_ABYSS_ARTIFACT_INFO2(getSiegeLocations().values()));

		// Chk login when teleporter is dead
		// for (FortressLocation loc : getFortresses().values()) {
		// // remove teleportation to dead teleporters
		// if (!loc.isCanTeleport(player))
		// PacketSendUtility.sendPacket(player, new SM_FORTRESS_INFO(loc.getLocationId(), false));
		// }

		// First part will be sent to all
		if (SiegeConfig.SIEGE_ENABLED) {
			PacketSendUtility.sendPacket(player, new SM_INFLUENCE_RATIO());
			PacketSendUtility.sendPacket(player, new SM_SIEGE_LOCATION_INFO());
			PacketSendUtility.sendPacket(player, new SM_AFTER_SIEGE_LOCINFO_475());
			PacketSendUtility.sendPacket(player, new SM_RIFT_ANNOUNCE(getOutpost(3111).isSilenteraAllowed(), getOutpost(2111).isSilenteraAllowed()));
		}
	}

	public void onEnterSiegeWorld(Player player) {
		// Second part only for siege world
		Map<Integer, SiegeLocation> worldLocations = new LinkedHashMap<>();
		Map<Integer, ArtifactLocation> worldArtifacts = new LinkedHashMap<>();

		for (SiegeLocation location : getSiegeLocations().values())
			if (location.getWorldId() == player.getWorldId())
				worldLocations.put(location.getLocationId(), location);

		for (ArtifactLocation artifact : getArtifacts().values())
			if (artifact.getWorldId() == player.getWorldId())
				worldArtifacts.put(artifact.getLocationId(), artifact);

		PacketSendUtility.sendPacket(player, new SM_SHIELD_EFFECT(worldLocations.values()));
		PacketSendUtility.sendPacket(player, new SM_ABYSS_ARTIFACT_INFO3(worldArtifacts.values()));
	}

	public void onAbyssPointsAdded(Player player, VisibleObject obj, int abyssPoints) {
		if (obj instanceof Player || obj instanceof SiegeNpc siegeNpc && siegeNpc.getSpawn().getSiegeModType() != SiegeModType.PEACE)
			activeSieges.values().forEach(a -> a.onAbyssPointsAdded(player, abyssPoints));
	}

	public int getSiegeIdByLocId(int locId) {
		switch (locId) {
			case 49:
			case 61:
				return 1011; // Divine Fortress
			case 36:
			case 54:
				return 1131; // Siel's Western Fortress
			case 37:
			case 55:
				return 1132; // Siel's Eastern Fortress
			case 39:
			case 56:
				return 1141; // Sulfur Archipelago
			case 44:
			case 62:
				return 1211; // Roah Fortress
			case 45:
			case 57:
			case 72:
			case 75:
				return 1221; // Krotan Refuge
			case 46:
			case 58:
			case 73:
			case 76:
				return 1231; // Kysis Fortress
			case 47:
			case 59:
			case 74:
			case 77:
				return 1241; // Miren Fortress
			case 48:
			case 60:
				return 1251; // Asteria Fortress
			case 90:
				return 2011; // Temple of Scales
			case 91:
				return 2021; // Altar of Avarice
			case 93:
				return 3011; // Vorgaltem Citadel
			case 94:
				return 3021; // Crimson Temple
			case 322:
			case 323:
			case 358:
			case 359:
				return 7011; // Wealhtheow Fortress
			case 316:
			case 317:
			case 368:
			case 369:
				return 7012; // Hero's Fall Artifact
			case 370:
			case 371:
				return 7013; // Ashen Glade Artifact
			case 372:
			case 373:
				return 7014; // Molten Cliffs Artifact
			default:
				return 0;
		}
	}

	public Set<Player> getRvrEventPlayers() {
		return rvrEventPlayers;
	}

	/**
	 * Checks if the player is in an RVR event list, if not the player is added.
	 */
	public void checkRvrEventPlayer(Player player) {
		if (player != null && !rvrEventPlayers.contains(player))
			rvrEventPlayers.add(player);
	}

	public void clearRvrEventPlayers() {
		rvrEventPlayers = new HashSet<>();
	}

	/**
	 * Modifies to original cron expression to add additional time for preparations.
	 * Five minutes for regular fortress sieges.
	 * Ten minutes for Panesterra fortress sieges.
	 */
	private String getPreparationCronString(String siegeTime, int fortressId) {
		try {
			String[] cronParts = siegeTime.split(" ");
			byte minutes = Byte.parseByte(cronParts[1]);
			byte hours = Byte.parseByte(cronParts[2]);
			minutes -= (byte) (fortressId < 10000 ? 5 : 10);
			if (minutes < 0) {
				minutes += 60;
				hours -= 1;
				if (hours < 0)
					throw new UnsupportedOperationException("Failed converting cron expression: " + siegeTime + "\nPreparation over midnight not supported.");
			}
			cronParts[1] = String.valueOf(minutes);
			cronParts[2] = String.valueOf(hours);
			return String.join(" ", cronParts);
		} catch (NumberFormatException e) {
			throw new UnsupportedOperationException("Failed converting cron expression: " + siegeTime, e);
		}
	}
}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 TOP 10
순위 닉네임 포인트
1 no_profile 타키야겐지쪽지보내기 자기소개 아이디로 검색 전체게시물 102,949
2 no_profile 동가리쪽지보내기 자기소개 아이디로 검색 전체게시물 63,733
3 no_profile 라프텔쪽지보내기 자기소개 아이디로 검색 전체게시물 51,771
4 no_profile 불멸의행복쪽지보내기 자기소개 아이디로 검색 전체게시물 36,923
5 서번트쪽지보내기 자기소개 아이디로 검색 전체게시물 35,011
6 no_profile 닥터스쪽지보내기 자기소개 아이디로 검색 전체게시물 29,470
7 no_profile 검은고양이쪽지보내기 자기소개 아이디로 검색 전체게시물 29,077
8 no_profile Revolution쪽지보내기 자기소개 아이디로 검색 전체게시물 28,199
9 no_profile 보거스쪽지보내기 자기소개 아이디로 검색 전체게시물 26,731
10 no_profile 호롤롤로쪽지보내기 자기소개 아이디로 검색 전체게시물 17,020
알림 0