테스트

aion-server 4.8

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

import java.time.ZonedDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.dao.EventDAO;
import com.aionemu.gameserver.dao.EventDAO.StoredBuffData;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.model.ChatType;
import com.aionemu.gameserver.model.Race;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.team.TeamMember;
import com.aionemu.gameserver.model.team.TemporaryPlayerTeam;
import com.aionemu.gameserver.model.templates.InstanceCooltime;
import com.aionemu.gameserver.model.templates.event.Buff;
import com.aionemu.gameserver.model.templates.event.Buff.BuffMapType;
import com.aionemu.gameserver.model.templates.event.Buff.Trigger;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.skillengine.SkillEngine;
import com.aionemu.gameserver.skillengine.model.Effect;
import com.aionemu.gameserver.skillengine.model.Effect.ForceType;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.time.ServerTime;
import com.aionemu.gameserver.world.World;
import com.aionemu.gameserver.world.WorldMapInstance;

/**
 * @author Neon
 */
public class EventBuffHandler {

	private final String eventName;
	private final List<Buff> buffs;
	private final Map<Buff, Set<Integer>> activeBuffPoolSkillIds = new ConcurrentHashMap<>();
	private final Map<Buff, Set<Integer>> allowedBuffDays = new ConcurrentHashMap<>();
	private volatile int dayOfMonth = ServerTime.now().getDayOfMonth();
	private final ForceType effectForceType;

	public EventBuffHandler(String eventName, List<Buff> buffs) {
		this.eventName = eventName;
		this.buffs = buffs;
		this.effectForceType = Event.getOrCreateEffectForceType(eventName);
		initBuffData();
	}

	private void initBuffData() {
		updateActiveBuffSkillIds();
		updateAllowedBuffDays(ServerTime.now().toLocalDate().lengthOfMonth());
		List<StoredBuffData> buffData = EventDAO.loadStoredBuffData(eventName);
		if (buffData != null) {
			for (StoredBuffData storedBuffData : buffData) {
				if (storedBuffData.getBuffIndex() < buffs.size()) {
					Buff buff = buffs.get(storedBuffData.getBuffIndex());
					if (storedBuffData.getActivePoolSkillIds() != null && buff.getSkillIds().containsAll(storedBuffData.getActivePoolSkillIds()))
						activeBuffPoolSkillIds.put(buff, storedBuffData.getActivePoolSkillIds());
					if (storedBuffData.getAllowedBuffDays() != null && buff.getRestriction() != null
						&& buff.getRestriction().getRandomDaysPerMonth() == storedBuffData.getAllowedBuffDays().size())
						allowedBuffDays.put(buff, storedBuffData.getAllowedBuffDays());
				}
			}
		}
		storeBuffDataInDb();
	}

	private void updateActiveBuffSkillIds() {
		for (Buff buff : buffs) {
			if (buff.getPool() > 0)
				activeBuffPoolSkillIds.put(buff, collectNRandomElements(buff.getSkillIds(), buff.getPool()));
		}
	}

	private void updateAllowedBuffDays(int endOfMonthDay) {
		buffs.forEach(buff -> {
			int limit = buff.getRestriction() == null ? 0 : buff.getRestriction().getRandomDaysPerMonth();
			if (limit > 0 && limit < endOfMonthDay) {
				List<Integer> daysThisMonth = IntStream.rangeClosed(1, endOfMonthDay).boxed().collect(Collectors.toList());
				Set<Integer> allowedRandomDaysThisMonth = collectNRandomElements(daysThisMonth, limit);
				allowedBuffDays.put(buff, allowedRandomDaysThisMonth);
			} else {
				allowedBuffDays.remove(buff);
			}
		});
	}

	private void storeBuffDataInDb() {
		List<StoredBuffData> storedBuffData = new ArrayList<>(buffs.size());
		for (int i = 0; i < buffs.size(); i++) {
			Buff buff = buffs.get(i);
			Set<Integer> poolSkillIds = activeBuffPoolSkillIds.get(buff);
			Set<Integer> allowedDays = allowedBuffDays.get(buff);
			if (poolSkillIds != null && allowedDays != null)
				storedBuffData.add(new StoredBuffData(i, poolSkillIds, allowedDays));
		}
		EventDAO.storeBuffData(eventName, storedBuffData);
	}

