Skip to content

Commit

Permalink
add Networking to proj3 for remote game sharing
Browse files Browse the repository at this point in the history
  • Loading branch information
BorenTsai authored and czar committed Oct 26, 2024
1 parent 9bc32d2 commit 73b7087
Show file tree
Hide file tree
Showing 2 changed files with 292 additions and 0 deletions.
160 changes: 160 additions & 0 deletions proj3/byow/Networking/BYOWClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package byow.Networking;

import edu.princeton.cs.introcs.StdDraw;

import java.awt.*;
import java.io.*;
import java.net.Socket;
import java.nio.file.Paths;
import java.util.Scanner;

/**
* Created by Boren Tsai and Arjun Sahai.
*/

public class BYOWClient {
private int width;
private int height;

private Socket clientStringSocket;
private Socket clientReadSocket;
private BufferedWriter out;
private BufferedReader in;
private DataInputStream dis;

static public final String CANVAS_FILE = ".client_canvas";

static final String canvasPath = join(new File(System.getProperty("user.dir")), CANVAS_FILE).getAbsolutePath();
static int magic = Integer.MIN_VALUE;

/*
Open socket, input/output streams, and create buffered writer & data input streams.
*/
public void startConnection(String ip, int port) throws IOException {
clientReadSocket = new Socket(ip, port);
clientStringSocket = new Socket(ip, port);
dis = new DataInputStream(clientReadSocket.getInputStream());
out = new BufferedWriter(new OutputStreamWriter(clientStringSocket.getOutputStream()));
in = new BufferedReader(new InputStreamReader(clientStringSocket.getInputStream()));
}

/*
Check that the server has acknowledged that it is quitting in a nonblocking fasion
*/
private boolean shouldClose() throws IOException {
if (in.ready()) {
char[] buf = new char[4];
in.read(buf, 0, 4); // block client
System.out.println(String.copyValueOf(buf));
return true;
}
return false;
}

/*
Close reader and writer then close socket.
*/
private void stopConnection() throws IOException {
dis.close();
out.close();
clientReadSocket.close();
clientStringSocket.close();
}

/*
Non Blocking
Sends a String Command to the server i.e. W, A, S, D, etc.
*/
private void sendCommand(String msg) throws IOException {
out.write(msg);
out.flush();
}

/*
Blocking
Displays a canvas if the server has sent the client something to read
i.e. The server has sent a png file to the client
*/
private void showCanvas() throws IOException {
if (dis.available() > 0) {
boolean configure = dis.readBoolean();
if (configure) {
System.out.println("CONFIGURING CANVAS");
width = dis.readInt();
height = dis.readInt();
StdDraw.setCanvasSize(width, height);
StdDraw.setXscale(0, width);
StdDraw.setYscale(0, height);
StdDraw.clear(new Color(0, 0, 0));
StdDraw.enableDoubleBuffering();
StdDraw.show();
}

StdDraw.clear();

File newFile = new File(canvasPath + magic + ".png");
File oldFile = new File(canvasPath + (magic - 1) + ".png");

FileOutputStream fos = new FileOutputStream(newFile);

// wait for incoming file size
long size = dis.readLong();

int bytes;
byte[] buffer = new byte[4 * 1024];
while (size > 0 && (bytes = dis.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
fos.write(buffer, 0, bytes);
size -= bytes;
}
// Write all buffered bytes into the file
fos.flush();

StdDraw.picture(width / 2, height / 2, canvasPath + magic + ".png");
magic = magic + 1;

oldFile.delete();
StdDraw.show();
}
}

private static File join(File first, String... others) {
return Paths.get(first.getPath(), others).toFile();
}


public static void main(String[] args) throws IOException {
System.out.println("BYOW Client. Please Enter the following information to connect to a server...");
Scanner scanner = new Scanner(System.in);
System.out.print("IP Address: ");
String ip = scanner.next();
System.out.print("Port (this must be a number): ");
int port = scanner.nextInt();

BYOWClient client = new BYOWClient();
client.startConnection(ip, port); //ip port changes depending on link supplied by ngrok
client.showCanvas();
char command;

try {
while (true) {
if (StdDraw.hasNextKeyTyped()) {
command = StdDraw.nextKeyTyped();
client.sendCommand(Character.toString(command));
}
client.showCanvas();
StdDraw.clear();
if (client.shouldClose()) {
client.stopConnection();
System.exit(0);
}
}
} catch (java.net.SocketException e) {
client.stopConnection();
System.out.println("Disconnected from server");
System.exit(0);
}
client.stopConnection();
System.out.println("Disconnected from server");
System.exit(0);
}
}
132 changes: 132 additions & 0 deletions proj3/byow/Networking/BYOWServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package byow.Networking;

import edu.princeton.cs.introcs.StdDraw;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Paths;

/**
* Created by Arjun Sahai and Boren Tsai.
*/

public class BYOWServer {

static private final File CWD = new File(System.getProperty("user.dir"));
static private final String CANVAS_FILE = ".server_canvas.png";

private ServerSocket serverSocket;
private Socket clientStringSocket;
private Socket clientWriteSocket;

private BufferedReader in;
private BufferedWriter out;
private DataOutputStream dos;

public BYOWServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
System.out.println("Server started. Waiting for client to connect... ");
clientWriteSocket = serverSocket.accept(); // block until client connects
clientStringSocket = serverSocket.accept();
in = new BufferedReader(new InputStreamReader(clientStringSocket.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(clientStringSocket.getOutputStream()));
dos = new DataOutputStream(clientWriteSocket.getOutputStream());
System.out.println("Client connected!");
}

public void sendCanvasConfig(int width, int height) {
sendCanvas(width, height, true);
}

public void sendCanvas() {
sendCanvas(0, 0, false);
}

/*
This method will check to see if the client is sending a key press to the server
This will not block your code
*/
public boolean clientHasKeyTyped() {
try {
return in.ready();
} catch (IOException e) {
stopConnection();
return false;
}
}

/*
Gives the next character sent from the client.
If the client has not sent anything yet, then this method will block
*/
public char clientNextKeyTyped() {
try {
return (char) in.read();
} catch (IOException e) {
System.out.println("IO EXCEPTION CAUGHT");
stopConnection();
return 'q';
}
}

/*
Closes all input/output streams and sockets.
*/
public void stopConnection() {
try {
out.write("QUIT");
out.flush();
in.close();
dos.close();
clientStringSocket.close();
clientWriteSocket.close();
serverSocket.close();
} catch (IOException e) {
return;
}
}

/*
Sends world bitmap and, optionally, StdDraw canvas configuration metadata.
*/
private void sendCanvas(int width, int height, boolean sendConfig) {
try {
dos.writeBoolean(sendConfig);

if (sendConfig) {
dos.writeInt(width);
dos.writeInt(height);
dos.flush();
} else {
dos.flush();
}


// Save the canvas to a PNG file
StdDraw.save(CANVAS_FILE);
File canvas = join(CWD, CANVAS_FILE);

// Send file size and unblock client from waiting
dos.writeLong(canvas.length());
dos.flush();

FileInputStream fis = new FileInputStream(canvas);

// break file into chunks and send to client
int bytes;
byte[] buffer = new byte[4 * 1024];
while ((bytes = fis.read(buffer)) != -1) {
dos.write(buffer, 0, bytes);
dos.flush();
}
fis.close();
} catch (IOException e) {
stopConnection();
}
}

private static File join(File first, String... others) {
return Paths.get(first.getPath(), others).toFile();
}
}

0 comments on commit 73b7087

Please sign in to comment.