Не совсем понимаю, что вы имеете ввиду.Для начала стоит самостоятельно изучить хотя бы основы программирования на Java, иначе вызвавшемуся помочь для начала придется именно этому учить, а отнюдь не пониманию "кода ла2".
Для более быстрого освоения .если есть опыт в java, то тогда не очень понятно зачем нужен учитель.
в плане понимания кода сервера и его работы в целом обычных познаний в яве должно хватать вроде вполне.
struct _S_EX_PAYBACK_LIST
{
var array<_PaybackRewardSet> vRewardSet;
var int cEventIDType;
var int nEndDatetime;
var int nConsumedItemclassID;
var int nUserConsumption;
};
struct _PaybackRewardSet
{
var array<_PaybackRewardItem> vItemList;
var int cSetIndex;
var int nRequirement;
var int cReceived;
};
struct _PaybackRewardItem
{
var int nClassID;
var int nAmount;
};
public boolean write(PacketWriter packet)
{
OutgoingPackets.EX_PAYBACK_LIST.writeId(packet);
packet.writeD(3); // колличество строк // string size //nSize
for (int i = 1; i < 4; i++)
{
//заполняем строку //fill the string
//start _PaybackRewardSet
packet.writeD(3); // колличество предметов в строке // item count in field (max 3)//i
for (int j = 1; j < 4; j++)
//start _PaybackRewardItem
//заполняем предметы //fill the items
{
packet.writeD(57); // предмет // item id
packet.writeD(1); // количество // count
}
//закончили заполнять предметы // item fill end
//end _PaybackRewardItem
packet.writeC(i); // cSetIndex
packet.writeD(5); // сколько нужно потратить // how much you need //nRequirement
packet.writeC(0x00); //получена ли награда // check reward receiving ( 0x00 - no, 0x01 - yes ) //cReceived
//закончили заполнять строку // end string fill
//end _PaybackRewardSet
}
packet.writeC(_EventID); //cEventIDType
packet.writeD(10); //nEndDatetime
packet.writeD(91663); //Итем, который должен светиться вверху // display item //nConsumedItemclassID
packet.writeD(7); //Сколько всего было потрачено итемов // summary item spend //nUserConsumption
return true;
}
Благодарю. Часть из этого я уже сам понял ,но большинство информации было полезно.Гайд для старта:
- В каждой сборке есть классы "Npc", "Creature", "WorldObject", "Player" которые хранят в себе 80% используемых методов по всей сборке.
- 10% это статические классы по типу "Util" какой-то, который хранит в себе методы по типу "Посчитай сколько будет 3 2 4 и выбери макс число" или "посчитай какой heading (куда будет смотреть) будет у NPC который был тута, а пойдет туда" или же классы которые написаны попередниками и в которых нет смысла.
- 5% это классы для работы с пакетами - крипт, декрипт, связь с логин сервером и тд.
Ну и остальное это сами пакеты - чтение / запись - методы для удобного хранения World Object и другая лабуда для удобного хранения информации.
Еще есть такие приколы как "Geoengine" но туда если и лезть - то лучше сразу смотря на реализации в разных сборках чтоб собрать в кучу все то, что там происходит.
Ну и вот пример для записи пакетов. На пример "PayBack" УИшка. Информацию о том, какие данные принимает оно можно найти или Реверсом Engine или перехватив пакет с офа и разобрав его (Бог в помощь) или Реверсом слитых ПТС серверов или некоторые из них прячутся в Interface.u в классе "UIPacket".
Описание с interface.u
Как будет адаптировано в JavaC-подобный:struct _S_EX_PAYBACK_LIST { var array<_PaybackRewardSet> vRewardSet; var int cEventIDType; var int nEndDatetime; var int nConsumedItemclassID; var int nUserConsumption; }; struct _PaybackRewardSet { var array<_PaybackRewardItem> vItemList; var int cSetIndex; var int nRequirement; var int cReceived; }; struct _PaybackRewardItem { var int nClassID; var int nAmount; };
Что за что отвечает:Java:public boolean write(PacketWriter packet) { OutgoingPackets.EX_PAYBACK_LIST.writeId(packet); packet.writeD(3); // колличество строк // string size //nSize for (int i = 1; i < 4; i++) { //заполняем строку //fill the string //start _PaybackRewardSet packet.writeD(3); // колличество предметов в строке // item count in field (max 3)//i for (int j = 1; j < 4; j++) //start _PaybackRewardItem //заполняем предметы //fill the items { packet.writeD(57); // предмет // item id packet.writeD(1); // количество // count } //закончили заполнять предметы // item fill end //end _PaybackRewardItem packet.writeC(i); // cSetIndex packet.writeD(5); // сколько нужно потратить // how much you need //nRequirement packet.writeC(0x00); //получена ли награда // check reward receiving ( 0x00 - no, 0x01 - yes ) //cReceived //закончили заполнять строку // end string fill //end _PaybackRewardSet } packet.writeC(_EventID); //cEventIDType packet.writeD(10); //nEndDatetime packet.writeD(91663); //Итем, который должен светиться вверху // display item //nConsumedItemclassID packet.writeD(7); //Сколько всего было потрачено итемов // summary item spend //nUserConsumption return true; }
Посмотреть вложение 52499
Прикольно. Даже я начинающий всё понял.Гайд для старта:
- В каждой сборке есть классы "Npc", "Creature", "WorldObject", "Player" которые хранят в себе 80% используемых методов по всей сборке.
- 10% это статические классы по типу "Util" какой-то, который хранит в себе методы по типу "Посчитай сколько будет 3 2 4 и выбери макс число" или "посчитай какой heading (куда будет смотреть) будет у NPC который был тута, а пойдет туда" или же классы которые написаны попередниками и в которых нет смысла.
- 5% это классы для работы с пакетами - крипт, декрипт, связь с логин сервером и тд.
Ну и остальное это сами пакеты - чтение / запись - методы для удобного хранения World Object и другая лабуда для удобного хранения информации.
Еще есть такие приколы как "Geoengine" но туда если и лезть - то лучше сразу смотря на реализации в разных сборках чтоб собрать в кучу все то, что там происходит.
Ну и вот пример для записи пакетов. На пример "PayBack" УИшка. Информацию о том, какие данные принимает оно можно найти или Реверсом Engine или перехватив пакет с офа и разобрав его (Бог в помощь) или Реверсом слитых ПТС серверов или некоторые из них прячутся в Interface.u в классе "UIPacket".
Описание с interface.u
Как будет адаптировано в JavaC-подобный:struct _S_EX_PAYBACK_LIST { var array<_PaybackRewardSet> vRewardSet; var int cEventIDType; var int nEndDatetime; var int nConsumedItemclassID; var int nUserConsumption; }; struct _PaybackRewardSet { var array<_PaybackRewardItem> vItemList; var int cSetIndex; var int nRequirement; var int cReceived; }; struct _PaybackRewardItem { var int nClassID; var int nAmount; };
Что за что отвечает:Java:public boolean write(PacketWriter packet) { OutgoingPackets.EX_PAYBACK_LIST.writeId(packet); packet.writeD(3); // колличество строк // string size //nSize for (int i = 1; i < 4; i++) { //заполняем строку //fill the string //start _PaybackRewardSet packet.writeD(3); // колличество предметов в строке // item count in field (max 3)//i for (int j = 1; j < 4; j++) //start _PaybackRewardItem //заполняем предметы //fill the items { packet.writeD(57); // предмет // item id packet.writeD(1); // количество // count } //закончили заполнять предметы // item fill end //end _PaybackRewardItem packet.writeC(i); // cSetIndex packet.writeD(5); // сколько нужно потратить // how much you need //nRequirement packet.writeC(0x00); //получена ли награда // check reward receiving ( 0x00 - no, 0x01 - yes ) //cReceived //закончили заполнять строку // end string fill //end _PaybackRewardSet } packet.writeC(_EventID); //cEventIDType packet.writeD(10); //nEndDatetime packet.writeD(91663); //Итем, который должен светиться вверху // display item //nConsumedItemclassID packet.writeD(7); //Сколько всего было потрачено итемов // summary item spend //nUserConsumption return true; }
Посмотреть вложение 52499
Я считаю пора курсы обучающие продавать.Гайд для старта:
- В каждой сборке есть классы "Npc", "Creature", "WorldObject", "Player" которые хранят в себе 80% используемых методов по всей сборке.
- 10% это статические классы по типу "Util" какой-то, который хранит в себе методы по типу "Посчитай сколько будет 3 2 4 и выбери макс число" или "посчитай какой heading (куда будет смотреть) будет у NPC который был тута, а пойдет туда" или же классы которые написаны попередниками и в которых нет смысла.
- 5% это классы для работы с пакетами - крипт, декрипт, связь с логин сервером и тд.
Ну и остальное это сами пакеты - чтение / запись - методы для удобного хранения World Object и другая лабуда для удобного хранения информации.
Еще есть такие приколы как "Geoengine" но туда если и лезть - то лучше сразу смотря на реализации в разных сборках чтоб собрать в кучу все то, что там происходит.
Ну и вот пример для записи пакетов. На пример "PayBack" УИшка. Информацию о том, какие данные принимает оно можно найти или Реверсом Engine или перехватив пакет с офа и разобрав его (Бог в помощь) или Реверсом слитых ПТС серверов или некоторые из них прячутся в Interface.u в классе "UIPacket".
Описание с interface.u
Как будет адаптировано в JavaC-подобный:struct _S_EX_PAYBACK_LIST { var array<_PaybackRewardSet> vRewardSet; var int cEventIDType; var int nEndDatetime; var int nConsumedItemclassID; var int nUserConsumption; }; struct _PaybackRewardSet { var array<_PaybackRewardItem> vItemList; var int cSetIndex; var int nRequirement; var int cReceived; }; struct _PaybackRewardItem { var int nClassID; var int nAmount; };
Что за что отвечает:Java:public boolean write(PacketWriter packet) { OutgoingPackets.EX_PAYBACK_LIST.writeId(packet); packet.writeD(3); // колличество строк // string size //nSize for (int i = 1; i < 4; i++) { //заполняем строку //fill the string //start _PaybackRewardSet packet.writeD(3); // колличество предметов в строке // item count in field (max 3)//i for (int j = 1; j < 4; j++) //start _PaybackRewardItem //заполняем предметы //fill the items { packet.writeD(57); // предмет // item id packet.writeD(1); // количество // count } //закончили заполнять предметы // item fill end //end _PaybackRewardItem packet.writeC(i); // cSetIndex packet.writeD(5); // сколько нужно потратить // how much you need //nRequirement packet.writeC(0x00); //получена ли награда // check reward receiving ( 0x00 - no, 0x01 - yes ) //cReceived //закончили заполнять строку // end string fill //end _PaybackRewardSet } packet.writeC(_EventID); //cEventIDType packet.writeD(10); //nEndDatetime packet.writeD(91663); //Итем, который должен светиться вверху // display item //nConsumedItemclassID packet.writeD(7); //Сколько всего было потрачено итемов // summary item spend //nUserConsumption return true; }
Посмотреть вложение 52499
я бы сказал это главное сосредоточение гавнокода в современном мире.Мобиус считается говнокодом в соверменном мире?
Иметь:Можете мне аргументировано объяснить, почему КОД мобиуса - это говнокод?
Желательно хотя бы пару примеров, с разбором, почему так не стоит делать и как нужно?
Т.е безотносительно личности, политики комьюнити, личерства, читерства, дрочерства и прочего персонифицированного. Тупо код.
private void resetClanBonus()
{
ClanTable.getInstance().getClans().forEach(Clan::resetClanBonus);
LOGGER.info("Daily clan bonus has been resetted.");
}
public void resetClanBonus()
{
// Save current state
getVariables().set("PREVIOUS_MAX_ONLINE_PLAYERS", getMaxOnlineMembers());
getVariables().set("PREVIOUS_HUNTING_POINTS", getHuntingPoints());
// Reset
_members.values().forEach(ClanMember::resetBonus);
getVariables().remove("HUNTING_POINTS");
// force store
getVariables().storeMe();
// Send Packet
broadcastToOnlineMembers(ExPledgeBonusMarkReset.STATIC_PACKET);
}
public void resetBonus()
{
_onlineTime = 0;
final PlayerVariables vars = getVariables();
vars.set("CLAIMED_CLAN_REWARDS", 0);
vars.storeMe();
}
private void resetClanContributionList()
{
for (Clan clan : ClanTable.getInstance().getClans())
{
clan.getVariables().deleteWeeklyContribution();
}
}
public boolean deleteWeeklyContribution()
{
try (Connection con = DatabaseFactory.getConnection())
{
// Clear previous entries.
try (PreparedStatement st = con.prepareStatement(DELETE_WEAKLY_QUERY))
{
st.setInt(1, _objectId);
st.execute();
}
// Clear all entries
getSet().entrySet().stream().filter(it -> it.getKey().startsWith("CONTRIBUTION_WEEKLY_")).collect(Collectors.toList()).forEach(it -> getSet().remove(it.getKey()));
}
catch (Exception e)
{
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't delete variables for: " + _objectId, e);
return false;
}
return true;
}
final Player player = (maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker.getActingPlayer();
broadcastPacket(new SystemMessage(SystemMessageId.CONGRATULATIONS_YOUR_RAID_WAS_SUCCESSFUL));
final int raidbossPoints = (int) (getTemplate().getRaidPoints() * Config.RATE_RAIDBOSS_POINTS);
final Party party = player.getParty();
if (party != null)
{
final CommandChannel command = party.getCommandChannel();
final List<Player> members = new ArrayList<>();
if (command != null)
{
for (Player p : command.getMembers())
{
if (p.calculateDistance3D(this) < Config.ALT_PARTY_RANGE)
{
members.add(p);
}
}
}
else
{
for (Player p : player.getParty().getMembers())
{
if (p.calculateDistance3D(this) < Config.ALT_PARTY_RANGE)
{
members.add(p);
}
}
}
members.forEach(p ->
{
final int points = (int) (Math.max(raidbossPoints / members.size(), 1) * p.getStat().getValue(Stat.BONUS_RAID_POINTS, 1));
p.increaseRaidbossPoints(points);
p.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points));
if (p.isNoble())
{
Hero.getInstance().setRBkilled(p.getObjectId(), getId());
}
});
}
else
{
final int points = (int) (Math.max(raidbossPoints, 1) * player.getStat().getValue(Stat.BONUS_RAID_POINTS, 1));
player.increaseRaidbossPoints(points);
player.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points));
if (player.isNoble())
{
Hero.getInstance().setRBkilled(player.getObjectId(), getId());
}
}
}
broadcastPacket(new SystemMessage(SystemMessageId.CONGRATULATIONS_YOUR_RAID_WAS_SUCCESSFUL));
final Player player = (maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker.getActingPlayer();
final int raidbossPoints = (int) (getTemplate().getRaidPoints() * Config.RATE_RAIDBOSS_POINTS);
final AbstractPlayerGroup group = player.isInCommandChannel() ? player.getCommandChannel() : player.getParty();
final List<Player> members = group == null ? List.of(player) : new ArrayList<>();
if (group != null)
{
for (Player member : group.getMembers())
{
if (member.calculateDistance3D(this) < Config.ALT_PARTY_RANGE)
{
members.add(member);
}
}
}
for (Player member : members)
{
final int points = (int) (Math.max(raidbossPoints / members.size(), 1) * member.getStat().getValue(Stat.BONUS_RAID_POINTS, 1));
member.increaseRaidbossPoints(points);
member.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points));
if (member.isNoble())
{
Hero.getInstance().setRBkilled(member.getObjectId(), getId());
}
}
Ощущение, что тебя мобиус байтит на разбор....Иметь:
1. Закешированные ИД - ИМЯ персонажа.
2. Закешированная информация рейтинга;
3. Закешированная информация о всех мемберах клана / альянса;
(Там еще что-то было).
При этом восстанавливать информацию для некоторых пакетов / классов каждый раз когда требуется и базы данных. Почему бы не сделать это все в одном классе если информация зачастую о информации игроков (имя, левел, клан, альянса) нужны достаточно часто.
Инвентарь, который в угоду 10 милисекунд, был переделан и забит (х... забит) таким образом, что его можно задюпать из-за отстутсвия Concurrent.lock (ВРАНЬЕ, НЕТ ТАКОГО, Я НЕ НАШЕЛ (сарказм)).
Реализация инстанс зон (ну ок, я тут тоже приложил свою руку, но только в Храме Валакаса, ибо я его сделал на половину, а потом как-то и не потребовалось, а он просто взял и переназвал некоторые переменные) на очень низком уровне.
Что можно выделить из низкого уровня:
* Храм Валакаса - багается если просто пробежать и убить печать;
* Этис Ван Этина (соло) - просто прекрасный пример как не нужно делать - мобы стоят абы как та и просто страшно смотреть если играть с офа (ведь делали типо под ЦЦ версию);
* Таверны просто не работают. Фрею брать - нет дополнительных НПС, которые могут появится и быть с лутом. Таути - можна забагать если убить после печати Ангела до того, как он договорит и телепортирует. Остальных таверн просто не завезли.
* Убежище Бранштейна - стоят абы как, нету ивент тригеров (не понятно что в зоне происходит), итемы, которые внутри выдаются, не работают, у НПСов нет АИшки и тд...
Возвращаясь к коду...
= TimedHuntingZone - самая прекрасна реализация Сессионных Зон. Сделано по всем заветам, которых мобиус придерживается - економия на спичках и еще каким-то...
По итогу что мы получили:
* Жалобы на то, что народ через дырки в геодате или просто в текстурах пробивается в сесионную зону, ведь ради економии мы их сделаем в обычном мире (нас даже не смутило наличие отдельных иснстанс зон внути ДАТ файлов) (сейчас правда это прикрутили, но такая жесть была, я помню какие костыли ПИЛИЛИСЬ когда я пытался 3 куба ТОИ запихнуть в одну зону);
* Не нужные скрипты, которые проверяют есть ли ты в зоне или нет тебя в зоне для работы с НПСами и телепорта по зонам;
* Забитый болт на то что клиент багается время от времени при выходе с сессионных зон;
И опять, вренемся к коду.
Есть у нас такой прикол как "DailyTaskManager", в котором есть метод "resetClanBonus" (который там где он есть уже не нужен после 228 протокола), но мы не будем его чистить.
В чем его прелесть?
Выглядит просто, да? Просто берем все кланы и сбрасываем им бонус ежедневныйJava:private void resetClanBonus() { ClanTable.getInstance().getClans().forEach(Clan::resetClanBonus); LOGGER.info("Daily clan bonus has been resetted."); }
Давай посмотрим дальше...
Тут уже переменные сбрасываются и дальше идет сброс для каждого игрока клана?Java:public void resetClanBonus() { // Save current state getVariables().set("PREVIOUS_MAX_ONLINE_PLAYERS", getMaxOnlineMembers()); getVariables().set("PREVIOUS_HUNTING_POINTS", getHuntingPoints()); // Reset _members.values().forEach(ClanMember::resetBonus); getVariables().remove("HUNTING_POINTS"); // force store getVariables().storeMe(); // Send Packet broadcastToOnlineMembers(ExPledgeBonusMarkReset.STATIC_PACKET); }
А, ну и просто идет сброс переменной и сохранение в базу.Java:public void resetBonus() { _onlineTime = 0; final PlayerVariables vars = getVariables(); vars.set("CLAIMED_CLAN_REWARDS", 0); vars.storeMe(); }
Ничего такого, никто не думал о том, что на лайве (где не 2 человека и 10 персонажей в офлайне) отработка данного метода может занимать до 15 минут.
Еще у нас есть вот такое красивый метод...
Ну тут как минимум из-за того что может в один момент использоваться для записи clanVariables - может просто ошибка выбиться и сбросится только для некоторых.Код:private void resetClanContributionList() { for (Clan clan : ClanTable.getInstance().getClans()) { clan.getVariables().deleteWeeklyContribution(); } } public boolean deleteWeeklyContribution() { try (Connection con = DatabaseFactory.getConnection()) { // Clear previous entries. try (PreparedStatement st = con.prepareStatement(DELETE_WEAKLY_QUERY)) { st.setInt(1, _objectId); st.execute(); } // Clear all entries getSet().entrySet().stream().filter(it -> it.getKey().startsWith("CONTRIBUTION_WEEKLY_")).collect(Collectors.toList()).forEach(it -> getSet().remove(it.getKey())); } catch (Exception e) { LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't delete variables for: " + _objectId, e); return false; } return true; }
Та и как по мне - тут очень много кода, который пишется огромными полотнами, по нему очень сложно ориентироваться. Я пытаюсь перебраться и сделать 1 метод - на 1 экран, чтоб видел все что и где происходит.
Ну а полотен там хватает.
Еще хватает излишнего кода (дублирующего к примеру).
Есть у нас Attackable - calculateRewards.
Красивый код, не так ли? Но почему-бы не сделать вот так?Java:final Player player = (maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker.getActingPlayer(); broadcastPacket(new SystemMessage(SystemMessageId.CONGRATULATIONS_YOUR_RAID_WAS_SUCCESSFUL)); final int raidbossPoints = (int) (getTemplate().getRaidPoints() * Config.RATE_RAIDBOSS_POINTS); final Party party = player.getParty(); if (party != null) { final CommandChannel command = party.getCommandChannel(); final List<Player> members = new ArrayList<>(); if (command != null) { for (Player p : command.getMembers()) { if (p.calculateDistance3D(this) < Config.ALT_PARTY_RANGE) { members.add(p); } } } else { for (Player p : player.getParty().getMembers()) { if (p.calculateDistance3D(this) < Config.ALT_PARTY_RANGE) { members.add(p); } } } members.forEach(p -> { final int points = (int) (Math.max(raidbossPoints / members.size(), 1) * p.getStat().getValue(Stat.BONUS_RAID_POINTS, 1)); p.increaseRaidbossPoints(points); p.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points)); if (p.isNoble()) { Hero.getInstance().setRBkilled(p.getObjectId(), getId()); } }); } else { final int points = (int) (Math.max(raidbossPoints, 1) * player.getStat().getValue(Stat.BONUS_RAID_POINTS, 1)); player.increaseRaidbossPoints(points); player.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points)); if (player.isNoble()) { Hero.getInstance().setRBkilled(player.getObjectId(), getId()); } } }
Код стал меньше в два раза и понимание его осталось таким же с учетом всех видов группы.Java:broadcastPacket(new SystemMessage(SystemMessageId.CONGRATULATIONS_YOUR_RAID_WAS_SUCCESSFUL)); final Player player = (maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker.getActingPlayer(); final int raidbossPoints = (int) (getTemplate().getRaidPoints() * Config.RATE_RAIDBOSS_POINTS); final AbstractPlayerGroup group = player.isInCommandChannel() ? player.getCommandChannel() : player.getParty(); final List<Player> members = group == null ? List.of(player) : new ArrayList<>(); if (group != null) { for (Player member : group.getMembers()) { if (member.calculateDistance3D(this) < Config.ALT_PARTY_RANGE) { members.add(member); } } } for (Player member : members) { final int points = (int) (Math.max(raidbossPoints / members.size(), 1) * member.getStat().getValue(Stat.BONUS_RAID_POINTS, 1)); member.increaseRaidbossPoints(points); member.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points)); if (member.isNoble()) { Hero.getInstance().setRBkilled(member.getObjectId(), getId()); } }
Там еще есть прекрасное полотно с расчетом експы для пати/соло игрока, в котом только группа добавляется и чуть-чуть меняется из-за этого код, но я уже и так много времени потратил на это
Как же 6лять раздражает, когда е6аной скобой занимают целую строку.Иметь:
1. Закешированные ИД - ИМЯ персонажа.
2. Закешированная информация рейтинга;
3. Закешированная информация о всех мемберах клана / альянса;
(Там еще что-то было).
При этом восстанавливать информацию для некоторых пакетов / классов каждый раз когда требуется и базы данных. Почему бы не сделать это все в одном классе если информация зачастую о информации игроков (имя, левел, клан, альянса) нужны достаточно часто.
Инвентарь, который в угоду 10 милисекунд, был переделан и забит (х... забит) таким образом, что его можно задюпать из-за отстутсвия Concurrent.lock (ВРАНЬЕ, НЕТ ТАКОГО, Я НЕ НАШЕЛ (сарказм)).
Реализация инстанс зон (ну ок, я тут тоже приложил свою руку, но только в Храме Валакаса, ибо я его сделал на половину, а потом как-то и не потребовалось, а он просто взял и переназвал некоторые переменные) на очень низком уровне.
Что можно выделить из низкого уровня:
* Храм Валакаса - багается если просто пробежать и убить печать;
* Этис Ван Этина (соло) - просто прекрасный пример как не нужно делать - мобы стоят абы как та и просто страшно смотреть если играть с офа (ведь делали типо под ЦЦ версию);
* Таверны просто не работают. Фрею брать - нет дополнительных НПС, которые могут появится и быть с лутом. Таути - можна забагать если убить после печати Ангела до того, как он договорит и телепортирует. Остальных таверн просто не завезли.
* Убежище Бранштейна - стоят абы как, нету ивент тригеров (не понятно что в зоне происходит), итемы, которые внутри выдаются, не работают, у НПСов нет АИшки и тд...
Возвращаясь к коду...
= TimedHuntingZone - самая прекрасна реализация Сессионных Зон. Сделано по всем заветам, которых мобиус придерживается - економия на спичках и еще каким-то...
По итогу что мы получили:
* Жалобы на то, что народ через дырки в геодате или просто в текстурах пробивается в сесионную зону, ведь ради економии мы их сделаем в обычном мире (нас даже не смутило наличие отдельных иснстанс зон внути ДАТ файлов) (сейчас правда это прикрутили, но такая жесть была, я помню какие костыли ПИЛИЛИСЬ когда я пытался 3 куба ТОИ запихнуть в одну зону);
* Не нужные скрипты, которые проверяют есть ли ты в зоне или нет тебя в зоне для работы с НПСами и телепорта по зонам;
* Забитый болт на то что клиент багается время от времени при выходе с сессионных зон;
И опять, вренемся к коду.
Есть у нас такой прикол как "DailyTaskManager", в котором есть метод "resetClanBonus" (который там где он есть уже не нужен после 228 протокола), но мы не будем его чистить.
В чем его прелесть?
Выглядит просто, да? Просто берем все кланы и сбрасываем им бонус ежедневныйJava:private void resetClanBonus() { ClanTable.getInstance().getClans().forEach(Clan::resetClanBonus); LOGGER.info("Daily clan bonus has been resetted."); }
Давай посмотрим дальше...
Тут уже переменные сбрасываются и дальше идет сброс для каждого игрока клана?Java:public void resetClanBonus() { // Save current state getVariables().set("PREVIOUS_MAX_ONLINE_PLAYERS", getMaxOnlineMembers()); getVariables().set("PREVIOUS_HUNTING_POINTS", getHuntingPoints()); // Reset _members.values().forEach(ClanMember::resetBonus); getVariables().remove("HUNTING_POINTS"); // force store getVariables().storeMe(); // Send Packet broadcastToOnlineMembers(ExPledgeBonusMarkReset.STATIC_PACKET); }
А, ну и просто идет сброс переменной и сохранение в базу.Java:public void resetBonus() { _onlineTime = 0; final PlayerVariables vars = getVariables(); vars.set("CLAIMED_CLAN_REWARDS", 0); vars.storeMe(); }
Ничего такого, никто не думал о том, что на лайве (где не 2 человека и 10 персонажей в офлайне) отработка данного метода может занимать до 15 минут.
Еще у нас есть вот такое красивый метод...
Ну тут как минимум из-за того что может в один момент использоваться для записи clanVariables - может просто ошибка выбиться и сбросится только для некоторых.Код:private void resetClanContributionList() { for (Clan clan : ClanTable.getInstance().getClans()) { clan.getVariables().deleteWeeklyContribution(); } } public boolean deleteWeeklyContribution() { try (Connection con = DatabaseFactory.getConnection()) { // Clear previous entries. try (PreparedStatement st = con.prepareStatement(DELETE_WEAKLY_QUERY)) { st.setInt(1, _objectId); st.execute(); } // Clear all entries getSet().entrySet().stream().filter(it -> it.getKey().startsWith("CONTRIBUTION_WEEKLY_")).collect(Collectors.toList()).forEach(it -> getSet().remove(it.getKey())); } catch (Exception e) { LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Couldn't delete variables for: " + _objectId, e); return false; } return true; }
Та и как по мне - тут очень много кода, который пишется огромными полотнами, по нему очень сложно ориентироваться. Я пытаюсь перебраться и сделать 1 метод - на 1 экран, чтоб видел все что и где происходит.
Ну а полотен там хватает.
Еще хватает излишнего кода (дублирующего к примеру).
Есть у нас Attackable - calculateRewards.
Красивый код, не так ли? Но почему-бы не сделать вот так?Java:final Player player = (maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker.getActingPlayer(); broadcastPacket(new SystemMessage(SystemMessageId.CONGRATULATIONS_YOUR_RAID_WAS_SUCCESSFUL)); final int raidbossPoints = (int) (getTemplate().getRaidPoints() * Config.RATE_RAIDBOSS_POINTS); final Party party = player.getParty(); if (party != null) { final CommandChannel command = party.getCommandChannel(); final List<Player> members = new ArrayList<>(); if (command != null) { for (Player p : command.getMembers()) { if (p.calculateDistance3D(this) < Config.ALT_PARTY_RANGE) { members.add(p); } } } else { for (Player p : player.getParty().getMembers()) { if (p.calculateDistance3D(this) < Config.ALT_PARTY_RANGE) { members.add(p); } } } members.forEach(p -> { final int points = (int) (Math.max(raidbossPoints / members.size(), 1) * p.getStat().getValue(Stat.BONUS_RAID_POINTS, 1)); p.increaseRaidbossPoints(points); p.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points)); if (p.isNoble()) { Hero.getInstance().setRBkilled(p.getObjectId(), getId()); } }); } else { final int points = (int) (Math.max(raidbossPoints, 1) * player.getStat().getValue(Stat.BONUS_RAID_POINTS, 1)); player.increaseRaidbossPoints(points); player.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points)); if (player.isNoble()) { Hero.getInstance().setRBkilled(player.getObjectId(), getId()); } } }
Код стал меньше в два раза и понимание его осталось таким же с учетом всех видов группы.Java:broadcastPacket(new SystemMessage(SystemMessageId.CONGRATULATIONS_YOUR_RAID_WAS_SUCCESSFUL)); final Player player = (maxDealer != null) && maxDealer.isOnline() ? maxDealer : lastAttacker.getActingPlayer(); final int raidbossPoints = (int) (getTemplate().getRaidPoints() * Config.RATE_RAIDBOSS_POINTS); final AbstractPlayerGroup group = player.isInCommandChannel() ? player.getCommandChannel() : player.getParty(); final List<Player> members = group == null ? List.of(player) : new ArrayList<>(); if (group != null) { for (Player member : group.getMembers()) { if (member.calculateDistance3D(this) < Config.ALT_PARTY_RANGE) { members.add(member); } } } for (Player member : members) { final int points = (int) (Math.max(raidbossPoints / members.size(), 1) * member.getStat().getValue(Stat.BONUS_RAID_POINTS, 1)); member.increaseRaidbossPoints(points); member.sendPacket(new SystemMessage(SystemMessageId.YOU_HAVE_EARNED_S1_RAID_POINT_S).addInt(points)); if (member.isNoble()) { Hero.getInstance().setRBkilled(member.getObjectId(), getId()); } }
Там еще есть прекрасное полотно с расчетом експы для пати/соло игрока, в котом только группа добавляется и чуть-чуть меняется из-за этого код, но я уже и так много времени потратил на это
if
{ //Ебаная скоба на всю строку
//Говнокод
} //Ебаная скоба на всю строку, ведь далее мы юзаем какой-нибудь else
else
{ //Ебаная скоба на всю строку
//Говнокод
} //Закрываем ебаной скобой
if {
//Говнокод
} else {
//Говнокод
}
ну е... зачем скобки вообще использовать?Как же 6лять раздражает, когда е6аной скобой занимают целую строку.
Java:if { //Ебаная скоба на всю строку //Говнокод } //Ебаная скоба на всю строку, ведь далее мы юзаем какой-нибудь else else { //Ебаная скоба на всю строку //Говнокод } //Закрываем ебаной скобой
Ведь если к примеру писать вот так, то код нихуя работать не будет:
Java:if { //Говнокод } else { //Говнокод }
if
code; code; code; code;
else
for (;;;)
code; code; code; code;
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?