	public ForceType getEffectForceType() {
		return effectForceType;
	}

	public void onTimeChanged(ZonedDateTime now) {
		int nowDayOfMonth = now.getDayOfMonth();
		if (nowDayOfMonth != dayOfMonth) {
			dayOfMonth = nowDayOfMonth;
			updateActiveBuffSkillIds();
			if (dayOfMonth == 1)
				updateAllowedBuffDays(now.toLocalDate().lengthOfMonth());
			storeBuffDataInDb();
			resetTodaysBuffs();
		}
	}

	private void resetTodaysBuffs() {
		World.getInstance().forEachPlayer(this::onEnterMap);
	}

	public void onEventStop() {
		World.getInstance().forEachPlayer(this::endEventBuffs);
	}

	public void onEnterMap(Player player) {
		endRestrictedEventBuffs(player);
		tryBuff(player, Buff.TriggerCondition.ENTER_MAP);
	}

	public void onEnteredTeam(Player player, TemporaryPlayerTeam<? extends TeamMember<Player>> team) {
		team.forEach(this::endRestrictedEventBuffs);
		tryBuff(player, Buff.TriggerCondition.ENTER_TEAM);
	}

	public void onLeftTeam(Player player, TemporaryPlayerTeam<? extends TeamMember<Player>> team) {
		endRestrictedEventBuffs(player); // player isn't in team anymore
		team.forEach(member -> {
			endRestrictedEventBuffs(member);
			// try to apply buffs since some restrictions are now maybe met (team_size_max_percent)
			buffs.forEach(buff -> tryBuff(buff, member, Buff.TriggerCondition.ENTER_TEAM));
		});
	}

	public void onPveKill(Player killer, Npc victim) {
		if (killer.getLevel() - victim.getLevel() < 10) // victim can be 9 levels below killer level
			tryBuff(killer, Buff.TriggerCondition.PVE_KILL);
	}

	public void onPvpKill(Player killer, Player victim) {
		tryBuff(killer, Buff.TriggerCondition.PVP_KILL);
	}

	private void endEventBuffs(Player player) {
		player.getEffectController().getAllEffects().forEach(effect -> {
			if (effect.getForceType() == effectForceType)
				effect.endEffect();
		});
	}

	private void endRestrictedEventBuffs(Player player) {
		player.getEffectController().getAllEffects().forEach(effect -> {
			if (effect.getForceType() == effectForceType) {
				for (Buff buff : buffs) {
					if (getActiveBuffSkillIds(buff).contains(effect.getSkillId()) && checkRestrictions(buff, player))
						return; // event effect is still valid, check next one
				}
				effect.endEffect();
			}
		});
	}

	private boolean applyOnTeam(Player player, Consumer<Player> memberAction) {
		TemporaryPlayerTeam<?> team = player.getCurrentTeam();
		if (team != null) {
			team.forEach(memberAction);
			return true;
		}
		return false;
	}

	private void tryBuff(Player player, Buff.TriggerCondition triggerCondition) {
		buffs.forEach(buff -> {
			if (!buff.isTeam() || !applyOnTeam(player, member -> tryBuff(buff, member, triggerCondition)))
				tryBuff(buff, player, triggerCondition);
		});
	}

	private void tryBuff(Buff buff, Player player, Buff.TriggerCondition triggerCondition) {
		if (canReceiveBuff(buff, player, triggerCondition)) {
			for (int skillId : getActiveBuffSkillIds(buff)) {
				if (player.getEffectController().hasAbnormalEffect(skillId))
					continue;
				Effect effect = SkillEngine.getInstance().applyEffectDirectly(skillId, player, player, buff.isPermanent() ? 0 : null, effectForceType);
				if (effect != null) {
					int msgId = 1400697; // You received %0: %1.
					SM_SYSTEM_MESSAGE message = new SM_SYSTEM_MESSAGE(ChatType.BRIGHT_YELLOW_CENTER, player, msgId, "[Server Buff]",
						effect.getSkillTemplate().getL10n());
					PacketSendUtility.sendPacket(player, message);
				}
			}
		}
	}

