I am wondering how to write a "good" gameserver. I had a few ideas but I never made a server and I don't want to end up in writing brainfuck code.
I know how to handle TCP-Connections and so on but my problem is how do I communicate between server and client.
As example: I write a game like TicTacTow. Now a user clicked on a cell and I want to tell that server. The server should validate whether the user can click on that cell and tell that the client. If the server tells yes; you can click that the client displays this as a "X".
Now my problem: How exactly do I tell the server that I want to click that field. I came across another question here and they ended up in using the command-pattern. But if I understood it right, I would have to create a Command that implements an Interface. I serialize an instance of that command and send it to the server. The server executes the command. But I have to main problems with that:
If the command sets a cell of the tictacto to an X. How do I tell the Server that he has to pass the GameBoard which I need to set the cell to an X to my Invoke-Method of the interface ICommand.
Isn't that extremely unsecure? I mean I could write a command that deletes all my files or stops the server and send it to the server. I don't believe that the Command-Pattern is that nice idea.
So I am searching for something better. I just want to have an easy and extensible architecture for my client and the server. Is there any good pattern?
Oh and another question: Would you use a serializer or would you encode the data yourself?
What gave you the idea to use serialization of objects directly? That would be a very bad thing for a game server as it's slow, can be prone to break (especially if you have a complicated object graph to serialize) and generally is hackish. The solution is to design and implement your own game communication protocol from scratch - fortunately it's easy.
Serialization is largely done in boring business applications and data tiers, where the objective is to easily transfer data, often between heterogeneous systems, which is why XML-based serialization is often used. These requirements do not apply to games.
Note that serializing an object only serializes the data members, it does not serialize methods. So your fears about malicious code being sent down the line are ill-founded.
Anyway, The first rule of server design is to never trust the client - which means the game server needs to maintain a copy of the current game-state in memory and apply the game's rules to each game-move message sent from a client.
From a bird's eye perspective, here is how I'd design your tic-tac-toe system:
Protocol
Because changes to the game state are event-driven and it's turn-based, a protocol based on verbs and arguments works best. I would have the following verbs, on the assumption this is strictly a 2-player game (using 2 clients and a server)
Client-to-Server
JOIN
READY
MOVE (x, y)
QUIT
Server-to-Client
JOINED
ISREADY
MOVED (player, x, y)
DENIED (reason)
LEFTGAME (player)
The client-to-server verbs should be self-explanatory. You'll notice the server-to-client verbs are proxied versions of the original client-to-server messages, with the exception that MOVED contains the ID of the player who moved, and also contains DENIED to inform clients their move was rejected. The LEFTGAME verb is used to signal that the other player has quit.
Server
This is an incomplete psuedo-code implementation of a hypothetical Tic-tac-toe server. The code I have written is concerned only with the network layer of the application, all of the actual logic surrounding tic-tac-toe game rules and moves is contained within the TicTacToeBoard class and is not described here, however it should be trivial to implement.
The server logic happens in a single thread, the logic for demultiplexing incoming messages can be done in a single thread very easily if you use the modern Task/async IO APIs in .NET, otherwise using one-thread-per-remote-connection can be quick and easy way to handle it too (2-player games don't need to worry about scaling - but this won't scale well to hundreds of players, just saying). (The code for handling those remote connections is not detailed here, it is hidden behind the abstract WaitForAndGetConnection, GetLastIncomingMessage, and SendMessage methods).
// Ready-room state
connection1 = WaitForAndGetConnection();
connection2 = WaitForAndGetConnection();
SendMessage( connection1, "JOINED" ); // inform player 1 that another player joined
p1Ready = false, p2Ready = false;
while(message = GetLastIncomingMessage() && !p1Ready && !p2Ready) {
if( message.From == connection1 && message.Verb == "READY" ) p1Ready = true;
if( message.From == connection2 && message.Verb == "READY" ) p2Ready = true;
}
SendMessage( connection1, "ISREADY" ); // inform the players the game has started
SendMessage( connection2, "ISREADY" ); // inform the players the game has started
// Game playing state
TicTacToeBoard board = new TicTacToeBoard(); // this class represents the game state and game rules
p1Move = true; // indicates whose turn it is to move
while(message = GetLastIncomingMessage()) {
if( message.Verb == "MOVE" ) {
if( p1Move && message.From == connection1 ) {
if( board.Player1Move( message.X, message.Y ) ) {
SendMessage( connection1, "MOVED (1, " + message.X + "," + message.Y + " )");
SendMessage( connection2, "MOVED (1, " + message.X + "," + message.Y + " )");
p1Move = false;
} else {
SendMessage( message.From, "DENIED \"Disallowed move.\".");
}
} else if( !p1Move && message.From == connection2 ) {
if( board.Player2Move( message.X, message.Y ) ) {
SendMessage( connection1, "MOVED (2, " + message.X + "," + message.Y + " )");
SendMessage( connection2, "MOVED (2, " + message.X + "," + message.Y + " )");
p1Move = true;
} else {
SendMessage( message.From, "DENIED \"Disallowed move.\".");
}
} else {
SendMessage( message.From, "DENIED \"It isn't your turn to move\".");
}
if( board.IsEnded ) {
// handle game-over...
}
} else if( message.Verb == ... // handle all of the other verbs, like QUIT
}
}
Related
So I have a piece of software I'm hooking into. My problem is that the software has a launcher-like home window. From that home I click "Start" and it opens a second process with the same name. In my task manager they are identical in processes/details.
My program has to hook into this second process and I can only hook after the process exists. There's no way to launch it directly without the home window.
They both have randomized PID's each time. I can't figure out a way to differentiate the two processes. If my program hooks the wrong one it will freeze up the software.
p = Process.GetProcessesByName("programName");//This is specifically just the window name so that we can interact with the client using keystrokes.
System.Diagnostics.Debug.WriteLine("Attempting to hook into the program...");
process = Process.GetProcessesByName("programName").ToList().FirstOrDefault();
if (process == null) {
System.Diagnostics.Debug.Write("Hook failed! Make sure the program is open.");
Application.Exit();
}
if (process != null) {
mreader.ReadProcess = process;//Set the process we want to read to be the one we just got in the above line.
mreader.OpenProcess();//Gets the handle of the process and hook in.
for (int i = 0; i < process.Modules.Count; i++) {
System.Diagnostics.Debug.WriteLine("Module " + i + ": " + process.Modules[i].ModuleName);
if (process.Modules[i].ModuleName == "programcore.dll") {
System.Diagnostics.Debug.WriteLine("programcore.dll found at Module " + i);
iCounter = i;//Set the number programcore is on to our counter so we can hook in each time, even if it moves.
System.Diagnostics.Debug.WriteLine("Success!");
break;
}
}
}
This is how I'm hooking into the client to read/write the memory. Unfortunately both processes have the programcore.dll that I need so I don't know how to tell them apart.
I have a web form with 4 dropdownlists and a search button that obtains a list from the database using the values of the selected dropdownlist as filters, what I need is that if user A and B select the same values of the dropdownlist, only 1 of them can work with the list obtained from the database. What would be the best way to work this?
//Get employee list
List<Entity.Employee> lstEmployees = new List<Entity.Employee>();
lstEmployees = Logic.Employee.getEmployees(DropDownList1.SelectedValue, DropDownList2.SelectedValue, DropDownList3.SelectedValue, DropDownList4.SelectedValue);
foreach(Employee emp in lstEmployees)
{
//single process per user required
}
//release single process
Here are two options depending on the environment you are using
1) If you are hosting it on a single server
You can use the application pool Application[Key1 + Key2 + Key3] as a way to track if someone is already working on that combination if not, let them continue.
2) If you are hosting it on a web farm
Use a database (or a shared storage somewhere ex: network share) to track the locking of those parameter combination similar to #1
Obviously #1 is easier/faster
2 is scalable
//Get employee list
List<Entity.Employee> lstEmployees = new List<Entity.Employee>();
lstEmployees = Logic.Employee.getEmployees(DropDownList1.SelectedValue, DropDownList2.SelectedValue, DropDownList3.SelectedValue, DropDownList4.SelectedValue);
foreach(Employee emp in lstEmployees)
{
String MyKey = DropDownList1.SelectedValue + DropDownList2.SelectedValue + DropDownList3.SelectedValue + DropDownList4.SelectedValue;
if(Application[MyKey]==null || Application[MyKey]=""){
//single process per user required
}
}
//release single process
I'm assuming that Employee is a class that you have access to?
The simplest solution I can picture here would be to incorporate a boolean field titled something like "isCheckedOut" and simply check for this value before allowing any data modification.
This solution doesn't really mechanically "lock-down" the code, but depending on how you're accessing it, this sort of quick check could be a very simple fix.
I write the code like this
string sProcesoUnico = ddlCompania.SelectedValue + ddlNomina.SelectedValue + ddlPeriodo.SelectedValue + ddlClaveMovi.SelectedValue;
if (Application[sProcesoUnico].ToString() == "" || Application[sProcesoUnico] == null)
{
try
{
// Process
}
catch (Exception)
{
throw;
}
finally
{
Application[sProcesoUnico] = ""; //release process
}
}
It´s ok the way that I release the Application State?
I would like to generate a 3D scenario for a traffic simulation.
The main idea would be having SUMO running a simulation and then getting the direction, speed and coordinates (X,Y) from each vehicle, so that I would create 3D models for this cars.
For this purpose, I was thinking about using some kind of TCP/IP communication between Unity and SUMO. Since this is possible while communicating SUMO with a network simulator such as OMNeT++, I was wondering if this would also be possible. I don't need to control the simulation in SUMO from Unity, just retrieve data regarding the vehicles in the network.
Unfortunately, I have no remarkable experience with Unity, so I cannot provide any code trying to achieve this...
EDIT:
As requested, I included some code. However, I only have code in Java.
String configFile = "test/resources/sumo_maps/Test2/Test2.sumo.cfg";
SumoTraciConnection trial = new SumoTraciConnection(configFile,-1);
trial.runServer();
Collection<Vehicle> vehicles = trial.getVehicleRepository().getAll().values();
for(Vehicle car : vehicles){
bw.write(time + " // The vehicle with ID: " + car.getID()+ " is driving "
+ "with a speed of "+ car.getSpeed() + " and is in coordinates x: " +car.getPosition().getX()+
" and y: " + car.getPosition().getY());
bw.newLine();
}
Now, let's proceed to get a bit into the class SumoTraciConnection and its methods. This class is part of the mentioned (in the comments) library Traci4j.
It can be found in GitHub in case you need more info: https://github.com/egueli/TraCI4J/blob/master/src/java/it/polito/appeal/traci/SumoTraciConnection.java
The constructor:
public SumoTraciConnection(String configFile, int randomSeed) {
this.randomSeed = randomSeed;
this.configFile = configFile;
}
Now the runServer() method (I put the one with a boolean argument because if no parameter is given then it is automatically called with a false) Basically, this boolean is used to determine wheter the GUI version of SUMO or the console version will be ran:
public void runServer(boolean withGui) throws IOException, InterruptedException {
retrieveFromURLs(); //Checks if the configFile given has an "http://" at the beggining, in order to download the file
int port = findAvailablePort(); //creates a Socket and finds a port with ServerSocket.getLocalPort()
runSUMO(port, withGui); //It is used to run SUMO with different options, such as the configFile for the simulation, the remote port... sumoProcess is set here as: sumoProcess = Runtime.getRuntime().exec(argsArray);, where argsArray contains the different options mentioned
tryConnect(InetAddress.getLocalHost(), port, sumoProcess); // tryConnect basicaly calls this method tryConnectOnce, which connects as a client to the sumo process mentioned before, and does some checks that everything is correct.
postConnect(); //I will explain this function after
}
postConnect() initialices the DataInput and DataOutput streams and creates the repositories. I show now the relevant parts of the code:
dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
vehicles = new HashMap<String, Vehicle>();
edgeRepo = new Repository.Edges(dis, dos, newIDListQuery(Constants.CMD_GET_EDGE_VARIABLE));
addStepAdvanceListener(edgeRepo);
laneRepo = new Repository.Lanes(dis, dos, edgeRepo, newIDListQuery(Constants.CMD_GET_LANE_VARIABLE));
vehicleListQuery = newIDListQuery(Constants.CMD_GET_VEHICLE_VARIABLE);
addStepAdvanceListener(new StepAdvanceListener() {
public void nextStep(double step) {
vehicleListQuery.setObsolete();
}
});
vehicleListBefore = new HashSet<String>(vehicleListQuery.get());
vehicleRepo = new Repository.Vehicles(dis, dos, edgeRepo, laneRepo, vehicles, vehicleListQuery);
addStepAdvanceListener(vehicleRepo);
Where one StepAdvanceListener is just the following(I cannot explain exactly what is this for but I understand that is something that allow us to realize the new simulationstep has been done, so we have to update the repositories):
//Interface for an object that can be notified when the simulation advances by one step.
public interface StepAdvanceListener {
/**
* Callback for step advancement.
* #param step the new simulation time, in seconds
*/
void nextStep(double step);
}
Up to here, it would be the part related to the connection with SUMO. In the next edit (I need some rest right now..) I'll put the parts related with the Repositories and the Data retrieval
Thanks in advance!
When I am detecting a pixel with a given color, I want to send the Key "k".
The problem is that even though the window is active, wit the following code it sends me an exception : SendKeys cannot run inside this application because the application is not handling Windows messages. Either change the application to handle messages, or use the SendKeys.SendWait method. The Sendwait method doesn't seem to press the key fast enough (but at least it gives no exception). I don't really care if the required solution is "dirty", it's a poc I'll use once
static void Main(string[] args)
{
string ligne;
string previousligne = string.Empty;
int compteur = 0;
while (true)
{
Color pixColor = Win32.GetPixelColor(System.Windows.Forms.Cursor.Position.X, System.Windows.Forms.Cursor.Position.Y);
ligne = pixColor.Name;
if (previousligne != ligne)
{
if (ligne == "ffcecefe")
{
SendKeys.Send("k");
}
Console.WriteLine(ligne);
System.IO.File.AppendAllText(#"C:\Users\Public\WriteLines.txt", "-----" + DateTime.Now.Minute + ":" + DateTime.Now.Second + ":" + DateTime.Now.Millisecond + " = " + ligne);
previousligne = ligne;
compteur++;
if (compteur % 10 == 0)
{
System.IO.File.AppendAllText(#"C:\Users\Public\WriteLines.txt", "---------" + compteur);
Console.WriteLine("---------" + compteur);
}
}
}
}
If you know Final Fantasy X, I'm trying to automate the process of avoiding the lightning bolts : video
I could just cheat to get the ingame result (or do it the legit way) and it would have already been done, but if I can learn a bit more of C# instead it would be better.
The console window (i.e. your running process) is the active window which SendKeys is sending data to. Since the console doesn't have a message loop, there is nowhere for the message to be received at, and it's lost. You would need to activate the target window with something like SetActiveWindow().
See also How do I send key strokes to a window without having to activate it using Windows API?
I plan to load only as much data as required in my app. Which means, that when the data is loaded via Wifi, I want to prefetch things. If the data is loaded via mobile plan or even roaming, I would like to ask the user.
However, I only found Microsoft.Phone.Net.NetworkInformation.DeviceNetworkInformation which gives me feedback on what is available, not what is actually used. NetworkInterface.GetInternetInterface() also works, but does not give me details on whether it's roaming or not.
Is there any way to do it?
Let's solve it by myself:
There is the Data Sense API, which allows one to not only check whether the device is roaming, but also check whether the app approaches or is over the data limit set in Data Sense. The API also works when the provider doesn't allow to usse the Data Sense UI.
In particular, this code from the link above solves everything!
// Get current Internet Connection Profile.
ConnectionProfile internetConnectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile();
// Check the connection details.
if (internetConnectionProfile.NetworkAdapter.IanaInterfaceType != IANA_INTERFACE_TYPE_WIFI)
{
// Connection is not a Wi-Fi connection.
if (internetConnectionProfile.GetConnectionCost().Roaming)
{
// User is roaming. Don't send data out.
m_bDoNotSendData = true;
}
if (internetConnectionProfile.GetConnectionCost().ApproachingDataLimit)
{
// User is approaching data limit. Send low-resolution images.
m_bSendLowResolutionImage = true;
}
if (internetConnectionProfile.GetConnectionCost().OverDataLimit)
{
// User is over data limit. Don't send data out.
m_bDoNotSendData = true;
}
}
else
{
//Connection is a Wi-Fi connection. Data restrictions are not necessary.
m_bDoNotSendData = false;
m_bSendLowResolutionImage = false;
}
// Optionally, report the current values in a TextBox control.
string cost = string.Empty;
switch (internetConnectionProfile.GetConnectionCost().NetworkCostType)
{
case NetworkCostType.Unrestricted:
cost += "Cost: Unrestricted";
break;
case NetworkCostType.Fixed:
cost += "Cost: Fixed";
break;
case NetworkCostType.Variable:
cost += "Cost: Variable";
break;
case NetworkCostType.Unknown:
cost += "Cost: Unknown";
break;
default:
cost += "Cost: Error";
break;
}
cost += "\n";
cost += "Roaming: " + internetConnectionProfile.GetConnectionCost().Roaming + "\n";
cost += "Over Data Limit: " + internetConnectionProfile.GetConnectionCost().OverDataLimit + "\n";
cost += "Approaching Data Limit : " + internetConnectionProfile.GetConnectionCost().ApproachingDataLimit + "\n";
NetworkStatus.Text = cost;
Have you tried the System.Net.NetworkInformation namespace on WP8. This package has a static method which returns the network status. You can then switch based on this information
NetworkInterface.NetworkInterfaceType
More details can be found here
The phone can use both 3G and WiFi at the same time. The case I've tested - the phone haven't close existing TCP connections opened while on 3G after it found and connected to a WiFi network. If a new TCP connection is opened it'll use WiFi instead.
There's SocketExtensions.GetCurrentNetworkInterface extension method from Microsoft.Phone.dll that tell you which interface is used for the specified socket.