player.Send({'action': 'number', 'num': len(self.players)})
player.playernum = len(self.players)[/code:13ofx2w7]
When a player (client) connects to the server the following code is called:
[code:13ofx2w7] def Connected(self, player, addr):
self.players[player] = True [/code:13ofx2w7]
This adds a reference to the player to the Dictionary. This reference is what is used to send data to the player:
[code:13ofx2w7]def SendToOthers(self, data, player):
for p in self.players:
if p != player:
p.Send(data)[/code:13ofx2w7]
Notice that in the above function, a check is made if the current player connecting is "yourself" and only sends to everybody else. Also note that the player number is not part of any of the sending of data from client to server or vice-versa. The player number is primarily used on the client side to determine which myplayer instance to control.
Also, each time a player disconnects their entry is indeed removed from the list/Dictionary, so the dictionary can never grow out of proportion:
[code:13ofx2w7]def DelPlayer(self, player):
statusText.AppendText("Player dead/disconneted" + str(player.addr) + "\n")
if System.globalvar("listenServer") == 0:
myplayer[player.playernum - 1].SetPosition(deadp.X,deadp.Y)
del self.players[player]
self.SendToOthers({'action': 'dead', 'player': player.playernum},player)[/code:13ofx2w7]
If you wanted
also, wouldn't each client need a unique "ID" so you can send messages directly to certain clients from the server?
You already can send messages to certain clients using the "player" weak reference. It is important to note that an instance of a client connecting to the server is a channel. The channel and player are one and the same. There is no private channel that multiple players exist on. For example, lets say in your game you want "Bob" to chat only with "Jill" instead of flooding the message to all players. When "Bob" sends his chat message to the server, he could tag it with an option that inlcudes "Jills's" name. Then the server would have a function called "Send to Player", which would take the name as input, figure out which player had a class variable name called Jill (for p in players... if p.name == "Jill", p.send...) and only send to that specific player.
2) I couldn't quite work out how channels work. Can we send messages to all players on a channel? And can channel names be strings? Surely its important to ensure that we can send messages to certain groups of clients, but not everyone connected?
Remember that a channel is a player connected to the server. I get what you are asking for though...you want groups of players. You can do this by creating additional dictionaries and adding the "Player" references to those dictionaries. Then when you want, let's say friendly factions/groups to communicate with each other, instead of sending to the "players" dictionary/list you instead send to "Faction1", etc... You could add an additional capability to each client to be able to create a new faction or group or whatever and you could even add some authentication word/string as well. So clients might have to connect with the name of the faction and the code word.
Keep in mind that PodSixNet is client-server architecture... all data must travel through the server. There are no peer to peer channels between different clients. You can however, create "logical" channels, but lets call them groups so it doesn't confuse the issue.
Now that Python support really rocks, I plan on updating the Tuts (sometime in the next couple months.. don't want to make any guarantees and may add in a few extra features to the chat example to describe this.
There are some areas for abuse to look out for:
1. Right now, when a player connects they are a new "myplayer" instance on the client side. They send their player number to the server to update their position. However, there is no check on the server to make sure that the player they are updating is indeed themselves. A simple check to see if their self.playernum (which is only settable by the server) is equal to the "player" the incoming player want to control should solve this.
2. When a player is dead or disconnects they are removed from the dictionary on the server and packets no longer go to that player. However, their character still exists. This could cause a DOS if somebody repeatedly connected/disconnected creating a plethora of players. I can't remember why I didn't delete the player... I believe it threw off the numbering system. For example, lets say that you were player #3 and player #2 got killed. If you deleted the #2 instance of myplayer, I believe the #3 instance now becomes #2. Well, that is a problem because now player #3 doesn't have anybody to control because his instance is now #2. A couple of options: don't use playernumber tied to instances...this solves the problem of controlling the wrong or non-existant instance.. but then how do you control the instance? You need some type of mapping to an instance (for sake of code simplicity, unless I'm missing a better way). The second option is to update everybodies ID's when somebody dies, well actually this would have to happen in all cases since instance numbers change. When somebody disconnects or dies, you could send out an update to all of the players changing their global playernum (and thus which instance they control) and also send out a delete player "X". Some synchronization would need to be done to make sure this happened smoothly. I didn't want to overly complicate the Tut so I went with the simple/naive solution of copying the dead/disconnected instance off the playing board (which is not practical due to the DOS possibility in your MMO case).
Any ideas from Construct gurus (that bothered to read this far on better ideas to control a sprite instance?
Well that is enough of a brain dump for now. Please let me know if you have any questions!