XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Желтая пресса: обучающие статьи
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

 
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
Создаем загрузочный код
В этой статье я расскажу, как создавать загрузочные коды для online-RPG карт. Советую закачать аттачи и прочитать статью в оффлайне, с открытым WE.
Что нам понадобится:
-Скрипт CCS.j из аттача
-Warcraft 3 TFT версии 1.17 или выше
-Минимальное знание JASS
-Прямые руки =)

Предисловие. Зачем это надо
Ну, например, создал ты мапу для мультиплеера, где можно качать хира до 50 уровня. За один раз, ясен пень, до такого уровня докачаться сложно. Надо как-то сохранять героя, тем более, что если игрок может качаться очень долго, то у него появляется азарт, желание прокачаться до упора, и он может целыми днями играть в твою мапу. Так вот, для сохранения героя большинство мэпмейкеров используют зашифрованный пароль. Некоторые умники (не буду показывать пальцем, но я таких видел) используют кэш, но он в мультеплеере не работает. Вобщем, если ты хочешь создать онлайн-РПГ карту, то без умения создавать загрузочные коды тебе не обойтись.

Глава первая. «cHAm’s Crypt System» или «Шифруй по-нашему!»
сHAm’s Crypt System (далее CCS) - это jass-скрипт, позволяющий без особого труда шифровать числа и переводить их в строку. СCS работает на основе перевода числа в заданную систему исчисления по указанному словарю. Таким образом можно значительно сократить длину загрузочного кода.
Вообще, систему перевода из одной системы исчисления в другую при создании загрузочных кодов предлагал NETRAT еще до меня, однако он написал об этом так заумно, что его не понял почти никто =D. Я же не только создал готовый шифровальный скрипт, но и сейчас объясню, как им пользоваться. Итак, приступим…

Глава вторая. «Перенос CCS на карту» или «Вперед и с песней!»
Сейчас я научу тебя, как правильно сохранить обычного героя на обычной карте.
Прежде всего качаем из аттача файл CCS.rar и извлекаем его куда-нибудь. Сделано? Отлично! Теперь открываем World Editor и создаем новую карту. Размер, тайлсет и прочую фигню поставь на свое усмотрение. Потом сразу создай стартовую локацию для 1 игрока, убери стандартные триггеры и т.д. Едем дальше. Открываешь CCS.j любым текстовым или jass редактором и копируешь содержание в custom script карты. Потом создаешь переменную pvpcache типа буфер игры (game cache) и триггер InitPvP с событием “Map Initialization”. Кидаешь в него два действия:
Game сache – Create a game cache from PvP.w3v
Set pvpcache = (Last created game cache)
И сохраняешь карту. Все, CCS был успешно импортирован!

Глава третья. «Словари» или «Моя твоя не понимай!»
Систему CCS ты уже перекачал на карту, однако работать сейчас она не будет. Почему? Потому, что CCS для шифровки использует словарь символов, и если он не задан, то и шифровать не получится. Сейчас мы его зададим. В комплекте CCS уже имеется один готовый словарь. Его мы и будем пока юзать. Чтобы инициировать словарь, в CCS есть функция CreateGlossary. Единственным параметром этой функции является количество символов в словаре. Это число от 1 до 90. Причем, если ввести число 0, то словарь будет 61 символ, включая нуль. Еще в CCS имеется функция CustomGlossary(string s), которая создает нестандартный словарь, т.е. вместо словаря будет использоваться строка s. ВНИМАНИЕ! Первый символ строки s в нестандартном словаре будет считаться на нуль. Пока нам вполне хватит стандарта на 60 символов, поэтому в триггере InitPvP добавляем действие:
Код:
Custom script: call CreateGlossary(0)

Ок, словарь инициирован, осталось только создать на карте героя, которого мы будем сохранять. Кидаем на карту паладина, создаем переменную Hero типа юнит (unit) и в том же триггере добавляем действие Set Hero=Паладин 0001 <gen>. Итого должно получиться так:

Вот, мы все инициировали, и теперь можно начать шифровать.

Глава четвертая. «Триггер сохранения» или «Пароль «Рыба-Конь»»
Ну-с, приступим… Для начала создай два массива – массив строк str и массив целых чисел int. Потом создаешь новый триггер – Saving с событием
Игрок - Игрок 1 (красный) types a chat message containing -save as Точное совпадение
Все, полигон готов. Теперь кидай такие действия
Код:
Set int[1] = (Hero level of Hero)
Set int[2] = (Level of Благодать for Hero)
Set int[3] = (Level of Божественный щит for Hero)
Set int[4] = (Level of Доспехи веры for Hero)
Set int[5] = (Level of Воскрешение for Hero)
Set int[6] = (Игрок 1 (красный) Золото (текущ.))
Set int[7] = (Игрок 1 (красный) Древесина (текущ.))

Пока хватит. Как видишь, здесь записывается вся инфа о хире и ресурсах с массив int. Теперь это все надо зашифровать. Для шифровки в CCS есть две функции: GetCharCode(integer i) и GetCharCodeWithLength(integer i, integer length). Первая просто шифрует указанное число, а вторая возвращает шифровку с указанной длиной. Т.е., если код получится меньше указанного, то число выйдет с нулями впереди. ВНИМАНИЕ! Функции GetCharCode и GetCharCodeWithLength не работают с числами больше 1000000000 или меньше 0.
Ладно, хорош теории, создаем цикл:
Код:
For each (Integer A) from 1 to 5, do (Actions)
    Цикл - Действия
    Custom script:   set udg_str[bj_forLoopAIndex]=GetCharCode(udg_int[bj_forLoopAIndex])

