Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Темы - Shagg_E

Страницы: [1]
1
Столкнулся с проблемой, которая всё-таки вынудила меня начать писать плагин, производящий некоторые операции спецом для CarRec(на самом деле для ActRec).
И как я и думал - меня понесло куда-то не туда и теперь пишу плагин, добавляющий новые опкоды, не только для CarRec но и вообще(перенесу в опкоды кое-какие свои старые и новые задумки, типа фотокамеры, отрывания колес и т.п., а также разные вещи, которые я увидел на этом сайте(авторов укажу))...

Пока список планируемых опкодов такой(эти я по большей мере знаю, как реализовать, либо подсмотрел в разных темах на этом сайте):
опкоды CarRec, ObjRec, ActRec

get object rotation
set object rotation
get vehicle rotation
set vehicle rotation
get actor rotation
set actor rotation

is_vehicle car
is_vehicle bike
is_vehicle heli
is_vehicle boat
is_vehicle plane

альтернатива z_ground(processlineofsight)

съемка скриншотов без hud и прочих надписей

детач компонентов авто(пока не уверен, но возможно выйдет сделать не только для колес)

поворот компонентов авто(не 100%)

разбивание разбиваемых объектов(типа стекла)

атач/детач различных entity к другим, в т.ч. - к костям

repair car completely

remove actor bodypart?(не уверен)

play mpg video

enable_blur/trails

get camera direction vector

ped_say

Play_1d_Sound

Get Camera position
Get Camera direction

get angle from vector XYZ store to XaYaZa

Сделано:
0E10: rotate_actor $PLAYER_ACTOR boneindex 5 angles 0.0 0.0 0.0 blending_time 500 freeze_time 2000 release_time 1000
0E11: store_actor $PLAYER_ACTOR boneindex 5 global 1 rotation_to 1@ 2@ 3@
0E12: store_actor $PLAYER_ACTOR boneindex 5 global 1 position_to 4@ 5@ 6@

Не удалось/не знаю, как сделать(FAIL):
play_3d_sfx

Пишите, если есть какие идеи новых опкодов. Если мне будет по силам - реализую.

2
Моды / CarRec
« : Май 28, 2017, 01:34:43 am »
Решил я сделать "визуальный эквалайзер" для Dubstep-пушки(да простит меня Prographer за то что я влез и изнасиловал его идею), для чего понадобилось записать огромное кол-во значений в файл, который позднее был бы загружен скриптом. ini для этого не подходил(пустой расход ресурсов) - понадобилось создать бинарник средствами CLEO. Опыта у меня в этом не было, однако DK мне всё разъяснил и показал на конкретных примерах(за что ему еще раз огромнейшее спасибо!).
Однако пока я ковырял эту тему, на ум мне пришла ооочень старая идея, реализацию которой я несколько лет откладывал на "потом", а сейчас возникла реальная возможность её воплотить.
Подробная запись движения автомобиля.
Без лишних слов - вот 2 видоса:
! No longer available

! No longer available


Думаю, нет нужды объяснять, для чего такая запись может понадобиться(все помнят подобные сцены из SA, либо записи трюков в школе вождения), вопрос лишь в том, как лучше её произвести.

Я сделал так: взял(для начала) 19 переменных:
1)время
2-13)матрица позиции и поворота транспорта
14-16)скорость движения(movement speed) транспорта
17-19)сила вращения(turn speed) транспорта
20)переменная про запас(сейчас уже понял, что "докинуть" придется гораздо больше переменных)

На каждую переменную по 4 байта(знаю, что в SA версии всё гораздо экономнее, но за идеями оптимизации я сюда и пишу), 20x4=80 байт за такт x30 тактов в секунду при записи с ограничителем кадров = 2400 байт в секунду. Я сделал для теста лимит 4 млн байт(около получаса времени записи), однако если записывать без ограничителя кадров - может уходить до миллиона(!) байт в минуту, а то и больше. Скрипт написан так, что фреймрейт записи никак не влияет на скорость воспроизведения, так что никаких проблем с синхронизацией не возникнет.
Запись происходит в CLEO/carrec.cr
Активация/деактивация скрипта: C+R
Далее R - начать/закончить запись(можно писать поверх старого файла)
P - начать/закончить воспроизведение имеющейся записи.
При отсутствии carrec.cr файла воспроизведение не начнется.
Воспроизведение автоматически повторяется после завершения, пока не будет нажата P.

