robin_be Geplaatst: 21 juli 2016 Rapport Geplaatst: 21 juli 2016 (bewerkt) Eigen trein types spawnen In deze tutorial ga ik uitleggen hoe je aangepaste trein types kan spawnen. Ben je die 16 voorgedefiniëerde types beu? Zin in verandering? Wil je eindelijk een keer een Freight box in werking zien? Dan is dit de tut voor jou! Benodigdheden CLEO3 of hoger Sannybuilder GTA:SA v1 of v1.01 We maken gebruik van geheugenadressen, waardoor dit hoogstwaarschijnlijk niet zal kloppen voor andere versies SCM-kennis Basiskennis is een vereiste (Basis SCM-scripten: tutorial door @Dutchy3010 & @PatrickW) We zullen ook werken met het geheugen (Werken met geheugen (adressen) in CLEO: tutorial door @Crypteq) Inhoud Voorwoord Inhoud Werking Methode 1 Methode 2 Nog langere types Finito Werking Zoals je (misschien) weet zijn er 16 verschillende trein types in SA (je kan ze zien in sannybuilder help: druk F12 en ga naar SCM documentation > GTA SA > Train types) De samenstellingen van de types zitten in het geheugen van het spel (baseadres 0x8D44F8). Vanaf dit adres zijn er 16 blokken die elk 16 nummers (4 bytes) bevatten (dus elk blok is 64 bytes groot (40h), totaal 1024 bytes). Als het spel een trein spawnt, zal hij kijken vanaf adres 0x8D44F8 + type * 40h. Daar staat het modelid van de eerste wagon. Dan zoekt het spel 4 bytes verder voor de volgende wagon, totdat het volgende nummer een 0 is, dan is de volledige trein gespawnt. Tijdens de testen heb ik gemerkt dat het spel tot 19 wagons kan spawnen, als ik probeer om 20 wagons in één type te steken, crasht het spel als zo een trein spawnt. Merk op dat 19 wagons meer is dan de 16 nummers per blok. Dit betekent dat de laatste 3 wagons eigenlijk al in het volgende treintype zit. Ook interessant om te weten: treinen die willekeurig voorbijkomen hebben geen probleem met aangepaste types, deze laden de modellen zelf. Maar in missies worden enkel de modellen geladen die in de standaard types zitten. Als je hier andere modellen toevoegt, zal je game crashen als die missie een trein probeert te spawnen! Meerdere dezelfde wagentjes toevoegen is echter geen probleem. Opgelet: het is aangeraden om iedere keer terug de waardes op default te zetten nadat je je trein gespawnt hebt. Als de speler namelijk een ander script start (bv andere MPACK) zitten de vorige waarden er nog in en zal de game waarschijnlijk crashen als er een trein spawnt. Het is ook waarschijnlijk niet zo handig voor de speler als er opeens rare treinen spawnen als hij een nieuw spel start. Bij methode 2 zal de game zeker crashen als er een ander script wordt geladen en er een trein spawnt. Methode 1 Nu kunnen we de nummers veranderen in die blokken om zo de types aan te passen. Als je een enkele trein wilt spawnen is het handig om type 15 aan te passen en die te spawnen. Ik raad types 9,14,15 aan omdat die types slechts één wagon hebben. Als je de standaardwaarde dan terug moet zetten, hoef je enkel die ene wagon terug te zetten én de volgende op 0 zetten. Om dit te doen, moeten we dus de nieuwe model ids schrijven naar de correcte geheugenplaatsen. De offset van het basis adres naar type 15 is dus 15 * 64 bytes = 960 (3C0h) 0x8D44F8 + 0x3C0 = 0x8D48B8 0247: load_model #FREIGHT 0247: load_model #FREIFLAT 0247: load_model #FREIBOX 0247: load_model #TRAM 038B: load_requested_models :LOAD 0001: wait 0 00D6: if and 0248: model #FREIGHT available 0248: model #FREIFLAT available 0248: model #FREIBOX available 0248: model #TRAM available 004D: jump_if_false @LOAD 0006: 0@ = 0x8D48B8 // base adres type 15 0A8C: write_memory 0@ size 4 value #FREIGHT vp 0 //car1 000A: 0@ += 4 // 4 bytes verder, volgende wagon 0A8C: write_memory 0@ size 4 value #FREIFLAT vp 0 //car2 000A: 0@ += 4 // 4 bytes verder, volgende wagon 0A8C: write_memory 0@ size 4 value #FREIBOX vp 0 //car3 000A: 0@ += 4 // 4 bytes verder, volgende wagon 0A8C: write_memory 0@ size 4 value #TRAM vp 0 //car4 000A: 0@ += 4 // 4 bytes verder, volgende wagon 0A8C: write_memory 0@ size 4 value 0 vp 0 //car5 // spawn onze trein 06D8: 0@ = create_train_at 2785.3813 1821.3121 10.8203 type 15 direction 1 // type 15! 036A: put_actor $PLAYER_ACTOR in_car 0@ // waardes terugzetten 0006: 0@ = 0x8D48B8 // base adres type 15 0A8C: write_memory 0@ size 4 value #STREAK vp 0 //car1 000A: 0@ += 4 // 4 bytes verder, volgende wagon 0A8C: write_memory 0@ size 4 value 0 vp 0 //car2 0249: release_model #FREIGHT 0249: release_model #FREIFLAT 0249: release_model #FREIBOX 0249: release_model #TRAM Merk op dat we enorm handig gewoon de modellen kunnen schrijven met #FREIGHT enz. Sannybuilder verandert dit automatisch naar het juiste nummer bij compilatie (hier: 537). Methode 2 In plaats van de nummers te veranderen, kunnen we er ook gewoon voor zorgen dat het spel op een andere plaats gaat zoeken naar de types! Met een disassembler kan je in de code van de exe kijken en zoeken waar de waardes die op locatie 0x8D44F8 liggen ingelezen worden. Als we dan zeggen 'kijk niet naar 0x8D44F8, maar zoek op het adres dat wij jou geven', kunnen we op een simpelere manier de waardes veranderen en terugzetten. 0247: load_model #FREIGHT 0247: load_model #FREIFLAT 0247: load_model #FREIBOX 0247: load_model #TRAM 038B: load_requested_models :LOAD 0001: wait 0 00D6: if and 0248: model #FREIGHT available 0248: model #FREIFLAT available 0248: model #FREIBOX available 0248: model #TRAM available 004D: jump_if_false @LOAD jump @OVER :CARRIAGES hex #FREIGHT 00 00 #FREIFLAT 00 00 #FREIBOX 00 00 #TRAM 00 00 00 00 00 00 end :OVER 0AC6: 0@ = label @CARRIAGES offset 0A8C: write_memory 0x6F75D6 size 4 value 0@ vp 0 //006F75D6 add eax, offset unk_8D44F8 0A8C: write_memory 0x6F7B17 size 4 value 0@ vp 0 //006F7B16 add esi, offset unk_8D44F8 0A8C: write_memory 0x6F7D2E size 4 value 0@ vp 0 //006F7D2C add ecx, offset unk_8D44F8 // spawn onze trein 06D8: 0@ = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1 // type 0! 036A: put_actor $PLAYER_ACTOR in_car 0@ // waardes terugzetten 0A8C: write_memory 0x6F75D6 size 4 value 0x8D44F8 vp 0 //006F75D6 add eax, offset unk_8D44F8 0A8C: write_memory 0x6F7B17 size 4 value 0x8D44F8 vp 0 //006F7B16 add esi, offset unk_8D44F8 0A8C: write_memory 0x6F7D2E size 4 value 0x8D44F8 vp 0 //006F7D2C add ecx, offset unk_8D44F8 0249: release_model #FREIGHT 0249: release_model #FREIFLAT 0249: release_model #FREIBOX 0249: release_model #TRAM Met opcode 0AC6 krijgen we het adres van de locatie waar label :CARRIAGES staat. Na die label kom er een hex blok, waardoor die waarden letterlijk in het script komen te staan. Natuurlijk worden eerst de #FREIGHT enzo omgezet in hun nummers. Sannybuilder zet ze om naar een number die 2 bytes neemt. Elke wagon moet 4 bytes zijn dus staan er nog 00 00 achter. Dit is dan de locatie waar wij willen dat het spel kijkt om de wagonnen te spawnen. Dan kunnen we die locatie schrijven op de plaatsen die normaal naar de gewone plaats zou kijken (0x8D44F8). Hierdoor zal het spel dus de modellen van de wagonnen halen uit de bytes die in ons script zit, op de locatie van :CARRIAGES. Hex blok met de standaard waarden: hex 19 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type0 1A 02 00 00 3A 02 00 00 3A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type1 1A 02 00 00 3A 02 00 00 3A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type2 19 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type3 1A 02 00 00 3A 02 00 00 3A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type4 1A 02 00 00 3A 02 00 00 3A 02 00 00 3A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type5 19 02 00 00 39 02 00 00 39 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type6 1A 02 00 00 3A 02 00 00 3A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type7 C1 01 00 00 C1 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type8 C1 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type9 19 02 00 00 39 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type10 1A 02 00 00 3A 02 00 00 3A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type11 19 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 19 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type12 19 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 39 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type13 C1 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type14 1A 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 // type15 end Merk op dat het eerste getal bv 19 02 00 00 is. Dit is omdat het nummer in little-endiannotatie staat. 19 02 00 00 = 0x00000219 = 537 = #FREIGHT Nog langere types Heb je nog niet genoeg met 19 wagonnen? Moet het begin van de trein tegen het einde zitten? Dat kan! (Neen Robin, dat kan niet. Het spel zal crashen omdat je teveel voertuigen zal spawnen) Op het forum van sannybuilder heb ik code gevonden om 2 treinen aan elkaar te koppelen: https://sannybuilder.com/forums/viewtopic.php?id=18 (post #13). Maar: hoe langer je het maakt, hoe trager de trein zal versnellen/vertragen! 06D8: $DEM_TRAIN = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1 06D8: $DEM_TRAIN2 = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1 gosub @ATTACH2 06D8: $DEM_TRAIN2 = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1 gosub @ATTACH2 06D8: $DEM_TRAIN2 = create_train_at 2785.3813 1821.3121 10.8203 type 0 direction 1 gosub @ATTACH2 // nu heb je 4 treinen aan elkaar! :ATTACH2 // https://sannybuilder.com/forums/viewtopic.php?id=18 #13 // https://github.com/multitheftauto/mtasa-blue/blob/9b1fbaf639657a446790469aa6711e11be0d3eee/MTA10/game_sa/CVehicleSA.h#L472 // https://github.com/multitheftauto/mtasa-blue/blob/9b1fbaf639657a446790469aa6711e11be0d3eee/MTA10/game_sa/CVehicleSA.h#L456 // https://github.com/multitheftauto/mtasa-blue/blob/9b1fbaf639657a446790469aa6711e11be0d3eee/MTA10/game_sa/CVehicleSA.h#L306 06DE: 1@ = get_train $DEM_TRAIN last_carriage_handle 0A97: 1@ = car 1@ struct // pointer van laatste wagon van eerste trein 078A: 3@ = get_train $DEM_TRAIN2 carriage 0 handle 0A97: 3@ = car 3@ struct // pointer van eerste wagon van tweede trein // Fix afstand tussen wagons. Omdat de eerste wagon van de tweede train geen voorganger heeft, is de afstand tot de voorganger 0. // Hierdoor zal de eerste wagon van de tweede trein IN de laatste wagon van de eerste trein zitten // dus zullen we die waarde instellen op de afstand van de tweede wagon tot de eerste wagon. // (dit is een incorrecte waarde, als de eerste wagon niet even groot is als de tweede, maar een betere manier dan dit heb ik nog niet gevonden) 078A: 10@ = get_train $DEM_TRAIN2 carriage 1 handle 0A97: 10@ = car 10@ struct // pointer naar tweede wagon van tweede trein 000A: 10@ += 0x5AC // float m_fDistanceToNextCarriage; 0A8D: 10@ = read_memory 10@ size 4 vp 0 // 10@ is nu de afstand van de tweede wagon naar de eerste 0085: 4@ = 3@ // (int) // pointer naar eerste wagon van tweede trein 000A: 4@ += 0x5AC // float m_fDistanceToNextCarriage; 0A8C: write_memory 4@ size 4 value 10@ vp 0 // de afstand van de eerste wagon is nu hetzelfde als de afstand tussen de tweede en de eerste (10@) // De eerste wagon van de tweede trein is de engine. // Als je instapt in een wagon dat geen engine is, kan je de trein niet besturen // Een engine wagon kan geen voorganger hebben dus kan niet aan de laatste wagon van de eerste trein gekoppeld worden. // In de post op het sannybuilder forum wordt dit opgelost door de eerste wagon van de tweede trein te verwijderen en de tweede wagon van de tweede trein aan de laatste wagon van de eerste trein te koppelen. // Maar het kan dus ook opgelost worden door gewoon de flag die zegt dat het een engine is uit te zetten 0085: 4@ = 3@ // (int) // pointer naar eerste wagon van tweede trein 000A: 4@ += 0x5B8 // CTrainFlags trainFlags; 0A8D: 5@ = read_memory 4@ size 1 vp 0 08C0: clear 5@ bit 3 // unsigned char bIsTheChainEngine : 1; // Only the first created train on the chain gets this set to true, others get it set to false. 0A8C: write_memory 4@ size 1 value 5@ vp 0 // Nu kunnen we ze samenkoppelen 0085: 2@ = 1@ // (int) // pointer naar laatste wagon van eerste trein 000A: 2@ += 0x5D4 // CVehicleSAInterface* m_nextCarriage; 0085: 4@ = 3@ // (int) // pointer naar eerste wagon van tweede trein 000A: 4@ += 0x5D0 // CVehicleSAInterface* m_prevCarriage; 0A8C: write_memory 2@ size 4 value 3@ vp 0 0A8C: write_memory 4@ size 4 value 1@ vp 0 return Finito En voila, eigen trein types He, psst! Al eens gedacht wat er zou gebeuren als je een gewone auto in een trein steekt? Probeer het eens Bewerkt: 14 april 2017 door robin_be Reageren
Crypteq Geplaatst: 5 november 2016 Rapport Geplaatst: 5 november 2016 Schandalig van mij dat ik hier helemaal overheen gekeken heb. Mijn grote complimenten voor deze tutorial. Mooi om te zien hoe de onderliggende laag werkt, en hoe je de limieten van het spel kan omzeilen. Geweldig die video! De tutorial heb ik natuurlijk in de Master Tutorial List gezet. KUTGW Reageren
Dutchy3010 Geplaatst: 5 november 2016 Rapport Geplaatst: 5 november 2016 Wow, ik had m ook gemist. Very nice Robin! Reageren
Recommended Posts
Een reactie plaatsen
Je kan nu een reactie plaatsen en pas achteraf registreren. Als je al lid bent, log eerst in om met je eigen account een reactie te plaatsen.