Jump to content
  • Advertisement

Oconzer

Member
  • Content Count

    16
  • Joined

  • Last visited

Everything posted by Oconzer

  1. After asking about the possibility of protecting save data on a clients computer for a game that I'm developing that was going to be single player with multiplayer, I'm going to have to figure out how to set up a actual server for hosting a server for my game (which is a TCG).   I've not a clue what I'd do or how long it would take to get a server setup or what not to host a server program for my game.   I've got basic networking knowledge as I've had to self teach myself how to do some networking (only have done a simple TCP console chat program). I understand that with making a server program that its to handle everything for the game (aside from the drawing) and that the client only draws and sends what the user is trying to do to the server for it to interpret what action the user wants to take.   I had originally intended to make the game offline mostly (because I do dislike the whole you have to be online to play a single player game) but since I won't be able to prevent cheating enough that way I have to go the server hosted route.
  2.   OK. I had posted earlier that I was going to only have the client responsible for drawing the information that is necessary for interacting with the game, as well as sending what the client wants to do to the server. The server was going to interpret what the user wants to do based on what state the game has that player on the server (basically checks to make sure that if they are in a game that they can't trade with a player for example or edit their deck, etc). If this was what you were meaning, I was already planning on making sure that the player can't do something that they aren't supposed to be able to do unless the server says its fine.
  3.   A bit confused on what you mean by this. Do you mean that despite me setting up my server program (when i get there that is) to have only certain things as acceptable messages for controlling the game from the client side that they can cheat / create their own rules???
  4. Thank you that helps me greatly for when I get to making the networking part of my game.
  5. I read over the FAQ again and didn't see anything about how to make sure the sessions are secure and can't be hijacked. What do I need to learn to do that with what I already know?
  6. Ok I'll probably then go with the virtual server unless when I do my kickstarter for my game that I get enough funding (and interest) that I may look into the physical server renting.   As I was also wondering based on the code that I posted from my console chat program (networking code that I know at the moment) is that going to be enough to do a TCG, is it secure, and what do I have to do to ensure that people can't cheat, aside from encrypting the data that will be sent back and for between the server and client?   I am going to design my client so it only will of course draw everything so the player can interact with the game, as well as send messages that the server will interpret to what the player wants to do.
  7. I was wondering about with protecting saves from being edited from outside of the program that they are supposed to be for. Specifically for games.   I'm currently trying to figure out what I can do to protect my game's save file along with using encryption.   I had thought to try and use a file that holds the save file's creation, last edited, and accessed times (encrypted of course), but found out that you can edit those from outside sources, so this won't work to my knowledge.   I have thought to make another file that is used for matching to see if the data from the one file matches the other data when decrypted (the match file would be encrypted differently was what I was thinking), so I'm not sure if this would help along side with encrypting.   Outside of a strong encryption algorithm (that I'm sure people can decompile the game somehow and find out the code for it and create an editor anyway), is there anything else I can do to protect a file from being tampered with?  
  8. Yeah I apparently forgot to ask sorry. >.<   What does it take to setup (or get someplace to host) a server (physical not the program) and, what all do I need to know to set up the server program or is what I know fine enough for now?   The networking code that I know at the moment from my server / client console chat program:   // Main code of console chat program using System; using System.Collections.Generic; using System.Linq; using System.Text; using ClientTest; using ServerTest; using System.Net; using System.Net.Sockets; using System.Threading; namespace MainProgram {     class ClientServerTest     {         #region Messages         public static string PMain = "Enter a command: \n\t/C to connect to a server\n\t/H to host a server\n\t/E to quit";         public static string PMInvalid = "Invalid Command. Valid commands are:\n\t/C to connect to a server\n\t/H to host a server\n\t/E to quit";         public static string PQuit = "Enter some text to send, or /q to stop hosting and return to main menu.";         public static string PConnect = "Enter an address to connect to or /C to return: ";         #endregion Messages         public static AsyncClient CLIENT = new AsyncClient();         public static AsyncServer SERVER = new AsyncServer(3);         const int port = 11000;         public static void HostAndRun()         {             IPAddress sip = null;             IPHostEntry ipEntry = Dns.GetHostEntry(Dns.GetHostName());             foreach (IPAddress a in ipEntry.AddressList)             {                 if (a.AddressFamily == AddressFamily.InterNetwork)                 {                     sip = a;                     break;                 }             }             IPEndPoint ServerEndPoint = new IPEndPoint(sip, port);             SERVER.Host(ServerEndPoint);             CLIENT.Host(ServerEndPoint);             string Feed = string.Empty;             Console.WriteLine(PQuit);             while (!CLIENT.isQuitting)             {                 CLIENT.RunClient();                 if (!CLIENT.isQuitting)                 {                     SERVER.RunServer();                 }                 else                 {                     CLIENT.StopConnection();                     SERVER.StopServer();                 }             }             Console.WriteLine(PMain);         }         public static void ConnectAndRun()         {             bool loop = true;             IPAddress ip = null;             string serverIP = string.Empty;             Console.WriteLine(PConnect);             while (loop)             {                 serverIP = Console.ReadLine();                 switch (serverIP.ToUpper())                 {                     case "/C":                         loop = false;                         serverIP = string.Empty;                         break;                     default:                         if (serverIP != string.Empty)                         {                             try                             {                                 ip = IPAddress.Parse(serverIP);                                 loop = false;                             }                             catch (FormatException fe)                             {                                 Console.WriteLine("Invalid address\n");                                 Console.WriteLine(PConnect);                                 serverIP = string.Empty;                                 loop = true;                             }                         }                         break;                 }             }             if (serverIP != string.Empty)             {                 IPEndPoint remoteEP = new IPEndPoint(ip, port);                 CLIENT.Start(remoteEP);             }             CLIENT.StopConnection();             Console.WriteLine(PMain);         }         public static void Run()         {             bool loop = true;             string command = string.Empty;             Console.WriteLine(PMain);             while (loop)             {                 command = Console.ReadLine();                 switch (command.ToUpper())                 {                     case "/C":                         ConnectAndRun();                         break;                     case "/H":                         HostAndRun();                         break;                     case "/E":                         loop = false;                         break;                     default:                         Console.WriteLine(PMInvalid);                         break;                 }             }         }         public static int Main(string[] args)         {             Console.Title = "ClientServer Test Program";             Run();             Console.WriteLine("Press any key to exit...");             Console.ReadLine();             return 0;         }     } }   // Misc code for console chat program using System; using System.Net; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.IO; using System.Threading; namespace MiscStuff {     public enum ReasonForQuit     {         Default = 0, ServerFull = 1     }     class BufferSpace     {         public const int BufferSize = 512;     }     public class QuitReason     {         public static string CloseReason(ReasonForQuit reason = ReasonForQuit.Default)         {             string output = string.Empty;             switch (reason)             {                 case ReasonForQuit.Default:                     break;                 case ReasonForQuit.ServerFull:                     output = "<#Reason#>:FULL";                     break;             }             return output;         }     }     // State object for reading client data asynchronously     public class Client     {         // Client socket.         public byte[] readBuffer = new byte[BufferSpace.BufferSize];         public byte[] writeBuffer = new byte[BufferSpace.BufferSize];         private Socket Socket = null;         public Socket clientSocket         {             get { return Socket; }             set { Socket = value; }         }         //create a network stream for easier access         private NetworkStream outStream;         public NetworkStream WriteFeed         {             get { return outStream; }         }         //use a stream reader because of ReadLine() method         private NetworkStream inStream;         public NetworkStream ReadFeed         {             get { return inStream; }         }         public bool toRemove = false;         public string feedBack = string.Empty;         public StringBuilder sb = new StringBuilder();         public IPEndPoint ID;         public Client(Socket s)         {             if (s != null)             {                 Socket = s;                 ID = (IPEndPoint)s.RemoteEndPoint;                 outStream = new NetworkStream(s);                 inStream = new NetworkStream(s);             }         }         public void Set(Socket s)         {             Socket = s;             if (s != null)             {                 ID = (IPEndPoint)s.RemoteEndPoint;                 outStream = new NetworkStream(s);                 inStream = new NetworkStream(s);             }         }     } }   // client code for console chat program using System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Text; using MiscStuff; namespace ClientTest {     using qr = MiscStuff.QuitReason;     public class AsyncClient     {         #region Messages         public string PFConnect = "Failed to connect to server.\nType /R to try connecting again or type /C to return to main.";         public string PFInvald = "Invalid Command. Type /R to try connecting again or type /C to return to main.";         public static string PDC = "Enter some text to send, or /q to disconnect and return to main menu.";         public static string PConnected = "Connected to the server.\n";         #endregion Messages         private int ConTryTimeOut = 6000;         private Client ThisClient = new Client(null);         private string Feed = string.Empty;         // ManualResetEvent instances signal completion.         private static ManualResetEvent connectDone;         private static ManualResetEvent sendDone;         private static ManualResetEvent receiveDone;         private static ManualResetEvent disconnetDone;         private static ManualResetEvent issueCheckDone;         private bool Started;         private bool AttempingCon;         private bool Quit;         public bool isQuitting         {             get { return Quit; }         }         private bool Hosting = false;         private IPEndPoint ID;         public AsyncClient()         {         }         private void SetupClientSocket()         { // Resolving local machine information             ThisClient.clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);         }         public void Reset()         {             connectDone = new ManualResetEvent(false);             sendDone = new ManualResetEvent(false);             receiveDone = new ManualResetEvent(false);             disconnetDone = new ManualResetEvent(false);             issueCheckDone = new ManualResetEvent(false);             AttempingCon = false;             Started = false;             Quit = false;         }         public void Start(IPEndPoint id)         {             Reset();             ID = id;             Hosting = false;             StartConnection();             CheckForIssues();             while (AttempingCon)             {                 if (AttempingCon)                 {                     Console.WriteLine(PFConnect);                 }                 AttemptConnect();             }             if (Started)             {                 Console.WriteLine(PConnected);                 Console.WriteLine(PDC);                 while (!Quit)                 {                     RunClient();                 }             }         }         public void RunClient()         {             if (Connected(ThisClient.clientSocket))             {                 if (Console.KeyAvailable)                 {                     Feed = Console.ReadLine();                     if (Feed.ToUpper() == "/Q")                     {                         if (!Hosting)                         {                             Disconnect();                             disconnetDone.WaitOne();                         }                         Quit = true;                         Feed = string.Empty;                     }                     else if (Feed != string.Empty)                     {                         Feed += "<EOF>";                     }                 }                 ProcessConnection();             }             else             {                 ServerClosed();             }         }         public void Host(IPEndPoint self)         {             Reset();             Hosting = true;             ID = self;             if (ThisClient.clientSocket == null)             {                 SetupClientSocket();             }             ThisClient.clientSocket.BeginConnect(ID, new AsyncCallback(ConnectCallback), ThisClient.clientSocket);             connectDone.WaitOne();         }         private void ProcessConnection()         {             //what I want it to do is read asynchronously if data is available, and write the data asynchronously to the client after reading is done, and if the             //client is closing or disconnecting, it will close the client's connection.             if (!Quit)             {                 if (!Connected(ThisClient.clientSocket) && ThisClient.clientSocket != null)                 {                     ServerClosed();                 }                 else                 {                     if (Feed != string.Empty)                     {                         Send(ThisClient, Feed);                         sendDone.WaitOne(100);                         sendDone.Reset();                     }                     if (ThisClient.ReadFeed.DataAvailable)                     {                         Receive();                         receiveDone.WaitOne(100);                         receiveDone.Reset();                     }                     Feed = string.Empty;                 }             }         }         private void ConnectCallback(IAsyncResult ar)         {             try             {                 // Retrieve the socket from the state object.                 Socket client = (Socket)ar.AsyncState;                 // Complete the connection.                 client.EndConnect(ar);                 ThisClient.Set(client);                 // Signal that the connection has been made.                 connectDone.Set();                 AttempingCon = false;                 Started = true;             }             catch (Exception e)             {                 Console.WriteLine("The server is not responding.\n");                 AttempingCon = true;                 Started = false;                 //Console.WriteLine(e.ToString());             }         }         private void ConnectIssueCallback(IAsyncResult result)         {             if (Connected(ThisClient.clientSocket))             {                 try                 {                     Client state = (Client)result.AsyncState;                     NetworkStream handler = state.ReadFeed;                     state.feedBack = string.Empty;                     int bytesRead = handler.EndRead(result);                     state.sb.Append(Encoding.ASCII.GetString(state.readBuffer, 0, bytesRead));                     state.feedBack = state.sb.ToString();                     if (state.feedBack == qr.CloseReason(ReasonForQuit.ServerFull))                     {   //data transfer done                         state.sb.Clear();                         issueCheckDone.Set();                         Console.WriteLine("Can't connect to the server. Server is full.");                     }                 }                 catch (Exception e)                 {                     Console.WriteLine(e.ToString());                 }             }         }         private void Receive()         {             if (Connected(ThisClient.clientSocket))             {                 try                 {                     // Begin receiving the data from the remote device.                     ThisClient.ReadFeed.BeginRead(ThisClient.readBuffer, 0, BufferSpace.BufferSize,                         new AsyncCallback(ReadStream), ThisClient);                 }                 catch (Exception e)                 {                     Console.WriteLine(e.ToString());                 }             }         }         private void ReadStream(IAsyncResult result)         {             if (Connected(ThisClient.clientSocket))             {                 try                 {                     Client state = (Client)result.AsyncState;                     NetworkStream handler = state.ReadFeed;                     state.feedBack = string.Empty;                     int bytesRead = handler.EndRead(result);                     if (bytesRead > 0)                     {                         state.sb.Append(Encoding.ASCII.GetString(state.readBuffer, 0, bytesRead));                         state.feedBack = state.sb.ToString();                         if (state.feedBack.IndexOf("<EOF>") > -1)                         {   //data transfer done                             string temp = state.feedBack.Remove(state.feedBack.Length - 5, 5);                             state.feedBack = temp;                             //Console.WriteLine("Recieved {0} bytes from {1}:{2}. Message: {3}", state.feedBack.Length, state.ID.Address,                                 //state.ID.Port, state.feedBack);                             Console.WriteLine("Recieved message from {0}:{1}. Message: {2}", state.ID.Address,                                 state.ID.Port, state.feedBack);                             state.sb.Clear();                             receiveDone.Set();                         }                         else                         {   //not all data sent                             handler.BeginRead(state.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ReadStream), state);                         }                     }                 }                 catch (Exception e)                 {                     Console.WriteLine(e.ToString());                 }             }         }         private void WriteStream(IAsyncResult result)         {             if (Connected(ThisClient.clientSocket))             {                 try                 {                     // Retrieve the socket from the state object.                     Client state = (Client)result.AsyncState;                     NetworkStream handler = state.WriteFeed;                     // Complete sending the data to the remote device.                     handler.EndWrite(result);                     sendDone.Set();                     Feed = string.Empty;                 }                 catch (Exception e)                 {                     Console.WriteLine(e.ToString());                 }             }         }         private void Send(Client c, string data)         {             if (Connected(ThisClient.clientSocket))             {                 try                 {                     byte[] byteData = Encoding.ASCII.GetBytes(data);                     c.WriteFeed.BeginWrite(byteData, 0, byteData.Length, new AsyncCallback(WriteStream), c);                 }                 catch (Exception e)                 {                     Console.WriteLine(e.ToString());                 }             }         }         public void AttemptConnect()         {             string i = string.Empty;             i = Console.ReadLine();             switch (i.ToUpper())             {                 case "/R":                     Console.WriteLine("Attempting to connect to the server...\n");                     StartConnection();                     break;                 case "/C":                     Console.WriteLine("Returning to Main...\n");                     AttempingCon = false;                     break;                 default:                     Console.WriteLine(PFInvald);                     break;             }             i = string.Empty;         }         private void StartConnection()         {             if (ThisClient.clientSocket == null)             {                 SetupClientSocket();             }             ThisClient.clientSocket.BeginConnect(ID, new AsyncCallback(ConnectCallback), ThisClient.clientSocket);             connectDone.WaitOne(ConTryTimeOut);         }         private void CheckForIssues()         {             if (Connected(ThisClient.clientSocket))             {                 if (ThisClient.ReadFeed.DataAvailable)                 {                     ThisClient.ReadFeed.BeginRead(ThisClient.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ConnectIssueCallback), ThisClient);                     Started = false;                     Quit = true;                     issueCheckDone.WaitOne();                 }             }         }         private bool Connected(Socket s)         {             if (s != null)             {                 return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);             }             return false;         }         private void Disconnect()         {             try             {                 ThisClient.clientSocket.BeginDisconnect(false, new AsyncCallback(DisconnectCallBack), ThisClient);             }             catch (Exception e)             {                 Console.WriteLine(e.ToString());             }         }         private void ServerClosed()         {             if (!Hosting)             {                 Console.WriteLine("Server connection stopped. Returning to main...\n");             }             ThisClient.ReadFeed.Close();             ThisClient.WriteFeed.Close();             if (ThisClient.clientSocket != null)             {                 ThisClient.clientSocket.Close();             }             ThisClient.Set(null);             Quit = true;         }         private void DisconnectCallBack(IAsyncResult result)         {             try             {                 Client c = (Client)result.AsyncState;                 c.clientSocket.EndDisconnect(result);                 c.WriteFeed.Close();                 c.ReadFeed.Close();                 c.clientSocket.Close();                 c.Set(null);                 Console.WriteLine("Disconnected from the server. Returning to main...\n");                 disconnetDone.Set();             }             catch (Exception e)             {                 Console.WriteLine(e.ToString());             }         }         public void StopConnection()         {             if (ThisClient.clientSocket != null)             {                 if (ThisClient.clientSocket.Connected)                 {                     ThisClient.WriteFeed.Close();                     ThisClient.ReadFeed.Close();                     ThisClient.clientSocket.Close();                 }                 connectDone.Close();                 sendDone.Close();                 receiveDone.Close();                 disconnetDone.Close();                 issueCheckDone.Close();             }             ThisClient.clientSocket = null;         }     } }   // server code for console chat program using System; using System.Net; using System.Collections.Generic; using System.Net.Sockets; using System.Text; using System.IO; using System.Threading; using MiscStuff; namespace ServerTest {     using qr = MiscStuff.QuitReason;     public class AsyncServer     {         private Socket serverSocket;         private int maxConnections = 0;         private List<Client> connections;         private int endedConnections = 0;         private bool AttemptingAccept = false;         public AsyncServer(int maxC)         {             maxConnections = maxC;         }         private void SetupServerSocket(IPEndPoint id)         { // Resolving local machine information             serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);             serverSocket.Bind(id);             serverSocket.Listen(100);             Console.WriteLine("Hosting started");         }         public void Start(IPEndPoint id)         {             connections = new List<Client>();             AttemptingAccept = false;             SetupServerSocket(id);         }         public void RunServer()         {             if (!AttemptingAccept)             {                 AttemptingAccept = true;                 serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);             }             ProcessConnections();         }         public void Host(IPEndPoint ip)         {             Start(ip);             serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);         }         private void ProcessConnections()         {             // process the connections and then remove ones that are to be closed from dcing or because the server is full.             lock (connections)             {                 foreach (Client c in connections)                 {                     if (!c.toRemove)                     {                         if (!Connected(c.clientSocket))                         {                             CloseConnection(c); // sets a connection to close after all connections have been processed.                         }                         else                         {                             if (c.ReadFeed.DataAvailable)                             {                                 c.ReadFeed.BeginRead(c.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ReadStream), c);                             }                         }                     }                 }             }             if (endedConnections > 0)             {                 for (int i = 0; i < connections.Count; i++)                 {                     if (connections[i].toRemove)                     {                         connections.RemoveAt(i);                     }                 }                 endedConnections = 0;             }         }         private void AcceptCallback(IAsyncResult result)         {             try             {                 // Finish Accept                 Socket s = (Socket)result.AsyncState;                 Client ConTest = new Client(null);                 ConTest.Set(s.EndAccept(result));                 if (ConTest.clientSocket != null)                 {                     AttemptingAccept = false;                     if (connections.Count == maxConnections) //server is full send a message to the client that its full so it can notify the user that its full                     {                         string reason = qr.CloseReason(ReasonForQuit.ServerFull);                         Send(ConTest, reason);                         Console.WriteLine("Client {0}:{1} tried to connnect but the server is full.", ConTest.ID.Address, ConTest.ID.Port);                     }                     else // server isn't full continue as normal                     {                         lock (connections)                         {                             connections.Add(ConTest);                         }                         Console.WriteLine("Client {0}:{1} connected. Total connected clients {2}", ConTest.ID.Address, ConTest.ID.Port, connections.Count);                     }                 }             }             catch (Exception exc)             {             }         }         private void ReadStream(IAsyncResult result)         {             try             {                 Client state = (Client)result.AsyncState;                 NetworkStream handler = state.ReadFeed;                 state.feedBack = string.Empty;                 int bytesRead = handler.EndRead(result);                 if (bytesRead > 0)                 {                     state.sb.Append(Encoding.ASCII.GetString(state.readBuffer, 0, bytesRead));                     state.feedBack = state.sb.ToString();                     if (state.feedBack.IndexOf("<EOF>") > -1)                     {   //data transfer done                         lock (connections)                         {                             foreach (Client c in connections)                             {                                 if (TestForSend(c))                                 {                                     Send(c, state.feedBack);                                 }                             }                         }                         state.sb.Clear();                     }                     else                     {   //not all data sent                         handler.BeginRead(state.readBuffer, 0, BufferSpace.BufferSize, new AsyncCallback(ReadStream), state);                     }                 }             }             catch(Exception e)             {                 Console.WriteLine(e.ToString());             }         }         private bool TestForSend(Client c)         {             return (!c.toRemove && Connected(c.clientSocket));         }         private void WriteStream(IAsyncResult result)         {             try             {                 // Retrieve the socket from the state object.                 Client state = (Client)result.AsyncState;                 NetworkStream handler = state.WriteFeed;                 // Complete sending the data to the remote device.                 handler.EndWrite(result);             }             catch (Exception e)             {                 Console.WriteLine(e.ToString());             }         }         private void Send(Client c, string data)         {             try             {                 byte[] byteData = Encoding.ASCII.GetBytes(data);                 c.WriteFeed.BeginWrite(byteData, 0, byteData.Length, new AsyncCallback(WriteStream), c);             }             catch(Exception e)             {                 Console.WriteLine(e.ToString());             }         }         private bool Connected(Socket s)         {             if (s != null)             {                 return !((s.Poll(1000, SelectMode.SelectRead) && (s.Available == 0)) || !s.Connected);             }             return false;         }         private void CloseConnection(Client c)         {             try             {                 if (c.clientSocket != null)                 {                     c.WriteFeed.Close();                     c.ReadFeed.Close();                     c.clientSocket.Close();                     c.toRemove = true;                     ++endedConnections;                     Console.WriteLine("Client {0}:{1} disconnected. Total connected clients {2}", c.ID.Address, c.ID.Port, connections.Count - endedConnections);                 }             }             catch (Exception e)             {                 Console.WriteLine(e.ToString());             }         }                         public void StopServer()         {             foreach (Client c in connections)             {                 c.WriteFeed.Close();                 c.ReadFeed.Close();                 c.clientSocket.Close();             }             connections.Clear();             serverSocket.Close();             serverSocket = null;             Console.WriteLine("Hosting stopped. Returning to main...\n");         }     } }
  9. Well that's an issue then. My game is a card game (TCG) that I wanted to have players be able to play offline, and there was going to be multiplayer and trading. I don't know anything about setting up a server for running a game and was going to make the server basically a matchmaking server that would have just been responsible for redirecting players to play with others / trading.
  10.       Ok I didn't understand that. I thought texture was in the memory rather than video memory. Then would that apply to the color array that I use to grab the data from the render target (is it in video or normal memory) or would that work for keeping the cards data from being lost?   Because if that would work then all I have to do is after drawing to the scaled down rendertarget is get the data and then when I want to draw the card use a texture to set the data into and draw it.   Also I've got the draw calls reduced to the max frames that the user has set by doing a test for if the time has passed the next allowed frame time.   Not sure what you mean by texture switches, unless you mean the redrawing of the card if something changes to its stats / abilities.   (Sorry for not posting this sooner been busy).  
  11. For my game that I'm developing I want to have my cards dynamically drawn so if there is any changes done to them it could be drawn on the card itself. I'm currently using a CPU method as I'm not sure if there is a way to do it via GPU as I'm new to drawing and textures. What I have currently is that the cards are drawn to a RenderTarget at their originally designed size of 2100x1480 px. (I'll probably for game purposes have to scale that down to 1050x740 for its native size, but was designed that way to have 600 dpi for physical versions). Anyway the way I want to do it is that after drawing everything to the RenderTarget I scale it down and store that scaled down texture to the card's texture (which will be 164 x 115 for the playing size, the 1050 x 740 is the zoomed in size that I want so players can view what the card does and stats). The issue that I'm facing is that the way I currently tried to do it was far too slow taking over 9 seconds to scale it down after drawing the original size to the RenderTarget. The code that I'm currently using:   protected void DrawCardTest(decimal cardScale) { startTime = DateTime.Now; // Set the device to the render target graphics.GraphicsDevice.SetRenderTarget(cardRenderTarget); graphics.GraphicsDevice.Clear(Color.Transparent); spriteBatch.Begin(); Vector2 pos = Vector2.Zero; spriteBatch.Draw(cardDrawables.Texture, pos, cardDrawables.SourceRectangle("Blank Card Front"), Color.White, 0.0F, pos, new Vector2(1.0F, 1.0F), SpriteEffects.None, 0.0F); spriteBatch.End(); // Reset the device to the back buffer so can grab the texture from the rendertarget graphics.GraphicsDevice.SetRenderTarget(null); colorArrayForTexture = new Color[cardDrawables.SourceRectangle("Blank Card Front").Width * cardDrawables.SourceRectangle("Blank Card Front").Height]; cardRenderTarget.GetData(colorArrayForTexture); cardTest = new Texture2D(graphics.GraphicsDevice, (int)(cardRenderTarget.Width * (decimal)cardScale), (int)(cardRenderTarget.Height * (decimal)cardScale)); Color[] arrayAfterScale = new Color[(int)(cardRenderTarget.Width * (decimal)cardScale) * (int)(cardRenderTarget.Height * (decimal)cardScale)]; cardTest.SetData(ScaleTexture(colorArrayForTexture, cardRenderTarget.Width, cardRenderTarget.Height, (decimal)cardScale)); endTime = DateTime.Now; } public Color[] ScaleTextureNew(Color[] textureData, int width, int height, decimal scaleAmount) { #region ScaleTexture Variables and Setup decimal scaleX = scaleAmount; decimal scaleY = scaleAmount; int widthAfterScale = (int)(width * scaleX); int heightAfterScale = (int)(height * scaleY); //create a pixel array that will hold the scaled texture data Color[] scaledTextureData = new Color[widthAfterScale * heightAfterScale]; ColorStorage colorToAverage = new ColorStorage(); decimal widthStep = (decimal)width / (decimal)widthAfterScale; decimal heightStep = (decimal)height / (decimal)heightAfterScale; decimal widthTotal = widthStep; decimal heightTotal = heightStep; //check to see if width sample total or height sample total will be repeating if ((widthStep * widthAfterScale) != width) // this should equal out if not there is a repeating issue widthTotal += repeatingFix; if ((heightStep * heightAfterScale) != height) // this should equal out if not there is a repeating issue heightTotal += repeatingFix; decimal sampledWidth = 0.0M; decimal sampledHeight = 0.0M; decimal widthSampling = 0.0M; decimal heightSampling = 0.0M; decimal widthSamplingTotal = 0.0M; decimal heightSamplingTotal = 0.0M; decimal widthIncrement = 0.0M; decimal heightIncrement = 0.0M; decimal widthRemainder = 0.0M; decimal heightRemainder = 0.0M; decimal transparentPixelArea = 0.0M; decimal areaSampled = 1.0M; decimal totalAreaSampled = 0.0M; decimal currentHeight = 0.0M; decimal currentWidth = 0.0M; decimal alpha = 0.0M; if (widthStep > 1.0M) widthIncrement = 1.0M; else if (widthStep < 1.0M) widthIncrement = widthStep; if (heightStep > 1.0M) heightIncrement = 1.0M; else if (heightStep < 1.0M) heightIncrement = heightStep; Index widthIndexUnscaled = new Index(0); Index heightIndexUnscaled = new Index(0); Index widthIndexScaled = new Index(0); Index heightIndexScaled = new Index(0); Index widthIndexToUse; Index heightIndexToUse; int indexIntoArray = 0; decimal[] samplingArrayWidth; // use the bigger between width and widthafterscale if (width > widthAfterScale) { samplingArrayWidth = new decimal[width]; widthIndexToUse = widthIndexUnscaled; } else { samplingArrayWidth = new decimal[widthAfterScale]; widthIndexToUse = widthIndexScaled; } CalculateSampling(ref samplingArrayWidth, widthStep); decimal[] samplingArrayHeight; // use the bigger between width and widthafterscale if (height > heightAfterScale) { samplingArrayHeight = new decimal[height]; heightIndexToUse = heightIndexUnscaled; } else { samplingArrayHeight = new decimal[heightAfterScale]; heightIndexToUse = heightIndexScaled; } CalculateSampling(ref samplingArrayHeight, heightStep); bool doneScaling = false; #endregion //will iterate top left to right bottom while (!doneScaling) { while (sampledHeight < heightStep) { if (heightRemainder == 0.0M) { heightRemainder = heightStep - samplingArrayHeight[heightIndexToUse.Point]; heightSampling = heightStep - heightRemainder; } else if (heightRemainder >= 1.0M) { heightRemainder -= samplingArrayHeight[heightIndexToUse.Point]; heightSampling = 1.0M; } else heightSampling = heightRemainder; while (sampledWidth < widthStep) { if (widthRemainder == 0.0M) { widthRemainder = widthStep - samplingArrayWidth[widthIndexToUse.Point]; widthSampling = widthStep - widthRemainder; } else if (widthRemainder >= 1.0M) { widthRemainder -= samplingArrayWidth[widthIndexToUse.Point]; widthSampling = 1.0M; } else widthSampling = widthRemainder; areaSampled *= heightSampling * widthSampling; // check to see if the pixel is blank to correctly sample indexIntoArray = width * heightIndexUnscaled.Point + widthIndexUnscaled.Point; // so don't have to calculate index every time if (textureData[indexIntoArray].A == 0) transparentPixelArea += areaSampled; alpha = textureData[indexIntoArray].A; colorToAverage.Alpha += alpha * areaSampled; alpha /= 255; //get the oppacity percentage to reverse the multiplyied alpha onto the colors if (alpha == 0.0M) alpha = 1.0M; // this is so colors don't get created where there were none. // undivide the colors by alpha since its been done and needs to be corrected colorToAverage.Red += textureData[indexIntoArray].R * areaSampled / alpha;// *alpha * areaSampled; colorToAverage.Green += textureData[indexIntoArray].G * areaSampled / alpha;// *alpha * areaSampled; colorToAverage.Blue += textureData[indexIntoArray].B * areaSampled / alpha;// *alpha * areaSampled; //add the area sampled to total and reset area to sample totalAreaSampled += areaSampled; areaSampled = 1.0M; sampledWidth += widthSampling; widthSamplingTotal += widthSampling; widthIndexUnscaled.Point = (int)widthSamplingTotal; // have to do this here since counter has to change to sample properly } widthSampling = 0.0M; widthRemainder = 0.0M; sampledWidth = 0.0M; widthSamplingTotal = currentWidth; widthIndexUnscaled.Point = (int)widthSamplingTotal; // have to do this here since counter has to change to sample properly sampledHeight += heightSampling; heightSamplingTotal += heightSampling; heightIndexUnscaled.Point = (int)heightSamplingTotal; // have to do this here since counter has to change to sample properly } heightSampling = 0.0M; heightRemainder = 0.0M; sampledHeight = 0.0M; //calculate the scaled texture's value here scaledTextureData[heightIndexScaled.Point * widthAfterScale + widthIndexScaled.Point] = ColorAveraged(colorToAverage, (totalAreaSampled - transparentPixelArea), totalAreaSampled); //reset colorToAverage for next pass colorToAverage.Alpha = 0.0M; colorToAverage.Red = 0.0M; colorToAverage.Blue = 0.0M; colorToAverage.Green = 0.0M; totalAreaSampled = 0.0M; transparentPixelArea = 0.0M; if (widthTotal >= width) // at the right of the texture { if (heightTotal >= height) // at the bottom of the texture doneScaling = true; else { //increment height stuff for next line of texture currentHeight = heightTotal; heightSamplingTotal = currentHeight; heightIndexUnscaled.Point = (int)heightSamplingTotal; // have to do this here since counter has to change to sample properly heightTotal += heightStep; heightIndexScaled.Point++; //reset width stuff for next line of texture widthTotal = widthStep; if ((widthStep * widthAfterScale) != width) // this should equal out if not there is a repeating issue widthTotal += repeatingFix; widthIndexScaled.Point = 0; widthIndexUnscaled.Point = 0; } } else { currentWidth = widthTotal; widthSamplingTotal = currentWidth; widthIndexUnscaled.Point = (int)widthSamplingTotal; // have to do this here since counter has to change to sample properly widthTotal += widthStep; widthIndexScaled.Point++; heightSamplingTotal = currentHeight; heightIndexUnscaled.Point = (int)heightSamplingTotal; // have to do this here since counter has to change to sample properly } } decimal widthToBlur; if (widthAfterScale > width) // only blur width if its been scaled up widthToBlur = ((decimal)widthAfterScale / (decimal)width) / 2.0M; else widthToBlur = 0.0M; decimal heightToBlur; if (heightAfterScale > height) // only blur height if its been scaled up heightToBlur = ((decimal)heightAfterScale / (decimal)height) / 2.0M; else heightToBlur = 0.0M; //if ((height < heightAfterScale) || (width < widthAfterScale)) //texture was scaled up so need to blur it // scaledTextureData = Blur(scaledTextureData, widthAfterScale, heightAfterScale, // widthToBlur, heightToBlur); return scaledTextureData; } }   What the function is supposed to do. Example1: if scaling down a 4x4 image to a 2x2 image each pixel for the 2x2 image will be a composition of a 2x2 pixel sampling area of the original image. Example2: if scaling down a 66x66 image to a 10x10 image each pixel for the 10x10 image will be a composition of a 6.6x6.6 pixel sampling area of the original image.   EDIT: Not sure how to do code for this site so it shows up more readable. :S
  12.   Right, but I'm asking why you need to store their images. You obviously already have the logic to render what you need to the render target where you're currently storing their image. Can't you just use that logic to draw them directly to the back buffer? Does your draw code not support scaling for some reason? Or do you think it's faster to store them in a render target and just draw that image? It might be, but it might not be. Using cached images means less draw calls, but it also comes with limitations like no texture compression (which means more texture bandwidth required to draw the card).   If you really decide you need cached images, and for some reason you need to render your cards at 2100x1480 even though you store them smaller, then you only need a single 2100x1480 render target. You'll render to the 2100x1480 render target, and then render again to a 164x115 render target  (or whatever size you decide you need per-card). The large render target would only be used as an intermediate step, and you don't care about preserving its contents.     OK. I may be explaining it in a way that is confusing people (one of my bad traits). Going to explain as best I can what I was doing.   I've got a single rendertarget that is 2100x1480 at the moment for my game for testing out drawing cards. I don't have multiple. The reason that I was going to render to that rendertarget then shrink it down to store it in a texture was because I thought it would save on having to redraw everything that each card needs every time the game needs to redraw the cards(which depending on the number of cards that need to be drawn based on number in play would become an issue from what I'm thinking), making the game perform better.   I've got a "blank" card front that is the common image that the cards use. I am setting up the code to draw all the stats, icons, artwork for the card (the image on the card that represents what the object that the card is for would look like) to the blank card after its been drawn to the render target.   I was going to have my game render the card at the time that the player draws it from their deck of cards, as well as if any changes happen to a card and then store the texture for the small (164x115 texture) card only. The reason for this is that I figured I'd just remake the zoomed card image (1050x740 texture) when the player zooms in on a card to be able to see what the card does because you can only zoom on one card.   While I'm thinking of it I may have thought of a way to do what I wanted to do originally. I should be able to draw everything about the card to the one 2100x1480 render target, then store that to a texture, then redraw that texture at the scaled size to a new render target that is of the zoomed or small card size and store that so I have my reduced in size card textures right?
  13. Well for the cards they are being rendered to a render target then placed in a texture for storage. I planned on having the cards have stats changed based on effects on them from abilities or other cards, as well as showing any ability changes from temporary abilities being added to a card.   As for the game play its not action paced but more of TCG paced is the best way I can put it.   As for cards on the playing field if players aren't losing many there could be situations where there would be at least 400+ cards out on the field. Cards in the deck of course wouldn't need to have but the back of the card drawn, but cards in the scrapyard would need to be kept to be drawn in case a player has a card that allows them to do stuff with the scrapyard or if a player wants to see what all is in a scrapyard.
  14. Not sure what you mean by the texture formats as I'm new to textures and drawing. Do you mean like the file format or something with when I declare the texture that will hold the image?
  15. Thanks braindigitalis as I couldn't figure out how to get the code to show up as code so it was less obnoxious.
  16. I want to be able to scale the texture down so it doesn't take up as much memory is the reason that I'm trying to scale the texture down from the render target and storing it in a texture. If I do not the memory taken by each card will be 2100x1480x4/1024/1024 = 11.856 MB per card and when my game is going to have 6 players able to play at once each with upto 100 cards that could not be duplicates, thats now 11.856 MB * 100 * 6 = 7113.6 MB   That is the reason that I need to be able to scale the texture down, not for being drawn but for storage reasons.   Also I don't have any clue how to format the code on this site to show up as code so its easily read.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!