Присваиваю шифр первых пяти переменных массива int соответственным номерам массива str. Кстати, если кто не знает, bj_forLoopAIndex – это тот же (Integer A) цикла, только в jass. Теперь создаем еще два действия:
Код:
Custom script:   set udg_str[6]=GetCharCodeWithLength(udg_int[6],4)
Custom script:   set udg_str[7]=GetCharCodeWithLength(udg_int[7],4)

Здесь мы шифруем ресурсы, отводя по 4 символа на каждый. В четырех символах можно уместить число до 12960000, поэтому на этого хватит.
Ладно, теперь мы это все сбиваем в две строки:
Код:
Set str[100] = (str[1] + (str[2] + (str[3] + str[6])))
Set str[101] = (str[4] + (str[5] + str[7]))

И выводим пасс игроку:
Код:
Игра  - Display to (All players) the text: (str[100] + (- + str[101]))

Итого, должно получиться так:

Теперь запускаем карту и набираем –save. Работает! Базу сделали, теперь едем дальше…

Глава пятая. «О безопасности и айтемах» или «Будь продвинутым!»
Теперь ты уже познакомился с основами и пора приниматься за штучки «попродвинутее». А именно, за безопасность и сэйв айтемов. Начнем с безопасности. Как известно из курса зоологии, геймеры делятся на два класса – честные геймеры и читеры =). Первые будут честно качать хира и записывать пассы, а вторые попытаются твой пасс взломать. Что же делать? Бородануть их! Для этого используется контрольная сумма. Кидаем перед циклом еще одно действие:
Код:
Set int[8] = (Abs((int[5] + (int[5] - (int[3] - (int[2] + int[1]))))))

То есть прибавляем/вычитаем все числа, кроме дерева и золота, т.к. с ресурсами контрольная сумма будет очень большой… Прописываем после цикла действие
Код:
Custom script:   set udg_str[8]=GetCharCode(udg_int[8])
и добавляем к str[101] еще и str[8]. Также можно зашифровать, например, длину имени игрока и первые две буквы имени, и тогда пасс будет именным, но с этим ты будешь разбираться сам.
Перейдем к айтемам. Чтобы не криптовать их огромные id, в CCS есть три функции:
SetItemNumber(integer id, integer n) - присваивает типу айтемов id номер n
GetItemNumber(integer id) – возвращает номер для типа айтемов id
GetItemId(integer n) – возвращает тип айтема с номером n.
Например, чтобы присвоить кресту перерождения номер 1, надо в триггере InitPvP добавить действие:
Код:
Custom script:   call SetItemNumber('ankh',1)

Теперь можно в пароле добавить новый символ (например str[9]) со значением GetItemNumber(‘ankh’).
Но сейчас мы с тобой этого делать не будем. Сам потом разберешься… Итак, у нас есть вот такой триггер сохранения:

Такой в точности? Тогда приступим к загрузке…

Глава шестая. «Триггер загрузки» или «Грузчика вызывали?»
Наконец, мы закончили сохранение и перешли к загрузке. Создаем триггер Loading с событием
Код:
Игрок - Игрок 1 (красный) types a chat message containing -load as Подстрока

и условием
Код:
(Substring((Entered chat string), 1, 5)) равно –load

Кидаем в него следующие действия:
Код:
Set str[0] = (Substring((Entered chat string), 7, (Length of (Entered chat string))))
If ((Length of str[0]) не равно 10) then do (Skip remaining actions) else do (Do nothing)
Set str[1] = (Substring(str[0], 1, 1))
Set str[2] = (Substring(str[0], 2, 2))
Set str[3] = (Substring(str[0], 3, 3))
Set str[6] = (Substring(str[0], 4, 7))
Set str[4] = (Substring(str[0], 9, 9))
Set str[5] = (Substring(str[0], 10, 10))
Set str[7] = (Substring(str[0], 11, 14))
Set str[8] = (Substring(str[0], 15, 15))

Вот. Здесь мы извлекаем сам код, а потом из него значения параметров игрока. Теперь это все надо разкодировать. Для этого есть функция Decode(string s). Она превращает строку-код s в целое число. Создаем цикл разкодировки:
Код:
For each (Integer A) from 1 to 8, do (Actions)
    Цикл - Действия
        Custom script:   set udg_int[bj_forLoopAIndex]=Decode(udg_str[bj_forLoopAIndex])

Тоже самое, что и при кодировке, только наоборот. Теперь проверяем контрольную сумму и, если она правильная, восстанавливаем хира и ресурсы. Вот так:

Ну вот. Система сохранения/загрузки готова! Кричи «ура»!

Часть вторая
В первой части я рассказал, как создавать простые загрузочные коды. Однако я не уделил нужное внимание шифровке предметов и безопасности кода. Сейчас я буду долго и упорно это внимание уделять =). Поехали…

Глава первая «Что мы знаем» или «Я и так не нуб!»
В первой части я вкратце рассказал о шифровке айтемов и безопасности. А именно, что:
1.Для шифровки предметов можно дать каждой вещи свой номер. Для этого есть функция SetItemNumber(integer id, integer n).
2.После определения номера можно получить как номер предмета по типу ( функция GetItemNumber(integer id) ), так и тип по номеру ( функция GetItemId(integer n) ).
3.Ввиду неизбежного столкновения с агрессивной разновидностью геймеров – читерами, нужно вставлять в пасс контрольные суммы.
И на этом, вроде, все. Если ты знаешь больше, значит тебе незачем читать дальше =).

