diff --git a/app/src/main/java/com/simplecoil/simplecoil/FullscreenActivity.java b/app/src/main/java/com/simplecoil/simplecoil/FullscreenActivity.java index f7f86ba..7c14219 100644 --- a/app/src/main/java/com/simplecoil/simplecoil/FullscreenActivity.java +++ b/app/src/main/java/com/simplecoil/simplecoil/FullscreenActivity.java @@ -259,6 +259,12 @@ private class LastHitData { private long mLastShotFired = 0; // to reduce shots fired message spam private long mLastHitMessage = 0; // to reduce hit/out message spam + // Grenade stuff + private static final byte GRENADE_DAMAGE = (byte) 0x01; + private static final byte GRENADE_NEW_PAIR = (byte) 0x0E; + private static final byte GRENADE_PAIR_ID = (byte) 0x0F; + private static final byte GRENADE_DISARM = (byte) 0x0D; + /* We run a continuous handler in the background while the tagger is connected to monitor the connection status. Simply put, we set connectionTestHandler to false every time the handler runs. Every time we receive telemetry data, we set connectionTestHandler back to true. When @@ -2066,35 +2072,74 @@ else if (averageBattery >= BATTERY_LEVEL_PISTOL_YELLOW) // Only the right-most 3 bits make up the shot ID byte shot_id1 = (byte)(data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0x07); byte shot_id2 = (byte)(data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0x07); - /*Log.e(TAG, "Hit by " + hit_by_player1); - if (hit_by_player2 != 0) { - Log.e(TAG, "hitdata: " + hit_by_player1 + " " + Integer.toHexString(data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0xFF) + " " + hit_by_player2 + " " + Integer.toHexString(data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0xFF)); + //Log.e(TAG, "Hit by " + hit_by_player1); + /*if (hit_by_player2 != 0) { + Log.e(TAG, "hitdata: " + Integer.toHexString(hit_by_player1) + " " + Integer.toHexString(data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0xFF) + " " + Integer.toHexString(hit_by_player2) + " " + Integer.toHexString(data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0xFF)); } else { - Log.e(TAG, "hitdata: " + hit_by_player1 + " " + Integer.toHexString(data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0xFF)); + Log.e(TAG, "hitdata: " + Integer.toHexString(hit_by_player1) + " " + Integer.toHexString(data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0xFF)); }*/ + if (hit_by_player1 == Globals.GRENADE_PLAYER_ID && (data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0x0F) != GRENADE_DAMAGE) { + if ((data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0x0F) == GRENADE_PAIR_ID) { + // This is a grenade trying to pair + if (Globals.getInstance().mPairedGrenadeID == 0) { + Globals.getInstance().mPairedGrenadeID = (byte)((data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0xF0) >> 4); + if (mUseNetwork && mTcpClient.isDedicatedServer()) + mTcpClient.sendPlayerGrenade(); + Toast.makeText(getApplicationContext(), getString(R.string.grenade_paired_toast), Toast.LENGTH_SHORT).show(); + } + } else if ((data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0x0F) == GRENADE_NEW_PAIR || (data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0x0F) == GRENADE_DISARM) { + Globals.getInstance().mPairedGrenadeID = 0; + } + } + if (hit_by_player2 == Globals.GRENADE_PLAYER_ID && (data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0x0F) != GRENADE_DAMAGE) { + if ((data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0x0F) == GRENADE_PAIR_ID) { + // This is a grenade trying to pair + if (Globals.getInstance().mPairedGrenadeID == 0) { + Globals.getInstance().mPairedGrenadeID = (byte)((data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0xF0) >> 4); + if (mUseNetwork && mTcpClient.isDedicatedServer()) + mTcpClient.sendPlayerGrenade(); + Toast.makeText(getApplicationContext(), getString(R.string.grenade_paired_toast), Toast.LENGTH_SHORT).show(); + } + } else if ((data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0x0F) == GRENADE_NEW_PAIR || (data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0x0F) == GRENADE_DISARM) { + Globals.getInstance().mPairedGrenadeID = 0; + } + } if (Globals.getInstance().mGameState != Globals.GAME_STATE_NONE) { if ((mLastHitData1.playerID == hit_by_player1 && mLastHitData1.shotID == shot_id1) || (mLastHitData2.playerID == hit_by_player1 && mLastHitData2.shotID == shot_id1)) { //Log.e(TAG, "Hit by 1 is using same shot ID from a previous hit, filter!" + hit_by_player1 + " " + data[RECOIL_OFFSET_HIT_BY1_SHOTID]); } else { - mHitsTaken++; - String hitsTaken = "" + mHitsTaken; - mHitsTakenTV.setText(hitsTaken); - healthRemoved = Globals.DAMAGE_PER_HIT; - if (mUseNetwork) { - hit_by_id = (byte) (hit_by_player1 >> 2); - //Log.d(TAG, "hit by 1 ID is " + hit_by_id); - if ((hit_by_player1 != Globals.GRENADE_PLAYER_ID) && Globals.getInstance().mGameMode != Globals.GAME_MODE_FFA && Globals.getInstance().calcNetworkTeam(hit_by_id) == mNetworkTeam) { - //Log.d(TAG, "friendly fire ignored"); - healthRemoved = 0; - } else { - if (Globals.getInstance().mPlayerSettings.get(hit_by_id) != null) - healthRemoved = Globals.getInstance().mPlayerSettings.get(hit_by_id).damage; - if (mLastHitMessage < System.currentTimeMillis()) { - mLastHitMessage = System.currentTimeMillis() + HIT_ANIMATION_DURATION_MILLISECONDS; - if (mHealth + healthRemoved > 0) - mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_HIT, hit_by_id); - else - mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_OUT, hit_by_id); + if (hit_by_player1 == Globals.GRENADE_PLAYER_ID && (data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0x0F) != GRENADE_DAMAGE) { + // Ignore non-damage events from grenades + } else { + mHitsTaken++; + String hitsTaken = "" + mHitsTaken; + mHitsTakenTV.setText(hitsTaken); + healthRemoved = Globals.DAMAGE_PER_HIT; + if (mUseNetwork) { + hit_by_id = (byte) (hit_by_player1 >> 2); + //Log.d(TAG, "hit by 1 ID is " + hit_by_id); + if ((hit_by_player1 != Globals.GRENADE_PLAYER_ID) && Globals.getInstance().mGameMode != Globals.GAME_MODE_FFA && Globals.getInstance().calcNetworkTeam(hit_by_id) == mNetworkTeam) { + //Log.d(TAG, "friendly fire ignored"); + healthRemoved = 0; + } else { + if (hit_by_player1 == Globals.GRENADE_PLAYER_ID) { + int grenadeID = (data[RECOIL_OFFSET_HIT_BY1_SHOTID] & 0xF0) >> 4; + if (grenadeID != 0) { + Globals.getmGrenadePairingsSemaphore(); + if (Globals.getInstance().mGrenadePairings[grenadeID] != Globals.INVALID_PLAYER_ID) + hit_by_id = (byte)Globals.getInstance().mGrenadePairings[grenadeID]; + Globals.getInstance().mGrenadePairingsSemaphore.release(); + } + } + if (Globals.getInstance().mPlayerSettings.get(hit_by_id) != null) + healthRemoved = Globals.getInstance().mPlayerSettings.get(hit_by_id).damage; + if (mLastHitMessage < System.currentTimeMillis()) { + mLastHitMessage = System.currentTimeMillis() + HIT_ANIMATION_DURATION_MILLISECONDS; + if (mHealth + healthRemoved > 0) + mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_HIT, hit_by_id); + else + mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_OUT, hit_by_id); + } } } } @@ -2102,22 +2147,35 @@ else if (averageBattery >= BATTERY_LEVEL_PISTOL_YELLOW) if ((mLastHitData1.playerID == hit_by_player2 && mLastHitData1.shotID == shot_id2) || (mLastHitData2.playerID == hit_by_player2 && mLastHitData2.shotID == shot_id2)) { //Log.e(TAG, "Hit by 2 is using same shot ID from a previous hit, filter!"); } else if (hit_by_player2 != 0 && mHealth + healthRemoved > 0) { - healthRemoved += Globals.DAMAGE_PER_HIT; - if (mUseNetwork) { - hit_by_id = (byte)(hit_by_player1 >> 2); - //Log.d(TAG, "hit by 2 ID is " + hit_by_id); - if ((hit_by_player2 != Globals.GRENADE_PLAYER_ID) && Globals.getInstance().mGameMode != Globals.GAME_MODE_FFA && Globals.getInstance().calcNetworkTeam(hit_by_id) == mNetworkTeam) { - //Log.d(TAG, "friendly fire ignored"); - healthRemoved -= Globals.DAMAGE_PER_HIT; - } else { - if (Globals.getInstance().mPlayerSettings.get(hit_by_id) != null) - healthRemoved += Globals.getInstance().mPlayerSettings.get(hit_by_id).damage; - if (mLastHitMessage < System.currentTimeMillis()) { - mLastHitMessage = System.currentTimeMillis() + HIT_ANIMATION_DURATION_MILLISECONDS; - if (mHealth + healthRemoved > 0) - mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_HIT, hit_by_id); - else - mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_OUT, hit_by_id); + if (hit_by_player2 == Globals.GRENADE_PLAYER_ID && (data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0x0F) != GRENADE_DAMAGE) { + // Ignore non-damage events from grenades + } else { + healthRemoved += Globals.DAMAGE_PER_HIT; + if (mUseNetwork) { + hit_by_id = (byte) (hit_by_player1 >> 2); + //Log.d(TAG, "hit by 2 ID is " + hit_by_id); + if ((hit_by_player2 != Globals.GRENADE_PLAYER_ID) && Globals.getInstance().mGameMode != Globals.GAME_MODE_FFA && Globals.getInstance().calcNetworkTeam(hit_by_id) == mNetworkTeam) { + //Log.d(TAG, "friendly fire ignored"); + healthRemoved -= Globals.DAMAGE_PER_HIT; + } else { + if (hit_by_player2 == Globals.GRENADE_PLAYER_ID) { + int grenadeID = (data[RECOIL_OFFSET_HIT_BY2_SHOTID] & 0xF0) >> 4; + if (grenadeID != 0) { + Globals.getmGrenadePairingsSemaphore(); + if (Globals.getInstance().mGrenadePairings[grenadeID] != Globals.INVALID_PLAYER_ID) + hit_by_id = (byte)Globals.getInstance().mGrenadePairings[grenadeID]; + Globals.getInstance().mGrenadePairingsSemaphore.release(); + } + } + if (Globals.getInstance().mPlayerSettings.get(hit_by_id) != null) + healthRemoved += Globals.getInstance().mPlayerSettings.get(hit_by_id).damage; + if (mLastHitMessage < System.currentTimeMillis()) { + mLastHitMessage = System.currentTimeMillis() + HIT_ANIMATION_DURATION_MILLISECONDS; + if (mHealth + healthRemoved > 0) + mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_HIT, hit_by_id); + else + mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_OUT, hit_by_id); + } } } } @@ -2180,10 +2238,12 @@ public void run() { eliminatedBy = Globals.getInstance().getPlayerName(hit_by_id); startSpawn(eliminatedBy); if (mUseNetwork) { - if (mTcpClient.isDedicatedServer()) - mTcpClient.sendTCPMessage(TcpServer.TCPMESSAGE_PREFIX + TcpServer.TCPPREFIX_MESG + NetMsg.NETMSG_ELIMINATED + hit_by_id, true); - else - mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_ELIMINATED, hit_by_id); + if (hit_by_id != Globals.getInstance().mPlayerID && Globals.getInstance().calcNetworkTeam(hit_by_id) != Globals.getInstance().calcNetworkTeam(Globals.getInstance().mPlayerID)) { + if (mTcpClient.isDedicatedServer()) + mTcpClient.sendTCPMessage(TcpServer.TCPMESSAGE_PREFIX + TcpServer.TCPPREFIX_MESG + NetMsg.NETMSG_ELIMINATED + hit_by_id, true); + else + mUDPListenerService.sendUDPMessage(NetMsg.NETMSG_ELIMINATED, hit_by_id); + } if (mHasLivesLimit && mEliminationCount <= 0) { if (mTcpClient.isDedicatedServer()) mTcpClient.sendTCPMessage(TcpServer.TCPMESSAGE_PREFIX + TcpServer.TCPPREFIX_MESG + NetMsg.NETMSG_LEAVE); diff --git a/app/src/main/java/com/simplecoil/simplecoil/Globals.java b/app/src/main/java/com/simplecoil/simplecoil/Globals.java index 45ff5da..2d9eff1 100644 --- a/app/src/main/java/com/simplecoil/simplecoil/Globals.java +++ b/app/src/main/java/com/simplecoil/simplecoil/Globals.java @@ -94,11 +94,16 @@ public class Globals { public volatile Map mGPSData; public volatile Map mPlayerSettings; + public static final int MAX_GRENADE_IDS = 16; + public volatile byte mPairedGrenadeID = 0; + public volatile int[] mGrenadePairings; + public Semaphore mIPTeamMapSemaphore; public Semaphore mTeamIPMapSemaphore; public Semaphore mTeamPlayerNameSemaphore; public Semaphore mGPSDataSemaphore; public Semaphore mPlayerSettingsSemaphore; + public Semaphore mGrenadePairingsSemaphore; public volatile boolean mUseGPS = false; public volatile boolean mOnlyServerSettings = false; @@ -121,6 +126,8 @@ public static synchronized Globals getInstance(){ mInstance.mTeamPlayerNameSemaphore = new Semaphore(1); mInstance.mGPSDataSemaphore = new Semaphore(1); mInstance.mPlayerSettingsSemaphore = new Semaphore(1); + mInstance.mGrenadePairingsSemaphore = new Semaphore(1); + mInstance.mGrenadePairings = new int[MAX_GRENADE_IDS]; } return mInstance; } @@ -266,6 +273,24 @@ public static void getmPlayerSettingsSemaphore() { } } + public static void getmGrenadePairingsSemaphore() { + try { + getInstance().mGrenadePairingsSemaphore.acquire(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public static void ClearGrenadePairings(boolean getSemaphore) { + if (getSemaphore) + getmGrenadePairingsSemaphore(); + for (int index = 0; index < MAX_GRENADE_IDS; index++) { + getInstance().mGrenadePairings[index] = Globals.INVALID_PLAYER_ID; + } + if (getSemaphore) + getInstance().mGrenadePairingsSemaphore.release(); + } + public static class PlayerSettings { int health = Globals.MAX_HEALTH; byte shots = Globals.RELOAD_COUNT; diff --git a/app/src/main/java/com/simplecoil/simplecoil/TcpClient.java b/app/src/main/java/com/simplecoil/simplecoil/TcpClient.java index 2eebddd..103f18e 100644 --- a/app/src/main/java/com/simplecoil/simplecoil/TcpClient.java +++ b/app/src/main/java/com/simplecoil/simplecoil/TcpClient.java @@ -289,6 +289,8 @@ private void sendPlayerInfo(boolean rejoin) { } catch (JSONException e) { e.printStackTrace(); } + if (Globals.getInstance().mPairedGrenadeID != 0) + sendPlayerGrenade(); } public void sendPlayerSettings() { @@ -315,6 +317,18 @@ public void sendPlayerSettings() { } } + public void sendPlayerGrenade() { + try { + JSONObject playerGrenade = new JSONObject(); + playerGrenade.put(TcpServer.JSON_PLAYERID, (int) Globals.getInstance().mPlayerID); + playerGrenade.put(TcpServer.JSON_PAIRED_GRENADE_ID, (int) Globals.getInstance().mPairedGrenadeID); + String message = TcpServer.TCPMESSAGE_PREFIX + TcpServer.TCPPREFIX_JSON + playerGrenade.toString(); + sendTCPMessage(message); + } catch (JSONException e) { + e.printStackTrace(); + } + } + public void stopTcpClient() { if (mIsDedicatedServer) sleep(75); // Make sure that the end game message gets sent before we close down the socket @@ -341,8 +355,22 @@ private void parseGameInfo(String message) { boolean gotGPSSemaphore = false; boolean gotPlayerSemaphores = false; boolean gotPlayerSettingsSemaphore = false; + boolean gotGrenadePairingsSemaphore = false; try { JSONObject game = new JSONObject(message); + if (game.has(TcpServer.JSON_GRENADE_PAIRINGS)) { + Globals.getmGrenadePairingsSemaphore(); + gotGrenadePairingsSemaphore = true; + Globals.ClearGrenadePairings(false); + JSONArray grenadePairings = game.getJSONArray(TcpServer.JSON_GRENADE_PAIRINGS); + for (int x = 0; x < grenadePairings.length(); x++) { + JSONObject grenadePairing = grenadePairings.getJSONObject(x); + Globals.getInstance().mGrenadePairings[grenadePairing.getInt(TcpServer.JSON_PAIRED_GRENADE_ID)] = grenadePairing.getInt(TcpServer.JSON_PLAYERID); + } + gotGrenadePairingsSemaphore = false; + Globals.getInstance().mGrenadePairingsSemaphore.release(); + return; + } if (game.has(TcpServer.JSON_GPSUPDATE)) { JSONArray updates = game.getJSONArray(TcpServer.JSON_GPSUPDATE); Globals.getmGPSDataSemaphore(); @@ -516,6 +544,7 @@ private void parseGameInfo(String message) { } if (gotGPSSemaphore) Globals.getInstance().mGPSDataSemaphore.release(); if (gotPlayerSettingsSemaphore) Globals.getInstance().mPlayerSettingsSemaphore.release(); + if (gotGrenadePairingsSemaphore) Globals.getInstance().mGrenadePairingsSemaphore.release(); } } diff --git a/app/src/main/java/com/simplecoil/simplecoil/TcpServer.java b/app/src/main/java/com/simplecoil/simplecoil/TcpServer.java index 27e2405..009e2b4 100644 --- a/app/src/main/java/com/simplecoil/simplecoil/TcpServer.java +++ b/app/src/main/java/com/simplecoil/simplecoil/TcpServer.java @@ -76,6 +76,8 @@ public class TcpServer extends Service { public static final String JSON_TEAM = "team"; public static final String JSON_GAMESTATE = "gamestate"; public static final String JSON_ONLY_SERVER_SETTINGS = "onlyserversettings"; + public static final String JSON_PAIRED_GRENADE_ID = "pairedgrenadeID"; + public static final String JSON_GRENADE_PAIRINGS = "grenadepairings"; public static final String JSON_GPSLONGITUDE = "gpslongitude"; public static final String JSON_GPSLATITUDE = "gpslatitude"; @@ -276,6 +278,7 @@ public void run() { Globals.getmIPTeamMapSemaphore(); Globals.getInstance().mIPTeamMap.clear(); Globals.getInstance().mIPTeamMapSemaphore.release(); + Globals.getInstance().mPairedGrenadeID = Globals.INVALID_PLAYER_ID; sendBroadcast(new Intent(NetMsg.NETMSG_ENDGAME)); } }); @@ -563,6 +566,7 @@ private void runTcpServer() { Globals.getInstance().mGPSData = new HashMap<>(); else Globals.getInstance().mGPSData.clear(); + Globals.ClearGrenadePairings(true); keepListening = true; ServerSocket ss = null; int clientID = 0; @@ -835,6 +839,37 @@ public void run() { mClientDataSemaphore.release(); } + private void sendGrenadePairings(boolean getSemaphore) { + boolean has_data = false; + if (getSemaphore) + Globals.getmGrenadePairingsSemaphore(); + try { + JSONArray grenadePairings = new JSONArray(); + for (int index = 1; index < Globals.MAX_GRENADE_IDS; index++) { + if (Globals.getInstance().mGrenadePairings[index] != Globals.INVALID_PLAYER_ID) { + has_data = true; + JSONObject grenadePairing = new JSONObject(); + grenadePairing.put(JSON_PLAYERID, Globals.getInstance().mGrenadePairings[index]); + grenadePairing.put(JSON_PAIRED_GRENADE_ID, index); + grenadePairings.put(grenadePairing); + } + } + if (getSemaphore) + Globals.getInstance().mGrenadePairingsSemaphore.release(); + getSemaphore = false; // don't release the semaphore in the exception clause if we fail after this point + if (has_data) { + JSONObject data = new JSONObject(); + data.put(JSON_GRENADE_PAIRINGS, grenadePairings); + String message = TCPMESSAGE_PREFIX + TCPPREFIX_JSON + data.toString(); + sendTCPMessageAll(message); + } + } catch (JSONException e) { + if (getSemaphore) + Globals.getInstance().mGrenadePairingsSemaphore.release(); + e.printStackTrace(); + } + } + private void parsePlayerInfo(String message, ClientData client) { JSONObject player; try { @@ -843,6 +878,17 @@ private void parsePlayerInfo(String message, ClientData client) { e.printStackTrace(); return; } + if (player.has(JSON_PAIRED_GRENADE_ID)) { + Globals.getmGrenadePairingsSemaphore(); + try { + Globals.getInstance().mGrenadePairings[player.getInt(JSON_PAIRED_GRENADE_ID)] = player.getInt(JSON_PLAYERID); + } catch (JSONException e) { + e.printStackTrace(); + } + sendGrenadePairings(false); + Globals.getInstance().mGrenadePairingsSemaphore.release(); + return; + } if (player.has(JSON_GPSLONGITUDE)) { Globals.getmGPSDataSemaphore(); Globals.GPSData gps = Globals.getInstance().mGPSData.get(client.mPlayerID); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f12c12c..82ac60f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -100,6 +100,7 @@ Pistol Detected! Rifle Detected! + Grenade Paired! Dedicated Server DedicatedServerActivity