|
|
multiplayer player missile projectile
#434716
12/24/13 18:19
12/24/13 18:19
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
OP
Serious User
|
OP
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
Hey all, I am making a multiplayer co-op shooter. Player movement etc. works well (thanks to the nice lite-c workshop 25 tutorial  ) and I am now trying to get the player projectiles working. While the projectile code work fine on the server+client/host, it is does not work properly on the client. The skills of the projectile are running on the client and sent to the server, which moves the projectile. But the server code does not seems to work (proectile does not move, it is not scaled, flags are not set correctly etc.). The code of projectile is below, thanks for taking the time. dplay_localfunction = 2;
action gun_missile()
{
//on client
if (my.client_id == dplay_id) {
my.WEAPONSELECTED = player.WEAPONSELECTED;
//weapon 1 selected (now only 1 weapon for testing)
my.LIFETIME = 400;
my.DAMAGE = 20;
my.MOVEMENTSPEED = 60;
my.AREAOFEFFECT = 40;
my.EXPLOSIONSIZE = 0.5;
my.GRAVITY = 0;
my.AMBIENTSKILL = 100;
my.SCALESKILL = 0.2;
my.ALPHASKILL = 100;
my.ROTATION_PAN = camera.pan+random(1)-0.5; // face same direction as player
my.ROTATION_TILT = camera.tilt+random(1)-0.5;
//sends info to server
send_skill(my.WEAPONSELECTED,0);
send_skill(my.DAMAGE,0);
send_skill(my.MOVEMENTSPEED,0);
send_skill(my.AREAOFEFFECT,0);
send_skill(my.EXPLOSIONSIZE,0);
send_skill(my.GRAVITY,0);
send_skill(my.ROTATION_PAN,0);
send_skill(my.ROTATION_TILT,0);
send_skill(my.SCALESKILL,0);
send_skill(my.AMBIENTSKILL,0);
if (my.ALPHASKILL != 100) send_skill(my.ALPHASKILL,0);
}
//on server
if (connection & CONNECT_SERVER) {
my.ambient = my.AMBIENTSKILL;
vec_scale(my.scale_x,my.SCALESKILL);
my.pan = my.ROTATION_PAN;
my.tilt = my.ROTATION_TILT;
my.alpha = my.ALPHASKILL;
if (my.WEAPONSELECTED != 1) set(my,BRIGHT | TRANSLUCENT);
}
set(my,FLAG2);
my.group = 3; // runs through all entities with the same group value, group 3 = world & projectiles
my.CREATOR = player;
my.STATE = 1;
my.roll = random(360);
my.GRAVITY_SUM = 0;
while(1)
{
// state 1: flying ///////////////////////////////////////////
if (my.STATE == 1)
{
//on client
if (my.client_id == dplay_id) {
my.LIFETIME -= time_step *4;
my.GRAVITY_SUM -= my.GRAVITY * time_step;
//sends info to server
send_skill(my.LIFETIME,SEND_UNRELIABLE);
send_skill(my.GRAVITY_SUM,SEND_UNRELIABLE);
}
//on server
if (connection & CONNECT_SERVER) {
if (my.LIFETIME <= 0) my.STATE = 2;
c_move(me,vector(my.MOVEMENTSPEED*time_step,0,0),vector(0,0,my.GRAVITY_SUM),IGNORE_MODELS | IGNORE_SPRITES);
if (HIT_TARGET) my.STATE = 2; // go to next state
c_ignore(1,3,0);
if (c_scan(my.x, my.pan, vector(360, 360, my.AREAOFEFFECT), IGNORE_ME | IGNORE_FLAG2 | IGNORE_PASSABLE) > 0) my.STATE = 2; // go to next state
}
}
// state 2: exploding ////////////////////////////////////////
if (my.STATE == 2)
{
//on server
if (connection & CONNECT_SERVER) {
set(me,ZNEAR); // render in front of close objects\
vec_scale(my.scale_x,1+0.8*time_step);
if (my.scale_x > my.EXPLOSIONSIZE) { // explosion finished?
ent_remove(me);
return;
}
}
}
wait(1);
}
}
|
|
|
Re: multiplayer player missile projectile
[Re: Reconnoiter]
#434850
12/28/13 13:47
12/28/13 13:47
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
OP
Serious User
|
OP
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
I think I know what is wrong, but I don't know how to solve it. The problem is probably the following:
action gun_missile()
{
//on client
if (my.client_id == dplay_id) { <- the 'my' is not recognized so the engine ignores the code within the if
my.WEAPONSELECTED = player.WEAPONSELECTED;
....
where the my is not recognized in 'if (my.client_id == dplay_id)'. I don't understand why that the engine does not recognize it though, since it is created only by the player
// state 2: attack ///////////////////////////////////
if (my.STATE == 2)
{
//on client
if (my.client_id == dplay_id) {
...ent_create("MissileEnergy.mdl",vector(camera.x+(40)*cos(camera.tilt)*cos(camera.pan),camera.y+(40)*cos(camera.tilt)*sin(camera.pan),camera.z+(40)*sin(camera.tilt)),gun_missile);
...
and the player is created in such a way that it is unique per user/client (I think so atleast):
function main()
{
...
if (connection & CONNECT_SERVER) { // this instance of the game runs on the server
STRING* title = str_create("Server: ");
str_cat(title,server_ip);
video_window(0,0,0,title);
ent_create("PlayerBot.mdl",vector(0,0,70),player_control);
} else { // otherwise, it runs on a connected client
video_window(0,0,0,player_name);
random_seed(0); // allow random player positions
ent_create("PlayerBot.mdl",vector(50+random(100),50+random(100),70),player_control);
So I tried using 'you' in the first 'if' of the gun_missile code where 'you' should refer to the entity that creates the missile (the player entity of the client):
action gun_missile()
{
//on client
if (you.client_id == dplay_id) {
but this gives me a crash when the projectile is casted by a client (so when not casted by the server+client / host but by someone who joined the server). Replacing the 'my' with 'player' in the first 'if' (like in the code below) does not help cause than obviously the server+client/host player pointer is used and not the client player pointer;
action gun_missile()
{
//on client
if (player.client_id == dplay_id) {
Anyone any ideas what to use instead of (or how to fix) the line 'if (my.client_id == dplay_id)' in the action gun_missile? Thanks for taking the time.
|
|
|
Re: multiplayer player missile projectile
[Re: EpsiloN]
#434976
12/31/13 12:27
12/31/13 12:27
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
OP
Serious User
|
OP
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
Hi Epsilon, Thanks for the tip. I still get an error with 'you' when firing the missile as a client (crash in action gun_missile). And when the server/host fires a missile, my.client_id stays 0.
action gun_missile()
{
//wait for entity to be created
while(my.client_id == 0) {wait(1);}
my.WEAPONSELECTED = you.WEAPONSELECTED;
my.CREATOR = you;
...
Now that I think about it, maybe it is cause the 'server' does not recognize 'you' (since the client than created it through "if (my.client_id == dplay_id):"). But what could I use instead of 'you' pointer?
|
|
|
Re: multiplayer player missile projectile
[Re: Reconnoiter]
#435229
01/04/14 05:16
01/04/14 05:16
|
Joined: Jan 2006
Posts: 968
EpsiloN
User
|
User
Joined: Jan 2006
Posts: 968
|
Dont rely on You pointer. It is changed many times in one frame...Use it only directly after an instruction that modifies it, eg: you = ent_create...you.skill1 =... You can use a temporary pointer to store handles, but the server and client dont share the pointers (and handles) between them. What you can do, if you want to identify each client and use their entities, is to generate an unique ID for each client, synchronized with server and other clients. Then whenever you need a certain player's entity you search for that client ID... I dont know exactly what you are trying to do in your script, so I can be more specific, but I cant read it in depth right now eighter  I'm late for work. Also, dont forget all ent_create are actualy executed on the server,and you can pass pointers if you use functions...
function example()
{
you = ent_create(dummy_mdl, NULLVECTOR , null);
move_dummy(you);
}
function move_dummy( ENTITY* tempyou )
{
me = tempyou;
}
Btw, this would also work on the client, move_dummy will be executed on the client with a pointer to the created entity and ent_create will be executed on the server. I'm using it to start local player movement and interaction.
|
|
|
Re: multiplayer player missile projectile
[Re: EpsiloN]
#435389
01/07/14 08:55
01/07/14 08:55
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
OP
Serious User
|
OP
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
I can't get it working on the client. It works fine on the host/server, but the client is ignoring everything outside of its own action:
function create_gunmissile()
{
you = ent_create("MissileEnergy.mdl",vector(my.x+(40)*cos(my.CAMERA_TILT_DUMMY)*cos(my.pan),my.y+(40)*cos(my.CAMERA_TILT_DUMMY)*sin(my.pan),(my.z+100)+(40)*sin(my.CAMERA_TILT_DUMMY)),gun_missile);
while(!you) {wait(1);} //replacing this loop with e.g. wait(3); does also not work on client
you.pan = my.pan;
you.tilt = my.CAMERA_TILT_DUMMY;
you.WEAPONSELECTED = my.WEAPONSELECTED;
you.CREATOR = my;
}
I also tried replacing you with a custom ENTITY local pointer, but the exact same problem. I also put waits in the action gun_missile itself, but on the client the gun_missile still ignores the above written function.
action gun_missile()
{
////these all do not work on the client
//while(my.client_id == 0) {wait(1);}
// while(my.pan == 0) {wait(1);}
// while (my.client_id != dplay_id) wait(1);
wait(3);
my.LIFETIME = 400;
my.DAMAGE = 20;
my.MOVEMENTSPEED = 60;
my.AREAOFEFFECT = 40;
my.EXPLOSIONSIZE = 0.5;
my.GRAVITY = 0;
my.AMBIENTSKILL = 100;
my.SCALESKILL = 0.2;
my.ALPHASKILL = 100;
my.ambient = my.AMBIENTSKILL; // medium bright
vec_scale(my.scale_x,my.SCALESKILL); // small size
my.alpha = my.ALPHASKILL;
if (my.WEAPONSELECTED != 1) set(my,BRIGHT | TRANSLUCENT);
set(my,FLAG2);
my.group = 3; // runs through all entities with the same group value, group 3 = world & projectiles
my.STATE = 1;
my.roll = random(360);
my.GRAVITY_SUM = 0;
wait(1);
while(1)
{
........
|
|
|
Re: multiplayer player missile projectile
[Re: Reconnoiter]
#435611
01/09/14 16:22
01/09/14 16:22
|
Joined: Jan 2006
Posts: 968
EpsiloN
User
|
User
Joined: Jan 2006
Posts: 968
|
create_gunmissile() has to be called on the client. It'll create the missile on the server... You get a pointer to the created entity (you) so you can modify it. If you need a local client function running, you have to call it on the client! So, in create_gunmissile() you'd call a function wich takes an entity pointer as an argument and assign it to "my" or "me"... This function will run on the client. Now... On the server, gun_missile will be called and assigned to the created entity (wich you created ('requested') on the client) and will run ONLY on the server. The logic here is this: [Client] you = missile_entity - no function running yet, created on server and client, but running only on server as a function run_missile(you) - run a function on the client to steer the missile on client according to received data [Server] gun_missile called and an entity has been created by a client, but gin_missile runs only here, on server! after creation, start moving the missile, perform collision detection and send data about position (and maby velocity) to client And always perform the movement and collision on the server, or you'll have to deal with cheats and trainers. PS.: If its not clear yet, you'd have to read and experiment more with functions in multiplayer. Dont create complicated functions, start with movement on both server and client (without collision) and work your way up to get a working entity. When you get an entity to move both on client and server simultaneously, you can start adding more code. 
|
|
|
Re: multiplayer player missile projectile
[Re: EpsiloN]
#435651
01/10/14 10:26
01/10/14 10:26
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
OP
Serious User
|
OP
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
Thanks for tip. I noticed through adding DEBUG_VAR(my.pan,10); in the gun_missile action that on the client side the pan is correctly, but on the server side the pan stays 0 and the server does the moving. So I added an send_skill with a long wait in gun_missile right before the while loop;
wait(1);
if (my.client_id == dplay_id) send_skill(my.ROTATION_PAN,0);
wait(10);
my.pan = my.ROTATION_PAN;
This seems to do the trick. Apperently, in my previous code I used too short waits. With wait(3); the pan is rotated rarely. Probably use wait(5); than. Anyway thanks for all the help!
Last edited by Reconnoiter; 01/10/14 10:26.
|
|
|
Re: multiplayer player missile projectile
[Re: Reconnoiter]
#435665
01/10/14 13:03
01/10/14 13:03
|
Joined: Apr 2007
Posts: 3,751 Canada
WretchedSid
Expert
|
Expert
Joined: Apr 2007
Posts: 3,751
Canada
|
This is a race condition waiting to happen. And it will happen the second your code has to face the real world and runs outside of your walled development garden.
Shitlord by trade and passion. Graphics programmer at Laminar Research. I write blog posts at feresignum.com
|
|
|
Re: multiplayer player missile projectile
[Re: WretchedSid]
#435709
01/11/14 13:24
01/11/14 13:24
|
Joined: Dec 2011
Posts: 1,823 Netherlands
Reconnoiter
OP
Serious User
|
OP
Serious User
Joined: Dec 2011
Posts: 1,823
Netherlands
|
What is a 'race condition'  ? I assume by that you mean it can give problems on e.g. networks with a high latency cause the wait does not adjust itself. Is that right? And hey my development garden is quite nice actually  . Anyway, I agree is it not perfect. What I don't get why it takes so long in the engine to sent a few variables (except for the part with latency). Maybe I tested it on a crappy network (still need to test it at home), next to that my code is lacking. Could it perhaps be that the missile is created at first only on the client and delayed on the server? (cause I call the function create_gun_missile within "if (my.client_id == dplay_id)" in the player action) ps; if it helps, entrate is default. - edit; I found a few AUMs about multiplayer which I have not yet read, that will probably clarify alot.
Last edited by Reconnoiter; 01/11/14 15:28.
|
|
|
|