Код скрипта:
Код: Text
  1. {$CLEO .cs}
  2.  
  3. //-------------MAIN---------------
  4. thread 'CARREC'
  5.  
  6. :CARRECORD_01
  7. wait 0
  8. if and
  9.    Player.Defined($PLAYER_CHAR)
  10. 00E0:   player $PLAYER_CHAR driving
  11. jf @CARRECORD_01
  12. if and
  13. 0AB0: key_pressed 67 // C
  14. 0AB0: key_pressed 82 // R
  15. jf @CARRECORD_01
  16.  
  17. :CARRECORD_02
  18. wait 0
  19. if and
  20.    Player.Defined($PLAYER_CHAR)
  21. 00E0:   player $PLAYER_CHAR driving
  22. jf @CARRECORD_01
  23. if or
  24. 8AB0: NOT key_pressed 67 // C
  25. 8AB0: NOT key_pressed 82 // R
  26. jf @CARRECORD_02
  27. 03C1: 0@ = player $PLAYER_CHAR car_no_save
  28. 018C: play_sound 14 at 0.0 0.0 0.0
  29.  
  30. :CARRECORD_03
  31. wait 0
  32. 0AD1: show_formatted_text_highpriority "Car Recording Script is ~t~ready. ~h~Press ~o~R ~h~to start recording. ~h~Press ~p~P ~h~to play record." time 100
  33. if and
  34.    Player.Defined($PLAYER_CHAR)
  35. 00E0:   player $PLAYER_CHAR driving
  36. 8039:   NOT 0@ == -1
  37. 00DC:   player $PLAYER_CHAR driving 0@
  38. jf @CARRECORD_CANCEL
  39. if
  40. 0AB0: key_pressed 82 // R
  41. jf @CARRECORD_PLAY
  42. if
  43. 8AB0: NOT key_pressed 67 // C
  44. jf @CARRECORD_CANCEL
  45.  
  46. :CARRECORD_04
  47. wait 0
  48. if and
  49.    Player.Defined($PLAYER_CHAR)
  50. 00E0:   player $PLAYER_CHAR driving
  51. 8039:   NOT 0@ == -1
  52. 00DC:   player $PLAYER_CHAR driving 0@
  53. jf @CARRECORD_CANCEL
  54. if
  55. 8AB0: NOT key_pressed 82 // R
  56. jf @CARRECORD_04
  57. 0006: 1@ = 4000000 // memory limit
  58. 0AC8: 2@ = allocate_memory_size 1@
  59. 0006: 3@ = 0x00 // allocated memory offset
  60. 018C: play_sound 16 at 0.0 0.0 0.0
  61. 0006: 16@ = 0
  62.  
  63. :CARRECORD_05
  64. 0AD1: show_formatted_text_highpriority "~o~RECORDING: %d ms ~h~Press ~x~R ~h~to finish recording." time 100 16@
  65. if and
  66.    Player.Defined($PLAYER_CHAR)
  67. 00E0:   player $PLAYER_CHAR driving
  68. 8039:   NOT 0@ == -1
  69. jf @CARRECORD_END
  70. if and
  71. 00DC:   player $PLAYER_CHAR driving 0@
  72. 8AB0: NOT key_pressed 82 // R
  73. jf @CARRECORD_END
  74. 0AB1: call_scm_func @CARRECORD_RECORDING 4 0@ 2@ 3@ 16@ 3@
  75. wait 0
  76. 0085: 15@ = 1@
  77. 0062: 15@ -= 3@
  78. 000E: 15@ -= 0x50 // 80 bytes
  79. 001B:   0 > 15@ // if memory full
  80. jf @CARRECORD_05
  81. //jump @CARRECORD_END
  82.  
  83. :CARRECORD_END
  84. 0AB1: call_scm_func @CARRECORD_RECORDTOCR 2 2@ 3@
  85. 0AC9: free_allocated_memory 2@
  86. 018C: play_sound 10 at 0.0 0.0 0.0
  87. 0AD1: show_formatted_text_highpriority "Car Recording ~x~is finished. ~h~Time: ~x~%d ms." time 3000 16@
  88. jump @CARRECORD_01
  89.  
  90. :CARRECORD_CANCEL
  91. wait 0
  92. if or
  93. 8AB0: NOT key_pressed 67 // C
  94. 8AB0: NOT key_pressed 82 // R
  95. jf @CARRECORD_CANCEL
  96. 018C: play_sound 13 at 0.0 0.0 0.0
  97. 0AD1: show_formatted_text_highpriority "Car Recording Script ~y~deactivated!" time 2000
  98. jump @CARRECORD_01
  99.  
  100. :CARRECORD_PLAY
  101. if
  102. 0AB0: key_pressed 80 // P
  103. jf @CARRECORD_03
  104.  
  105. :CARRECORD_PLAY_02
  106. wait 0
  107. if and
  108.    Player.Defined($PLAYER_CHAR)
  109. 00E0:   player $PLAYER_CHAR driving
  110. 8039:   NOT 0@ == -1
  111. 00DC:   player $PLAYER_CHAR driving 0@
  112. jf @CARRECORD_CANCEL
  113. if
  114. 8AB0: NOT key_pressed 80 // P
  115. jf @CARRECORD_PLAY_02
  116. if
  117. 0AAB: file_exists "cleo\carrec.cr"
  118. jf @CARRECORD_CANCEL
  119. //04C4: create_coordinate 1@ 2@ 3@ from_actor $PLAYER_ACTOR offset 0.0 0.0 2.0
  120. //012A: put_player $PLAYER_CHAR at 1@ 2@ 3@ and_remove_from_car
  121. //0464: put_actor $PLAYER_ACTOR into_turret_on_car 0@ at_car_offset 0.0 0.0 1.0 position 0 angle 0.0 with_weapon 0
  122. //wait 0
  123. 0AB1: call_scm_func @CARRECORD_READCR 0 2@ 1@
  124.  
  125. :CARRECORD_PLAY_START
  126. 0006: 3@ = 0x00 // allocated memory offset
  127. 018C: play_sound 16 at 0.0 0.0 0.0
  128. 0227: 14@ = car 0@ health
  129. 0006: 16@ = 0
  130. 046C: 15@ = car 0@ driver
  131. 0039:   15@ == -1
  132. jf @CARRECORD_PLAY_05
  133. 03A2: set_car_status 0@ to 3
  134.  
  135. :CARRECORD_PLAY_05
  136. 0AD1: show_formatted_text_highpriority "~p~RECORD PLAYBACK: %d ms ~h~Press ~p~P ~h~to finish playback." time 100 16@
  137. //Camera.OnPed($PLAYER_ACTOR, 0, 2)
  138. if and
  139.    Player.Defined($PLAYER_CHAR)
  140. //00E0:   player $PLAYER_CHAR driving
  141. 8039:   NOT 0@ == -1
  142. jf @CARRECORD_PLAY_END
  143. if// and
  144. //00DC:   player $PLAYER_CHAR driving 0@
  145. 8AB0: NOT key_pressed 80 // P
  146. jf @CARRECORD_PLAY_END
  147. 0AB1: call_scm_func @CARRECORD_RECORDPLAYBACK 4 0@ 2@ 3@ 16@ 3@
  148. wait 0
  149. 0224: set_car 0@ health_to 14@
  150. 0085: 15@ = 1@
  151. 0062: 15@ -= 3@
  152. 000E: 15@ -= 0x50 // 80 bytes
  153. 001B:   0 > 15@ // if playback is finished
  154. jf @CARRECORD_PLAY_05
  155. jump @CARRECORD_PLAY_START
  156.  
  157. :CARRECORD_PLAY_END
  158. 0AC9: free_allocated_memory 2@
  159. //0465: remove_actor $PLAYER_ACTOR from_turret_mode
  160. //Camera.Restore_WithJumpCut
  161. 018C: play_sound 10 at 0.0 0.0 0.0
  162. 0AD1: show_formatted_text_highpriority "Car record playback ~x~is finished. ~h~Time: ~x~%d ms." time 3000 16@
  163. jump @CARRECORD_01
  164.  
  165. :CARRECORD_RECORDING
  166. // Recording Time:
  167. 0085: 15@ = 1@
  168. 005A: 15@ += 2@
  169. 0A8C: write_memory 15@ size 4 value 3@ virtual_protect 1 // recording time
  170. 000A: 15@ += 0x04
  171. 0A97: 14@ = car 0@ struct
  172. // Recording Matrix:
  173. 0085: 13@ = 14@
  174. 000A: 13@ += 0x04 // right x
  175. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  176. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording right x
  177. 000A: 15@ += 0x04
  178. 000A: 13@ += 0x04 // right y
  179. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  180. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording right y
  181. 000A: 15@ += 0x04
  182. 000A: 13@ += 0x04 // right z
  183. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  184. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording right z
  185. 000A: 15@ += 0x04
  186. 000A: 13@ += 0x08 // up x
  187. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  188. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording up x
  189. 000A: 15@ += 0x04
  190. 000A: 13@ += 0x04 // up y
  191. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  192. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording up y
  193. 000A: 15@ += 0x04
  194. 000A: 13@ += 0x04 // up z
  195. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  196. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording up z
  197. 000A: 15@ += 0x04
  198. 000A: 13@ += 0x08 // at x
  199. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  200. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording at x
  201. 000A: 15@ += 0x04
  202. 000A: 13@ += 0x04 // at y
  203. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  204. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording at y
  205. 000A: 15@ += 0x04
  206. 000A: 13@ += 0x04 // at z
  207. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  208. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording at z
  209. 000A: 15@ += 0x04
  210. 000A: 13@ += 0x08 // position x
  211. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  212. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording position x
  213. 000A: 15@ += 0x04
  214. 000A: 13@ += 0x04 // position y
  215. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  216. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording position y
  217. 000A: 15@ += 0x04
  218. 000A: 13@ += 0x04 // position z
  219. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  220. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording position z
  221. 000A: 15@ += 0x04
  222. // Recording Movement Speed:
  223. 0085: 13@ = 14@
  224. 000A: 13@ += 0x70 // x push
  225. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  226. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording x push
  227. 000A: 15@ += 0x04
  228. 000A: 13@ += 0x04 // y push
  229. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  230. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording y push
  231. 000A: 15@ += 0x04
  232. 000A: 13@ += 0x04 // z push
  233. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  234. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording z push
  235. 000A: 15@ += 0x04
  236. // Recording Turn Speed:
  237. 000A: 13@ += 0x04 // x turn speed
  238. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  239. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording x turn speed
  240. 000A: 15@ += 0x04
  241. 000A: 13@ += 0x04 // y turn speed
  242. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  243. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording y turn speed
  244. 000A: 15@ += 0x04
  245. 000A: 13@ += 0x04 // z turn speed
  246. 0A8D: 12@ = read_memory 13@ size 4 virtual_protect 1
  247. 0A8C: write_memory 15@ size 4 value 12@ virtual_protect 1 // recording z turn speed
  248. 000A: 2@ += 0x50
  249.  
  250. :CARRECORD_RECORDING_RETURN
  251. 0AB2: ret 1 2@
  252.  
  253. :CARRECORD_RECORDTOCR
  254. 0AA7: call_function 0x48DF90 num_params 2 pop 2 "wb" "cleo\\carrec.cr" 15@ // FILE *file = CFileMgr::Open("cleo\carrec.cr", "wb");
  255. 0AC7: 13@ = var 14@ offset                                           // float *var_offset = &vars[3];
  256. 0006: 12@ = 0x00
  257.  
  258. :CARRECORD_RECORDTOCR_02
  259. if
  260. 001D:   1@ > 12@
  261. jf @CARRECORD_RECORDTOCR_RETURN
  262. 0085: 11@ = 0@
  263. 005A: 11@ += 12@
  264. 0A8D: 14@ = read_memory 11@ size 4 virtual_protect 1
  265. 0AA5: call 0x48DF30 num_params 3 pop 3 4 13@ 15@                 //     CFileMgr::Write(file, var_offset, 4);
  266. 000A: 12@ += 0x04
  267. jump @CARRECORD_RECORDTOCR_02
  268.  
  269. :CARRECORD_RECORDTOCR_RETURN
  270. 0AA5: call 0x48DEA0 num_params 1 pop 1 15@                          // CFileMgr::Close(file);
  271. 0AB2: ret 0
  272.  
  273. :CARRECORD_READCR
  274. 0AA7: call_function 0x48DF90 num_params 2 pop 2 "rb" "cleo\\carrec.cr" 15@ // file = CFileMgr::Open("cleo\carrec.cr", "rb");
  275. // Get file size to 14@:
  276. 0AA5: call 0x48DEE0 num_params 3 pop 3 2 0 15@                      // CFileMgr::Seek(file, 0, SEEK_END);
  277. 0AA7: call_function 0x652D50 num_params 1 pop 1 15@ 14@              // size = ftell(file);
  278. // Go to beginning of the file:
  279. 0AA5: call 0x48DEE0 num_params 3 pop 3 0 0 15@                      // CFileMgr::Seek(file, 0, SEEK_SET);
  280. // Now start reading:
  281. 0AC8: 13@ = allocate_memory_size 14@
  282. 0006: 12@ = 0x00
  283.  
  284. :CARRECORD_READCR_02
  285. if
  286. 801D:   NOT 12@ > 14@
  287. jf @CARRECORD_READCR_RETURN
  288. 0085: 11@ = 13@
  289. 005A: 11@ += 12@
  290. 0AA5: call 0x48DF50 num_params 3 pop 3 4 11@ 15@                 //     CFileMgr::Read(file, var_offset, 4);
  291. 000A: 12@ += 0x04    
  292. jump @CARRECORD_READCR_02
  293.  
  294. :CARRECORD_READCR_RETURN
  295. 0AA5: call 0x48DEA0 num_params 1 pop 1 15@                          // CFileMgr::Close(file);
  296. 0AB2: ret 2 13@ 14@
  297.  
  298. :CARRECORD_RECORDPLAYBACK
  299. // Check Time:
  300. 0085: 15@ = 1@
  301. 005A: 15@ += 2@
  302. 0A8D: 14@ = read_memory 15@ size 4 virtual_protect 1
  303. 001D:   3@ > 14@
  304. jf @CARRECORD_RECORDPLAYBACK_RETURN
  305.  
  306. :CARRECORD_RECORDPLAYBACK_2
  307. 000A: 2@ += 0x50
  308. 0085: 15@ = 1@
  309. 005A: 15@ += 2@
  310. 0A8D: 14@ = read_memory 15@ size 4 virtual_protect 1
  311. 801D:   NOT 3@ > 14@
  312. jf @CARRECORD_RECORDPLAYBACK_2
  313. 000E: 2@ -= 0x50
  314. 0085: 15@ = 1@
  315. 005A: 15@ += 2@
  316. 000A: 15@ += 0x04
  317. 0A97: 14@ = car 0@ struct
  318. // Playback Matrix:
  319. 0085: 13@ = 14@
  320. 000A: 13@ += 0x04 // right x
  321. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  322. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback right x
  323. 000A: 15@ += 0x04
  324. 000A: 13@ += 0x04 // right y
  325. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  326. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback right y
  327. 000A: 15@ += 0x04
  328. 000A: 13@ += 0x04 // right z
  329. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  330. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback right z
  331. 000A: 15@ += 0x04
  332. 000A: 13@ += 0x08 // up x
  333. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  334. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback up x
  335. 000A: 15@ += 0x04
  336. 000A: 13@ += 0x04 // up y
  337. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  338. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback up y
  339. 000A: 15@ += 0x04
  340. 000A: 13@ += 0x04 // up z
  341. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  342. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback up z
  343. 000A: 15@ += 0x04
  344. 000A: 13@ += 0x08 // at x
  345. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  346. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback at x
  347. 000A: 15@ += 0x04
  348. 000A: 13@ += 0x04 // at y
  349. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  350. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback at y
  351. 000A: 15@ += 0x04
  352. 000A: 13@ += 0x04 // at z
  353. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  354. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback at z
  355. 000A: 15@ += 0x04
  356. 000A: 13@ += 0x08 // position x
  357. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  358. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback position x
  359. 000A: 15@ += 0x04
  360. 000A: 13@ += 0x04 // position y
  361. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  362. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback position y
  363. 000A: 15@ += 0x04
  364. 000A: 13@ += 0x04 // position z
  365. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  366. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback position z
  367. 000A: 15@ += 0x04
  368. // Playback Movement Speed:
  369. 0085: 13@ = 14@
  370. 000A: 13@ += 0x70 // x push
  371. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  372. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback x push
  373. 000A: 15@ += 0x04
  374. 000A: 13@ += 0x04 // y push
  375. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  376. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback y push
  377. 000A: 15@ += 0x04
  378. 000A: 13@ += 0x04 // z push
  379. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  380. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback z push
  381. 000A: 15@ += 0x04
  382. // Playback Turn Speed:
  383. 000A: 13@ += 0x04 // x turn speed
  384. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  385. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback x turn speed
  386. 000A: 15@ += 0x04
  387. 000A: 13@ += 0x04 // y turn speed
  388. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  389. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback y turn speed
  390. 000A: 15@ += 0x04
  391. 000A: 13@ += 0x04 // z turn speed
  392. 0A8D: 12@ = read_memory 15@ size 4 virtual_protect 1
  393. 0A8C: write_memory 13@ size 4 value 12@ virtual_protect 1 // playback z turn speed
  394. 000A: 2@ += 0x50
  395.  
  396.  :CARRECORD_RECORDPLAYBACK_RETURN
  397. 0AB2: ret 1 2@