Глава вторая «Шифруем предметы» или «Шестерых одним ударом»
Уверен, следуя моей статье, ты создал карту, где у тебя создается загрузочный код и сейчас она у тебя на винте. Нет? Ну тогда качай карту-пример из аттача к первой части. В общем, как бы то ни было, карта с генерацией пасса у тебя должна быть открыта. Открыл? Тогда поехали!
Для начала мы будем делать поддержку трех айтемов – зелья хелсов, зелья маны и креста перерождения. Кидай их все на карту, рядом с хиром. Теперь открываешь редактор объектов на вкладке «Предметы», ищешь эти три айтема там. Когда найдешь первый айтем выдели его и жми Ctrl+D. После этого перед названием появится id предмета, запиши его куда-нить. И снова жми Ctrl+D.

И так со всеми тремя айтемами. Сделал? Ок! Теперь открываешь триггер InitPvP и добавляешь там три действия:
Код:
Custom script:   call SetItemNumber('ankh',1)
Custom script:   call SetItemNumber('phea',2)
Custom script:   call SetItemNumber('pman',3)

Как видишь, мы присваиваем кресту перерождения и зельям номера 1,2 и 3 соответственно. Заметь, что ид айтема пишется в ОДИНАРНЫХ кавычках. Номера мы поставили, теперь будем это все шифровать.
Создаешь новую переменную ItemId – массив типа Тип предмета (Item type). Открываешь триггер Saving и добавляешь перед циклом преобразования действия:
Код:
For each (Integer A) from 1 to 6, do (Set ItemId[(Integer A)] = (Item-type of (Item carried by Hero in slot (Integer A))))
For each (Integer A) from 1 to 6, do (Custom script:   set udg_str[bj_forLoopAIndex+10]=GetCharCode(GetItemNumber(udg_ItemId[bj_forLoopAIndex])))

Разъясняю, если ты не понял: Первый цикл сохраняет типы айтемов у героя в переменную ItemId с номерами 1-6. Второй цикл заносит в переменную str с номерами 11-16 номера предметов, занесенные в ItemId. Для расширения кругозора, скажу, что в jass типы «тип юнита», «тип предмета» и «целочисленная» - абсолютно идентичны, поэтому их можно заменять без опасения вылета вара. Теперь в конце триггера заменяем вывод пасса на два действия:
Код:
Set str[102] = (str[11] + (str[12] + (str[13] + (str[14] + (str[15] + str[16])))))
Игра - Display to (All players) the text: (str[100] + (- + (str[101] + (- + str[102]))))
То есть добавляем пассу третью часть с типами айтемов. В итоге должно получиться так:

Готово? Отлично! Теперь приступим к загрузке айтемов. Открываем триггер Loading и меняем действие
If ((Length of str[0]) не равно 15) then do (Skip remaining actions) else do (Do nothing)
На
If ((Length of str[0]) не равно 22) then do (Skip remaining actions) else do (Do nothing)
То есть увеличиваем длину пасса. И перед первым циклом вставляем действия:
Код:
Set str[11] = (Substring(str[0], 17, 17))
Set str[12] = (Substring(str[0], 18, 18))
Set str[13] = (Substring(str[0], 19, 19))
Set str[14] = (Substring(str[0], 20, 20))
Set str[15] = (Substring(str[0], 21, 21))
Set str[16] = (Substring(str[0], 22, 22))
For each (Integer A) from 1 to 6, do (Actions)
    Цикл - Действия
        Custom script:   set udg_ItemId[bj_forLoopAIndex]=GetItemId(Decode(udg_str[bj_forLoopAIndex+10]))

Здесь мы извлекаем зашифрованные айтемы из пасса, а затем расшифровываем их с сохраняем в ItemId с номерами 1-6. Теперь в действиях If прописываем действия:
Код:
For each (Integer A) from 1 to 6, do (Actions)
    Цикл - Действия
        Герой - Create ItemId[(Integer A)] and give it to Hero

То есть добавляем хиру сохраненные айтемы. Должен получиться такой триггер:

Ну, вот и готово сохранение айтемов. Едем дальше, видим мост, на мосту ворона сохнет, я ее беру за хвост, и пускай она помокнет…

Глава третья «Безопасность кода» или «Как бородануть читеров»
Я думаю, хорош уже практики. Карту закрываем и займемся теорией. Щас я буду рассказывать про приемы безопасности кода.
Прием 1. Контрольная сумма.
Про этот прием я уже рассказывал. То есть создается число равное сумме (а может, и разности) некоторых параметров. Например controlsumm=p1+p2+p3-p4+p5. Контрольная сумма весит 1-2 символа, но это незаменимая штука. Она позволяет избежать неприятности с читерами и опечатками.
Прием 2. Именной пасс.
Некоторые «умники» догадываются списывать чужие пассы и забирать их себе. Чтобы этого не происходило, нужно в пассе зашифровать имя игрока. Как это сделать? Легко! Ставим три символа (не обязательно подряд) в пасс. Один символ – первый символ имени игрока, набравшего «-save», второй символ, соответственно второй символ имени, а третий – длинна имени игрока. Этого хватит вполне. Вероятность, что найдутся два разных имени, соответствующих одному шаблону около 3%, поэтому больше заморачиваться не стоит. При расшифровке проверяем, чтобы символы соответствовали реальным символам имени игрока.
Прием 3. Переменный словарь. !!!Не для нубов!!!
Этот прием работает только в CCS. Если ты CCS не юзаешь, можешь не читать. Суть состоит вот в чем: У тебя есть массив строк – словарей, скажем, таких
S[0]=”0918273645”
S[1]=”0123456789”
S[2]=”9876543210”
S[3]=”9081726354”

