Помощь с пакетом от клиента игровому серверу RequestCharacterCreate

nesss

Путник
Участник
Сообщения
37
Розыгрыши
0
Решения
2
Репутация
-2
Реакции
7
Баллы
34
Хроники
  1. Interlude
Исходники
Присутствуют
Сборка
Собственная
Всем привет, столкнулся с проблемой при создании персонажа, после выбора всех настроек и нажатии на кнопку "Создать", клиент высылает пакет RequestCharacterCreate на игровой сервер с информацией, которую ввел клиент при создании персонажа, ну там - имя, расу, пол и т.д. Но вот что заметил, если ввести в имени 2 символа, приходит ошибка о не корректном имени, если 4, 5, 6 и т.д. символов так же, при этом имя приходит на сервер следующего вида - к примеру имя персонажа вводим Admin ( а приходит Adm ?н ), то есть первые 3 символа норм читаются, потом начинается белиберда. Если ввести 3 символа, игровой сервер выдает ошибку :
Exception in thread "Thread-1" java.nio.BufferUnderflowException
at java.base/java.nio.Buffer.nextGetIndex(Buffer.java:721)
at java.base/java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:498)
at battleR.gameserver.client.network.PacketReadC.readInt(PacketReadC.java:32)
at battleR.gameserver.client.network.read.RequestCharacterCreate.read(RequestCharacterCreate.java:56)
at battleR.gameserver.client.ClientThreadHandler.read(ClientThreadHandler.java:280)
at battleR.gameserver.client.ClientThread.run(ClientThread.java:79)

Пакет принимаю так:
name = readString();
race = (byte) readInt();
sex = (byte) readInt();
baseClass = (byte) readInt();
readInt();
readInt();
readInt();
readInt();
readInt();
readInt();
hairStyle = (byte) readInt();
hairColor = (byte) readInt();
face = (byte) readInt();
 
Решение
Все решил ))))) ура ))
Короче дело все было в blowfish ключе, он получается не верно дешифровывал пакеты данных. Ну смысла был в чем:
1. Каждому клиенту выделяется свой blowfish ключ для расшифровки, зашифровки пакета, и хранится он в экземпляре класса.
2. Я присваивал в экземпляр класса таким методом :
Java:
    private final byte[] blowfishKey;

    /**
     * <b>Конструктор</b><br>
     * <small>Выполняет действия при создании нового экземпляра класса.</small>
     * @param blowfishKey blowfish ключ.
     */
    public GameCrypt(byte[] blowfishKey) {

        this.blowfishKey = blowfishKey;

    }