Скрипт пока сырой(пока записывается лишь самое-самое необходимое) и публикую я его потому, что хотел спросить у вас какие-нибудь идеи того, что можно записывать в такой файл помимо уже имеющегося(разумеется, будут добавлены все оставшиеся переменные из формата SA) и при этом не переборщить с нагрузкой.
Перемножать и конвертировать, как в SA, некоторые float для превращения их в INT16 или INT8 мне не охота(мне не лень, просто не очень хочется ставить производительность во главе угла в ущерб точности в года, когда иметь 2х-ядерник - моветон), а вот узнать, почему в SA версии поворот записывается в 6 адресов поворота, а их по-идее 9(насколько я понял), как в Вайсе - мне интересно.
Может, кто-нибудь на этом форуме знает, зачем вообще для поворота объекта 9 адресов?

Ну и вообще интересны ваши мысли и идеи по этому поводу  :)

3
Туториал для "внедрения" своего кода в оригинальный код игры.
Предупреждаю, что я "чайник", в связи с чем могу ошибаться, однако способ проверенно работает!
Спасибо DK за помощь с IDA и Sector за помощь с подменой функции!

Итак, суть проблемы:
Когда Вайс(далее - игра) запущен и загружен, загрузка сохранений происходит без перезагрузки всех ресурсов. Это вызвало проблему в Main Menu Scene, когда мне потребовалось загружать сохранения оригинальной игры, когда по-факту загружены игровые ресурсы "меню". Я решил, что необходимо найти способ перезагрузить ресурсы игры во время загрузки сохранений, подобно тому, как это происходит при старте новой игры.
Копаясь в IDA и проведя несколько часов, тестируя разные догадки, в псевдокоде я обнаружил такой момент:

Когда игра уже запущена и загружает сохранение, она переходит к функциям ShutDownForRestart[1] и InitialiseWhenRestarting[2], которые перезагружают избранные моменты игры("легкая перезагрузка"), но не все ресурсы. В случае, если игра еще не загружена, игра просто загружает все ресурсы при помощи InitialiseGame[4], но потом всё равно переходит на "быструю перезагрузку"[1]. В случае, если игра загружена, но игрок выбрал старт новой игры - та, в свою очередь, полностью выгружает ресурсы при помощи Shutdown[3] и потом снова их загружает[4]. Таким образом, мне требовалось сделать так, чтобы перед "легкой перезагрузкой" происходила полная перезагрузка ресурсов игры, т.е. "внедрить" [3] и [4] перед [1]. Я решил подменить адрес функции [1] на свою функцию, в которой происходит вызов функций [3] и [4], а потом идет переброс обратно на функцию [1]. Чтобы не произошла рекурсия(т.к. функцию [1] я уже подменил на свою), было решено восстановить побайтово старый заголовок функции [1] и только потом делать переброс туда.
Короче, вначале необходимо найти адрес функции: жмем в режиме псевдокода на функцию ShutDownForRestart[1], потом переносимся в IDA View, нажав TAB:

Там дважды жмем ЛКМ на вызове нашей функции, т.е. на _ZN5CGame18ShutDownForRestartEv[5], и попадаем на начало самой функции ShutDownForRestart[6] по адресу 4A47B0:

Таким образом, зная адрес начала функции, мы можем пошалить с ней, а именно - подменить заголовок на переброс к нашей собственной функции. Узнав аналогичным способом адреса функций [3] и [4], переходим к делу.
Объявляем оригинальные функции, которые мы будем потом вызывать, а также адрес подменяемой функции:
Код: C++
  1. auto _GameShutDown = (void (_cdecl*)())0x4A49E0;
  2. auto _GameInitialise = (void (_cdecl*)())0x4A5C40;
  3. auto _GameShutDownForRestart = (void (_cdecl*)())0x4A47B0;
  4. BYTE *GameShutDownForRestartRestore     = (BYTE *)  0x4A47B0;

Создаем методом Sector-а функцию, которая будет подменять оригинальную функцию на нашу:
Код: C++
  1. void injectFunction (DWORD address, DWORD function)
  2. {
  3.         DWORD _old;
  4.         VirtualProtect((LPVOID)address,4,  PAGE_READWRITE, &_old);
  5.         BYTE * patch = (BYTE *)address;
  6.         *patch = 0xE9;    // JMP
  7.         *(DWORD *)(patch+1) = (function-(address+5));    
  8.         VirtualProtect((LPVOID)address,4, _old, &_old);
  9. }

Пишем нашу функцию:
Код: C++
  1. void __stdcall LoadGameShutDown(char key)
  2. {
  3.         _GameShutDown();  
  4.         _GameInitialise();  
  5.         ProtectBYTE(GameShutDownForRestartRestore,0x53);
  6.         ProtectBYTE(GameShutDownForRestartRestore+1,0x55);
  7.         ProtectBYTE(GameShutDownForRestartRestore+2,0x6A);
  8.         ProtectBYTE(GameShutDownForRestartRestore+3,0x00);
  9.         ProtectBYTE(GameShutDownForRestartRestore+4,0xE8);
  10.         _GameShutDownForRestart();
  11. }