Перед генерацией кода берешь целочисленную переменную (например, I) и ставишь ей RandomNumer(1,3), далее пишешь
Код:
Custom script: call CustomGlossary(udg_S[0])
Custom script: set str[1]=GetCharCode(udg_I)
Custom script: call CustomGlossary(udg_S[udg_I])

То есть, ставишь словарь ”0918273645” и шифруешь переменную I по нему. Далее ставишь один из словарей массива S, а именно, который имеет номер I. Все! Теперь каждый раз, даже при одинаковых данных пасс будет разный. А узнать, какой именно легко – надо только разкодировать первый символ по словарю ”0918273645”!
Вот три кита, на которых держится безопасность пароля. Усё.

Глава четвертая «Оптимизация по методу NETRAT’a» или «Подать сюда микроскоп!»
Слово предоставляется NETRAT’у.

Рассмотрим теперь более полную модель - пускай нам нужно сохранить героя в такой карте, в которой могут быть использованы книжки ловкости, силы, жизни - то есть такого героя, которому необходимо сохранять дополнительно атрибуты и очки жизни. Разумеется, ни один нормальный герой не может обойтись без инвентаря - ему будет очень обидно, если супер-пупер меч, который он заработал в бесчисленных схватках ценой своих постоянно ноющих и незаживающих ран и ссадин, не перенесется в другую карту, а попросту будет потерян. То есть добавим так же к этой модели и 6-слотовый инвентарь. Возьмем именно шесть слотов, так как это стандартный размер, следовательно такой инвентарь можно считать самым популярным. Если у вас инвентарь более 6 слотов, то вы можете оформить спецзаказ, обращаясь к авторам данной статьи (Сомневаюсь, что найдутся такие люди, которые юзают инвентарь больше 6 слотов и не смогут сделать генератор пассов сами – прим. cHAm), либо сделать все по аналогии самому. Разумеется, помимо уровня героя, неплохо бы еще запоминать уровни его скиллов, добавим и этот пункт в модель.

Итак, входные данные:
1. Уровень героя
2. Уровни скиллов
3. Атрибуты
4. Дополнительные очки жизни
5. Инвентарь
6. Ресурсы

Теперь опишем входные данные более подробно. Пределы будем брать для среднестатистической RPG карты - то есть такие, которых хватает хорошей карте.
1. Уровень героя - целое число, находится между 0 и 100.
2. Уровни скиллов - пускай у нашего героя 5 скиллов, но сумма уровней скиллов не может превосходить уровень героя - это при нормальной прокачке - то есть когда за уровень дается одно очко скилла. Разумеется, скиллы могут быть неравнозначными - то есть могут быть ультимейты, которые мы получаем не так уж и часто. Тогда предположим, что уровень каждого из скиллов не может превосходить 30. Тогда рассчитать максимальное число, которое может понадобиться для хранения данных о скиллах нам поможет комбинаторика. Это число равно 30*30*30*30*30 = 3^5 * 10^5 = 243 * 10^5. Это достаточно большое число, поэтому, пока, оставим его в таком виде.
3. Аттрибуты - три аттрибута, каждый из которых не превосходит 500. Использовать значения больше не рекомендуется, потому что это уже попахивает извращением, в всяком случае карта из рпг может перейти в разряд аркадных. Таким образом все та же комбинаторика дает нам верхний предел числа, которое может однозначно определять все 3 аттрибута как 500*500*500 = 125 * 10^6. Аналогично и это число оставим в таком виде.
4. Дополнительные очки жизни - это очки жизни, которые могут быть получены при помощи томов жизни. Колеблются в пределах от 0 до 20000. Однако эти очки будут
кратны 50 так как том жизни поднимает очки на 50. Значит, мы можем заменить это поле на очки жизни, поделенные на модификатор жизни. В данном случае, модификатор очков жизни равен 50, значит верхний предел для этого поля будет равен 20000/50 = 400. Если вы будете использовать значения больше 20000, то можете увеличить модификатор жизни. Таким образом, мы можем сказать, что значение этого поля колеблется в промежутке между 0 и 400 с модификатором 50.
5. Инвентарь - не думаю, что в своей карте вы будете использовать более, чем 400 вещей. Использовать строковые коды(или соответствующие им численные дескрипторы) для идентификации вещей - это верх расточительства. Объясняю почему - строковые коды используют для идентификации объекта 4 символа(эквивалентные им числовые дескрипторы являются числами порядка 10) - то есть один слот инвентаря будет кодироваться числами десятого порядка - то есть число будет колебаться от 0 до 10000000000, и это только один слот. Нетрудно посчитать что 6 слотов таким образом будут кодироваться 10^60 числом, и в итоге выйдет, что один только инвентарь кодируется 30 символами. Почему так получается - да потому что игра Warcraft использует универсальную кодировку всех своих объектов - то есть каждый игровой объект - будь то дерево, камень, казармы, грант, олень или маска Соби, имеет свой идентификатор типа, причем этот идентификатор уникален. А поскольку в игре используется огромное количество различных объектов, а еще существует возможность добавления пользовательских объектов, то для идентификации используются числа типа longint с огромным верхним пределом. Нам же нужна не универсальная идентификация, а идентификация только вещей. Для этого необходимо создать базу данных вещей - нечто вроде двух массивов - один массив типа int, а второй - item-type. Первый будет содержать
идентификатор вещи по нашей системе, а второй - по системе игры Warcraft. Это может показаться непосильной задачей, однако база такого типа уже создавалась в наработке DimonT'а "Полноэкранный инвентарь", ее нетрудно адаптировать для наших нужд (разумеется при некоторых навыках жасс-скриптера). Таким образом, весь инвентарь можно закодировать числом, находящимся между 0 и 400^6 = 4096 * 10^12.
6. Ресурсы - тут все достаточно просто. Пусть золото находится в пределах от 0 до 100000, тогда возьмем это поле с модификатором 10, получим предел равным 10000 с модификатором 10. Если у вас предел больше, то модификатор тоже можно взять больше. Дерево аналогично - от 0 до 10000 с модификатором 10. Таким образом золото и дерево мы можем закодировать числом, предел которого равен 10^8.