3. Потом изменил на:
Java:
    private final byte[] blowfishKey = new byte[16];

    /**
     * <b>Конструктор</b><br>
     * <small>Выполняет...
Пакет принимаю так:
name = readString();
race = (byte) readInt();
sex = (byte) readInt();
baseClass = (byte) readInt();
readInt();
readInt();
readInt();
readInt();
readInt();
readInt();
hairStyle = (byte) readInt();
hairColor = (byte) readInt();
face = (byte) readInt();
Варианты из головы:
* readString читает не UTF-16LE (new String(readBytes(readShort()), StandartCharset.UTF_16LE);
* Были случаи, когда вот такое try(LineNumberReader lnr = new LineNumberReader(new BufferedReader(new FileReader(file)))) сьедало какие-то символы,
1715883877067.png
когда как:
Java:
            byte[] array = Files.readAllBytes(file.toPath());
            final String values = new String(array, StandardCharsets.UTF_8);
            return Arrays.asList(values.split("\n"));
читал все символы правильно.
Итого - неявно заданая кодировка - скорее всего.
 
Последнее редактирование модератором:
У меня принимает строку так:
Java:
    protected String readString() {

        char ch;
        final StringBuilder string = new StringBuilder();

        while((ch = byteBuffer.getChar()) != 0) {

            string.append(ch);

        }

        return string.toString();

    }

Но до этого то в других пакетах присылает от сервера авторизации к игровому серверу через клиент логин, и логин все четко принимает без проблем, все тем же методом )
 
Вот такая штука приходит как ввожу имя:
adaᩤada
Admᵩnus
admက
AdmὩns
a
add℀
asd②sd
asd⭡sdasdas⭤as
 
Посмотрите как реализованы пакеты в других исходниках и сравните опкоды.
Возможно у Вас длинна запроса совсем другая. 🤔
Пакеты не менялись в обычном интерлюде, у всех одинаковое должно быть, разная реализация только с проверками.

Как пример с гитхаба:
Код:
package ru.catssoftware.gameserver.network.clientpackets; 
 
import ru.catssoftware.Config; 
import ru.catssoftware.gameserver.datatables.CharNameTable; 
import ru.catssoftware.gameserver.datatables.CharTemplateTable; 
import ru.catssoftware.gameserver.datatables.ItemTable; 
import ru.catssoftware.gameserver.datatables.SkillTable; 
import ru.catssoftware.gameserver.datatables.SkillTreeTable; 
import ru.catssoftware.gameserver.idfactory.IdFactory; 
import ru.catssoftware.gameserver.instancemanager.QuestManager; 
import ru.catssoftware.gameserver.model.L2ItemInstance; 
import ru.catssoftware.gameserver.model.L2ShortCut; 
import ru.catssoftware.gameserver.model.L2SkillLearn; 
import ru.catssoftware.gameserver.model.L2World; 
import ru.catssoftware.gameserver.model.actor.instance.L2PcInstance; 
import ru.catssoftware.gameserver.model.actor.instance.L2PlayableInstance; 
import ru.catssoftware.gameserver.model.base.Experience; 
import ru.catssoftware.gameserver.model.itemcontainer.PcInventory; 
import ru.catssoftware.gameserver.model.quest.Quest; 
import ru.catssoftware.gameserver.model.quest.QuestState; 
import ru.catssoftware.gameserver.network.Disconnection; 
import ru.catssoftware.gameserver.network.L2GameClient; 
import ru.catssoftware.gameserver.network.serverpackets.CharCreateFail; 
import ru.catssoftware.gameserver.network.serverpackets.CharCreateOk; 
import ru.catssoftware.gameserver.network.serverpackets.CharSelectionInfo; 
import ru.catssoftware.gameserver.taskmanager.SQLQueue; 
import ru.catssoftware.gameserver.templates.chars.L2PcTemplate; 
import ru.catssoftware.gameserver.templates.chars.L2PcTemplate.PcTemplateItem; 
 
@SuppressWarnings("unused") 
public class CharacterCreate extends L2GameClientPacket 
{ 
    private static final String    _C__0B_CHARACTERCREATE    = "[C] 0B CharacterCreate"; 
    private String                _name; 
    private int                    _race, _classId, _int, _str, _con, _men, _dex, _wit; 
    private byte                _sex, _hairStyle, _hairColor, _face; 
 
    private static final Object _lock = new Object(); 
 
    @Override 
    protected void readImpl() 
    { 
        _name = readS(); 
        _race = readD(); 
        _sex = (byte) readD(); 
        _classId = readD(); 
        _int = readD(); 
        _str = readD(); 
        _con = readD(); 
        _men = readD(); 
        _dex = readD(); 
        _wit = readD(); 
        _hairStyle = (byte) readD(); 
        _hairColor = (byte) readD(); 
        _face = (byte) readD(); 
    } 
 
    @Override 
    protected void runImpl() 
    { 
        synchronized (_lock) 
        { 
            if (CharNameTable.getInstance().doesCharNameExist(_name)) 
            { 
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_NAME_ALREADY_EXISTS); 
                sendPacket(ccf); 
                return; 
            } 
            else if (CharNameTable.getInstance().accountCharNumber(getClient().getAccountName()) >= Config.MAX_CHARACTERS_NUMBER_PER_ACCOUNT && Config.MAX_CHARACTERS_NUMBER_PER_ACCOUNT != 0) 
            { 
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_TOO_MANY_CHARACTERS); 
                sendPacket(ccf); 
                return; 
            } 
            else if (!Config.CNAME_PATTERN.matcher(_name).matches()) 
            { 
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_16_ENG_CHARS); 
                sendPacket(ccf); 
                return; 
            } 
 
            L2PcTemplate template = CharTemplateTable.getInstance().getTemplate(_classId); 
            if (template == null || template.getClassBaseLevel() > 1) 
            { 
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED); 
                sendPacket(ccf); 
                return; 
            } 
 
            int objectId = IdFactory.getInstance().getNextId(); 
            L2PcInstance newChar = L2PcInstance.create(objectId, template, getClient().getAccountName(),_name, _hairStyle, _hairColor, _face, _sex!=0); 
            newChar.getStatus().setCurrentHp(template.getBaseHpMax()); 
            newChar.getStatus().setCurrentCp(template.getBaseCpMax()); 
            newChar.getStatus().setCurrentMp(template.getBaseMpMax()); 
 
            // send acknowledgement 
            CharCreateOk cco = new CharCreateOk(); 
            sendPacket(cco); 
 
            initNewChar(getClient(), newChar); 
        } 
    } 
 
    private void initNewChar(L2GameClient client, L2PcInstance newChar) 
    { 
        L2World.getInstance().storeObject(newChar); 
 
        L2PcTemplate template = newChar.getTemplate(); 
 
        if (Config.STARTING_ADENA > 0) 
            newChar.addAdena("Init", Config.STARTING_ADENA, null, false); 
        if (Config.STARTING_AA > 0) 
            newChar.addAncientAdena("Init", Config.STARTING_AA, null, false); 
 
        for (int[] startingItems : Config.CUSTOM_STARTER_ITEMS) 
        { 
            if (newChar == null) 
            { 
                continue; 
            } 
            PcInventory inv = newChar.getInventory(); 
            if (ItemTable.getInstance().createDummyItem(startingItems[0]).isStackable()) 
            {  
                inv.addItem("Starter Items", startingItems[0], startingItems[1], newChar, null); 
            } 
            else 
            { 
                for (int i = 0; i < startingItems[1]; i++) 
                { 
                    inv.addItem("Starter Items", startingItems[0], 1, newChar, null); 
                } 
            } 
        } 
        if (Config.ALLOW_NEW_CHAR_CUSTOM_POSITION) 
            newChar.getPosition().setXYZInvisible(Config.NEW_CHAR_POSITION_X, Config.NEW_CHAR_POSITION_Y, Config.NEW_CHAR_POSITION_Z); 
        else 
            newChar.getPosition().setXYZInvisible(template.getSpawnX(), template.getSpawnY(), template.getSpawnZ()); 
        if (Config.ALLOW_NEW_CHARACTER_TITLE) 
            newChar.setTitle(Config.NEW_CHARACTER_TITLE); 
        else 
            newChar.setTitle(""); 
        if(Config.ENABLE_STARTUP_LVL) 
        { 
            long EXp = Experience.LEVEL[Config.ADD_LVL_NEWBIE]; 
            newChar.addExpAndSp(EXp , 0); 
        } 
        if (Config.NEW_CHAR_IS_NOBLE) 
            newChar.setNoble(true); 
 
 
        // new char give Lucky Protection 
        newChar.addSkill(SkillTable.getInstance().getInfo(194, 1), true); 
 
        L2ShortCut shortcut; 
        //add attack shortcut 
        shortcut = new L2ShortCut(0, 0, 3, 2, 0, 1); 
        newChar.registerShortCut(shortcut); 
        //add take shortcut 
        shortcut = new L2ShortCut(3, 0, 3, 5, 0, 1); 
        newChar.registerShortCut(shortcut); 
        //add sit shortcut 
        shortcut = new L2ShortCut(10, 0, 3, 0, 0, 1); 
        newChar.registerShortCut(shortcut); 
 
        for (PcTemplateItem ia : template.getItems()) 
        { 
            L2ItemInstance item = newChar.getInventory().addItem("Init", ia.getItemId(), ia.getAmount(), newChar, null); 
 
            // add tutbook shortcut 
            if (item.getItemId() == 5588) 
            { 
                shortcut = new L2ShortCut(11, 0, 1, item.getObjectId(), 0, 1); 
                newChar.registerShortCut(shortcut); 
            } 
            if (item.isEquipable() && ia.isEquipped()) 
                newChar.getInventory().equipItemAndRecord(item); 
        } 
 
 
        for (L2SkillLearn skill: SkillTreeTable.getInstance().getAvailableSkills(newChar, newChar.getClassId())) 
        { 
            newChar.addSkill(SkillTable.getInstance().getInfo(skill.getId(), skill.getLevel()), true); 
            if (skill.getId() == 1001 || skill.getId() == 1177) 
            { 
                shortcut = new L2ShortCut(1, 0, 2, skill.getId(), skill.getLevel(), 1); 
                newChar.registerShortCut(shortcut); 
            } 
            if (skill.getId() == 1216) 
            { 
                shortcut = new L2ShortCut(10, 0, 2, skill.getId(), skill.getLevel(), 1); 
                newChar.registerShortCut(shortcut); 
            } 
        } 
        startTutorialQuest(newChar); 
        startNewbieHelperQuest(newChar); 
        //new Disconnection(getClient(), newChar).defaultSequence(true); 
        newChar.store(); 
        newChar.deleteMe(); 
 
        // send char list 
        CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1); 
        client.sendPacket(cl); 
        client.setCharSelection(cl.getCharInfo()); 
    } 
 
    public void startTutorialQuest(L2PcInstance player) 
    { 
        QuestState qs = player.getQuestState("255_Tutorial"); 
        Quest q = null; 
        if (qs == null) 
            q = QuestManager.getInstance().getQuest("255_Tutorial"); 
        if (q != null) 
            q.newQuestState(player); 
    } 
    public void startNewbieHelperQuest(L2PcInstance player) 
    { 
        QuestState qs = player.getQuestState("7003_NewbieHelper"); 
        Quest q = null; 
        if (qs == null) 
            q = QuestManager.getInstance().getQuest("7003_NewbieHelper"); 
        if (q != null) 
        { 
            q.newQuestState(player); 
            player.getQuestState("7003_NewbieHelper").set("cond","0"); 
        } 
        qs = player.getQuestState("1201_NewbieToken"); 
        q = null; 
        if (qs == null) 
            q = QuestManager.getInstance().getQuest("1201_NewbieToken"); 
        if (q != null) 
            q.newQuestState(player); 
    } 
 
    @Override 
    public String getType() 
    { 
        return _C__0B_CHARACTERCREATE; 
    } 
}

Не могу сейчас посмотреть более подробно с смарта.
 
Последнее редактирование:
Оффтоп:
Нужно срочно вознаградить человека который впихнул synchronized в runImpl
 
Оверпостинг запрещен!
Посмотрите как реализованы пакеты в других исходниках и сравните опкоды.
Возможно у Вас длинна запроса совсем другая. 🤔
Пакеты не менялись в обычном интерлюде, у всех одинаковое должно быть, разная реализация только с проверками.

Как пример с гитхаба:
Код:
package ru.catssoftware.gameserver.network.clientpackets;
 
import ru.catssoftware.Config;
import ru.catssoftware.gameserver.datatables.CharNameTable;
import ru.catssoftware.gameserver.datatables.CharTemplateTable;
import ru.catssoftware.gameserver.datatables.ItemTable;
import ru.catssoftware.gameserver.datatables.SkillTable;
import ru.catssoftware.gameserver.datatables.SkillTreeTable;
import ru.catssoftware.gameserver.idfactory.IdFactory;
import ru.catssoftware.gameserver.instancemanager.QuestManager;
import ru.catssoftware.gameserver.model.L2ItemInstance;
import ru.catssoftware.gameserver.model.L2ShortCut;
import ru.catssoftware.gameserver.model.L2SkillLearn;
import ru.catssoftware.gameserver.model.L2World;
import ru.catssoftware.gameserver.model.actor.instance.L2PcInstance;
import ru.catssoftware.gameserver.model.actor.instance.L2PlayableInstance;
import ru.catssoftware.gameserver.model.base.Experience;
import ru.catssoftware.gameserver.model.itemcontainer.PcInventory;
import ru.catssoftware.gameserver.model.quest.Quest;
import ru.catssoftware.gameserver.model.quest.QuestState;
import ru.catssoftware.gameserver.network.Disconnection;
import ru.catssoftware.gameserver.network.L2GameClient;
import ru.catssoftware.gameserver.network.serverpackets.CharCreateFail;
import ru.catssoftware.gameserver.network.serverpackets.CharCreateOk;
import ru.catssoftware.gameserver.network.serverpackets.CharSelectionInfo;
import ru.catssoftware.gameserver.taskmanager.SQLQueue;
import ru.catssoftware.gameserver.templates.chars.L2PcTemplate;
import ru.catssoftware.gameserver.templates.chars.L2PcTemplate.PcTemplateItem;
 
@SuppressWarnings("unused")
public class CharacterCreate extends L2GameClientPacket
{
    private static final String    _C__0B_CHARACTERCREATE    = "[C] 0B CharacterCreate";
    private String                _name;
    private int                    _race, _classId, _int, _str, _con, _men, _dex, _wit;
    private byte                _sex, _hairStyle, _hairColor, _face;
 
    private static final Object _lock = new Object();
 
    @Override
    protected void readImpl()
    {
        _name = readS();
        _race = readD();
        _sex = (byte) readD();
        _classId = readD();
        _int = readD();
        _str = readD();
        _con = readD();
        _men = readD();
        _dex = readD();
        _wit = readD();
        _hairStyle = (byte) readD();
        _hairColor = (byte) readD();
        _face = (byte) readD();
    }
 
    @Override
    protected void runImpl()
    {
        synchronized (_lock)
        {
            if (CharNameTable.getInstance().doesCharNameExist(_name))
            {
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_NAME_ALREADY_EXISTS);
                sendPacket(ccf);
                return;
            }
            else if (CharNameTable.getInstance().accountCharNumber(getClient().getAccountName()) >= Config.MAX_CHARACTERS_NUMBER_PER_ACCOUNT && Config.MAX_CHARACTERS_NUMBER_PER_ACCOUNT != 0)
            {
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_TOO_MANY_CHARACTERS);
                sendPacket(ccf);
                return;
            }
            else if (!Config.CNAME_PATTERN.matcher(_name).matches())
            {
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_16_ENG_CHARS);
                sendPacket(ccf);
                return;
            }
 
            L2PcTemplate template = CharTemplateTable.getInstance().getTemplate(_classId);
            if (template == null || template.getClassBaseLevel() > 1)
            {
                CharCreateFail ccf = new CharCreateFail(CharCreateFail.REASON_CREATION_FAILED);
                sendPacket(ccf);
                return;
            }
 
            int objectId = IdFactory.getInstance().getNextId();
            L2PcInstance newChar = L2PcInstance.create(objectId, template, getClient().getAccountName(),_name, _hairStyle, _hairColor, _face, _sex!=0);
            newChar.getStatus().setCurrentHp(template.getBaseHpMax());
            newChar.getStatus().setCurrentCp(template.getBaseCpMax());
            newChar.getStatus().setCurrentMp(template.getBaseMpMax());
 
            // send acknowledgement
            CharCreateOk cco = new CharCreateOk();
            sendPacket(cco);
 
            initNewChar(getClient(), newChar);
        }
    }
 
    private void initNewChar(L2GameClient client, L2PcInstance newChar)
    {
        L2World.getInstance().storeObject(newChar);
 
        L2PcTemplate template = newChar.getTemplate();
 
        if (Config.STARTING_ADENA > 0)
            newChar.addAdena("Init", Config.STARTING_ADENA, null, false);
        if (Config.STARTING_AA > 0)
            newChar.addAncientAdena("Init", Config.STARTING_AA, null, false);
 
        for (int[] startingItems : Config.CUSTOM_STARTER_ITEMS)
        {
            if (newChar == null)
            {
                continue;
            }
            PcInventory inv = newChar.getInventory();
            if (ItemTable.getInstance().createDummyItem(startingItems[0]).isStackable())
            { 
                inv.addItem("Starter Items", startingItems[0], startingItems[1], newChar, null);
            }
            else
            {
                for (int i = 0; i < startingItems[1]; i++)
                {
                    inv.addItem("Starter Items", startingItems[0], 1, newChar, null);
                }
            }
        }
        if (Config.ALLOW_NEW_CHAR_CUSTOM_POSITION)
            newChar.getPosition().setXYZInvisible(Config.NEW_CHAR_POSITION_X, Config.NEW_CHAR_POSITION_Y, Config.NEW_CHAR_POSITION_Z);
        else
            newChar.getPosition().setXYZInvisible(template.getSpawnX(), template.getSpawnY(), template.getSpawnZ());
        if (Config.ALLOW_NEW_CHARACTER_TITLE)
            newChar.setTitle(Config.NEW_CHARACTER_TITLE);
        else
            newChar.setTitle("");
        if(Config.ENABLE_STARTUP_LVL)
        {
            long EXp = Experience.LEVEL[Config.ADD_LVL_NEWBIE];
            newChar.addExpAndSp(EXp , 0);
        }
        if (Config.NEW_CHAR_IS_NOBLE)
            newChar.setNoble(true);
 
 
        // new char give Lucky Protection
        newChar.addSkill(SkillTable.getInstance().getInfo(194, 1), true);
 
        L2ShortCut shortcut;
        //add attack shortcut
        shortcut = new L2ShortCut(0, 0, 3, 2, 0, 1);
        newChar.registerShortCut(shortcut);
        //add take shortcut
        shortcut = new L2ShortCut(3, 0, 3, 5, 0, 1);
        newChar.registerShortCut(shortcut);
        //add sit shortcut
        shortcut = new L2ShortCut(10, 0, 3, 0, 0, 1);
        newChar.registerShortCut(shortcut);
 
        for (PcTemplateItem ia : template.getItems())
        {
            L2ItemInstance item = newChar.getInventory().addItem("Init", ia.getItemId(), ia.getAmount(), newChar, null);
 
            // add tutbook shortcut
            if (item.getItemId() == 5588)
            {
                shortcut = new L2ShortCut(11, 0, 1, item.getObjectId(), 0, 1);
                newChar.registerShortCut(shortcut);
            }
            if (item.isEquipable() && ia.isEquipped())
                newChar.getInventory().equipItemAndRecord(item);
        }
 
 
        for (L2SkillLearn skill: SkillTreeTable.getInstance().getAvailableSkills(newChar, newChar.getClassId()))
        {
            newChar.addSkill(SkillTable.getInstance().getInfo(skill.getId(), skill.getLevel()), true);
            if (skill.getId() == 1001 || skill.getId() == 1177)
            {
                shortcut = new L2ShortCut(1, 0, 2, skill.getId(), skill.getLevel(), 1);
                newChar.registerShortCut(shortcut);
            }
            if (skill.getId() == 1216)
            {
                shortcut = new L2ShortCut(10, 0, 2, skill.getId(), skill.getLevel(), 1);
                newChar.registerShortCut(shortcut);
            }
        }
        startTutorialQuest(newChar);
        startNewbieHelperQuest(newChar);
        //new Disconnection(getClient(), newChar).defaultSequence(true);
        newChar.store();
        newChar.deleteMe();
 
        // send char list
        CharSelectionInfo cl = new CharSelectionInfo(client.getAccountName(), client.getSessionId().playOkID1);
        client.sendPacket(cl);
        client.setCharSelection(cl.getCharInfo());
    }
 
    public void startTutorialQuest(L2PcInstance player)
    {
        QuestState qs = player.getQuestState("255_Tutorial");
        Quest q = null;
        if (qs == null)
            q = QuestManager.getInstance().getQuest("255_Tutorial");
        if (q != null)
            q.newQuestState(player);
    }
    public void startNewbieHelperQuest(L2PcInstance player)
    {
        QuestState qs = player.getQuestState("7003_NewbieHelper");
        Quest q = null;
        if (qs == null)
            q = QuestManager.getInstance().getQuest("7003_NewbieHelper");
        if (q != null)
        {
            q.newQuestState(player);
            player.getQuestState("7003_NewbieHelper").set("cond","0");
        }
        qs = player.getQuestState("1201_NewbieToken");
        q = null;
        if (qs == null)
            q = QuestManager.getInstance().getQuest("1201_NewbieToken");
        if (q != null)
            q.newQuestState(player);
    }
 
    @Override
    public String getType()
    {
        return _C__0B_CHARACTERCREATE;
    }
}
Ну это пример получения и обработки данного пакета, с этим у меня все отлично, дело в том, что _name = readS(); принимает белиберду, которую я скидывал ранее, то есть помимо имени скажем Admin приходит Admက, если ввожу Admins приходит AdmὩns, и что интересно, когда ввожу 3 символа, то в _face = (byte) readD(); уже приходит не 4 байта, а меньше, проверил пока-что, что точно 1 байт доходит

Вот мой пакет, который пытается прочитать из ByteBuffer:
Java:
package battleR.gameserver.client.network.read;

import battleR.gameserver.client.network.PacketReadC;
import battleR.gameserver.client.network.write.CharCreateFail;
import battleR.gameserver.client.network.write.CharCreateOk;
import battleR.gameserver.client.network.write.CharList;
import battleR.gameserver.data.model.template.CharacterClass;
import battleR.gameserver.data.model.template.Npc;
import battleR.gameserver.data.sql.Character;
import battleR.gameserver.data.xml.CharacterData;
import battleR.gameserver.data.xml.NpcData;

/**
 * <b>Пакет данных</b><br><br>
 * <small>Читает содержимое из пакета данных от клиента.</small><br><br>
 * <b>Полученные данные:</b><br><br>
 * <small>* Имя персонажа.</small><br><br>
 * <small>* Раса персонажа.</small><br><br>
 * <small>* Пол персонажа.</small><br><br>
 * <small>* Базовый класс персонажа.</small><br><br>
 * <small>* Прическа персонажа.</small><br><br>
 * <small>* Цвет прически персонажа.</small><br><br>
 * <small>* Лицо персонажа.</small><br><br>
 */
