Page 1 of 1

Moving between rooms

Posted: Tue Jul 10, 2007 10:46 am
by Foil
Now I have another problem: one of the functions of my new gametype is a \"teleport\" function, which just moves the player to a different room by resetting the playerobject position-vector to the center of the destination room, and resetting the playerobject roomnumber.

It works perfectly! The player is suddenly in the destination room, just like I wanted. That is, until some point later (usually when flying normally from room to room) when D3 just locks up. No error message, it just dies.

I have been trying to debug this one for hours. Any ideas?

Posted: Tue Jul 10, 2007 12:33 pm
by DCrazy
struct room has an \"objects\" member, which according to room_external.h is the objnum of the first object in the room. If you change the player's roomnum without checking to make sure that the old room's first object index doesn't still point at the player, the game will probably crash when firing On(Server|Client)PlayerChangeSegment.

Posted: Tue Jul 10, 2007 12:52 pm
by Foil
Ah... I was looking at it from the perspective of a player-object keeping track of which room it was in; I didn't even think to look at whether the room-object kept track of which objects were in it. That's probably the issue, thank you!

Posted: Tue Jul 10, 2007 1:09 pm
by Foil
Note:

Which of these do you think would be the likeliest to work?

A. Manually setting the object references in the room structs.

B. Manually calling the OnClientChangeSegment event, and passing it the old and new room references.

I figure B., since I figure it would take care of the changes to the room struct for me... but I'm not sure.

[Edit: this is all on the client side.]

Posted: Tue Jul 10, 2007 9:56 pm
by DCrazy
B will not work because OnClientChangeSegment is a callback, not a mutator. And doing it on the client side only will cause an inconsistency between the client and server and probably lead to an assertion failure when the player next changes rooms.

Re:

Posted: Tue Jul 10, 2007 11:06 pm
by Foil
DCrazy wrote:B will not work because OnClientChangeSegment is a callback, not a mutator.
Yeah, I realized that after I got home today.

Thanks for the info, though! I'm still new at this; my coding background is mostly VB and web stuff, so I'm having to pick up the C/C++ as I go along. :roll:

Posted: Wed Jul 11, 2007 12:10 am
by DCrazy
No worries, man. I was still relatively green when I wrote Elimination. Working with DMFC finally gave me the courage to attempt to wrangle with COM.

Posted: Fri Jul 20, 2007 10:24 am
by Foil
After about a weeks' vacation, I'm getting back to working on this.

I put in some HUD messages as a primitive debugging tool, to see what the room.objects values (and other values) are at different points. After some testing, I can't seem to find any relationship between the room.objects value and the player objnum, so it doesn't seem to be pointing at any player objects. In fact, most of the time, the room.objects value is -1 (which would make sense when there are no objects in the room). I also tried playing around with the player.oldroom value, but still got the crash.

Anyway, since that doesn't seem to be the issue, any more suggestions on where I might look? I think you're right that it's something about the ChangeSegment event when returning to the room I \"teleported\" from, but I'm not sure where to look anymore.

Posted: Fri Jul 20, 2007 10:45 am
by SuperSheep
Heya Foil!

When I wrote Asteroids, I had to create a teleport function for both the warping of the ship from one side of the level to the other and for the hyperspace jump drive. I didn't use Dallas to write the code, I compiled it as a DLL in MSVS however you might be able to glean some useful information from it.

Code: Select all

