Client/Server GKSessions - iphone

I have an application that is set up so that if the user selects the device to be a server it creates a GKSession in server mode, and if it selects cient it create a GKSession in client mode.
Whats happening at the moment is the server is sending out the data fine, which is just a string containing the time of the server.
The problem starts however, when I have one client already connected to the server and I then connect another client .. the problem is: the second connected client connects also to the first client for some reason.
I want to be able to not connect to other clients and just connect to the server. Any help would be great

You've hit the nail on the head:
Strangely enough, GK allows an "any to any" model.
This is a truly impressive achievement, technologically, by Apple
BUT !!! ........it is very important to realise that this is a very unusual option. In networking - for games - you almost always want a "normal" client-server model.
Over some 30 years, a huge amount of science has become established, regarding doing networking using a normal client-server "spoke" model. And indeed, for game programming, 99% of the time you definitely need, and want, a standard client-server "spoke" model.
This bears repeating:
(1) Apple created a highly unusual "peer to peer" mode when they made GK.
(2) That is technologically astounding, but,
(3) this novel P2P technology would not, actually, be used in very typical networking programming for games.
(4) Very confusingly: all the documentation talks about the P2P mode. This is confusing because: if you are new to networking programming, it would make you think that is "normal". In fact, it is very likely you will never use the P2P mode at all, when making real normal games.
To repeat!
If you are new to networking, when you see all the mentions of P2P mode in Apple's doco, it's important to realise that the (amazing) P2P feature is more of a novelty. In fact, for essentially all game networking, you will definitely need normal "everyday" client-server "spoke style" networking.
Just to ne crystal-clear .. it is much, much, much !! easier to do real-life networking using a normal client-server "spoke" model.
The P2P mode is "really clever" and you could definitely spend some time experimenting with it. For instance, it is fine for just "sending chat around" to every device connected.
But again (if you're a new networking programmer) you should realise it is rather a novelty. You will have to program using a normal, everyday, client-server model.
So ......................
given that you are going to program in a normal everyday client-server model.
Your first job becomes, strangely enough, "disabling" the P2P aspect!!!!!
This is easy enough if you know how. Here's precisely how to do it...
sessionMode:GKSessionModeServer .. on the server.
sessionMode:GKSessionModeClient .. on the client.
So, for normal client-server programming, don't use GKSessionModePeer anywhere.
Secondly, don't forget in your clients, simply do not implement didReceiveConnectionRequestFromPeer:
Finally if all that doesn't work! In your clients, in peer:didChangeState:, you need to do this ...
// so this is in the CLIENT...
-(void)session:(GKSession *)session peer:(NSString *)peerID
didChangeState:(GKPeerConnectionState)state
{
switch (state)
{
case GKPeerStateAvailable:
// you have found the server!!
// [session displayNameForPeer:peerID]
self.theServerWeAreConnectedToPeerID = peerID;
// you will definitely need to save that
[session connectToPeer:theServerWeAreConnectedToPeerID
withTimeout:0];
break;
case GKPeerStateConnected:
// MAKE SURE it's our server
// not just some bizarre peers, etc etc.
if ( [theServerWeAreConnectedToPeerID isEqualToString:peerID] )
{
// you are connected - launch your tick or whatever
}
else
{
// completely ignore this!
}
break;
case GKPeerStateDisconnected:
if ( [theServerWeAreConnectedToPeerID isEqualToString:peerID] )
{
// you have been disconnected from the server!!
}
else
{
// weirdly this is telling you that one of your sister
// clients, has been disconnected from the server. IGNORE
}
break;
// GKPeerStateUnavailable .. likely not relevant
case GKPeerStateUnavailable:
// do nothing, ignore
break;
// from the modern doco..
// "The delegate should ignore GKPeerStateConnecting changes
// and implement the session:didReceiveConnectionRequestFromPeer:
// method instead." .. blah blah .. for us that comment only
// applies TO OUR SERVER, NOT here in the client.
case GKPeerStateConnecting:
// do nothing, ignore
break;
}
}
Just to repeat. It is very likely you will want to NOT-use the P2P model: so, all of the above explains "how to DISABLE the P2P stuff."
Once again to repeat for absolute clarity:
GK (surpriginsly) contains a P2P mode. This is technologically amazing. You can, of course, use P2P mode for simple networking problems (notably chat-like problems). In practice, all the typical networking needs of any real game (whether an FPS, sports game, or whatever) must be done in ordinary client-server paradigm. (It would be staggeringly difficult to use P2P mode.)
Thus, it's necessary as a "first step" to know how to "not use" the P2P system in GK -- that is explained above in length.
(If you DO want to use the P2P system - you're all set, go for it !!)
GK is fantastic if you can figure out all the subtleties. With GK and ASIHttpRequest, you can basically do anything between computers at least in a basic way.
This question has hit the nail on the head ........ GK has a (highly unusual) P2P mode, and the documentation focusses on the P2P mode, which can be confusing to newcomers. Again P2P is incredibly clever, but as a rule you do not want the P2P mode. You want a normal clients-with-server spoke model, which is incedibly easier to program. Hope it helps!

Related

One time Internet Connection Check swift

I need to check the internet connection of a user for one time.
I thought of something like Device.isConnectedToTheInternet but I didn't find something similar...
Every solution that if found was like an internet monitor over time, but that's not exactly what I need.
Someone ideas?
Thanks, Boothosh
As Rob Napier mentioned, it looks like the only thing readily available is the NWPathMonitor, which you can use to check the 'connectivity' to a certain location, like www.google.com, or something else that would be relatively trustworthy to be available 24/7, or just the URL you are about to try and use. Here is a short HackingWithSwift tutorial for NWPathMonitor.
I know this isn't exactly your current situation, but in my projects (and a lot of peoples projects) using an API like AlamoFire is pretty common, and has a ton of usefulness for creating GET/PUT/POST/DELETE requests and of course, has a NetworkReachabilityManager which can be used to make a convenient global function for a simple true/false result for 'isConnectedToInternet' like this:
/*
Connectivity
Struct
Utilizes AlamoFire to check for network availability.
isConnectedToInternet should return true in all cases the phone has access (Cellular, No cellular + wifi, Cellular + wifi, wifi)
*/
struct Connectivity {
static let sharedInstance = NetworkReachabilityManager()!
static var isConnectedToInternet:Bool {
let connected = self.sharedInstance.isReachable
return connected
}
}//end Connectivity
See NWPathMonitor().currentPath. It will tell you the current path. This is only occasionally useful, since "connected to the internet" is not a meaningful condition. There is not concrete definition of "the internet." But you can use the NWPath to answer some questions you probably are looking for. The fact that there is an NSPath available does not mean that you can actually connect to something on "the internet." The only way to know that is to send a packet and get a packet back. So if your real question is "can I connect to a specific host," then you're going to need to send packets to that host (and that still won't prove that you can send packets to the host in the future).
All that said, there is a little UI-level usefulness to asking "if I tried to connect, would it certainly fail?" And currentPath can help you answer that. It just can't tell you if it would succeed.

Read from a serial port in Swift 4 using ORSSerialPort

I've been wanting to make an app that sends instructions over serial to my LED controller. For this to work, I need to read what the controller sends back after sending it a command. I found the following function in ORSSerialPort:
func serialPort(_ serialPort: ORSSerialPort, didReceive data: Data) {
// Do things
}
However, is there something like ORSSerialPort.read()?
I don't think ORSSerialPort.read() is a good idea. I know some other serial libraries are written that way, but the only way for that to work is for read() to block (possibly with a timeout) until a byte comes in on the port. Blocking I/O makes it a lot harder to write a good, responsive app, and I want to guide developers using ORSSerialPort away from that approach.
Instead, you should indeed implement serialPort(_:, didReceive:) in your ORSSerialPort delegate. When data is received by the serial port, that method will be called with the received data and you can do whatever you'd like with it.
That said, if your device communicates using a command/response type protocol (ie. every time you send a command, the device sends some response), you ought to look at ORSSerialPort's request/response API. It allows you to explicitly define the format of expected responses to commands, and ORSSerialPort itself will handle asynchronously waiting for, parsing, and validating responses. See the documentation for more info about this part of ORSSerialPort. The library also includes a sample project, RequestResponseDemo, that demonstrates using this API. Both Swift and Objective-C versions are included.
The ORSSerialPort library is popular and generally good. However, I'd found that it didn't work well with TTY serial devices. This was primarily because of its use of IOKit to discover serial ports -- it would only discover physical devices.
This is likely OK in your case but where you want to test your code but don't want to connect to a physical device, it falls over. Good code always needs a testing framwork. So, check out https://github.com/kpishere/POSIXSerialPort for a very simple serial interface API it is just what you need to write and respond to incoming data and also works with physical or virtual devices (as Unix was originally envisoned!).
To your question though, you don't want to call read() directly. You get into understanding whether or not, "is it a blocking read?" Then you get into dealing with threads. Both of the suggested APIs insulate you from that and allow you to think in terms of an event driven model -- this makes for much simpler code.

Showing timer with WebSockets

I have an application (Laravel + MongoDB running on Nginx) where I pull some data from the database and render it on the screen. The application focusses on multiple real life objects. Once an object is turned on (is_on equals to true in the database), the timer on the screen needs to start ticking. Once the object is turned off (is_on equals to false in the database) the clock stops ticking and resets to 0. The format of the clock is HH:MM:SS. So it shows how long the real life object is turned on.
My problem is that I don't really now how to save/implement such timer. When the user request the page, I pull the necessary data from the database. If I also save the timer in the database, you have to make a query every second which is very bad practice.
I remembered something about WebSockets and tried to look into them. I actually managed to build a basic Hello World chat application, but don't really know how to implement this in my project. There is no place for it in the database (because of the queries), so I don't really know where to save that timer on the server. I'm also doubting if WebSockets are the way to go.
So are WebSockets the way to go and if it is, can you guys point me in the right direction on how to implement this? If not, can you advise me what I should do?
Thanks in advance!
From your question:
I understand that the objects you print in the screen are modified by
users in the application, and your aim is to live forward those
modifications to other active client instances of your application.
In that case, as you mention, I would point you to websockets. They are a great way to feed information directly to the client, so the client receives the update signals and modify the interface, with no need of user action.
In order to implement the logic to notify the client, I recommend using a push approach, but this is really depending on what kind of clients you'd like to notify, since the push world is still a bit tricky.
Further readings for this websocket based push implementation:
Question about Push Flags:
Difference between push and urgent flags in TCP
If your client runs in browser or mobile this question is nice to read:
How to send push notification to web browser?
Also html5 websockets:
http://www.websocket.org/aboutwebsocket.html
As a sidenote:
A nice architecture for client-server live communication is based on node.js together with socket.io library offering good performance and not really complex implementation if you know what you do.

Unity - trading card game architecture

I'm trying to develop a TCG(trading card game) in Unity(I'm Unity newbie) and currently stuck on the architecture of the project and the card effects in particular. Coming from web development background for me all the logic and card effects should be on the server but going through some tutorials for Unity I think the logic should be on the client and I should use a simple room-based server to notify for player actions. Is that correct?
To summarize - where the game logic should be(e.g. card effects, rounds etc)? On the client or on the server?
I actually worked on one of the major TCG's out now for iOS/droid, so this is coming from experience. You definitely want all game logic and rules to be on the server. Do not trust your client to be the source of truth for any game outcomes etc. People will be able to hack that by tampering with the data sent back to the server. They don't have to decompile the game to do that, it can be done merely by sniffing the net traffic.
That said, you may end up with some duplicated logic on both client and server, only so that you can enforce game rules and display the outcomes without always hitting the server. However, your server is always the source of truth and the client is just there to accept input and display outcomes.
The general flow was the client would send a message requesting a new game to the server. The server would respond with the cards for each side and the opening move for the first player. Then the client would simply parse each move and display the outcome. On the cards objects we had methods for many of the actions, such as DrainHealth() and BuffAttack(). When called, these methods would trigger things like particle effects and sound fx attached to the card script.
Yeah the effects should be on the client, I assume your game will be turn based right? You might want to take a look at photon then:
https://doc.photonengine.com/en-us/realtime/current/getting-started/realtime-intro
They have a loot of good tutorials about their API and it's well documented :)
Hope that helps you,
good luck

