Jump to content
Sign in to follow this  
Rogue

RelationChanged GF

Recommended Posts

Почему-то на осаде замка творится дичь с иконками, они рандомно добавляются. Откуда они вообще бродкастятся? Новых релейшенов для осад не добавляли в гф, а у старых такие же байткоды. Откуда клиент узнает, какого цвета делать иконку и активную/неактивную? Кроме самого релейшена ничего не пересылают. Причем на клиент для разных иконок приходят разные числа, но откуда они берутся - непонятно, набор релейшенов то не менялся.

Спойлер

XyVi1IB.png

 

Share this post


Link to post
Share on other sites
Posted (edited)

Хотя в принципе оно все верно показывается, если персы сделают что-нибудь, то иконка меняется на верную.

Но вот на самом персонаже показывается  неактивная иконка, это та, которая через юзеринфо приходит.

Спойлер

48iJY97.png

 

Edited by Rogue

Share this post


Link to post
Share on other sites

Приходят не "разные числа" а битовая маска.

Ну а копать? ищи начиная с пакета RelationChanged, где идет формирование этой маски и что с ней не так.

Еще как вариант возможно не шлется вовремя при входе/выходе в зоны или телепорте  - тут можно долго гадать.

Share this post


Link to post
Share on other sites
Posted (edited)
59 минут назад, Gaikotsu сказал:

Приходят не "разные числа" а битовая маска.

Ну а копать? ищи начиная с пакета RelationChanged, где идет формирование этой маски и что с ней не так.

Еще как вариант возможно не шлется вовремя при входе/выходе в зоны или телепорте  - тут можно долго гадать.

У меня больше подозрение закралось, что там надо всю систему релейшенов переносить. Там например появились куча левых типа 4 штук для пати и патилидера и прочие. Я так понимаю, маска собирается за счет проверки по всем этим релейшенам, которые в клиенте есть. Если проверок на эти "левые" не хватает, то маска наверное другая будет на выходе.

С другой стороны оно бы не показывало верные значки, вместо просто неактивных. Тобишь когда к нам на клиент идет релейшенченжд обычный то все в порядке. А вот когда в юзеринфо маска приходит на твоего перса, то там лажа какая-то.

Edited by Rogue

Share this post


Link to post
Share on other sites
Posted (edited)

Вообще вот смотрю на овере они просто в юзеринфо прямо делают getUserRelation на чара и не парятся. У меня же там хардкоженые конструкции по типу

		if (_activeChar.getSiegeState() == 1)
			_relation |= 0x180;
		if (_activeChar.getSiegeState() == 2)
			_relation |= 0x80;

Но вот любая попытка сделать так же терпит фиаско, ибо символ не найден)) Хотя нужные методы и импорты есть, хз че ему надо.

Edited by Rogue

Share this post


Link to post
Share on other sites
package l2p.gameserver.enums;

public enum Relation
{
	BATTLE_ZONE(1 << 0),
	PVP(1 << 1),
	PK(1 << 2),
	PARTY_MEMBER(1 << 3), // party member
	PARTY_LEADER(1 << 4), // true if is party leader
	HAS_PARTY(1 << 5), // true if is in party
	CLAN_MEMBER(1 << 6), // true if is in clan
	CLAN_LEADER(1 << 7), // true if is clan leader
	CLAN_MATE(1 << 8), // true if is in same clan
	IN_SIEGE(1 << 9), // true if in siege
	SIEGE_ATTACKER(1 << 10), // true when attacker
	SIEGE_ALLY(1 << 11), // blue siege icon, cannot have if red
	SIEGE_ENEMY(1 << 12), // true when red icon, doesn't matter with blue
	UNK_13(1 << 13),
	CLAN_WAR_1_SIDED(1 << 14), // single sword
	CLAN_WAR_2_SIDED(1 << 15), // double sword
	ALLY_MEMBER(1 << 16), // clan is in alliance
	ALLY_LEADER(1 << 17), // ally leader
	DUEL_ENEMY(1 << 18),
	TERRITORY_WAR(1 << 19), // in erritory war
	TERRITORY_WAR_ENEMY(1 << 20), // territory war enemy?
	BLOCK_CHECKER_BLUE(1 << 21), // block checker blue?
	BLOCK_CHECKER_RED(1 << 22), // block checker red?
	PVP_BLUE(1 << 23), // blue sword
	PVP_RED(1 << 24), // red sword
	PVP_MASTER(1 << 25); // blue/red sword + this = blue/red crown

