Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (580)
games submitted by our members
Games in WIP (500)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Wait for network input thread to receive vector  (Read 656 times)
0 Members and 1 Guest are viewing this topic.
Offline cheeseburgers

Senior Newbie





« Posted 2012-10-26 21:26:58 »

Hi!

I have a multi-threaded server waiting for incoming connections. When a client connects, an input and an output thread are created to handle I/O to that client. The server's output thread starts to send a Vector<Tank> to the client.

The client, when constructed, joins the server and creates a thread to handle all input coming from the server. The thread starts when constructed and waits for the Vector<Tank> to be sent. After joining, the client creates a GameBoard, giving it a reference to the input thread. The GameBoard, when constructed, tries to retrieve the Vector<Tank> from the input thread.

The issue is, the GameBoard is constructed before the input thread can receive the Vector<Tank>. I need the GameBoard constructor to wait for the input thread to receive it's first update of the vector, or have the client wait for the thread to receive it before constructing the GameBoard. I hope this makes sense!

If there's an easier solution to this mess, then please tell me. Also, if you notice anything else that's wrong or could be better, don't hesitate to mention it. Thanks! Smiley

-CLIENT-
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
package tw.client;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;


public class Client implements ActionListener {

   // Frame
  private               JFrame      frame      = null;
   public static final    int       W_WIDTH    = 800;
   public static final    int       W_HEIGHT    = 600;
   private               JButton      joinButton   = null;
   
   // Network
  private static final    int             PORT    = 2720;
   private               Socket            socket   = null;
   private                InputThread       input   = null;
   private               DataOutputStream    output   = null;
   
   // Game loop and game board
  private static final    int       FRAMES_PER_SECOND    = 25;
   private static final    int       SKIP_TICKS         = 1000 / FRAMES_PER_SECOND;  
   private             GameBoard    gameBoard;
   private             boolean    running          = true;
     
   
   /**
    * Client constructor.
    * Initializes a frame, game board and network connection.
    */

   public Client() {      
      // Initialize the frame
     frame = new JFrame("Tank Wars - Client");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(W_WIDTH, W_HEIGHT);
      frame.setLocationRelativeTo(null);      
      frame.setResizable(false);
      frame.setVisible(true);        
     
      // Initialize network connection
     joinServer();
     
      // Add game board to frame
     gameBoard = new GameBoard(input, output);
      //gameBoard.setVisible(false);      
     frame.add(gameBoard);
      gameBoard.requestFocusInWindow();
     
      // Start game loop
     run();
     
      // Initialize join button
     /*joinButton = new JButton("Join");
      joinButton.setActionCommand("Join");
      joinButton.addActionListener(this);
      frame.getContentPane().add(joinButton);*/

   }
   
   @Override
   public void actionPerformed(ActionEvent e) {
      if (e.getActionCommand() == "Join") {
         //client.joinServer();
        joinButton.setEnabled(false);
         joinButton.setVisible(false);
         gameBoard.setVisible(true);
         frame.validate();
         
         // Start game loop
        run();
      }      
   }
   
   /**
    * Starts the game loop.
    */

   private void run() {
      // While client is not connected to server
     /*while (!client.isConnected()) {
         System.out.println("Client not connected to server.");
      }*/

     
      long nextGameTick = System.nanoTime() / 1000000;
      long sleepTime;
     
      while (running) {
         gameBoard.updateGame();
         gameBoard.repaint();
         
         nextGameTick += SKIP_TICKS;
         sleepTime = nextGameTick - System.nanoTime() / 1000000;

         if (sleepTime > 0) {
            try {
               Thread.sleep(sleepTime);
            }
            catch(Exception e){
               e.getStackTrace();
            }
         } // if
     } // while
  } // run
 
   /**
    * When called, establishes connection to server.
    */

   public void joinServer() {
      try {
         // Open socket to server
        System.out.println("Initializing ...");
         InetAddress addr = InetAddress.getLocalHost();
         socket = new Socket(addr, PORT);
         System.out.println("The new socket: " + socket);
         
         // Initialize I/O
        input = new InputThread(socket);
         output = new DataOutputStream(socket.getOutputStream());
         
      } catch(Exception e) {
         e.printStackTrace();
      }
   }  
   
   /**
    * Stops the game loop.
    */

