Duke4.net Forums: MP—What's broken? - Duke4.net Forums

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

MP—What's broken?

User is offline   ThothXV 

#1

Okay, so eduke32 MP has been broken for... jeez. Years. Which is why OldMP is around.

However, I can't find any documentation as to why the MP is in an unworkable state right now. What's actually broken? Does the code buggy, or an actually totally broken WIP mess full of //TODOs? What would it take for us to get it working?
1

User is offline   Mark 

#2

Its being totally rewritten for a modern client/server approach. I don't know the reasons behind why its taking so long. It looks like OldMP has had quite a few upgrades and people here have been using it and having a good time.

This post has been edited by Mark: 24 January 2019 - 02:40 PM

0

User is offline   oasiz 

  • Dr. Effector

#3

Build never had proper MP, it was an outdated p2p approach that introduced other things such as copious amounts of input lag that increased with your latency. Desyncs galore, etc..
Making proper MP for something like this and an engine that is not MP friendly (very extensive scripting & dynamic geometry) is just not that simple.

general lack of coders / time / people crazy enough / etc.. is probably the biggest thing.
2

User is offline   Hendricks266 

  • Weaponized Autism

  #4

View PostThothXV, on 24 January 2019 - 02:30 PM, said:

What would it take for us to get it working?

Wait 6-8 months for IM MP dev to complete.
6

User is offline   ThothXV 

#5

View Postoasiz, on 24 January 2019 - 03:39 PM, said:

Build never had proper MP, it was an outdated p2p approach that introduced other things such as copious amounts of input lag that increased with your latency. Desyncs galore, etc..
Making proper MP for something like this and an engine that is not MP friendly (very extensive scripting & dynamic geometry) is just not that simple.

general lack of coders / time / people crazy enough / etc.. is probably the biggest thing.



Since I AM crazy, where's MP on the source tree? I know originally Build's MP was on the Build side of the Build/Duke divide, but it looks like the new stuff has jumped the gap and is currently in net.cpp/net.h. Just wanna make sure I got that right. It also has licensing implications, as the Build tree is of course under BUILDLIC, and Duke is GPL2 (and thus I don't have to make EXTRA sure I haven't been seen near the Quake sources lately)...

Also... coding convention? Are we 1TBS, K&R, or Allman? Tabs or spaces? I don't wanna muck any of that up.

Sorry for asking so many questions, but while I am a lazy git who promises nothing, if I'm gonna try and do this I wanna do it right.

This post has been edited by ThothXV: 24 January 2019 - 05:47 PM

0

User is offline   necroslut 

#6

View Postoasiz, on 24 January 2019 - 03:39 PM, said:

Build never had proper MP, it was an outdated p2p approach that introduced other things such as copious amounts of input lag that increased with your latency. Desyncs galore, etc..
Making proper MP for something like this and an engine that is not MP friendly (very extensive scripting & dynamic geometry) is just not that simple.

general lack of coders / time / people crazy enough / etc.. is probably the biggest thing.

In my experience it always worked pretty flawlessly over LAN, and JF/ED32 online worked pretty well too if the distance between players wasn't too big.
0

User is offline   Striker 

  • Auramancer

#7

View PostThothXV, on 24 January 2019 - 05:46 PM, said:

Since I AM crazy, where's MP on the source tree? I know originally Build's MP was on the Build side of the Build/Duke divide, but it looks like the new stuff has jumped the gap and is currently in net.cpp/net.h. Just wanna make sure I got that right. It also has licensing implications, as the Build tree is of course under BUILDLIC, and Duke is GPL2 (and thus I don't have to make EXTRA sure I haven't been seen near the Quake sources lately)...

Also... coding convention? Are we 1TBS, K&R, or Allman? Tabs or spaces? I don't wanna muck any of that up.

Sorry for asking so many questions, but while I am a lazy git who promises nothing, if I'm gonna try and do this I wanna do it right.

Most of the C/S netcode is in net.cpp/net.h. Spaces, no tabs. Allman braces.

There's a number of things that need to be done. Handling of sector animation and synchronization (Changes in both the netcode and the game code itself need to be made), handling of allocating player sprites and spawning needs to be rewritten, etc. [IFOC]75 (jwaffe on the forum here) could give you a better run-down of what needs to be done.
2

User is offline   Kyanos 

#8

Might as well ask here, where is the bot ai in current EDuke32?

Also will Ion Maiden have bots?
0

User is offline   jwaffe 

#9