Теперь посмотрим, какое число у нас получается в итоге:
100 * 243 * 10^5 * 125 * 10^6 * 400 * 4096 * 10^12 * 10^8 = 243 * 125 * 4 * 4096 * 10^34 = 497664000 * 10^34 = 497664 * 10^37
Немаленькое число получается, неправда ли?!
Теперь, возьмем максимально возможный словарь - 90 символов.(такой словарь в пассе смотрится крайне некрасиво, поэтому-то я и сделал длину по умолчанию 60. Не спеши всегда ставить 90 символов. - прим. cHAm) И возведем это число в 22-юю степень, получим число, равное 90^22 = 984770902183611232881 * 10^22 ] 984770 * 10^37 а, значит большее числа, которое нам нужно чтобы закодировать всю модель. Таким образом получаем, что для кодирования описанной выше модели, нам необходимо всего 22 символа - то есть код может состоять из 22х символов. Однако это нереализуемо. Для того, чтобы получить оптимальный код, нам придется работать с очень большими числами - более чем 40го порядка. Игра Warcraft неспособна на такие манипуляции. Поэтому нам придется уменьшить эти числа и увеличить длину кода.

Словарь 90 символов позволяет нам наиболее оптимально кодировать числа, ограниченные числами, степени 90, то есть:
90 - один символ
8100 - два символа
729000 - три символа
Числа больше брать не рекомендуется, так как они могут оказаться слишком большими для расчетов.

Объясню теперь, как наиболее оптимально использовать словарь в 90 символов в описанной системе:
1. Для начала, мы можем объединить два поля - поле уровня и поле дополнительных очков жизни - то есть число, представляющее объединение этих полей будет колебаться от 0 до 100*400 = 400000, а такое число может быть закодировано по словарю тремя символами.
2. Далее закодируем объединение поля скилла и поля золота. Оно может колебаться от 0 до 30*10000 = 300000, и, значит, может быть закодировано тремя символами. Такую операцию можно проделать со вторым полем скилла и с количеством ресурсов дерева. То есть еще два объединения по три символа.
3. Затем объединим поле скилла с полем вещи из инвентаря. Такое объединение кодируется числом от 0 до 30*400 = 12000. Объединим таким образом оставшееся три
поля скиллов и первые три поля вещей инвентаря. Три объединения, по три символа каждое.
4. Нам остается только объединить каждую из трех оставшихся вещей, с каждым из трех аттрибутов. Максимальное число, представляющее объединение будет равно 400*500 = 200000. Три объединения, каждое по три символа.

Таким образом получаем длину кода, равную 1*3 + 2*3 + 3*3 + 3*3 = 27 символов. Разумеется, длинна этого кода больше чем длинна оптимального кода, но оптимальный код намного труднее реализовать и генерация такого кода может занять достаточно много процессорного времени, и, значит, вызывать значительные лаги.

Это не самый оптимальный вариант объединения полей, зато достаточно понятный.

Теперь напомню, чем можно пользоваться для уменьшения длинны кода:
1. Модификаторы - то есть множители для чисел, значения которых могут быть достаточно велики, и небольшие ошибки в этих числах не имеют значения. То есть
если у меня 50037 золота, то если я во время сохранения/загрузки потеряю из них 37 единиц, то я не буду сильно о них жалеть. Зато это уменьшит длину кода.
2. Объединения нескольких полей - такой метод не только уменьшает длину, но и делает код более устойчивым к взлому.
3. Уменьшение максимально допустимого значения поля - это означает, что можно "подгонять" максимумы всех полей под длину словаря - например, сделать
максимальное число уровней не 100, а 90 и кодировать ее отдельным символом, или максимальное количество ресурсов сделать не 10000 (с модификатором 50), а 8100 (с модификатором 50) и кодировать это число двумя символами.

В модели отсутствует сохранение накопленного опыта - то есть при загрузке вы получите героя с опытом, соответствующему началу уровня. Поле опыта может принимать различные значения - от нескольких тысяч, до сотен миллионов, поэтому это поле нужно выбирать относительно карты, для которой строится система. Из общих принципов я могу посоветовать только разделить уровень на несколько частей и заносить номер части в дополнительное поле. Вообще говоря, это поле можно и опустить, ну а если оно так важно для вашей карты, то, думаю, вы сможете сделать его по аналогии с другими описанными мной полями.

Так же в модели отсутствует такое поле как Тип героя, но это поле тоже достаточно специфично - сложно предположить сколько типов героев вы будете в нем использовать, в любом случае оно не должно занимать более одного символа. Идентифицировать это поле придется опять же таблицей, вроде той, которую я предлагал для идентификации вещей, но тут она будет намного короче.