public class RequestCharacterCreate extends PacketReadC {

    private String name;
    private byte race;
    private byte sex;
    private byte baseClass;
    private byte hairStyle;
    private byte hairColor;
    private byte face;

    /**
     * <b>Описание</b><br>
     * <small>Формирует полученный пакет данных от клиента для чтения.</small>
     */
    @Override
    public boolean read() {

        if (byteBuffer.remaining() >= 51) {

            name = readString();
            race = (byte) readInt();
            sex = (byte) readInt();
            baseClass = (byte) readInt();
            readInt();
            readInt();
            readInt();
            readInt();
            readInt();
            readInt();
            hairStyle = (byte) readInt();
            hairColor = (byte) readInt();
            face = (byte) readByte();
            return true;

        }

        return false;

    }

    /**
     * <b>Описание</b><br>
     * <small>Отдельный поток для выполнения действий при получении пакета данных.</small>
     */
    @Override
    public void run() {

        if (race < 0 || race > 4) {

            sendPacket(CharCreateFail.CREATION_FAILED);
            return;

        }

        if (face < 0 || face > 2) {

            sendPacket(CharCreateFail.CREATION_FAILED);
            return;

        }

        if (hairStyle < 0 || (sex == 0 && hairStyle > 4) || (sex != 0 && hairStyle > 6)) {

            sendPacket(CharCreateFail.CREATION_FAILED);
            return;

        }

        if (hairColor < 0 || hairColor > 3) {

            sendPacket(CharCreateFail.CREATION_FAILED);
            return;

        }

        name = name.replaceAll("[^A-Za-z]", "*");

        if (name.contains("*") || name.length() < 3 || name.length() > 14) {

            sendPacket(CharCreateFail.INCORRECT_NAME);
            return;

        }

        for (Npc npc : NpcData.getInstance().getNpcs().values())
            if (npc.getName().equals(name)) {

                sendPacket(CharCreateFail.NAME_ALREADY_EXISTS);
                return;

            }

        final String login = client.getLogin();
        final Character character = new Character();

        if (!character.checkAccountCharacters(login)) {

            sendPacket(CharCreateFail.TOO_MANY_CHARACTERS);
            return;

        }

        if (!character.checkServerCharacters(name)) {

            sendPacket(CharCreateFail.NAME_ALREADY_EXISTS);
            return;

        }

        final CharacterClass characterClass = CharacterData.getInstance().getCharacterClass(baseClass);

        if (characterClass == null) {

            sendPacket(CharCreateFail.CREATION_FAILED);
            return;

        }

        if (!character.addCharacter(login, name, sex, race, baseClass, characterClass, hairStyle, hairColor, face)) {

            sendPacket(CharCreateFail.CREATION_FAILED);
            return;

        }

        sendPacket(new CharCreateOk());
        sendPacket(new CharList(client));

     }

}