   public void stop() {
      running = false;
   }
   
   /**
    * MAIN METHOD
    * @param args
    */

   public static void main(String[] args) {
      new Client();
   }
}



-InputThread-
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
package tw.client;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.Vector;

import tw.Projectile;
import tw.Tank;


public class InputThread extends Thread {
   
   private    ObjectInputStream    in               = null;
   private    boolean          running            = true;
   
   private      int               playerNr         = 0;
   private    Vector<Tank>      updatedTanks      = null;
   private      Vector<Projectile>   updatedProjectiles    = null;        
   
   
   /**
    * ClientThread constructor.
    */

   public InputThread(Socket socket) {
      // Initialize input stream
     try {
         in = new ObjectInputStream(socket.getInputStream());
      } catch (IOException e) {
         e.printStackTrace();
      }
     
      // Initialize empty tank vector
     updatedTanks = new Vector<Tank>();
     
      start();
   }  
   
   
   /**
    * Run method, called when thread is started.
    */

   @SuppressWarnings("unchecked")
   public void run() {
     
      // Receive player number from server
     try {
         playerNr = in.readInt();
         System.out.println("playerNr " + playerNr);
      } catch (IOException e1) {
         e1.printStackTrace();
      }
     
         // Receive current turn and entity vector
        try {
            while (running) {
               updatedTanks = (Vector<Tank>) in.readObject();
            }
         }
         catch (IOException e) {
            e.printStackTrace();  
         }
         catch (ClassNotFoundException e) {
            e.printStackTrace();
         }
   } // run  
 
   
   /**
    * Sets 'running' to 'false', stopping the input loop.
    */

   public void stopRunning() {
      running = false;
   }
   
   
   /**
    * Getter of the property <tt>playerNr</tt>
    * @return Returns playerNr
    * @uml.property name="playerNr"
    */

   public int getPlayerNr() {
      return playerNr;
   }
   
   
   /**
    * Getter of the property (vector) <tt>updatedEntitites</tt>
    * @return  Returns the updatedEntities vector.
    * @uml.property  name="updatedEntities"
    */

   public Vector<Tank> getUpdatedTanks() {      
      return updatedTanks;
   }
}



-GameBoard-
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
package tw.client;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Vector;

import javax.swing.JComponent;

import tw.Projectile;
import tw.Tank;


/**
 * .
 */

public class GameBoard extends JComponent implements KeyListener {
   
   // Network
  private InputThread         input      = null;
   private DataOutputStream    output       = null;
   
   // Status panel
  private StatusPanel       statusPanel   = null;
   
   // Players and entities
  private int               playerNr   = 0;
   private Vector<Tank>       tanks      = null;
   private Vector<Projectile>   projectiles   = null;
   private Tank            pTank      = null;
   
   
   /**
    * GameBoard constructor.
    * @param client
    */

   public GameBoard(InputThread input, DataOutputStream output) {
      // Give access to input thread and output stream
     this.input = input;
      this.output = output;
     
      // Setup panel
     setFocusable(true);
      setBackground(Color.LIGHT_GRAY);
      setDoubleBuffered(true);
      setSize(Client.W_WIDTH, Client.W_HEIGHT);

      // Setup key listener
     addKeyListener(this);
      //setFocusTraversalKeysEnabled(false);
     
      // Get playerNr and tanks from server
     playerNr = input.getPlayerNr();
      tanks = input.getUpdatedTanks();
     
      // Set pTank to tank matching playerNr
     for (int i = 0; i < tanks.size(); i++)
         if (tanks.get(i).getPlayerNr() == playerNr)
            pTank = tanks.get(i);      
     
      // Initialize status panel
     statusPanel = new StatusPanel(pTank, playerNr);
      add(statusPanel);
      this.revalidate();
   }
   
   
   /**
    * Update logic
    */

   public void updateGame() entitieset updated entities
      tanks = input.getUpdatedTanks();
     
      // Get playerNr of currently active tank
     int activeTank = 0;
      for (int i = 0; i < tanks.size(); i++)
         if (tanks.get(i).isActive())
            activeTank = tanks.get(i).getPlayerNr();
     