Глава пятая «Защита кода по методу NETRAT’a» или «Open Source в студию!»
Пускай у нас есть готовый код - код, который выдается генератором. Так вот предлагаю его перекодировать невырожденным(то есть восстановить оригинальный код вы сможете) преобразованием. Преобразование такого вида - пробегаем все буквы кода, получаем их номер по словарю, добавляем к нему определенное число, находим это число в словаре и вместо взятой буквы, подставляем букву из словаря, соответствующую полученному числу.

Обьясню это все на примере:
Пускай у нас есть словарь - "0WVUYXZRQSTqPONMLponmlKkJjIiHhGgFfEeDdCcBbAa1r2s3t4u5v6w7x8y9z~`!@#$%^&*()-_=+;:[]{},.[]/?" - это словарь по умолчанию из системы cHAm'а. И есть некоторый 8-символьный код "Netrat?!" . Преобразуем его по описанному правилу, с добавлением ключевого числа 21.
Код символа "N" в словаре равен его позиции - то есть 15, добавим к нему число 21, получаем 36, буква с номер 36 из словаря - это "e", далее символ "e" имеет код 36, с добавлением 21 получаем 57, соответственно символ "7", далее, аналогично из символа "t" получаем символ "&", из символа "r" получаем символ "#", из символа "a" получаем символ "!", из символа "t" мы уже получали "&", далее для символа "?" код по словарю равен 90, при добавлении 21 получаем 111, в этом случае число превосходит размер словаря и предлагаю просто поделить на 90 (длину словаря) по модулю - то есть взять остаток от деления на 90, а он будет равен 21 и полученный символ будет "m", для символа "!" получаем символ ".". Тогда исходный код будет кодироваться строкой "e7&#!&m.". Это все достаточно просто реализуется и достаточно эффективно защищает от взлома.(Лично я понял, о чем здесь говорится с третьего раза =) – прим. cHAm) Для обратного преобразования достаточно будет отнять ключевое число от каждого из символов, а если получится отрицательное число, то добавить длину словаря - в данном случае это 90. Для более извращенного кодирования, предлагается добавлять к числу кодирования(то есть к 21) еще и номер позиции символа в коде, тогда код получится еще более безопасным - то есть вот таким "D8)&^=iU". Если вам нужно ввести в код защиту от использования кода другим игроком, предлагаю вместо ключевого числа вводить код буквы ника - либо всегда одной(скажем первой), либо по очередности.(ИМХО пустая трата времени– прим. cHAm)

Однако описанные методы могут раскрываться то есть взламываться открытием j файла карты. Для того чтобы еще сильнее обезопасить код от взлома, предлагаю вместо(или вместе) с ключевым числом ввести какой-нибудь атрибут статического объекта на карте, например угол поворота одного из зданий на карте, или одну из его координат, или положение на карте какого-нибудь специфического дерева. Человеку, вскрывшему *.j файл будет непонятно что это за атрибут и какой единице он соответствует. Даже если он вскроет карту и получит слой дудадов и единиц, то ему придется найти соответствие между объектом на карте и файлом скрипта, а это, если и возможно, то достаточно трудно.

Обращаю ваше внимание, что вышеописанные методы защиты кода от взлома не увеличивают размер самого кода, то есть просто трансформируют код, без увеличения его длинны. Именно поэтому они так удобны.

Глава шестая. «Немного практики» или «Пошлем теорию подальше!»
Последние три главы была исключительно теория. Пора бы это все на практике применить. Итак открываем мапу, что мы сделали. Теперь открываем триггер Saving. Сейчас мы его будем ужимать… Чтобы не переписывать триггер заново кидаем еще два действия перед циклом:
Код:
Set int[2] = (int[2] + (int[3] x 4))
Set int[4] = (int[4] + (int[5] x 4))

Здеся, мы сбиваем четыре абилки в два числа. Теперь кидаем еще 2 действия:
Код:
Set int[6] = (int[6] / 10)
Set int[7] = (int[7] / 10)

То есть делим золото и дерево на 10. Теперь меняем количество символов, выделяемых на ресурсы с 4 на 3:
Код:
Custom script:   set udg_str[6]=GetCharCodeWithLength(udg_int[6],3)
Custom script:   set udg_str[7]=GetCharCodeWithLength(udg_int[7],3)

И изменяем переменные str[100] и str[101]:
Код:
Set str[100] = (str[1] + (str[2] + str[6]))
Set str[101] = (str[4] + (str[7] + str[8]))

Код после этого уменьшится на 4 символа. Неплохо, да? Теперь ужимаем пердметы. Поскольку их только 3, можно использовать на весь инвентарь 3 символа (если хочешь, можешь увеличить их количество до 7). Вместо второго цикла кидаем действа:
Код:
Custom script:   set udg_int[10]=GetItemNumber(udg_ItemId[1])+GetItemNumber(udg_ItemId[2])*4
Custom script:   set udg_int[11]=GetItemNumber(udg_ItemId[3])+GetItemNumber(udg_ItemId[4])*4
Custom script:   set udg_int[12]=GetItemNumber(udg_ItemId[5])+GetItemNumber(udg_ItemId[6])*4
For each (Integer A) from 10 to 12, do (Custom script:   set udg_str[bj_forLoopAIndex]=GetCharCode(udg_int[bj_forLoopAIndex]))