// Warp player using Hyper Space Jump Drive
void WarpPlayer(int player_handle)
{
	float mult = 800.0f/RAND_HALF;
	msafe_struct mstruct;

	// Determine if player should be killed
	bool bKill=((float)rand()>(RAND_MAX*0.8f));

	// Play appropriate warp sound
	mstruct.objhandle = player_handle;
	mstruct.state     = 1;
	mstruct.index     = (bKill)?Sound_indexes[4]:Sound_indexes[5];
	mstruct.volume    = 1.0f;
	MSafe_CallFunction(MSAFE_SOUND_2D,&mstruct);

	// Set players new position
	MSafe_GetValue(MSAFE_OBJECT_WORLD_POSITION, &mstruct);
	mstruct.pos.x=2000 + mult*((float)rand()-RAND_HALF);
	mstruct.pos.y=mult * ((float)rand()-RAND_HALF);
	mstruct.pos.z=2000 + mult*((float)rand()-RAND_HALF);
	MSafe_CallFunction(MSAFE_OBJECT_WORLD_POSITION, &mstruct);

	// Deform the player
	mstruct.amount   = 0.2f;
	mstruct.lifetime = (bKill)?2.0f:1.0f;
	MSafe_CallFunction(MSAFE_OBJECT_DEFORM,&mstruct);

	// Kill player if dead or shake viewer if player not dead
	if(bKill)
		Obj_Kill(player_handle,OBJECT_HANDLE_NONE,0.0f,-1,0.0f,0.0f);
	else
	{
		mstruct.amount = 40.0f;
		mstruct.scalar = 10.0f;
		MSafe_CallFunction(MSAFE_OBJECT_SHAKE_AREA,&mstruct);
	}
}
I never did get Multiplayer functioning properly but I do think it's possible.

Posted: Fri Jul 20, 2007 12:28 pm
by Foil
Looks like the relevant part of what you're doing is essentially what I'm doing, as well.

My function does the following:

- Uses the ComputeRoomCenter function to get the center of the \"destination\" room
- Resets the player.pos to that spot (it currently leaves the orientation and velocity matrices alone)
- Resets the player.roomnum to that room handle (otherwise you get the \"hall of mirrors\" effect)
- Resets the playerobject.oldroom to the \"source\" room (the one the player was in before the move)

It's in a .dll, MSVS 2005, packaged into a .d3m.

The problem is that the functions works perfectly, once!... but when the player flies back to the \"source\" room, D3 crashes.

Posted: Sat Jul 21, 2007 1:12 am
by SuperSheep
Are you using the same function to set the players position?
Are you initializing the mstruct structure properly?

How about posting a snippet of your code for comparison.

And, this code only transports within the same room so that could be causing the problem. Have you tried teleporting within the same room to see if that crashes as well?

Re:

Posted: Sat Jul 21, 2007 7:22 am
by Floyd
SuperSheep wrote:I never did get Multiplayer functioning properly but I do think it's possible.
sup Sheep :)
it seems to be worked out in the Duel MOD.

Foil, you could also monitor what D3 changes itself when you fly trough a portal. I'd check both the player and both rooms structs. maybe there's something in room structs that keeps record of which objects are inside, which i'm too lazy to look up now ;)

Posted: Sat Jul 21, 2007 10:02 am
by Foil
Here's the function:

Code: Select all

//Will move player to an entry room
void DoClientTeleport(void)
{
	vector vPosition;
	int CurrentRoomNumber;
	int NewRoomNumber;

	CurrentRoomNumber = dObjects[dPlayers[DMFCBase->GetPlayerNum()].objnum].roomnum;

	//Get player team
	int team;
	team = DMFCBase->GetMyTeam();

	//Choose a random entry room from the array
	if(team==RED_TEAM){
		//use red entry rooms
		int randomroomindex = rand() % NumberOfRedEntryRooms; //will be an integer in the range [0,NumberOfRedEntryRooms)
		NewRoomNumber = RedEntryRoomNumber[randomroomindex];
	}
	if(team==BLUE_TEAM){
		//use blue entry rooms
		int randomroomindex = rand() % NumberOfBlueEntryRooms; //will be an integer in the range [0,NumberOfBlueEntryRooms)
		NewRoomNumber = BlueEntryRoomNumber[randomroomindex];
	}

	//Get the coordinates for the center of the room
	DLLComputeRoomCenter(&vPosition,&dRooms[NewRoomNumber]);

	//Set the player's coordinates to that point
	memcpy(&dObjects[dPlayers[DMFCBase->GetPlayerNum()].objnum].pos,&vPosition,sizeof(vector));

	//Set the player's room to that room
	dPlayers[DMFCBase->GetPlayerNum()].oldroom = CurrentRoomNumber;
	dObjects[dPlayers[DMFCBase->GetPlayerNum()].objnum].roomnum = NewRoomNumber;
	
	//Display a HUD message
	DLLAddHUDMessage(TXT_ENTRY);
}
It's called only for clients, when certain conditions are met.