Вот метод чтения строки из ByteBuffer:
Java:
    /**
     * <b>Описание</b><br>
     * <small>Читает из пакета данных строку.</small>
     */
    protected String readString() {

        Character ch;
        final StringBuilder string = new StringBuilder();

        while ((ch = byteBuffer.getChar()) != 0) {

            string.append(ch);

        }

        return string.toString();

    }

Посмотрел несколько сборок, там MMO не лучшим образом реализовано, методами древних времен. Но суть принципа у меня та же. Думал ну мало-ли что-то с клиентом, поменял клиент, все так же.
 
Последнее редактирование модератором:
Посмотрел несколько сборок, там MMO не лучшим образом реализовано, методами древних времен. Но суть принципа у меня та же. Думал ну мало-ли что-то с клиентом, поменял клиент, все так же.
Посмотрите как реализован readS тут:
Скрытое содержимое для пользователя(ей): nesss
 
Попробуйте поменять метод на
Код:
    /**
     * <b>Описание</b><br>
     * <small>Читает из пакета данных строку.</small>
     */
    protected String readString() {

        final StringBuilder string = new StringBuilder();
        int charId;
        while ((charId = readShort()) != 0) {

            string.append((char) charId);

        }

        return string.toString();

    }
 
Наблюдение: ввел dddddddddddd , а пришло dddᩤdddddddᨀ, и так всегда, именно 4й и 12й символ кракозябра, что-бы туда не ввел, всегда 4й и 12й.