Её суть:
Сначала происходит вызов оригинальных функций Shutdown[3] и InitialiseGame[4]. Затем, прежде чем перейти обратно на ShutDownForRestart[1], побайтово восстанавливаются 5 байт оригинальной функции:

Почему именно 5 байт? Дело в том, что injectFunction заменяет именно первые 5 байт на "прыжок" к нашей функции LoadGameShutDown, поэтому нам нужно "подчистить" за собой эти изменения.
После восстановления оригинальной функции и перехода на неё, игра исполняет остальной код в обычном режиме, т.е. после ShutDownForRestart[1] исполняется InitialiseWhenRestarting[2] и так далее.
Ах да - о применении этого(момент самого внедрения): когда потребуется, в вашем коде пропишите
Код: C++
  1. injectFunction((DWORD)GameShutDownForRestartRestore, (DWORD)LoadGameShutDown);
, где GameShutDownForRestartRestore - адрес функции, перед которой нужно внедрить ваш код, а LoadGameShutDown - ваша функция.

4
Моды / Сцена Главного Меню
« : Май 16, 2016, 01:47:59 am »
Бывает - делаешь что-то важное(диплом, например) - а какая-нибудь безумная идея заполняет разум, не давая ничего сделать(прав был Лёнчик). Пару дней назад такой стала для меня идея мини-сценки в главном меню игры, по типу многих современных(и не очень) игр.
Выглядит это примерно так:
! No longer available