Разъясняю: здесь мы объединяем айтемы в 3 числа, а потом шифруем эти числа. Соответственно, предпоследние действие будет выглядеть так:
Код:
Set str[102] = (str[10] + (str[11] + str[12]))

Еще не все. Как ты, помнишь, здесь существует контрольная сумма. Удаляем ее объявление и перед 1 циклом пишем:
Код:
Set int[8] = (Abs((int[2] - (int[4] + int[1]))))

Усе. Теперь код стал меньше еще на 3 символа. Итого – 15 символов вместо 22. Для перестраховки сравни твой триггер с моим:

Тэкс, теперь приступим к загрузке. Открываем триггер Loading и перестраиваем его под новый триггер сохранения. Я думаю, здесь ты и сам справишься. Скажу только, что для извлечения, скажем второго предмета, нужно первый символ инвентаря разделить на 4, а для первого- узнать остаток от деления на 4. На случай, если у тебя не получается, можешь скатать мой триггер:

Ну вот. Теперь тестим. Работает? Ну тогда ты крутой мэпмейкер!

Эпилог. «Вот и все» или «Концы в воду!»
Ну вот ты и научился создавать полноценный пасс. Конечно можно этот пасс доработать и сделать меньше и безопаснее, но это ты уже сам делай. У меня и так мозги загружены =). Вобщем, основы изучены и дальше ты можешь пробывать создавать пассы самостоятельно. Если есть вопросы, ори, мы с Нетратом услышим :bis: .
Прикрепленные файлы
Тип файла: rar CCS.rar (1.2 Кбайт, 151 просмотров )
Тип файла: w3x TestMap.w3x (17.3 Кбайт, 121 просмотров )
Тип файла: w3x TestMap.w3x (18.3 Кбайт, 175 просмотров )

Отредактировано cHAm, 05.10.2005 в 15:06.
Старый 05.10.2005, 14:03
NETRAT

offline
Опыт: 83,712
Активность:
1. Что ты там фтыкал 3 раза - это же обычные коды символов по твоему дефаултовому словарю =)

2. Если тебе нужна верификация ника, то это самый простой вариант, если нет - не трать время

NETRAT добавил:
Это я про 100 слотовый инвентарь - если вдруг ламеры научатся им пользоваться и захотят сделать его сохранение =) это будет геморрой!
Старый 05.10.2005, 14:23
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
1.Я лишь выражал свое мнение. Если тебе это совсем не нравится, могу убрать.
2.Че-то я не въехал, повтори еще раз и по-русски.
Старый 05.10.2005, 14:26
NETRAT

offline
Опыт: 83,712
Активность:
Ну я что-то совсем не понимаю - ты работаешь со словарем и не понимаешь как я его использую - так что ли?!
Я про то что ник прошивать в код - вполне нормально и просто
Старый 05.10.2005, 14:31
tysch_tysch
Работаем
offline
Опыт: отключен
ребят вы когда закончите мне приваткой свистнити, чтоб я это на сайте разместил=)
Старый 05.10.2005, 14:34
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
Цитата:
Ну я что-то совсем не понимаю - ты работаешь со словарем и не понимаешь как я его использую - так что ли?!

Да все я понимаю. просто ты пишешь черезчур заумно =).

cHAm добавил:
Ну так че, я тогда уберу эти комменты, чтобы еще полчаса не базарить?
Старый 05.10.2005, 14:35
NETRAT

offline
Опыт: 83,712
Активность:
cHAm пытаюсь быть корректным - это же научно-поп.-литература. Придерживаюсь стилистики - чтобы всем понятно было и интересно

коменты ка хочешь, я мысль изложил, комментировать можно
Старый 05.10.2005, 14:56
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
Хех, после клика "Сохранить изменения" у меня вылетает "Невозмодно отобразить страницу". Вощем, комменты оставляю.
Старый 05.10.2005, 15:09
TiM
Старичок
offline
Опыт: 8,594
Активность:
Знаешь, у менятакое мнение:
Сохранение под кодом вещь не черезчур сложная, но геморойная. Вариантов кодировки множество... Но! Если какой-нибуть мапмэйкер захочет сделать код, то он конечноже САМ будет придумывать систему кодировки, сам будет все делать испытывать и в итоге-Сделает это. Как например я года 2назад ;). Это не так уж сложно

Посмотри с другой стороны:
Ты выложил ету тему. Наверняка здесь есть люди, которые любят "почитерить" и еси они не дай бог увидят такую же систему в какой-нибудь карте, то они полезут в ету тему, начнут ЛОМАТЬ карту, например депротектором НЕТРАТА ;). Сломают, найду ИД вещей и будут писать самых грозных героев. Даже если не взломают-они будут тестить, менять вещи туда-сюда итд ;). Так что ЛУЧШЕ-делать собственный код, пусть это геморойно, но можно на порядок повысить свой интеллект!

TiM добавил:
Кстати, например карта МЯСО1-4. Тама помоему есть тож какая-то система загрузки, но она такая нупрактичная и просто говоря ТУПАЯ! Я с первого раза никак не смог! поиграть. Просто поиграть. Тама проблема такая, что неуспеваешь просто код ввести, как идет волна, не успеешь сохраниться, записать код , как тебя разорвут на части!;)

И еще! Рекомендую в мультиплеерной карте в начале делать всех друг с другом врагами а затем всех СОЮЗНИКАМИ с одним из компов, тогда мона будет писать код "отправить союзникам", а союзник-глупый комп ;) вот так вот!