Попробуйте поменять метод на
Код:
    /**
     * <b>Описание</b><br>
     * <small>Читает из пакета данных строку.</small>
     */
    protected String readString() {

        final StringBuilder string = new StringBuilder();
        int charId;
        while ((charId = readShort()) != 0) {

            string.append((char) charId);

        }

        return string.toString();

    }
Попробовал, все так же
 
В таком случае смотрите на дешифровку данных пакето из клиента.
 
Все решил ))))) ура ))
Короче дело все было в blowfish ключе, он получается не верно дешифровывал пакеты данных. Ну смысла был в чем:
1. Каждому клиенту выделяется свой blowfish ключ для расшифровки, зашифровки пакета, и хранится он в экземпляре класса.
2. Я присваивал в экземпляр класса таким методом :
Java:
    private final byte[] blowfishKey;

    /**
     * <b>Конструктор</b><br>
     * <small>Выполняет действия при создании нового экземпляра класса.</small>
     * @param blowfishKey blowfish ключ.
     */
    public GameCrypt(byte[] blowfishKey) {

        this.blowfishKey = blowfishKey;

    }
3. Потом изменил на:
Java:
    private final byte[] blowfishKey = new byte[16];

    /**
     * <b>Конструктор</b><br>
     * <small>Выполняет действия при создании нового экземпляра класса.</small>
     * @param blowfishKey blowfish ключ.
     */
    public GameCrypt(byte[] blowfishKey) {

        System.arraycopy(blowfishKey, 0, this.blowfishKey, 0, 16);

    }