Выложил на сайт тестовую версию, там же - сурсы.
В принципе - поскольку делалось это изначально для своей мини-глобалки - я добился желаемого результата, однако идея сделать версию "для всех" стала следующей на очереди безумных идей, а тут возникает несколько проблем(все они прописаны в ридми, но я продублирую с комментариями):
- Меню выбора скина игрока вызывает краш игры. Это происходит потому, что меню использует другой img архив, нежели игра.
Игра подгружает модель игрока до того, как я подменяю img-архив. А после подмены, какие-то оффсеты не совпадают и у игры возникает конфликт на ровном месте. Но тут можно заблочить это меню путем временной переделки кнопки вызова этого меню: чтобы кнопка "Player Skin Setup" вела не в соответствующее меню, а обратно в опции. Но я не знаю нужного адреса памяти.
- "Main Menu Scene" не совместим с плагином "GInput". GInput просто блокирует всё это.
Тут фигня какая-то - не знаю, почему так происходит.
- "Тяжелые" модели коллизии для "Main Menu Scene" вызывают краш при загрузке новой игры. Так что, пожалуйста, не используйте их.
Одна и та же col-модель(даже "тяжелая") может спокойно позволять загружать новую игру снова и снова(простейший пример - та недавняя сборка с каньоном - ссылка в конце сообщения), однако если сунуть таковую в кол меню - новая игра потом не загрузится. Но это мелочь - всё равно в меню желательно использовать максимально простую и "легкую" сцену для быстрой первоначальной загрузки.
Ну, и - на десерт:
- Загрузка сохранений вызывает краш. Это потому, что игра уже "загружена"(для "Main Menu Scene") и новый scm скрипт "Main Menu Scene" не совместим с сохранением. По этой причине, меню загрузки сохранений заблокировано, так что вам придется запускать новую игру, чтобы загрузить сохранение после этого.
Это большая проблема для почти для всех. Не для меня - поскольку в моей мини-глобалке не будет сохранений, но для всех остальных вариант "запускать новую игру, чтобы загрузить сохранение после этого" может оказаться крайне геморройным. Да и мне самому играть в оригинальный Вайс из-за этого становится неудобно.
Это - основная причина создания темы. Можно сделать рандомные сцены, экспериментировать со звуками, пунктами меню и прочими фантазиями, но без решения этой проблемы дальнейшее развитие проекта бесполезно, ибо любые прикольные менюшки не стоят такого геморроя при загрузки сохранений.

Нужно как-то убедить игру, что игра не начата и чтобы при загрузке сохранения игра загружала всё заного, как в случае старта новой игры. Но я понятия не имею, как это сделать(хоть подозреваю, что это возможно).

