Windows I need help I've been trying to get this working for 5 days!

D

DumbBot

Guest
Hello everyone

I spent my 5 entire days to finish this multiplayer game but I can't get it running. Clients can join and disconnect but the biggest problem is there is no way to return if an object is controlled by a local player or not. So if I try to move my character all the player objects move. I tried to get the local state from the player usernames but that ain't worked. I need some help here.

https://drive.google.com/open?id=0ByOoLxsec-VfNmpnUTlkZG9lQTg - Here is the link for my .GMZ file.

Thanks
 
C

CrazyOmar

Guest
Maybe try to use another object for all the other players? That's what I did when I experimented with clients and servers. Don't know if it's the best solution, though.
 

jo-thijs

Member
Hi and welcome to the GMC!

First of all, don't reply to your own topic so soon after creating it,
a lot of people here only look at topics with 0 replies, because those have not had attention yet.
I almost didn't check this topic for that reason.

Now, skimming through your code, I see something else that needs to be addressed first.
In the script ServerRecievedData, you don't use ds maps the way you think you're using them.
When stroing a value in a map "varMap", you need to do it like this:
Code:
varMap[? index_key] = value;
Without the question mark, you ask GameMaker to not treat the variable as a map, but as an array instead.
GameMaker sees that the variable isn't an array, so it throws away the reference to the map and turns the variable "varMap" to an empty array.

Furthermore, you also don't seem to care for deleting your ds maps.
Maps in GameMaker are not held inside a variable, but are stored in memory and have to be referenced by an identifier.
If you don't destroy the map, it will create a memory leak.

Now, to answer your question.
Every time someone connects to the server, you would assign them a unique identifier.
When creating a player object for them, you would put this identifier in some variable of the player object.
Then, whenever you receive an update from a client, you would recalculate its identifier and search for the appropriate player object to apply the update to.

As identifier, you could use the automatically generated socket identifiers.

@CrazyOmar, that's not the best solution at all.
It's messy and it disallows easy extensions of the game.
 
D

DumbBot

Guest
Hi and welcome to the GMC!

First of all, don't reply to your own topic so soon after creating it,
a lot of people here only look at topics with 0 replies, because those have not had attention yet.
I almost didn't check this topic for that reason.

Now, skimming through your code, I see something else that needs to be addressed first.
In the script ServerRecievedData, you don't use ds maps the way you think you're using them.
When stroing a value in a map "varMap", you need to do it like this:
Code:
varMap[? index_key] = value;
Without the question mark, you ask GameMaker to not treat the variable as a map, but as an array instead.
GameMaker sees that the variable isn't an array, so it throws away the reference to the map and turns the variable "varMap" to an empty array.

Furthermore, you also don't seem to care for deleting your ds maps.
Maps in GameMaker are not held inside a variable, but are stored in memory and have to be referenced by an identifier.
If you don't destroy the map, it will create a memory leak.

Now, to answer your question.
Every time someone connects to the server, you would assign them a unique identifier.
When creating a player object for them, you would put this identifier in some variable of the player object.
Then, whenever you receive an update from a client, you would recalculate its identifier and search for the appropriate player object to apply the update to.

As identifier, you could use the automatically generated socket identifiers.

@CrazyOmar, that's not the best solution at all.
It's messy and it disallows easy extensions of the game.
Thanks for your reply jo-thijs but I don't know how to use automatically generated socket identifiers. Its really easy to identify the difference between the Client and the Server, but hard part is to identify the Client from the Client.

Thanks!
 

Roa

Member
a very simple solution is to immediately upon connection send another packet, that packet should be knowledge by the server, and it should send a unique connection ID, basically just have a counter count up for each new connection. Once the client receives its ID, it can map that to its instance of the player.

when players join, they will also get ids and when the server tells the other clients that someone has joined, you just use a map to map that client's id to the player object he represents.
 

jo-thijs