FYI, dPlayers and dObjects are exactly as in the Entropy code, NumberOfRedEntryRooms is the number of possible rooms to teleport to, and RedEntryRooms[] is a 0-based array with room handles - that part works fine, it picks a random \"destination\" room correctly.

In fact, the whole function works correctly the first time.


Floyd, I have done a little experimenting with seeing what the room.objects and player-object.room does when going through a portal... there's nothing useful I've seen so far. Of course, I could be missing something obvious.

(P.S. I know, there are easier ways to handle a couple of those variables... I just want to get this working before I start tweaking it.)

Posted: Sat Jul 21, 2007 11:16 am
by SuperSheep
Now I see why your function is failing. You can not simply set the room number and position in the players structure as D3 does not know that it has changed. You need to move the player using one of the built in functions.

In gamedll_header.h, you will find a huge number of functions. In particular you want the functions for moving an object.

Code: Select all


typedef void( *ObjSetPosNoMark_fp ) (object *objp,vector *newpos,int roomnum,matrix *orient,bool f_update_attached_children);
DMFCDLLOUT(ObjSetPosNoMark_fp DLLObjSetPosNoMark;)

// ObjSetPos, that automatically sets the OF_MOVED_THIS_FRAME
typedef void (*ObjSetPos_fp)(object *obj,vector *pos,int roomnum,matrix *orient,bool f_update_attached_children);
DMFCDLLOUT(ObjSetPos_fp DLLObjSetPos;)

I would write the code to be more usable for any player as well...

Code: Select all

//Will move player to an entry room
void DoClientTeleport(int pnum)
{
  object* obj     = &dObjects[dPlayers[pnum].objnum];
  matrix* orient  = &obj->orient;
  int     newroom = obj->roomnum;
  vector  newpos  = obj->pos;
  int     team    = DMFCBase->GetPlayerTeam(pnum);

  //Choose a random entry room from the array
  if(team == RED_TEAM)
  {
    //use red entry rooms
    newroom = RedEntryRoomNumber[rand() % NumberOfRedEntryRooms];
    DLLComputeRoomCenter(&newpos, &dRooms[newroom]);
  }
  else if(team==BLUE_TEAM)
  {
    //use blue entry rooms
    newroom = BlueEntryRoomNumber(rand() % NumberOfBlueEntryRooms);
    DLLComputeRoomCenter(&newpos, &dRooms[newroom]);
  }

  // Teleport Player
  DLLObjSetPos(obj, &newpos, newroom, &obj->orient, true);
}
This function sets newroom and newpos to the players current room and current position in case they aren't on red or blue team. Simply to protect the function call to setpos.

Posted: Sat Jul 21, 2007 12:07 pm
by Foil
Ah... thanks, SS!

I figured there had to be something not getting moved/re-set properly, I just didn't know what, or how else to move the player. Heck, I had even tried to implement the DALLAS \"FadeAndMovePlayer\" cinematic. :roll:

How I missed the possibility of using that function, I don't know. It should have been obvious:
typedef void (*ObjSetPos_fp)(object *obj,vector *pos,int roomnum,matrix *orient,bool f_update_attached_children);

Posted: Sat Jul 21, 2007 12:46 pm
by Foil
BTW, that works perfectly. :D

Now to round up a teammate or three, and do some more thorough testing!

Posted: Sat Jul 21, 2007 7:30 pm
by SuperSheep
Glad to hear it. :P

You know, Anticheat is still looking for coders willing to take over. :D

Posted: Sat Jul 21, 2007 8:30 pm
by Foil
So I've heard. :wink:

Seriously, lemme finish this first. I'm also dabbling in D3Edit now, gotta make some levels for this new mod of mine.