Hi,

Instead of using MP_EntityCreate() for rockets, lasers, etc. because there is a slight lag with that function(especially noticeable in combat), I use the the MP_SendChatMessage() for these types of entities and effects, which is very effective.

The steps to do this are as follows:

1) On the computer that is firing the weapon:
a) Create the projectile like you would in single player with ent_create().
b) Encode a string with information about the projectile: start position, pan, etc.
c) Send this string to all Players.

2) Once all the other machines receive this string:
a) Decode the string and extract the information from it.
b) Use ent_create() on those machines to create a local version of it on those machines.

Sounds a bit weird, but works very well. MP_SendChatMessage() is very fast over the net. I spend countless hours testing to figure this stuff out with online test, so take my word for it please. Although someone, someday will find a better method because they didn't listen to me.

Here is an example of this method which is very effient for you to deceifer if you want. Lets say we are shooting a projectile from a spaceship.

------------------------------------------------------------------------------

string strCommand = [256];
string strCommand1 = [256];
string strCommand2 = [256];
string strTemp = [256];

// command values for local projectiles
var cmdRecID;
var cmdRecPos[3];
var cmdRecPan[3];

action SpaceShip
{
while(1)
{
.
.
// Key d flag? Shoot weapon
if(my.INPUT_FLAGS & fKeyD)
{
my.INPUT_FLAGS -= fKeyD;

// create projectile in front of ship
vec_for_angle(temp,my.pan);
vec_scale(temp,(my.max_X+35)); // create missile 35 quants in front of ship
vec_add(temp,my.x);

// create projectile locally
you = ent_create(mdlTorpedo,temp,ProjectileFunction);
vec_set(you.pan,my.pan);
you.peer_id = player_id;

// send a command string to create projectile on all other peers/clients
EncodeString(strCommand); // encode creation info into a string
MP_SendChatMessage(strCommand, "ProjectileLocal", MP_ALL_PLAYERS, 0); // send this string to all peers to create
// projectile locally on them

}
.
.
wait(1);
}

// This function sets team and peer_id
// it tracks peer_id & team long enough for them to be set
// and then stops tracking them
function SetTeamPeerID(pEnt)
{
my = pEnt;
//make sure to track the peer_id
MP_TrackSkill(my, MPUC_SKILL_39); //team
MP_TrackSkill(my, MPUC_SKILL_42); //peer
sleep(1);
if(my)
{
MP_IgnoreSkill(my, MPUC_SKILL_39); //team
MP_IgnoreSkill(my, MPUC_SKILL_42); //peer
}
}

//--------------------------------------------------------------------
// CREATE PLAYER - create player at random location
// Ran Locally
//--------------------------------------------------------------------
function CreatePlayer()
{

var temp1[3];

temp1.x =-1000 + random(2000);
temp1.y =-1000 + random(2000);
temp1.z = 0;

// Host?
if(player_team == 1)
{
player = MP_EntityCreate(mdlJFT, vector(temp1.x,temp1.y,temp1.z), "SpaceShip", "");
}
else // Client?
{
player = MP_EntityCreate(mdlFighter, vector(temp1.x,temp1.y,temp1.z), "SpaceShip", "");
}

// track pan, tilt, roll, health on peer that created entity over network
// set peer_id & team on peer that created entity over network
// track pan, tilt and roll
MP_TrackField(player, MPUC_PAN);
MP_TrackField(player, MPUC_TILT);
MP_TrackField(player, MPUC_ROLL);

//make sure to track the health
MP_TrackSkill(player, MPUC_SKILL_1); //health

player.peer_id = player_id;
player.team = player_team;
SetTeamPeerID(player);// set team and peer_id for ship
}


// ProjectileEvent function
// Runs locally on each peer/client
function ProjectileEvent()
{
// projectile hit a entity in level
if(event_type == event_entity)
{
// only do damage to hit entity on the peer that created it
// the peer that created the entity handles transmitting changes
// to that entities skills to the other players, so to keep absolute
// control of damage on all machines, we only want to do
// damage on the machine that created the entity
if(you.peer_id == player_id)
{
you.HEALTH -= my.HEALTH;
}
my.HEALTH = 0;
}

// projectile hit level geometry
if (event_type == event_block)
{
my.HEALTH = 0;
}
}


// ProjectileFunction function
// Runs locally on each Peer/Client
function ProjectileFunction()
{
var distance;

// set events
my.enable_entity = ON;
my.enable_block = ON;
my.event = ProjectileEvent;

// set poly collision stuff
c_setminmax(my);
my.narrow = on;
my.fat = on;
my.polygon = on;

my.FORCE_X = 100*time; // set speed of projectile

my.RANGE = WEAPON_RANGE;

my.push = -1;
my.passable = on; // passable until a certain distance from emntity that created it

my.health = int(random(30))+20; // set random damage of projectile

wait(1); // wait until pan set


// while haven't hit something and range not reached
while(my.HEALTH && distance<my.Range)
{
distance += c_move(my,my.FORCE_X, nullvector, ignore_passable);
// make sure not in ship - not really necessary if projectile creation correct, but left in for reference
if(distance > 10)
{
my.passable = off;
}
wait(1);
}

// hit something instead of reached range limit, so do explosion
if(my.health <= 0)
{
effect(effect_explosion,50,my.X,normal.x); // do explosion effect locally
}

wait(1); // let effect start
ent_remove(my); // remove pprojectile

}

// This function recieves string to decode to create local projectile
function ProjectileLocal(strCommand, playerId, teamId)
{
if ( playerId == player_id || playerId == MP_ALL_PLAYERS)
{
DecodeString(strCommand);
}
}

// This function encodes Projectile creation information into a command string
function EncodeString(strCommand)
{
str_cpy(strCommand,""); // clear command string

// encode owner id
str_for_num(strTemp,player_id);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);

// encode position
str_for_num(strTemp,temp.x);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);

