package com.chughes.dip.game; import java.util.Date; import java.util.List; import java.util.Map; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Async; import org.springframework.social.connect.Connection; import org.springframework.social.connect.ConnectionFactory; import org.springframework.social.connect.ConnectionFactoryLocator; import org.springframework.social.connect.ConnectionRepository; import org.springframework.social.connect.UsersConnectionRepository; import org.springframework.social.facebook.api.Facebook; import org.springframework.social.facebook.api.GraphApi; import org.springframework.social.facebook.api.OpenGraphOperations; import org.springframework.social.facebook.api.impl.FacebookTemplate; import org.springframework.social.facebook.connect.FacebookAdapter; import org.springframework.social.facebook.connect.FacebookConnectionFactory; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import com.chughes.dip.game.GameEntity.Stage; import com.chughes.dip.misc.Mailer; import com.chughes.dip.misc.PushNotifier; import com.chughes.dip.user.UserEntity; import com.chughes.dip.user.UserService; import dip.gui.order.GUIOrderFactory; import dip.process.Adjustment; import dip.process.Adjustment.AdjustmentInfoMap; import dip.process.StdAdjudicator; import dip.world.Phase.PhaseType; import dip.world.Power; import dip.world.TurnState; @Service public class Judge { private static final int ACCEPTABLE_MISSES = 3; private @Autowired GameService gs; protected @Autowired SessionFactory sessionFactory; protected @Autowired Mailer mailer; private @Autowired Facebook facebookApp; private @Autowired UsersConnectionRepository ucr; private @Autowired UserService us; private @Autowired PushNotifier pn; private static final Logger logger = LoggerFactory.getLogger(Judge.class); @Transactional @Async public void advanceGame(GameEntity ge){ if (!ge.isCrashed()){ try{ //Adjudicate orders StdAdjudicator stdJudge = new StdAdjudicator(new GUIOrderFactory(), ge.getW().getLastTurnState()); stdJudge.process(); TurnState ts = stdJudge.getNextTurnState(); if (ts != null){ ge.getW().setTurnState(ts); sessionFactory.getCurrentSession().save(ts); } //End Game if Victory Occurs if (ge.getW().getLastTurnState().isEnded()){ endGame(ge); }else{ updateInfo(ge); } sessionFactory.getCurrentSession().update(ge.getW()); //Fixed a problem with too much memory being used. sessionFactory.getCurrentSession().flush(); sessionFactory.getCurrentSession().clear(); }catch(Exception e){ ge.setCrashed(true); e.printStackTrace(); } } } @Transactional public void endGame(GameEntity ge){ ge.setStage(Stage.ENDED); ge.setPhase("Ended"); AdjustmentInfoMap info = Adjustment.getAdjustmentInfo(ge.getW().getLastTurnState(), ge.getW().getRuleOptions(), ge.getW().getMap().getPowers()); int total = ge.getW().getLastTurnState().getPosition().getOwnedSupplyCenters().length; for (UserGameEntity player : ge.getPlayers()) { int owned = info.get(ge.getW().getMap().getPower(player.getPower())).getSupplyCenterCount(); player.setVictory_share(((float)owned)/((float)total)); //Adds to score if (ge.isTournament()){ player.getUser().setRoundgamesplayed(player.getUser().getRoundgamesplayed()+1); player.getUser().setScore((int) (.75 * player.getUser().getScore() + 25 * owned/total)); us.updateLevel(player.getUser()); } if (owned > 0) { player.getUser().setWins(player.getUser().getWins()+1); }else { player.getUser().setLosses(player.getUser().getLosses()+1); } sessionFactory.getCurrentSession().update(player.getUser()); } sessionFactory.getCurrentSession().saveOrUpdate(ge); } @Transactional public void updateInfo(GameEntity game) { game.setPhase(game.getW().getLastTurnState().getPhase().toString()); for (UserGameEntity player : game.getPlayers()) { player.setOrderable(true); if (!player.isReady()){ player.setMissed(player.getMissed()+1); if (player.getMissed() > ACCEPTABLE_MISSES){ gs.removeUserFromGame(game, player.getUser()); } } Power power = game.getW().getMap().getPower(player.getPower()); int supply = game.getW().getLastTurnState().getPosition().getOwnedSupplyCenters(power).length; //System.out.println(game.getW().getMap().getPower(player.getPower())); player.setSupply_centers(supply); if (!player.getUser().getUsername().equals("EMPTY")){ player.setReady(false); try{ //Email Notify mailer.newphase(player.getUser().getEmail(), game.getName()); //Facebook Notify ConnectionRepository cr = ucr.createConnectionRepository(player.getUser().getId()+""); List<Connection<Facebook>> fb = cr.findConnections(Facebook.class); if (fb.size() == 1){ MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>(); map.set("href", "game/"+game.getId()); map.set("template", "Your game titled '"+game.getName()+"' has advanced to the next phase."); String uri = GraphApi.GRAPH_API_URL + fb.get(0).getKey().getProviderUserId() + "/notifications"; Map<String, Object> result = facebookApp.restOperations().postForObject(uri, map, Map.class); if (!result.containsKey("success")){ System.out.println("Facebook returned: "+result.get("message")); } } //Android Notify for (String reg:player.getUser().getAndroidApps()){ pn.push(reg, game.getName(), game.getId()); } }catch (Exception e){ e.printStackTrace(); } //Determine players that have no Orders to give if (game.getW().getLastTurnState().getPosition().getUnitProvinces(power).length == 0 && game.getW().getLastTurnState().getPhase().getPhaseType() == PhaseType.MOVEMENT){ player.setOrderable(false); player.setReady(true); }else if (game.getW().getLastTurnState().getPhase().getPhaseType() == PhaseType.ADJUSTMENT && supply == game.getW().getLastTurnState().getPosition().getUnitProvinces(power).length){ player.setOrderable(false); player.setReady(true); }else if (game.getW().getLastTurnState().getPhase().getPhaseType() == PhaseType.RETREAT && game.getW().getLastTurnState().getPosition().getDislodgedUnitProvinces(power).length == 0){ player.setOrderable(false); player.setReady(true); } } } sessionFactory.getCurrentSession().saveOrUpdate(game); } @Transactional public void cron() { Query q = sessionFactory.getCurrentSession().createQuery("from GameEntity where turnend < current_timestamp() and stage= 'PLAYING'"); List<GameEntity> list = q.list(); for (GameEntity ge : list){ //TODO:This still leaves the possibility for game to be processed twice //Determine next phase end if (ge.getTurnlength() != 0){ long milis = new Date().getTime() + (60L * 60L * 1000L * ge.getTurnlength()); Date end = new Date(milis); ge.setTurnend(end); }else{ ge.setTurnend(null); } //System.out.println("Opening game "+ge.getId()+" for Processing"); advanceGame(ge); } } }