Member
When the network event is triggered because a client connects to the server,
a socket is automatically created over which communication can happen.
The async_load map will contain the identifier of this socket.
I think
Code:
async_load[? "socket"]
got the id of the socket,
otherwise it could also have been
Code:
async_load[? "id"]
.

Alternatively, you can also do as Roa suggested and manage the identifiers completely yourself.
 

Roa

Member
When the network event is triggered because a client connects to the server,
a socket is automatically created over which communication can happen.
The async_load map will contain the identifier of this socket.
I think
Code:
async_load[? "socket"]
got the id of the socket,
otherwise it could also have been
Code:
async_load[? "id"]
.

Alternatively, you can also do as Roa suggested and manage the identifiers completely yourself.
That only works one way before you have to cough it back up to the clients. There was some way to do it, but its really convoluted and easier just to organize it yourself. Sending a socket to the server, and then getting that socket ID out to other clients is a pain. you have the ID and the socket and they each go in a specific place and return sockets of different devices weather one is the listening server or the client. It's not the most intuitive mess to work with. This is why I have been avoiding making a networking tutorial cause I dont want to seem like an idiot and avoid the work yoyo already has built in, but my word. I can barely keep it straight along everything else.
 
D

DumbBot

Guest
That only works one way before you have to cough it back up to the clients. There was some way to do it, but its really convoluted and easier just to organize it yourself. Sending a socket to the server, and then getting that socket ID out to other clients is a pain. you have the ID and the socket and they each go in a specific place and return sockets of different devices weather one is the listening server or the client. It's not the most intuitive mess to work with. This is why I have been avoiding making a networking tutorial cause I dont want to seem like an idiot and avoid the work yoyo already has built in, but my word. I can barely keep it straight along everything else.
When the network event is triggered because a client connects to the server,
a socket is automatically created over which communication can happen.
The async_load map will contain the identifier of this socket.
I think
Code:
async_load[? "socket"]
got the id of the socket,
otherwise it could also have been
Code:
async_load[? "id"]
.

Alternatively, you can also do as Roa suggested and manage the identifiers completely yourself.
This script is being triggered when someone connects to a game. It could be both server/client objects

Code:
/// Herhangibir Client bağlanırsa veya bağlantıyı kapatırsa aktifleşecek olan script bu. Eğer herhangibir
//Oyunculara bildiri göndermek istiyorsanız kodunuzu bu Script'e ekleyin!

//This is the script that triggers when a client disconnects from the server. So if you want to
//add some notifications for players, add your code to this script!
{
    // Bağlımı bağlanmadımı? (1=bağlı)
    var t = ds_map_find_value(async_load, "type");

    // Get the NEW socket ID, or the socket that's disconnecting
    var sock = ds_map_find_value(async_load, "socket");
   
    // Get the IP that the socket comes from
    var ip = ds_map_find_value(async_load, "ip");
   
    // Connecting?
    if( t==network_type_connect)
    {
        // add client to our list of connected clients
        ds_list_add( socketlist, sock );

        // Create a new player, and pick a random colour for that player       
        var inst = instance_create(64,64, oPlayer);
        inst.image_blend = ColourArray[colourindex];
        colourindex = (colourindex+1) & 15;

        // put this instance into a map, using the socket ID as the lookup
        ds_map_add( Clients, sock, inst );
    }
    else
    {
        // disconnect a CLIENT. First find the player instance using the socket ID as a lookup
        var inst = ds_map_find_value(Clients, sock );
        // Create a disconnecting "PUFF" at the current coords
        instance_create( inst.x, inst.y, oPuff );

                // Delete the socket from out map, and kill the player instance
        ds_map_delete(Clients, sock );
        with(inst) { instance_destroy(); }
       
        // Also delete the socket from our global list of connected clients
        var index = ds_list_find_index( socketlist, sock );
        ds_list_delete(socketlist,index);
    }
}
So there is actually a ds map that actually has Clients and their sockets also their instances in. But I don't know how to use it because this is not
my code. Is it possible to read from a ds map and turn it to a variable like self.islocal?
 
Top