package tools.packet; import client.MapleCharacter; import client.MapleClient; import client.MapleCoolDownValueHolder; import client.MapleQuestStatus; import client.Skill; import client.SkillEntry; import client.SkillFactory; import client.inventory.Equip; import client.inventory.Item; import client.inventory.MapleInventory; import client.inventory.MapleInventoryType; import client.inventory.MaplePet; import client.inventory.MapleRing; import constants.GameConstants; import constants.ItemConstants; import handling.Buffstat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import server.MapleCarnivalChallenge; import server.MapleItemInformationProvider; import server.movement.LifeMovementFragment; import server.quest.MapleQuest; import server.shop.MapleShop; import server.shop.MapleShopItem; import server.shops.AbstractPlayerStore; import server.shops.IMaplePlayerShop; import tools.BitTools; import tools.DateUtil; import tools.FileoutputUtil; import tools.Pair; import tools.StringUtil; import tools.Triple; import tools.data.output.MaplePacketLittleEndianWriter; public class PacketHelper { public static long MAX_TIME = 150842304000000000L; public static long ZERO_TIME = 94354848000000000L; public static long PERMANENT = 150841440000000000L; public static long getKoreanTimestamp(long realTimestamp) { return realTimestamp * 10000L + 116444592000000000L; } public static long getTime(long realTimestamp) { if (realTimestamp == -1L) { return MAX_TIME; } if (realTimestamp == -2L) { return ZERO_TIME; } if (realTimestamp == -3L) { return PERMANENT; } return DateUtil.getFileTimestamp(realTimestamp); } public static void addQuestInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { List<MapleQuestStatus> started = chr.getStartedQuests(); /* mplew.writeShort(4); mplew.writeInt(100); mplew.writeMapleAsciiString("info"); // quest值 info不行 mplew.writeInt(1001100); mplew.writeMapleAsciiString("s"); mplew.writeInt(1000100); mplew.writeMapleAsciiString("w"); mplew.writeInt(1001800); mplew.writeMapleAsciiString("2s"); */ mplew.writeShort(started.size()); for (MapleQuestStatus q : started) { mplew.writeInt(q.getQuest().getId()); mplew.writeMapleAsciiString(q.getCustomData() == null ? "" : q.getCustomData()); } } /** * 添加角色技能信息 * @param mplew * @param chr */ public static void addSkillInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { Map<Skill, SkillEntry> skills = chr.getSkills(true); if (skills != null) { mplew.writeShort(skills.size()); for (Entry<Skill, SkillEntry> skill : skills.entrySet()) { mplew.writeInt((skill.getKey()).getId()); mplew.writeInt((skill.getValue()).skillLevel); } } else { mplew.writeShort(0); } } /** * 添加戒指信息 * @param mplew * @param chr */ public static void addRingInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { Triple aRing = chr.getRings(true); List<MapleRing> cRing = (List) aRing.getLeft(); mplew.writeShort(cRing.size()); for (MapleRing ring : cRing) { // 39个字节 mplew.writeInt(ring.getPartnerChrId()); mplew.writeAsciiString(ring.getPartnerName(), 0x13); mplew.writeInt(ring.getRingId()); mplew.writeInt(0); mplew.writeInt(ring.getPartnerRingId()); mplew.writeInt(0); } } /** * 添加背包信息 * @param mplew * @param chr */ public static void addInventoryInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { MapleInventory iv = chr.getInventory(MapleInventoryType.EQUIPPED); List<Item> equippedList = iv.newList(); Collections.sort(equippedList); List<Item> equipped = new ArrayList(); List<Item> equippedCash = new ArrayList(); for (Item item : equippedList) { if ((item.getPosition() < 0) && (item.getPosition() > -100)) { equipped.add(item); } else if ((item.getPosition() <= -100) && (item.getPosition() > -1000)) { equippedCash.add(item); } } for (Item item : equipped) { addItemInfo(mplew, item); } mplew.write(0); for (Item item : equippedCash) { addItemInfo(mplew, item); } mplew.write(0); iv = chr.getInventory(MapleInventoryType.EQUIP); mplew.write(chr.getInventory(MapleInventoryType.EQUIP).getSlotLimit()); for (Item item : iv.list()) { addItemInfo(mplew, item); } mplew.write(0); iv = chr.getInventory(MapleInventoryType.USE); mplew.write(chr.getInventory(MapleInventoryType.USE).getSlotLimit()); for (Item item : iv.list()) { addItemInfo(mplew, item); } mplew.write(0); iv = chr.getInventory(MapleInventoryType.SETUP); mplew.write(chr.getInventory(MapleInventoryType.SETUP).getSlotLimit()); for (Item item : iv.list()) { addItemInfo(mplew, item); } mplew.write(0); iv = chr.getInventory(MapleInventoryType.ETC); mplew.write(chr.getInventory(MapleInventoryType.ETC).getSlotLimit()); for (Item item : iv.list()) { if (item.getPosition() < 100) { addItemInfo(mplew, item); } } mplew.write(0); iv = chr.getInventory(MapleInventoryType.CASH); mplew.write(chr.getInventory(MapleInventoryType.CASH).getSlotLimit()); for (Item item : iv.list()) { addItemInfo(mplew, item); } mplew.write(0); } /** * 添加角色状态 ok * @param mplew * @param chr * GW_CharacterStat::Decode */ public static void addCharStats(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { mplew.writeInt(chr.getId()); mplew.writeAsciiString(chr.getName(), 0x13); mplew.write(chr.getClient().getGender()); // 帐号控制 mplew.write(chr.getSkinColor()); // 肤色 mplew.writeInt(chr.getFace()); mplew.writeInt(chr.getHair()); mplew.writeLong(0); // Pet SN mplew.write(chr.getLevel()); mplew.writeShort(chr.getJob()); mplew.writeShort(chr.getStat().str); mplew.writeShort(chr.getStat().dex); mplew.writeShort(chr.getStat().int_); mplew.writeShort(chr.getStat().luk); mplew.writeShort(chr.getStat().baseHp); mplew.writeShort(chr.getStat().baseMaxHp); mplew.writeShort(chr.getStat().baseMp); mplew.writeShort(chr.getStat().baseMaxMp); mplew.writeShort(chr.getRemainingAp()); mplew.writeShort(chr.getRemainingSp()); mplew.writeInt((int)chr.getExp()); // @TODO 经验用int mplew.writeShort(chr.getFame()); mplew.writeInt(chr.getMapId()); mplew.write(chr.getInitialSpawnpoint()); mplew.writeReversedLong(getTime(System.currentTimeMillis())); mplew.writeInt(0); mplew.writeInt(0); } public static void addCharLook(MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean mega, boolean second) { if (mega) { mplew.write(chr.getGender()); } mplew.write(chr.getSkinColor()); // skin color mplew.writeInt(chr.getFace()); // face mplew.write(0); // OdinMS: mega ? 1 : 0 mplew.writeInt(chr.getHair()); // hair Map<Byte, Integer> myEquip = new LinkedHashMap(); Map<Byte, Integer> maskedEquip = new LinkedHashMap(); MapleInventory equip = chr.getInventory(MapleInventoryType.EQUIPPED); for (Item item : equip.newList()) { if (item.getPosition() < -128) { continue; } byte pos = (byte) (item.getPosition() * -1); if ((pos < 100) && (myEquip.get(pos) == null)) { Equip skin = (Equip) item; myEquip.put(pos, item.getItemId()); } else if (((pos > 100) || (pos == -128)) && (pos != 111)) { pos = (byte) (pos == -128 ? 28 : pos - 100); if (myEquip.get(pos) != null) { maskedEquip.put(pos, myEquip.get(pos)); } myEquip.put(pos, item.getItemId()); } else if (myEquip.get(pos) != null) { maskedEquip.put(pos, item.getItemId()); } } for (Map.Entry entry : myEquip.entrySet()) { mplew.write((Byte) entry.getKey()); mplew.writeInt((Integer) entry.getValue()); } mplew.write(0xFF); mplew.writeInt(0); // PET // if (chr.getPets() != null) { // mplew.writeInt(chr.getPet(0).getItemId()); // } else { // mplew.writeInt(0); // Pet // } } public static void addExpirationTime(MaplePacketLittleEndianWriter mplew, long time) { mplew.writeLong(getTime(time)); } /** * 添加道具信息 * GW_ItemSlotBase::Decode * @param mplew * @param item */ public static void addItemInfo(MaplePacketLittleEndianWriter mplew, Item item){ addItemInfo(mplew,item,false); } /** * 添加道具信息 * @param mplew * @param item * @param isCreateItem 是否从外部获取道具,也就是道具操作为0时要使用 */ public static void addItemInfo(MaplePacketLittleEndianWriter mplew, Item item,boolean isCreateItem) { if (!isCreateItem) { byte pos = item.getPosition(); if (pos <= -1) { // 身上的装备 pos = (byte) (pos * -1); if ((pos > 100) && (pos < 1000)) { pos = (byte)(pos - 100); } mplew.write(pos); } else { mplew.write(pos); } } if (item.getPet() != null) { addPetItemInfo(mplew, item, item.getPet()); } else { if (item.getType() == 1) { // 装备 addEquipItemInfo(mplew, item); } else { // 非装备 addOtherItemInfo(mplew, item); // 其它道具 } } } /** * 非装备 * @param mplew * @param item */ private static void addOtherItemInfo(MaplePacketLittleEndianWriter mplew, Item item) { PacketHelper.addBaseItemHeader(mplew,item); mplew.writeShort(item.getQuantity()); mplew.writeMapleAsciiString(item.getOwner()); } /** * 添加准备信息 * @param mplew * @param item */ private static void addEquipItemInfo(MaplePacketLittleEndianWriter mplew, Item item) { PacketHelper.addBaseItemHeader(mplew,item); Equip equip = (Equip) item; mplew.write(equip.getUpgradeSlots()); mplew.write(equip.getLevel()); mplew.writeShort(equip.getStr()); mplew.writeShort(equip.getDex()); mplew.writeShort(equip.getInt()); mplew.writeShort(equip.getLuk()); mplew.writeShort(equip.getHp()); mplew.writeShort(equip.getMp()); mplew.writeShort(equip.getWatk()); mplew.writeShort(equip.getMatk()); mplew.writeShort(equip.getWdef()); mplew.writeShort(equip.getMdef()); mplew.writeShort(equip.getAcc()); mplew.writeShort(equip.getAvoid()); mplew.writeShort(equip.getHands()); mplew.writeShort(equip.getSpeed()); mplew.writeShort(equip.getJump()); mplew.writeMapleAsciiString(equip.getOwner()); } public static void serializeMovementList(MaplePacketLittleEndianWriter lew, List<LifeMovementFragment> moves) { lew.write(moves.size()); for (LifeMovementFragment move : moves) { move.serialize(lew); } } public static void addAnnounceBox(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { if ((chr.getPlayerShop() != null) && (chr.getPlayerShop().isOwner(chr)) && (chr.getPlayerShop().getShopType() != 1) && (chr.getPlayerShop().isAvailable())) { addInteraction(mplew, chr.getPlayerShop()); } else { mplew.write(0); } } public static void addInteraction(MaplePacketLittleEndianWriter mplew, IMaplePlayerShop shop) { mplew.write(shop.getGameType()); mplew.writeInt(((AbstractPlayerStore) shop).getObjectId()); mplew.writeMapleAsciiString(shop.getDescription()); if (shop.getShopType() != 1) { mplew.write(shop.getPassword().length() > 0 ? 1 : 0); } mplew.write(shop.getItemId() - 5030000); mplew.write(shop.getSize()); mplew.write(shop.getMaxSize()); if (shop.getShopType() != 1) { mplew.write(shop.isOpen() ? 0 : 1); } } /** * 添加角色信息到地图 * @param mplew * @param chr */ public static void addCharacterInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { mplew.writeShort(-1); // 二进制 111 addCharStats(mplew, chr); mplew.write(chr.getBuddylist().getCapacity()); mplew.writeInt(chr.getMeso()); addInventoryInfo(mplew, chr); addSkillInfo(mplew, chr); addQuestInfo(mplew, chr); mplew.writeShort(0); // Mini Games ? addRingInfo(mplew, chr); // getVIPRockMaps // for (int i = 0; i < 5; i++) { // mplew.writeInt(910000000 + i); // } for (int map : chr.getRegRocks()) { mplew.writeInt(map); } } public static void addQuestDataInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) { Map<Integer, String> questInfos = chr.getInfoQuest_Map(); mplew.writeShort(questInfos.size()); for (Map.Entry quest : questInfos.entrySet()) { mplew.writeShort(((Integer) quest.getKey())); mplew.writeMapleAsciiString(quest.getValue() == null ? "" : (String) quest.getValue()); } } /** * 添加宠物信息 * @param mplew * @param item * @param pet */ public static void addPetItemInfo(MaplePacketLittleEndianWriter mplew, Item item, MaplePet pet) { PacketHelper.addBaseItemHeader(mplew,item); mplew.writeAsciiString(pet.getName(), 0x13); mplew.write(pet.getLevel()); mplew.writeShort(pet.getCloseness()); mplew.write(pet.getFullness()); if (item == null) { mplew.writeLong(getKoreanTimestamp((long) (System.currentTimeMillis() * 1.5D))); } else { addExpirationTime(mplew, item.getExpiration() <= System.currentTimeMillis() ? -1L : item.getExpiration()); } } /* * Rank: * 0 - 无标题 * 1 - 装备 * 2 - 消耗 * 3 - 设置 * 4 - 其他 * 5 - 配方 * 6 - 卷轴 * 7 - 特殊 * 8 - 8周年 * 9 - 纽扣 * 10 - 入场券 * 11 - 材料 * 12 - 冒险岛 * 13 - 运动会 * 14 - 级核 * 80 - 乔 * 81 - 海美蜜 * 82 - 小龙 * 83 - 李卡司 */ public static void addShopInfo(MaplePacketLittleEndianWriter mplew, MapleShop shop, MapleClient c) { MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance(); List<MapleShopItem> shopItems = shop.getItems(c); mplew.writeShort(shopItems.size()); for (MapleShopItem item : shopItems) { mplew.writeInt(item.getItemId()); mplew.writeInt(item.getPrice()); if (ItemConstants.is飞镖道具(item.getItemId())) { mplew.writeLong(1000); //显示的购买数量 } mplew.writeShort(item.getBuyable()); } } public static <E extends Buffstat> void writeSingleMask(MaplePacketLittleEndianWriter mplew, E statup) { for (int i = GameConstants.MAX_BUFFSTAT; i >= 1; i--) { mplew.writeInt(i == statup.getPosition() ? statup.getValue() : 0); } } public static <E extends Buffstat> void writeMonsterStatusMask(MaplePacketLittleEndianWriter mplew, E statup) { for (int i = GameConstants.MAX_MONSTERSTATUS; i >= 1; i--) { mplew.writeInt(i == statup.getPosition() ? statup.getValue() : 0); } } public static <E extends Buffstat> void writeMask(MaplePacketLittleEndianWriter mplew, Collection<E> statups) { int[] mask = new int[GameConstants.MAX_BUFFSTAT]; for (Buffstat statup : statups) { mask[(statup.getPosition() - 1)] |= statup.getValue(); } for (int i = mask.length; i >= 1; i--) { mplew.writeInt(mask[(i - 1)]); } } //TODO 修复给怪物状态 public static <E extends Buffstat> void writeMonsterStatusMask(MaplePacketLittleEndianWriter mplew, Collection<E> statups) { int[] mask = new int[GameConstants.MAX_MONSTERSTATUS]; for (Buffstat statup : statups) { mask[(statup.getPosition() - 1)] |= statup.getValue(); } for (int i = mask.length; i >= 1; i--) { mplew.writeInt(mask[(i - 1)]); } } public static <E extends Buffstat> void writeBuffMask(MaplePacketLittleEndianWriter mplew, Collection<Pair<E, Integer>> statups) { int[] mask = new int[GameConstants.MAX_BUFFSTAT]; for (Pair statup : statups) { mask[(((Buffstat) statup.left).getPosition() - 1)] |= ((Buffstat) statup.left).getValue(); } for (int i = mask.length; i >= 1; i--) { mplew.writeInt(mask[(i - 1)]); } } public static <E extends Buffstat> void writeBuffMask(MaplePacketLittleEndianWriter mplew, Map<E, Integer> statups) { int[] mask = new int[GameConstants.MAX_BUFFSTAT]; for (Buffstat statup : statups.keySet()) { mask[(statup.getPosition() - 1)] |= statup.getValue(); } for (int i = mask.length; i >= 1; i--) { mplew.writeInt(mask[(i - 1)]); } } /** * 通用道具头部信息 * CBaseItem::DecodeHeader * @param mplew * @param item */ public static void addBaseItemHeader(MaplePacketLittleEndianWriter mplew,Item item) { mplew.writeInt(item.getItemId()); if (item.getUniqueId() > 0) { mplew.write(1); mplew.writeLong(item.getUniqueId()); } else { mplew.write(0); } PacketHelper.addExpirationTime(mplew, item.getExpiration()); } }