Посмотрите видео ниже, чтобы узнать, как установить наш сайт в виде веб-приложения на главном экране.
Примечание: Эта функция может быть недоступна в некоторых браузерах.
Это в каком классе чекнуть?а тип в пакете инфы о предмете точно правильный шлется?
речь про двухбайтовое поле после поля количества.
Ну в RequestRefine я убрал лишние int и long, и добавил readByte как в 542, чтобы камни вставлялись.в серверных пакетах, а точнее без конкретизации сборки не могу сказать.
еще кстати может не того типа идшники ауг шлешь.
к примеру в хф это hh, а после уже dd. и вроде еще в самых новых хрониках вобще 3 ид шлются, а не 2 (но это неточно).
package org.l2jmobius.gameserver.network.clientpackets;
import org.l2jmobius.gameserver.data.AugmentationData;
import org.l2jmobius.gameserver.model.Augmentation;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.item.enums.ItemProcessType;
import org.l2jmobius.gameserver.model.item.instance.Item;
import org.l2jmobius.gameserver.network.SystemMessageId;
import org.l2jmobius.gameserver.network.enums.StatusUpdateType;
import org.l2jmobius.gameserver.network.serverpackets.ExVariationResult;
import org.l2jmobius.gameserver.network.serverpackets.InventoryUpdate;
import org.l2jmobius.gameserver.network.serverpackets.StatusUpdate;
/**
* @author -Wooden-
*/
public class RequestRefine extends AbstractRefinePacket
{
private int _targetItemObjId;
private int _refinerItemObjId;
private int _gemStoneItemObjId;
private long _gemStoneCount;
@Override
protected void readImpl()
{
_targetItemObjId = readInt();
_refinerItemObjId = readInt();
readByte();
}
@Override
protected void runImpl()
{
final Player player = getPlayer();
if (player == null)
{
return;
}
final Item targetItem = player.getInventory().getItemByObjectId(_targetItemObjId);
if (targetItem == null)
{
return;
}
final Item refinerItem = player.getInventory().getItemByObjectId(_refinerItemObjId);
if (refinerItem == null)
{
return;
}
final Item gemStoneItem = player.getInventory().getItemByObjectId(_gemStoneItemObjId);
if (gemStoneItem == null)
{
return;
}
if (!isValid(player, targetItem, refinerItem, gemStoneItem))
{
player.sendPacket(new ExVariationResult(0, 0, 0));
player.sendPacket(SystemMessageId.AUGMENTATION_FAILED_DUE_TO_INAPPROPRIATE_CONDITIONS);
return;
}
final LifeStone ls = getLifeStone(refinerItem.getId());
if (ls == null)
{
return;
}
final int lifeStoneLevel = ls.getLevel();
final int lifeStoneGrade = ls.getGrade();
if (_gemStoneCount != getGemStoneCount(targetItem.getTemplate().getCrystalType(), lifeStoneGrade))
{
player.sendPacket(new ExVariationResult(0, 0, 0));
player.sendPacket(SystemMessageId.AUGMENTATION_FAILED_DUE_TO_INAPPROPRIATE_CONDITIONS);
return;
}
// unequip item
if (targetItem.isEquipped())
{
final InventoryUpdate iu = new InventoryUpdate();
for (Item itm : player.getInventory().unEquipItemInSlotAndRecord(targetItem.getLocationSlot()))
{
iu.addModifiedItem(itm);
}
player.sendPacket(iu); // Sent inventory update for unequip instantly.
player.broadcastUserInfo();
}
// consume the life stone
if (!player.destroyItem(ItemProcessType.FEE, refinerItem, 1, null, false))
{
return;
}
// consume the gemstones
if (!player.destroyItem(ItemProcessType.FEE, gemStoneItem, _gemStoneCount, null, false))
{
return;
}
final Augmentation aug = AugmentationData.getInstance().generateRandomAugmentation(lifeStoneLevel, lifeStoneGrade, targetItem.getTemplate().getBodyPart(), refinerItem.getId(), targetItem);
targetItem.setAugmentation(aug);
final int stat12 = 0x0000FFFF & aug.getAugmentationId();
final int stat34 = aug.getAugmentationId() >> 16;
player.sendPacket(new ExVariationResult(stat12, stat34, 1));
final InventoryUpdate iu = new InventoryUpdate();
iu.addModifiedItem(targetItem);
player.sendPacket(iu); // Sent inventory update for destruction instantly.
final StatusUpdate su = new StatusUpdate(player);
su.addUpdate(StatusUpdateType.CUR_LOAD, player.getCurrentLoad());
player.sendPacket(su);
}
}
То-есть надо слать типо вот такого, как в 542?ну финальная ауга у тебя точно криво формируется
не нужно тут делать битовые операции с ид опций - просто послать как есть 2 int значения их в пакетах
// Only reuse old options for slots that are truly optional and intentionally left empty (if needed).
// For your rare group, we don't fallback to old augment.
final int option1 = augment.getOption1Id();
final int option2 = augment.getOption2Id();
final int option3 = augment.getOption3Id();
// Optional: only fallback for option1/2 if your design requires at least 2 guaranteed options.
final VariationInstance oldAugment = targetItem.getAugmentation();
if (oldAugment != null)
{
final int newOption1 = (option1 > 0) ? option1 : 0;
final int newOption2 = (option2 > 0) ? option2 : 0;
final int newOption3 = (option3 > 0) ? option3 : 0; // Do not fallback to old 3rd option.
augment = new VariationInstance(augment.getMineralId(), newOption1, newOption2, newOption3);
}
player.sendPacket(new ExVariationResult(augment.getOption1Id(), augment.getOption2Id(), augment.getOption3Id(), true));
final int stat12 = 0x0000FFFF & aug.getAugmentationId();
final int stat34 = aug.getAugmentationId() >> 16;
player.sendPacket(new ExVariationResult(stat12, stat34, 1));
Ну по дефолту хф вот такое тамтут еще надо посмотреть что у тебя там в итоге generateRandomAugmentation выдает и уже от этого плясать
/**
* Generate a new random augmentation
* @param lifeStoneLevel
* @param lifeStoneGrade
* @param bodyPart
* @param lifeStoneId
* @param targetItem
* @return
*/
public Augmentation generateRandomAugmentation(int lifeStoneLevel, int lifeStoneGrade, BodyPart bodyPart, int lifeStoneId, Item targetItem)
{
switch (bodyPart)
{
case BodyPart.LR_FINGER:
case BodyPart.LR_EAR:
case BodyPart.NECK:
{
return generateRandomAccessoryAugmentation(lifeStoneLevel, bodyPart, lifeStoneId);
}
default:
{
return generateRandomWeaponAugmentation(lifeStoneLevel, lifeStoneGrade, lifeStoneId, targetItem);
}
}
}
private Augmentation generateRandomWeaponAugmentation(int level, int lifeStoneGrade, int lifeStoneId, Item item)
{
int stat12 = 0;
int stat34 = 0;
if (PlayerConfig.RETAIL_LIKE_AUGMENTATION)
{
if (item.getTemplate().isMagicWeapon())
{
final List<AugmentationChance> selectedChances12 = new ArrayList<>();
final List<AugmentationChance> selectedChances34 = new ArrayList<>();
for (AugmentationChance ac : _augmentationChances)
{
if (ac.getWeaponType().equals("mage") && (ac.getStoneId() == lifeStoneId))
{
if (ac.getVariationId() == 1)
{
selectedChances12.add(ac);
}
else
{
selectedChances34.add(ac);
}
}
}
int r = Rnd.get(10000);
float s = 10000;
for (AugmentationChance ac : selectedChances12)
{
if (s > r)
{
s -= (ac.getAugmentChance() * 100);
stat12 = ac.getAugmentId();
}
}
int[] gradeChance = null;
switch (lifeStoneGrade)
{
case AbstractRefinePacket.GRADE_NONE:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_NG_CHANCE;
break;
}
case AbstractRefinePacket.GRADE_MID:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_MID_CHANCE;
break;
}
case AbstractRefinePacket.GRADE_HIGH:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_HIGH_CHANCE;
break;
}
case AbstractRefinePacket.GRADE_TOP:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_TOP_CHANCE;
break;
}
default:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_NG_CHANCE;
}
}
int c = Rnd.get(100);
if (c < gradeChance[0])
{
c = 55;
}
else if (c < (gradeChance[0] + gradeChance[1]))
{
c = 35;
}
else if (c < (gradeChance[0] + gradeChance[1] + gradeChance[2]))
{
c = 7;
}
else
{
c = 3;
}
final List<AugmentationChance> selectedChances34final = new ArrayList<>();
for (AugmentationChance ac : selectedChances34)
{
if (ac.getCategoryChance() == c)
{
selectedChances34final.add(ac);
}
}
r = Rnd.get(10000);
s = 10000;
for (AugmentationChance ac : selectedChances34final)
{
if (s > r)
{
s -= (ac.getAugmentChance() * 100);
stat34 = ac.getAugmentId();
}
}
}
else
{
final List<AugmentationChance> selectedChances12 = new ArrayList<>();
final List<AugmentationChance> selectedChances34 = new ArrayList<>();
for (AugmentationChance ac : _augmentationChances)
{
if (ac.getWeaponType().equals("warrior") && (ac.getStoneId() == lifeStoneId))
{
if (ac.getVariationId() == 1)
{
selectedChances12.add(ac);
}
else
{
selectedChances34.add(ac);
}
}
}
int r = Rnd.get(10000);
float s = 10000;
for (AugmentationChance ac : selectedChances12)
{
if (s > r)
{
s -= (ac.getAugmentChance() * 100);
stat12 = ac.getAugmentId();
}
}
int[] gradeChance = null;
switch (lifeStoneGrade)
{
case AbstractRefinePacket.GRADE_NONE:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_NG_CHANCE;
break;
}
case AbstractRefinePacket.GRADE_MID:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_MID_CHANCE;
break;
}
case AbstractRefinePacket.GRADE_HIGH:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_HIGH_CHANCE;
break;
}
case AbstractRefinePacket.GRADE_TOP:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_TOP_CHANCE;
break;
}
default:
{
gradeChance = PlayerConfig.RETAIL_LIKE_AUGMENTATION_NG_CHANCE;
}
}
int c = Rnd.get(100);
if (c < gradeChance[0])
{
c = 55;
}
else if (c < (gradeChance[0] + gradeChance[1]))
{
c = 35;
}
else if (c < (gradeChance[0] + gradeChance[1] + gradeChance[2]))
{
c = 7;
}
else
{
c = 3;
}
final List<AugmentationChance> selectedChances34final = new ArrayList<>();
for (AugmentationChance ac : selectedChances34)
{
if (ac.getCategoryChance() == c)
{
selectedChances34final.add(ac);
}
}
r = Rnd.get(10000);
s = 10000;
for (AugmentationChance ac : selectedChances34final)
{
if (s > r)
{
s -= (ac.getAugmentChance() * 100);
stat34 = ac.getAugmentId();
}
}
}
return new Augmentation(((stat34 << 16) + stat12));
}
/**
* Generates a new random variation instance based on the specified variation template.
* <p>
* This method creates a {@link VariationInstance} by selecting random effects for the given variation and applying it to the specified target item.
* </p>
* @param variation the {@link Variation} template from which the instance will be generated
* @param targetItem the {@link Item} on which the variation will be applied
* @return a new {@link VariationInstance} with random effects
*/
public VariationInstance generateRandomVariation(Variation variation, Item targetItem)
{
return generateRandomVariation(variation, targetItem.getId());
}
/**
* Generates a new random variation instance based on the specified variation template and target item ID.
* <p>
* This private method is a helper that generates a {@link VariationInstance} by selecting random effects based on the target item ID.
* </p>
* @param variation the {@link Variation} template from which the instance will be generated
* @param targetItemId the ID of the item on which the variation will be applied
* @return a new {@link VariationInstance} with random effects
*/
private VariationInstance generateRandomVariation(Variation variation, int targetItemId)
{
final Options option1 = variation.getRandomEffect(0, targetItemId);
final Options option2 = variation.getRandomEffect(1, targetItemId);
final Options option3 = variation.getRandomEffect(2, targetItemId);
return new VariationInstance(variation.getMineralId(), option1, option2, option3);
}
мобиус жекакой п...ц
ты где такую древность выкопал?
по моему уже во всех вменяемых сборках этот допотопный п..ц с такой генерацией ауг выпилили давно.
Ну вот тебе теперь надо слать 3 ид опций, ну или хотя бы в последней слать 0, если надо только данные от 2 опций в ауге показывать как в хф.А в 542 вот такое
Я думаю там не сильно система аугмента различается между 286 и 542Ну вот тебе теперь надо слать 3 ид опций, ну или хотя бы в последней слать 0, если надо только данные от 2 опций в ауге показывать как в хф.
т.е. вобщем 3 int слать в качестве инфы об ауге
Ну в любом случае тебе лучше пытать тех кто колупает именно последние протоколы - я то пишу это все чисто теоретически, ибо сам все так же потихоньку мучаю уже старенький 286 протокол![]()
protected void writeItem(ItemInfo item, long count, int mask)
{
writeH(mask);
writeD(item.getObjectId());
writeD(item.getTemplate().getId());
writeC(item.getEquipSlot());
writeQ(count);
writeC(item.getTemplate().getType2ForPackets()); // тип предмета: 00-weapon, 01-shield/armor, 02-ring/earring/necklace, 03-questitem, 04-adena, 05-item
writeC(item.getCustomType1()); // всегда 0
writeH(item.isEquipped());
writeQ(item.getTemplate().getBodyPartSlot()); // слот для эквипа
writeH(item.getEnchantLevel()); // уровень заточки (уровень пета, если это предмет для его призыва)
writeC(item.getCustomType2()); // 0 - пет с стандартным именем (имя NPC), 1 - пет с именем, заданным игроком
writeD(item.getRemainingDurationTime());
writeD(item.getAppearanceId() == 0 ? item.getRemainingPeriodTime() : item.getAppearanceTimeForPackets()); // оставшееся время жизни для временного предмета/временной внешки
writeC(item.isUseable());
writeH(item.isLocked());
if (containsMask(mask, ItemListType.AUGMENTATION_OPTIONS))
writeItemAugment(item);
if (containsMask(mask, ItemListType.ELEMENTAL_ATTRIBUTE))
writeItemElemental(item);
if (containsMask(mask, ItemListType.ENCHANT_OPTIONS))
writeItemEnchantEffect(item);
if (containsMask(mask, ItemListType.APPEARANCE))
writeD(item.getAppearanceId());
if (containsMask(mask, ItemListType.ENSOUL_OPTIONS))
writeItemEnsoulOptions(item);
if (containsMask(mask, ItemListType.USE_COUNT))
writeH(item.getCurrentUseCount());
if (containsMask(mask, ItemListType.REUSE_DELAY))
writeD(item.getCurrentReuse());
if (containsMask(mask, ItemListType.PET_DATA))
writePetData(item);
if (containsMask(mask, ItemListType.BLESS_OPTION))
writeC(1);
}
protected static final int calculateMask(ItemInfo item)
{
int mask = 0;
if (!item.getAugmentation().equals(AugmentationData.EMPTY))
mask |= ItemListType.AUGMENTATION_OPTIONS.getMask();
if (item.getAttackAttribute() != AttributeType.NONE || item.checkDefenceAttributeValues())
mask |= ItemListType.ELEMENTAL_ATTRIBUTE.getMask();
if (item.getEnchantOptions() != null)
for (int id : item.getEnchantOptions())
if (id > 0)
{
mask |= ItemListType.ENCHANT_OPTIONS.getMask();
break;
}
if (item.getAppearanceId() > 0)
mask |= ItemListType.APPEARANCE.getMask();
if (item.getEnsoulOptions(EnsoulType.NORMAL).size() > 0 || item.getEnsoulOptions(EnsoulType.SPECIAL).size() > 0)
mask |= ItemListType.ENSOUL_OPTIONS.getMask();
if (item.getMaxUseCount() > 0)
{
mask |= ItemListType.USE_COUNT.getMask();
if (item.getCurrentReuse() > 0)
mask |= ItemListType.REUSE_DELAY.getMask();
}
if (item.isBlessed())
mask |= ItemListType.BLESS_OPTION.getMask();
return mask;
}
protected void writeItemAugment(AugmentationData data)
{
writeD(data.getOption1Id());
writeD(data.getOption2Id());
}
protected void writeItemAugment(ItemInfo item)
{
writeItemAugment(item != null ? item.getAugmentation() : AugmentationData.EMPTY);
}
protected void writeItemAugment(MultiSellItem item)
{
writeItemAugment(item != null ? item.getAugmentation() : AugmentationData.EMPTY);
}
А что на счет лостов? Я еще их просто время от времени ковыряю, но пока на только на клиенте хф.Ну у меня шлютстся просто 2 инта в блоке инфы об ауге, вот в целом и всей разницы.
Java:protected void writeItem(ItemInfo item, long count, int mask) { writeH(mask); writeD(item.getObjectId()); writeD(item.getTemplate().getId()); writeC(item.getEquipSlot()); writeQ(count); writeC(item.getTemplate().getType2ForPackets()); // тип предмета: 00-weapon, 01-shield/armor, 02-ring/earring/necklace, 03-questitem, 04-adena, 05-item writeC(item.getCustomType1()); // всегда 0 writeH(item.isEquipped()); writeQ(item.getTemplate().getBodyPartSlot()); // слот для эквипа writeH(item.getEnchantLevel()); // уровень заточки (уровень пета, если это предмет для его призыва) writeC(item.getCustomType2()); // 0 - пет с стандартным именем (имя NPC), 1 - пет с именем, заданным игроком writeD(item.getRemainingDurationTime()); writeD(item.getAppearanceId() == 0 ? item.getRemainingPeriodTime() : item.getAppearanceTimeForPackets()); // оставшееся время жизни для временного предмета/временной внешки writeC(item.isUseable()); writeH(item.isLocked()); if (containsMask(mask, ItemListType.AUGMENTATION_OPTIONS)) writeItemAugment(item); if (containsMask(mask, ItemListType.ELEMENTAL_ATTRIBUTE)) writeItemElemental(item); if (containsMask(mask, ItemListType.ENCHANT_OPTIONS)) writeItemEnchantEffect(item); if (containsMask(mask, ItemListType.APPEARANCE)) writeD(item.getAppearanceId()); if (containsMask(mask, ItemListType.ENSOUL_OPTIONS)) writeItemEnsoulOptions(item); if (containsMask(mask, ItemListType.USE_COUNT)) writeH(item.getCurrentUseCount()); if (containsMask(mask, ItemListType.REUSE_DELAY)) writeD(item.getCurrentReuse()); if (containsMask(mask, ItemListType.PET_DATA)) writePetData(item); if (containsMask(mask, ItemListType.BLESS_OPTION)) writeC(1); } protected static final int calculateMask(ItemInfo item) { int mask = 0; if (!item.getAugmentation().equals(AugmentationData.EMPTY)) mask |= ItemListType.AUGMENTATION_OPTIONS.getMask(); if (item.getAttackAttribute() != AttributeType.NONE || item.checkDefenceAttributeValues()) mask |= ItemListType.ELEMENTAL_ATTRIBUTE.getMask(); if (item.getEnchantOptions() != null) for (int id : item.getEnchantOptions()) if (id > 0) { mask |= ItemListType.ENCHANT_OPTIONS.getMask(); break; } if (item.getAppearanceId() > 0) mask |= ItemListType.APPEARANCE.getMask(); if (item.getEnsoulOptions(EnsoulType.NORMAL).size() > 0 || item.getEnsoulOptions(EnsoulType.SPECIAL).size() > 0) mask |= ItemListType.ENSOUL_OPTIONS.getMask(); if (item.getMaxUseCount() > 0) { mask |= ItemListType.USE_COUNT.getMask(); if (item.getCurrentReuse() > 0) mask |= ItemListType.REUSE_DELAY.getMask(); } if (item.isBlessed()) mask |= ItemListType.BLESS_OPTION.getMask(); return mask; } protected void writeItemAugment(AugmentationData data) { writeD(data.getOption1Id()); writeD(data.getOption2Id()); } protected void writeItemAugment(ItemInfo item) { writeItemAugment(item != null ? item.getAugmentation() : AugmentationData.EMPTY); } protected void writeItemAugment(MultiSellItem item) { writeItemAugment(item != null ? item.getAugmentation() : AugmentationData.EMPTY); }
З.Ы. А вобще зря ты за основу взял хф мобиуса - мало того там код древний, так та еще какашка.
даже чистый овер 2012-2013 годов был бы лучшим вариантом для последующего допила и адаптации к новым клиентам.