И все заработало :)))
 
Решение
Все решил ))))) ура ))
Короче дело все было в blowfish ключе, он получается не верно дешифровывал пакеты данных. Ну смысла был в чем:
1. Каждому клиенту выделяется свой blowfish ключ для расшифровки, зашифровки пакета, и хранится он в экземпляре класса.
2. Я присваивал в экземпляр класса таким методом :
Java:
    private final byte[] blowfishKey;

    /**
     * <b>Конструктор</b><br>
     * <small>Выполняет действия при создании нового экземпляра класса.</small>
     * @param blowfishKey blowfish ключ.
     */
    public GameCrypt(byte[] blowfishKey) {

        this.blowfishKey = blowfishKey;

    }
3. Потом изменил на:
Java:
    private final byte[] blowfishKey = new byte[16];

    /**
     * <b>Конструктор</b><br>
     * <small>Выполняет действия при создании нового экземпляра класса.</small>
     * @param blowfishKey blowfish ключ.
     */
    public GameCrypt(byte[] blowfishKey) {

        System.arraycopy(blowfishKey, 0, this.blowfishKey, 0, 16);

    }
И все заработало :)))
а в чем разница? с тз ява-нуба выглядит просто как два метода сделать одно и то же... длина массива обязательно указана должна быть?
 