	private final int _mask;

	Relation(int mask)
	{
		_mask = mask;
	}

	public int getMask()
	{
		return _mask;
	}
}
package l2p.gameserver.network.s2c;

import static l2p.gameserver.network.s2c.ExSetCompassZoneCode.ZONE_PVP_FLAG;

import java.util.ArrayList;
import java.util.List;

import l2p.gameserver.enums.ClanUnitType;
import l2p.gameserver.enums.Relation;
import l2p.gameserver.enums.TeamType;
import l2p.gameserver.managers.games.HandysBlockCheckerManager;
import l2p.gameserver.managers.games.HandysBlockCheckerManager.ArenaParticipantsHolder;
import l2p.gameserver.model.Party;
import l2p.gameserver.model.Playable;
import l2p.gameserver.model.Player;
import l2p.gameserver.model.clan.Clan;
import l2p.gameserver.model.entity.events.GlobalEvent;

public class RelationChanged extends L2GameServerPacket
{
	public static final byte SEND_ONE = (byte) 0x00;
	public static final byte SEND_DEFAULT = (byte) 0x01;
	public static final byte SEND_MULTI = (byte) 0x04;

	private RelationData _single;
	private List<RelationData> _multi;
	private byte _mask = (byte) 0x00;

	public static class RelationData
	{
		int _objId;
		int _relation;
		int _autoAttackable;
		int _karma;
		int _pvpFlag;
	}

	public RelationChanged()
	{
		_mask |= SEND_MULTI;
		_multi = new ArrayList<RelationData>();
	}

	public RelationChanged(Playable playable, boolean autoAttackable, int relation)
	{
		_mask |= SEND_ONE;
		_single = new RelationData();
		_single._objId = playable.getObjectId();
		_single._relation = relation;
		_single._autoAttackable = autoAttackable ? 1 : 0;
		_single._karma = playable.getKarma();
		_single._pvpFlag = playable.getPvpFlag();
	}

	public void add(RelationData data)
	{
		_multi.add(data);
	}

	@Override
	protected void writeImpl()
	{
		writeC(0xCE);
		writeC(_mask);

		if (_multi == null || _multi.isEmpty())
		{
			writeRelation(_single);
		}
		else
		{
			writeH(_multi.size());

			for (RelationData data : _multi)
				writeRelation(data);
		}
	}

	private void writeRelation(RelationData data)
	{
		writeD(data._objId);

		if ((_mask & SEND_DEFAULT) == 0)
		{
			writeD(data._relation);
			writeC(data._autoAttackable);
			writeD(data._karma);
			writeC(data._pvpFlag);
		}
	}

	/**
	 * @param targetPlayable игрок, отношение к которому изменилось
	 * @param activeChar     игрок, которому будет отослан пакет с результатом
	 */
	public static L2GameServerPacket update(Player sendTo, Playable targetPlayable, Player activeChar)
	{
		if (sendTo == null || targetPlayable == null || activeChar == null)
			return null;

		Player targetPlayer = targetPlayable.getPlayer();
		int relation = targetPlayer == null ? 0 : getRelation(targetPlayer, activeChar);
		return new RelationChanged(targetPlayable, targetPlayable.isTargetable() && targetPlayable.isAutoAttackable(activeChar, null), relation);
	}