Hi there, I'm 75 AKA Jwaffe,

Take a look at this post I made a while back it's still pretty much up to date as far as the main issues the c/s netcode is facing right now: https://forums.duke4...988#entry309988, since then my work has been merged into mainline, it's no longer on a private repo.

Quote

What's actually broken? Does the code buggy, or an actually totally broken WIP mess full of //TODOs?

- The netcode is functional as in you can launch it and play it, but it's not very stable unfortunately
- The sync code is done in that it can sync pretty much any change in the map except gamevars (I held off on those for now but I have a plan)

Most of the work left relates to integrating that sync code in with the rest of the engine, right now there are significant parts of the engine that I have trouble converting from p2p to c/s. While the netcode is in net.cpp, other files like premap.cpp could use some work (G_EnterLevel, for example)

Here are some of the main issues still present:

- Players joining and leaving mid-game isn't reliable
- Some sector effectors don't work well yet with the c/s netcode
- Animation smoothness can be improved in general, there's some sector movements that aren't interpolated that really should be
- Map transitions don't work most of the time
- Usermaps don't work correctly, I think this problem's related to the map transition problems (i.e., the player sprite code on startup doesn't quite work right in c/s)
- The player position sync code is vulnerable to speedhacking

Quote

What would it take for us to get it working?


- Adjust the startup code / map loading code so that player sprites are allocated in a way that allows midgame joining
- Investigate some of the SEs and find out special cases where the game should ignore some stuff like t_data values that should be interpolated instead of directly synced

Also, if there's any volunteers:

Quote

At this point what would really help is:
- If somebody could help me work with the map loading / startup code because I have had a lot of trouble figuring out how to implement some of the map change / initialization code for the netcode.
- If somebody who is really knowledgeable with Duke3D (somebody who's worked with the Duke3D source for a long time, or perhaps a really good modder) could go through and find more struct fields that should / shouldn't be synced for certain SEs, picnums, etc.


I've been trying to fix the startup code / map change code for a while but nothing I've done seems to have worked; I'm hoping that after IM ships somebody who's worked with that part of the code more can help me figure out what I'm doing wrong.

This post has been edited by jwaffe: 25 January 2019 - 03:04 PM

6

#10

View Postjwaffe, on 25 January 2019 - 02:56 PM, said:

Hi there, I'm 75 AKA Jwaffe,

Take a look at this post I made a while back it's still pretty much up to date as far as the main issues the c/s netcode is facing right now: https://forums.duke4...988#entry309988, since then my work has been merged into mainline, it's no longer on a private repo.


- The netcode is functional as in you can launch it and play it, but it's not very stable unfortunately
- The sync code is done in that it can sync pretty much any change in the map except gamevars (I held off on those for now but I have a plan)

Most of the work left relates to integrating that sync code in with the rest of the engine, right now there are significant parts of the engine that I have trouble converting from p2p to c/s. While the netcode is in net.cpp, other files like premap.cpp could use some work (G_EnterLevel, for example)

Here are some of the main issues still present:

- Players joining and leaving mid-game isn't reliable
- Some sector effectors don't work well yet with the c/s netcode
- Animation smoothness can be improved in general, there's some sector movements that aren't interpolated that really should be
- Map transitions don't work most of the time
- Usermaps don't work correctly, I think this problem's related to the map transition problems (i.e., the player sprite code on startup doesn't quite work right in c/s)
- The player position sync code is vulnerable to speedhacking



- Adjust the startup code / map loading code so that player sprites are allocated in a way that allows midgame joining
- Investigate some of the SEs and find out special cases where the game should ignore some stuff like t_data values that should be interpolated instead of directly synced

Also, if there's any volunteers:


I've been trying to fix the startup code / map change code for a while but nothing I've done seems to have worked; I'm hoping that after IM ships somebody who's worked with that part of the code more can help me figure out what I'm doing wrong.



I was checking out the code for networking to try to fix some of these problems.

The first thing I noticed is that the connectpoint2 list is not cleared correctly. Therefore, disconnected clients are still in the list of frags, etc.
I added the following function to network.c:

void removePlayerFromConnectPoint2(int32_t player)
{
    int32_t i, j = 0;
    for (i = 0; i < g_mostConcurrentPlayers; i++)
    {
        if (connectpoint2[i] == player)
        {
            for (j = i; j < g_mostConcurrentPlayers; j++)
            {
                connectpoint2[j] = connectpoint2[j + 1];
            }
            break;
        }
    }
}


And called it at:
Net_HandleClientPackets() in the case ENET_EVENT_TYPE_DISCONNECT after P_RemovePlayer(playeridx);

Like so:

 case ENET_EVENT_TYPE_DISCONNECT:
            numplayers--;
            ud.multimode--;
            g_mostConcurrentPlayers--; //LITTLETIJN

            P_RemovePlayer(playeridx);
            removePlayerFromConnectPoint2(playeridx); //LITTLETIJN

            g_player[playeridx].revision = cInitialMapStateRevisionNumber;

            packbuf[0] = PACKET_PLAYER_DISCONNECTED;
            packbuf[1] = playeridx;
            packbuf[2] = numplayers;
            packbuf[3] = ud.multimode;
            packbuf[4] = g_mostConcurrentPlayers;
            packbuf[5] = myconnectindex;

            enet_host_broadcast(g_netServer, CHAN_GAMESTATE,
            enet_packet_create(&packbuf[0], 6, ENET_PACKET_FLAG_RELIABLE));

            initprintf("%s disconnected.\n", g_player[playeridx].user_name);
            event.peer->data = NULL;

            Dbg_PacketSent(PACKET_PLAYER_DISCONNECTED);

            break;


It looks like it fixed the frag bar on the server. Now the client. I changed in Net_ParseServerPacket() the case PACKET_PLAYER_DISCONNECTED like:

 case PACKET_PLAYER_DISCONNECTED:
        if ((g_player[myconnectindex].ps->gm & MODE_GAME))
        {
            P_RemovePlayer(pbuf[1]);
        }

        numplayers = pbuf[2];
        ud.multimode = pbuf[3];
        g_mostConcurrentPlayers = pbuf[4];

		removePlayerFromConnectPoint2(pbuf[1]); //LITTLETIJN

        break;


That fixed the frag bar on the client as well as far as I can see.

A question I have, what is stored in g_mostConcurrentPlayers? It looks like it always have the same value as numplayers until someone leaves the server.

What I try to fix next is checking when a player joins it gets the same player spot as the server. Because I noticed than when a client joins, it always spawns on the same spot as the server player. They are somehow connected while it shouldn't be.

Next, when a player disconnects, its player sprite is not removed, only hidden. In P_RemovePlayer() the call to P_QuickKill() only hides it. Is this correct? Or should it really be removed from the list of active sprites? If so, a new call should be made to remove it in the P_RemovePlayer function.

Hopefully this information will help us :lol:.
4

#11

When players connect and disconnect, the frag bar keeps the spots of the disconnected players open. Instead of relying on the playerIndex to set the position in the frag bar I think it is a better idea to use the connectpoint2 array instead. The following code is the change for the frag bar, so when a player leaves, its spot get removed as well.

In sbar.cpp:

void G_DrawFrags(void)
{
    if (ud.statusbarflags & STATUSBAR_NOFRAGBAR)
        return;

    int32_t i, j = 0;
    const int32_t orient = 2+8+16+64;

    for (TRAVERSE_CONNECT(i))
        j++;

    for (i=0; i<=(j>>2); i++)
        rotatesprite_fs(0, (8*i)<<16, 65600, 0, FRAGBAR, 0, 0, orient);

	j = 0;
    for (TRAVERSE_CONNECT(i))
    {
        const DukePlayer_t *ps = g_player[i].ps;
        minitext(21+(73*(j&3)), 2+((j&28)<<1), g_player[i].user_name, ps->palookup, 2+8+16);
        Bsprintf(tempbuf, "%d", ps->frag-ps->fraggedself);
        minitext(17+50+(73*(j&3)), 2+((j&28)<<1), tempbuf, ps->palookup, 2+8+16);
        j++;
    }
}


This post has been edited by Little Tijn: 23 March 2019 - 04:23 AM

1

#12

Guess I forgot a spot where the fragbar height is calculated. Not tested, but I guess this change should work.

int fragbarheight(void)
{
    if (ud.screen_size > 0 && !(ud.statusbarflags & STATUSBAR_NOFRAGBAR)
#ifdef SPLITSCREEN_MOD_HACKS
        && !g_fakeMultiMode
#endif
        && (g_netServer || ud.multimode > 1) && GTFLAGS(GAMETYPE_FRAGBAR))
    {
        int j = 0;

        for (int TRAVERSE_CONNECT(i))
            j++;

        return ((j + 3) >> 2) * tilesiz[FRAGBAR].y;
    }

    return 0;
}


Just the same change from using playerIndex to number of player via length of connectpoint2 array.
0

#13

I see the problem with the player indexes now.

The game is using the following define in macros.h:
TRAVERSE_CONNECT(i)


I trying to make a method to get the lowest available player index and to call it in Net_SyncPlayer() so the new player gets a nice index. Problem is, the TRAVERSE_CONNECT always assumes that the list of player ids in connectpoint2 is in order and that the indexes of connectpoint2 are the same as the player ids. Because of the new way of assigning player ids and the changes to the frag bar, this is not correct anymore.

Now, the solution I see is that the TRAVERSE_CONNECT needs to be modified to walk all player ids in connectpoint2 until -1 is found. I haven't found a good way to do this. If someone has a hint, that would be really nice! :lol:

EDIT: Removed broken code for now.

This post has been edited by Little Tijn: 24 March 2019 - 01:28 AM

0

User is offline   Striker 

  • Auramancer

#14

FYI: g_mostConcurrentPlayers should not be reduced. It's to store the most number of players that have ever been in the server simultaneously, not the number that are currently IN the server.

This post has been edited by Striker: 25 March 2019 - 08:06 AM

0

#15

That's explaining the name of the variable. Although I though it was used for that, I couldn't find the reason to store this information.

About that problem with spawning, I notice that it is likely occuring when loading the snapshot from the server. When I have time, I will check it again.

Btw, I have a git repository available where my changes are at https://github.com/l...tijn/eduke32-mp

Also, how should the flow for connecting go? That I think is:
- When using the command line to connect, store information given in cmdline.cpp
- Start game as usual till S_ClearSoundLocks()
- Start connecting to server (should not block, so we can show a nice "Waiting for connect" screen
- Get the map to load from and load it with G_NewGame(). This will show the loading map screen
- Call G_CollectSpawnPoints so we get the spawn points for the map
- Wait for snapshot and apply it to the current map (Also with "Waiting for snapshot" message)
- Start game with G_EnterLevel()

Connecting from within the game render will allow us to implement connecting via the menu. It is already there, but not in a working state.

The snapshot will modify the spawn point positions, like all the other sprites. This is wanted, because some levels have changing spawn points (Like E2M2).

Is this correct?

Hope that I can help and not bother you with my questions :lol:

This post has been edited by Little Tijn: 25 March 2019 - 12:19 PM

0

User is offline   jwaffe 

#16

Sorry for the late reply, I guess I forgot to click the "watch topic" button, I just noticed this now,

Feel free to keep posting anything else you find, I'm going through what you wrote but it might take me a bit of time. Thanks for the suggestions!
0

User is offline   Striker 

  • Auramancer

#17

View PostLittle Tijn, on 25 March 2019 - 11:23 AM, said:

That's explaining the name of the variable. Although I though it was used for that, I couldn't find the reason to store this information.

About that problem with spawning, I notice that it is likely occuring when loading the snapshot from the server. When I have time, I will check it again.

Btw, I have a git repository available where my changes are at https://github.com/l...tijn/eduke32-mp

Also, how should the flow for connecting go? That I think is:
- When using the command line to connect, store information given in cmdline.cpp
- Start game as usual till S_ClearSoundLocks()
- Start connecting to server (should not block, so we can show a nice "Waiting for connect" screen
- Get the map to load from and load it with G_NewGame(). This will show the loading map screen
- Call G_CollectSpawnPoints so we get the spawn points for the map
- Wait for snapshot and apply it to the current map (Also with "Waiting for snapshot" message)
- Start game with G_EnterLevel()

Connecting from within the game render will allow us to implement connecting via the menu. It is already there, but not in a working state.

The snapshot will modify the spawn point positions, like all the other sprites. This is wanted, because some levels have changing spawn points (Like E2M2).

Is this correct?

Hope that I can help and not bother you with my questions :lol:


Spawn positions are initialized at map start. They only time they should ever move, is if they're moved by certain sector types.
0

#18

View PostStriker, on 25 March 2019 - 07:31 PM, said:

Spawn positions are initialized at map start. They only time they should ever move, is if they're moved by certain sector types.


Like in E2M2. It's correct that they do not change in most levels. But if they move (for instance by a moving sector), the latest snapshot from the server will set them correct. Right? So therefore the coordinates collected from G_CollectSpawnPoints are not always the correct ones. Because the snapshot will modify all changed sprites, including the spawn points, they will get set correct when the client connects while a game with modified points is joined. If the are not changed, they will not be in the snapshot and therefore not be changed at all.

So we use G_CollectSpawnPoints to get the sprites and the start coordinates and later on get and apply the snapshot to modify them when needed.
0

#19

View Postjwaffe, on 25 March 2019 - 04:50 PM, said:

Sorry for the late reply, I guess I forgot to click the "watch topic" button, I just noticed this now,

Feel free to keep posting anything else you find, I'm going through what you wrote but it might take me a bit of time. Thanks for the suggestions!


That's nice to hear! Thanks!

My idea with the change of connectpoint2 is that it is a list of currently connected players in order of connect time.
Maybe a example will explain it:

At first we have the server started without any player, so the array will be:
[-1] (the rest of the indexes are not important)

Then three players connect, and the array looks like this:
[1, 2, 3 ,-1]

When the first and second client disconnect the array will be modified to look like:
[3, -1]

The frag bar will only show the server player (with ID 0) and the player with index 3 next to each other. All the spots that where used by the other players will be cleared.

Next a new client connect, we give it the lowest available ID (that is 1) and add it to the array:
[3, 1, -1]

Now the frag bar will still be in the same order (0 and 3) and the new player will be in the spot of the previous second client.

As far as I see, the order does not matter, as long as the IDs are unique.

The only problem with this I see is that the macro TRAVERSE_CONNECT(i) will loop all the indexes in connectpoint2 by using the player index. The idea I have is that it should loop the indexes in the order set in the array. In the latest example that will be 0, 3, 1.

One thing I do not understand at the moment is that it looks like my modification does work. But if I read the loop in TRAVERSE_CONNECT(i) it shouldn't work. Or does TRAVERSE_CONNECT(i) loop the array correct? Hmm.. Maybe I should check that i variable with a nice breakpoint :lol:

Also, with the change of the connect time I get a nice loading screen for the map, following the message "Waiting for snapshot" and finally the game with the latest snaphot applied. The screen with garbled sprites is no longer. What I noticed is that before this change, the demo's where started and just after that the map get loaded. I think the demo's should not be loaded because we want to connect to the server instead (and by using the command line, we can support multiplayer launchers later on). When a -connect parameter is set, the demo running is skipped, like when using ud.warp_on (but loading the level when we received it from the server) and in the meantime, we should show a nice "waiting for server" screen.

Only when no parameters are given should the demo's be loaded with the default main menu. In this menu there should be a option to join a running game. (The code for this is already available. Maybe add a temporary -netmenu parameter to enable this menu option for testing purposes. When multiplayer is ready, the parameter can be dropped and the main menu should have the multiplayer option with host and join in it.)

Another thingy, when I throw a grenade I sometimes get a thousand explosions instead of a single one. (A grenade?! Yes, I test sometimes with NAM, because I'm a bit silly :lol:). I was wondering, how does the syncing goes? When a player spawns a item (like grenade, pipebomb etc) how does this get communicated to the other clients?

What I though is:
- Client send new actor to server
- Server add it to list of new actors
- Server send new actor to other clients but not the client that made the actor
- Actor is in every game

Then, who decides the lifetime of the item? In other words, when the actor code is executed on what time? Does the server send ticks of it to every client or does every client execute the code associated with the actor? I guess not because it all needs to be in somewhat the same time. Or is time synchronised somehow? And if a actor spawns something (like a explosion) how is that synced? This is something I could not figure out at the moment. Just like hitting a player etc.

This post has been edited by Little Tijn: 25 March 2019 - 11:03 PM

0

User is offline   Striker 

  • Auramancer

#20

View PostLittle Tijn, on 25 March 2019 - 10:14 PM, said:

Like in E2M2. It's correct that they do not change in most levels. But if they move (for instance by a moving sector), the latest snapshot from the server will set them correct. Right? So therefore the coordinates collected from G_CollectSpawnPoints are not always the correct ones. Because the snapshot will modify all changed sprites, including the spawn points, they will get set correct when the client connects while a game with modified points is joined. If the are not changed, they will not be in the snapshot and therefore not be changed at all.

So we use G_CollectSpawnPoints to get the sprites and the start coordinates and later on get and apply the snapshot to modify them when needed.

Do NOT use G_CollectSpawnPoints on the client, AT ALL. Because this will make the client consider other players as spawn points (It treats all existing APLAYER sprites as spawn points, and this would include active players moving around the map). Send the contents of g_playerSpawnPoints and the value of g_playerSpawnCnt to the clients in the initial snapshot, and put a if(g_netClient) return; at the top of G_CollectSpawnPoints.

EDuke32-OldMP also has a refactor to that code that I want to bring to mainline, where it can allocate and de-allocate player sprites on the fly, making this a whole lot easier.

Also, about connectpoint2: You should refer to how it works in EDuke32-OldMP, it does properly remove someone from connectpoint2, while properly updating the linkage of the rest of the clients. (It's a linked list, after all)

This post has been edited by Striker: 26 March 2019 - 11:28 AM

1

User is offline   jwaffe 

#21

Okay, let's see what I can cover from this tonight, I sent you a message on Discord too just so you know who I am on that.

Quote

A question I have, what is stored in g_mostConcurrentPlayers? It looks like it always have the same value as numplayers until someone leaves the server.


g_mostConcurrentPlayers is kind of a carryover from the p2p code that I kinda wanted to remove for a long time because it makes it really hard to handle players that join late to a game. It might be kept in for CON compatibility or something but its original purpose isn't very helpful for c/s multiplayer. If a player in the middle of the list drops out, you can't just go from 0 to g_maxConcurrentPlayers without hitting some players that aren't there, but in the original p2p code you'd be guaranteed to only hit players that are in the game because all players have to join before the game starts.

Quote

What I try to fix next is checking when a player joins it gets the same player spot as the server. Because I noticed than when a client joins, it always spawns on the same spot as the server player. They are somehow connected while it shouldn't be.


What game mode are you running the map in? Are there player starts in the map? With the existing code I've had the client show up in odd places (e.g., getting warped directly to where the server player is standing rather than a real spawn, or at some oddball corner of the map), but it doesn't seem to happen every time.

Really the spawn code needs to be reworked, I had a couple branches where the server sent all clients all of the spawn locations on the map as part of the initial snapshot, I think it might be a good idea for me to add you to my gitlab repo so that I can show you some of my experiments on that; hit me up on Discord.

Quote

Next, when a player disconnects, its player sprite is not removed, only hidden. In P_RemovePlayer() the call to P_QuickKill() only hides it.


In general clients don't really delete or insert sprites, they just hide them or insert them to a temporary "scratch pad" list that's wiped out when a snapshot is received; the server handles sprite deletions and inserts. This is because the only way the client and server can communicate about sprites is through the sprite index, (e.g., the server and client have to agree on what sprite[343] is so it can be synchronized).

I think probably the best route to handling players joining midgame would be to preallocate a range of sprite indexes in the sprite list that are reserved for only players (like Quake does), that way there wouldn't be any disagreement between clients and servers as to what sprite belongs to which player (which has been a challenge in the c/s code to sync for quite a long time). That's been easier said than done though, I haven't had much luck in changing the behavior of the startup code to support that.

Quote

removePlayerFromConnectPoint2


I think your function to remove players from the list is a pretty good idea, but I kinda wonder if we even really need the connectpoint2 array anymore. I vaguely remember that at one point a field was added to the player struct that indicated whether the player was connected or not (something other than playerquitflag), maybe we could just iterate up the player indexes and just check to see if the player is connected?

I really think that field was implemented but I can't seem to find it, I'll have to dig around for that commit

EDIT: I was mixing up something that got added to oldMP, unfortunately the c/s netcode never had the playerdata_t::connected field, though something like that would probably be worth adding

(to be continued)

This post has been edited by jwaffe: 26 March 2019 - 04:27 PM

1

#22

View PostStriker, on 26 March 2019 - 07:42 AM, said:

Do NOT use G_CollectSpawnPoints on the client, AT ALL. Because this will make the client consider other players as spawn points (It treats all existing APLAYER sprites as spawn points, and this would include active players moving around the map). Send the contents of g_playerSpawnPoints and the value of g_playerSpawnCnt to the clients in the initial snapshot, and put a if(g_netClient) return; at the top of G_CollectSpawnPoints.

That might be a better idea. My initial idea was that to get all the spawn points in g_playerSpawnPoints calling G_CollectSpawnPoints before getting a snapshot. Then the snapshot will modify the spawn points as needed. Because calling G_CollectSpawnPoints after loading the map but before getting the snapshot, the other players on the server aren't loaded yet and G_CollectSpawnPoints will collect the correct points only from the static map file. This way we do not need to add specific logic for getting the g_playerSpawnPoints contents from the server.

View PostStriker, on 26 March 2019 - 07:42 AM, said:

EDuke32-OldMP also has a refactor to that code that I want to bring to mainline, where it can allocate and de-allocate player sprites on the fly, making this a whole lot easier.

That's interesting! Will definitely check this out. Maybe this can fix the problem we are having now...

View PostStriker, on 26 March 2019 - 07:42 AM, said:

Also, about connectpoint2: You should refer to how it works in EDuke32-OldMP, it does properly remove someone from connectpoint2, while properly updating the linkage of the rest of the clients. (It's a linked list, after all)

Linkage of the other clients? Not quite sure what you mean with that. Another bit of code to study :blink:. Or do you mean you made it in a linked list instead of the array it is now, (that behaves like a linked list)?


View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

g_mostConcurrentPlayers is kind of a carryover from the p2p code that I kinda wanted to remove for a long time because it makes it really hard to handle players that join late to a game. It might be kept in for CON compatibility or something but its original purpose isn't very helpful for c/s multiplayer. If a player in the middle of the list drops out, you can't just go from 0 to g_maxConcurrentPlayers without hitting some players that aren't there, but in the original p2p code you'd be guaranteed to only hit players that are in the game because all players have to join before the game starts.

That was my idea also. It isn't used for anything anymore. About looping all available players, that TRAVERSE_CONNECT(i) isn't making it easier.


View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

What game mode are you running the map in? Are there player starts in the map? With the existing code I've had the client show up in odd places (e.g., getting warped directly to where the server player is standing rather than a real spawn, or at some oddball corner of the map), but it doesn't seem to happen every time.

I had to with both Co-op and Duke/Grunt Match. I think it happens after getting the latest snapshot from the server.

View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

Really the spawn code needs to be reworked, I had a couple branches where the server sent all clients all of the spawn locations on the map as part of the initial snapshot, I think it might be a good idea for me to add you to my gitlab repo so that I can show you some of my experiments on that; hit me up on Discord.

That will be really nice! Send a message already :lol:

View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

In general clients don't really delete or insert sprites, they just hide them or insert them to a temporary "scratch pad" list that's wiped out when a snapshot is received; the server handles sprite deletions and inserts. This is because the only way the client and server can communicate about sprites is through the sprite index, (e.g., the server and client have to agree on what sprite[343] is so it can be synchronized).

Have found references to this scratch pad and wondered where it was used for. Now I know :lol:. I guess there is still something not completely right with it, like when I get many explosions from a single pipebomb for instance.

View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

I think probably the best route to handling players joining midgame would be to preallocate a range of sprite indexes in the sprite list that are reserved for only players (like Quake does), that way there wouldn't be any disagreement between clients and servers as to what sprite belongs to which player (which has been a challenge in the c/s code to sync for quite a long time). That's been easier said than done though, I haven't had much luck in changing the behavior of the startup code to support that.

That's going to be a challenge for me. Hopefully the code in Eduke32-oldMP can help in this regard.

View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

I think your function to remove players from the list is a pretty good idea, but I kinda wonder if we even really need the connectpoint2 array anymore. I vaguely remember that at one point a field was added to the player struct that indicated whether the player was connected or not (something other than playerquitflag), maybe we could just iterate up the player indexes and just check to see if the player is connected?

I use it to store the order of the players. So when players connect and disconnect, that the order in the fragbar, etc. isn't dependent on the player index but in the position in this array. Like in my examples. Because we can have situations where player with index 3 is still in the server while 1 and 2 have left before. When a new client connect, it might get index 1 but should be in the fragbar after player with index 3. The connectpoint2 array stores this order (like [3,1,-1])

View Postjwaffe, on 26 March 2019 - 04:17 PM, said:

I really think that field was implemented but I can't seem to find it, I'll have to dig around for that commit

EDIT: I was mixing up something that got added to oldMP, unfortunately the c/s netcode never had the playerdata_t::connected field, though something like that would probably be worth adding

Something else to borrow from Eduke32-oldMP :huh:

This post has been edited by Little Tijn: 27 March 2019 - 04:30 AM

0

User is offline   Striker 

  • Auramancer

#23

View PostLittle Tijn, on 27 March 2019 - 04:28 AM, said:

Linkage of the other clients? Not quite sure what you mean with that. Another bit of code to study :lol:. Or do you mean you made it in a linked list instead of the array it is now, (that behaves like a linked list)?

None of these. I'm saying that connecthead/connectpoint2 works like a linked list. connectpoint2[i] is the next player index of i. It isn't enough to set connectpoint2[<index of disconnecting player>] to -1, you got to find which player has the index of disconnecting player as their connectpoint2, and set it to the connectpoint2 of the disconnecting player. When someone joins, you'll want to find the first free space in connectpoint2 and link everything back together in order.

Though, you could just avoid this altogether by doing what I do in EDuke32-OldMP: use the .connected member of playerdata_t. If someone disconnects, it's as simple as setting it to 0, and if someone connects, setting it to 1. Then, if you want to find a free player index, all you have to do is
for(int i = 0; i < MAXPLAYERS; i++) if(g_player[i].connected == 0) { do shit }


And instead of TRAVERSE_CONNECT for iterating over active players, do the following:
for(int i = 0; i < MAXPLAYERS; i++) if(g_player[i].connected && g_player[i].ps != NULL) { do shit }


BTW, these are the specific commits for the spawn refactor:

https://gitlab.com/m...f90c88071b53887
https://gitlab.com/m...1951f5913ccc56e
https://gitlab.com/m...464bc34ab4de96c

This post has been edited by Striker: 27 March 2019 - 03:30 PM

0

User is offline   Striker 

  • Auramancer

#24

Just so you know, I've been working hard on refactoring a lot of Duke's startup code, and bits of the C/S netcode to address some major roadblocks to getting this working. I've made some significant headway, but I'm not out of the dark yet.

Either way, I've eliminated TRAVERSE_CONNECT, and I'm well on the way to getting rid of connectpoint2 (coop spy is the only thing left that uses it, I need to fix this). Player sprites are also spawned and deleted on the fly, auto player color selection behavior has been made more robust, there's no technical limitation on how many players can be supported by EDuke32 now, etc. Now, I need to find out why statnums aren't being synched properly (and possibly other bits of sprite data).

This post has been edited by Striker: 17 April 2019 - 10:54 PM

7

User is offline   Master O 

#25

View PostStriker, on 17 April 2019 - 10:00 PM, said:

Just so you know, I've been working hard on refactoring a lot of Duke's startup code, and bits of the C/S netcode to address some major roadblocks to getting this working. I've made some significant headway, but I'm not out of the dark yet.

Either way, I've eliminated TRAVERSE_CONNECT, and I'm well on the way to getting rid of connectpoint2 (coop spy is the only thing left that uses it, I need to fix this). Player sprites are also spawned and deleted on the fly, auto player color selection behavior has been made more robust, there's no technical limitation on how many players can be supported by EDuke32 now, etc. Now, I need to find out why statnums aren't being synched properly (and possibly other bits of sprite data).


Keep up the good work. We all support your efforts.

This post has been edited by Master O: 18 April 2019 - 04:51 AM

0

#26

View PostStriker, on 17 April 2019 - 10:00 PM, said:

Just so you know, I've been working hard on refactoring a lot of Duke's startup code, and bits of the C/S netcode to address some major roadblocks to getting this working. I've made some significant headway, but I'm not out of the dark yet.

Either way, I've eliminated TRAVERSE_CONNECT, and I'm well on the way to getting rid of connectpoint2 (coop spy is the only thing left that uses it, I need to fix this). Player sprites are also spawned and deleted on the fly, auto player color selection behavior has been made more robust, there's no technical limitation on how many players can be supported by EDuke32 now, etc. Now, I need to find out why statnums aren't being synched properly (and possibly other bits of sprite data).


That is great to hear! I was messing with this, but your solution by eliminating TRAVERSE_CONNECT is really nice. Just a little question about this, will the order of the players in the fragbar not change? My latest idea was to make a linked list out of the players, so that when a player disconnects the order of all the other players is kept in the fragbar (but not the position). Also no need for a array that way. But I see that is covered already :lol:

I was a bit busy lately. Hopefully I can spend some time this weekend...

(Also I'm a simple Magento 2 webshop developer by day, so C++ is quite tricky for me :lol:)
0

User is offline   Master O 

#27

View PostHendricks266, on 24 January 2019 - 03:56 PM, said:

Wait 6-8 months for IM MP dev to complete.


Does that mean we get to frag the IM developers online? (in Duke Nukem multiplayer, I mean) :lol:
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic


All copyrights and trademarks not owned by Voidpoint, LLC are the sole property of their respective owners. Play Ion Fury! ;) © Voidpoint, LLC

Enter your sign in name and password


Sign in options