sa-mp-fixes
sa-mp-fixes copied to clipboard
Train carriages IDs when spawning
Solution:
I noticed some time ago that fixes had some useful array related to this problem: validIDs
which will be removed in this commit: https://github.com/Open-GTO/sa-mp-fixes/commit/84bf57f37450850e052f307aed7b5c34143270dd .
My suggestion is to deprecate the ability to spawn trains with the AddStaticVehicle(Ex) (only model IDs 537 and 538, because AFAIK the carriages can be spawned one by one not even on rails - at least this is what I remember from few years ago when I used one of the carriages [model ID 590] for a kind of cannon, players got launched with speed when entering in those "doors"/empty spaces in the middle) functions and add a custom function called "AddTrain
" or "AddStaticTrain
" or something like that. This is how it should look like, as trains don't support angle and colors:
native AddTrain(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, carriages[], maxcarriages = sizeof carriages);
I can't remember how many carriages are spawned with a train, but it should stop the function and print an error if the vector is too small, or print a warning if the vector is too big. The vector should be exactly the correct size (should also provide a definition for the default carriages spawned, maybe FIXES_MAX_CARRIAGES
).
Also, optionally, I just thought about these: Problem: GetPlayerVehicleID, IsPlayerInVehicle: Return 0 if you are in a train or carriage (model IDs 537, 538, 569, 570, 590).
Solution: I didn't test these things at all, only a bit few years ago, trains were bugged as hell and I decided to remove them entirely from my server). Maybe IsPlayerInAnyVehicle
returns 1
if the player is in a train/carriage or GetPlayerState
returns PLAYER_STATE_DRIVER
/PASSENGER
and maybe GetVehiclePos
gets the correct position of the train/carriage ? Fixing these could be CPU intensive, as looping would be required, I guess. Not sure if this is fixable at all if those functions are bugged too. If IsPlayerInAnyVehicle
/GetPlayerState
and GetVehiclePos
work correctly, this include should store all trains/carriages in an array and loop through them when GetPlayerVehicleID
or IsPlayerInVehicle
are called and return 0
but GetPlayerState
or IsPlayerInAnyVehicle
return correctly and check the closest train/carriage, if the player is really close to one of them GetPlayerVehicleID
should return its ID and IsPlayerInVehicle
should return 1
without looping, just checking if the player is really close to that train/carriage ID if the conditions are met.
I think that it would have been better to provide some kind of (pseudo) code, because I think that the explanation wasn't clear enough due to the if if if if conditions, but there are too many cases of possible (not) working functions in trains. It should be tested before by somebody, maybe by me if I will find some time.
EDIT: Totally related:
(YouTube: I'm In Love With The Damn Train - click on image)
Who will fix all these bugs could listen this song on loop for motivation !
I had a completely different experience. I first tried spawning a train, near the track, realized it put it directly on the nearby track and adds 3 wagons. The 3 wagons takes the 3 next IDs than the train, so to avoid problems with ID I only had one train and always kept him as my last vehicle. The rest behaved perfectly. What I like here would be the ability to choose which wagons we plane, maybe mix them. Would ID 590 work? This is interesting.
I only added that validIDs
array as an experiment in a private branch for something about 2 weeks ago - that's a pretty keen eye you've got there to have seen that! It would do what you say though (and is easy to put back in - just revert some commits).
Also, if the number of carriages is consistent (I don't know), you can get the compiler to do the work for you:
native AddTrain(modelid, Float:spawn_x, Float:spawn_y, Float:spawn_z, carriages[3]);
That will check that the function is called correctly, and allows you to use sizeof
within the function should you want to.
I am certain at 100% that when you spawn ID 538, 3 wagons ID 570 spawns and 99% sure that ID 537 does the same with 569. I can control the angle myself, it is stuck to a track, cannot derail. I never tried to spawn wagons, but I used that train for like 7 years and it's just how it works. So we can just make a condition for those 2 ID and fill our array accordingly. rt-2
It won't always be the next IDs, if those are already in use (I suspect).
Well, I saw it because I like this project and I started to watch every commit and every branch. (I really like how you guys are working over this project, you fixed almost everything for probably almost every use case, this is some real dedication from you and ziggi)
Didn't think at the moment of writing about that little compiler trick. That's even better, if the number of carriages is indeed consistent !
Nice info, @rt-2. The include could only check for carriage ID 570 when train ID 538 is spawned and only for carriage ID 569 when train ID 570 is spawned.
Now the only question remaining is if GetPlayerState
/IsPlayerInAnyVehicle
/GetVehiclePos
work correctly while in/for trains and carriages, for the second issue.
Also, I can remember probably not too exactly, from few years ago too, that using DestroyVehicle
on a carriage would bug few things, can't remember exactly what things, but I think it printed some warnings in chat (also when the carriage should be restreamed, when the player entered in the range of that train ?) and bugged the rest carriages of the train. Maybe DestroyVehicle
should also be "fixed" by deprecating its usage on train carriages which are attached on a train, by storing the main train in an array too. If this would be done, I think that GetVehicleTrailer
should be deprecated for trains too (maybe just return 0
?) and add a
native GetTrainCarriages(trainid, carriages[3]);
(that should probably return 0
if it isn't actually a train: model ID 569/570)
EDIT 2: Maybe even a
native DeleteTrainCarriages(trainid);
(same returning case) if it won't cause client warnings or other bugs.
EDIT: I'm almost sure that you are right, they most probably can't be successive IDs, things would be really bugged with two vehicles with the same IDs.
If these things will be fixed too I'll think about integrating these fixes in my C++ gamemode (EDIT: I removed all fixes related to train. By the way, I think that the camera bugs fixes related to trains/carriages entering were still bugged somehow, not sure, can't remember too fine, it was years ago) and test them again, thinking about readding trains in my server. Players were asking about that. Trains offered pretty much fun few years ago in my server. Not sure if I remember correctly, but I could also set their direction by applying SetVehicleZAngle
as GetVehicleZAngle
Z
+ 180.0
.
I guess if the vehicle IDs are used it just skips and go to the next available ones. I always just spawn all vehicle and despawn at save so I don't have some issues. All the functions worked for me except OnPlayerExitVehicle
, the animation is also not played, in fact it is like the player is teleported when he exit. there is some info here that relates: http://wiki.sa-mp.com/wiki/OnPlayerExitVehicle.
Sorry my english aint too good I been debugging all day.
Just tested - GetPlayerVehicleID
is correct in carriages.
Also, there are three carriages, but I can't control them at all. I can't destroy them, I can't spawn separate new ones, except the box car. If anyone else has more luck please tell me. This is my complete testing code:
// This is a comment
// uncomment the line below if you want to write a filterscript
//#define FILTERSCRIPT
#include <a_samp>
#include <a_samp>
#define FIXES_Single 0
//#define FIXES_Debug
#include <sa-mp-fixes\fixes>
#define IsNull(%0) (%0[%0[0]=='\1']=='\0')
new train, trailer;
main()
{
print("\n----------------------------------");
print(" Blank Gamemode by your name here");
print("----------------------------------\n");
new str[20];
printf("%d", IsNull(str));
str = "hi";
printf("%d", IsNull(str));
str = "\1\1\1";
printf("%d", IsNull(str));
str = "\1";
printf("%d", IsNull(str));
str = "Hello";
printf("%d", IsNull(str));
str = "";
printf("%d", IsNull(str));
str = " ";
printf("%d", IsNull(str));
// HideGameTextForPlayer(0, 2);
}
public OnGameModeInit()
{
// Don't use these lines if it's a filterscript
SetGameModeText("Blank Script");
AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
AddPlayerClass(0,2776.1812,1769.5072,10.8203,269.2125,0,0,0,0,0,0); //
AddStaticVehicle(400,2039.7755,1289.1331,10.7642,0.1392,-1,-1); //
AddStaticVehicle(400,2039.7491,1301.1296,10.7658,0.2301,-1,-1); //
AddStaticVehicle(400,2039.7031,1312.7373,10.7644,0.2296,-1,-1); //
AddStaticVehicle(400,2039.6451,1327.2947,10.7642,0.2291,-1,-1); //
AddStaticVehicle(400,2039.6079,1336.4807,10.7642,0.2286,-1,-1); //
AddStaticVehicle(400,2039.5537,1350.1993,10.7642,0.2283,-1,-1); //
AddStaticVehicle(400,2039.4780,1369.2970,10.7642,0.2283,-1,-1); //
AddStaticVehicle(400,2039.4366,1379.7119,10.7642,0.2280,-1,-1); //
AddStaticVehicle(400,2039.3961,1389.9030,10.7642,0.2292,-1,-1); //
AddStaticVehicle(400,2039.3462,1402.4453,10.7642,0.2294,-1,-1); //
AddStaticVehicle(400,2039.2964,1414.8751,10.7642,0.2296,-1,-1); //
AddStaticVehicle(400,2039.2494,1426.6548,10.7642,0.2303,-1,-1); //
AddStaticVehicle(400,2039.1992,1439.1519,10.7642,0.2294,-1,-1); //
AddStaticVehicle(411,2045.1892,1281.8202,10.3990,359.9105,10,-1); //
AddStaticVehicle(411,2045.2081,1294.3406,10.3990,359.9104,10,-1); //
AddStaticVehicle(411,2045.2344,1311.3165,10.3990,359.9104,10,-1); //
AddStaticVehicle(411,2045.2491,1321.0527,10.3990,359.9104,10,-1); //
AddStaticVehicle(411,2045.2805,1341.4132,10.3990,359.9103,10,-1); //
AddStaticVehicle(411,2045.2955,1351.0165,10.3990,359.9103,10,-1); //
AddStaticVehicle(411,2045.3101,1359.9663,10.3990,359.9102,10,-1); //
AddStaticVehicle(411,2045.3239,1369.0702,10.3990,359.9102,10,-1); //
AddStaticVehicle(411,2045.3455,1382.8953,10.3990,359.9102,10,-1); //
AddStaticVehicle(411,2045.3676,1397.0078,10.3990,359.9102,10,-1); //
AddStaticVehicle(411,2045.3964,1415.1661,10.3990,359.9101,10,-1); //
AddStaticVehicle(411,2045.4244,1432.8805,10.3990,359.9101,10,-1); //
AddStaticVehicle(541,2034.2761,1436.6519,10.4453,0.2245,-1,-1); //
AddStaticVehicle(541,2034.3223,1424.9602,10.4460,0.2249,-1,-1); //
AddStaticVehicle(541,2034.3956,1410.7571,10.4422,0.3886,-1,-1); //
AddStaticVehicle(541,2034.4985,1397.0366,10.4460,0.4292,-1,-1); //
AddStaticVehicle(541,2034.5962,1381.3999,10.4429,0.2943,-1,-1); //
AddStaticVehicle(541,2034.6818,1365.3406,10.4460,0.3133,-1,-1); //
AddStaticVehicle(541,2034.7692,1349.4158,10.4460,0.3141,-1,-1); //
AddStaticVehicle(541,2034.8660,1331.7131,10.4460,0.3141,-1,-1); //
AddStaticVehicle(541,2034.9546,1315.5437,10.4460,0.3141,-1,-1); //
AddStaticVehicle(541,2035.0564,1296.9766,10.4460,0.3142,-1,-1); //
AddStaticVehicle(429,2044.5012,1273.6184,10.3516,8.4745,-1,-1); //
AddStaticVehicle(429,2050.7148,1289.2220,10.3516,354.1748,-1,100); //
AddStaticVehicle(429,2050.3994,1297.3622,10.3516,3.9064,-1,100); //
AddStaticVehicle(429,2050.8145,1311.5519,10.3516,358.8593,-1,100); //
AddStaticVehicle(429,2050.9924,1320.5864,10.3516,358.8669,-1,100); //
AddStaticVehicle(429,2051.2146,1331.8392,10.3516,358.8668,-1,100); //
AddStaticVehicle(429,2051.4226,1342.3762,10.3516,358.8668,-1,100); //
AddStaticVehicle(429,2050.5105,1360.3627,10.3516,3.7774,100,-1); //
AddStaticVehicle(429,2051.2524,1382.2150,10.3516,0.3160,100,-1); //
AddStaticVehicle(429,2051.2036,1391.8086,10.3516,0.2919,100,-1); //
AddStaticVehicle(429,2051.1360,1405.1134,10.3516,0.2918,100,-1); //
AddStaticVehicle(429,2051.0579,1420.4298,10.3516,0.2915,100,-1); //
AddStaticVehicle(429,2050.9678,1438.2125,10.3516,0.2912,100,-1); //
train = CreateVehicle(537,2865.3696,1503.1801,10.5091,18.8312,-1,-1, 5000);
train = AddStaticVehicleEx(538,2780.8750,1762.2300,12.3495,0.0000,-1,-1, -1);
printf("Train = %d", train); //
SetVehicleHealth(train + 1, 0.0);
SetVehicleHealth(train + 2, 0.0);
SetVehicleHealth(train + 3, 0.0);
DestroyVehicle(train + 1);
DestroyVehicle(train + 2);
DestroyVehicle(train + 3);
trailer = AddStaticVehicle(570,2780.8750,1700.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(569,2780.8750,1640.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(590,2780.8750,1580.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(570,2760.8750,1700.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(569,2760.8750,1640.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(590,2760.8750,1580.2300,12.3495,0.0000,-1,-1);
trailer = CreateVehicle(570,2790.8750,1700.2300,12.3495,0.0000,-1,-1, 1000);
trailer = CreateVehicle(569,2790.8750,1640.2300,12.3495,0.0000,-1,-1, 1000);
trailer = CreateVehicle(590,2790.8750,1580.2300,12.3495,0.0000,-1,-1, 1000);
return 1;
}
public OnGameModeExit()
{
return 1;
}
public OnPlayerRequestClass(playerid, classid)
{
GameTextForPlayer(playerid, "Hello There", 20000, 0);
SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
return 1;
}
public OnPlayerConnect(playerid)
{
return 1;
}
public OnPlayerDisconnect(playerid, reason)
{
return 1;
}
public OnPlayerSpawn(playerid)
{
return 1;
}
public OnPlayerDeath(playerid, killerid, reason)
{
return 1;
}
public OnVehicleSpawn(vehicleid)
{
return 1;
}
public OnVehicleDeath(vehicleid, killerid)
{
return 1;
}
public OnPlayerText(playerid, text[])
{
return 1;
}
public OnPlayerCommandText(playerid, cmdtext[])
{
if (strcmp("/kill", cmdtext, true, 5) == 0)
{
SetPlayerHealth(playerid, 0.0);
// Do something here
return 1;
}
if (strcmp("/state", cmdtext, true, 6) == 0)
{
printf("vehicleid: %d", GetPlayerVehicleID(playerid));
// Do something here
return 1;
}
if (strcmp("/connect", cmdtext, true, 8) == 0)
{
SetVehicleHealth(train + 1, 0.0);
SetVehicleHealth(train + 2, 0.0);
SetVehicleHealth(train + 3, 0.0);
DestroyVehicle(train + 1);
DestroyVehicle(train + 2);
DestroyVehicle(train + 3);
// AttachTrailerToVehicle(train + 1, train + 0);
// AttachTrailerToVehicle(train + 2, train + 1);
// AttachTrailerToVehicle(train + 3, train + 2);
// Do something here
trailer = AddStaticVehicle(570,2800.8750,1700.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(569,2800.8750,1640.2300,12.3495,0.0000,-1,-1);
trailer = AddStaticVehicle(590,2800.8750,1580.2300,12.3495,0.0000,-1,-1);
trailer = CreateVehicle(570,2810.8750,1700.2300,12.3495,0.0000,-1,-1, 1000);
trailer = CreateVehicle(569,2810.8750,1640.2300,12.3495,0.0000,-1,-1, 1000);
trailer = CreateVehicle(590,2810.8750,1580.2300,12.3495,0.0000,-1,-1, 1000);
return 1;
}
return 0;
}
public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
printf("Enter %d", vehicleid);
// new
// c1,
// c2;
// FIXES_GetVehicleColour(vehicleid, c1, c2);
// printf("c1 = %d, c2 = %d", c1, c2);
// SendClientMessage(playerid, GetVehicleModelRGB(c1), "THIS IS COLOUR 1");
// SendClientMessage(playerid, GetVehicleModelRGB(c2), "THIS IS COLOUR 2");
return 1;
}
public OnPlayerExitVehicle(playerid, vehicleid)
{
printf("Exit %d", vehicleid);
return 1;
}
public OnPlayerStateChange(playerid, newstate, oldstate)
{
printf("State %d %d", newstate, oldstate);
return 1;
}
I think it's just the way it is, trains have forced carriages.
Yes, that probably is the case, but I wonder what happens if you create 1 less than the maximum vehicles, then create a train.
I assume it will miss a carriage,, that really needs to be tested.
The game crashes, and that's just missing one slot for one carriage:
SA-MP 0.3.7
Exception At Address: 0x03AD1C44
Base: 0x03A20000
Registers:
EAX: 0x00000000 EBX: 0x00000000 ECX: 0x00000000 EDX: 0x00000000
ESI: 0x00000000 EDI: 0x00000000 EBP: 0x0028FD8C ESP: 0x0028FD4C
EFLAGS: 0x00010206
Stack:
+0000: 0x0A0610F0 0x00000000 0x03A3B2D7 0x0000001A
+0010: 0xFFFFFFFF 0x03ABDA76 0x0000001A 0xA4B2C6F4
+0020: 0x00000000 0x0A044B00 0x0028FD64 0x0028F78C
+0030: 0x0028FF70 0x03AD5D64 0x03AFA678 0xFFFFFFFF
+0040: 0x756B9F10 0x0053E986 0x00000001 0x00000001
+0050: 0x0000000A 0x0053ECC2 0x00000001 0x00619B71
+0060: 0x0000001A 0x00000001 0x00000001 0x0000000A
+0070: 0x00748DA0 0x0000001A 0x00000001 0x773D8F60
+0080: 0x00000000 0x0028FF80 0x7FFDE000 0x018B0000
+0090: 0x4F24B2BD 0x038B0B00 0x00000008 0x00000100
+00A0: 0x00000008 0x00000102 0x44520000 0x44034000
+00B0: 0x00000000 0x00000000 0x00000690 0x0000041A
+00C0: 0x00000000 0x00000001 0x0011096A 0x00000113
+00D0: 0x00000001 0x00000000 0x09F37143 0x0000039E
+00E0: 0x000003D0 0x0000002C 0x0028FE24 0x00825EA4
+00F0: 0x0028FF70 0x76D74115 0x00000000 0x7FFDE000
+0100: 0x00821D17 0x00821D27 0xFCEE03D6 0x0028FF80
+0110: 0x008246F1 0x00400000 0x00000000 0x017B3973
+0120: 0x0000000A 0x00000094 0x00000006 0x00000002
+0130: 0x000023F0 0x00000002 0x00000000 0x00000000
+0140: 0x00000000 0x00000000 0x00000000 0x00000000
+0150: 0x00000008 0x00000000 0x0018F0F8 0x00208C20
+0160: 0xC0000135 0x0018F2BC 0x0018F168 0x00000000
+0170: 0x00000000 0x00000000 0x00000000 0x0018F2BC
+0180: 0x00000000 0x00000000 0x0000004C 0xC0000135
+0190: 0x77E90DF0 0x001E2284 0x00000000 0x00000000
+01A0: 0x00000000 0x0018F0DC 0x77DD8732 0x77E90720
+01B0: 0x77DD8651 0x00824588 0x00824570 0x00824570
+01C0: 0x7FFDE000 0xC0000005 0x0018F0B4 0x017B3973
+01D0: 0x00000044 0x017BF3C8 0x017BF4E0 0x017C6418
+01E0: 0x00000000 0x00000000 0x00000000 0x00000000
+01F0: 0x00000000 0x00000000 0x00000000 0x00000000
+0200: 0x00000000 0x00000000 0xFFFFFFFF 0xFFFFFFFF
+0210: 0xFFFFFFFF 0x00000000 0x00000000 0x0028FE70
+0220: 0x0028F78C 0x0028FFCC 0x00825EA4 0x00888078
+0230: 0x00000000 0x0028FF94 0x773D7C04 0x7FFDE000
+0240: 0x773D7BE0 0xFD4007C0 0x0028FFDC 0x77DEAB8F
+0250: 0x7FFDE000 0xFDE54774 0x00000000 0x00000000
+0260: 0x7FFDE000 0x00000000 0x00650000 0x006E0072
+0270: 0x006C0065 0xFDE54774 0x0028FFA0 0x004C004C
SCM Op: 0x165, lDbg: 0 LastRendObj: 1656
Game Version: US 1.0
State Information: Ped Context: 0
I think the short answer is: this can't be changed.
If anything, that crash is something to try detect and protect against.
So I think we knoe the paramaters now.
The only thing to keep in mind is that OnPlayerExitVehicle
is not called when someone exits a carriages or the locomotive because the player is simply teleported, no animation.
rt-2
That's easy to fix.
I'm not even sure that would need a fix absolutely,,
Why? Seems pretty annoying to me.
IDK, what's the single player behavior?
Best option is to hook cvehicle::new and store the 3 carriage ids somewhere, now those arent stored anywhere thats the reasonson why you cant delete trains. Ids will be closest vehicle ids. Im thinking about a hook for former mentioned function sometime.
Except we know the IDs - they are displayed correctly from GetPlayerVehicleId and are what are correctly predicted as the next ones after the train ID. Even using those IDs they can't be destroyed though, so I don't see what use hooking CVehicle::New would have over any other hook in terms of using the IDs.
About the exit animation, right now it teleports you a bit behind the door and away from the wagon a bit, might be easier to survive the exit that way, just saying, just had a flash while playing ingame. And the locomotives HAVE the same behaviors as carriages on exit.
Kurta plz, not hooks again (I love the fact that kurta is always suggesting memory hooking, it is pretty funny). The best idea would be just to deny the spawn of a train if there aren't 3 vehicle slots available.
I think that I should make a list with all these bugged things from trains that should be solved, to have a compact list. Right now, I don't even know anymore what needs to be solved. But I have to test every single thing we talked about.
By the way, I don't think that OnPlayerEnterVehicle
and OnPlayerExitVehicle
represent a problem, but maybe calling it under OnPlayerStateChange
would be fine ?
Forgot my post, i havent saw former posts from phone before i wrote that :)
OnPlayerStateChange
will work.
That does work, I also tested it when investigating the IDs, which is why I suggested fixing OnPlayerExitVehicle
- just call the callback from OnPlayerStateChange
.