You are not logged in.
Было бы совсем здорово, если сейчас появился listener и развеял тучи пессимизма своей невероятной позитивной энергетикой и технической подкованностью, и буквально написал "да я смотрел что у них в rdr2, все легко, вот база ida, и в gta vi все будет просто, а моды не делают потому что вокруг много лентяев ". Тогда я буду рад ошибаться.
Допустим, я появлюсь. И, допустим, скажу, что да - RDR2 практически не отлючается от от пятёрки: ну, новый формат архива, ещё кое-что по мелочи...
И это всё будет чистой правдой, и даже вполне оптимистично... Но что делать с лентяями?
Скриптовый мод - это история. История, которую нужно не только придумать, но и правильно преподнести. История, для которой нужно создать нарратив.
Проблема пятёрки в том, что она набита так, что места для добавления своего нарратива - просто не остаётся. Слишком плотная история. Слишком детальные персонажи... И добавление к этому, не влезая в ловушку total conversion - будет смотреться неуместно.
Вот как-то так.... Не совсем позитивненько.
Нет. Зеркала в GTA создаются как виртуальные камеры с выводом в текстуру
И вот опять 31-е. До нового года осталось 12 часов (а для большинства здесь присутствующих - всего четыре).
У нас был веселый год. Следующий должен быть еще веселее.
У нас большие планы на слдующий год (но о них мы скажем, when it will be done).
У меня лично, это тоже был очень насыщенный год. Я активно мотался по планете и, за год, в общей сложности, пропутешествовал порядка 50 000 км.
Так что, всего наилучшего, успехов и достижений!
PS. А предновогодний Vice City выглядит как-то так:
cmp cx, 208h
208h = 520 => т.е. hydra
В теории, можно попробовать убрать эту проверку
1. не sizeof (4), а просто 4 - иначе это может быть значение от 1 до 8, в зависимости от того, какой тип для 4 предложит компилятор
2. насколько я понимаю, читается g_pPlayerVehicle->m_pHandling->m_dwIndex. формально - все правильно
1) p1 нужно проверять на NULL (находится ли игрок в машине - иначе получим GPF, если он идет пешком)
2) за давностью лет, я не помню, что там с индексами. Если я вспомнил правильно, 188 - это hotdog.
Во время летит...
Мои поздравления.
Встречный вопрос, лол:
как вернуть игроку управление в катсценах?
В катсценах управление игроку вернуть нельзя, потому что там нет игрока.
Катсцена - это просто записанная анимация, которая рендерится в реалтайме и использует текущие модели игрока и персонажей.
Касательно .dll - там получается порядка 100 хуков.
Очень оптимистичный прогноз ^_^. По большому счёту, чтобы получить рабочую dll, нужно заменить достаточно много моих функций с макросом __DUMMY() - а их только при запуске игры вызывается около 300. Плюс перехватить обращения к глобальным объектам.
Кстати, CPopulation имеет только статические поля, поэтому, по-хорошему, на каждое его поле должна быть своя ссылка, иначе, опять-таки, будем привязаны к одному .exe.
А здесь начинается группировка. Если к каждой переменной обращаться отдельно, то хуков будет немерянно.
Но, в исходном коде, переменные и функции обявляются внутри модуля, и обращений извне достаточно мало.
Т.о., если мы реализуем всю (или, хотя бы, большую часть) функциональности модуля, переменные, не используемые извне можно будет оставить внутри своего модуля и не обращаться к ним в игровой памяти.
CPopulation - статический экземпляр объекта. Все обращения непосредственно к полям сгенерированы оптимизатором.
Для IV я объявлял и CPopulation и CPopCycle (вот он - просто огромный, 17М)
Работы с ресурсами в RWG практически нет, если не считать чтение RwStream. Там по коду получается совсем чуть-чуть, строчек триста, и это именно та часть, которая сильно помогает разобраться в структуре объектов RW.
Я сюда включаю работу с RwFrame, RwAtomic, RwImage, RwRaster, RwTexture и т.д. Сам RWGraphics тут, по сути, выступает в роли менеджера объектов этих типов, предоставляя более-менее кроссплатформенный API.
Текущая реализация в ogRW.cpp не настолько гибкая без системы плагинов - на мой взгляд, довольно неплохой фишки. Сейчас там, практически, аналоги Rw-структур, только с методами вместо функций. Неплохое начало, но на более-менее рабочую замену RW нужно ещё N-ое количество времени. Если это действительно интерсено, то можно создать проект в солюшене и постепенно переписать необходимый набор функций, но я бы пока что переключился на более актуальные задачи - по крайней мере, мне всё сразу не потянуть.
А здесь, все зависит от того, что мы хотим.
У меня была конкретная цель: сделать нечто, что может полностью заменить ту часть RWG, которая используется в SA.
Развивать серьезно, в том виде, в котором оно есть - непродуктивно. Для начала - хотелось перейти полностью на собственный код не сильно отступая от идеологии, а потом уже думать, что можно улучшить.
Заниматься этим прямо сейчас некогда, да и я уже давно переключился на RDR и пятерку.
Немного пооффтоплю, но уж очень хочется спросить listener'а:
осталось ли что-нибудь от похожего openLC?
не моё дело, конечно, но чем продиктовано решение разрабатывать просмотрщик скриптов RDR на JS?
openRage/IV - осталось порядка мегабайта кода.
openRage/MP3 - еще полмегабайта (в основном, графика)
Еще есть немного по RDR и пятерке, но там, в основном, всякая инструментальщина - дамперы карт и т.д.
Сейчас я пытаюсь как-то навести в этом порядок, а то пять разных версий только для реализации atPtr/atArray/atMap - немного напрягают.
Учитывая, что я мотаюсь по планете, как укуренный страус (40 000км - кругосветка - толко за последние три месяца) - времени на это найти проблематично
А JS я просто люблю, и, сейчас пишу практиески только на нем (я просто не вижу никакой альтернативы)
Касательно .dll - там получается порядка 100 хуков.
В общем случае - это достаточно сильно помогает - когда стремишься минимизировать количество хуков, с одной стороны, лучше получается разбиегие на модули, с другой - собираются статические объекты (когда нужен один адрес большого объекта, например, CPopulation, а не полсотни ссылок на его поля).
Работы с ресурсами в RWG практически нет, если не считать чтение RwStream. Там по коду получается совсем чуть-чуть, строчек триста, и это именно та часть, которая сильно помогает разобраться в структуре объектов RW. Большая часть у меня была сделана (я не вспомню точно, чего там не было, кажется, было недоделано чтение нескольких чанков).
Как человек, заваривший эту кашу, могу только порадоваться.
А вот по исполнению - у меня есть вопросы.
Во-первых, как предполагается это отлаживать? gta_sa_dll неспроста был именно .dll - там я шел, последовательно заменяя куски кода и проверяя, как заменилось. Более того, можно было вызвать оригинальную функцию и сравнить результат.
Как это предполагается здесь?
Дальше... имеет ли смысл цепляться за библиотеки от RWG ? Учитывая количество кода, которое из них используется, не проще ли его переписать? (я ведь даже начинал это, и какой-то ощутимый кусок сделал)
И еще... Нужно ли тянуть заведомо устаревшие решения? Например, те же пулы, в пятерке почти такие же, но аллокация в них гарантировано за O(1). Всех изменений - по паре строчек в конструкторе, alloc и release.
Надеяться не вредно, вредно не надеяться.
Там все плохо. Даже если расшифровать exe-шник, не становится ни капли легче.
Ключи-то я достал за пять минут. Проблема в том, что они используются для двух .rpf (из, примерно, полутора тысяч).
Что делать с остальными - пока нет ни малейших идей.
Не имеется. И даже не в паблике.
Просто, я занимался EfLC 1.1.2, который отличается буквально парой объектов.
А вести параллельно две базы - у меня просто сил не хватает
Я уже, как и говорил, два с половиной года покрутился в этой кухне, и, об упомянутых событиях... скажем так - знаю несколько больше.
А от политики - всегда можно убежать. Есть масса мест, где этот зверь не водится.
Где я - это, на данный момент времени, достаточно сложный вопрос. Надеюсь, что через два-три месяца на этот вопрос появится простой и четкий ответ, и тогда я расскажу подробно. А пока - можно быть уверенным в одном: пока в OpenIV появляется поддержка новых форматов - я где-то есть.
А политики - не надо. Поверьте опыту человека, который два с половиной года имел отношение к внутренней кухне этой гадости.
И, если я не успеваю появляться на форумах - у меня, действительно есть ЖЖ, есть facebook и даже есть linkedin (не к ночи он будь помянут)
rutracker, искать IDA Pro
6.5 не пробовал, в 6.1 точно все работает
До нового года в Москве остались считанные минуты. Прошедший год был какой-то мутный в целом, но, тем не менее подарил нам много новых возможностей приложения сил.
Хочется, чтобы в новом году эти возможности реализовались в массу новых интересных вещей. Помните, что каждая написанная функция, каждая созданная модель, каждая нарисованная текстура - это средний палец, показанный всеобщему отупению.
С наступающим!
Судя по отсутствию комментариев, либо всем все понятно, либо все онемели от ужаса. Логичнее предположить второе. (Есть, конечно, вариант, что это никто не прочел, но, пока, на нем останавливаться не будем...)
Наверное, стоит разобрать некоторые места подробно и с примерами.
0. Некоторые замечания по устройству VMX128.
VMX128 можно считать аналогом SSE. В нем, так же, производятся операции над 128-битными регистрами, которые, в зависимости от команды, могут представляться массивом элементов того или иного типа.
В отличие от оригинального VMX/Altivec, количество регистров увеличено с 32 до 128. Кроме этого, добавлено несколько очень полезных команд, например, vmsum3fp128 и vmsum4fp128.
Еще одно важное отличие - из-за увеличившегося количества регистров, стало невозможно использовать в команде четыре различных регистра (4*ln2(128) = 28, что не укладывается в отведенные на параметры 26 бит).
Как следствие, команды vmadd и vnmsub существуют в нескольких различных вариантах (например vmaddfp, vmaddfp128 и vmaddcfp128).
Все три команды делают одно и то же: VT = VA * VB + VC. Но, если оригинальный vmaddfp использует полноценные четыре регистра, 128-варианты ограничены только тремя. Из-за этого, в них VT должен совпадать с одним из регистров-параметров.
Т.е., для vmadd128 получается VC += VA * VB, а для vmaddcfp128: VB *= VA; VB += VC. В коде, тем не менее, по историческим причинам записываются все четыре регистра (два из которых должны совпадать)
Аналогичная ситуация - с vnmsubfp/vnmsubfp128. В vnmsubfp128 получается VB = VC - VA * VB.
Еще одно ограничение - для команды vperm128, в качестве маски могут использоваться только регистры %vr0 .. %vr7.
1. Загрузка и сохранение операндов.
Традиционно, векторные операнды должны располагаться по адресам, кратным 16 байтам. Попытка получить вектор по невыровненному адресу в SSE, приведет к возникновению исключения.
В VMX пошли даже дальше, и адреса выравниваются автоматически: все команды VMX, которые обращаются к памяти, просто обнуляют младшие четыре бита адреса.
В качестве адреса, выступает сумма двух регистров общего назначения - как правило, в одном хранится база (например, указатель на объект или массив), в другом - смещение в объекте или массиве.
В этом правиле есть одно исключение: если в качестве первого регистра (RA) используется %r0, то используется не значение %r0, а просто 0.
Для загрузки из памяти используется команда lvx, для сохранения - stvx.
1.1. Загрузка невыравненного операнда.
Те, кто работал с SSE, должны вспомнить, что в SSE можно загружать одиночный float с произвольного адреса. Как обстоят с этим дела в VMX ?
В VMX с этим еще лучше: в нем можно загружать не только отдельное число, но и операнд произвольной длины с произвольного адреса. Для этого, есть две способа: один классический, второй - введенный в VMX128.
Для наглядности, стоит снова прибегнуть к ASCII-artу.
Пусть у нас есть 32 байта в памяти, и два VMX-регистра с некоторыми значениями
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ 87654320: | A0 | A1 | A2 | A3 | A4 | A5 | A6 | A7 | A8 | A9 | AA | AB | AC | AD | AE | AF | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ 87654330: | B0 | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 | B9 | BA | BB | BC | BD | BE | BF | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ %vr8: | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 3A | 3B | 3C | 3D | 3E | 3F | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ %vr9: | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 4A | 4B | 4C | 4D | 4E | 4F | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ %r5 = 0x87654300 %r6 = 0x00000039
"Классический" способ, подразумевает использование команд lvsl/lvsr и vperm.
Команда vperm позволяет скомбинировать содержимое двух регистров в один, при этом, в отличие от SSE-аналога, выбор отдельных компонентов, производится с точностью до отдельного байта.
Т.о., чтобы загрузить 16-байтовый операнд с адреса 0x87654339, нужно загрузить 32 байта с адреса 0x87654330 в два регистра, после чего скомбинировать 7 байт из первого регистра и 9 байт из второго.
lvx %vr8, %r5, %r6 # загружаем первые 16 байт addi %r7, %r6, 0x10 # подготавливаем смещение второй части .. lvx %vr9, %r5, %r7 # .. и загружаем ее vlsl %vr7, %r5, %r6 # подготавливаем маску: берем из 32-байтного числа 16 последовательных байт, начиная с 9-го байта. # получившаяся маска: 0x090A0B0C0D0E0F101112131415161718 vperm %vr10, %vr8, %vr9, %vr7 # собираем нужные байты в один регистр: # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ # %vr10: | A9 | AA | AB | AC | AD | AE | AF | B0 | B1 | B2 | B3 | B4 | B5 | B9 | B7 | B8 | # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
Недостаток метода в том, что в нем всегда читается из памяти 32 байта, даже если можно было обойтись меньшим количеством. Кроме того, сохранить что-то в память таким способом - достаточно проблематично
Чтобы избежать этого, в VMX128 добавили команды lvlx и lvrx, которые читают произвольное количество байт с произвольного адреса, выравнивая их, сосответственно, по левому либо правому краю регистра
Что из этого получается, проще показать на картинке:
lvlx %vr8, %r5, %r6 lvrx %vr9, %r5, %r6 # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ # %vr8: | A9 | AA | AB | AC | AD | AE | AF | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ # %vr9: | 00 | 00 | 00 | 00 | 00 | 00 | 00 | A7 | A8 | A9 | AA | AB | AC | AD | AE | AF | # +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
Аналогично, для записи части регистра в память, введены stvlx и stvrx.
Кроме этого, есть команды stvbx/stvhx/stvwx, которые позволяют сохранить в память произвольный байт, WORD и DWORD из регистра. Адрес в памяти выравнивается на размер сохраняемого операнда.
1.2. Операции с данными в регистрах
Забавный факт: в VMR отсутствует команда mr для векторных регистров. Вместо нее используется конструкция vor VT, VS, VS => VT = VS
Нужно ли продолжать? Стоит ли описать подробно, как работают Splat и Merge; уточнить, как работает преобразование типов с saturationи т.д., или все это и так знают?
Прошло какие-то пять с половиной лет, и я дозрел до продолжения.
До выхода GTAV все было хорошо: код был простой, разбирался легко, многие непонятные вещи можно было подсмотреть на PC. Все изменилось с выходом пятерки.
Самое большое (и самое неприятное) отличие от предыдущих игр - повсеместное использование VMX. Раньше, VMX применялся достаточно мало и, о непонятных командах можно было догадаться по смыслу. В пятерке же, началась битва за эффективность, и теперь мы можем наблюдать огромные куски кода, целиком состоящие из VMX-команд.
Проблема усугубляется тем, что единого внятного описания этих команд просто нет. Что-то есть в документации на Xenon, что-то есть в офицальном мануале по Altivec, о чем-то можно только догадаться.
Как человек в меру ленивый, я потратил день на сборку псевдокода всех используемых в GTAV VMX-команд.
Для начала - немного ASCII-art: формат регистра, который я использую в псевдокоде.
// all indices are from low addresses to high +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ char | c0 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c9 | cA | cB | cC | cD | cE | cF | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ BYTE | b0 | b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | b9 | bA | bB | bC | bD | bE | bF | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+ short | s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7 | +---------+---------+---------+---------+---------+---------+---------+---------+ WORD | w0 | w1 | w2 | w3 | w4 | w5 | w6 | w7 | +---------+---------+---------+---------+---------+---------+---------+---------+ int | n0 | n1 | n2 | n3 | +-------------------+-------------------+-------------------+-------------------+ DWORD | u0 | u1 | u2 | u3 | +-------------------+-------------------+-------------------+-------------------+ float | x | y | z | w | +-------------------+-------------------+-------------------+-------------------+ union VMXREG { struct sint8 { char c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, cA, cB, cC, cD, cE, cF }; struct uint8 { BYTE b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, bA, bB, bC, bD, bE, bF }; struct sint16 { short s0, s1, s2, s3, s4, s5, s6, s7 }; struct uint16 { WORD w0, w1, w2, w3, w4, w5, w6, w7 }; struct sint32 { int n0, n1, n2, n3 }; struct uint32 { DWORD u0, u1, u2, u3 }; struct flt { float x, y, z, w }; char cv[16]; BYTE bv[16]; short sv[8]; WORD wv[8]; int nv[4]; DWORD uv[4]; float fv[4]; };
Дальше - сам псевдокод.
Замечание: некоторые вещи, возможно, будут нуждаться в дополнительном разъяснении: например, понять, что делают lvlx/lvrx/stlx/stvx без картинки, практически невоззможно. А краткое описание vpkd3d128/vupkd3d128 занимает по четыре страницы на каждую.
Плюс к этому, для некоторых команд, IDA Altivec Plugin выводит некорректный порядок операндов - я это подкорректирую по мере нахождения.
lvlx/lvlx128 V, RA, RB p = (RA + RB) & ~15; c = (RA + RB) & 15; V = *p << c*8; // load register from unaligned address to next aligned address, from left lvrx128 V, RA, RB p = (RA + RB) & ~15; c = (RA + RB) & 15; V = *p & ((1 << (16-c)*8)-1); // load register from next aligned address to unaligned address, from right lvsl V, RA, RB c = (RA+RB)&15; V = (0x000102030405060708090A0B00C0D0E0F101112131415161718191A1B1C1D1E1F >> (16-c)*8) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // get 16 bytes from 32 bytes vector lvsr V, RA, RB c = (RA+RB)&15; V = (0x000102030405060708090A0B00C0D0E0F101112131415161718191A1B1C1D1E1F >> c*8) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; // get 16 bytes from 32 bytes vector lvx/lvx128 V, RA, RB V = *((RA + RB) & ~15); stvebx V, RA, RB p = (RA + RB); c = (RA + RB) & 15; *p = V.bv[c]; // store arbitrary byte from the register stvehx V, RA, RB p = (RA + RB) & ~1; c = (RA + RB) & 15; memcpy (p, V.bv+c, 2); // store 2 bytes from the register stvewx/stvewx128 V, RA, RB p = (RA + RB) & ~3; c = (RA + RB) & 15; memcpy (p, V.bv+c, 4); // store 4 bytes from the register stvlx/stvlx128 V, RA, RB p = (RA + RB) & ~15; c = (RA + RB) & ~15; *p = (*p & ~ ((1 << (16-c)*8)-1)) | (V >> c*8); // store 16-c leftmost bytes of register stvrx/stvrx128 V, RA, RB p = (RA + RB) & ~15; c = (RA + RB) & ~15; *p = (*p & ((1 << (16-c)*8))-1)) | (V << ((16-c) * 8)); // store only c rightmost bytes of register stvx/stvx128 V, RA, RB *((RA + RB) & ~ 15) = V; vaddfp/vaddfp128 VT, VA, VB VT.x = VA.x + VB.x; VT.y = VA.y + VB.y; VT.z = VA.z + VB.z; VT.w = VA.w + VB.w; vaddsws VT, VA, VB VT.n0 = satS32 (VA.n0 + Vb.n0); VT.n1 = satS32 (VA.n1 + Vb.n1); VT.n2 = satS32 (VA.n2 + Vb.n2); VT.n3 = satS32 (VA.n3 + Vb.n3); // saturate to range -2,147,483,648 .. 2,147,483,647 vaddubm VT, VA, VB VT.b0 = VA.b0 + Vb.b0; ...; VT.bF = VA.bF + Vb.bF; vadduwm VT, VA, VB VT.u0 = VA.u0 + Vb.u0; VT.u1 = VA.u1 + Vb.u1; VT.u2 = VA.u2 + Vb.u2; VT.u3 = VA.u3 + Vb.u3; vand/vand128 VT, VA, VB VT = VA & VB; // 128 bit logical op vandc128 VT, VA, VB VT = VA & ~VB; // 128 bit logical op vcfpsxws128 VT, VA, Imm VT.n0 = satFtoS32 (VA.x * (1 << Imm)); VT.n1 = satFtoS32 (VA.y * (1 << Imm)); VT.n2 = satFtoS32 (VA.z * (1 << Imm)); VT.n3 = satFtoS32 (VA.w * (1 << Imm)); // saturate to range -2,147,483,648 .. 2,147,483,647 vcfpuxws128 VT, VA, Imm VT.u0 = satFtoU32 (VA.x * (1 << Imm)); VT.u1 = satFtoU32 (VA.y * (1 << Imm)); VT.u2 = satFtoU32 (VA.z * (1 << Imm)); VT.u3 = satFtoU32 (VA.w * (1 << Imm)); // saturate to range 0 .. 2^32-1 vcfsx VT, VA VT.x = VA.n0; VT.y = VA.n1; VT.z = VA.n2; VT.w = VA.n3; vcfux VT, VA VT.x = VA.u0; VT.y = VA.u1; VT.z = VA.u2; VT.w = VA.u3; vcmpbfp128 VT, VA, VB VT.u0 = ((VA.x < VB.x) << 31)| ((VA.x > -VB.x) << 30); ...; VT.u0 = ((VA.x > VB.x) << 31)| ((VA.x < -VB.x) << 30); vcmpbfp128. VT, VA, VB VT.u0 = ((VA.x < VB.x) << 31)| ((VA.x > -VB.x) << 30); ...; VT.u0 = ((VA.x > VB.x) << 31)| ((VA.x < -VB.x) << 30); CR0:4 = 0; CR0:5 = VT == 0; CR0:6 = CR0:7 = 0; vcmpeqfp/vcmpeqfp128 VT, VA, VB VT.u0 = VA.x == VB.x ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.w == VB.w ? 0xFFFFFFFF : 0; vcmpeqfp128. VT, VA, VB VT.u0 = VA.x == VB.x ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.w == VB.w ? 0xFFFFFFFF : 0; CR0:4 = 0; CR0:5 = (VA.x != VB.x) && ... && (VA.w != VB.w); CR0:6 = 0; CR0:7 = (VA.x == VB.x) && ... && (VA.w == VB.w); vcmpequb VT, VA, VB VT.b0 = VA.b0 == VB.b0 ? 0xFF : 0; ...; VT.bF = VA.bF == VB.bF ? 0xFF : 0; vcmpequb. VT, VA, VB VT.b0 = VA.b0 == VB.b0 ? 0xFF : 0; ...; VT.bF = VA.bF == VB.bF ? 0xFF : 0; CR0:4 = 0; CR0:5 = (VA.b0 != VB.b0) && ... && (VA.bF != VB.bF); CR0:6 = 0; CR0:7 = (VA.b0 == VB.b0) && ... && (VA.bF == VB.bF); vcmpequw128 VT, VA, VB VT.u0 = VA.u0 == VB.u0 ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.u3 == VB.u3 ? 0xFFFFFFFF : 0; vcmpequw128. VT, VA, VB VT.u0 = VA.u0 == VB.u0 ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.u3 == VB.u3 ? 0xFFFFFFFF : 0; CR0:4 = 0; CR0:5 = (VA.u0 != VB.u0) && ... && (VA.u3 != VB.u3); CR0:6 = 0; CR0:7 = (VA.u0 == VB.u0) && ... && (VA.u3 == VB.u3); vcmpgefp/vcmpgefp128 VT, VA, VB VT.u0 = VA.x >= VB.x ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.w >= VB.w ? 0xFFFFFFFF : 0; vcmpgefp128. VT, VA, VB VT.u0 = VA.x >= VB.x ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.w >= VB.w ? 0xFFFFFFFF : 0; CR0:4 = 0; CR0:5 = (VA.x < VB.x) && ... && (VA.w < VB.w); CR0:6 = 0; CR0:7 = (VA.x >= VB.x) && ... && (VA.w >= VB.w); vcmpgtfp/vcmpgtfp128 VT, VA, VB VT.u0 = VA.x > VB.x ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.w > VB.w ? 0xFFFFFFFF : 0; vcmpgtfp128. VT, VA, VB VT.u0 = VA.x > VB.x ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.w > VB.w ? 0xFFFFFFFF : 0; CR0:4 = 0; CR0:5 = (VA.x > VB.x) && ... && (VA.w > VB.w); CR0:6 = 0; CR0:7 = (VA.x <= VB.x) && ... && (VA.w <= VB.w); vcmpgtsw VT, VA, VB VT.u0 = VA.n0 > VB.n0 ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.n3 > VB.n3 ? 0xFFFFFFFF : 0; vcmpgtub VT, VA, VB VT.b0 = VA.b0 > VB.b0 ? 0xFF : 0; ...; VT.b7 = VA.b7 > VB.b7 ? 0xFF : 0; vcmpgtuw. VT, VA, VB VT.u0 = VA.u0 > VB.u0 ? 0xFFFFFFFF : 0; ...; VT.u3 = VA.u3 > VB.u3 ? 0xFFFFFFFF : 0; CR0:4 = 0; CR0:5 = (VA.u0 > VB.u0) && ... && (VA.u3 > VB.u3); CR0:6 = 0; CR0:7 = (VA.u0 <= VB.u0) && ... && (VA.u3 <= VB.u3); vcsxwfp128 VT, VA, Imm VT.x = (float)VA.n0/(float)(1 << Imm); VT.y = (float)VA.n1/(float)(1 << Imm); VT.z = (float)VA.n2/(float)(1 << Imm); VT.w = (float)VA.n3/(float)(1 << Imm); vcuxwfp128 VT, VA, Imm VT.x = (float)VA.u0/(float)(1 << Imm); VT.y = (float)VA.u1/(float)(1 << Imm); VT.z = (float)VA.u2/(float)(1 << Imm); VT.w = (float)VA.u3/(float)(1 << Imm); vexptefp128 VT, VA VT.x = exp2 (VA.x); VT.y = exp2 (VA.y); VT.z = exp2 (VA.z); VT.w = exp2 (VT.w); vlogefp128 VT, VA VT.x = log2 (VA.x); VT.y = log2 (VA.y); VT.z = log2 (VA.z); VT.w = log2 (VA.w); vmaddcfp128 VT, VA, VB, VC VT.x = VA.x * VB.x + VC.x; VT.y = VA.y * VB.y + VC.y; VT.z = VA.z * VB.z + VC.z; VT.w = VA.w * VB.w + VC.w; // VT = VB vmaddfp/vmaddfp128 VT, VA, VB, VC VT.x = VA.x * VB.x + VC.x; VT.y = VA.y * VB.y + VC.y; VT.z = VA.z * VB.z + VC.z; VT.w = VA.w * VB.w + VC.w; // VT = VC vmaxfp/vmaxfp128 VT, VA, VB VT.x = max(VA.x, VB.x); VT.y = max(VA.y, VB.y); VT.z = max(VA.z, VB.z); VT.w = max(VA.w, VB.w); vminfp/vminfp128 VT, VA, VB VT.x = min(VA.x, VB.x); VT.y = min(VA.y, VB.y); VT.z = min(VA.z, VB.z); VT.w = min(VA.w, VB.w); vmrghb VT, VA, VB VT.b0 = VA.b0; VT.b1 = VB.b0; ...; VT.bE = VA.b7; VT.bF = VB.b7; vmrghh VT, VA, VB VT.w0 = VA.w0; VT.w1 = VB.w0; VT.w2 = VA.w1; VT.w3 = VB.w1; VT.w4 = VA.w2; VT.w5 = VB.w2; VT.w6 = VA.w3; VT.w7 = VB.w3; vmrghw/vmrghw128 VT, VA, VB VT.u0 = VA.u0; VT.u1 = VB.u0; VT.u2 = VA.u1; VT.u3 = VB.u1; vmrglb VT, VA, VB VT.b0 = VA.b8; VT.b1 = VB.b8; ...; VT.bE = VA.bF; VT.bF = VB.bF; vmrglh VT, VA, VB VT.w0 = VA.w4; VT.w1 = VB.w4; VT.w2 = VA.w5; VT.w3 = VB.w5; VT.w4 = VA.w6; VT.w5 = VB.w6; VT.w6 = VA.w7; VT.w7 = VB.w7; vmrglw/vmrglw128 VT, VA, VB VT.u0 = VA.u2; VT.u1 = VB.u2; VT.u2 = VA.u3; VT.u3 = VB.u3; vmsum3fp128 VT, VA, VB VT.x = VT.y = VT.z = VT.w = VA.x * VB.x + VA.y * VB.y + VA.z * VB.z vmsum4fp128 VT, VA, VB VT.x = VT.y = VT.z = VT.w = VA.x * VB.x + VA.y * VB.y + VA.z * VB.z + VA.w * VB.w vmulfp128 VT, VA, VB VT.x = VA.x * VB.x; VT.y = VA.y * VB.y; VT.z = VA.z * VB.z; VT.w = VA.w * VB.w; vnmsubfp/vnmsubfp128 VT, VA, VB, VC VT.x = -((VA.x*VB.x)-VC.x); VT.y = -((VA.y*VB.y)-VC.y); VT.z = -((VA.z*VB.z)-VC.z); VT.w = -((VA.w*VB.w)-VC.w); // WARNING!! Ida VMX plugin shows parameters in different order!! vnor128 VT, VA, VB VT = ~(VA | VB); // 128 bit logical op vor/vor128 VT, VA, VB VT = VA | VB; // 128 bit logical op vperm/vperm128 VT, VA, VB, VC for (i = 0; i < 15; i++) { BYTE t = VC.bv[i] & 31; VT.bv[i] = t < 16 ? VA.bv[t] : VB.bv[t-16]; } vpermwi128 VT, VA, Imm VT.x = VA.fv[Imm >> 6]; VT.y = VA.fv[(Imm >> 4)&3]; VT.z = VA.fv[(Imm >> 2)&3]; VT.w = VA.fv[Imm & 3]; vpkd3d128 VT, VA, Type, Mask, sh D3DPack vpkshus/vpkshus128 VT, VA, VB VT.b0 = satS16toU8 (VA.s0); ...; VT.b7 = satS16toU8 (VA.s7); VT.b8 = satS16toU8 (VB.s0); ...; VT.bF = satS16toU8 (VB.s7); // saturate signed short to 0..255 vpkswss/vpkswss128 VT, VA, VB VT.s0 = satS32toS16 (VA.n0); ...; VT.s3 = satS32toS16 (VA.n3); VT.s4 = satS32toS16 (VB.n0); ...; VT.s7 = satS32toS16 (VB.n3); // saturate signed int to -32768..32767 vpkswus128 VT, VA, VB VT.w0 = satS32toU16 (VA.n0); ...; VT.w3 = satS32toU16 (VA.n3); VT.w4 = satS32toU16 (VB.n0); ...; VT.w7 = satS32toU16 (VB.n3); // saturate signed int to 0..65535 vpkuwus128 VT, VA, VB VT.w0 = satU32toU16 (VA.u0); ...; VT.w3 = satU32toU16 (VA.u3); VT.w4 = satU32toU16 (VB.u0); ...; VT.w7 = satU32toU16 (VB.u3); // saturate unsigned int to 0..65535 vrefp/vrefp128 VT, VA VT.x = 1.f/VA.x; VT.y = 1.f/VA.y; VT.z = 1.f/VA.z; VT.w = 1.f/VA.w; vrfim128 VT, VA VT.n0 = floor(VA.x); VT.n1 = floor(VA.y); VT.n2 = floor(VA.z); VT.n3 = floor(VA.w); vrfin/vrfin128 VT, VA VT.n0 = round(VA.x); VT.n1 = round(VA.y); VT.n2 = round(VA.z); VT.n3 = round(VA.w); vrfip128 VT, VA VT.n0 = ceil(VA.x); VT.n1 = ceil(VA.y); VT.n2 = ceil(VA.z); VT.n3 = ceil(VA.w); vrfiz/vrfiz128 VT, VA VT.n0 = VA.x; VT.n1 = VA.y; VT.n2 = VA.z; VT.n3 = VA.w; // convert float to int, rounding toward zero vrlimi128 VT, VA, Mask, Rot Tmp = (VA << Rot*32)|(VA >> (4-Rot)*32); VT.x = (Mask&8) ? Tmp.x : VT.x; VT.y = (Mask&4) ? Tmp.y : VT.y; VT.z = (Mask&2) ? Tmp.z : VT.z; VT.w = (Mask&1) ? Tmp.w : VT.w; vrsqrtefp/vrsqrtefp128 VT, VA VT.x = 1.f/sqrt(VA.x); VT.y = 1.f/sqrt(VA.y); VT.z = 1.f/sqrt(VA.z); VT.w = 1.f/sqrt(VA.w); vsel VT, VA, VB, VC VT = (VA & ~VC) | (VB & VC); vsel128 VT, VA, VB VT = (VA & ~VT) | (VB & VT); vsl VT, VA, VB VT = VA << (VB.bF & 7); // 128 bit shift, up to 7 bit vslb VT, VA, VB VT.b0 = VA.b0 << (VB.b0 & 7); ...; VT.bF = VA.bF << (VB.bF & 7); vsldoi/vsldoi128 VT, VA, VB, Imm VT = (VA << (Imm * 8)) | (VB >> ((16-Imm) * 8); // 256 bit shift vslh VT, VA, VB VT.w0 = VA.w0 << (VB.w0 & 15); ...; VT.w7 = VA.w7 << (VB.w7 & 15); vslo128 VT, VA, VB VT = VA << (VB.bF & 0x78); // 128 bit shift, byte aligned vslw128 VT, VA, VB VT.u0 = VA.u0 << (VB.u0 & 31); VT.u1 = VA.u1 << (VB.u1 & 31); VT.u2 = VA.u2 << (VB.u2 & 31); VT.u3 = VA.u3 << (VB.u3 & 31); vspltb VT, VA, Imm VT.b0 = ... = VT.bF = VA.bv[Imm]; // Imm in range 0..15 vsplth VT, VA, Imm VT.w0 = ... = VT.w7 = VA.wv[Imm]; // Imm in range 0..7 vspltisb VT, VA, Imm VT.c0 = ... = VT.cF = Imm; // Imm in range -16 .. 15 (5 bit) vspltish VT, VA, Imm VT.s0 = ... = VT.s7 = Imm; // Imm in range -16 .. 15 (5 bit) vspltisw/vspltisw128 VT, VA, Imm VT.n0 = VT.n1 = VT.n2 = VT.n3 = Imm; // Imm in range -16 .. 15 (5 bit) vspltw/vspltw128 VT, VA, Imm VT.u0 = VT.u1 = VT.u2 = VT.u3 = VA.uv[Imm]; // Imm in range 0..3 vsr VT, VA, VB VT = VA >> (VB.bF & 7); // 128 bit shift, up to 7 bit vsrab VT, VA, VB VT.b0 = VA.b0 >> (VB.b0 & 7); ...; VT.bF = VA.bF >> (VB.bF & 7); // sign extended vsraw128 VT, VA, VB VT.u0 = VA.u0 >> (VB.u0 & 31); VT.u1 = VA.u1 >> (VB.u1 & 31); VT.u2 = VA.u2 >> (VB.u2 & 31); VT.u3 = VA.u3 >> (VB.u3 & 31); // sign extended vsrb VT, VA, VB VT.b0 = VA.b0 >> (VB.b0 & 7); ...; VT.bF = VA.bF >> (VB.bF & 7); vsrh VT, VA, VB VT.w0 = VA.w0 >> (VB.w0 & 15); ...; VT.w7 = VA.w7 >> (VB.w7 & 15); vsro128 VT, VA, VB VT = VA >> (VB.bF & 0x78); // 128 bit shift, byte aligned vsrw128 VT, VA, VB VT.u0 = VA.u0 >> (VB.u0 & 31); VT.u1 = VA.u1 >> (VB.u1 & 31); VT.u2 = VA.u2 >> (VB.u2 & 31); VT.u3 = VA.u3 >> (VB.u3 & 31); vsubfp/vsubfp128 VT, VA, VB VT.x = VA.x - VB.x; VT.y = VA.y - VB.y; VT.z = VA.z - VB.z; VT.w = VA.w - VB.w; vsububm VT, VA, VB VT.b0 = VA.b0 - VB.b0; ....; VT.bF = VA.bF - VB.bF; vsubuwm VT, VA, VB VT.u0 = VA.u0 - VB.u0; VT.u1 = VA.u1 - VB.u1; VT.u2 = VA.u2 - VB.u2; VT.u3 = VA.u3 - VB.u3; vupkd3d128 VT, VA, Imm VT = D3DUnpack (VA, Imm); vupkhsb128 VT, VA VT.s7 = VA.c7; VT.s6 = VA.c6; VT.s5 = VA.c5; VT.s4 = VA.c4; VT.s3 = VA.s3; VT.s2 = VA.s2; VT.s1 = VA.c1; VT.s0 = VT.c0; // sign extended vupklsb128 VT, VA VT.s7 = VA.cF; VT.s6 = VA.cE; VT.s5 = VA.cD; VT.s4 = VA.cC; VT.s3 = VA.sB; VT.s2 = VA.sA; VT.s1 = VA.c9; VT.s0 = VT.c8; // sign extended vxor/vxor128 VT, VA, VB VT = VA^VB; // 128 bit logical op
Пока базу не выложат в публичный доступ, переношу тему в обсуждение.
Моей базы, в публичном доступе, пока не планируется (отправлена в ПМ).
Там уже слишком много вещей, которые пока не хочется засвечивать (меня и так постоянно достают с вопросами по скриптам, подписыванию сэйвов для онлайна и прочим вещам, участвовать в которых, мягко говоря, не хочется).
@Alien - Он packed/encrypred/signed. Нужны PS3 tools, чтобы получить нормальный .elf
Аналогично, на боксе нужно распаковать/дешифровать xex, чтобы получить .exe
(а при работе с патчами, еще и предварительно наложить патч)
PS. В рамках флейма: мой двадцатилетний опыт работы с *IX говорит мне, что в линуксе работать нельзя А против рекламы есть adblock. Для особо назойливых, можно даже прописать кастомные зоны на ближайшем bind/DNS service.
На память не помню, а документации под рукой сейчас нет.
Я не помню, что есть origPixels, возможно что-то с ним.
И выставлен ли корректный stride ?
Да.
Формат задается полем format.
А вообще, это все должно быть в документации на RWG
НикИТОС wrote:SHooZ wrote:мне тоже кажется что это банальный пиар
ЛОЛШТО? Это было бы тоже самое, если бы ради пиара Михалков раздавал бы диски со своими фильмами на горбушке
Ну а сам подумай:
Игра полностью защищена от запуска - т.е. они не теряют денег из-за пиратских копий до релиза (как было с фар краем). Кракеры смогли вытащить только музыку и видео, а это огромный ажиотаж на пустом месте, который только заставит купить игру. С другой стороны они абсолютно не виновны - мол это всё Сони. А я сомневаюсь, что такая компания как Сони могла "нечаяно" не заметить что они выложили GTA V на почти свободное скачивание.
Так-что ИМХО это простой пиар, а в образе может быть и не полная GTA=)
Как минимум, утек сюжет и все диалоги. Это ужас, кошмар и спойлеры.
Скачванный архив - оригинальный. Т.е., он имеет честный package number, подписи и лицензии. Учитывая сложность процесса подписывания (не техническую, а административную), делать это, чтобы приколоться - никто не будет.
А что касается бардака в Сони - после использования константы для генерации ключей, от них можно ожидать всего.
Толку от этого достаточно мало. Ключи RPF в EBOOT-е, EBOOT закриптован, ключи к EBOOT выдают при покупке, купить нельзя до 17го.
Можно пока попробовать поискать текстурки в RPF.
Напрямую - никак. Над ней очень сильно поработал оптимизатор.
сама по себе функция очень простая:
float makeAngleAccute (float fAngle) { return fmodf (fAnfle, M_PI_2); }
Но, поскольку параметр передается в ST, без ассемблерной вставки, ее переопределить нельзя.