	private static int getRelation(Player player, Player target)
	{
		int result = 0;

		if ((player.getZoneMask() & ZONE_PVP_FLAG) == ZONE_PVP_FLAG)
			result |= Relation.BATTLE_ZONE.getMask();

		if (player.getPvpFlag() != 0)
			result |= Relation.PVP.getMask();

		if (player.getKarma() < 0)
			result |= Relation.PK.getMask();

		Clan clan1 = player.getClan();
		Clan clan2 = target.getClan();

		if (clan1 != null)
		{
			result |= Relation.CLAN_MEMBER.getMask();

			if (player.isClanLeader())
				result |= Relation.CLAN_LEADER.getMask();

			if (clan1 == clan2)
				result |= Relation.CLAN_MATE.getMask();

			if (clan1.getAllianceId() != 0)
			{
				result |= Relation.ALLY_MEMBER.getMask();

				if (clan1.getAlliance().getLeader() == clan1 && player.isClanLeader())
					result |= Relation.ALLY_LEADER.getMask();
			}
		}

		if (clan1 != null && clan2 != null)
		{
			if (target.getUnitType() != ClanUnitType.ACADEMY && player.getUnitType() != ClanUnitType.ACADEMY && target.getChaosFestivalMode() < 2 && player.getChaosFestivalMode() < 2)
			{
				if (clan2.isAtWarWith(clan1))
				{
					result |= Relation.CLAN_WAR_1_SIDED.getMask();

					if (clan1.isAtWarWith(clan2))
						result |= Relation.CLAN_WAR_2_SIDED.getMask();
				}
			}
		}

		Party party = player.getParty();

		if (party != null)
		{
			if (party == target.getParty())
				result |= Relation.HAS_PARTY.getMask();

			result |= Relation.PARTY_MEMBER.getMask();

			if (party.isLeader(player))
				result |= Relation.PARTY_LEADER.getMask();
		}

		if (player.getBlockCheckerArena() != -1)
		{
			ArenaParticipantsHolder holder = HandysBlockCheckerManager.getInstance().getHolder(player.getBlockCheckerArena());
			int team = holder.getPlayerTeam(player);

			if (team == 0)
			{
				result |= Relation.BLOCK_CHECKER_RED.getMask();
				result |= Relation.PVP_RED.getMask();
			}
			else if (team == 1)
			{
				result |= Relation.BLOCK_CHECKER_BLUE.getMask();
				result |= Relation.PVP_BLUE.getMask();
			}
		}

		if (player.getPvPEventMode() > 0)
		{
			int mode = player.getPvPEventMode();
			TeamType team = player.getTeam();

			if (mode == 2)
			{
				if (team == TeamType.RED)
					result |= Relation.PVP_RED.getMask();
				else if (team == TeamType.BLUE)
					result |= Relation.PVP_BLUE.getMask();
			}
			else
			{
				if (team != TeamType.NONE)
					result |= Relation.PVP_RED.getMask();
			}
		}

		for (GlobalEvent e : player.getEvents())
			result = e.getRelation(player, target, result);

		return result;
	}

}

Ну и дополняется маска еще в глобал эвентах, упаравляющих разными видами осад

Например вот так

	public int getRelation(Player thisPlayer, Player targetPlayer, int result)
	{
		Clan clan1 = thisPlayer.getClan();
		Clan clan2 = targetPlayer.getClan();

		if (clan1 == null || clan2 == null)
			return result;

		SiegeEvent<?, ?> siegeEvent2 = targetPlayer.getEvent(SiegeEvent.class);

		if (this == siegeEvent2)
		{
			result |= Relation.IN_SIEGE.getMask();

			if ((thisPlayer.getZoneMask() & ExSetCompassZoneCode.ZONE_SIEGE_FLAG) != ExSetCompassZoneCode.ZONE_SIEGE_FLAG)
				return result;

			SiegeClanObject siegeClan1 = getSiegeClan(SiegeEvent.ATTACKERS, clan1);
			SiegeClanObject siegeClan2 = getSiegeClan(SiegeEvent.ATTACKERS, clan2);

			if (siegeClan1 == null && siegeClan2 == null || siegeClan1 != null && siegeClan2 != null && isAttackersInAlly())
				result |= Relation.SIEGE_ALLY.getMask();
			else
				result |= Relation.SIEGE_ENEMY.getMask();

			if (siegeClan1 != null)
				result |= Relation.SIEGE_ATTACKER.getMask();
		}

		return result;
	}

Сразу говрю, что тут у меня скорее всего немного избыточный список типов релейшнов, т.к. это с более свежих хроник - не факт что все из них были в ГФ.

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

Спасибо за код конечно, но тут чтобы это адаптировать придется все ядро переписывать))

Релейшены работают нормально и корректно, как я выяснил.

Проблема именно в том, чтобы достать нужное значение в пакете юзер инфо, проблема именно с локальным чаром по иконке.

Edited by Rogue

Share this post


Link to post
Share on other sites

В принципе просто заменю в клиенте эти неактивные иконки на активные и все, у меня все равно этих пенальти нет.

Share this post


Link to post
Share on other sites
Posted (edited)

а, ты про пенальти на получение славы при убийстве противников на осаде? того, что должно препятствовать фарму славы на одних и тех же целях нонстопом?

кстати то, чтобы вовремя визуально обновлялся статус этого пенальти делается тоже влегкую. просто заведи таск, который будет запускаться в момент назначения пенальти и при выполнении  при истечении времени пенальти (а для надежности даже чуть попозже, на пару сотен мс) будет просто вызывать броадкаст CharInfo для своевременного обновления видимого статуса.

у меня именно так это работает.

Edited by Gaikotsu

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...