SCO — различия между версиями

Материал из GTAModding.ru
Перейти к: навигация, поиск
м (Инструменты)
 
(не показаны 10 промежуточных версий 4 участников)
Строка 2: Строка 2:
  
 
== Формат файла ==
 
== Формат файла ==
Файл SCO разделен на 4 сегмента. Первый является [[#Заголовок|заголовком]] и содержит информацию о файле. Второй слой это [[#Сегмент кода|сегмент кода]], он состоит из последовательности опкодов, которые определяют как скрипт будет интерпретирован игрой. Третий сегмент содержит достаточно места для размещения [[#Глобальные переменные|глобальных переменных]] скрипта. И четвертый сегмент используется для размещения [[#Публичные переменные|публичных переменных]].
+
Файл SCO разделен на 4 сегмента. Первый является [[#Заголовок|заголовком]] и содержит информацию о файле. Второй сегмент - это [[#Сегмент кода|сегмент кода]], он состоит из последовательности опкодов, которые определяют как скрипт будет интерпретирован игрой. Третий сегмент содержит [[#Статические переменные|статические переменные]] - данные, доступные только этому скрипту. Четвертый сегмент присутствует в одном и только в одном скрипте (как правило, это <code>startup.sco</code>). В нем содержатся [[#Глобальные переменные|глобальные переменные]], доступные из любого скрипта.
  
 
=== Заголовок ===
 
=== Заголовок ===
Существуют кодированные и не кодированные SCO файлы. Вне зависимости от этого файл содержит не кодированную заголовочную структуру, что позволяет всегда определить какой вид SCO файла перед вами. Размер заголовка - 24 байта, которые состоят из 6 частей каждый по 4 байта:
+
SCO файлы могут быть шифрованные, не шифрованные и упакованные. Заголовок файла всегда не кодированный и неупакованный. Размер заголовка 24 байта для неупакованной версии и 28 - для не упакованной.
  
  4b - CHAR[4]/UINT32 - SCO идентификатор
+
  4b - UINT32 - SCO идентификатор
  4b - UINT32 – Размер кода – количество байт, занятых сегментом кода
+
  4b - UINT32 – Размер сегмента кода в байтах
  4b - UINT32 – Количество глобальных переменных
+
4b - UINT32 Размер сегмента статических данных в DWORD-ах (чтобы получить размер в байтах, нужно умножить на 4)
  4b - UINT32 – Количество публичных переменных
+
  4b - UINT32 – Размер сегмента глобальных переменных в DWORD-ах
  4b - UINT32 – Скриптовые флаги
+
  4b - UINT32 – Количество аргументов у основной функции скрипта
  4b - UINT32 – Сигнатура
+
  4b - UINT32 – Версия сегмента глобальных данных
 +
  4b - UINT32 - Размер упакованных данных (только для упакованных файлов)
 
   
 
   
 
  UINT32 – это беззнаковое целое 32 бит (= 4 байта), оно может принимать значения от 0 до (2^32 – 1)
 
  UINT32 – это беззнаковое целое 32 бит (= 4 байта), оно может принимать значения от 0 до (2^32 – 1)
CHAR[4] – строка из 4 символов (4*8 = 32 бит = 4 байта)
 
  
SCO идентификатор может быть типа "SCR\r" (или 0xD524353) в не кодированной версии, и "scr"+0xE (или 0xE726373) в кодированной. Для декодирования любого кодированного файла вы должны декодировать каждый сегмент (кроме не кодированного заголовка) используя специальный метод GTA IV AES [http://http://www.gtamodding.com/index.php?title=Cryptography криптографии]. Сегмент глобальных переменных начинается с байта номер (24 + Размер кода + 1), и содержит (4 * Количество глобальных переменных) байт, т.к. каждая глобальная переменная должна быть описана в 4 байта.  Аналогично сегмент публичных переменных начинается с байта (24 + Размер кода + 4 * Количество глобальных переменных + 1) и содержит (4 * Количество публичных переменных) байт. Скриптовые флаги это 32 булевых бита характеризующие данный скрипт. Сигнатура отличается только в navgen_main, но может использоваться для установки приоритета скрипту.
+
SCO идентификатор может быть "SCR\x0d" (или 0xD524353) в не кодированной версии, "scr\x0e" (или 0xE726373) в кодированной и "Scr\x0e" (0xE726353) в упакованной.  
 +
 
 +
В кодированных неупакованных файлах, каждый сегмент декодируется отдельно. Чтобы декодировать файл, из файла считываются два или три сегмента, после чего применяется метод [[Шифрование (GTA 4)|расшифровки]] (каждый сегмент расшифровывается отдельно).
 +
Сегмент кода начинается со смещения 24 байта, сегмент статических данных - со смещения (24 + размер кода), сегмент глобальных данных (если он присутствует) - со смещения (24 + размер кода + (4 * размер статических данных)).
 +
 
 +
Чтобы прочитать упакованный файл, нужно выполнить сначала декодирование, а потом распаковать данные. Данные начинаются со смещения 28 байтов. Размер упакованных данных берется из заголовка, размер распакованных - вычисляется как (размер кода + (4 * размер статических данных) + (4 * размер глобальных данных)).  
  
 
=== Сегмент кода ===
 
=== Сегмент кода ===
Строка 23: Строка 28:
  
 
====Опкоды====
 
====Опкоды====
Разные опкоды могут занимать разное количество байт, но все опкоды идентифицируются в первом байте. Всего есть 79 опкодов которые могут встретится, а все опкоды после 96  включительно это Push (помещаемые) опкоды которые помещаются в стек. Для примера опкод 100 будет помещён 4 в стек. Опкоды 76, 77, 78 даются с поддержкой XLive буфера и доступны только на PC платформе. Неопределенные опкоды будучи использованными приведут к вылету скрипта.
+
Любая команда состоит из кода операции (опкода) и опциональных параметров. В PC-версии используется 78 опкодов (1..78), в консольной - 75 (1..75).
 +
Опкоды 80..255 используются для сокращенной записи ipush (поместить на стек int). При выполнении таких опкодов, на стек помещается число (opcode-96).
 +
Неопределенные опкоды (79 на PC, 76..79 на консолях) приводят к аварийному завершению скрипта.
  
 
{|{{Таблица}} class="collapsible"
 
{|{{Таблица}} class="collapsible"
Строка 31: Строка 38:
 
!Длина
 
!Длина
 
|-
 
|-
|0|| nop || Нет оператора || 1 byte
+
|0|| invalid|| Не используется (текущая версия помещает на стек 160) || 1 byte
 
|-
 
|-
|1|| iadd || Складывает 2 верхних элемента в стеке || 1 байт
+
|1|| iadd || Складывает 2 верхних элемента в стеке (int) || 1 байт
 
|-
 
|-
|2|| isub || Вычитает 2 верхних элемента в стеке || 1 байт
+
|2|| isub || Вычитает 2 верхних элемента в стеке (int) || 1 байт
 
|-
 
|-
|3|| imul || Умножает 2 верхних элемента в стеке || 1 байт
+
|3|| imul || Умножает 2 верхних элемента в стеке (int) || 1 байт
 
|-
 
|-
|4|| idiv || Делит нацело 2 верхних элемента в стеке || 1 байт
+
|4|| idiv || Делит нацело 2 верхних элемента в стеке (int) || 1 байт
 
|-
 
|-
|5|| imod || Дает остаток от деления 2 верхних элементов в стеке || 1 байт
+
|5|| imod || Дает остаток от деления 2 верхних элементов в стеке (int) || 1 байт
 
|-
 
|-
|6|| iszero || Проверяет первый элемент стека на равенство 0 || 1 байт
+
|6|| inot || Логическая инверсия верхнего элемента стека (0 если он ненулевой, 1 если он равен нулю) || 1 байт
 
|-
 
|-
|7|| ineg || Меняет знак верхнего элемента в стеке || 1 байт
+
|7|| ineg || Меняет знак верхнего элемента в стеке (int) || 1 байт
 
|-
 
|-
 
|8|| icmpeq || Сравнивает два целых сверху стека на равенство || 1 байт
 
|8|| icmpeq || Сравнивает два целых сверху стека на равенство || 1 байт
Строка 59: Строка 66:
 
|13|| icmple || Сравнивает два целых сверху стека на то что первый меньше или равен второму || 1 байт
 
|13|| icmple || Сравнивает два целых сверху стека на то что первый меньше или равен второму || 1 байт
 
|-
 
|-
|14|| fadd || Складывает 2 верхних дробных элемента в стеке || 1 байт
+
|14|| fadd || Складывает 2 верхних элемента в стеке (float) || 1 байт
 
|-
 
|-
|15|| fsub || Вычитает 2 верхних дробных элемента в стеке || 1 байт
+
|15|| fsub || Вычитает 2 верхних элемента в стеке (float) || 1 байт
 
|-
 
|-
|16|| fmul || Умножает 2 верхних дробных элемента в стеке || 1 байт
+
|16|| fmul || Умножает 2 верхних элемента в стеке (float) || 1 байт
 
|-
 
|-
|17|| fdiv || Делит 2 верхних дробных элемента в стеке || 1 байт
+
|17|| fdiv || Делит 2 верхних элемента в стеке (float) || 1 байт
 
|-
 
|-
|18|| fmod || Дает остаток от деления 2 верхних дробных элементов в стеке || 1 байт
+
|18|| fmod || Дает остаток от деления 2 верхних элементов в стеке (float) || 1 байт
 
|-
 
|-
|19|| fneg || Меняет знак верхнего дробных элемента в стеке || 1 байт
+
|19|| fneg || Меняет знак верхнего элемента в стеке (float) || 1 байт
 
|-
 
|-
|20|| fcmpeq || Сравнивает два дробных сверху стека на равенство || 1 байт
+
|20|| fcmpeq || Сравнивает два элемента сверху стека на равенство (float) || 1 байт
 
|-
 
|-
|21|| fcmpne || Сравнивает два дробных сверху стека на не равенство || 1 байт
+
|21|| fcmpne || Сравнивает два элемента сверху стека на не равенство (float) || 1 байт
 
|-
 
|-
|22|| fcmpgt || Сравнивает два дробных сверху стека на то что первый больше второго || 1 байт
+
|22|| fcmpgt || Сравнивает два элемента  сверху стека на то что первый больше второго (float) || 1 байт
 
|-
 
|-
|23|| fcmpge || Сравнивает два дробных сверху стека на то что первый больше или равен второму || 1 байт
+
|23|| fcmpge || Сравнивает два элемента  сверху стека на то что первый больше или равен второму (float) || 1 байт
 
|-
 
|-
|24|| fcmplt || Сравнивает два дробных сверху стека на то что первый меньше второго || 1 байт
+
|24|| fcmplt || Сравнивает два элемента  сверху стека на то что первый меньше второго (float) || 1 байт
 
|-
 
|-
|25|| fcmple || Сравнивает два дробных сверху стека на то что первый меньше или равен второму || 1 байт
+
|25|| fcmple || Сравнивает два элемента  сверху стека на то что первый меньше или равен второму (float) || 1 байт
 
|-
 
|-
|26|| vadd || Складывает 2 верхних вектора{{Ref|1}} в стеке || 1 байт
+
|26|| vadd || Складывает 2 верхних вектора{{Ref|1|[*]}} в стеке || 1 байт
 
|-
 
|-
|27|| vsub || Вычитает 2 верхних вектора{{Ref|1}} в стеке || 1 байт
+
|27|| vsub || Вычитает 2 верхних вектора{{Ref|1|[*]}} в стеке || 1 байт
 
|-
 
|-
|28|| vmul || Умножает 2 верхних вектора{{Ref|1}} в стеке || 1 байт
+
|28|| vmul || Умножает 2 верхних вектора{{Ref|1|[*]}} в стеке || 1 байт
 
|-
 
|-
|29|| vdiv || Делит 2 верхних вектора{{Ref|1}} в стеке || 1 байт
+
|29|| vdiv || Делит 2 верхних вектора{{Ref|1|[*]}} в стеке || 1 байт
 
|-
 
|-
|30|| vneg || Меняет знак верхнего вектора{{Ref|1}} в стеке || 1 байт
+
|30|| vneg || Меняет знак верхнего вектора{{Ref|1|[*]}} в стеке || 1 байт
 
|-
 
|-
 
|31|| iand || Оператор [[Wikipedia:Logical_conjunction|And]] для 2 первых целых в стеке || 1 байт
 
|31|| iand || Оператор [[Wikipedia:Logical_conjunction|And]] для 2 первых целых в стеке || 1 байт
Строка 109: Строка 116:
 
|38|| ftoi || Переводит верхнее дробное в стеке в целое и кладет это целое в стек || 1 байт
 
|38|| ftoi || Переводит верхнее дробное в стеке в целое и кладет это целое в стек || 1 байт
 
|-
 
|-
|39|| ftov || Переводит верхнее дробное в стеке в вектор{{Ref|1}} (содержащий три числа, равных этому дробному) и кладет указатель на вектор{{Ref|1}} в стек || 1 байт
+
|39|| ftov || Переводит верхнее дробное в стеке в вектор{{Ref|1|[*]}} (содержащий три числа, равных этому дробному) и кладет указатель на вектор в стек || 1 байт
 
|-
 
|-
|40|| ipush2 || Кладет короткое целое в стек, которое определятся следующими за опкодом 2 байтами. || 3 байт
+
|40|| ipush2 || Короткая форма ipush для значений в диапазоне -32768..32767 (два байта) || 3 байт
 
|-
 
|-
|41|| ipush || Кладет целое в стек, которое определятся следующими за опкодом 4 байтами || 5 байт
+
|41|| ipush || Помещает в стек число (int), которое следует в коде за командой (4 байта) || 5 байт
 
|-
 
|-
|42|| fpush || Кладет дробное в стек, которое определятся следующими за опкодом 4 байтами || 5 байт
+
|42|| fpush || Помещает в стек число (float), которое следует в коде за командой (4 байта) || 5 байт
 
|-
 
|-
|43|| dup || Копирует первый элемент стека, и помещает его обратно в стек || 1 байт
+
|43|| dup || Копирует верхний элемент стека || 1 байт
 
|-
 
|-
|44|| pop || Извлекает верхний элемент из стека || 1 байт
+
|44|| drop || Выбрасывает верхний элемент из стека || 1 байт
 
|-
 
|-
|45|| native || Вызов native функции. Количество аргументов определяется 2 байтом. Количество значение (либо 0 либо 1) определяется 3 байтом. Последние 4 байта из 7 содержат идентификатор имени функции. || 7 байт
+
|45|| native || Вызов native функции. Количество аргументов определяется вторым байтом. Количество значений (как правило, 0 либо 1) определяется 3 байтом. Последние 4 байта из 7 содержат хэш имени функции. || 7 байт
 
|-
 
|-
|46|| call || Вызов функции в скрипте. Помещает возращенный адрес на стек. Местоположение функции определяется следующими 4 байтами. || 5 байт
+
|46|| call || Вызов функции в скрипте. Параметр команды - адрес функции (4 байта) || 5 байт
 
|-
 
|-
|47|| enter || Индикатор начала функции, определяемой в скрипте. Байт после опкода определяет количество аргументов функции, которые будут взяты из стека. Следующие 2 байта определяют количество переменных функции, которые будут сгенерированы в стеке. || 4 байт
+
|47|| enter || Создать стековый фрейм (блок локальных переменных) функции. Байт после опкода определяет количество аргументов функции, которые будут взяты из стека. Следующие 2 байта определяют размер фрейма (и то, и другое - в DWORD-ах) || 4 байт
 
|-
 
|-
|48|| ret || Индикатор конца функции, определяемой в скрипте. Байт после опкода определяет количество аргументов, которые будут извлечены из стека. 3 байт определяет номер в стеке с возвращенным адресом. || 3 байт
+
|48|| ret || Завершить текущую функцию и вернуть значение. Байт после опкода определяет количество аргументов, которые будут извлечены из стека. Следующий байт содержит размер результата, возвращаемого функцией || 3 байта
 
|-
 
|-
 
|49|| pget || Извлекает указатель из стека и помещает в стек значение по адресу указателя. || 1 байт
 
|49|| pget || Извлекает указатель из стека и помещает в стек значение по адресу указателя. || 1 байт
Строка 133: Строка 140:
 
|50|| pset || Извлекает 2 элемента из стека и записывает второй элемент по адресу обозначенному в первом элементе (должен быть указателем). || 1 байт
 
|50|| pset || Извлекает 2 элемента из стека и записывает второй элемент по адресу обозначенному в первом элементе (должен быть указателем). || 1 байт
 
|-
 
|-
|51|| ppeekset || Извлекает первый элемент из стека и линкует его во втором элементе. Теперь на содержание первого элемента указывает указатель во втором. || 1 байт
+
|51|| ppeekset || Извлекает из стека два элемента. Записывает первый элемент по адресу из второго. Возвращает второй элемент в стек || 1 байт  
 
|-
 
|-
|52|| explode || Извлекает 2 элемента из стека, один становится началом массива в памяти, а другой – концом. Разница между ними деленная на 4 дает количество элементов в массиве, после чего элементы массива помещается в стек один за одним с 4 байтным сегментом. || 1 байт
+
|52|| pnget || Извлекает 2 элемента из стека. Первый содежит адрес, второй - количество элементов. Помещает указанные элементы на стек || 1 байт
 
|-
 
|-
|53|| implode || Извлекает первый элемент из стека для получения адреса массива для записи и помещает стек в массив. || 1 байт
+
|53|| pnset || Извлекает из стека два элемента. Первый содержит адрес, второй -  количество. Извлекает из стека указанное количество элементов и записывает их в память, начиная с указанного адреса || 1 байт
 
|-
 
|-
|54|| flvar0 || Помещает указатель на 1 локальную переменную функции в стек. || 1 байт  
+
|54|| pframe0 || Помещает указатель на 1 локальную переменную функции в стек. || 1 байт  
 
|-
 
|-
|55|| flvar1 || Помещает указатель на 2 локальную переменную функции в стек. || 1 байт
+
|55|| pframe1 || Помещает указатель на 2 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|56|| flvar2 || Помещает указатель на 3 локальную переменную функции в стек. || 1 байт
+
|56|| pframe2 || Помещает указатель на 3 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|57|| flvar3 || Помещает указатель на 4 локальную переменную функции в стек. || 1 байт
+
|57|| pframe3 || Помещает указатель на 4 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|58|| flvar4 || Помещает указатель на 5 локальную переменную функции в стек. || 1 байт
+
|58|| pframe4 || Помещает указатель на 5 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|59|| flvar5 || Помещает указатель на 6 локальную переменную функции в стек. || 1 байт
+
|59|| pframe5 || Помещает указатель на 6 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|60|| flvar6 || Помещает указатель на 7 локальную переменную функции в стек. || 1 байт
+
|60|| pframe6 || Помещает указатель на 7 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|61|| flvar7 || Помещает указатель на 8 локальную переменную функции в стек. || 1 байт
+
|61|| pframe7 || Помещает указатель на 8 локальную переменную функции в стек. || 1 байт
 
|-
 
|-
|62|| flvar || Помещает указатель на локальную переменную функции в стек, индекс меньше или равен 8. || 1 байт
+
|62|| pframe || Извлекает из стека число. Помещает в стек указатель на локальную переменную функции с этим номером || 1 байт
 
|-
 
|-
|63|| global || Извлекает индекс глобальной переменной из стека, помещает указатель на глобальную переменную скрипта в стек. || 1 байт
+
|63|| pstatic || Извлекает индекс статической переменной из стека, помещает указатель на эту переменную скрипта в стек. || 1 байт
 
|-
 
|-
|64|| public || Извлекает индекс публичной переменной из стека, помещает указатель на публичную переменную в стек. || 1 байт
+
|64|| pglobal || Извлекает индекс глобальной переменной из стека, помещает указатель на эту переменную в стек. || 1 байт
 
|-
 
|-
|65|| array || Извлекает местоположение массива, размер элемента и индекс из стека. Помещает указатель на индекс массива в стек || 1 байт
+
|65|| parray || Извлекает указатель на начало массива, размер элемента и индекс из стека. Помещает указатель на элемент массива в стек || 1 байт
 
|-
 
|-
|66|| switch || Pops the item to compare off the stack, and then jumps to location corresponding to that item. After the opcode byte it contains a byte defining the number of possible entries, and after that the number of possible entries times 8 are taken up with repeating instances of 4 bytes of the index identifier, and 4 bytes of the location to jump to if that index is correct || (Байт после опкода * 8) + 2
+
|66|| switch || Следующий за командой байт - количество case. За ним следуют пары "значение (4 байта):адрес (4 байта)". Команда извлекает из стека число и последовательно сравнивает его со всеми значениями. При совпедении, выполняется переход по адресу, соответствующему этому значению || (Байт после опкода * 8) + 2
 
|-
 
|-
 
|67|| spush || Помещает строку в стек. Байт после опкода обозначает длину строки. Дальше следуют символы строки. || (Байт после опкода)+2
 
|67|| spush || Помещает строку в стек. Байт после опкода обозначает длину строки. Дальше следуют символы строки. || (Байт после опкода)+2
Строка 177: Строка 184:
 
|72|| saddi || Извлекает 2 элемента из стека, переводит второй в из целого в строку (IntToStr) и добавляет эту строку к первому элементу. || 1 байт
 
|72|| saddi || Извлекает 2 элемента из стека, переводит второй в из целого в строку (IntToStr) и добавляет эту строку к первому элементу. || 1 байт
 
|-
 
|-
|73|| catch || Устанавливает верх области сохранения, содержащей состояния перехваченных ошибок. || 1 байт
+
|73|| catch || Устанавливает верх области сохранения, содержащей состояния перехваченных ошибок. (не используется) || 1 байт
 
|-
 
|-
|74|| throw || Индикатор области хендлов скриптовых ошибок относительно перехваченных скриптов. || 1 байт
+
|74|| throw || Индикатор области хендлов скриптовых ошибок относительно перехваченных скриптов. (не используется) || 1 байт
 
|-
 
|-
|75|| memcpy || Извлекает 3 указателя из стека, копирует содержание по 3 адресу в первый элемент (по адресу) с повторением, определенным во втором элементе. Затем добавляет null в содержание по первому адресу. Получается строка в (1) = строке (3) дублированной (2) раз и завершенная нулевым символом. || 1 байт
+
|75|| sncpy || Извлекает 3 значения из стека, копирует содержание по 3 адресу в первый элемент (по адресу) с повторением, определенным во втором элементе. Затем добавляет null в содержание по первому адресу. Получается строка в (1) = строке (3) дублированной (2) раз и завершенная нулевым символом. || 1 байт
 
|-
 
|-
|76|| getxprotect || Извлекает адресс памяти из стека и добавляет в стек не поддерживаемое XLive значение (только для PC) || 1 байт
+
|76|| xget || Из стека извлекается идентификатор live protected buffer, на стек помещается значение из этого буфера (4 байта) (только для PC) || 1 байт
 
|-
 
|-
|77|| setxprotect || Извлекает расположение памяти из стека извлекает другое значение из стека. Преобразует/поддерживает втрое значение используя XLive и записывает новое значение в память по адресу. (только для PC) || 1 байт
+
|77|| xset || Извлекает из стека идентификатор live protected buffer и значение (4 байта). Записывает занчение в буфер. (только для PC) || 1 байт
 
|-
 
|-
|78|| refxprotect || Извлекает адресс памяти из стека, извлекает другое значение для определения флагов преобразования, и наконец извлекает следующее значение, которое содержит количество элементов для обработки. Если первый бит в флаге установлен все элементы в памяти по адресу будут преобразованы в не поддерживаемое XLive состояние. Если 2 бит установлен они будут XLive поддержаны. (только для PC) || 1 байт
+
|78|| xref || Извлекает адресс памяти из стека, извлекает другое значение для определения флагов преобразования, и наконец извлекает следующее значение, которое содержит количество элементов для обработки. Если первый бит в флаге установлен все элементы в памяти по адресу будут преобразованы в не поддерживаемое XLive состояние. Если 2 бит установлен они будут XLive поддержаны. (только для PC) || 1 байт
 
|-
 
|-
|79|| exit || Терминирует скрипт возвращая ошибку || 1 байт
 
|-
 
|80 -> 255|| ipush1 || Помещает любое целое в стек. Целое определяется числом 96. Для примера: опкод 95 поместит -1 в стек, а опкод 97 поместит 1 || 1 байт
 
 
|}
 
|}
  
{{note|1}} Вектор на стеке это указатель по адресу, который содержит полный адрес. Т.е. при передачи через стек (например при вызове функций) передается не весь вектор/массив, а только указатель (как это делается в С). Вектор это синоним следующей структуре:
+
{{note|1}} Вектор - это структура, стостоящая из трех полей типа float
  
 
  4b - FLOAT32 - X
 
  4b - FLOAT32 - X
 
  4b - FLOAT32 - Y
 
  4b - FLOAT32 - Y
 
  4b - FLOAT32 - Z
 
  4b - FLOAT32 - Z
 +
 +
===Статические переменные===
 +
Сегмент, содержащий данные, доступные только этому скрипту (любой его функции).
 +
Размер любой переменной, кратен 32-м битам. Если переменная занимает меньше, ее размер округляется вверх до кратного четырем байтам.
  
 
===Глобальные переменные===
 
===Глобальные переменные===
Содержит глобальные переменные скрипта. Каждая глобальная переменная занимает 4 байта, и может содержать информацию о самом скрипте.
+
Глобальные переменные доступны из любого скрипта.  
 +
Сегмент глобальных переменных должен присутствовать в одном и только в одном скрипте (startup.sco).
 +
Поскольку обращение к переменным производится не по имени, а по адресу, важно, чтобы порядок глобальных переменных совпадал для всех скриптов. Для достижения этого, при компиляции, генерируется версия сегмента глобальных данных, которая записывается в заголовок скрипта. Если эта версия не совпадает с той, которая записана в заголовке того скрипта, из которого был загружен сегмент глобальных данных, загрузка скрипта не выполняется.
 +
 
  
===Публичные переменные===
 
Определяют что делает секция.
 
  
==Высокоуровневое представление==
 
При переводе ассамблера SCO файлов в высокоуровневое представление возникает несколько моментов. Массивы и структуры могут быть определены только на основе следующих типов: целых [[Wikipedia:Integer_(computer_science)|int]], дробных [[Wikipedia:Floating_point|float]], строк [[Wikipedia:String_(computer_science)|string]] или уже определенных структур. Интересно заметить что опкоды содержат типы целых и объединения в строки, это свойство роднит язык SCO с java где строки определяются также (равно как и в С строки – массивы целых типа char). Еще кажется что SCO файлы не имеют низкоуровневой поддержки классов, однако это не значит что они не могут быть введены в SCO также как они были введены в C++.
 
  
 
== Инструменты ==
 
== Инструменты ==
* [[OpenIV]]  
+
* [[Scocl]] &ndash; высокоуровневый компилятор игровых скриптов GTA IV и EFLC.
* [[SparkIV]]
+
* [[OpenIV]] &ndash; Имеет встроенный декомпилятор.
 +
* [[SparkIV]] &ndash; Имеет встроенный декомпилятор.
  
 
{{GTA4-navi}}
 
{{GTA4-navi}}
 
[[Категория:GTA 4]][[Категория: Форматы файлов]][[Категория:Скриптинг]]
 
[[Категория:GTA 4]][[Категория: Форматы файлов]][[Категория:Скриптинг]]

Текущая версия на 07:12, 8 ноября 2011

Файлы формата SCO (с расширением *.sco) содержат скрипты игры GTA 4. Это новый формат, пришедший на смену соответствующих файлов *.scm в предыдущих версиях.

Содержание

Формат файла

Файл SCO разделен на 4 сегмента. Первый является заголовком и содержит информацию о файле. Второй сегмент - это сегмент кода, он состоит из последовательности опкодов, которые определяют как скрипт будет интерпретирован игрой. Третий сегмент содержит статические переменные - данные, доступные только этому скрипту. Четвертый сегмент присутствует в одном и только в одном скрипте (как правило, это startup.sco). В нем содержатся глобальные переменные, доступные из любого скрипта.

Заголовок

SCO файлы могут быть шифрованные, не шифрованные и упакованные. Заголовок файла всегда не кодированный и неупакованный. Размер заголовка 24 байта для неупакованной версии и 28 - для не упакованной.

4b - UINT32 - SCO идентификатор
4b - UINT32 – Размер сегмента кода в байтах
4b - UINT32 – Размер сегмента статических данных в DWORD-ах (чтобы получить размер в байтах, нужно умножить на 4) 
4b - UINT32 – Размер сегмента глобальных переменных в DWORD-ах
4b - UINT32 – Количество аргументов у основной функции скрипта
4b - UINT32 – Версия сегмента глобальных данных
4b - UINT32 - Размер упакованных данных (только для упакованных файлов) 

UINT32 – это беззнаковое целое 32 бит (= 4 байта), оно может принимать значения от 0 до (2^32 – 1)

SCO идентификатор может быть "SCR\x0d" (или 0xD524353) в не кодированной версии, "scr\x0e" (или 0xE726373) в кодированной и "Scr\x0e" (0xE726353) в упакованной.

В кодированных неупакованных файлах, каждый сегмент декодируется отдельно. Чтобы декодировать файл, из файла считываются два или три сегмента, после чего применяется метод расшифровки (каждый сегмент расшифровывается отдельно). Сегмент кода начинается со смещения 24 байта, сегмент статических данных - со смещения (24 + размер кода), сегмент глобальных данных (если он присутствует) - со смещения (24 + размер кода + (4 * размер статических данных)).

Чтобы прочитать упакованный файл, нужно выполнить сначала декодирование, а потом распаковать данные. Данные начинаются со смещения 28 байтов. Размер упакованных данных берется из заголовка, размер распакованных - вычисляется как (размер кода + (4 * размер статических данных) + (4 * размер глобальных данных)).

Сегмент кода

Сегмент кода состоит из последовательности опкодов, которые определяют как скрипт будет интерпретирован игрой.

Опкоды

Любая команда состоит из кода операции (опкода) и опциональных параметров. В PC-версии используется 78 опкодов (1..78), в консольной - 75 (1..75). Опкоды 80..255 используются для сокращенной записи ipush (поместить на стек int). При выполнении таких опкодов, на стек помещается число (opcode-96). Неопределенные опкоды (79 на PC, 76..79 на консолях) приводят к аварийному завершению скрипта.

ID Имя Определение Длина
0 invalid Не используется (текущая версия помещает на стек 160) 1 byte
1 iadd Складывает 2 верхних элемента в стеке (int) 1 байт
2 isub Вычитает 2 верхних элемента в стеке (int) 1 байт
3 imul Умножает 2 верхних элемента в стеке (int) 1 байт
4 idiv Делит нацело 2 верхних элемента в стеке (int) 1 байт
5 imod Дает остаток от деления 2 верхних элементов в стеке (int) 1 байт
6 inot Логическая инверсия верхнего элемента стека (0 если он ненулевой, 1 если он равен нулю) 1 байт
7 ineg Меняет знак верхнего элемента в стеке (int) 1 байт
8 icmpeq Сравнивает два целых сверху стека на равенство 1 байт
9 icmpne Сравнивает два целых сверху стека на не равенство 1 байт
10 icmpgt Сравнивает два целых сверху стека на то что первый больше второго 1 байт
11 icmpge Сравнивает два целых сверху стека на то что первый больше или равен второму 1 байт
12 icmplt Сравнивает два целых сверху стека на то что первый меньше второго 1 байт
13 icmple Сравнивает два целых сверху стека на то что первый меньше или равен второму 1 байт
14 fadd Складывает 2 верхних элемента в стеке (float) 1 байт
15 fsub Вычитает 2 верхних элемента в стеке (float) 1 байт
16 fmul Умножает 2 верхних элемента в стеке (float) 1 байт
17 fdiv Делит 2 верхних элемента в стеке (float) 1 байт
18 fmod Дает остаток от деления 2 верхних элементов в стеке (float) 1 байт
19 fneg Меняет знак верхнего элемента в стеке (float) 1 байт
20 fcmpeq Сравнивает два элемента сверху стека на равенство (float) 1 байт
21 fcmpne Сравнивает два элемента сверху стека на не равенство (float) 1 байт
22 fcmpgt Сравнивает два элемента сверху стека на то что первый больше второго (float) 1 байт
23 fcmpge Сравнивает два элемента сверху стека на то что первый больше или равен второму (float) 1 байт
24 fcmplt Сравнивает два элемента сверху стека на то что первый меньше второго (float) 1 байт
25 fcmple Сравнивает два элемента сверху стека на то что первый меньше или равен второму (float) 1 байт
26 vadd Складывает 2 верхних вектора[*] в стеке 1 байт
27 vsub Вычитает 2 верхних вектора[*] в стеке 1 байт
28 vmul Умножает 2 верхних вектора[*] в стеке 1 байт
29 vdiv Делит 2 верхних вектора[*] в стеке 1 байт
30 vneg Меняет знак верхнего вектора[*] в стеке 1 байт
31 iand Оператор And для 2 первых целых в стеке 1 байт
32 ior Оператор Or для 2 первых целых в стеке 1 байт
33 ixor Оператор Xor для 2 первых целых в стеке 1 байт
34 jmp Перейти по адресу в коде, использует следующие после опкода 4 байта как адрес 5 байт
35 jmpf Перейти по адресу в коде, если сверху стека 0, использует следующие после опкода 4 байта как адрес 5 байт
36 jmpt Перейти по адресу в коде, если сверху стека 1, использует следующие после опкода 4 байта как адрес 5 байт
37 itof Переводит верхнее целое в стеке в дробное и кладет это дробное в стек 1 байт
38 ftoi Переводит верхнее дробное в стеке в целое и кладет это целое в стек 1 байт
39 ftov Переводит верхнее дробное в стеке в вектор[*] (содержащий три числа, равных этому дробному) и кладет указатель на вектор в стек 1 байт
40 ipush2 Короткая форма ipush для значений в диапазоне -32768..32767 (два байта) 3 байт
41 ipush Помещает в стек число (int), которое следует в коде за командой (4 байта) 5 байт
42 fpush Помещает в стек число (float), которое следует в коде за командой (4 байта) 5 байт
43 dup Копирует верхний элемент стека 1 байт
44 drop Выбрасывает верхний элемент из стека 1 байт
45 native Вызов native функции. Количество аргументов определяется вторым байтом. Количество значений (как правило, 0 либо 1) определяется 3 байтом. Последние 4 байта из 7 содержат хэш имени функции. 7 байт
46 call Вызов функции в скрипте. Параметр команды - адрес функции (4 байта) 5 байт
47 enter Создать стековый фрейм (блок локальных переменных) функции. Байт после опкода определяет количество аргументов функции, которые будут взяты из стека. Следующие 2 байта определяют размер фрейма (и то, и другое - в DWORD-ах) 4 байт
48 ret Завершить текущую функцию и вернуть значение. Байт после опкода определяет количество аргументов, которые будут извлечены из стека. Следующий байт содержит размер результата, возвращаемого функцией 3 байта
49 pget Извлекает указатель из стека и помещает в стек значение по адресу указателя. 1 байт
50 pset Извлекает 2 элемента из стека и записывает второй элемент по адресу обозначенному в первом элементе (должен быть указателем). 1 байт
51 ppeekset Извлекает из стека два элемента. Записывает первый элемент по адресу из второго. Возвращает второй элемент в стек 1 байт
52 pnget Извлекает 2 элемента из стека. Первый содежит адрес, второй - количество элементов. Помещает указанные элементы на стек 1 байт
53 pnset Извлекает из стека два элемента. Первый содержит адрес, второй - количество. Извлекает из стека указанное количество элементов и записывает их в память, начиная с указанного адреса 1 байт
54 pframe0 Помещает указатель на 1 локальную переменную функции в стек. 1 байт
55 pframe1 Помещает указатель на 2 локальную переменную функции в стек. 1 байт
56 pframe2 Помещает указатель на 3 локальную переменную функции в стек. 1 байт
57 pframe3 Помещает указатель на 4 локальную переменную функции в стек. 1 байт
58 pframe4 Помещает указатель на 5 локальную переменную функции в стек. 1 байт
59 pframe5 Помещает указатель на 6 локальную переменную функции в стек. 1 байт
60 pframe6 Помещает указатель на 7 локальную переменную функции в стек. 1 байт
61 pframe7 Помещает указатель на 8 локальную переменную функции в стек. 1 байт
62 pframe Извлекает из стека число. Помещает в стек указатель на локальную переменную функции с этим номером 1 байт
63 pstatic Извлекает индекс статической переменной из стека, помещает указатель на эту переменную скрипта в стек. 1 байт
64 pglobal Извлекает индекс глобальной переменной из стека, помещает указатель на эту переменную в стек. 1 байт
65 parray Извлекает указатель на начало массива, размер элемента и индекс из стека. Помещает указатель на элемент массива в стек 1 байт
66 switch Следующий за командой байт - количество case. За ним следуют пары "значение (4 байта):адрес (4 байта)". Команда извлекает из стека число и последовательно сравнивает его со всеми значениями. При совпедении, выполняется переход по адресу, соответствующему этому значению (Байт после опкода * 8) + 2
67 spush Помещает строку в стек. Байт после опкода обозначает длину строки. Дальше следуют символы строки. (Байт после опкода)+2
68 null Помещает указатель на пустую память в стек. 1 байт
69 scpy Извлекает 2 указателя из стека и копирует второй элемент в первый. 1 байт
70 itos Извлекает целое из стека и помещает массив-строку, соответствующую числу, в стек. 1 байт
71 sadd Извлекает 2 указателя из стека, и прибавляет второй элемент к первому. 1 байт
72 saddi Извлекает 2 элемента из стека, переводит второй в из целого в строку (IntToStr) и добавляет эту строку к первому элементу. 1 байт
73 catch Устанавливает верх области сохранения, содержащей состояния перехваченных ошибок. (не используется) 1 байт
74 throw Индикатор области хендлов скриптовых ошибок относительно перехваченных скриптов. (не используется) 1 байт
75 sncpy Извлекает 3 значения из стека, копирует содержание по 3 адресу в первый элемент (по адресу) с повторением, определенным во втором элементе. Затем добавляет null в содержание по первому адресу. Получается строка в (1) = строке (3) дублированной (2) раз и завершенная нулевым символом. 1 байт
76 xget Из стека извлекается идентификатор live protected buffer, на стек помещается значение из этого буфера (4 байта) (только для PC) 1 байт
77 xset Извлекает из стека идентификатор live protected buffer и значение (4 байта). Записывает занчение в буфер. (только для PC) 1 байт
78 xref Извлекает адресс памяти из стека, извлекает другое значение для определения флагов преобразования, и наконец извлекает следующее значение, которое содержит количество элементов для обработки. Если первый бит в флаге установлен все элементы в памяти по адресу будут преобразованы в не поддерживаемое XLive состояние. Если 2 бит установлен они будут XLive поддержаны. (только для PC) 1 байт

^ Вектор - это структура, стостоящая из трех полей типа float

4b - FLOAT32 - X
4b - FLOAT32 - Y
4b - FLOAT32 - Z

Статические переменные

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

Глобальные переменные

Глобальные переменные доступны из любого скрипта. Сегмент глобальных переменных должен присутствовать в одном и только в одном скрипте (startup.sco). Поскольку обращение к переменным производится не по имени, а по адресу, важно, чтобы порядок глобальных переменных совпадал для всех скриптов. Для достижения этого, при компиляции, генерируется версия сегмента глобальных данных, которая записывается в заголовок скрипта. Если эта версия не совпадает с той, которая записана в заголовке того скрипта, из которого был загружен сегмент глобальных данных, загрузка скрипта не выполняется.



Инструменты

  • Scocl – высокоуровневый компилятор игровых скриптов GTA IV и EFLC.
  • OpenIV – Имеет встроенный декомпилятор.
  • SparkIV – Имеет встроенный декомпилятор.
п · о · р
GTA 4 Grand Theft Auto IV
Форматы файлов.dat.gxt.ide.img.ipl.nod.sco.rpf.rrr.wdd.wdr.wft.wbd/wbn.whm.wad.wnv.wpl.wtd
Документация Handling.datgta.datОружиеКатсценыПутиСкриптовые функцииШифрованиеФормат CFG файла настроек
Скриптинг в GTA 4
ИнструментыAPE IVASI LoaderIV NeedleGIMSOpenIVPathViewerSparkIVXLiveLessRaCon
Скриптовые программыAliceC++ Script HookScocl.NET Script HookDelphi Hook
ТуториалыИмпортирование текстур с помощью OpenIVИмпортирование текстур с помощью SparkIV
МодификацииGTA Vice City RageIV:SAGostown Paradise IV