TiM добавил:
Обожаю фишку- пишешь код в своей карте и тебе ЛИЧНО приходят все сообщения, которые пишут враги ;) рекомендую попробовать!
Старый 05.10.2005, 16:32
NETRAT

offline
Опыт: 83,712
Активность:
TiM ну да, ты еще скажи что в Мясе крутой код, потому что мапмейкер его сам придумал... Тут фича в том, что словарь и ключи будут именно твои, да и алгорит можешь прошить свой - то есть cham за тебя уже сделал 80% работы. Хорошо сделать сложно.

Ты не пользовался депром - взломать карту тоже не так просто сломать, это уметь нужно. Депр - не панацея. Попробуй доту ломануть для начала. И почитав статейку, разобравшись в примерах - пиши свою систему, ради бога, но ты уже будешь намного более подкован, чем когда ты все берешь это из своей головы

В мясе элементарно тупая система - данные хранятся в кеше, а код - это просто проверка и левел. Проверки элементарнейшие, ломается за пол часа

Неплохая идея, если работает...
Старый 05.10.2005, 18:46
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
Алё, Тыща, ты статью выкладывать будешь или нет? А то я те приватку послал, а ты так ниче и не ответил...
Старый 13.10.2005, 11:29
vlad_C0M
Босс DarkSkyTeam
offline
Опыт: 10,459
Активность:
Ну и я скажу свое скромное мнение... Как бы я (если бы захотел себе героя получше).

Вытащил файл джассовой версии триггеров. Создал себе юнита с нужными параметрами... И просто прогнал этого юнита через карту в б нете. После того как я нажал сэйв. Я получил бы все эти заморочки в готовом варианте этого кода.... Скопировал бы и записал под именем код на самого ядреного героя такой то там карты.

Дело - в том, что можно не ломится на пролом, ломая кодировки и загружая голову.... А можно это все наипростейшим образом использовать, чуть ли не себе на благо.
Старый 14.10.2005, 08:20
TiM
Старичок
offline
Опыт: 8,594
Активность:
Для НЕТРАТА: Ты написал, что МОЖНО ССЫЛАТЬСЯ, допустим на дерево. Как он может его найти!?!? Еси он НУБА, то он пошлет этот взлом. А еси он провел хоть один месяц за триггерами- он подумает и придумает команду: ПИНГ МИНИКАРТЫ НА ПОЗИЦИИ ДЕРЕВА...ххх. Отметится и найдет. Вот и все! Облом нашему коду! А ваще я не рекомендую делать через систему последовательности символов. Лучше делать самому систему кодировки. И чтобы она была "случайной". Типа для шифровки ника, или ИД предмета , например ankh, соответствовало так- для буквы "а" варианты A&G или Y&Н(я использовал по два СИМВОЛА на одну букву кодировки).

TiM добавил:
А у меня еще проектик был- Hero Hack. Короче смысл в том, что ты выбираешь себе любого героя, делаешь ему лвл, даешь ему предметы,он сохраняется в КЭШЕ и выбираешь через ДИАЛОГОВОЕ меню любой УРОВЕНЬ из кампаний- например в Миссии за андедов у тебя будет вместо артеса-блейд-мастер. Тока я заеб-ся и запутался в системе буфа в каждой карте.
Старый 15.10.2005, 20:41
NETRAT

offline
Опыт: 83,712
Активность:
TiM ну, вообще говоря про дерево - это как вариант ключа - аттрибут дерева. По-крайней мере это изошренный вариант и кто тебе мешает этот ключ проксорить с твоим? Кстати пинг миникарты тебе ничего не даст - тебе нужен аттрибут обьекта, а не сам обьект. И нет облома! Подумаешь, получил один из ключей, а если таких ключей много? Ну об этом уже много говорилось - нормальному жассеру не проблема взломать как саму карту так и любой код. Все что для этого нужно это время и терпение. Случайная кодировка тебе не даст распутать код. Случайной кодировки просто не может быть. Все что ты можешь сделать - это как можно глубже запутать концы твоего алгоритма - чтобы их сложнее было распутать. А для этого любой способ подойдет. Ну и как вариант взлома - то что описал vlad_C0M - если такая фича пройдет, то тут ни один код и ни один алгоритм не поможет.

Неплохая идея была =)
Старый 16.10.2005, 00:16
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
Да ваще, взломать карту - проще простого. Тут хоть че хошь делай, не поможет. вот, например, готовая версия крякера на Мясо 2. Правда, доисторическая штуковина, но все же рабочая... Тута я даже не вникал в структуру кода, просто триггер перекопировал.
Старый 21.10.2005, 12:32
KENDO

offline
Опыт: 5,817
Активность:
может глупый вопрос...
а это зачем нужно? ;)
сорри если займу ваше время, просто до меня не че не допирает..
Старый 21.10.2005, 20:54
NETRAT

offline
Опыт: 83,712
Активность:
KENDO читай самый большой пост в этой теме (а может и на форуме) где вся статья целиком - там в начале второй абзац посвящен именно ответу на твой вопрос
Старый 21.10.2005, 21:38
KENDO

offline
Опыт: 5,817
Активность:
;) сорри как ни странно этот абзац я пропустил..
Старый 22.10.2005, 17:59
cHAm
Бывший модмейкер
offline
Опыт: 5,291
Активность:
Але, адимны, статью кто-нить будет выкладывать или я зря старался???
Старый 01.11.2005, 09:16
NETRAT

offline
Опыт: 83,712
Активность:
Done!
Второй аттач TestMap скачать не могу
Старый 01.11.2005, 13:20

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 19:49.