project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/netplay/Netconn.java
author Medo <smaxein@googlemail.com>
Thu, 19 Jul 2012 18:58:18 +0200
changeset 7342 0e29eec2df5c
parent 7332 3f2e130f9715
child 7349 12fdfd2038d4
permissions -rw-r--r--
Hedgeroid: Got the roomlist working... more or less.

package org.hedgewars.hedgeroid.netplay;

import java.io.File;
import java.io.IOException;

import org.hedgewars.hedgeroid.Utils;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.IntStrCallback;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.MetaschemePtr;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.NetconnPtr;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomArrayPtr;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomCallback;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomListCallback;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.RoomPtr;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrCallback;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrRoomCallback;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.StrStrCallback;
import org.hedgewars.hedgeroid.netplay.JnaFrontlib.VoidCallback;

import com.sun.jna.Pointer;

import android.content.Context;
import android.util.Log;

/**
 * Java-wrapper for the C netconn type. Apart from turning netconn into a more Java-like
 * object with methods, this also handles some of the problems of C <-> Java interop (e.g.
 * ensuring that callback objects don't get garbage collected).
 */
public class Netconn {
	private static final JnaFrontlib FLIB = Flib.INSTANCE;
	private static final String DEFAULT_SERVER = "140.247.62.101";
	private static final int DEFAULT_PORT = 46631;
	
	private NetconnPtr conn;
	private String playerName;
	
	public final PlayerList playerList = new PlayerList();
	public final RoomList roomList = new RoomList();
	public final MessageLog lobbyLog;
	public final MessageLog roomLog;
	
	private StrCallback lobbyJoinCb = new StrCallback() {
		public void callback(Pointer context, String arg1) {
			playerList.addPlayerWithNewId(arg1);
			lobbyLog.appendPlayerJoin(arg1);
		}
	};
	
	private StrStrCallback lobbyLeaveCb = new StrStrCallback() {
		public void callback(Pointer context, String name, String msg) {
			playerList.remove(name);
			lobbyLog.appendPlayerLeave(name, msg);
		}
	};
	
	private StrStrCallback chatCb = new StrStrCallback() {
		public void callback(Pointer context, String name, String msg) {
			getCurrentLog().appendChat(name, msg);
		}
	};
	
	private IntStrCallback messageCb = new IntStrCallback() {
		public void callback(Pointer context, int type, String msg) {
			getCurrentLog().appendMessage(type, msg);
		}
	};
	
	private RoomCallback roomAddCb = new RoomCallback() {
		public void callback(Pointer context, RoomPtr roomPtr) {
			roomList.addRoomWithNewId(roomPtr);
		}
	};
	
	private StrRoomCallback roomUpdateCb = new StrRoomCallback() {
		public void callback(Pointer context, String name, RoomPtr roomPtr) {
			roomList.updateRoom(name, roomPtr);
		}
	};
	
	private StrCallback roomDeleteCb = new StrCallback() {
		public void callback(Pointer context, String name) {
			roomList.remove(name);
		}
	};
	
	private VoidCallback connectedCb = new VoidCallback() {
		public void callback(Pointer context) {
			// TODO I guess more needs to happen here...
			FLIB.flib_netconn_send_request_roomlist(conn);
		}
	};
	
	private RoomListCallback roomlistCb = new RoomListCallback() {
		public void callback(Pointer context, RoomArrayPtr arg1, int count) {
			roomList.clear();
			for(RoomPtr roomPtr : arg1.getRooms(count)) {
				roomList.addRoomWithNewId(roomPtr);
			}
		}
	};
	
	/**
	 * Connect to the official Hedgewars server.
	 * 
	 * @throws IOException if the metascheme file can't be read or the connection to the server fails
	 */
	public Netconn(Context context, String playerName) throws IOException {
		this(context, playerName, DEFAULT_SERVER, DEFAULT_PORT);
	}
	
	/**
	 * Connect to the server with the given hostname and port
	 * 
	 * @throws IOException if the metascheme file can't be read or the connection to the server fails
	 */
	public Netconn(Context context, String playerName, String host, int port) throws IOException {
		if(playerName == null) {
			playerName = "Player";
		}
		this.playerName = playerName;
		this.lobbyLog = new MessageLog(context);
		this.roomLog = new MessageLog(context);
		
		MetaschemePtr meta = null;
		File dataPath = Utils.getDataPathFile(context);
		try {
			String metaschemePath = new File(dataPath, "metasettings.ini").getAbsolutePath();
			meta = FLIB.flib_metascheme_from_ini(metaschemePath);
			if(meta == null) {
				throw new IOException("Missing metascheme");
			}
			conn = FLIB.flib_netconn_create(playerName, meta, dataPath.getAbsolutePath(), host, port);
			if(conn == null) {
				throw new IOException("Unable to connect to the server");
			}
			FLIB.flib_netconn_onLobbyJoin(conn, lobbyJoinCb, null);
			FLIB.flib_netconn_onLobbyLeave(conn, lobbyLeaveCb, null);
			FLIB.flib_netconn_onChat(conn, chatCb, null);
			FLIB.flib_netconn_onMessage(conn, messageCb, null);
			FLIB.flib_netconn_onRoomAdd(conn, roomAddCb, null);
			FLIB.flib_netconn_onRoomUpdate(conn, roomUpdateCb, null);
			FLIB.flib_netconn_onRoomDelete(conn, roomDeleteCb, null);
			FLIB.flib_netconn_onConnected(conn, connectedCb, null);
			FLIB.flib_netconn_onRoomlist(conn, roomlistCb, null);
		} finally {
			FLIB.flib_metascheme_release(meta);
		}
	}
	
	public void disconnect() {
		if(conn != null) {
			FLIB.flib_netconn_send_quit(conn, "User quit");
			FLIB.flib_netconn_destroy(conn);
			conn = null;
		}
	}
	
	public void tick() {
		FLIB.flib_netconn_tick(conn);
	}
	
	public void sendChat(String s) {
		FLIB.flib_netconn_send_chat(conn, s);
		if(FLIB.flib_netconn_is_in_room_context(conn)) {
			roomLog.appendChat(playerName, s);
		} else {
			lobbyLog.appendChat(playerName, s);
		}
	}
	
	private MessageLog getCurrentLog() {
		if(FLIB.flib_netconn_is_in_room_context(conn)) {
			return roomLog;
		} else {
			return lobbyLog;
		}
	}
	
	public void sendNick(String nick) { FLIB.flib_netconn_send_nick(conn, nick); }
	public void sendPassword(String password) { FLIB.flib_netconn_send_password(conn, password); }
	public void sendQuit(String message) { FLIB.flib_netconn_send_quit(conn, message); }
	public void sendRoomlistRequest() { FLIB.flib_netconn_send_request_roomlist(conn); }
	
	public boolean isConnected() {
		return conn != null;
	}
	
	@Override
	protected void finalize() throws Throwable {
		if(conn != null) {
			FLIB.flib_netconn_destroy(conn);
			Log.e("Netconn", "Leaked Netconn object");
		}
	}
}