You are not logged in.
в первую очередь, хотелось нормально методы CScriptThread обозвать нормально
1 | .text :00469F00 ParseThread |
движок перебирает опкоды, пока не найдет 0001: wait
1 | .text :00464080 ; int __stdcall CollectNumberParams(__int 16 ParamsNumber) |
движок читает опр. число числовых параметров (константы, переменные, массивы) из SCM. Параметры пишутся в ParamsArray[32].
1 | .text :00464DA0 ; int __cdecl j_SetJumpLocation(int JumpLocation) |
thread->IP ставится в указанную позицию (опкод 0002: jump и подобные)
1 | .text :00464790 ; int __cdecl GetVariablePos(int VarType) |
функция читает следующий параметр (предполагается, что там переменная) и возвращает адрес переменной в варспейсе. Используется в основном в выражениях
Vartype:
1 - local var
2 - global var
Параметр не используется.
1 | .text :004859D0 ; int __stdcall SetConditionResult(boolean ConditionResult) |
устанавливает значение условия в потоке (Thread->If_result)
1 | .text :00464500 ; int __stdcall GetThreadExtraParams(int *NewThreadStruct) |
собирает параметры, переданные в новый поток (опкод 004F). Останавливается после типа данных 0. Параметры пишутся в ParamsArray[32].
1 | .text :00464370 ; int __stdcall WriteResult2Variable(__int 16 VariablesCount) |
записывает N значений из ParamsArray[32] в переменные, которые идут в SCM. Используется в основном для записи результата (конструкторов).
1 | .text :00463D50 ; int __stdcall GetStringParam(int MoveAddress_ptr,byte MaxStringLength) |
тоже что CollectNumberParams только для строковых параметров (строк, строковых переменных).
1 | .text :00465AA0 EndThread |
заканчивает поток (опкод 004E)
Offline
2Seemann:
.text:00464080 ; int __stdcall CollectNumberParams(__int16 ParamsNumber)
.text:00464370 ; int __stdcall WriteResult2Variable(__int16 VariablesCount)
У меня они сначала назывались примерно так же. Потом я решил их унифицировать и обозвал их
CScriptThread::loadNumberParams и CScriptThread::storeNumberParams.
Обсуждабельно, но хотелось бы прийти к какому-нибудь унифицированному наименованию.
.text:00464DA0 ; int __cdecl j_SetJumpLocation(int JumpLocation)
У меня CScriptThread::goto. Опять-таки, обсуждабельно.
Была идея называть подобные методы opЧтоТо (она, соответственно, была opJump).
.text:00464790 ; int __cdecl GetVariablePos(int VarType)
До этой я пока не добрался.
.text:004859D0 ; int __stdcall SetConditionResult(boolean ConditionResult)
Предполагаtncz CScriptThread::storeConditionResult (для унификации с storeNumberParams).
.text:00464500 ; int __stdcall GetThreadExtraParams(int *NewThreadStruct)
Угу. А это как раз то, над чем я задумался. Параметром должен, по идее, передаваться CScriptThread * newThread.
Что касается того, что он заполняет. У меня это обозвано tls (Thread Local Storage) - по аналогии с "реальными потоками". Массив там 34 элемента, два последних - таймеры. Если есть лучшие идеи - переобзову.
.text:00463D50 ; int __stdcall GetStringParam(int MoveAddress_ptr,byte MaxStringLength)
Опять же, по аналогии - CScriptThread::loadStringParam (хотелось бы договориться о какой-то паре слов для обзывания этих функций: либо get/put, либо load/store, чтобы, в дальнейшем, не было разногласий. IMHO, load/store чуть логичнее, но, по большому счету, мне без разницы).
.text:00465AA0 EndThread
Если нет возражений, CScriptThread::terminate - два Thread в одном имени - слегка нелогично.
Еще немного:
.text:00463CA0 ; int __stdcall CScriptThread__localPtr(int idx)
Возвращает указатель на локальную переменную по указанному индексу.
.text:00463CC0 ; int __stdcall CScriptThread__localArrayPtr(int off,__int16 idx,char mul)
Возвращает указатель на элемент массива в локальных переменных. Параметры - смещение первого элемента массива, индекс в массива и размер элемента.
Возможно, правильнее будет CScriptThread::getLocalArrayPtr - но как-то длинно получается.
.text:00463CF0 ; int __stdcall CScriptThread__getArrayIndex(int move,__int16 *pOff,__int32 *pIdx)
Получить смещение первого элемента массива и индекс в нем из параметра.
.text:00464250 ; int __cdecl CScriptThread__peekNumber()
Получить следующий numberParam, не перемещая instructionPointer потока.
.text:004648E0 ; void __cdecl CScriptThread__init()
Проинициализировать поля объекта. (начальная инициализация)
Есть еще несколько методов, но они пока еще окончательно не оформлены.
Offline
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class CScriptThread { // только поля, без методов CScriptThread * prev; // _f00: предыдущий поток в очереди исполнения CScriptThread * next; // _f04: следующий поток в очереди исполнения char threadName[8]; // _f08: имя потока (8 символов, включая завершающий \0) u32 _f10; // _f10: u08 * ip; // _f14: instruction pointer - указатель на текущий обрабатываемый байт u32 stack[8]; // _f18: стек (для возвратов из процедур) u16 sp; // _f38: stack pointer - текущий элемент стека (индекс) u16 _f3A; // _f3A: u32 tls[34]; // _f3C: thread local storage - локальные переменные потока (два последних элемента - таймеры) u08 _fC4; // _fC4: u08 _fC5; // _fC5: u08 _fC6; // _fC6: u08 _fC7; // _fC7: u08 _fC8; // _fC8: u08 _fC9; // _fC9: u08 _fCA; // _fCA: u08 _fCB; // _fCB: u32 wakeTime; // _fCC: время пробуждения потока (используется для команды WAIT) u16 _fD0; // _fD0: u08 _fD2; // _fD2: u08 _fD3; // _fD3: u08 _fD4; // _fD4: u08 _fD5; // _fD5: u16 _fD6; // _fD6: u32 _fD8; // _fD8: u08 _fDC; // _fDC: 0 - в качестве локальных переменных используется TLS, 1 - используется scriptLocals u08 pad[3]; // заглушка для выравнивания } ; |
Размер структуры - 240 байт. Поля, относящиеся к логическим операциям, найдены, но еще не поименованы.
Сами структуры размещаются в:
1 2 | .data :00A8B430 ; CScriptThread scriptThreads[96]; .data :00A8B430 _scriptThreads CScriptThread 60h dup(<?>) |
Перед ними, в 0xA8B428 и 0xA8B42С находятся два указателя, один из них (пока не ясно, какой), указывает на активный поток. Для чего нужен другой - я пока не понял, возможно, это очередь неактивных потоков. Разберу подробно старт/завершения потока - будет ясно.
Last edited by listener (25-04-2007 15:57)
Offline
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 00000000 THREAD struc ; (sizeof=0xE0) 00000000 @Active dd ? 00000004 @Inactive dd ? 00000008 Name dd 2 dup(?) 00000010 BaseIP dd ? 00000014 CurrentIP dd ? 00000018 ReturnStack dd 8 dup(?) 00000038 StackCounter dw ? 0000003A field_3A dw ? 0000003C LocalVars dd 32 dup(?) 000000BC TimerA dd ? 000000C 0 TimerB dd ? 000000C 4 _isThreadActive db ? 000000C 5 IF_result db ? 000000C 6 __mission_cleanup db ? 000000C 7 ExternalFlag db ? 000000C 8 InMenu db ? 000000C 9 UnknownScriptAssigned db ? 000000CA field_CA dw ? 000000CC wakeup_time dd ? 000000D 0 if_Number dw ? 000000D 2 not_flag db ? 000000D 3 WBcheckFlag db ? 000000D 4 isWastedOrBusted db ? 000000D 5 field_D 5 db ? 000000D 6 field_D 6 db ? 000000D 7 field_D 7 db ? 000000D 8 SkipScenePos dd ? 000000DC MissionFlag db ? 000000DD field_DD db ? 000000DE field_DE dw ? 000000E 0 THREAD ends |
первые 2 поля указатели на след. активный (используется при парсинге потоков при переходе от одного к другому), и след. пустой (используется при создании нового потока).
Offline
У меня CScriptThread::goto.
скорее CScriptThread::SetIP
хотелось бы договориться о какой-то паре слов для обзывания этих функций: либо
get/put, либо load/store
мне нравится пара Get/Set Хотя значения особого не имеет.
Еще есть процедура, связанная с потоками:
1 | .text :00464D40 j_CreateThreadFromStartScm |
Создает поток с базой 0xA49960 (т.е. с начала main.scm). Этот поток запускается всегда при начале новой игры (загрузке). Именно благодаря нему создается игрок (CLEO2 тоже запускается из этого потока). Стартовый поток заканчивается после первого wait.
Last edited by Seemann (25-04-2007 16:33)
Offline
первые 2 поля указатели на след. активный (используется при парсинге потоков при переходе от одного к другому), и след. пустой (используется при создании нового потока).
Проверил еще раз. У меня получается четко, что потоки собираются в двусвязный список, и это указатели на предыдущий и следующий элемент списка (возможно, я их перепутал между собой, но это малокритично).
Есть две очереди: активных и неактивных потоков.
.data:00A8B428 ; CScriptThread *inactiveThreadQueue
.data:00A8B42C ; CScriptThread *activeThreadQueue
.text:00464C00 ; int __stdcall CScriptThread__addToQueue(CScriptThread **queue)
.text:00464BD0 ; int __stdcall CScriptThread__removeFromQueue(CScriptThread **queue)
По коду получается так.
В 004E: end_thread получается:
1 2 3 4 5 6 | .... // сбрасывается какой-то флаг removeFromQueue (&activeThreadQueue); addToQueue (&inactiveThreadQueue); endThread (); // да, terminate в качестве названия этой функции подойдет не очень - если не писать явно this->, не ясно, кого терминировать return true ; |
Last edited by listener (25-04-2007 17:01)
Offline
У меня получается четко, что потоки собираются в двусвязный список, и это указатели на предыдущий и следующий элемент списка (возможно, я их перепутал между собой, но это малокритично).
да, у меня тоже сначала эти поля называлиcь @Next, @Prev.
сбрасывается какой-то флаг
1 2 3 4 5 6 7 | .text :004667DB mov al, [esi+THREAD.MissionFlag] .text :004667E1 test al, al .text :004667E3 jz short _not_mission .text :004667E5 mov ds :bContinueMission , 0 .text :004667EC .text :004667EC _not_mission: .text :004667EC push offset @ActiveThread |
не помню уже почему назвал bContinueMission
Offline
Все-таки _f0 - next, а _f4 - prev.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // >> 464BD0 - исключить поток из очереди void CScriptThread: :removeFromQueue (CScriptThread ** queue) { if (prev) prev->next = next; else *queue = next; if (next) next->prev = prev; } // >> 464C00 - добавить поток в очередь void CScriptThread: :addToQueue (CScriptThread **queue) { next = *queue; prev = NULL; if (next) next->prev = this; *queue = this; } |
PS. А на gtaforums народ радостно публикует адрес WinMain ... Жуть какая. Зарегистриться там что-ли и закинуть не только адрес, но и весь декомпилированный WinMain...
Я, кстати, ни из чего найденного не делаю секрета, так что, если кто-нибудь закинет туда что-нибудь из накопанного - я буду только рад.
PPS. Кстати, какие-нибудь C++ - ные куски нужны? А то у меня их уже уже килобайт сто получается.
Offline
Зарегистриться там что-ли и закинуть не только адрес, но и весь декомпилированный WinMain...
ты бы лучше сразу сюда добавлял http://www.gtamodding.com/index.php?tit … _Addresses
Кстати, какие-нибудь C++ - ные куски нужны?
выкладывай, могут пригодиться (лучше наверно в текстовом файле, чтобы простыней не постить).
Offline
выкладывай, могут пригодиться (лучше наверно в текстовом файле, чтобы простыней не постить).
Ну, постить такие куски в форум - это техномазохизм какой-то получается.
Если все пойдет нормально - за выходные причешу текст (за три месяца, накопилось много изменений, без них оно (по сравнению с тем, что есть) практически нечитабельно) и выложу, возможно вместе со свежей базой.
А пока, вот что полностью разобрано по CScriptThread:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | // >> 463CA0 получить указатель на локальную переменную (с учетом того, используется TLS или нет) inline u 32 * localPtr (u 32 idx) { return (_fDC ? scriptLocals : tls)+idx; } // >> 464700 получить смещение в scmBlock следующего операнда (типы 2, 7) // т.е., возвращается не операнд, а только его смещение в scmBlock u 32 getGlobalOffset (); // >> 463CC0 получить индексированный указатель на локальную переменную (с учетом того, используется TLS или нет) inline u 32 * localArrayPtr (u 32 off, u 16 idx, u 08 mul) { return (_fDC ? scriptLocals : tls)+off+idx*mul; } // >> 463CF0 получить индекс и смещение для индексированного операнда. Первый параметр - выполнять переход к следующему байту или нет void getArrayIndex (bool move, u 16 * off, u 32 * idx); void getNumberParams (u 16 count); // >> 464080 получить числовые параметры команды void getStringParam (char * ptr, u 32 len); // >> 463D50 получить строковый параметр команды u 32 peekNumber (); // >> 464250 получить числовой операнд по текущему IP. IP не меняется void setNumberParams (u 16 count); // >> 464370 записать числовые значения (из opcodeParams в указанные переменные (т.е., indirect значения невозможны)) void getThreadParams (CScriptThread * thread); // >> 464500 получить набор переменных для TLS создаваемого потока void init (); // >> 4648E0 - проинициализировать объект void removeFromQueue (CScriptThread ** queue); // >> 464BD0 - исключить поток из очереди void addToQueue (CScriptThread ** queue); // >> 464C00 - добавить поток в очередь // >> 464C20 - взять поток из очереди неактивных потоков, проинициализировать и добавить в очередь активных потоков static CScriptThread * allocThread (u 08 * startIP); // >> 464C90 - аналогично предыдущему, только указывается индекс объекта в scriptThreads (проверяется, что он находится в inactiveThreadQueue) static CScriptThread * allocThreadByIndex (u 08 * startIP, u 32 index); void * getPointerParam (); // >> 464790 void setIP (s 32 newIP); // 464DA0 - перейти к указанному адресу |
Дальше можно, прикола ради и проверки для, вкомпилить это в DLL и попробовать подменить то, что в exe-шнике.
Offline
2Seemann:
2listener:
Нельзя ли в exe'шник встроить что-то типа эксепшинхендлера, чтобы при падении игры можно было увидеть хоть какую-нибудь информацию о причинах, или место скрипта где произошел баг ???
ps: Это резко снизило бы кол-во багов в разных модах...
Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ
Offline
2Capushon:
дык, это... CLEO2 + ScmLog. Берутся с http://cleo.sannybuilder.com
Offline
2listener:
2Seemann:
Выложите структуру CPlayer и CWanted, если такая имеется.
Last edited by Sanchez (28-04-2007 08:55)
Offline
Offline
2listener:
Есть идеи как при старте игры пропустить главное меню и сразу начать новую игру?
Пробовал 2 способа:
1. занопить строки в 0x0053E799, 0x00576C34, 0x576C41
глюк: в игре по понятной причине не открывается меню
2. заменить в 00748C90
mov ds:dwLoadingStage, 7
на
mov ds:dwLoadingStage, 8
глюк: если в игре выбрать новую игру - вылетает.
Offline
2. заменить в 00748C90
mov ds:dwLoadingStage, 7
на
mov ds:dwLoadingStage, 8глюк: если в игре выбрать новую игру - вылетает.
Так в САМП сделали , тоже новая игра не запускается ...
Offline
База listener'а по его же компактному gta_sa.exe.
[You must login to view hidden text.]
Must have для всех кто интересуется устройством игры. Надеюсь, мы еще увидим обновление для этого.
Offline
2listener:
Рад вновь видеть тебя Надеюсь время у тебя появится и ты нас еще чем-нибудь порадуешь.
Если можешь, ответь пожалуйста на пост 66 в этой теме.
Offline
Не совсем в рамках темы, но всё таки...
В ходе разработки своей программы SFX Editor(http://rapidshare.com/files/44154049/SF … r.rar.html) у меня возникла мысль заглянуть в дебри опкода 03CF и в ходе разбора кода я нарыл много полезной информации. Думаю она вам пригодится.
Вот функции и структуры связанные со звуком (в основном звуковые эффекты):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | CODE: 004D88A 0 void CAudio->AudioSFX: :LoadBankWave (int 16 BankID,BankSlotID) 004D8ED 0 void CAudio->AudioSFX: :LoadWave (int 16 BankID,WaveID,BankSlotID) 004D 9930 bool CAudio: :Create () 004D9CC 0 bool CAudioEvents: :Buffer : :LoadInfo (int32* pAudioEvent,pBankID,pWaveID,EBufferID) 004E01B 0 BankLookup* CAudioSFX: :GetBankLookupAddress (uint 8 BankID) 004E 0220 bool CAudioSFX: :LoadedBankToSlot (uint 16 BankID; int 16 BankSlotID) 004EBFE 0 bool CAudioEvents: :Buffer : :LoadedSlot (uint 8 BufferID) 004EF 520 int 8 CSoundManager: :LoadedBank (int 16 BankSlotID) 00507290 void CAudioEvents: :Buffer : :Load (uint 8 BufferId; int 32 AudioEvent) 005B9A 60 void CAudioEvents: :LoadExplosionSounds () 005B 9690 bool CSoundManager: :Init (?) 005B9A 60 void CAudioEvents: :LoadExplosionSounds 005B9C 60 bool CAudioEvents: :Create () DATA: 00B5F8B 8 CAudio +D 98 CAudioSFX* // здесь лежит указатель, адрес динамический, обычно 021F0000, насчёт класса не уверен 00B62CB 0 CSoundManager 00B6BC 90 CAudioEvents CAudioSFX + 0 dd* pBankSlotData // BankSlot.dat + 4 dd* pBankLookupData // BankLkup.dat + 8 dd* pPakFilesData // PakFiles.dat +C dw NumSlots +E dw NumBanks + 10 db NumPakFiles + 14 db BufferFlag? + 24 CAudioSFX: :Buffer [50] // С этим буфером до конца ещё не разобрался + 0 dd* pBankSlot + 4 dd BankLookup.WaveOffset + 8 dd BankLookup.WaveLenght + 14 dd UnkFlag? + 18 dw BankID +1A dw BankSlotID + 20 dw WaveID + 22 db BankLookup.PackID + 668 dw InitBufferSlotsNum // количество проинициализированных слотов буфера |
Ниже следующий кусок кода из моей программы. Он отражает назначение некоторых структур и переменных, которые используются в вышеперечисленных функциях.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | { === Wave Audio Bank Structure === } TWaveInfo = record HeaderOffset: Cardinal; StartLoop: Integer; SampleRate: Word; UnknownFlag1: Byte; // Pan?? UnknownFlag2: Shortint; // Loops??? end ; TWaveBankHeader = record WaveCount: Cardinal; WaveInfoList: array[0..399] of TWaveInfo; end ; TWaveBank = record Header: TWaveBankHeader; Data: array of Byte; end ; { === SFX PACK Structure === } TSFX_Pack = array of TWaveBank; { === BankLkup.dat Structure === } TWaveBankInfo = record PackFileID: Cardinal; // ($CCCCCC00 or $XX), $XX - File ID Offset: Cardinal; DataSize: Cardinal; end ; TWaveBanks = array of TWaveBankInfo; { === PakFiles.dat Structure === } TPackName = array of array[0..51] of Char; |
Здесь я хочу показать алгоритм работы опкода 03CF. Некоторые куски кода мне не совсем понятны, их назначение.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | 03CF: load_in (AUDIO_EVENT_BUFFER :unsigned_byte ) audio_event (AUDIO_EVENT :int ) AUDIO_EVENT_BUFFER(MAX 4 SLOTS) 1,2,3,4: для звуков (SOUNDs 2000..45400,-1) 3,4: для набора звуков (BANKs 1800..1829) ========================================================================================================================= <gta_sa._opcode_03CF> ========================================================================================================================= 0048519B > > 6A 02 PUSH 2 ; _opcode_03CF; Case 3CF of switch 00483BF 2 0048519D . 8BCE MOV ECX,ESI 0048519F . E 8 DCEEFDFF CALL <gta_sa.CScriptThread: :LoadNumParams > 004851A 4 . 8B0D 7C3CA 400 MOV ECX,DWORD PTR DS:[<OpcodeParams[1]>] 004851AA . 33D 2 XOR EDX,EDX 004851AC . 8A 15 783CA 400 MOV DL,BYTE PTR DS:[<OpcodeParams[0]>] 004851B 2 . FECA DEC DL 004851B 4 . 51 PUSH ECX ; 2: int 32 AudioEvent 004851B 5 . B 9 90BCB 600 MOV ECX,OFFSET <gta_sa.CAudioEvent> 004851BA . 52 PUSH EDX ; 1: uint 8 BufferID 004851BB . E 8 D 0200800 CALL <gta_sa.CAudioEvent: :Load > 004851C 0 . 32C 0 XOR AL,AL ========================================================================================================================= <gta_sa.CAudioEvent: :Load > ========================================================================================================================= 00507290 > $ 81C 1 A 0020000 ADD ECX,2A 0 ; Buffer& = CAudioEvents: :Buffer 00507296 .^E 9 F54EFEFF JMP gta_sa.004EC 190 ......................................................................................................................... 004EC 190 > 83EC 0C SUB ESP,0C 004EC 193 . 53 PUSH EBX 004EC 194 . 8B5C 24 14 MOV EBX,DWORD PTR SS:[ESP+14] ; EBX = BufferID 004EC 198 . 80FB 04 CMP BL, 4 004EC19B . 56 PUSH ESI 004EC19C . 8BF 1 MOV ESI,ECX 004EC19E . 0F 83 C 0000000 JNB gta_sa.004EC 264 ; exit if BufferID >= 4 004EC1A 4 . 53 PUSH EBX 004EC1A 5 . E 8 36FEFFFF CALL <gta_sa.CAudioEvents: :Buffer : :LoadedSlot > 004EC1AA . 84C 0 TEST AL,AL 004EC1AC . 0F 84 B 2000000 JE gta_sa.004EC 264 ; exit if prc = false 004EC1B 2 . 0FB6C 3 MOVZX EAX,BL 004EC1B 5 . 55 PUSH EBP 004EC1B 6 . 8BC 8 MOV ECX,EAX 004EC1B 8 . 57 PUSH EDI 004EC1B 9 . C1E 1 05 SHL ECX, 5 ; BufferID * 32 004EC1BC . 03F 1 ADD ESI,ECX 004EC1BE . 50 PUSH EAX ; 4: int 32 EBufferID = BufferID 004EC1BF . 8DBE AC 000000 LEA EDI,DWORD PTR DS:[ESI+AC] 004EC1C 5 . 57 PUSH EDI ; 3: int32* pWaveID = *Buffer: :Slot [BufferId].WaveID 004EC1C 6 . 8DAE A 8000000 LEA EBP,DWORD PTR DS:[ESI+A8] 004EC1CC . 8D 5424 2C LEA EDX,DWORD PTR SS:[ESP+2C] 004EC1D 0 . 55 PUSH EBP ; 2: int32* pBankID = *Buffer: :Slot [BufferId].BankID 004EC1D 1 . 52 PUSH EDX ; 1: int32* pAudioEvent = *AudioEvent 004EC1D 2 . E 8 E9DAFEFF CALL <gta_sa.CAudioEvents: :Buffer : :LoadInfo > 004EC1D 7 . 83C 4 10 ADD ESP, 10 004EC1DA . 84C 0 TEST AL,AL 004EC1DC . 0F 84 80000000 JE gta_sa.004EC 262 ; exit if PROC = false 004EC1E 2 . 8B 07 MOV EAX,DWORD PTR DS:[EDI] 004EC1E 4 . 33C 9 XOR ECX,ECX 004EC1E 6 . 85C 0 TEST EAX,EAX 004EC1E 8 . 66 :0FB6C3 MOVZX AX,BL 004EC1EC . 7C 1B JL SHORT gta_sa.004EC 209 ; jump if WaveID < 0 004EC1EE . 66 :8B0F MOV CX,WORD PTR DS:[EDI] 004EC1F 1 . 33D 2 XOR EDX,EDX 004EC1F 3 . 66 :8B55 00 MOV DX,WORD PTR SS:[EBP] 004EC1F 7 . 83C 0 1A ADD EAX,1A 004EC1FA . 50 PUSH EAX ; 3: int 16 BankSlotID 004EC1FB . 51 PUSH ECX ; 2: int 16 WaveID 004EC1FC . B 9 B8F8B 500 MOV ECX,<gta_sa.CAudio> 004EC 201 . 52 PUSH EDX ; 1: int 16 BankID 004EC 202 . E 8 C9CCFEFF CALL <gta_sa.CAudio->CAudioSFX: :LoadWave > 004EC 207 . EB 13 JMP SHORT gta_sa.004EC21C 004EC 209 > 66 :8B4D 00 MOV CX,WORD PTR SS:[EBP] 004EC20D . 83C 0 1A ADD EAX,1A 004EC 210 . 50 PUSH EAX ; 2: int 16 BankSlotID 004EC 211 . 51 PUSH ECX ; 1: int 16 BankID 004EC 212 . B 9 B8F8B 500 MOV ECX,<gta_sa.CAudio> 004EC 217 . E 8 84C6FEFF CALL <gta_sa.CAudio->AudioSFX: :LoadBankWave > 004EC21C > 8B 5424 24 MOV EDX,DWORD PTR SS:[ESP+24] 004EC 220 . 8996 A 4000000 MOV DWORD PTR DS:[ESI+A4],EDX ; Buffer: :Slot [BufferId].AudioEvent = AudioEvent 004EC 226 . C 786 9C 000000 >MOV DWORD PTR DS:[ESI+9C], 0 004EC 230 . C 74424 10 0000>MOV DWORD PTR SS:[ESP+10],C47A 0000 004EC 238 . 8B 4424 10 MOV EAX,DWORD PTR SS:[ESP+10] 004EC23C . 81C 6 90000000 ADD ESI, 90 ; CurSlot& = Buffer: :Slot [BufferId] 004EC 242 . C 74424 14 0000>MOV DWORD PTR SS:[ESP+14],C47A 0000 004EC24A . 8B4C 24 14 MOV ECX,DWORD PTR SS:[ESP+14] 004EC24E . 8906 MOV DWORD PTR DS:[ESI],EAX ; CurSlot.ddvar 1 = 0xC47A 0000 004EC 250 . C 74424 18 0000>MOV DWORD PTR SS:[ESP+18],C47A 0000 004EC 258 . 8B 5424 18 MOV EDX,DWORD PTR SS:[ESP+18] 004EC25C . 894E 04 MOV DWORD PTR DS:[ESI+4],ECX ; CurSlot.ddvar 2 = 0xC47A 0000 004EC25F . 8956 08 MOV DWORD PTR DS:[ESI+8],EDX ; CurSlot.ddvar 3 = 0xC47A 0000 004EC 262 > 5F POP EDI 004EC 263 . 5D POP EBP 004EC 264 > 5E POP ESI 004EC 265 . 5B POP EBX 004EC 266 . 83C 4 0C ADD ESP,0C 004EC 269 . C 2 0800 RETN 8 ========================================================================================================================= GetAudioEventInfo для 03CF опкода: загружает в буфер информацию о аудио событии . Буфер находится по адресу 0x00B6BFC 0 и содержит четыре элемента размером 32 байта . AudioEventBuffer [0x00B6BFC0, 32 bytes, 4 elements] + 0 dd ?C4A 70000 + 4 dd ?C4A 70000 + 8 dd ?C4A 70000 + 14 dd AudioEventId + 18 dd BankId + 20 dd WaveId EBufferID - Extended Buffer Identificator . Он может содержитать не только номер буфера, но и дополнительную информацию . Pascal: function CAudioEvents: :Buffer : :LoadInfo ( var pAudioEvent,pBankID,pWaveID: Integer; int EBufferID): Boolean; cdecl; C/C++: __cdecl int CAudioEvents: :Buffer : :LoadInfo (int* pAudioEvent,pBankID,pWaveID; int EBufferID); ------------------------- [ESP+8] pAudiEvent [ESP+C] pBankId [ESP+10] pWaveId [ESP+14] EBufferID ------------------------- ========================================================================================================================= 004D9CC 0 >/$ 56 PUSH ESI ; (* CAudioEvents: :Buffer : :LoadInfo *) 004D9CC 1 | . 8B 7424 08 MOV ESI,DWORD PTR SS:[ESP+8] 004D9CC 5 | . 8B 06 MOV EAX,DWORD PTR DS:[ESI] 004D9CC 7 | . 3D 08070000 CMP EAX, 708 ; if pAudioEvent < 1800 then 004D9CCC | . 7D 04 JGE SHORT gta_sa.004D9CD 2 ; begin 004D9CCE | . 32C 0 XOR AL,AL ; Result := False ; 004D9CD 0 | . 5E POP ESI ; Exit; 004D9CD 1 | . C 3 RETN ; end ; 004D9CD 2 |> 3D D 0070000 CMP EAX,7D 0 ; if pAudioEvent < 2000 then 004D9CD 7 | . 7D 1B JGE SHORT gta_sa.004D9CF 4 ; begin 004D9CD 9 | . 8B 0485 70BC8A 00 MOV EAX,DWORD PTR DS:[EAX*4+8ABC70] ; // BankEvent[AudioEvent - 1800] 004D9CE 0 | . 8B4C 24 0C MOV ECX,DWORD PTR SS:[ESP+C] 004D9CE 4 | . 8B 5424 10 MOV EDX,DWORD PTR SS:[ESP+10] 004D9CE 8 | . 8901 MOV DWORD PTR DS:[ECX],EAX ; pBankID := BankIdEvent[pAudioEvent - 1800]; 004D9CEA | . C 702 FFFFFFFF MOV DWORD PTR DS:[EDX],- 1 ; pWaveID := -1; 004D9CF 0 | . B 0 01 MOV AL, 1 ; Result := True ; 004D9CF 2 | . 5E POP ESI ; Exit; 004D9CF 3 | . C 3 RETN ; end ; 004D9CF 4 |> 3D FFFF 0000 CMP EAX,0FFFF ; if pAudioEvent = - 1 then // Для чего??? 004D9CF 9 | . 75 3D JNZ SHORT gta_sa.004D9D 38 ; begin 004D9CFB | . 8B 4424 0C MOV EAX,DWORD PTR SS:[ESP+C] ; // SOUND_BANK_NULL = 291 004D9CFF | . C 700 23010000 MOV DWORD PTR DS:[EAX], 123 ; pBankID := SOUND_BANK_NULL; 004D9D 05 | . 8B 4424 14 MOV EAX,DWORD PTR SS:[ESP+14] 004D9D 09 | . 85C 0 TEST EAX,EAX ; if (EBufferID >= 0) and 004D9D0B | . 7C 1D JL SHORT gta_sa.004D9D2A 004D9D0D | . 83F 8 04 CMP EAX, 4 ; (EBufferID < 4) then 004D9D 10 | . 7D 18 JGE SHORT gta_sa.004D9D2A ; begin 004D9D 12 | . 25 01000080 AND EAX, 80000001 ; EBufferID := EBufferID and $80000001 ; 004D9D 17 | . 79 05 JNS SHORT gta_sa.004D9D1E ; if EBufferID < 0 then // Зачем? Смысл? 004D9D 19 | . 48 DEC EAX ; begin 004D9D1A | . 83C 8 FE OR EAX,FFFFFFFE ; EBufferID := (EBufferID - 1) or $FFFFFFFE ; 004D9D1D | . 40 INC EAX ; Inc(EBufferID); 004D9D1E |> 8B4C 24 10 MOV ECX,DWORD PTR SS:[ESP+10] ; end ; 004D9D 22 | . D1E 0 SHL EAX, 1 ; pWaveID := EBufferID * 2; //всегда 0 или 2 004D9D 24 | . 8901 MOV DWORD PTR DS:[ECX],EAX ; Result := True ; 004D9D 26 | . B 0 01 MOV AL, 1 ; Exit; 004D9D 28 | . 5E POP ESI ; end ; 004D9D 29 | . C 3 RETN 004D9D2A |> 8B 5424 10 MOV EDX,DWORD PTR SS:[ESP+10] ; 004D9D2E | . C 702 00000000 MOV DWORD PTR DS:[EDX], 0 ; pWaveID := 0; 004D9D 34 | . B 0 01 MOV AL, 1 ; Result := True ; 004D9D 36 | . 5E POP ESI ; Exit; 004D9D 37 | . C 3 RETN ; end 004D9D 38 |> 05 30F8FFFF ADD EAX,-7D 0 004D9D3D | . 894424 08 MOV DWORD PTR SS:[ESP+8],EAX ; pAudioEvent := pAudioEvent - 2000; 004D9D 41 | . DB 4424 08 FILD DWORD PTR SS:[ESP+8] 004D9D 45 | . 83EC 08 SUB ESP, 8 004D9D 48 | . D80D 4C8B 8500 FMUL DWORD PTR DS:[858B4C] ; // CONST [858B4C] = 0.005 (1/200) 004D9D4E | . DD1C 24 FSTP QWORD PTR SS:[ESP] 004D9D 51 | . E 8 9A7C 3400 CALL <gta_sa.floor> 004D9D 56 | . 83C 4 08 ADD ESP, 8 004D9D 59 | . E 8 E27D 3400 CALL <gta_sa.__ftol2> 004D9D5E | . 8B4C 24 0C MOV ECX,DWORD PTR SS:[ESP+C] 004D9D 62 | . 05 93000000 ADD EAX, 93 004D9D 67 | . 8901 MOV DWORD PTR DS:[ECX],EAX ; pBankID := Floor(pAudioEvent/200) + 147 004D9D 69 | . 8B 06 MOV EAX,DWORD PTR DS:[ESI] ; // pBankID := AudioEvent div 200 + 147 004D9D6B | . 2D D 0070000 SUB EAX,7D 0 ; // 147 - SCRIPT_FIRST_BANK_ID 004D9D 70 | . 99 CDQ 004D9D 71 | . B 9 C 8000000 MOV ECX,0C 8 004D9D 76 | . F7F 9 IDIV ECX 004D9D 78 | . 8B 4424 10 MOV EAX,DWORD PTR SS:[ESP+10] 004D9D7C | . 5E POP ESI 004D9D7D | . 8910 MOV DWORD PTR DS:[EAX],EDX ; pWaveID := pAudioEvent mod 200 004D9D7F | . B 0 01 MOV AL, 1 ; Result := True ; 004D9D 81 \ . C 3 RETN ; Exit; ========================================================================================================================= CAudio->AudioSFX: :LoadBankWave (int 16 BankID,BankSlotID) ========================================================================================================================= 004D88A 0 > $ 8A 41 01 MOV AL,BYTE PTR DS:[ECX+1] ; 004D88A 3 . 84C 0 TEST AL,AL 004D88A 5 . 75 0B JNZ SHORT gta_sa.004D88B 2 004D88A 7 . 8B 89 980D 0000 MOV ECX,DWORD PTR DS:[ECX+D98] ; CAudioSFX& = *CAudio->AudioSFX 004D88AD . E 9 BE7D 0000 JMP gta_sa.004E 0670 004D88B 2 > C 2 0800 RETN 8 ......................................................................................................................... 004E 0670 > 56 PUSH ESI 004E 0671 . 8BF 1 MOV ESI,ECX ; ESI = CAudioSFX 004E 0673 . 8A 46 14 MOV AL,BYTE PTR DS:[ESI+14] 004E 0676 . 84C 0 TEST AL,AL 004E 0678 . 0F 84 15010000 JE gta_sa.004E 0793 ; exit if CAudioSFX: :UnkFlag1 = 0 004E067E . 0FBF 46 0E MOVSX EAX,WORD PTR DS:[ESI+E] 004E 0682 . 53 PUSH EBX 004E 0683 . 8B5C 24 0C MOV EBX,DWORD PTR SS:[ESP+C] 004E 0687 . 55 PUSH EBP 004E 0688 . 0FB7EB MOVZX EBP,BX 004E068B . 3BE 8 CMP EBP,EAX 004E068D . 57 PUSH EDI 004E068E . 0F8F FC 000000 JG gta_sa.004E 0790 ; exit if BankID > CAudioSFX: :NumBanks 004E 0694 . 8B7C 24 18 MOV EDI,DWORD PTR SS:[ESP+18] 004E 0698 . 66 :85FF TEST DI,DI 004E069B . 0F8C EF 000000 JL gta_sa.004E 0790 ; exit if BankID < 0 004E06A 1 . 66 :3B7E 0C CMP DI,WORD PTR DS:[ESI+C] 004E06A 5 . 0F8F E 5000000 JG gta_sa.004E 0790 ; exit if BankSlotID > CAudioSFX: :NumBankSlots 004E06AB . 57 PUSH EDI ; 2: int 16 BankSlotID 004E06AC . 53 PUSH EBX ; 1: int 16 BankID 004E06AD . E 8 6EFBFFFF CALL <gta_sa.CAudioSFX: :LoadedBankToSlot > ; <|=== LoadedBankToSlot??? === 004E06B 2 . 84C 0 TEST AL,AL 004E06B 4 . 0F 85 D 6000000 JNZ gta_sa.004E 0790 ; exit if proc = true 004E06BA . 33C 9 XOR ECX,ECX 004E06BC . 8D 46 3E LEA EAX,DWORD PTR DS:[ESI+3E] 004E06BF . 90 NOP ; /=== LoadedBankToBuffer??? === 004E06C 0 > 0FBF 50 FE MOVSX EDX,WORD PTR DS:[EAX-2] ; |!loop ECX = 0..31 004E06C 4 . 3BD 5 CMP EDX,EBP ; | 004E06C 6 . 75 09 JNZ SHORT gta_sa.004E06D 1 ; | jump if Buffer[ECX].BankID <> BankID 004E06C 8 . 66 :3938 CMP WORD PTR DS:[EAX],DI ; | 004E06CB . 0F 84 BF 000000 JE gta_sa.004E 0790 ; |exit if Buffer[ECX].BankSlotID = BankSlotID 004E06D 1 > 41 INC ECX ; | 004E06D 2 . 83C 0 20 ADD EAX, 20 ; | 004E06D 5 . 83F 9 32 CMP ECX, 32 ; | 004E06D 8 .^7C E 6 JL SHORT gta_sa.004E06C 0 ; \ jump !loop if ECX < 32 004E06DA . 53 PUSH EBX ; 1: BankID 004E06DB . 8BCE MOV ECX,ESI 004E06DD . E 8 CEFAFFFF CALL <gta_sa.CAudioSFX: :GetBankLookupAddress >; BankLookup* PROC 004E06E 2 . 0FBF8E 6806000>MOVSX ECX,WORD PTR DS:[ESI+668] 004E06E 9 . C1E 1 05 SHL ECX, 5 ; InitBufferSlotsNum* 32 004E06EC . 66 :895C31 3C MOV WORD PTR DS:[ECX+ESI+3C],BX ; Buffer[InitBufferSlotsNum].BankID = BankID 004E06F 1 . 0FBF 96 6806000>MOVSX EDX,WORD PTR DS:[ESI+668] 004E06F 8 . C1E 2 05 SHL EDX, 5 004E06FB . 66 :897C32 3E MOV WORD PTR DS:[EDX+ESI+3E],DI ; Buffer[InitBufferSlotsNum].BankSlotID = BankSlotID 004E 0700 . 0FBF8E 6806000>MOVSX ECX,WORD PTR DS:[ESI+668] 004E 0707 . 83C 1 02 ADD ECX, 2 004E070A . C1E 1 05 SHL ECX, 5 004E070D . 66 :C70431 FFFF MOV WORD PTR DS:[ECX+ESI],0FFFF ; Buffer[InitBufferSlotsNum].Unk 1 = - 1 004E 0713 . 0FBF8E 6806000>MOVSX ECX,WORD PTR DS:[ESI+668] 004E071A . 8B1E MOV EBX,DWORD PTR DS:[ESI] 004E071C . 0FBFD 7 MOVSX EDX,DI 004E071F . 69D 2 D 4120000 IMUL EDX,EDX,12D 4 004E 0725 . 03D 3 ADD EDX,EBX 004E 0727 . C1E 1 05 SHL ECX, 5 004E072A . 895431 24 MOV DWORD PTR DS:[ECX+ESI+24],EDX ; Buffer[InitBufferSlotsNum].pBankSlot = *BankSlot[BankSlotID] 004E072E . 8A 08 MOV CL,BYTE PTR DS:[EAX] 004E 0730 . 0FBF 96 6806000>MOVSX EDX,WORD PTR DS:[ESI+668] 004E 0737 . C1E 2 05 SHL EDX, 5 004E073A . 884C 32 42 MOV BYTE PTR DS:[EDX+ESI+42],CL ; Buffer[InitBufferSlotsNum].PackID = BankLookup.PackID 004E073E . 8B 48 04 MOV ECX,DWORD PTR DS:[EAX+4] 004E 0741 . 0FBF 96 6806000>MOVSX EDX,WORD PTR DS:[ESI+668] 004E 0748 . C1E 2 05 SHL EDX, 5 004E074B . 894C 32 28 MOV DWORD PTR DS:[EDX+ESI+28],ECX ; Buffer[InitBufferSlotsNum].PackID = BankLookup.WaveDataOffset 004E074F . 0FBF 96 6806000>MOVSX EDX,WORD PTR DS:[ESI+668] 004E 0756 . 8B 40 08 MOV EAX,DWORD PTR DS:[EAX+8] 004E 0759 . C1E 2 05 SHL EDX, 5 004E075C . 894432 2C MOV DWORD PTR DS:[EDX+ESI+2C],EAX ; Buffer[InitBufferSlotsNum].PackID = BankLookup.WaveLenght 004E 0760 . 0FBF8E 6806000>MOVSX ECX,WORD PTR DS:[ESI+668] 004E 0767 . C1E 1 05 SHL ECX, 5 004E076A . C 74431 38 0100>MOV DWORD PTR DS:[ECX+ESI+38], 1 ; Buffer[InitBufferSlotsNum].bUnkFlag 1 = 1 004E 0772 . 0FBF 86 6806000>MOVSX EAX,WORD PTR DS:[ESI+668] 004E 0779 . 66 :FF86 660600>INC WORD PTR DS:[ESI+666] ; CAudioSFX: :InitBankBufNum ++ 004E 0780 . 40 INC EAX 004E 0781 . 99 CDQ 004E 0782 . B 9 32000000 MOV ECX, 32 004E 0787 . F7F 9 IDIV ECX 004E 0789 . 66 :8996 680600>MOV WORD PTR DS:[ESI+668],DX ; CAudioSFX: :InitBufNum ++ %= 50 004E 0790 > 5F POP EDI 004E 0791 . 5D POP EBP 004E 0792 . 5B POP EBX 004E 0793 > 5E POP ESI 004E 0794 . C 2 0800 RETN 8 |
Ещё мне не совсем понятно назначение файла BankSlot.dat.
Наверное этот файл хранит глобальный буффер, его размер и начальные значения.
Вообще, я так понимаю в игре три буффера для звуковых эффектов.
Первый, и наверное самый главный - это буффер BankSlot. Количество слотов зависит от размера файла. Обычно 45.
Второй - это CAudiSFX::Buffer[]. Имеет 50 слотов.
И третий, наверное для скриптов - это CAudioEvent::Buffer. Он самый маленький имеет всего только 4 слота.
Но фишка в том, что в слот может загружатся как целый банк, так и отдельный файл!
А некоторые загружаются ещё в начале игры. Их не нужно загружать повторно.
Моей программой можно посмотреть EventId, BankId, WaveId и прослушать необходимые звуки.
Думаю, если Seemann согласится встроить SFX плагин, то в SB3 мы сможем прослушивать звуки,
не отвлекаясь от написания скриптов. Думаю, что в мой плагин можно будет добавить функцию,
которая возвращает имя аудио события, если в SB3 не будут именованы аудио-константы.
Ладно хватит. А то уже оффтоп пошёл
А, чуть не забыл.
По файловому адресу 004AB490 идут структуры размером 4 байта и в каждой из них номер банка,
положение который соотвествует скриптовым событиям, начиная с 1800 и до 2000.
Это те аудио события, которые загружают банки, а не звуки
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 352: 1800 310: 1801 296: 1802 291: 1803,1805,1808,1815, 1816 // считается как NULL, -1 указывает тоже на этот банк 242: 1804 222: 1806 209: 1807 167: 1809 163: 1810 160: 1811 265: 1812 304: 1813 158: 1814 292: 1817 171: 1818 198: 1819 226: 1820 293: 1821 319: 1822 345: 1823 351: 1824 266: 1825 183: 1826 153: 1827 298: 1828 339: 1829 |
Кстати, аудио события, начинающие с 1000 и до 1800, это звуки банков, которые доступны только при загрузке банков.
Они проигрываются только с помощью следующих опкодов:
1 2 | 097A: play_at 0.0 0.0 0.0 loaded_audio_event 1132 097B=2,play_audio_at_object %1d% event %2d% |
Но некоторые из этих событий не надо загружать, т. к. они уже либо загружены,
либо загружаются и проигрываются вышеупомянутыми опкодами.
Last edited by San'OK (21-07-2007 11:54)
Offline
Некоторую информацию по SA SFX можно почерпнуть отсюда:
http://www.gtaforums.com/index.php?showtopic=225049
http://pdescobar.home.comcast.net/gta/saat/sfx_dir.html
и посмотреть исходники SAAT.
За описания процедур спасибо. Насчет плагина еще обсудим
Edit:
На всякий случай скажу, что 0xC47A0000 = -100.0
Last edited by Seemann (21-07-2007 14:41)
Offline
На закуску:)
1 2 3 4 | 018c=4,play_sound %4d% at %1d% %2d% %3d% 097A=4,play_audio_at %1d% %2d% %3d% event %4d% 00507340 CAudioEvent: :Buffer : :PlayAt (t_coords Coords; int 16 EventID) |
Покапавшись в ассемблере отличий у этих опкодов не нашёл. Они положи почти как две капли воды. Хотя последний, наверное, должен использоваться после 03CF, который загружает банки.
Я думаю, так будет логичнее их назвать:
1 2 3 4 5 6 7 8 | 018c=4,play_at %1d% %2d% %3d% loaded_audio_event %4d% // проигрывает уже загруженные события (1000..1800) 097A=4,play_at %1d% %2d% %3d% loaded_bank_audio_event %4d% // проигрывает уже загруженные события (1000..1800) из банков (1800..2000) %4d% = - 1 // возможно проигрывает последний загруженный звук, но неуверен. Надо проверить в игре. |
Edit:
На всякий случай скажу, что 0xC47A0000 = -100.0
Почему -100 ?
(Добавлено) А точно это ж float! Блин, это значит, что в буфере содержутся координаты воспроизведения звука!
...посмотреть исходники SAAT.
Зачем? Я смотрел раньше, но ничего нового я не узнал.
А программа работает нормально? В будущем я ещё и для AudioStreams что-то подобное сделаю.
Last edited by San'OK (21-07-2007 18:43)
Offline
Кстати, может тебе пригодится вот этот кусок кода с одной программки, а то я смотрю у вас невнятно эта структрура описана здесь на форуме:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | struct GTASA_SCRIPT_THREAD // 0xE0 bytes total { void* pNext; // 0x00 void* pPrev; // 0x04 char strName[8]; // 0x08 DWORD dwBaseIP; // 0x10 DWORD dwScriptIP; // 0x14 DWORD dwReturnStack[8]; // 0x18 WORD dwStackPointer; // 0x38 DWORD dwLocalVar[34]; // 0x3C BYTE bStartNewScript; // 0xC4 BYTE bJumpFlag; // 0xC5 BYTE bIsMissionThread; // 0xC6 BYTE bIsExternalScript; // 0xC7 BYTE bInMenu; // 0xC8 BYTE bUnknown; // 0xC9 DWORD dwWakeTime; // 0xCC WORD wIfParam; // 0xD0 BYTE bNotFlag; // 0xD2 BYTE bWastedBustedCheck;// 0xD3 BYTE bWastedBustedFlag; // 0xD4 DWORD dwSceneSkipIP; // 0xD8 BYTE bMissionThread; // 0xDC } ; |
Offline
Добавил обновленные списки функций. Ссылки в первом посте.
Offline
Вот, немного покопался в новой базе, сравнивая некоторые функции с исходниками RenderWare'вского "скелета":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | файл: renderware/skel/skeleton.c 6193F 0 RsKeyFromScanCode 619410 RsTimer 619420 RsWindowSetText 619430 RsPathGetSeparator 619440 RsCameraShowRaster 619460 RsAlwaysOnTop 619470 RsRegisterImageLoader 619480 RsSetDebug 619490 RsMouseSetVisibility 6194A 0 RsMouseSetPos 6194B 0 RsSelectDevice 6194C 0 RsInputDeviceAttach 619510 rsCommandLine 619530 rsPreInitCommandLine 619560 RsKeyboardEventHandler 619580 RsMouseEventHandler 6195A 0 RsPadEventHandler 6195E 0 RsRwTerminate 6195F 0 RsTerminate 619600 RsInitialize 619670 RsSetModelTexturePath 619780 RsSetPresetView 619840 RsSetNextPresetView 619880 RsSetPreviousPresetView 6198C 0 RsDestroyPresetViews 619910 CameraElAzPosFromLTM 619AB 0 RsGetPresetViewDescription 619AF 0 RsGrabScreen 619B 00 RsErrorMessage 619B 30 RsWarningMessage 619C 90 RsRwInitialize 619D 60 RsLoadPresetViews 619FA 0 RsSavePresetView файл: renderware/skel/win/win.c 7451B 0 psWindowSetText (gta_SetWindowText) 7451D 0 psErrorMessage (_ShowMessageBoxHand) 7451F 0 psWarningMessage 745240 psCameraShowRaster 745270 psTimer 7452B 0 psGrabScreen 7453E 0 psMouseSetVisibility 7453F 0 psMouseSetPos 745500 psPathGetSeparator 745540 psDebugMessageHandler 7458A 0 psTerminate 7458B 0 psAlwaysOnTop 745CC 0 dialogInit 746190 psSelectDevice 747420 psInitialize RW: 802EA 0 RwImageSetPath Несколько переменных: dword_C1707C PresetViews dword_C 17080 NumPresetViews dword_C 92104 ClocksStart_msb dword_C 92108 ClocksStart_lsb array_8D2C 00 KeysNormal array_8D2D 00 KeysShifted struct_8D2E 00 Xaxis struct_8D2E0C Yaxis struct_8D2E 18 Zaxis string_8D2E 24 ViewsFileName dword_8D2E 30 CurrentPresetView dword_8D2E 34 DefaultVideoMode |
PS: в базе RwEngineInstance и RwGlobals представлены как две разных структуры, на самом деле RwEngineInstance это указатель на структуру типа RwGlobals.
PPS: если нужно, могу выложить исходники этого скелетного приложения.:cool:
[large][acronym=Завтра, завтра, постоянно завтра, так проходит жизнь]Cras, cras, semper cras, sic evadit aetas[/acronym][/large]
Offline