GameKit: sending reliable NSData to other players?

Okay, I managed to create a match between two players. Now I will do a little test about sending data to a player.
I didn't quite get the explanation about NSData. Essentially, what is it? How do I send a, dunno, array to another player?
Apple mentioned data packets could be lost. But there was a "reliable" mode to prevent that. But I couldn't find about such.
Any ideas?
Yes, you have to make your OWN protocol. "making a protocol" is something you do yourself. Something like...Essentially on the server end
// the message arrives and you then do this...
[data getBytes:&getMe length:sizeof(CommsProt)];
whereas on the client end to send messages, you do this...
NSData * data = [NSData dataWithBytes:&sendMe length:sizeof(CommsProt)];
// ...now send that data using GameKit or whatever system you end up with
and you define your protocol - at least the chunks of data - like this:
typedef struct _CommsProt
{
BOOL happyThing;
someThings wotJustHappened;
float happyValue;
float anotherHappyValue;
// etc
}
CommsProt;
If you are new to GK, be aware of this critical tip ...
Client/Server GKSessions
This could also help...
Most effective way to do networking on Mac/iPhone?
Some helpful notes...
(i) "client" and "server" mean nothing. You will be able to send the handbags of information (such as "CommsProt" above) in either direction. If you want to think of, and refer to one, end as a server (particularly if you have a hub-type arrangement), that's fine. But it's only in your head. (By the way, commonly you might use a different data structure in each direction, that's perfectly fine.)
(ii) Regarding sockets. If you get heavily in to networking, you will have to deal with sockets and write your own sockets code. However it is very likely you can choose a networking layer where you never even have to say the word "sockets"! GameKit + Bonjour, for example, completely take care of handling sockets for you, AND that combination takes care of the other incredibly difficult issue which is FINDING one of your client/servers. If you are new I recommend you completely set aside sockets for now, and use a system such as GameKit (or whatever is equivalent on Windows) for your networking layer.
(iii) Indeed AT FIRST just use something incredibly simple like GameKit, while you figure out your protocol and all the other headaches. Later, if necessary you can rewrite the networking layer, or, switch to some other package that you hear about. Happily everything up to the code examples above will be unchanged, only the networking layer will change.
(iv) Regarding WiFi. GameKit and most convenience packages, are completely agnostic to the physical layer: they take care of it for you. GK will work fine however the phones are connected -- bluetooth, ethernet, whatever! Indeed you "won't know" what physical layer is being used. (It's sometimes annoying you can't control this: let it go, users couldn't care less.)