      // Update status panel
     statusPanel.update(activeTank);
   }
   
   
   /**
    * Render entities
    */

   public void paintComponent(Graphics g) {
      // Clear off-screen bitmap
     super.paintComponent(g);
     
      // Cast to Graphics2D for more options
     Graphics2D g2d = (Graphics2D) g;
     
      // If there are entities in the entity vector and they are alive, draw those entities
     if (tanks != null) {
         for (int i = 0; i < tanks.size(); i++) {
            if (tanks.get(i).isAlive())
               tanks.get(i).draw(g2d);
         }
      }
   }
   
   
   
   ////////////////////////////
  // - HANDLING KEY INPUT - //
  ////////////////////////////
 
   /**
    * Key input - when key is pressed.
    */

   public void keyPressed(KeyEvent e) {
      int key = e.getKeyCode();
     
      if (pTank.isActive())
         if (key == KeyEvent.VK_UP || key == KeyEvent.VK_DOWN || key == KeyEvent.VK_LEFT || key == KeyEvent.VK_RIGHT) {
            try {
               output.writeInt(key);
               System.out.println("Client output: " + key);
            }
            catch (IOException e1) {
               e1.printStackTrace();
            }            
         }
         
   }
   
   /**
    * Key input - when key is released.
    */

   public void keyReleased(KeyEvent e) {
      int key = e.getKeyCode();
     
      if (pTank.isActive())
         if (key == KeyEvent.VK_SPACE)
            try {            
               output.writeInt(key);
               System.out.println("Client output: " + key);
            }
            catch (IOException e1) {
               e1.printStackTrace();
            }
   }
   
   public void keyTyped(KeyEvent e) {
      // do nothing
  }
}
Offline sproingie
« Reply #1 - Posted 2012-10-26 21:40:54 »

I need the GameBoard constructor to wait for the input thread

No, you really really don't, trust me.  Making constructors block on threads just puts you in a world of pain. Wait for the Vector<Tank> to be created (use any synchronization primitive that's handy -- I'm a fan of BlockingQueue), then pass it as a parameter to GameBoard's constructor.


Offline cheeseburgers

Senior Newbie





« Reply #2 - Posted 2012-10-26 21:54:46 »

Wait for the Vector<Tank> to be created (use any synchronization primitive that's handy -- I'm a fan of BlockingQueue), then pass it as a parameter to GameBoard's constructor.

meaning
Quote
have the client wait for the thread to receive it before constructing the GameBoard.
right?

I'd hoped to keep Client clean of Vector<Tank> and all the other things that are going to be sent through the socket by giving GameBoard direct access to the input thread.

I've never used BlockingQueue before, but I'll read up on it and see what I can come up with. In the meantime, all hints are appreciated! ;-)
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 605
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #3 - Posted 2012-10-26 22:04:57 »

1  
2  
3  
- if (e.getActionCommand() == "Join") {

+ if (e.getActionCommand().equals("Join")) {


You are checking whether two references refer to the same object, which is not the same as equality of what the objects represent:

1  
2  
3  
String a = "hi";
String b = "HI".toLowerCase();
// a != b, a.equals(b)==true
as 'a' and 'b' are different objects, both holding the text 'hi'.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline cheeseburgers

Senior Newbie





« Reply #4 - Posted 2012-10-30 22:31:07 »

The server doesn't seem to send the updated version of the tanks vector to the client. After receiving it the first time, the vector on the client side remains the same.

http://pastebin.com/dUBb4WM4 <-- write/readObject

I changed the code from write/readObject to write/readUnshared. Unfortunately, it's still not working.

http://pastebin.com/UrqMCBNy <-- write/readUnshared

(Output at the bottom)

What am I doing wrong?
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (51 views)
2014-04-15 18:08:23

BurntPizza (48 views)
2014-04-15 03:46:01

UprightPath (63 views)
2014-04-14 17:39:50

UprightPath (45 views)
2014-04-14 17:35:47

Porlus (62 views)
2014-04-14 15:48:38

tom_mai78101 (86 views)
2014-04-10 04:04:31

BurntPizza (146 views)
2014-04-08 23:06:04

tom_mai78101 (243 views)
2014-04-05 13:34:39

trollwarrior1 (202 views)
2014-04-04 12:06:45

CJLetsGame (209 views)
2014-04-01 02:16:10
List of Learning Resources
by SHC
2014-04-18 03:17:39

List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!