	private Set<Integer> getActiveBuffSkillIds(Buff buff) {
		return activeBuffPoolSkillIds.getOrDefault(buff, buff.getSkillIds());
	}

	private <T> Set<T> collectNRandomElements(Collection<T> input, int n) {
		List<T> shuffledInput = new ArrayList<>(input);
		Collections.shuffle(shuffledInput);
		Set<T> nRandomElements = new HashSet<>(n);
		for (int i = 0; i < n; i++)
			nRandomElements.add(shuffledInput.get(i));
		return nRandomElements;
	}

	private boolean canReceiveBuff(Buff buff, Player player, Buff.TriggerCondition triggerCondition) {
		Trigger trigger = findBuffTrigger(buff, triggerCondition);
		if (trigger == null)
			return false;
		if (!checkRestrictions(buff, player))
			return false;
		return trigger.getChance() == 100 || Rnd.chance() < trigger.getChance();
	}

	private Buff.Trigger findBuffTrigger(Buff buff, Buff.TriggerCondition triggerCondition) {
		for (Buff.Trigger trigger : buff.getTriggers()) {
			if (trigger.getCondition() == triggerCondition)
				return trigger;
		}
		return null;
	}

	private boolean checkRestrictions(Buff buff, Player player) {
		if (!isAllowedToday(buff, player))
			return false;
		if (!isAllowedOnCurrentMap(buff, player))
			return false;
		if (!isAllowedTeamSize(buff, player))
			return false;
		return true;
	}

	private boolean isAllowedTeamSize(Buff buff, Player player) {
		if (buff.getRestriction() == null || buff.getRestriction().getTeamSizeMaxPercent() == 0)
			return true;
		TemporaryPlayerTeam<?> team = player.getCurrentTeam();
		if (team != null) {
			int maxAllowedTeamSize = DataManager.INSTANCE_COOLTIME_DATA.getMaxMemberCount(player.getWorldId(), player.getRace());
			if (maxAllowedTeamSize == 0)
				maxAllowedTeamSize = team.getMaxMemberCount();

			if (buff.getRestriction().getTeamSizeMaxPercent() >= team.size() * 100f / maxAllowedTeamSize)
				return true;
		}
		return false;
	}

	private boolean isAllowedToday(Buff buff, Player player) {
		Set<Integer> allowedBuffDays = this.allowedBuffDays.get(buff);
		return allowedBuffDays == null || allowedBuffDays.contains(dayOfMonth);
	}

	private boolean isAllowedOnCurrentMap(Buff buff, Player player) {
		if (buff.getRestriction() == null || buff.getRestriction().getMaps() == null)
			return true;
		WorldMapInstance worldMapInstance = player.getPosition().getWorldMapInstance();
		for (BuffMapType buffMapType : buff.getRestriction().getMaps()) {
			if (buffMapType.matches(worldMapInstance)) {
				if (buffMapType == BuffMapType.WORLD_MAP)
					return true;
				if (checkInstanceLevel(player))
					return true;
			}
		}
		return false;
	}

	private boolean checkInstanceLevel(Player player) {
		// only allow if the player level is not too high (max 9 levels above the instance entry level)
		InstanceCooltime template = DataManager.INSTANCE_COOLTIME_DATA.getInstanceCooltimeByWorldId(player.getWorldId());
		if (template != null) {
			int instanceLevel = player.getRace() == Race.ELYOS ? template.getEnterMinLevelLight() : template.getEnterMinLevelDark();
			return instanceLevel == 0 || player.getLevel() - instanceLevel < 10;
		}
		return true;
	}

}

📎 첨부파일

댓글 작성 권한이 없습니다.
🏆 포인트 랭킹 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