Есть второй вариант - остановить выполнение scm путем выставления 0x44FEDD на 0(вернуть - 1), и создавать сценки, к примеру, на Lua, НО! Это половина решения, ибо остается аналогичная проблема с картой! Т.е. нужно всё равно найти способ заставить игру перезагрузить всё.
Есть еще вариант - взять предыдущий вариант и просто не использовать новую карту. Но это уныло, и глупо, ибо меню будет загружаться также долго, как и сама игра(скорость загрузки и была изначальной причиной создания своей карты).

Короче - не знаю, что делать... Во вложении дубликат исходника, что идет в комплекте с модом(если кому понадобится глянуть по-быстрому)

P.S. Также - подозреваю, что весь плагин написан через одно место, поэтому буду не против, если кто-нибудь переделает всё основательно. Вообще - это типа "open-source", так что, кто захочет - может сделать и опубликовать новую версию самостоятельно. Надеюсь - в финале мы получим что-то стоящее.

5
Идеи / Видео
« : Август 16, 2015, 03:59:11 am »
Вот задумался: поддержка воспроизведения видео включена в саму игру, значит, в теории, можно запустить mpg видосики по-середине игры, поставив её на паузу. Сразу возникло несколько потрясных идей по использованию этого, но вот знаний для реализации недостаточно.

Если даже не воспроизведение новых видео, то может кто подсказать, как хотя-бы запустить стандартные GTAtitles.mpg и Logo.mpg собственноручно во время игры? В принципе, мне подойдет и C++ код(хотя я надеюсь на вызов какой-нибудь функции через cleo).
Или хотя-бы запуск видео из меню(как выкинуть игру в меню, я, скорее всего, разберусь)

6
В этой теме задаем мелкие вопросы по памяти в Vice City, не подходящие для отдельной темы.

Я начну: Как узнать список адресов, не используемых игрой?(в которые можно записывать значения без проблем в будущем)

7
Идеи / Отражения воды
« : Март 15, 2015, 06:24:56 pm »
В общем, xanser уже работал с водой, так что эта тема по большей части к нему, но вдруг кто еще что-то знает..
В вайсе вода имеет отражения лишь в небольшом радиусе, и это убивает возможность создания "шейдерной водички"(т.е. замены стандартного отражения на реалтаймового) - граница воды с отражением и без находится слишком близко(на расстоянии около 30 игровых метров):
GTA vice city sea look like IV


Собственно, вопрос: как увеличить дальность прорисовки стандартных отражений воды в Vice City? Хотя бы раз в 10 увеличить, тогда шейдерные отражения выглядили бы норм.

8
Моделирование 3D / Бамп и всё такое
« : Март 06, 2015, 04:51:10 am »
Кто-нибудь здесь имеет опыт работы с бампом в Vice City?
Я стал замечать, что оооочень отстал от современного моддинга Вайса.
В ридми проги написан пример использования, но я не очень понял. Кто сможет описать конкретный пример добавления бампа на обычную, например, коробку в Vice City?

9
Справочная информация / Нижний цвет неба
« : Январь 09, 2015, 07:23:28 pm »
Кто-нибудь знает, как сменить цвет нижней половины неба? Той, что тёмно-серая. Может адрес какой есть, чтобы изменять его динамически: его можно было бы тогда сменять на тот же, что и у нижнего края "верхнего" неба(у "верхнего" неба 2 градиента цвета).
P.S. скайбокс(или сферу) не предлагать:)

10
Идеи / Рендер тени в Vice City
« : Апрель 18, 2014, 01:42:17 am »
Создавал подобную тему на sannybuilder.com , но там тему по Вайсу мало кто просматривал. Здесь в основном ковыряют Вайс, поэтому мб это принесет плоды?

Возможно многие заметили, что в катсценах Vice City модели актеров имеют собственные динамические тени(хотя на скрине это не очень хорошо и видно):

Вопрос(очевиден  ;D): возможно ли каким-либо способом "заставить игру подумать", что игровой актер - "катсценовый"? Иначе говоря, возможно ли заменить стандартный рендер теней актеров(педов, если вам так нравится) на динамический? Или просто активировать такой рендер(даже без замены)?

Вот что ответил DK22Pac там же, на sannybuilder.com:
Цитировать
В SA эти тени (HQ тени) включаются, если поставить в настройках высокое качество изображения.
Там эти тени создаются через ту же процедуру, что и LQ тени. Там как-то текстура формируется на основе положения костей педа.
Надо смотерть как именно это происходит.


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

Да, я знаю про Maxo's Vehicle Loader, но и Maxo, как мне кажется - глубоко копнул с созданием собственной тени с блэкджеком и багами. А так можно было бы всё сделать средствами игры.

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

Страницы: [1]