а в чем разница? с тз ява-нуба выглядит просто как два метода сделать одно и то же... длина массива обязательно указана должна быть?
Существуют два основных способа передачи параметров в методы: "по значению" (pass-by-value) и "по ссылке" (pass-by-reference). В первом случае метод работает с копией значения параметра, не изменяя исходное значение. Во втором случае метод получает ссылку на объект или переменную, и любые изменения в параметре отражаются на исходном объекте или переменной.
Если бы было так, то значение _blowfish не зависило бы от значения blowfish, которое где-то выполняется.
update key:
- генерирует новый ключ;
- присваивает его куда-то там;
- возвращает "стандартное" значение;
в методе updateKey - key будет со значением 0
а после метода setKey - _blowfish будет со значением generateNewKey.
Java:
private final static byte _standartKey = 0;
private byte _blowfish;

public static void updateKey()
{
    byte key = generateNewKey();
    setKey(key);
    key = _standartKey;
}

public static void setKey(byte blowfish)
{
    _blowfish = blowfish;
}
Если же вот так - то у нас массив в методе будет ссылкой на элемент и при изменении значения key на 1 позиции - он изменится и в присвоеном _blowfish
Java:
private byte[] _blowfish;

public static void updateKey()
{
    byte[] key = generateNewKey();
    setKey(key);
    key[1] = (byte) 0;
}

