Files
PTS3/app/src/main/java/com/iutlaval/myapplication/Game/GameLogicThread.java
T
2021-01-09 13:07:27 +01:00

578 lines
22 KiB
Java

package com.iutlaval.myapplication.Game;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.Toast;
import com.iutlaval.myapplication.Game.Cards.Card;
import com.iutlaval.myapplication.Game.Cards.CardRegistery;
import com.iutlaval.myapplication.GameActivity;
import com.iutlaval.myapplication.MainActivity;
import com.iutlaval.myapplication.PopupRunable;
import com.iutlaval.myapplication.R;
import com.iutlaval.myapplication.Video.Drawables.DrawableBitmap;
import com.iutlaval.myapplication.Video.Drawables.DrawableCard;
import com.iutlaval.myapplication.Video.Drawables.DrawableSelfRemoving;
import com.iutlaval.myapplication.Video.Drawables.DrawableText;
import com.iutlaval.myapplication.Video.Renderer;
import com.iutlaval.myapplication.exception.UnrecognizedCard;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.OptionalDataException;
import java.lang.reflect.Constructor;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
public class GameLogicThread extends Thread{
public static final float BUTTON_Y_POS = 45F;
public static final int BUTTON_X_POS = 0;
public static final float BUTTON_X_SIZE = 20F;
public static final float BUTTON_Y_SIZE = 10F;
public static final String BUTTONTURN_DRAWABLE_NAME = "buttonturn";
private Context cont;
private Renderer renderer;
private boolean ready;
private TouchHandler touch;
private GameActivity gameActivity;
private NetworkDeck deck;
private Hand hand;
private Board board;
private boolean isYourMainPhase;
private boolean isYourBattlePhase;
private boolean cancelled;
private String deckName;
private int mana=0;
private Communication coms;
//ces variable permette la comunication avec le thread android du tactile et le reseau en passant par ce thread
//cette variable controle la demande de gestion de placement de carte
private boolean requestPlaceCardDone =true;
//cette variable controle la demande de gestion de l'attaque
boolean requestAttackDone = true;
private DrawableCard requestDrawableCard =null;
private int requestCardZone =-1;
private boolean requestPlaceCardResult;
//si mise a true alors le thread va envoyer un message au serveur lui disant de passer a la phase suivante
private boolean requestEnd = false;
public GameLogicThread(GameActivity gameActivity, String deckName, Renderer renderer)
{
this.deckName=deckName;
Log.e("RESOLUTION:",""+GameActivity.screenWidth+"x"+GameActivity.screenHeight);
ready=false;
this.cont = gameActivity;
this.renderer = renderer;
board=new Board();
touch = new TouchHandler(renderer,this,gameActivity);
hand = new Hand();
this.gameActivity=gameActivity;
GameActivity.setGameEngine(this);
isYourMainPhase =false;
cancelled=false;
isYourBattlePhase=false;
}
@Override
public void run() {
//pickDeck();
//loading textures
Log.i("ressources","loading bitmaps");
Bitmap bitmapYourTurn = BitmapFactory.decodeResource(renderer.getResources(),R.drawable.t_pb_your_turn);
Bitmap bitmapEnemyTurn = BitmapFactory.decodeResource(renderer.getResources(),R.drawable.t_pb_enemy_turn);
Bitmap bitmapBattlePhase = BitmapFactory.decodeResource(renderer.getResources(),R.drawable.t_pb_battlephase);
Bitmap bitmapButtonEnd = BitmapFactory.decodeResource(renderer.getResources(),R.drawable.t_btn_boutonfintour);
Bitmap bitmapVictory = BitmapFactory.decodeResource(cont.getResources(), R.drawable.t_pb_victory);
Bitmap bitmapDefeat = BitmapFactory.decodeResource(cont.getResources(), R.drawable.t_pb_defeat);
Log.i("loading","prefs");
SharedPreferences sharedPref = gameActivity.getSharedPreferences("handicape",Context.MODE_PRIVATE);
boolean modeHandicape = sharedPref.getBoolean(gameActivity.getString(R.string.handicape), false);
Bitmap bitmapBackground;
if(!modeHandicape)
{
bitmapBackground = BitmapFactory.decodeResource(cont.getResources(), R.drawable.t_b_board_background);
}else{
bitmapBackground = BitmapFactory.decodeResource(cont.getResources(), R.drawable.t_b_board_background_handicapted);
}
Log.i("ressources","base ressources loaded");
//adding the background
renderer.addToDraw(new DrawableBitmap(bitmapBackground, 0,0, "background", 100, 100 ));
ready=true;
final String host = "2.tcp.ngrok.io";//192.168.43.251tcp://2.tcp.ngrok.io:
final int port = 17057;
//gameativity.finish() n'etait pas utilisable il fermais l'application
//on fait trois essay de connection
for(int i = 0 ; i < 3 ; i++)
{
try {
Socket client = new Socket(host, port);
coms= new Communication(client);
//connection reussie
break;
} catch (IOException e) {}
}
//si la connection a échouer on print un log + un toast
if(coms == null)
{
Log.e("ERROR SERVER DEAD","srv");
gameActivity.runOnUiThread(new PopupRunable("erreur de comunication avec le serveur",gameActivity));
//on arette le moteur de rendu
renderer.terminate();
//et on retourne la 'activité precedente
returnToTheMainActivity();
return;
}
renderer.updateFrame();
//principe de fonctionnement : on attends une comande du server et on l'execute
//si quelquechose se passe alors c'est le server qu'il l'a dit
while(ready && !cancelled)
{
if(!requestPlaceCardDone && requestCardZone != -1 && requestDrawableCard != null)
{
try {//on allonge le delais car sinon on skip l'autorisation serveur
coms.setUnlimitedTimeOut();
} catch (SocketException e) {}
requestPlaceCardResult = onCardPlayed(requestDrawableCard, requestCardZone);
requestCardZone =-1;
requestDrawableCard =null;
Log.e("request","done");
requestPlaceCardDone =true;
}
if(!requestAttackDone && requestCardZone != -1 && requestDrawableCard != null)
{
int zoneAttaquant = board.getCardZone(requestDrawableCard);
try {
coms.send(Command.ATTACK);
coms.send(zoneAttaquant);
coms.send(requestCardZone);
} catch (IOException e) {
e.printStackTrace();
}
requestAttackDone=true;
}
if(requestEnd)
{
try {
Log.e("TURN","PASSED");
coms.send(Command.PASS_TURN);
} catch (IOException e) {
e.printStackTrace();
}
requestEnd=false;
isYourBattlePhase=false;
}
try {
int zonecartecible;
//on limite le temps du readobject pour eviter les blockaeg
coms.setLimitedTimeOut();
String serveurCmd = coms.recieve();
coms.setUnlimitedTimeOut();
if(!serveurCmd.equals("timeout"))Log.e("command",serveurCmd);
switch (serveurCmd)
{
case Command.GET_DECK:
coms.send(deckName);
String deckstr = coms.recieve();
deck = new NetworkDeck(deckstr,gameActivity.getBaseContext());
Log.e("got deck",deckstr);
break;
case Command.DRAW:
int nbcard = coms.recieveInt();
hand.pickCardFromDeck(deck,nbcard);
Log.e("picked",nbcard+"card");
drawHandPreview();
break;
case Command.YOURTURN:
isYourMainPhase =true;
isYourBattlePhase=false;
renderer.addToDrawWithoutUpdate(new DrawableSelfRemoving(new DrawableBitmap(bitmapYourTurn,0,0,"yourTurn",100F,50F),1));
renderer.addToDraw(new DrawableBitmap(bitmapButtonEnd, BUTTON_X_POS, BUTTON_Y_POS, BUTTONTURN_DRAWABLE_NAME, BUTTON_X_SIZE, BUTTON_Y_SIZE));
break;
case Command.SETMANA:
renderer.removeToDrawWithoutUpdate("mana");
mana = coms.recieveInt();
renderer.addToDraw(new DrawableText("Mana : "+mana,85F,60F,"mana",13.3F,6.65F,20, 100,30,Color.WHITE));
break;
case Command.ENEMYTURN:
isYourMainPhase =false;
renderer.removeToDraw(BUTTONTURN_DRAWABLE_NAME);
renderer.removeToDraw("battlePhase");
renderer.addToDraw(new DrawableSelfRemoving(new DrawableBitmap(bitmapEnemyTurn,0,0,"enemyTurn",100F,50F),1));
break;
case Command.POPUP:
String recivedMessage = coms.recieve();
gameActivity.runOnUiThread(new PopupRunable(recivedMessage,gameActivity));
Log.e("popup",recivedMessage);
break;
case Command.WIN:
//on termine la parite
gameActivity.runOnUiThread(new PopupRunable("bravo ! vous avez gagné",gameActivity));
renderer.addToDraw(new DrawableBitmap(bitmapVictory,0,0,"victory",100F,50F));
renderer.updateFrame();
cancelled = true;
currentThread().sleep(2000);
returnToTheMainActivity();
break;
case Command.LOSE:
//on termine la partie
gameActivity.runOnUiThread(new PopupRunable("vous avez perdu!",gameActivity));
renderer.addToDraw(new DrawableBitmap(bitmapDefeat,0,0,"defeat",100F,50F));
renderer.updateFrame();
cancelled=true;
currentThread().sleep(2000);
//gameativity.finish() n'etait pas utilisable il fermais l'application
returnToTheMainActivity();
break;
case Command.PING:
coms.send(Command.PONG);
break;
case Command.UPDATE:
renderer.updateFrame();
case Command.PUT_ENEMY_CARD:
int cardId = coms.recieveInt();
int zone = coms.recieveInt();
//on instancie la carte recu
Class<? extends Card> c = CardRegistery.get(cardId);
Constructor con = c.getConstructor(String.class, Context.class);
Card cardPlayed = (Card) con.newInstance("enemy"+zone,gameActivity);
cardPlayed.getDrawableCard().setOnBoard(true);
//ajout de la carte au rendu
cardPlayed.getDrawableCard().setCoordinates(((DrawableCard.getCardWith()+1)*zone+20),10F);
renderer.addToDraw(cardPlayed.getDrawableCard());
//ajout la card au terain
cardPlayed.getDrawableCard().setDraggable(false);
board.setEnemyCard(zone,cardPlayed);
break;
case Command.MEULE:
//la carte pioché va être perdu vu que l'on ne la met pas dans une main
//c'est le role de la command meule de faire perde des cartes au joeur
int nbmeule = coms.recieveInt();
deck.draw(nbmeule);
break;
case Command.BATTLE:
renderer.addToDraw(new DrawableSelfRemoving(new DrawableBitmap(bitmapBattlePhase,0,0,"battlePhase",100F,50F),1));
isYourBattlePhase=true;
isYourMainPhase=false;
break;
case Command.DESTROY_CARD:
//detruit la carte sur le terrain du joueur
int zoneOfTheDestroyedCard = coms.recieveInt();
Card cardToDestroy = board.removeCardOnPlayerBoard(zoneOfTheDestroyedCard);
renderer.removeToDraw(cardToDestroy);
break;
case Command.DESTROY_ADV_CARD:
//detruit la carte sur le terrain du joueur adverse
int zoneOfTheDestroyedEnemyCard = coms.recieveInt();
Card enemyCardToDestroy = board.removeCardOnEnemyPlayerBoard(zoneOfTheDestroyedEnemyCard);
renderer.removeToDraw(enemyCardToDestroy);
break;
case Command.SET_ENEMY_HP:
renderer.removeToDrawWithoutUpdate("advHp");
renderer.addToDraw(new DrawableText(" Hp : " + coms.recieve(),1F,10F,"advHp",13.3F,6.65F,20, 100,30,Color.WHITE));
break;
case Command.SET_HP:
renderer.removeToDrawWithoutUpdate("playerHp");
renderer.addToDraw(new DrawableText(" Hp : " + coms.recieve(),85F,80F,"playerHp",13.3F,6.65F,20, 100,30,Color.WHITE));
break;
case Command.SET_CARD_HP :
zonecartecible = coms.recieveInt();
int health = coms.recieveInt();
if(board.getPlayerCardsOnBoard()[zonecartecible] == null)
{
Log.e("erro card",""+zonecartecible);
coms.recieveInt();
}else{
board.getPlayerCardsOnBoard()[zonecartecible].setHealth(health);
}
renderer.updateFrame();
break;
case Command.SET_ADV_CARD_HP:
zonecartecible = coms.recieveInt();
if(board.getAdvCardsOnBoard()[zonecartecible] == null)
{
Log.e("erro card",""+zonecartecible);
}
board.getAdvCardsOnBoard()[zonecartecible].setHealth(coms.recieveInt());
renderer.updateFrame();
break;
case Command.SET_CARD_ATK:
zonecartecible = coms.recieveInt();
board.getPlayerCardsOnBoard()[zonecartecible].setAttack(coms.recieveInt());
renderer.updateFrame();
break;
case Command.SET_ADV_CARD_ATK:
zonecartecible = coms.recieveInt();
board.getAdvCardsOnBoard()[zonecartecible].setAttack(coms.recieveInt());
renderer.updateFrame();
break;
case "timeout":
//ceci est une erreur et non une commande elle se doit donc de ne rien faire
break;
default:
Log.e("UNKOWN COMMAND",serveurCmd);
}
}catch (SocketTimeoutException e){}
catch (InterruptedIOException e)
{
if(e.getStackTrace().length != 0)
{
e.printStackTrace();
Log.e("Stopping","dead thread");
}
}catch(IOException e)
{
}
catch (Exception e) {
Log.e("ERROR DURING COMS","SERVER DIED");
e.printStackTrace();
if(e instanceof OptionalDataException)
{
System.out.println(((OptionalDataException)e).eof);
}
break;
}
}
}
private void returnToTheMainActivity() {
gameActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(gameActivity,MainActivity.class);
//on reset le top et recrée l'activité principale
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
gameActivity.startActivity(intent);
}
});
}
/**
* cette methode permet d'afficher la main
*/
private void drawHandPreview() {
int i = 0;
for(Card c : hand.getHand())
{
renderer.addToDraw(c.getDrawableCard());
renderer.moveToDraw(i* DrawableCard.getCardWith(),90F,c.getDrawableCard().getName());
i++;
}
}
/**
* cette evenement est appelé indirectement par la fonction request onCardPlayed et permet d'envoyer au serveur le fait qu'un carte a été jouer
* CE CODE CONTIEN DE l'ACCES RESEAU QUI N'APPARTIEN QU'A CE THREAD IS DOIT RESTER PRIVE
* @param card la carte jouer
* @param zone ou elle a été joué sur le terrain
* @return retourne si la carte a put être jouer
*/
private boolean onCardPlayed(DrawableCard card,int zone)
{
if(isYourMainPhase)
{
try {
//on veut jouer une carte
coms.send(Command.PUT_CARD);
//on lui dit quelle carte on veut
int cardId = CardRegistery.indexOf(card.getCard());
if (cardId == -1) {
coms.send("CLIENT REGISTRY ERROR");
throw new UnrecognizedCard();
}
coms.send(cardId);
coms.send(zone);
if (coms.recieve().equals(Command.OK)) {
board.setCard(zone, card.getCard());
hand.removeCard(card.getCard());
return true;
}
}catch (Exception e)
{
e.printStackTrace();
}
}
return false;
}
protected synchronized boolean setOnCardPlayedRequest(DrawableCard card,int zone)
{
Log.e("request","recived");
//on ne peut pas avoir 2 requette simultané
while(!requestPlaceCardDone)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) { }
}
this.requestDrawableCard =card;
this.requestCardZone =zone;
requestPlaceCardDone =false;
//on attends la fin de la requette
while(!requestPlaceCardDone) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return requestPlaceCardResult;
}
public synchronized boolean setOnCardAttackRequest(DrawableCard card, int zoneCible) {
if(zoneCible == -1 || zoneCible != 100 && board.getAdvCardsOnBoard()[zoneCible] == null
|| card.getCard().getAttack() == 0)
{
return false;
}
//on ne peut pas avoir 2 requette simultané
while(!requestAttackDone) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.requestCardZone =zoneCible;
this.requestDrawableCard=card;
requestAttackDone =false;
//on attends la fin de la requette
while(!requestAttackDone) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return true;
}
/**
* retourne vrai sir le moteur est pret a avoir sont evenemnt onFrameDoneRendering d'appeler
* @return
*/
public boolean isReady() {
return ready;
}
/**
* délegue l'evenement directement au touch Handler
* @param event
*/
public void onTouchEvent(MotionEvent event) {
if(isReady())touch.onTouchEvent(event);
}
public boolean isYourMainPhase() {
return isYourMainPhase;
}
public Board getBoard() {
return board;
}
/**
* cette fonction a pour rôle de kill le thread
* vu que Thread.destroy() est déprecier c'est la seul methode possible;
*/
public void terminate() {
ready=false;
try {
if(coms != null)coms.close();
} catch (IOException e) {}
cancelled=true;
interrupt();
}
/**
* déclanche une demande de debut de tours
*/
public void requestEndTurn() {
if(isYourMainPhase || isYourBattlePhase)
{
requestEnd=true;
}else{
Toast t = new Toast(gameActivity);
t.setText("IT'S NOT YOUR TURN BE PATIENT");
t.setDuration(Toast.LENGTH_SHORT);
t.show();
}
}
public boolean isYourBattlePhase() {
return isYourBattlePhase;
}
}