str_for_num(strTemp,temp.y);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);

str_for_num(strTemp,temp.z);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);

// encode pan, tilt, roll
str_for_num(strTemp,my.pan);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);

str_for_num(strTemp,my.tilt);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);

str_for_num(strTemp,my.roll);
str_cat(strTemp,",");
str_cat(strCommand, strTemp);
}

// This function decodes Projectile information from a string
// and then creates this projectile locally on client/peer
function DecodeString(strCommand)
{
var str_pos;
var str_size;
var clip_num;

str_cpy(strCommand1, strCommand);

// Get owner_id for this Projectile
str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecID = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

// Get position for this Projectile
str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecPos.x = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecPos.y = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecPos.z = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

// Get pan, tilt, roll for this Projectile
str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecPan.pan = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecPan.tilt = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

str_cpy(strTemp,strCommand1);
str_pos = str_stri(strTemp,",");
str_size = str_len(strTemp);
clip_num = str_size - str_pos + 1;
str_trunc(strTemp,clip_num);
cmdRecPan.roll = str_to_num(strTemp);
str_clip(strCommand1,str_pos);

// Create this projectile locally on all clients/peers based on decode string
you = ent_create(mdlTorpedo,cmdRecPos,ProjectileFunction);
vec_set(you.pan,cmdRecPan);
you.peer_id = cmdRecID;
}

------------------------------------------------------------------------

Hopes that helps some atleast.

This method is very effient like I said before. In the game I am working on there are missiles, bullets, laser effects, explosions, etc going on all over the place with no lag at all. My encoded strings and decoded string are much more complex than those shown though, I usually include in the strings the projectiles type (rocket, bullet, etc) and then take all the information and create the correct type of entity for that projectile.

Sometimes you have to think a bit outside of the box to get optimal performance with any networking code.

At some point when we get a beta out on a game using a hybrid of Populace done, I will put out some real tutorials, but it will probably be a while unfortuantely.

Loco


Professional A8.30
Spoils of War - East Coast Games