public static void setKey(byte[] blowfish)
{
    _blowfish = blowfish;
}
В случае использования
Java:
System.arraycopy(blowfish, 0, _blowfish, 0, blowfish.length());
будет создан новый элемент с новой ссылкой на него, и при изменении key - _blowfish останется первоначальным.
 
  • Мне нравится
Реакции: BladeRunner и Maksim

    BladeRunner

    Баллов: 5
    Ничего не понятно, но очень интересно) после работы еще раз перечитаю... раз 10)
а в чем разница? с тз ява-нуба выглядит просто как два метода сделать одно и то же... длина массива обязательно указана должна быть?
Ну так в том то и прикол :) я сделал свой вариант, потом начал искать ошибку от обратного, методом тестов узнал, что ошибка именно в бловфиш ключе и начал смотреть как в других сборках реализовано, увидел такой вариант, приминил и все отлично работает ))))
 
Ну так в том то и прикол :) я сделал свой вариант, потом начал искать ошибку от обратного, методом тестов узнал, что ошибка именно в бловфиш ключе и начал смотреть как в других сборках реализовано, увидел такой вариант, приминил и все отлично работает ))))

я правильно понял, что ключ меняется постоянно, а для корректной работы надо оставлять тот, который был при первом взаимодействии с ним?
 
Там ключ состоит из 16 байт, первые 8 байт для всех клиентов разные, вторые 8 байт статические.
 
Назад
Сверху Снизу