Compare commits

..

16 Commits

Author SHA1 Message Date
Calum c0bd498f1b Added debugs for missing xml 2017-09-27 02:50:36 +13:00
Calum b18d9e8573 Added empty cucumber
#test
2017-09-27 02:04:58 +13:00
Calum e9881bb24a Added per map max player count. Handles case when map cannot fit players behind start mark. Added initial implementation for spacing out yachts.
#implement  #story[1275]
2017-09-27 02:04:24 +13:00
Calum ab5ad58237 Merge branch 'develop' into story1275_host_customization
# Conflicts:
#	src/main/java/seng302/visualiser/GameView3D.java
2017-09-26 23:37:59 +13:00
Calum df7264cc1f Added per map max player count. Handles case when map cannot fit players behind start mark. Added initial implementation for spacing out yachts.
#implement.
2017-09-26 23:34:19 +13:00
Calum e990c68d40 #document 2017-09-26 01:12:43 +13:00
Calum 83871a0336 Fixed boat trials rendering abnormally
#issue[65] #fix
2017-09-26 01:07:02 +13:00
Calum 6cba024d64 Made changes to the shape of boat trials. 2017-09-26 00:59:04 +13:00
Calum 51747e2d13 Refactored the 2D and 3D game view class setups. Made scaling more logical.
#refactor #story[1275]
2017-09-26 00:55:28 +13:00
Calum b3981b19e0 Merge branch 'develop' into story1275_host_customization
# Conflicts:
#	src/main/java/seng302/gameServer/GameState.java
#	src/main/java/seng302/gameServer/ServerToClientThread.java
#	src/main/java/seng302/model/ServerYacht.java
#	src/main/java/seng302/visualiser/ClientToServerThread.java
#	src/main/java/seng302/visualiser/controllers/LobbyController.java
#	src/test/java/seng302/models/YachtTest.java
2017-09-25 23:25:33 +13:00
Calum 3d7a64068f Fixed scaling issues.
#fix
2017-09-25 23:19:03 +13:00
Calum c12f7408ad experimenting with map scaling
#implement
2017-09-25 22:57:45 +13:00
Calum 35b50d1436 Refactored 2d game view distance calculations to better size and sale the map,
#implement #refactor #story[1275]
2017-09-25 21:06:18 +13:00
Calum 9b00ba654a Added a race importer. Added imported races to visualizer. Made it so that the host sets the race. Refactored server to no longer be dependant on a specific race. Tested functionality of map manually. Some bugs found and listed below.
#implement #testmanual #story[1275]

Known bugs:
 * Can't move
 * Map is off center in lobby view.
 * 3D Map is off center
2017-09-23 22:45:53 +12:00
Calum 6ca75b2cac Changed default race 2017-09-21 15:08:39 +12:00
Calum 40a7f9bc5b New server creation view created. Added templates for custom races. Updated xml generator to remove all hard coded values. Updated XMLParser to parse custom race files. No unit tests exists currently.
#implement #story[1275]
2017-09-21 12:59:37 +12:00
82 changed files with 2060 additions and 3559 deletions
+111 -300
View File
@@ -9,15 +9,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import java.util.Set; import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.BoatStatus; import seng302.gameServer.messages.BoatStatus;
import seng302.gameServer.messages.ChatterMessage; import seng302.gameServer.messages.ChatterMessage;
@@ -36,11 +30,10 @@ import seng302.model.ServerYacht;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.mark.MarkOrder; import seng302.model.mark.MarkOrder;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType; import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.RandomSpawn;
import seng302.utilities.XMLParser;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
/** /**
@@ -58,100 +51,90 @@ public class GameState implements Runnable {
private static Logger logger = LoggerFactory.getLogger(GameState.class); private static Logger logger = LoggerFactory.getLogger(GameState.class);
private static final Integer STATE_UPDATES_PER_SECOND = 60;
//Scheduling constants
static final int WARNING_TIME = 10 * -1000; static final int WARNING_TIME = 10 * -1000;
static final int PREPATORY_TIME = 5 * -1000; static final int PREPATORY_TIME = 5 * -1000;
private static final int TIME_TILL_START = 10 * 1000; private static final int TIME_TILL_START = 10 * 1000;
//Wind Constants private static final Long POWERUP_TIMEOUT_MS = 10_000L;
private static final int MAX_WIND_SPEED = 12000;
private static final int MIN_WIND_SPEED = 8000;
//Rounding Constants private static final Integer STATE_UPDATES_PER_SECOND = 60;
private static final Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further private static Double ROUNDING_DISTANCE = 50d; // TODO: 14/08/17 wmu16 - Look into this value further
//Collision constants
private static final Double MARK_COLLISION_DISTANCE = 15d; private static final Double MARK_COLLISION_DISTANCE = 15d;
public static final Double YACHT_COLLISION_DISTANCE = 25.0; public static final Double YACHT_COLLISION_DISTANCE = 25.0;
private static final Double BOUNCE_DISTANCE_MARK = 20.0; private static final Double BOUNCE_DISTANCE_MARK = 20.0;
public static final Double BOUNCE_DISTANCE_YACHT = 30.0; public static final Double BOUNCE_DISTANCE_YACHT = 30.0;
private static final Double COLLISION_VELOCITY_PENALTY = 0.3; private static final Double COLLISION_VELOCITY_PENALTY = 0.3;
//Powerup Constants
public static final Double VELOCITY_BOOST_MULTIPLIER = 2d;
public static final Integer HANDLING_BOOST_MULTIPLIER = 2;
private static final Double BAD_RANDOM_SPEED_PENALTY = 0.3;
public static final Long BUMPER_DISABLE_TIME = 5_000L;
private static final Long TOKEN_SPAWN_TIME = 30_000L;
private static Long previousUpdateTime; private static Long previousUpdateTime;
public static Double windDirection; public static Double windDirection;
private static Double windSpeed; private static Double windSpeed;
private static Double serverSpeedMultiplier; private static Double speedMultiplier = 1d;
private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat. private static Boolean customizationFlag; // dirty flag to tell if a player has customized their boat.
private static Boolean playerHasLeftFlag; private static Boolean playerHasLeftFlag;
private static String hostIpAddress;
private static List<Player> players; private static List<Player> players;
private static Map<Integer, ServerYacht> yachts; private static Map<Integer, ServerYacht> yachts;
private static Boolean isRaceStarted; private static Boolean isRaceStarted;
private static GameStages currentStage; private static GameStages currentStage;
private static MarkOrder markOrder; private static MarkOrder markOrder;
private static long startTime; private static long startTime;
private static List<Mark> marks; private static Set<Mark> marks;
private static List<Limit> courseLimit; private static List<Limit> courseLimit;
private static Integer maxPlayers = 8; private static Integer maxPlayers = 8;
private static List<Token> allTokens;
private static List<Token> tokensInPlay; private static List<Token> tokensInPlay;
private static RandomSpawn randomSpawn;
private static List<NewMessageListener> newMessageListeners; private static List<NewMessageListener> newMessageListeners;
private static Map<Player, String> playerStringMap = new HashMap<>(); private static Map<Player, String> playerStringMap = new HashMap<>();
public GameState(String hostIpAddress) { public GameState() {
windDirection = 180d; windDirection = 180d;
windSpeed = 10000d; windSpeed = 10000d;
yachts = new HashMap<>(); yachts = new HashMap<>();
tokensInPlay = new ArrayList<>(); tokensInPlay = new ArrayList<>();
marks = new HashSet<>();
players = new ArrayList<>(); players = new ArrayList<>();
GameState.hostIpAddress = hostIpAddress;
customizationFlag = false; customizationFlag = false;
playerHasLeftFlag = false; playerHasLeftFlag = false;
serverSpeedMultiplier = 1.0; speedMultiplier = 1.0;
currentStage = GameStages.LOBBYING; currentStage = GameStages.LOBBYING;
isRaceStarted = false; isRaceStarted = false;
//set this when game stage changes to prerace
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
markOrder = new MarkOrder(); //This could be instantiated at some point with a select map?
newMessageListeners = new ArrayList<>(); newMessageListeners = new ArrayList<>();
marks = new MarkOrder().getAllMarks(); allTokens = makeTokens();
randomSpawn = new RandomSpawn(markOrder.getOrderedUniqueCompoundMarks());
resetStartTime(); resetStartTime();
setCourseLimit("/server_config/race.xml");
new Thread(this, "GameState").start(); //Run the auto updates on the game state new Thread(this, "GameState").start(); //Run the auto updates on the game state
} }
private void setCourseLimit(String url) { public static void setRace(RaceXMLData raceXMLData) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); markOrder = new MarkOrder(raceXMLData);
documentBuilderFactory.setNamespaceAware(true); for (CompoundMark compoundMark : raceXMLData.getCompoundMarks().values()){
DocumentBuilder documentBuilder; marks.addAll(compoundMark.getMarks());
Document document = null;
try {
documentBuilder = documentBuilderFactory.newDocumentBuilder();
document = documentBuilder.parse(new InputSource(getClass().getResourceAsStream(url)));
} catch (Exception e) {
// sorry, we have to catch general one, otherwise we have to catch five different exceptions.
logger.trace("Failed to load course limit for boundary collision detection.", e);
} }
courseLimit = XMLParser.parseRace(document).getCourseLimit(); courseLimit = raceXMLData.getCourseLimit();
} }
public static String getHostIpAddress() { /**
return hostIpAddress; * Make a pre defined set of tokensInPlay. //TODO wmu16 - Should read from some file for each
* race ideally
*
* @return A list of possible tokensInPlay for this race
*/
private ArrayList<Token> makeTokens() {
Token token1 = new Token(TokenType.BOOST, 57.66946, 11.83154);
Token token2 = new Token(TokenType.BOOST, 57.66877, 11.83382);
Token token3 = new Token(TokenType.BOOST, 57.66914, 11.83965);
Token token4 = new Token(TokenType.BOOST, 57.66684, 11.83214);
return new ArrayList<>(Arrays.asList(token1, token2, token3, token4));
}
public static Set<Mark> getMarks() {
return Collections.unmodifiableSet(marks);
} }
public static List<Player> getPlayers() { public static List<Player> getPlayers() {
@@ -254,75 +237,12 @@ public class GameState implements Runnable {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("[GameState] interrupted exception"); System.out.println("[GameState] interrupted exception");
} }
if (currentStage == GameStages.PRE_RACE) { if (currentStage == GameStages.PRE_RACE || currentStage == GameStages.RACING) {
update();
if (System.currentTimeMillis() > startTime) {
startSpawningTokens();
startUpdatingWind();
GameState.setCurrentStage(GameStages.RACING);
}
}
if (currentStage == GameStages.RACING) {
update(); update();
} }
} }
} }
/**
* Start spawning coins every 60s after the first minute
*/
private void startSpawningTokens() {
Timer timer = new Timer("Token Spawning Timer");
timer.schedule(new TimerTask() {
@Override
public void run() {
spawnNewToken();
notifyMessageListeners(MessageFactory.getRaceXML());
}
}, 0, TOKEN_SPAWN_TIME);
}
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
private static void startUpdatingWind() {
Timer timer = new Timer("Wind Updating Timer");
timer.schedule(new TimerTask() {
@Override
public void run() {
updateWind();
}
}, 0, 500);
}
private static void updateWind() {
Integer direction = GameState.getWindDirection().intValue();
Integer windSpeed = GameState.getWindSpeedMMS().intValue();
Random random = new Random();
if (Math.floorMod(random.nextInt(), 2) == 0) {
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 459;
} else {
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED) {
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED) {
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
GameState.setWindDirection(direction.doubleValue());
}
public static void updateBoat(Integer sourceId, BoatAction actionType) { public static void updateBoat(Integer sourceId, BoatAction actionType) {
ServerYacht playerYacht = yachts.get(sourceId); ServerYacht playerYacht = yachts.get(sourceId);
switch (actionType) { switch (actionType) {
@@ -357,12 +277,10 @@ public class GameState implements Runnable {
* Randomly select a subset of tokensInPlay from a pre defined superset * Randomly select a subset of tokensInPlay from a pre defined superset
* Broadasts a new race status message to show this update * Broadasts a new race status message to show this update
*/ */
private void spawnNewToken() { public static void spawnNewToken() {
Random random = new Random();
tokensInPlay.clear(); tokensInPlay.clear();
Token token = randomSpawn.getRandomTokenLocation(); tokensInPlay.add(allTokens.get(random.nextInt(allTokens.size())));
// token.assignType(TokenType.WIND_WALKER);
logger.debug("Spawned token of type " + token.getTokenType());
tokensInPlay.add(token);
} }
/** /**
@@ -379,12 +297,14 @@ public class GameState implements Runnable {
Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0; Double timeInterval = (System.currentTimeMillis() - previousUpdateTime) / 1000000.0;
previousUpdateTime = System.currentTimeMillis(); previousUpdateTime = System.currentTimeMillis();
if (System.currentTimeMillis() > startTime) {
GameState.setCurrentStage(GameStages.RACING);
}
for (ServerYacht yacht : yachts.values()) { for (ServerYacht yacht : yachts.values()) {
updateVelocity(yacht); updateVelocity(yacht);
checkPowerUpTimeout(yacht);
yacht.runAutoPilot(); yacht.runAutoPilot();
yacht.updateLocation(timeInterval); yacht.updateLocation(timeInterval);
preformTokenUpdates(yacht); //This update must be done before collision. Sorta hacky
checkCollision(yacht); checkCollision(yacht);
if (yacht.getBoatStatus() != BoatStatus.FINISHED) { if (yacht.getBoatStatus() != BoatStatus.FINISHED) {
checkForLegProgression(yacht); checkForLegProgression(yacht);
@@ -398,136 +318,17 @@ public class GameState implements Runnable {
} }
/**
* All token functionality entry points is taken care of here. So can be disabled and enabled
* easily
*
* @param yacht The yacht to perform token checks on
*/
private void preformTokenUpdates(ServerYacht yacht) {
Token collidedToken = checkTokenPickUp(yacht);
if (collidedToken != null) {
tokensInPlay.remove(collidedToken);
powerUpYacht(yacht, collidedToken);
}
checkPowerUpTimeout(yacht);
TokenType powerUp = yacht.getPowerUp();
if (powerUp != null) {
switch (powerUp) {
case WIND_WALKER:
windWalk(yacht);
break;
case BUMPER:
ServerYacht collidedYacht = checkYachtCollision(yacht, true);
if (collidedYacht != null) {
yacht.powerDown();
boatTempShutDown(collidedYacht);
notifyMessageListeners(MessageFactory.makePowerDownMessage(yacht));
notifyMessageListeners(
MessageFactory.makeStatusEffectMessage(collidedYacht, powerUp));
}
break;
case RANDOM:
yacht.setPowerUpSpeedMultiplier(BAD_RANDOM_SPEED_PENALTY);
}
}
}
/**
* Powers up a thisYacht with the given token type.
*
* @param thisYacht The yacht to be powered up
* @param collidedToken The token which this thisYacht collided with
*/
private void powerUpYacht(ServerYacht thisYacht, Token collidedToken) {
//The random token has a 50% chance of becoming another token else becoming a speed detriment!
if (collidedToken.getTokenType() == TokenType.RANDOM && new Random().nextBoolean()) {
collidedToken.realiseRandom();
}
//If another yacht has the wind walker token, They should be powered down. Only one allowed!
else if (collidedToken.getTokenType() == TokenType.WIND_WALKER) {
for (ServerYacht otherYacht : yachts.values()) {
if (otherYacht != thisYacht && otherYacht.getPowerUp() == TokenType.WIND_WALKER) {
powerDownYacht(otherYacht);
}
}
}
thisYacht.powerUp(collidedToken.getTokenType());
String logMessage =
thisYacht.getBoatName() + " has picked up a " + collidedToken.getTokenType().getName()
+ " token";
notifyMessageListeners(
MessageFactory.makeChatterMessage(thisYacht.getSourceId(), logMessage));
notifyMessageListeners(MessageFactory.getRaceXML());
notifyMessageListeners(MessageFactory.makePickupMessage(thisYacht, collidedToken));
logger.debug(
"Yacht: " + thisYacht.getShortName() + " got powerup " + collidedToken.getTokenType());
}
private void powerDownYacht(ServerYacht yacht) {
String logMessage =
yacht.getBoatName() + "'s " + yacht.getPowerUp().getName() + " expired";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
notifyMessageListeners(MessageFactory.makePowerDownMessage(yacht));
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
yacht.powerDown();
}
// TODO: 23/09/17 wmu16 - This is a hacky way to have the boat power down. Need some sort of separation between token and status effect :/
/**
* Disables the given boat for BUMPER_DISABLE_TIME ms.
*
* @param yacht The yacht to disable
*/
private void boatTempShutDown(ServerYacht yacht) {
yacht.setPowerUpSpeedMultiplier(0d);
Timer shutDownTimer = new Timer("Shutdown Timer");
shutDownTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.powerDown(); //Note this actually resets the boat to normal.
}
}, BUMPER_DISABLE_TIME);
}
/**
* Checks how long a powerup has been active for. If it has exceeded its timeout, it powers the
* yacht down.
*
* @param yacht The yacht to check to power down
*/
private void checkPowerUpTimeout(ServerYacht yacht) { private void checkPowerUpTimeout(ServerYacht yacht) {
if (yacht.getPowerUp() != null) { if (yacht.getPowerUp() != null) {
if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > yacht.getPowerUp() if (System.currentTimeMillis() - yacht.getPowerUpStartTime() > POWERUP_TIMEOUT_MS) {
.getTimeout()) { yacht.powerDown();
powerDownYacht(yacht); sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + "'s power-up token expired");
logger.debug("Yacht: " + yacht.getShortName() + " powered down!");
} }
} }
} }
/**
* This function changes the wind to be at an angle that causes the yacht in question to be at
* its fastest velocity
*
* @param yacht The yacht to fix the wind for
*/
private void windWalk(ServerYacht yacht) {
Double optimalAngle = PolarTable.getOptimalAngle();
Double heading = yacht.getHeading();
windDirection = (double) Math.floorMod(Math.round(heading + optimalAngle), 360L);
}
/** /**
* Check if the yacht has crossed the course limit * Check if the yacht has crossed the course limit
* *
@@ -549,15 +350,13 @@ public class GameState implements Runnable {
} }
/** /**
* Checks all tokensInPlay to see if a yacht has picked one up. If so, the yacht is powered up * Checks all tokensInPlay to see if a yacht has picked one up
* in the appropriate way * @return Token which was collided with
* @param yacht The yacht to check for collision with a token * @param serverYacht The yacht to check for collision with a token
*
* @return The token collided with
*/ */
private Token checkTokenPickUp(ServerYacht yacht) { private static Token checkTokenPickUp(ServerYacht serverYacht) {
for (Token token : tokensInPlay) { for (Token token : tokensInPlay) {
Double distance = GeoUtility.getDistance(token, yacht.getLocation()); Double distance = GeoUtility.getDistance(token, serverYacht.getLocation());
if (distance < YACHT_COLLISION_DISTANCE) { if (distance < YACHT_COLLISION_DISTANCE) {
return token; return token;
} }
@@ -580,7 +379,7 @@ public class GameState implements Runnable {
*/ */
public static void checkCollision(ServerYacht serverYacht) { public static void checkCollision(ServerYacht serverYacht) {
//Yacht Collision //Yacht Collision
ServerYacht collidedYacht = checkYachtCollision(serverYacht, false); ServerYacht collidedYacht = checkYachtCollision(serverYacht);
Mark collidedMark = checkMarkCollision(serverYacht); Mark collidedMark = checkMarkCollision(serverYacht);
if (collidedYacht != null) { if (collidedYacht != null) {
@@ -597,7 +396,9 @@ public class GameState implements Runnable {
collidedYacht.setCurrentVelocity( collidedYacht.setCurrentVelocity(
collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY collidedYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
); );
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht)); notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
);
} }
//Mark Collision //Mark Collision
@@ -609,7 +410,9 @@ public class GameState implements Runnable {
serverYacht.setCurrentVelocity( serverYacht.setCurrentVelocity(
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
); );
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht)); notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
);
} }
//Boundary Collision //Boundary Collision
@@ -622,7 +425,23 @@ public class GameState implements Runnable {
serverYacht.setCurrentVelocity( serverYacht.setCurrentVelocity(
serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY serverYacht.getCurrentVelocity() * COLLISION_VELOCITY_PENALTY
); );
notifyMessageListeners(MessageFactory.makeCollisionMessage(serverYacht)); notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION)
);
}
//Token Collision
Token collidedToken = checkTokenPickUp(serverYacht);
if (collidedToken != null) {
sendServerMessage(serverYacht.getSourceId(), serverYacht.getBoatName() + " has picked speed-up token");
tokensInPlay.remove(collidedToken);
serverYacht.powerUp(collidedToken.getTokenType());
logger.debug("Yacht: " + serverYacht.getShortName() + " got powerup " + collidedToken
.getTokenType());
System.out.println("AGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
notifyMessageListeners(MessageFactory.getRaceXML());
notifyMessageListeners(
new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.TOKEN));
} }
} }
@@ -630,30 +449,29 @@ public class GameState implements Runnable {
private void updateVelocity(ServerYacht yacht) { private void updateVelocity(ServerYacht yacht) {
Double trueWindAngle = Math.abs(windDirection - yacht.getHeading()); Double trueWindAngle = Math.abs(windDirection - yacht.getHeading());
Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle); Double boatSpeedInKnots = PolarTable.getBoatSpeed(getWindSpeedKnots(), trueWindAngle);
Double maxBoatSpeed = Double maxBoatSpeed = GeoUtility.knotsToMMS(boatSpeedInKnots) * speedMultiplier * yacht.getMaxSpeedMultiplier();
GeoUtility.knotsToMMS(boatSpeedInKnots) * serverSpeedMultiplier * yacht if (yacht.getPowerUp() != null) {
.getPowerUpSpeedMultiplier() * yacht.getBoatTypeSpeedMultiplier(); if (yacht.getPowerUp().equals(TokenType.BOOST)) {
// TODO: 11/09/17 wmu16 CHANGE THIS TO MAGIC NUMBER
maxBoatSpeed *= 2;
}
}
Double currentVelocity = yacht.getCurrentVelocity(); Double currentVelocity = yacht.getCurrentVelocity();
// TODO: 15/08/17 remove magic numbers from these equations. // TODO: 15/08/17 remove magic numbers from these equations.
if (yacht.getSailIn()) { if (yacht.getSailIn()) {
if (currentVelocity < maxBoatSpeed - 500) { if (currentVelocity < maxBoatSpeed - 500) {
yacht.changeVelocity( yacht.changeVelocity((maxBoatSpeed / 100) * yacht.getAccelerationMultiplier());
(maxBoatSpeed / 100) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity > maxBoatSpeed + 500) { } else if (currentVelocity > maxBoatSpeed + 500) {
yacht.changeVelocity( yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier());
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
} else { } else {
yacht yacht.setCurrentVelocity((maxBoatSpeed) * yacht.getAccelerationMultiplier());
.setCurrentVelocity((maxBoatSpeed) * yacht.getBoatTypeAccelerationMultiplier());
} }
} else { } else {
if (currentVelocity > 3000) { if (currentVelocity > 3000) {
yacht.changeVelocity( yacht.changeVelocity((-currentVelocity / 200) * yacht.getAccelerationMultiplier());
(-currentVelocity / 200) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity > 100) { } else if (currentVelocity > 100) {
yacht.changeVelocity( yacht.changeVelocity((-currentVelocity / 50) * yacht.getAccelerationMultiplier());
(-currentVelocity / 50) * yacht.getBoatTypeAccelerationMultiplier());
} else if (currentVelocity <= 100) { } else if (currentVelocity <= 100) {
yacht.setCurrentVelocity(0d); yacht.setCurrentVelocity(0d);
} }
@@ -716,10 +534,7 @@ public class GameState implements Runnable {
if (hasProgressed) { if (hasProgressed) {
if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) { if (currentMarkSeqID != 0 && !markOrder.isLastMark(currentMarkSeqID)) {
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed leg " + yacht.getLegNumber());
String logMessage = yacht.getBoatName() + " passed leg " + yacht.getLegNumber();
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
} }
yacht.incrementLegNumber(); yacht.incrementLegNumber();
sendMarkRoundingMessage(yacht); sendMarkRoundingMessage(yacht);
@@ -755,9 +570,7 @@ public class GameState implements Runnable {
if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) { if (crossedLine == 2 && isClockwiseCross || crossedLine == 1 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1); yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.RACING); yacht.setBoatStatus(BoatStatus.RACING);
String logMessage = yacht.getBoatName() + " passed start line"; sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed start line");
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
return true; return true;
} }
} }
@@ -861,10 +674,7 @@ public class GameState implements Runnable {
if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) { if (crossedLine == 1 && isClockwiseCross || crossedLine == 2 && !isClockwiseCross) {
yacht.setClosestCurrentMark(mark1); yacht.setClosestCurrentMark(mark1);
yacht.setBoatStatus(BoatStatus.FINISHED); yacht.setBoatStatus(BoatStatus.FINISHED);
sendServerMessage(yacht.getSourceId(), yacht.getBoatName() + " passed finish line");
String logMessage = yacht.getBoatName() + " passed finish line";
notifyMessageListeners(
MessageFactory.makeChatterMessage(yacht.getSourceId(), logMessage));
return true; return true;
} }
} }
@@ -887,7 +697,6 @@ public class GameState implements Runnable {
String name = new String(customizeData); String name = new String(customizeData);
playerYacht.setBoatName(name); playerYacht.setBoatName(name);
} else if (requestType.equals(CustomizeRequestType.COLOR)) { } else if (requestType.equals(CustomizeRequestType.COLOR)) {
//This low level stuff shouldnt be here alistair! In fact no logic LIKE THIS should! - wmu16
int red = customizeData[0] & 0xFF; int red = customizeData[0] & 0xFF;
int green = customizeData[1] & 0xFF; int green = customizeData[1] & 0xFF;
int blue = customizeData[2] & 0xFF; int blue = customizeData[2] & 0xFF;
@@ -900,7 +709,7 @@ public class GameState implements Runnable {
} }
private static Mark checkMarkCollision(ServerYacht yacht) { private static Mark checkMarkCollision(ServerYacht yacht) {
Set<Mark> marksInRace = new HashSet<>(marks); Set<Mark> marksInRace = GameState.getMarks();
for (Mark mark : marksInRace) { for (Mark mark : marksInRace) {
if (GeoUtility.getDistance(yacht.getLocation(), mark) if (GeoUtility.getDistance(yacht.getLocation(), mark)
<= MARK_COLLISION_DISTANCE) { <= MARK_COLLISION_DISTANCE) {
@@ -929,22 +738,15 @@ public class GameState implements Runnable {
* Collision detection which iterates through all the yachts and check if any yacht collided * Collision detection which iterates through all the yachts and check if any yacht collided
* with this yacht. Return collided yacht or null if no collision. * with this yacht. Return collided yacht or null if no collision.
* *
* UPDATE: HACK!!! wmu16 - forBumperCollision is (the goddamn dirtiest) dirty flag to fix a
* weird bug where the bumper collision would not be registerd but the knock back collision would.
* In other words, only set the 'forBumperCollision' flag true if used for the bumper power up.
*
* @return yacht to compare to all other yachts. * @return yacht to compare to all other yachts.
*/ */
private static ServerYacht checkYachtCollision(ServerYacht yacht, Boolean forBumperCollision) { private static ServerYacht checkYachtCollision(ServerYacht yacht) {
Double collisionDistance =
(forBumperCollision) ? YACHT_COLLISION_DISTANCE + 2.5 : YACHT_COLLISION_DISTANCE;
for (ServerYacht otherYacht : GameState.getYachts().values()) { for (ServerYacht otherYacht : GameState.getYachts().values()) {
if (otherYacht != yacht) { if (otherYacht != yacht) {
Double distance = GeoUtility Double distance = GeoUtility
.getDistance(otherYacht.getLocation(), yacht.getLocation()); .getDistance(otherYacht.getLocation(), yacht.getLocation());
; if (distance < YACHT_COLLISION_DISTANCE) {
if (distance < collisionDistance) {
return otherYacht; return otherYacht;
} }
} }
@@ -980,6 +782,13 @@ public class GameState implements Runnable {
roundingMark.getSourceID())); roundingMark.getSourceID()));
} }
public static void sendServerMessage(Integer messageType, String message) {
notifyMessageListeners(new ChatterMessage(
messageType, "SERVER: " + message
));
}
public static void processChatter(ChatterMessage chatterMessage, boolean isHost) { public static void processChatter(ChatterMessage chatterMessage, boolean isHost) {
String chatterText = chatterMessage.getMessage(); String chatterText = chatterMessage.getMessage();
String[] words = chatterText.split("\\s+"); String[] words = chatterText.split("\\s+");
@@ -987,19 +796,17 @@ public class GameState implements Runnable {
switch (words[2].trim()) { switch (words[2].trim()) {
case "/speed": case "/speed":
try { try {
serverSpeedMultiplier = Double.valueOf(words[3]); setSpeedMultiplier(Double.valueOf(words[3]));
String logMessage = "Speed modifier set to x" + words[3]; sendServerMessage(chatterMessage.getMessage_type(),
notifyMessageListeners(MessageFactory "Speed modifier set to x" + words[3]);
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
} catch (Exception e) { } catch (Exception e) {
Logger logger = LoggerFactory.getLogger(GameState.class); Logger logger = LoggerFactory.getLogger(GameState.class);
logger.error("cannot parse >speed value"); logger.error("cannot parse >speed value");
} }
return; return;
case "/finish": case "/finish":
String logMessage = "Game will now finish"; sendServerMessage(chatterMessage.getMessage_type(),
notifyMessageListeners(MessageFactory "Game will now finish");
.makeChatterMessage(chatterMessage.getMessageType(), logMessage));
endRace(); endRace();
return; return;
} }
@@ -1056,7 +863,11 @@ public class GameState implements Runnable {
currentStage = GameStages.FINISHED; currentStage = GameStages.FINISHED;
} }
public static double getServerSpeedMultiplier() { public static void setSpeedMultiplier (double multiplier) {
return serverSpeedMultiplier; speedMultiplier = multiplier;
}
public static double getSpeedMultiplier () {
return speedMultiplier;
} }
} }
@@ -1,30 +1,23 @@
package seng302.gameServer; package seng302.gameServer;
import java.io.IOException; import java.io.IOException;
import java.io.StringReader;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.gameServer.messages.Message; import seng302.gameServer.messages.Message;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.PolarTable; import seng302.model.PolarTable;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.model.mark.CompoundMark; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
/** /**
* A class describing the overall server, which creates and collects server threads for each client * A class describing the overall server, which creates and collects server threads for each client
@@ -37,34 +30,21 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
private static final int PORT = 4942; private static final int PORT = 4942;
private static final Integer CLIENT_UPDATES_PER_SECOND = 60; private static final Integer CLIENT_UPDATES_PER_SECOND = 60;
private static final int MAX_WIND_SPEED = 12000;
private static final int MIN_WIND_SPEED = 8000;
private boolean terminated; private boolean terminated;
private Thread thread; private Thread thread;
private ServerSocket serverSocket = null; private ServerSocket serverSocket = null;
private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();; private ArrayList<ServerToClientThread> serverToClientThreads = new ArrayList<>();
private static Integer capacity; private static Integer capacity;
private RaceXMLData raceXMLData;
private RegattaXMLData regattaXMLData;
private boolean serverStarted = false;
private void startAdvertisingServer() { private void startAdvertisingServer() {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc;
XMLGenerator generator = new XMLGenerator();
try {
db = dbf.newDocumentBuilder();
String regatta = generator.getRegattaAsXml();
StringReader stringReader = new StringReader(regatta);
InputSource is = new InputSource(stringReader);
doc = db.parse(is);
} catch (ParserConfigurationException | IOException | SAXException e) {
logger.warn("Couldn't load race regatta");
return;
}
RegattaXMLData regattaXMLData = XMLParser.parseRegatta(doc);
Integer capacity = GameState.getCapacity(); Integer capacity = GameState.getCapacity();
Integer numPlayers = GameState.getNumberOfPlayers(); Integer numPlayers = GameState.getNumberOfPlayers();
Integer spacesLeft = capacity - numPlayers; Integer spacesLeft = capacity - numPlayers;
@@ -76,31 +56,42 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
// Start advertising server // Start advertising server
try { try {
ServerAdvertiser.getInstance().setMapName(regattaXMLData.getCourseName()).setCapacity(capacity).setNumberOfPlayers(numPlayers); ServerAdvertiser.getInstance()
ServerAdvertiser.getInstance().registerGame(PORT, regattaXMLData.getRegattaName()); .setMapName(regattaXMLData.getCourseName())
.setCapacity(capacity)
.setNumberOfPlayers(numPlayers)
.registerGame(PORT, regattaXMLData.getRegattaName());
} catch (IOException e) { } catch (IOException e) {
logger.warn("Could not register server"); logger.warn("Could not register server");
} }
} }
public MainServerThread() { public MainServerThread() {
new GameState("localhost"); new GameState();
try { try {
serverSocket = new ServerSocket(PORT); serverSocket = new ServerSocket(PORT);
} catch (IOException e) { } catch (IOException e) {
logger.trace("IO error in server thread handler upon trying to make new server socket", logger.trace("IO error in server thread handler upon trying to make new server socket",
0); 0);
} }
startAdvertisingServer();
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv"));
GameState.addMessageEventListener(this::broadcastMessage);
terminated = false; terminated = false;
thread = new Thread(this, "MainServer"); thread = new Thread(this, "MainServer");
thread.start(); thread.start();
} }
private void startServer() {
MessageFactory.updateXMLGenerator(raceXMLData, regattaXMLData);
GameState.setRace(raceXMLData);
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
startAdvertisingServer();
PolarTable
.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
GameState.addMessageEventListener(this::broadcastMessage);
startUpdatingWind();
startSpawningTokens();
System.out.println("SAAAANNNNNNNNNDDDDDDDDDDDDDDDDDDDDDDDDDDdd");
sendSetupMessages();
}
public void run() { public void run() {
@@ -113,6 +104,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
for (ServerToClientThread stc : serverToClientThreads) { for (ServerToClientThread stc : serverToClientThreads) {
if (!stc.isSocketOpen()) { if (!stc.isSocketOpen()) {
GameState.getYachts().remove(stc.getSourceId()); GameState.getYachts().remove(stc.getSourceId());
System.out.println("AAAAAAAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
sendSetupMessages(); sendSetupMessages();
try { try {
stc.getSocket().close(); stc.getSocket().close();
@@ -128,8 +120,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} catch (InterruptedException e) { } catch (InterruptedException e) {
logger.trace("Interrupted exception in Main Server Thread thread sleep", 1); logger.trace("Interrupted exception in Main Server Thread thread sleep", 1);
} }
if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState if (GameState.getCurrentStage() == GameStages.LOBBYING && GameState.getCustomizationFlag()) {
.getCustomizationFlag()) { MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
System.out.println("gfdgfdgfdg");
sendSetupMessages(); sendSetupMessages();
GameState.resetCustomizationFlag(); GameState.resetCustomizationFlag();
} }
@@ -182,6 +175,63 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
} }
} }
private static void updateWind(){
Integer direction = GameState.getWindDirection().intValue();
Integer windSpeed = GameState.getWindSpeedMMS().intValue();
Random random = new Random();
if (Math.floorMod(random.nextInt(), 2) == 0){
direction += random.nextInt(4);
windSpeed += random.nextInt(20) + 459;
}
else{
direction -= random.nextInt(4);
windSpeed -= random.nextInt(20) + 459;
}
direction = Math.floorMod(direction, 360);
if (windSpeed > MAX_WIND_SPEED){
windSpeed -= random.nextInt(500);
}
if (windSpeed <= MIN_WIND_SPEED){
windSpeed += random.nextInt(500);
}
GameState.setWindSpeed(Double.valueOf(windSpeed));
GameState.setWindDirection(direction.doubleValue());
}
// TODO: 29/08/17 wmu16 - This sort of update should be in game state
private static void startUpdatingWind(){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
updateWind();
}
}, 0, 500);
}
/**
* Start spawning coins every 60s after the first minute
*/
private void startSpawningTokens() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
GameState.spawnNewToken();
broadcastMessage(MessageFactory.getRaceXML());
}
}, 10000, 60000);
}
/** /**
* A client has tried to connect to the server * A client has tried to connect to the server
* *
@@ -192,11 +242,34 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0); logger.debug("Player Connected From " + serverToClientThread.getThread().getName(), 0);
if (serverToClientThreads.size() == 0) { //Sets first client as host. if (serverToClientThreads.size() == 0) { //Sets first client as host.
serverToClientThread.setAsHost(); serverToClientThread.setAsHost();
serverToClientThread.raceXMLProperty().addListener((obs, oldVal, race) -> {
if (race != null) {
raceXMLData = race;
}
if (regattaXMLData != null) {
startServer();
}
});
serverToClientThread.regattaXMLProperty().addListener((obs, oldVal, regatta) -> {
if (regatta != null) {
regattaXMLData = regatta;
}
if (raceXMLData != null) {
startServer();
}
});
} else {
MessageFactory.updateBoats(new ArrayList<>(GameState.getYachts().values()));
for (ServerYacht serverYacht : GameState.getYachts().values()) {
System.out.println("Connecterino" + serverYacht);
}
serverToClientThread.addConnectionListener(() -> {
System.out.println("LUSTENER");
sendSetupMessages();
});
} }
serverToClientThreads.add(serverToClientThread); serverToClientThreads.add(serverToClientThread);
serverToClientThread.addConnectionListener(this::sendSetupMessages);
serverToClientThread.addDisconnectListener(this::clientDisconnected); serverToClientThread.addDisconnectListener(this::clientDisconnected);
try { try {
ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers()); ServerAdvertiser.getInstance().setNumberOfPlayers(GameState.getNumberOfPlayers());
} catch (IOException e) { } catch (IOException e) {
@@ -255,9 +328,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
}, 0, 500); }, 0, 500);
if (GameState.getCurrentStage() == GameStages.LOBBYING) { // if (GameState.getCurrentStage() == GameStages.LOBBYING) {
sendSetupMessages(); // sendSetupMessages();
} // }
} }
public void terminate() { public void terminate() {
@@ -268,39 +341,166 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
* Initialise boats to specific spaced out geopoints behind starting line. * Initialise boats to specific spaced out geopoints behind starting line.
*/ */
private void initialiseBoatPositions() { private void initialiseBoatPositions() {
CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0); // CompoundMark cm = GameState.getMarkOrder().getMarkOrder().get(0);
GeoPoint startMark1 = cm.getSubMark(1); // GeoPoint startMark1 = cm.getSubMark(1);
GeoPoint startMark2 = cm.getSubMark(2); // GeoPoint startMark2 = cm.getSubMark(2);
//
// // Calculating midpoint
// Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2);
// Double length = GeoUtility.getDistance(startMark1, startMark2);
// GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2);
//
// // Setting each boats position side by side
// final double SEPARATION = 50.0; // distance apart in meters
//
// int boatIndex = 0;
// for (ServerYacht yacht : GameState.getYachts().values()) {
// int distanceApart = boatIndex / 2;
//
// if (boatIndex % 2 == 1 && boatIndex != 0) {
// distanceApart++;
// distanceApart *= -1;
// }
//
// GeoPoint spawnMark = GeoUtility
// .getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * SEPARATION);
//
// if (yacht.getHeading() < perpendicularAngle) {
// spawnMark = GeoUtility
// .getGeoCoordinate(spawnMark, perpendicularAngle + 90, SEPARATION);
// } else {
// spawnMark = GeoUtility
// .getGeoCoordinate(spawnMark, perpendicularAngle + 270, SEPARATION);
// }
//
// yacht.setLocation(spawnMark);
// boatIndex++;
// }
// Calculating midpoint // final double SEPARATION = 50.0; // distance apart in meters
Double perpendicularAngle = GeoUtility.getBearing(startMark1, startMark2); //
Double length = GeoUtility.getDistance(startMark1, startMark2); // //Reverse of the angle from start to first mark
GeoPoint midpoint = GeoUtility.getGeoCoordinate(startMark1, perpendicularAngle, length / 2); // double angleToFirstMark = 360 - GeoUtility.getBearing(
// GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
// GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
// );
//
// //Length of start line
// double startLineLength = GeoUtility.getDistance(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
// );
//
// //Angle of start line
// double startMarkToMarkAngle = GeoUtility.getBearing(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
// );
//
// //How many yachts can fit along the start line
// int spacesAlongLine = (int) Math.round(startLineLength / SEPARATION);
// //The free space left by the boats.
// double buffer = (startLineLength % SEPARATION) / 2;
//
// //Randomize starting order.
// List<ServerYacht> serverYachtList = new ArrayList<>(GameState.getYachts().values());
// Collections.shuffle(serverYachtList);
//
// //set the starting point away from start line.
// GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
// GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
// angleToFirstMark, SEPARATION
// );
//
// //Move it along the start line
// startingPoint = GeoUtility.getGeoCoordinate(
// startingPoint, startMarkToMarkAngle, buffer
// );
//
// int yachtCount = 0;
// int repeats = 0;
//
// GeoPoint yachtLocation;
//
// for (ServerYacht serverYacht : serverYachtList) {
//
// //Move away from start line
// yachtLocation = GeoUtility.getGeoCoordinate(
// startingPoint, angleToFirstMark,repeats * SEPARATION
// );
// //Move along start line
// yachtLocation = GeoUtility.getGeoCoordinate(
// yachtLocation, startMarkToMarkAngle, yachtCount * SEPARATION
// );
// serverYacht.setLocation(yachtLocation);
// serverYacht.setHeading(GeoUtility.getBearing(
// yachtLocation, GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
// ));
// //Set location for next yacht
// yachtCount++;
// if (yachtCount > spacesAlongLine) {
// yachtCount = 0;
// repeats++;
// }
// }
// Setting each boats position side by side final double DISTANCE_TO_START = 75d;
double DISTANCE_FACTOR = 50.0; // distance apart in meters final double YACHT_SEPARATION = 20d;
int boatIndex = 0;
for (ServerYacht yacht : GameState.getYachts().values()) {
int distanceApart = boatIndex / 2;
if (boatIndex % 2 == 1 && boatIndex != 0) { //Length of start line
distanceApart++; double startLineLength = GeoUtility.getDistance(
distanceApart *= -1; GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
);
//How many yachts can fit along the start line
int spacesAlongLine = (int) Math.round(startLineLength / YACHT_SEPARATION);
//Angle of start line
double startMarkToMarkAngle = GeoUtility.getBearing(
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(1),
GameState.getMarkOrder().getMarkOrder().get(0).getSubMark(2)
);
//angle from first mark to the start
double angleToStart = GeoUtility.getBearing(
GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint(),
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint()
);
double angleFromStart = GeoUtility.getBearing(
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
GameState.getMarkOrder().getMarkOrder().get(1).getMidPoint()
);
GeoPoint startingPoint = GeoUtility.getGeoCoordinate(
GameState.getMarkOrder().getMarkOrder().get(0).getMidPoint(),
angleToStart, DISTANCE_TO_START
);
List<ServerYacht> randomisedYachts = new ArrayList<>(GameState.getYachts().values());
Collections.shuffle(randomisedYachts);
while (randomisedYachts.size() > 0) {
int numYachtsInLine = spacesAlongLine > randomisedYachts.size() ? randomisedYachts.size() : spacesAlongLine;
double yachtSpace = numYachtsInLine * YACHT_SEPARATION / 2;
GeoPoint firstYachtPoint = GeoUtility.getGeoCoordinate(
startingPoint, startMarkToMarkAngle + 180, yachtSpace
);
for (int i=0; i<numYachtsInLine; i++){
randomisedYachts.get(0).setHeading(angleFromStart);
randomisedYachts.get(0).setLocation(firstYachtPoint);
firstYachtPoint = GeoUtility.getGeoCoordinate(
firstYachtPoint, startMarkToMarkAngle, yachtSpace
);
randomisedYachts.remove(0);
} }
GeoPoint spawnMark = GeoUtility startingPoint = GeoUtility.getGeoCoordinate(
.getGeoCoordinate(midpoint, perpendicularAngle, distanceApart * DISTANCE_FACTOR); startingPoint, angleToStart, DISTANCE_TO_START
);
if (yacht.getHeading() < perpendicularAngle) {
spawnMark = GeoUtility
.getGeoCoordinate(spawnMark, perpendicularAngle + 90, DISTANCE_FACTOR);
} else {
spawnMark = GeoUtility
.getGeoCoordinate(spawnMark, perpendicularAngle + 270, DISTANCE_FACTOR);
}
yacht.setLocation(spawnMark);
boatIndex++;
} }
} }
} }
@@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import seng302.gameServer.messages.BoatLocationMessage; import seng302.gameServer.messages.BoatLocationMessage;
import seng302.gameServer.messages.BoatSubMessage; import seng302.gameServer.messages.BoatSubMessage;
import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.RaceStartNotificationType; import seng302.gameServer.messages.RaceStartNotificationType;
import seng302.gameServer.messages.RaceStartStatusMessage; import seng302.gameServer.messages.RaceStartStatusMessage;
import seng302.gameServer.messages.RaceStatus; import seng302.gameServer.messages.RaceStatus;
@@ -12,14 +11,13 @@ import seng302.gameServer.messages.RaceStatusMessage;
import seng302.gameServer.messages.RaceType; import seng302.gameServer.messages.RaceType;
import seng302.gameServer.messages.XMLMessage; import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType; import seng302.gameServer.messages.XMLMessageSubType;
import seng302.gameServer.messages.YachtEventCodeMessage;
import seng302.gameServer.messages.YachtEventType;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.model.stream.xml.generator.RaceXMLTemplate; import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate; import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
/** /**
@@ -39,6 +37,51 @@ Ideally this class would be created with an instance of the GameState (I tried i
public class MessageFactory { public class MessageFactory {
private static XMLGenerator xmlGenerator = new XMLGenerator(); private static XMLGenerator xmlGenerator = new XMLGenerator();
private static XMLMessage race;
private static XMLMessage regatta;
private static XMLMessage boats;
public static void updateXMLGenerator(RaceXMLData race, RegattaXMLData regatta) {
xmlGenerator.setRegattaTemplate(
new RegattaXMLTemplate(
regatta.getRegattaName(),
regatta.getCourseName(),
regatta.getCentralLat(),
regatta.getCentralLng()
)
);
xmlGenerator.setRaceTemplate(
new RaceXMLTemplate(
new ArrayList<>(),
new ArrayList<>(),
race.getMarkSequence(),
race.getCourseLimit(),
new ArrayList<>(race.getCompoundMarks().values()),
GameState.getCapacity(), true
)
);
String xmlStr = xmlGenerator.getRaceAsXml();
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
xmlStr = xmlGenerator.getRegattaAsXml();
MessageFactory.regatta = new XMLMessage(xmlStr, XMLMessageSubType.REGATTA, xmlStr.length());
xmlStr = xmlGenerator.getBoatsAsXml();
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
}
public static void updateBoats(List<ServerYacht> yachts) {
for (ServerYacht serverYacht : yachts) {
System.out.println(serverYacht);
}
xmlGenerator.getRace().setBoats(yachts);
String xmlStr = xmlGenerator.getBoatsAsXml();
MessageFactory.boats = new XMLMessage(xmlStr, XMLMessageSubType.BOAT, xmlStr.length());
}
public static void updateTokens(List<Token> tokens) {
xmlGenerator.getRace().setTokens(tokens);
String xmlStr = xmlGenerator.getRaceAsXml();
MessageFactory.race = new XMLMessage(xmlStr, XMLMessageSubType.RACE, xmlStr.length());
}
public static RaceStartStatusMessage getRaceStartStatusMessage() { public static RaceStartStatusMessage getRaceStartStatusMessage() {
@@ -99,106 +142,14 @@ public class MessageFactory {
} }
public static XMLMessage getRaceXML() { public static XMLMessage getRaceXML() {
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values()); return race;
List<Token> tokens = GameState.getTokensInPlay();
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
xmlGenerator.setRaceTemplate(raceXMLTemplate);
XMLMessage raceXMLMessage = new XMLMessage(
xmlGenerator.getRaceAsXml(),
XMLMessageSubType.RACE,
xmlGenerator.getRaceAsXml().length());
return raceXMLMessage;
} }
public static XMLMessage getRegattaXML() { public static XMLMessage getRegattaXML() {
//@TODO calculate lat/lng values return regatta;
return new XMLMessage(
xmlGenerator.getRegattaAsXml(),
XMLMessageSubType.REGATTA,
xmlGenerator.getRegattaAsXml().length());
} }
public static XMLMessage getBoatXML() { public static XMLMessage getBoatXML() {
List<ServerYacht> yachts = new ArrayList<>(GameState.getYachts().values()); return boats;
List<Token> tokens = GameState.getTokensInPlay();
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(yachts, tokens);
xmlGenerator.setRaceTemplate(raceXMLTemplate);
return new XMLMessage(
xmlGenerator.getBoatsAsXml(),
XMLMessageSubType.BOAT,
xmlGenerator.getBoatsAsXml().length());
}
public static YachtEventCodeMessage makeCollisionMessage(ServerYacht serverYacht) {
return new YachtEventCodeMessage(serverYacht.getSourceId(), YachtEventType.COLLISION);
}
/**
* Constructs a message to be sent out whenever a yacht picks up a boost
*
* @param serverYacht The yacht that has picked up a power up
* @param token The token which they picked up
* @return The corresponding YachtEventCodeMessage
*/
public static YachtEventCodeMessage makePickupMessage(ServerYacht serverYacht, Token token) {
YachtEventType yachtEventType = null;
switch (token.getTokenType()) {
case BOOST:
yachtEventType = YachtEventType.TOKEN_VELOCITY;
break;
case HANDLING:
yachtEventType = YachtEventType.TOKEN_HANDLING;
break;
case WIND_WALKER:
yachtEventType = YachtEventType.TOKEN_WIND_WALKER;
break;
case BUMPER:
yachtEventType = YachtEventType.TOKEN_BUMPER;
break;
case RANDOM:
yachtEventType = YachtEventType.TOKEN_RANDOM;
break;
}
return new YachtEventCodeMessage(serverYacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message representing a certain buff / debuff for a given yacht. For now this is
* just for the bumper debuff so the affected boat is aware that it has been crashed. This could
* however be extended to render affects for all boats given a certain debuff.
*
* @param yacht The yacht affected by some status
* @param token The token indicating what status they have
* @return A YachtEventCodeMessage
*/
public static YachtEventCodeMessage makeStatusEffectMessage(ServerYacht yacht,
TokenType token) {
YachtEventType yachtEventType = null;
switch (token) {
case BUMPER:
yachtEventType = YachtEventType.BUMPER_CRASH;
break;
}
return new YachtEventCodeMessage(yacht.getSourceId(), yachtEventType);
}
/**
* Constructs a message to be sent out when a given yacht powers down (From a boost of any type)
*
* @param yacht The yacht that is powering down
* @return A YachtEventCodeMessage representing this action
*/
public static YachtEventCodeMessage makePowerDownMessage(ServerYacht yacht) {
return new YachtEventCodeMessage(yacht.getSourceId(), YachtEventType.POWER_DOWN);
}
public static ChatterMessage makeChatterMessage(Integer messageType, String message) {
return new ChatterMessage(messageType, "SERVER: " + message);
} }
} }
@@ -1,23 +1,21 @@
package seng302.gameServer; package seng302.gameServer;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
import javafx.beans.property.SimpleObjectProperty;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
import seng302.gameServer.messages.ChatterMessage; import seng302.gameServer.messages.ChatterMessage;
import seng302.gameServer.messages.ClientType; import seng302.gameServer.messages.ClientType;
@@ -25,15 +23,16 @@ import seng302.gameServer.messages.CustomizeRequestType;
import seng302.gameServer.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RegistrationResponseMessage; import seng302.gameServer.messages.RegistrationResponseMessage;
import seng302.gameServer.messages.RegistrationResponseStatus; import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType;
import seng302.model.Player; import seng302.model.Player;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.generator.RaceXMLTemplate; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.utilities.XMLParser;
/** /**
* A class describing a single connection to a Client for the purposes of sending and receiving on * A class describing a single connection to a Client for the purposes of sending and receiving on
@@ -78,8 +77,12 @@ public class ServerToClientThread implements Runnable {
private List<ConnectionListener> connectionListeners = new ArrayList<>(); private List<ConnectionListener> connectionListeners = new ArrayList<>();
private DisconnectListener disconnectListener; private DisconnectListener disconnectListener;
private ServerYacht yacht;
private Player player; private Player player;
private SimpleObjectProperty<RaceXMLData> raceXMLProperty = new SimpleObjectProperty<>();
private SimpleObjectProperty<RegattaXMLData> regattaXMLProperty = new SimpleObjectProperty<>();
public ServerToClientThread(Socket socket) { public ServerToClientThread(Socket socket) {
this.socket = socket; this.socket = socket;
seqNo = 0; seqNo = 0;
@@ -100,16 +103,16 @@ public class ServerToClientThread implements Runnable {
} }
private void setUpPlayer(){ private void setUpPlayer(){
String shortName = "p" + sourceId; String fName = "Player" + GameState.getNumberOfPlayers().toString();
String longName = "player " + sourceId; String lName = "";
ServerYacht yacht = new ServerYacht( ServerYacht yacht = new ServerYacht(
BoatMeshType.DINGHY, sourceId, sourceId.toString(), shortName, longName, "NZ"); BoatMeshType.DINGHY, sourceId, sourceId.toString(), fName, fName + " " + lName, "NZ"
);
System.out.println(yacht);
player = new Player(socket, yacht); player = new Player(socket, yacht);
GameState.addYacht(sourceId, yacht); GameState.addYacht(sourceId, yacht);
GameState.addPlayer(player); GameState.addPlayer(player);
System.out.println(GameState.getYachts().size());
} }
private void completeRegistration(ClientType clientType) throws IOException { private void completeRegistration(ClientType clientType) throws IOException {
@@ -133,8 +136,9 @@ public class ServerToClientThread implements Runnable {
this.sourceId = sourceId; this.sourceId = sourceId;
isRegistered = true; isRegistered = true;
os.write(responseMessage.getBuffer()); os.write(responseMessage.getBuffer());
System.out.println("MAKING A PLAYER");
setUpPlayer(); setUpPlayer();
System.out.println("DONE MAKING A PLAYER");
for (ConnectionListener listener : connectionListeners) { for (ConnectionListener listener : connectionListeners) {
listener.notifyConnection(); listener.notifyConnection();
@@ -164,37 +168,51 @@ public class ServerToClientThread implements Runnable {
long computedCrc = checksum.getValue(); long computedCrc = checksum.getValue();
long packetCrc = Message.bytesToLong(getBytes(4)); long packetCrc = Message.bytesToLong(getBytes(4));
if (computedCrc == packetCrc) { if (computedCrc == packetCrc) {
StreamPacket packet = new StreamPacket(type, payloadLength, timeStamp, payload);
switch (PacketType.assignPacketType(type, payload)) { switch (PacketType.assignPacketType(type, payload)) {
case BOAT_ACTION: case BOAT_ACTION:
BoatAction actionType = ServerPacketParser BoatAction actionType = ServerPacketParser.extractBoatAction(packet);
.extractBoatAction(
new StreamPacket(type, payloadLength, timeStamp, payload));
GameState.updateBoat(sourceId, actionType); GameState.updateBoat(sourceId, actionType);
break; break;
case RACE_REGISTRATION_REQUEST: case RACE_REGISTRATION_REQUEST:
ClientType requestedType = ServerPacketParser.extractClientType( ClientType requestedType = ServerPacketParser
new StreamPacket(type, payloadLength, timeStamp, payload)); .extractClientType(packet);
completeRegistration(requestedType); completeRegistration(requestedType);
break; break;
case CHATTER_TEXT: case CHATTER_TEXT:
ChatterMessage chatterMessage = ServerPacketParser ChatterMessage chatterMessage = ServerPacketParser
.extractChatterText( .extractChatterText(packet);
new StreamPacket(type, payloadLength, timeStamp, payload));
GameState.processChatter(chatterMessage, isHost); GameState.processChatter(chatterMessage, isHost);
break; break;
case RACE_CUSTOMIZATION_REQUEST: case RACE_CUSTOMIZATION_REQUEST:
Long sourceID = Message Long sourceID = Message.bytesToLong(
.bytesToLong(Arrays.copyOfRange(payload, 0, 3)); Arrays.copyOfRange(payload, 0, 3)
);
CustomizeRequestType requestType = ServerPacketParser CustomizeRequestType requestType = ServerPacketParser
.extractCustomizationType( .extractCustomizationType(packet);
new StreamPacket(type, payloadLength, timeStamp, payload));
GameState.customizePlayer(sourceID, requestType, GameState.customizePlayer(sourceID, requestType,
Arrays.copyOfRange(payload, 6, payload.length)); Arrays.copyOfRange(payload, 6, payload.length)
);
GameState.setCustomizationFlag(); GameState.setCustomizationFlag();
// TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes. // TODO: 17/08/2017 ajm412: Send a response packet here, not really necessary until we do shapes.
break; break;
case RACE_XML:
Document document = StreamParser.extractXmlMessage(packet);
raceXMLProperty.set(
XMLParser.parseRace(document)
);
GameState.setMaxPlayers(XMLParser.getMaxPlayers(document));
break;
case REGATTA_XML:
regattaXMLProperty.set(
XMLParser.parseRegatta(
StreamParser.extractXmlMessage(packet)
)
);
break;
} }
} else { } else {
logger.warn("Packet has been dropped", 1); logger.warn("Packet has been dropped", 1);
@@ -211,23 +229,9 @@ public class ServerToClientThread implements Runnable {
} }
public void sendSetupMessages() { public void sendSetupMessages() {
xmlGenerator = new XMLGenerator(); sendMessage(MessageFactory.getRegattaXML());
RaceXMLTemplate race = new RaceXMLTemplate(new ArrayList<>(GameState.getYachts().values()), new ArrayList<>()); sendMessage(MessageFactory.getBoatXML());
sendMessage(MessageFactory.getRaceXML());
xmlGenerator.setRaceTemplate(race);
XMLMessage xmlMessage;
xmlMessage = new XMLMessage(xmlGenerator.getRegattaAsXml(), XMLMessageSubType.REGATTA,
xmlGenerator.getRegattaAsXml().length());
sendMessage(xmlMessage);
xmlMessage = new XMLMessage(xmlGenerator.getBoatsAsXml(), XMLMessageSubType.BOAT,
xmlGenerator.getBoatsAsXml().length());
sendMessage(xmlMessage);
xmlMessage = new XMLMessage(xmlGenerator.getRaceAsXml(), XMLMessageSubType.RACE,
xmlGenerator.getRaceAsXml().length());
sendMessage(xmlMessage);
} }
private void closeSocket() { private void closeSocket() {
@@ -296,6 +300,10 @@ public class ServerToClientThread implements Runnable {
return socket; return socket;
} }
public ServerYacht getYacht() {
return yacht;
}
public void addConnectionListener(ConnectionListener listener) { public void addConnectionListener(ConnectionListener listener) {
connectionListeners.add(listener); connectionListeners.add(listener);
} }
@@ -319,4 +327,12 @@ public class ServerToClientThread implements Runnable {
public void setAsHost() { public void setAsHost() {
isHost = true; isHost = true;
} }
public SimpleObjectProperty<RaceXMLData> raceXMLProperty() {
return raceXMLProperty;
}
public SimpleObjectProperty<RegattaXMLData> regattaXMLProperty() {
return regattaXMLProperty;
}
} }
@@ -40,7 +40,7 @@ public class ChatterMessage extends Message {
return message; return message;
} }
public int getMessageType() { public int getMessage_type() {
return message_type; return message_type;
} }
} }
@@ -1,18 +1,11 @@
package seng302.gameServer.messages; package seng302.gameServer.messages;
/** /**
* Enum for different event types for the yacht * Created by wmu16 on 11/09/17.
*/ */
public enum YachtEventType { public enum YachtEventType {
COLLISION(33), COLLISION(33),
TOKEN_VELOCITY(34), TOKEN(34);
TOKEN_BUMPER(35),
TOKEN_HANDLING(36),
TOKEN_WIND_WALKER(37),
TOKEN_RANDOM(38),
POWER_DOWN(39),
BUMPER_CRASH(40);
private int code; private int code;
@@ -13,13 +13,9 @@ import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyIntegerWrapper; import javafx.beans.property.ReadOnlyIntegerWrapper;
import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongProperty;
import javafx.beans.property.ReadOnlyLongWrapper; import javafx.beans.property.ReadOnlyLongWrapper;
import javafx.beans.value.ObservableObjectValue;
import javafx.collections.FXCollections;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import jdk.nashorn.internal.objects.annotations.Function;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.model.token.TokenType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.BoatObject;
@@ -41,26 +37,6 @@ public class ClientYacht extends Observable {
void notifyRounding(ClientYacht yacht, int legNumber); void notifyRounding(ClientYacht yacht, int legNumber);
} }
@FunctionalInterface
public interface ColorChangeListener {
void notifyColorChange(ClientYacht yacht);
}
//This notifies RaceViewController so it can display icon - wmu16
@FunctionalInterface
public interface PowerUpListener {
void notifyPowerUp(ClientYacht yacht, TokenType tokenType);
}
//This notifies RaceViewController so it can remove token icon - wmu16
@FunctionalInterface
public interface PowerDownListener {
void notifyPowerDown(ClientYacht yacht);
}
private Logger logger = LoggerFactory.getLogger(ClientYacht.class); private Logger logger = LoggerFactory.getLogger(ClientYacht.class);
@@ -71,7 +47,6 @@ public class ClientYacht extends Observable {
private String boatName; private String boatName;
private String country; private String country;
private Integer position; private Integer position;
private TokenType powerUp;
private Long estimateTimeAtFinish; private Long estimateTimeAtFinish;
private Boolean sailIn = true; private Boolean sailIn = true;
@@ -90,10 +65,6 @@ public class ClientYacht extends Observable {
private List<YachtLocationListener> locationListeners = new ArrayList<>(); private List<YachtLocationListener> locationListeners = new ArrayList<>();
private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>(); private List<MarkRoundingListener> markRoundingListeners = new ArrayList<>();
private List<PowerUpListener> powerUpListeners = new ArrayList<>();
private List<PowerDownListener> powerDownListeners = new ArrayList<>();
private List<ColorChangeListener> colorChangeListeners = new ArrayList<>();
private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper(); private ReadOnlyDoubleWrapper velocityProperty = new ReadOnlyDoubleWrapper();
private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeTillNextProperty = new ReadOnlyLongWrapper();
private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper(); private ReadOnlyLongWrapper timeSinceLastMarkProperty = new ReadOnlyLongWrapper();
@@ -237,32 +208,6 @@ public class ClientYacht extends Observable {
this.position = position; this.position = position;
} }
/**
* Powers down the boat and notifies the raceViewController to display
*/
public void powerDown() {
this.powerUp = null;
for (PowerDownListener listener : powerDownListeners) {
listener.notifyPowerDown(this);
}
}
/**
* powers up the boat and notifies the raceViewController to display
*
* @param tokenType The type of token that this boat is being powered up with
*/
public void setPowerUp(TokenType tokenType) {
this.powerUp = tokenType;
for (PowerUpListener listener : powerUpListeners) {
listener.notifyPowerUp(this, tokenType);
}
}
public TokenType getPowerUp() {
return powerUp;
}
public void toggleSail() { public void toggleSail() {
sailIn = !sailIn; sailIn = !sailIn;
} }
@@ -312,9 +257,6 @@ public class ClientYacht extends Observable {
public void setColour(Color colour) { public void setColour(Color colour) {
this.colour = colour; this.colour = colour;
for (ColorChangeListener listener : colorChangeListeners) {
listener.notifyColorChange(this);
}
} }
public void updateLocation(double lat, double lng, double heading, double velocity) { public void updateLocation(double lat, double lng, double heading, double velocity) {
@@ -340,18 +282,6 @@ public class ClientYacht extends Observable {
markRoundingListeners.add(listener); markRoundingListeners.add(listener);
} }
public void addPowerUpListener(PowerUpListener listener) {
powerUpListeners.add(listener);
}
public void addPowerDownListener(PowerDownListener listener) {
powerDownListeners.add(listener);
}
public void addColorChangeListener(ColorChangeListener listener) {
colorChangeListeners.add(listener);
}
public void removeMarkRoundingListener(MarkRoundingListener listener) { public void removeMarkRoundingListener(MarkRoundingListener listener) {
markRoundingListeners.remove(listener); markRoundingListeners.remove(listener);
} }
+5
View File
@@ -15,4 +15,9 @@ public class Limit extends GeoPoint {
public Integer getSeqID() { public Integer getSeqID() {
return seqID; return seqID;
} }
@Override
public String toString(){
return "Limit = {seqID=" + seqID + ", lat=" + getLat() + ", lng=" + getLng() + "}";
}
} }
+4 -37
View File
@@ -4,9 +4,7 @@ import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
/** /**
* A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised * A static class for parsing and storing the polars. Will parse the whole polar table and also store the optimised
@@ -19,7 +17,6 @@ public final class PolarTable {
private static HashMap<Double, HashMap<Double, Double>> polarTable; private static HashMap<Double, HashMap<Double, Double>> polarTable;
private static HashMap<Double, HashMap<Double, Double>> upwindOptimal; private static HashMap<Double, HashMap<Double, Double>> upwindOptimal;
private static HashMap<Double, HashMap<Double, Double>> downwindOptimal; private static HashMap<Double, HashMap<Double, Double>> downwindOptimal;
private static Double optimalAngle;
private static int upTwaIndex; private static int upTwaIndex;
private static int dnTwaIndex; private static int dnTwaIndex;
@@ -36,13 +33,11 @@ public final class PolarTable {
upwindOptimal = new HashMap<>(); upwindOptimal = new HashMap<>();
downwindOptimal = new HashMap<>(); downwindOptimal = new HashMap<>();
String line = null; String line;
String check;
Boolean isHeaderLine = true; Boolean isHeaderLine = true;
try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) { try (BufferedReader br = new BufferedReader(new InputStreamReader(polarFile))) {
while ((check = br.readLine()) != null) { while ((line = br.readLine()) != null) {
line = check;
String[] thisLine = line.split(","); String[] thisLine = line.split(",");
//Initial line in file //Initial line in file
@@ -71,10 +66,7 @@ public final class PolarTable {
upwindOptimal.put(thisWindSpeed, thisUpWindPolar); upwindOptimal.put(thisWindSpeed, thisUpWindPolar);
downwindOptimal.put(thisWindSpeed, thisDnWindPolar); downwindOptimal.put(thisWindSpeed, thisDnWindPolar);
} }
} }
getMaxSpeedAngle(line);
} catch (IOException e) { } catch (IOException e) {
System.out.println("[PolarTable] IO exception"); System.out.println("[PolarTable] IO exception");
@@ -82,27 +74,6 @@ public final class PolarTable {
} }
/**
* Passes the final line of the polar table and iterates over the speeds for each
* angle, velocity pair to find the angle that produces the highest velocity
*
* @param line The last line of the polar file
*/
private static void getMaxSpeedAngle(String line) {
String[] theLastLine = line.split(",");
Double maxWindVal = Double.parseDouble(theLastLine[0]);
Double optimalAngle = Double.parseDouble(theLastLine[1]);
Double maxSpeed = Double.parseDouble(theLastLine[2]);
for (Map.Entry<Double, Double> entry : polarTable.get(maxWindVal).entrySet()) {
if (entry.getValue() > maxSpeed) {
maxSpeed = entry.getValue();
optimalAngle = entry.getKey();
}
}
PolarTable.optimalAngle = optimalAngle;
}
/** /**
* Parses the header line of a polar file * Parses the header line of a polar file
@@ -114,18 +85,14 @@ public final class PolarTable {
String thisItem = thisLine[i]; String thisItem = thisLine[i];
if (thisItem.toLowerCase().startsWith("uptwa")) { if (thisItem.toLowerCase().startsWith("uptwa")) {
upTwaIndex = i; upTwaIndex = i;
} else if (thisItem.toLowerCase().startsWith("dntwa")) { }
else if (thisItem.toLowerCase().startsWith("dntwa")) {
dnTwaIndex = i; dnTwaIndex = i;
} }
} }
} }
public static Double getOptimalAngle() {
return optimalAngle;
}
/** /**
* @return The entire polar table * @return The entire polar table
*/ */
@@ -0,0 +1,122 @@
package seng302.model;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import javafx.geometry.Point2D;
import seng302.utilities.GeoUtility;
/**
* Contains information on a scaled lat lon point for use with mapping geographical elements to a 2d plane.
*/
public class ScaledPoint extends GeoPoint {
public enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
private double x, y, scaleFactor;
private ScaleDirection scaleDirection;
private ScaledPoint(double lat, double lng, double x, double y, double scaleFactor, ScaleDirection direction) {
super(lat, lng);
this.x = x;
this.y = y;
this.scaleFactor = scaleFactor;
this.scaleDirection = direction;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getScaleFactor() {
return scaleFactor;
}
public ScaleDirection getScaleDirection() {
return scaleDirection;
}
public Point2D findScaledXY(GeoPoint unscaled) {
return findScaledXY(unscaled.getLat(), unscaled.getLng());
}
public Point2D findScaledXY(double unscaledLat, double unscaledLon) {
double distanceFromReference;
double angleFromReference;
double xReference = this.getX();
double yReference = this.getY();
angleFromReference = GeoUtility.getBearingRad(
this, new GeoPoint(unscaledLat, unscaledLon)
);
distanceFromReference = GeoUtility.getDistance(
this, new GeoPoint(unscaledLat, unscaledLon)
);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
} else if (angleFromReference >= 0) {
angleFromReference = angleFromReference - Math.PI / 2;
xReference += scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
angleFromReference = Math.abs(angleFromReference);
xReference -= scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
yReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
} else {
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
xReference -= scaleFactor * Math.cos(angleFromReference) * distanceFromReference;
yReference += scaleFactor * Math.sin(angleFromReference) * distanceFromReference;
}
return new Point2D(xReference, yReference);
}
public static ScaledPoint makeScaledPoint(double width, double height,
List<? extends GeoPoint> points, boolean centered) {
double referencePointX, referencePointY, scaleFactor, lat, lng;
ScaleDirection scaleDirection;
points = new ArrayList<>(points);
points.sort(Comparator.comparingDouble(GeoPoint::getLat));
GeoPoint minLatPoint = points.get(0);
GeoPoint maxLatPoint = points.get(points.size() - 1);
points.sort(Comparator.comparingDouble(GeoPoint::getLng));
GeoPoint minLonPoint = points.get(0);
GeoPoint maxLonPoint = points.get(points.size() - 1);
referencePointX = centered ? 0 : width / 2;
referencePointY = centered ? 0 : height / 2;
lat = (maxLatPoint.getLat() - minLatPoint.getLat()) / 2 + minLatPoint.getLat();
lng = (maxLonPoint.getLng() - minLonPoint.getLng()) / 2 + minLonPoint.getLng();
GeoPoint ref = new GeoPoint(lat, lng);
double vertDistance = GeoUtility.getDistance(
ref, new GeoPoint(ref.getLat(), maxLonPoint.getLng())
) * 2.1;
double horiDistance = GeoUtility.getDistance(
ref, new GeoPoint(maxLatPoint.getLat(), ref.getLng())
) * 2.1;
double vertScale = height / vertDistance;
if (horiDistance * vertScale > width) {
scaleFactor = width / horiDistance;
scaleDirection = ScaleDirection.HORIZONTAL;
} else {
scaleFactor = vertScale;
scaleDirection = ScaleDirection.VERTICAL;
}
return new ScaledPoint(lat, lng, referencePointX, referencePointY, scaleFactor, scaleDirection);
}
}
+13 -51
View File
@@ -23,9 +23,9 @@ public class ServerYacht {
//Boat info //Boat info
private BoatMeshType boatType; private BoatMeshType boatType;
private Double turnStep = 5.0; private Double turnStep = 5.0;
private Double boatTypeSpeedMultiplier = 1.0; private Double maxSpeedMultiplier = 1.0;
private Double boatTypeTurnStepMultiplier = 1.0; private Double turnStepMultiplier = 1.0;
private Double boatTypeAccelerationMultiplier = 1.0; private Double accelerationMultiplier = 1.0;
private Integer sourceId; private Integer sourceId;
private String hullID; //matches HullNum in the XML spec. private String hullID; //matches HullNum in the XML spec.
private String shortName; private String shortName;
@@ -55,8 +55,6 @@ public class ServerYacht {
//PowerUp //PowerUp
private TokenType powerUp; private TokenType powerUp;
private Long powerUpStartTime; private Long powerUpStartTime;
private Double powerUpSpeedMultiplier;
private Integer powerUpHandlingMultiplier;
//turning mode //turning mode
private Boolean continuouslyTurning; private Boolean continuouslyTurning;
@@ -80,11 +78,11 @@ public class ServerYacht {
this.legNumber = 0; this.legNumber = 0;
this.boatColor = Colors.getColor(sourceId - 1); this.boatColor = Colors.getColor(sourceId - 1);
this.powerUp = null; this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
this.hasEnteredRoundingZone = false; this.hasEnteredRoundingZone = false;
this.hasPassedLine = false; this.hasPassedLine = false;
this.hasPassedThroughGate = false; this.hasPassedThroughGate = false;
this.continuouslyTurning = false; this.continuouslyTurning = false;
} }
@@ -112,33 +110,13 @@ public class ServerYacht {
location = geoPoint; location = geoPoint;
} }
/**
* Powers up a yacht with a given yacht, only after powering it down first to avoid double power
* ups
*
* @param powerUp The given power up
*/
public void powerUp(TokenType powerUp) { public void powerUp(TokenType powerUp) {
powerDown();
switch (powerUp) {
case BOOST:
powerUpSpeedMultiplier = GameState.VELOCITY_BOOST_MULTIPLIER;
break;
case HANDLING:
powerUpHandlingMultiplier = GameState.HANDLING_BOOST_MULTIPLIER;
break;
}
this.powerUp = powerUp; this.powerUp = powerUp;
powerUpStartTime = System.currentTimeMillis(); powerUpStartTime = System.currentTimeMillis();
} }
/**
* Powers down a yacht, returning its power multipliers back to 1
*/
public void powerDown() { public void powerDown() {
this.powerUp = null; this.powerUp = null;
this.powerUpSpeedMultiplier = 1d;
this.powerUpHandlingMultiplier = 1;
} }
public Long getPowerUpStartTime() { public Long getPowerUpStartTime() {
@@ -155,7 +133,7 @@ public class ServerYacht {
* @param amount the amount by which to adjust the boat heading. * @param amount the amount by which to adjust the boat heading.
*/ */
public void adjustHeading(Double amount) { public void adjustHeading(Double amount) {
Double newVal = heading + amount * powerUpHandlingMultiplier * boatTypeTurnStepMultiplier; Double newVal = heading + (amount * turnStepMultiplier);
lastHeading = heading; lastHeading = heading;
heading = (double) Math.floorMod(newVal.longValue(), 360L); heading = (double) Math.floorMod(newVal.longValue(), 360L);
} }
@@ -457,18 +435,18 @@ public class ServerYacht {
} }
public void setBoatType(BoatMeshType boatType) { public void setBoatType(BoatMeshType boatType) {
this.boatTypeAccelerationMultiplier = boatType.accelerationMultiplier; this.accelerationMultiplier = boatType.accelerationMultiplier;
this.boatTypeSpeedMultiplier = boatType.maxSpeedMultiplier; this.maxSpeedMultiplier = boatType.maxSpeedMultiplier;
this.boatTypeTurnStepMultiplier = boatType.turnStep; this.turnStepMultiplier = boatType.turnStep;
this.boatType = boatType; this.boatType = boatType;
} }
public Double getBoatTypeSpeedMultiplier() { public Double getMaxSpeedMultiplier() {
return boatTypeSpeedMultiplier; return maxSpeedMultiplier;
} }
public Double getBoatTypeAccelerationMultiplier() { public Double getAccelerationMultiplier(){
return boatTypeAccelerationMultiplier; return accelerationMultiplier;
} }
@@ -479,20 +457,4 @@ public class ServerYacht {
public void setContinuouslyTurning(Boolean continuouslyTurning) { public void setContinuouslyTurning(Boolean continuouslyTurning) {
this.continuouslyTurning = continuouslyTurning; this.continuouslyTurning = continuouslyTurning;
} }
public Double getPowerUpSpeedMultiplier() {
return powerUpSpeedMultiplier;
}
public void setPowerUpSpeedMultiplier(Double powerUpSpeedMultiplier) {
this.powerUpSpeedMultiplier = powerUpSpeedMultiplier;
}
public Integer getPowerUpHandlingMultiplier() {
return powerUpHandlingMultiplier;
}
public void setPowerUpHandlingMultiplier(Integer powerUpHandlingMultiplier) {
this.powerUpHandlingMultiplier = powerUpHandlingMultiplier;
}
} }
@@ -1,6 +1,6 @@
package seng302.model.mark; package seng302.model.mark;
import java.util.ArrayList; import java.util.Collections;
import java.util.List; import java.util.List;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
@@ -10,13 +10,13 @@ public class CompoundMark {
private int compoundMarkId; private int compoundMarkId;
private String name; private String name;
private List<Mark> marks = new ArrayList<>(); private List<Mark> marks;
private GeoPoint midPoint; private GeoPoint midPoint;
public CompoundMark(int markID, String name, List<Mark> marks) { public CompoundMark(int markID, String name, List<Mark> marks) {
this.compoundMarkId = markID; this.compoundMarkId = markID;
this.name = name; this.name = name;
this.marks.addAll(marks); this.marks = Collections.unmodifiableList(marks);
if (marks.size() > 1) { if (marks.size() > 1) {
this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1)); this.midPoint = GeoUtility.getDirtyMidPoint(marks.get(0), marks.get(1));
} else { } else {
@@ -32,4 +32,10 @@ public class Corner {
public Integer getZoneSize() { public Integer getZoneSize() {
return zoneSize; return zoneSize;
} }
@Override
public String toString() {
return "Corner = {seqID=" + seqID + ", compoundMarkID=" + compoundMarkID + ", rounding="
+ rounding +", zoneSize=" + zoneSize + "}";
}
} }
+13 -90
View File
@@ -1,35 +1,30 @@
package seng302.model.mark; package seng302.model.mark;
import java.io.IOException; import java.util.ArrayList;
import java.io.StringReader; import java.util.Collections;
import javax.xml.parsers.DocumentBuilder; import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.ServerYacht;
import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
import java.util.*;
/** /**
* Class to hold the order of the marks in the race. * Class to hold the order of the marks in the race.
*/ */
public class MarkOrder { public class MarkOrder {
private List<CompoundMark> raceMarkOrder; private List<CompoundMark> raceMarkOrder;
private List<CompoundMark> orderedUniqueCompoundMarks;
private Logger logger = LoggerFactory.getLogger(MarkOrder.class); private Logger logger = LoggerFactory.getLogger(MarkOrder.class);
private List<Mark> allMarks;
public MarkOrder(){
loadRaceProperties(); public MarkOrder(RaceXMLData raceXMLData){
raceMarkOrder = new ArrayList<>();
for (Corner corner : raceXMLData.getMarkSequence()){
CompoundMark compoundMark = raceXMLData.getCompoundMarks().get(corner.getCompoundMarkID());
compoundMark.setRoundingSide(
RoundingSide.getRoundingSide(corner.getRounding())
);
raceMarkOrder.add(compoundMark);
}
} }
/** /**
@@ -41,14 +36,9 @@ public class MarkOrder {
logger.warn("Race order accessed but not instantiated"); logger.warn("Race order accessed but not instantiated");
return null; return null;
} }
return Collections.unmodifiableList(raceMarkOrder); return Collections.unmodifiableList(raceMarkOrder);
} }
public List<CompoundMark> getOrderedUniqueCompoundMarks() {
return orderedUniqueCompoundMarks;
}
/** /**
* @param seqID The seqID of the current mark the boat is heading to * @param seqID The seqID of the current mark the boat is heading to
* @return A Boolean indicating if this coming mark is the last one (finish line) * @return A Boolean indicating if this coming mark is the last one (finish line)
@@ -79,71 +69,4 @@ public class MarkOrder {
public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException { public CompoundMark getNextMark(Integer currentSeqID) throws IndexOutOfBoundsException {
return raceMarkOrder.get(currentSeqID + 1); return raceMarkOrder.get(currentSeqID + 1);
} }
public List<Mark> getAllMarks() {
return Collections.unmodifiableList(allMarks);
}
/**
* Loads the race order from an XML string
* @param xml An AC35 RaceXML
* @return An ordered list of marks in the race
*/
private List<CompoundMark> loadRaceOrderFromXML(String xml) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc;
allMarks = new ArrayList<>();
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(xml)));
} catch (ParserConfigurationException | IOException | SAXException e) {
logger.error("Failed to read generated race XML");
return null;
}
RaceXMLData data = XMLParser.parseRace(doc);
if (data != null){
logger.debug("Loaded RaceXML for mark order");
List<Corner> corners = data.getMarkSequence();
Map<Integer, CompoundMark> marks = data.getCompoundMarks();
orderedUniqueCompoundMarks = new ArrayList<>(marks.values());
List<CompoundMark> course = new ArrayList<>();
for (Corner corner : corners){
CompoundMark compoundMark = marks.get(corner.getCompoundMarkID());
compoundMark.setRoundingSide(
RoundingSide.getRoundingSide(corner.getRounding())
);
course.add(compoundMark);
allMarks.addAll(compoundMark.getMarks());
}
return course;
}
return null;
}
/**
* Load the raceXML and mark order
*/
private void loadRaceProperties(){
XMLGenerator generator = new XMLGenerator();
// TODO: 29/08/17 wmu16 - This is terrible, having to make a template just to receive constant data
generator.setRaceTemplate(new RaceXMLTemplate(
new ArrayList<>(),
new ArrayList<>()));
String raceXML = generator.getRaceAsXml();
if (raceXML == null){
logger.error("Failed to generate raceXML (for race properties)");
return;
}
raceMarkOrder = loadRaceOrderFromXML(raceXML);
}
} }
@@ -1,10 +1,12 @@
package seng302.model.stream.xml.generator; package seng302.model.stream.xml.generator;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import seng302.model.Limit;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner;
import seng302.model.token.Token; import seng302.model.token.Token;
/** /**
@@ -15,11 +17,22 @@ public class RaceXMLTemplate {
private List<ServerYacht> yachts; private List<ServerYacht> yachts;
private LocalDateTime startTime; private LocalDateTime startTime;
private List<Token> tokens; private List<Token> tokens;
private List<Corner> roundings;
private List<Limit> courseLimit;
private List<CompoundMark> course;
private Integer maxPlayers;
private Boolean tokensEnabled;
public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens) { public RaceXMLTemplate(List<ServerYacht> yachts, List<Token> tokens, List<Corner> roundings,
List<Limit> limit, List<CompoundMark> course, Integer maxPlayers, Boolean tokensEnabled) {
this.yachts = yachts; this.yachts = yachts;
this.tokens = tokens; this.tokens = tokens;
this.roundings = roundings;
this.courseLimit = limit;
this.course = course;
startTime = LocalDateTime.now(); startTime = LocalDateTime.now();
this.maxPlayers = maxPlayers;
this.tokensEnabled = tokensEnabled;
} }
/** /**
@@ -39,6 +52,18 @@ public class RaceXMLTemplate {
return Collections.unmodifiableList(tokens); return Collections.unmodifiableList(tokens);
} }
public List<CompoundMark> getCompoundMarks() {
return Collections.unmodifiableList(course);
}
public List<Limit> getCourseLimit() {
return Collections.unmodifiableList(courseLimit);
}
public List<Corner> getRoundings() {
return Collections.unmodifiableList(roundings);
}
/** /**
* Set the time until the race starts * Set the time until the race starts
* @param seconds The time in seconds until the race starts * @param seconds The time in seconds until the race starts
@@ -54,4 +79,20 @@ public class RaceXMLTemplate {
public String getRaceStartTime(){ public String getRaceStartTime(){
return startTime.toString(); return startTime.toString();
} }
public void setBoats(List<ServerYacht> boats) {
yachts = boats;
}
public void setTokens(List<Token> tokens) {
this.tokens = tokens;
}
public String getTokensEnabled() {
return tokensEnabled.toString();
}
public String getMaxPlayers() {
return maxPlayers.toString();
}
} }
@@ -1,9 +1,5 @@
package seng302.model.token; package seng302.model.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import seng302.model.GeoPoint; import seng302.model.GeoPoint;
/** /**
@@ -13,50 +9,13 @@ import seng302.model.GeoPoint;
public class Token extends GeoPoint { public class Token extends GeoPoint {
private TokenType tokenType; private TokenType tokenType;
private Random random = new Random();
//Constructor for creating a specific type client side
public Token(TokenType tokenType, double lat, double lng) { public Token(TokenType tokenType, double lat, double lng) {
super(lat, lng); super(lat, lng);
this.tokenType = tokenType; this.tokenType = tokenType;
} }
//Making random type server side
public Token(double lat, double lng) {
super(lat, lng);
assignRandomType();
}
//Making random type server side
public Token(GeoPoint geoPoint) {
super(geoPoint.getLat(), geoPoint.getLng());
assignRandomType();
}
public TokenType getTokenType() { public TokenType getTokenType() {
return tokenType; return tokenType;
} }
/**
* Assigns a random type to the token (including the random type token)
*/
public void assignRandomType() {
tokenType = TokenType.values()[random.nextInt(TokenType.values().length)];
}
/**
* Assigns a random, concrete type to the token (cannot be the random type)
*/
public void realiseRandom() {
List<TokenType> tokenTypeList = new ArrayList<>(Arrays.asList(TokenType.values()));
tokenTypeList.remove(TokenType.RANDOM);
tokenType = tokenTypeList.get(random.nextInt(tokenTypeList.size()));
}
/**
* Exists for testing purposes only
*/
public void assignType(TokenType tokenType) {
this.tokenType = tokenType;
}
} }
@@ -5,32 +5,27 @@ package seng302.model.token;
* Created by wmu16 on 28/08/17. * Created by wmu16 on 28/08/17.
*/ */
public enum TokenType { public enum TokenType {
BOOST(0),
BOOST(0, "Boost", 10_000), HANDLING(1);
HANDLING(1, "Handling", 10_000),
BUMPER(2, "Bumper", 10_000),
WIND_WALKER(3, "Wind Walker", 10_000),
RANDOM(4, "Random", 10_000);
private int value; private int value;
private String name;
private int timeout;
TokenType(int value, String name, int timeout) { TokenType(int value) {
this.value = value; this.value = value;
this.name = name;
this.timeout = timeout;
} }
public int getValue() { public int getValue() {
return value; return value;
} }
public String getName() { public static TokenType getToken(int value) {
return name; switch (value) {
} case 0:
return BOOST;
public int getTimeout() { case 1:
return timeout; return HANDLING;
default:
return BOOST;
}
} }
} }
@@ -1,63 +0,0 @@
package seng302.utilities;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import seng302.model.GeoPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.token.Token;
/**
* A class for generating and spawning tokens in random locations
* Created by wmu16 on 27/09/17.
*/
public class RandomSpawn {
private static final Integer DEGREES_IN_CIRCLE = 360;
private HashMap<GeoPoint, Double> spawnRadii;
private Random random;
/**
* @param markOrder this must be the ORDERED list of marks. Better yet UNIQUE to avoid over
* computation
*/
public RandomSpawn(List<CompoundMark> markOrder) {
this.spawnRadii = new HashMap<>();
random = new Random();
spawnRadii = generateSpawnRadii(markOrder);
}
private HashMap<GeoPoint, Double> generateSpawnRadii(List<CompoundMark> markOrder) {
HashMap<GeoPoint, Double> spawnRadii = new HashMap<>();
for (int i = 0; i < markOrder.size() - 1; i++) {
GeoPoint spawnCentre = GeoUtility.getDirtyMidPoint(
markOrder.get(i).getMidPoint(),
markOrder.get(i + 1).getMidPoint());
Double distance = GeoUtility.getDistance(spawnCentre, markOrder.get(i).getMidPoint());
spawnRadii.put(spawnCentre, distance);
}
return spawnRadii;
}
/**
* @return A random token type at a random location in a random radii of the set of possible
* radii
*/
public Token getRandomTokenLocation() {
Object[] keys = spawnRadii.keySet().toArray();
GeoPoint randomSpawnCentre = (GeoPoint) keys[random.nextInt(keys.length)];
Double spawnRadius = spawnRadii.get(randomSpawnCentre);
Double randomDistance = spawnRadius * random.nextDouble();
Double randomAngle = random.nextDouble() * DEGREES_IN_CIRCLE;
GeoPoint randomLocation = GeoUtility
.getGeoCoordinate(randomSpawnCentre, randomAngle, randomDistance);
return new Token(randomLocation);
}
}
@@ -136,7 +136,7 @@ public class StreamParser {
long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14)); long messageLength = bytesToLong(Arrays.copyOfRange(payload, 12, 14));
String xmlMessage = new String( String xmlMessage = new String(
(Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim(); (Arrays.copyOfRange(payload, 14, (int) (14 + messageLength)))).trim();
System.out.println(xmlMessage);
//Create XML document Object //Create XML document Object
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db; DocumentBuilder db;
@@ -179,4 +179,8 @@ public class XMLGenerator {
public RegattaXMLTemplate getRegatta() { public RegattaXMLTemplate getRegatta() {
return regatta; return regatta;
} }
public RaceXMLTemplate getRace() {
return race;
}
} }
+203 -13
View File
@@ -1,21 +1,30 @@
package seng302.utilities; package seng302.utilities;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; import java.util.Random;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.util.Pair;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.Colors; import seng302.model.Colors;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.Token; import seng302.model.token.Token;
@@ -27,6 +36,8 @@ import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
*/ */
public class XMLParser { public class XMLParser {
private static final int MAX_PLAYERS = 8;
/** /**
* Returns the text content of a given child element tag, assuming it exists, as an Integer. * Returns the text content of a given child element tag, assuming it exists, as an Integer.
* *
@@ -37,7 +48,7 @@ public class XMLParser {
private static Integer getElementInt(Element ele, String tag) { private static Integer getElementInt(Element ele, String tag) {
NodeList tagList = ele.getElementsByTagName(tag); NodeList tagList = ele.getElementsByTagName(tag);
if (tagList.getLength() > 0) { if (tagList.getLength() > 0) {
return Integer.parseInt(tagList.item(0).getTextContent()); return Integer.parseInt(tagList.item(0).getTextContent().replaceAll("\\s+",""));
} else { } else {
return null; return null;
} }
@@ -69,7 +80,7 @@ public class XMLParser {
private static Double getElementDouble(Element ele, String tag) { private static Double getElementDouble(Element ele, String tag) {
NodeList tagList = ele.getElementsByTagName(tag); NodeList tagList = ele.getElementsByTagName(tag);
if (tagList.getLength() > 0) { if (tagList.getLength() > 0) {
return Double.parseDouble(tagList.item(0).getTextContent()); return Double.parseDouble(tagList.item(0).getTextContent().replaceAll("\\s+",""));
} else { } else {
return null; return null;
} }
@@ -187,6 +198,31 @@ public class XMLParser {
); );
} }
public static Boolean tokensEnabled(Document doc) {
Element docEle = doc.getDocumentElement();
try {
Node tokenNode = docEle.getAttributeNode("Tokens");
return Boolean.valueOf(XMLParser.getNodeAttributeString(tokenNode, "Enabled"));
} catch (NullPointerException npe) {
return false;
}
}
public static Integer getMaxPlayers(Document doc) {
Element docEle = doc.getDocumentElement();
try {
NamedNodeMap namedNodeMap = docEle.getElementsByTagName("Participants").item(0).getAttributes();
Node node = namedNodeMap.getNamedItem("MaxPlayers");
if (node != null) {
return Integer.parseInt(node.getNodeValue());
}
} catch (NullPointerException npe) {
npe.printStackTrace();
return MAX_PLAYERS;
}
return MAX_PLAYERS;
}
/** /**
* Returns an object containing the data extracted from the given xml formatted document * Returns an object containing the data extracted from the given xml formatted document
* *
@@ -196,7 +232,7 @@ public class XMLParser {
public static RaceXMLData parseRace(Document doc) { public static RaceXMLData parseRace(Document doc) {
Element docEle = doc.getDocumentElement(); Element docEle = doc.getDocumentElement();
return new RaceXMLData( return new RaceXMLData(
extractParticpantIDs(docEle), extractParticipantIDs(docEle),
extractTokens(docEle), extractTokens(docEle),
extractCompoundMarks(docEle), extractCompoundMarks(docEle),
extractMarkOrder(docEle), extractMarkOrder(docEle),
@@ -235,13 +271,11 @@ public class XMLParser {
for (int i = 0; i < limitList.getLength(); i++) { for (int i = 0; i < limitList.getLength(); i++) {
Node limitNode = limitList.item(i); Node limitNode = limitList.item(i);
if (limitNode.getNodeName().equals("Limit")) { if (limitNode.getNodeName().equals("Limit")) {
courseLimit.add( courseLimit.add(new Limit(
new Limit( XMLParser.getNodeAttributeInt(limitNode, "SeqID"),
XMLParser.getNodeAttributeInt(limitNode, "SeqID"), XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
XMLParser.getNodeAttributeDouble(limitNode, "Lat"), XMLParser.getNodeAttributeDouble(limitNode, "Lon")
XMLParser.getNodeAttributeDouble(limitNode, "Lon") ));
)
);
} }
} }
return courseLimit; return courseLimit;
@@ -273,7 +307,7 @@ public class XMLParser {
/** /**
* Extracts course participants data * Extracts course participants data
*/ */
private static List<Integer> extractParticpantIDs (Element docEle) { private static List<Integer> extractParticipantIDs(Element docEle) {
List<Integer> boatIDs = new ArrayList<>(); List<Integer> boatIDs = new ArrayList<>();
NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes(); NodeList pList = docEle.getElementsByTagName("Participants").item(0).getChildNodes();
for (int i = 0; i < pList.getLength(); i++) { for (int i = 0; i < pList.getLength(); i++) {
@@ -295,10 +329,11 @@ public class XMLParser {
for (int i = 0; i < cMarkList.getLength(); i++) { for (int i = 0; i < cMarkList.getLength(); i++) {
Node cMarkNode = cMarkList.item(i); Node cMarkNode = cMarkList.item(i);
if (cMarkNode.getNodeName().equals("CompoundMark")) { if (cMarkNode.getNodeName().equals("CompoundMark")) {
String name = XMLParser.getNodeAttributeString(cMarkNode, "Name");
name = (name == null || name.equals("")) ? "Mark " + i+1: name;
cMark = new CompoundMark( cMark = new CompoundMark(
XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"), XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID"),
XMLParser.getNodeAttributeString(cMarkNode, "Name"), name, createMarks(cMarkNode)
createMarks(cMarkNode)
); );
allMarks.add(cMark); allMarks.add(cMark);
} }
@@ -319,14 +354,169 @@ public class XMLParser {
Node markNode = childMarks.item(i); Node markNode = childMarks.item(i);
if (markNode.getNodeName().equals("Mark")) { if (markNode.getNodeName().equals("Mark")) {
Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID"); Integer seqID = XMLParser.getNodeAttributeInt(markNode, "SeqID");
seqID = (seqID == null) ? i+1 : seqID;
Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID"); Integer sourceID = XMLParser.getNodeAttributeInt(markNode, "SourceID");
sourceID = (sourceID == null) ? i+1 : sourceID;
String markName = XMLParser.getNodeAttributeString(markNode, "Name"); String markName = XMLParser.getNodeAttributeString(markNode, "Name");
markName = (markName == null || markName.equals("")) ? cMarkName + " " + i+1: markName;
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat"); Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "TargetLat");
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng"); Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "TargetLng");
Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID); Mark mark = new Mark(markName, seqID, targetLat, targetLng, sourceID);
subMarks.add(mark); subMarks.add(mark);
} }
} }
return subMarks; return subMarks;
} }
/**
* This ungodly combination of existing methods and code blocks parses a race definition file.
* Look upon it and despair.
* @param url the location of the race def file
* @param serverName the name of the server
* @param repetitions the repetitions of a segment of the race def file.
* @param maxPlayers max number of players. uses the default race max if null or greater than the actual max.
* @param tokensEnabled if tokens are enabled
* @return a pair which contains regatta string, race string as key, value pair.
*/
public static Pair<RegattaXMLTemplate, RaceXMLTemplate> parseRaceDef(
String url, String serverName, Integer repetitions, Integer maxPlayers, Boolean tokensEnabled
) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(url);
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
}
Element docEle = doc.getDocumentElement();
RegattaXMLTemplate regattaXMLTemplate = new RegattaXMLTemplate(
serverName, XMLParser.getElementString(docEle, "CourseName"),
XMLParser.getElementDouble(docEle, "CentralLat"),
XMLParser.getElementDouble(docEle, "CentralLng")
);
XMLGenerator xmlGenerator = new XMLGenerator();
xmlGenerator.setRegattaTemplate(regattaXMLTemplate);
if (maxPlayers == null) {
maxPlayers = XMLParser.getElementInt(docEle, "MaxPlayers");
} else if (maxPlayers > XMLParser.getElementInt(docEle, "MaxPlayers")) {
maxPlayers = XMLParser.getElementInt(docEle, "MaxPlayers");
}
RaceXMLTemplate raceXMLTemplate = new RaceXMLTemplate(
new ArrayList<>(), new ArrayList<>(),
XMLParser.extractMarkOrderRaceDef(docEle, repetitions),
XMLParser.extractCourseLimitRaceDef(docEle),
XMLParser.extractCompoundMarksRaceDef(docEle),
maxPlayers, tokensEnabled
);
xmlGenerator.setRaceTemplate(raceXMLTemplate);
return new Pair<>(regattaXMLTemplate, raceXMLTemplate);
}
private static List<Corner> extractMarkOrderRaceDef(Element docEle, int repitions){
List<Corner> compoundMarkSequence = new ArrayList<>();
NodeList cornerList = docEle.getElementsByTagName("Course").item(0).getChildNodes();
int seqId = 1;
final int zoneSize = 3;
for (int i=0; i<cornerList.getLength(); i++) {
Node segment = cornerList.item(i);
if (segment.getNodeName().equals("OpeningSegment") ||
segment.getNodeName().equals("ClosingSegment")) {
seqId = parseCourseSegment(segment, seqId, compoundMarkSequence);
} else if (segment.getNodeName().equals("RepeatingSegment")) {
for (int k = 0; k < repitions; k++) {
seqId = parseCourseSegment(segment, seqId, compoundMarkSequence);
}
}
}
return compoundMarkSequence;
}
/**
* Parses a segment of the course adding new Corners to the given list.
* @param segment Segment to parse
* @param seqID initial sequence ID
* @param course course to add corners to
* @return the last sequence id.
*/
private static int parseCourseSegment(Node segment, int seqID, List<Corner> course) {
NodeList segmentList = segment.getChildNodes();
for (int j = 0; j < segmentList.getLength(); j++) {
Node corner = segmentList.item(j);
if (corner.getNodeName().equals("Corner")) {
String rounding = XMLParser.getNodeAttributeString(corner, "Rounding");
rounding = //Converting "P" to "Port" and "S" to "Stbd"
rounding.equals("P") ? "Port" :
rounding.equals("S") ? "Stbd" : rounding;
course.add(new Corner(
seqID++, XMLParser.getNodeAttributeInt(corner, "CompoundMarkID"),
rounding, 3
));
}
}
return seqID;
}
private static List<Limit> extractCourseLimitRaceDef(Element docEle) {
List<Limit> courseLimit = new ArrayList<>();
NodeList limitList = docEle.getElementsByTagName("CourseLimit").item(0).getChildNodes();
int seqId = 1;
for (int i = 0; i < limitList.getLength(); i++) {
Node limitNode = limitList.item(i);
if (limitNode.getNodeName().equals("Limit")) {
courseLimit.add(new Limit(
seqId++, XMLParser.getNodeAttributeDouble(limitNode, "Lat"),
XMLParser.getNodeAttributeDouble(limitNode, "Lng")
));
}
}
return courseLimit;
}
private static List<CompoundMark> extractCompoundMarksRaceDef(Element docEle){
List<CompoundMark> allMarks = new ArrayList<>();
NodeList cMarkList = docEle.getElementsByTagName("Marks").item(0).getChildNodes();
CompoundMark cMark;
int markCount = 200;
for (int i = 0; i < cMarkList.getLength(); i++) {
Node cMarkNode = cMarkList.item(i);
if (cMarkNode.getNodeName().equals("CompoundMark")) {
Integer id = XMLParser.getNodeAttributeInt(cMarkNode, "CompoundMarkID");
List<Mark> subMarks = createMarksRaceDef(cMarkNode, markCount,"Mark " + id);
markCount += subMarks.size();
allMarks.add(new CompoundMark(id, "Mark " + id, subMarks));
}
}
return allMarks;
}
private static List<Mark> createMarksRaceDef(Node compoundMark, int markCount, String markName) {
List<Mark> subMarks = new ArrayList<>();
NodeList childMarks = compoundMark.getChildNodes();
int seqID = 1;
for (int i = 0; i < childMarks.getLength(); i++) {
Node markNode = childMarks.item(i);
if (markNode.getNodeName().equals("Mark")) {
Double targetLat = XMLParser.getNodeAttributeDouble(markNode, "Lat");
Double targetLng = XMLParser.getNodeAttributeDouble(markNode, "Lng");
Mark mark = new Mark(markName + " subMark " + seqID, seqID, targetLat, targetLng, markCount++);
subMarks.add(mark);
seqID += 1;
}
}
return subMarks;
}
} }
@@ -14,6 +14,7 @@ import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import java.util.zip.Checksum; import java.util.zip.Checksum;
import javafx.util.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import seng302.gameServer.messages.BoatAction; import seng302.gameServer.messages.BoatAction;
@@ -25,8 +26,14 @@ import seng302.gameServer.messages.CustomizeRequestType;
import seng302.gameServer.messages.Message; import seng302.gameServer.messages.Message;
import seng302.gameServer.messages.RegistrationRequestMessage; import seng302.gameServer.messages.RegistrationRequestMessage;
import seng302.gameServer.messages.RegistrationResponseStatus; import seng302.gameServer.messages.RegistrationResponseStatus;
import seng302.gameServer.messages.XMLMessage;
import seng302.gameServer.messages.XMLMessageSubType;
import seng302.model.stream.packets.PacketType; import seng302.model.stream.packets.PacketType;
import seng302.model.stream.packets.StreamPacket; import seng302.model.stream.packets.StreamPacket;
import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
/** /**
* A class describing a single connection to a Server for the purposes of sending and receiving on * A class describing a single connection to a Server for the purposes of sending and receiving on
@@ -44,7 +51,7 @@ public class ClientToServerThread implements Runnable {
@FunctionalInterface @FunctionalInterface
public interface DisconnectedFromHostListener { public interface DisconnectedFromHostListener {
void notifYDisconnection (String message); void notifyDisconnection(String message);
} }
private class ByteReadException extends Exception { private class ByteReadException extends Exception {
@@ -68,7 +75,7 @@ public class ClientToServerThread implements Runnable {
private Timer upWindPacketTimer = new Timer(); private Timer upWindPacketTimer = new Timer();
private Timer downWindPacketTimer = new Timer(); private Timer downWindPacketTimer = new Timer();
private boolean upwindTimerFlag = false, downwindTimerFlag = false; private boolean upwindTimerFlag = false, downwindTimerFlag = false;
static public final int PACKET_SENDING_INTERVAL_MS = 100; public static final int PACKET_SENDING_INTERVAL_MS = 100;
private int clientId = -1; private int clientId = -1;
@@ -166,7 +173,7 @@ public class ClientToServerThread implements Runnable {
private void notifyDisconnectListeners (String message) { private void notifyDisconnectListeners (String message) {
if (socketOpen) { if (socketOpen) {
for (DisconnectedFromHostListener listener : disconnectionListeners) { for (DisconnectedFromHostListener listener : disconnectionListeners) {
listener.notifYDisconnection(message); listener.notifyDisconnection(message);
} }
} }
} }
@@ -191,7 +198,7 @@ public class ClientToServerThread implements Runnable {
* @param packet The registration requests packet * @param packet The registration requests packet
*/ */
private void processRegistrationResponse(StreamPacket packet){ private void processRegistrationResponse(StreamPacket packet){
int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 3)); int sourceId = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 0, 4));
int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5)); int statusCode = (int) Message.bytesToLong(Arrays.copyOfRange(packet.getPayload(), 4,5));
RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode); RegistrationResponseStatus status = RegistrationResponseStatus.getResponseStatus(statusCode);
@@ -368,4 +375,25 @@ public class ClientToServerThread implements Runnable {
public int getClientId () { public int getClientId () {
return clientId; return clientId;
} }
public void sendXML(String path, String serverName, Integer legRepeats, Integer maxPlayers, Boolean tokensEnabled) {
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
path, serverName, legRepeats, maxPlayers, tokensEnabled
);
XMLGenerator xmlGenerator = new XMLGenerator();
xmlGenerator.setRegattaTemplate(regattaRace.getKey());
xmlGenerator.setRaceTemplate(regattaRace.getValue());
String regatta = xmlGenerator.getRegattaAsXml();
String race = xmlGenerator.getRaceAsXml();
sendByteBuffer(
new XMLMessage(
regatta, XMLMessageSubType.REGATTA, regatta.length()
).getBuffer()
);
sendByteBuffer(
new XMLMessage(
race, XMLMessageSubType.RACE, race.length()
).getBuffer()
);
}
} }
@@ -10,8 +10,6 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
@@ -19,7 +17,6 @@ import javafx.fxml.FXMLLoader;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.util.Pair; import javafx.util.Pair;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
@@ -40,7 +37,6 @@ import seng302.model.stream.parser.RaceStatusData;
import seng302.model.stream.parser.YachtEventData; import seng302.model.stream.parser.YachtEventData;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData; import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.model.token.TokenType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.utilities.StreamParser; import seng302.utilities.StreamParser;
import seng302.utilities.XMLGenerator; import seng302.utilities.XMLGenerator;
@@ -125,9 +121,11 @@ public class GameClient {
* @param ipAddress IP to connect to. * @param ipAddress IP to connect to.
* @param portNumber Port to connect to. * @param portNumber Port to connect to.
*/ */
public ServerDescription runAsHost(String ipAddress, Integer portNumber, String serverName, Integer maxPlayers) { public ServerDescription runAsHost(
String ipAddress, Integer portNumber, String serverName, Integer maxPlayers, String race,
Integer numLegs, Boolean tokensEnabled
) {
XMLGenerator.setDefaultRaceName(serverName); XMLGenerator.setDefaultRaceName(serverName);
GameState.setMaxPlayers(maxPlayers);
server = new MainServerThread(); server = new MainServerThread();
@@ -136,7 +134,7 @@ public class GameClient {
} catch (IOException e) { } catch (IOException e) {
showConnectionError("Cannot connect to server as host"); showConnectionError("Cannot connect to server as host");
} }
socketThread.sendXML(race, serverName, numLegs, maxPlayers, tokensEnabled);
while (regattaData == null){ while (regattaData == null){
try { try {
Thread.sleep(100); Thread.sleep(100);
@@ -216,6 +214,7 @@ public class GameClient {
break; break;
case RACE_XML: case RACE_XML:
System.out.println("HEY I GOT A RACE MANG AND I AM CLIENT " + ((Boolean) (server==null)).toString());
RaceXMLData raceXMLData = XMLParser.parseRace( RaceXMLData raceXMLData = XMLParser.parseRace(
StreamParser.extractXmlMessage(packet) StreamParser.extractXmlMessage(packet)
); );
@@ -255,7 +254,12 @@ public class GameClient {
break; break;
case YACHT_EVENT_CODE: case YACHT_EVENT_CODE:
processYachtEvent(StreamParser.extractYachtEventCode(packet)); YachtEventData yachtEventData = StreamParser.extractYachtEventCode(packet);
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(StreamParser.extractYachtEventCode(packet));
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN.getCode()) {
showPickUp();
}
break; break;
case CHATTER_TEXT: case CHATTER_TEXT:
@@ -414,66 +418,21 @@ public class GameClient {
return courseData; return courseData;
} }
/**
* Appropriately displays the event client side given the YachtEventCode (collision / token..)
*
* @param yachtEventData The YachtEvent data packet
*/
private void processYachtEvent(YachtEventData yachtEventData) {
ClientYacht thisYacht = allBoatsMap.get(yachtEventData.getSubjectId().intValue());
if (yachtEventData.getEventId() == YachtEventType.COLLISION.getCode()) {
showCollisionAlert(thisYacht);
} else if (yachtEventData.getEventId() == YachtEventType.POWER_DOWN.getCode()) {
thisYacht.powerDown();
Sounds.playTokenPickupSound(); // TODO: 23/09/17 This should be power down sound
} else if (yachtEventData.getEventId() == YachtEventType.BUMPER_CRASH.getCode()) {
showDisableAlert(thisYacht);
} else { //Else all token pickup types
TokenType tokenType = null;
if (yachtEventData.getEventId() == YachtEventType.TOKEN_VELOCITY.getCode()) {
tokenType = TokenType.BOOST;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_BUMPER.getCode()) {
tokenType = TokenType.BUMPER;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_HANDLING.getCode()) {
tokenType = TokenType.HANDLING;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_RANDOM.getCode()) {
tokenType = TokenType.RANDOM;
} else if (yachtEventData.getEventId() == YachtEventType.TOKEN_WIND_WALKER.getCode()) {
tokenType = TokenType.WIND_WALKER;
}
Sounds.playTokenPickupSound();
thisYacht.setPowerUp(tokenType);
}
}
/**
* Turns a disabled boat black until the bumper affect wears off
*
* @param yacht The yacht to show as disabled
*/
private void showDisableAlert(ClientYacht yacht) {
Color originalColor = yacht.getColour();
yacht.setColour(Color.BLACK);
Timer disableTimer = new Timer("Disable Timer");
disableTimer.schedule(new TimerTask() {
@Override
public void run() {
yacht.setColour(originalColor);
}
}, GameState.BUMPER_DISABLE_TIME);
}
/** /**
* Tells race view to show a collision animation. * Tells race view to show a collision animation.
*/ */
private void showCollisionAlert(ClientYacht yacht) { private void showCollisionAlert(YachtEventData yachtEventData) {
Sounds.playCrashSound(); Sounds.playCrashSound();
raceState.storeCollision(yacht); raceState.storeCollision(
allBoatsMap.get(
yachtEventData.getSubjectId().intValue()
)
);
}
// TODO: 11/09/17 wmu16 - Add in functionality to viually indicate a pickup to a user
private void showPickUp() {
Sounds.playTokenPickupSound();
} }
private void formatAndSendChatMessage(String rawChat) { private void formatAndSendChatMessage(String rawChat) {
+19 -431
View File
@@ -1,443 +1,31 @@
package seng302.visualiser; package seng302.visualiser;
import javafx.application.Platform; import java.util.ArrayList;
import javafx.collections.ObservableList; import java.util.List;
import javafx.geometry.Point2D; import javafx.scene.Group;
import javafx.scene.*; import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Polygon;
import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.ScaledPoint;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.assets_2D.*;
import java.util.*;
/** /**
* Created by cir27 on 20/07/17. * Common elements of game visualizing classes.
*/ */
public class GameView extends Pane { public abstract class GameView {
private double bufferSize = 50; double canvasWidth, canvasHeight;
private double horizontalBuffer = 0; ScaledPoint scaledPoint;
private double canvasWidth = 1100; List<Limit> borderPoints;
private double canvasHeight = 920; Group gameObjects = new Group();
private boolean horizontalInversion = false; Group markers = new Group();
Group tokens = new Group();
List<CompoundMark> course = new ArrayList<>();
List<CompoundMark> compoundMarks = new ArrayList<>();
List<Corner> courseOrder = new ArrayList<>();
private double distanceScaleFactor; public abstract Node getAssets();
private ScaleDirection scaleDirection; public abstract void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence);
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint; public abstract void updateBorder(List<Limit> border);
private double referencePointX, referencePointY;
private Polygon raceBorder = new CourseBoundary();
/* Note that if either of these is null then values for it have not been added and the other
should be used as the limits of the map. */
private List<Limit> borderPoints;
private Map<Mark, Marker2D> markerObjects;
private ObservableList<Node> gameObjects;
private Group markers = new Group();
private Group tokens = new Group();
private List<CompoundMark> course = new ArrayList<>();
private ImageView mapImage = new ImageView();
private enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
public GameView () {
gameObjects = this.getChildren();
gameObjects.addAll(mapImage, raceBorder, markers, tokens);
}
/**
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
* case the course is added relative ot the border.
*
* @param newCourse the mark objects that make up the course.
* @param sequence The sequence the marks travel through
*/
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
markerObjects = new HashMap<>();
for (Corner corner : sequence) { //Makes course out of all compound marks.
for (CompoundMark compoundMark : newCourse) {
if (corner.getCompoundMarkID() == compoundMark.getId()) {
course.add(compoundMark);
}
}
}
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
for (Corner corner : sequence){
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
compoundMark.setRoundingSide(
RoundingSide.getRoundingSide(corner.getRounding())
);
}
final List<Gate> gates = new ArrayList<>();
Paint colour = Color.BLACK;
//Creates new markers
for (CompoundMark cMark : newCourse) {
//Set start and end colour
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
colour = Color.GREEN;
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
colour = Color.RED;
}
//Create mark dots
for (Mark mark : cMark.getMarks()) {
makeAndBindMarker(mark, colour);
}
//Create gate line
if (cMark.isGate()) {
for (int i = 1; i < cMark.getMarks().size(); i++) {
gates.add(
makeAndBindGate(
markerObjects.get(cMark.getSubMark(i)),
markerObjects.get(cMark.getSubMark(i + 1)),
colour
)
);
}
}
colour = Color.BLACK;
}
createMarkArrows(sequence);
//Scale race to markers if there is no border.
if (borderPoints == null) {
rescaleRace(new ArrayList<>(markerObjects.keySet()));
}
//Move the Markers to initial position.
markerObjects.forEach(((mark, marker2D) -> {
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng());
marker2D.setLayoutX(p2d.getX());
marker2D.setLayoutY(p2d.getY());
}));
Platform.runLater(() -> {
markers.getChildren().clear();
markers.getChildren().addAll(gates);
markers.getChildren().addAll(markerObjects.values());
});
}
/**
* Calculates all the data needed for to create mark arrows. Requires that a course has been
* added to the gameview.
* @param sequence The order in which marks are traversed.
*/
private void createMarkArrows (List<Corner> sequence) {
for (int i=1; i < sequence.size()-1; i++) { //General case.
double averageLat = 0;
double averageLng = 0;
int numMarks = course.get(i-1).getMarks().size();
for (Mark mark : course.get(i-1).getMarks()) {
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
numMarks = course.get(i+1).getMarks().size();
averageLat = 0;
averageLng = 0;
for (Mark mark : course.get(i+1).getMarks()) {
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint nextMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
// TODO: 16/08/17 This comparison doesn't need to exist but the alternative is to user server enum client side.
for (Mark mark : course.get(i).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
GeoUtility.getBearing(lastMarkAv, mark),
GeoUtility.getBearing(mark, nextMarkAv)
);
}
}
createStartLineArrows();
createFinishLineArrows();
}
private void createStartLineArrows () {
double averageLat = 0;
double averageLng = 0;
int numMarks = 0;
for (Mark mark : course.get(1).getMarks()) {
numMarks += 1;
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint firstMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
for (Mark mark : course.get(0).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
0d, //90
GeoUtility.getBearing(mark, firstMarkAv)
);
}
}
private void createFinishLineArrows () {
double numMarks = 0;
double averageLat = 0;
double averageLng = 0;
for (Mark mark : course.get(course.size()-2).getMarks()) {
numMarks += 1;
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint secondToLastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
for (Mark mark : course.get(course.size()-1).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
GeoUtility.getBearing(secondToLastMarkAv, mark),
GeoUtility.getBearing(mark, mark)
);
}
}
/**
* Creates a new Marker and binds it's position to the given Mark.
*
* @param observableMark The mark to bind the marker to.
* @param colour The desired colour of the mark
*/
private void makeAndBindMarker(Mark observableMark, Paint colour) {
Marker2D marker2D = new Marker2D(colour);
// marker.addArrows(MarkArrowFactory.RoundingSide.PORT, ThreadLocalRandom.current().nextDouble(91, 180), ThreadLocalRandom.current().nextDouble(1, 90));
markerObjects.put(observableMark, marker2D);
observableMark.addPositionListener((mark, lat, lon) -> {
Point2D p2d = findScaledXY(lat, lon);
markerObjects.get(mark).setLayoutX(p2d.getX());
markerObjects.get(mark).setLayoutY(p2d.getY());
});
}
/**
* Creates a new gate connecting the given marks.
*
* @param m1 The first Mark of the gate.
* @param m2 The second Mark of the gate.
* @param colour The desired colour of the gate.
* @return the new gate.
*/
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) {
Gate gate = new Gate(colour);
gate.startXProperty().bind(
m1.layoutXProperty()
);
gate.startYProperty().bind(
m1.layoutYProperty()
);
gate.endXProperty().bind(
m2.layoutXProperty()
);
gate.endYProperty().bind(
m2.layoutYProperty()
);
return gate;
}
/**
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
* border already exists. Assumes the border is larger than the course.
*
* @param border the race border to be drawn.
*/
public void updateBorder(List<Limit> border) {
if (borderPoints == null) {
borderPoints = border;
rescaleRace(new ArrayList<>(borderPoints));
}
rescaleRace(new ArrayList<>(border));
List<Double> boundaryPoints = new ArrayList<>();
for (Limit limit : border) {
Point2D location = findScaledXY(limit.getLat(), limit.getLng());
boundaryPoints.add(location.getX());
boundaryPoints.add(location.getY());
}
raceBorder.getPoints().setAll(boundaryPoints);
}
/**
* Rescales the race to the size of the window.
*
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
*/
public void rescaleRace(List<GeoPoint> limitingCoordinates) {
//Check is called once to avoid unnecessarily change the course limits once the race is running
findMinMaxPoint(limitingCoordinates);
double minLonToMaxLon = scaleRaceExtremities();
calculateReferencePointLocation(minLonToMaxLon);
}
/**
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
* the leftmost point, rightmost point, southern most point and northern most point
* respectively.
*/
private void findMinMaxPoint(List<GeoPoint> points) {
List<GeoPoint> sortedPoints = new ArrayList<>(points);
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
horizontalInversion = true;
}
}
/**
* Calculates the location of a reference point, this is always the point with minimum latitude,
* in relation to the canvas.
*
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
* maximum longitude.
*/
private void calculateReferencePointLocation(double minLonToMaxLon) {
GeoPoint referencePoint = minLatPoint;
double referenceAngle;
if (scaleDirection == ScaleDirection.HORIZONTAL) {
referenceAngle = Math.abs(
GeoUtility.getBearingRad(referencePoint, minLonPoint)
);
referencePointX =
bufferSize + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
.getDistance(referencePoint, minLonPoint);
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
referencePointY = canvasHeight - (bufferSize + bufferSize);
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
.getDistance(referencePoint, maxLatPoint);
referencePointY = referencePointY / 2;
referencePointY += bufferSize;
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
.getDistance(referencePoint, maxLatPoint);
} else {
referencePointY = canvasHeight - bufferSize;
referenceAngle = Math.abs(
Math.toRadians(
GeoUtility.getDistance(referencePoint, minLonPoint)
)
);
referencePointX = bufferSize;
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
.getDistance(referencePoint, minLonPoint);
referencePointX +=
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
/ 2;
referencePointX += horizontalBuffer;
}
if (horizontalInversion) {
referencePointX = canvasWidth - bufferSize - (referencePointX - bufferSize);
}
}
/**
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
* it to distanceScaleFactor Returns the max horizontal distance of the map.
*/
private double scaleRaceExtremities() {
double vertAngle = Math.abs(
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
);
double vertDistance =
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
double horiAngle = Math.abs(
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
);
if (horiAngle <= (Math.PI / 2)) {
horiAngle = (Math.PI / 2) - horiAngle;
} else {
horiAngle = horiAngle - (Math.PI / 2);
}
double horiDistance =
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
scaleDirection = ScaleDirection.HORIZONTAL;
} else {
distanceScaleFactor = vertScale;
scaleDirection = ScaleDirection.VERTICAL;
}
return horiDistance;
}
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
double distanceFromReference;
double angleFromReference;
double xAxisLocation = referencePointX;
double yAxisLocation = referencePointY;
angleFromReference = GeoUtility.getBearingRad(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
);
distanceFromReference = GeoUtility.getDistance(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xAxisLocation += Math
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= Math
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
} else if (angleFromReference >= 0) {
angleFromReference = angleFromReference - Math.PI / 2;
xAxisLocation += Math
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
yAxisLocation += Math
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
angleFromReference = Math.abs(angleFromReference);
xAxisLocation -= Math
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
yAxisLocation -= Math
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
} else {
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
xAxisLocation -= Math
.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference);
yAxisLocation += Math
.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference);
}
if (horizontalInversion) {
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
}
return new Point2D(xAxisLocation, yAxisLocation);
}
public void setSize(Double width, Double height){
this.canvasWidth = width;
this.canvasHeight = height;
}
public void setHorizontalBuffer(Double buff){
this.horizontalBuffer = buff;
}
} }
+57 -261
View File
@@ -2,7 +2,6 @@ package seng302.visualiser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -24,14 +23,13 @@ import javafx.scene.transform.Translate;
import seng302.gameServer.messages.RoundingSide; import seng302.gameServer.messages.RoundingSide;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.GameKeyBind; import seng302.model.GameKeyBind;
import seng302.model.GeoPoint;
import seng302.model.KeyAction; import seng302.model.KeyAction;
import seng302.model.Limit; import seng302.model.Limit;
import seng302.model.ScaledPoint;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.token.Token; import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.cameras.ChaseCamera; import seng302.visualiser.cameras.ChaseCamera;
@@ -48,60 +46,39 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
/** /**
* Collection of animated3D assets that displays a race. * Collection of animated3D assets that displays a race.
*/ */
public class GameView3D extends GameView{
public class GameView3D {
private final double FOV = 60; private final double FOV = 60;
private final double DEFAULT_CAMERA_X = 0; private final double DEFAULT_CAMERA_X = 0;
private final double DEFAULT_CAMERA_Y = 155; private final double DEFAULT_CAMERA_Y = 100;
private Group root3D; private Group root3D;
private SubScene view; private SubScene view;
private Group gameObjects; private Group raceBorder = new Group();
// Cameras // Cameras
private PerspectiveCamera isometricCam; private PerspectiveCamera isometricCam;
private PerspectiveCamera topDownCam; private PerspectiveCamera topDownCam;
private PerspectiveCamera chaseCam; private PerspectiveCamera chaseCam;
private double bufferSize = 0;
private double canvasWidth = 200;
private double canvasHeight = 200;
private boolean horizontalInversion = false;
private double distanceScaleFactor;
private ScaleDirection scaleDirection;
private GeoPoint minLatPoint, minLonPoint, maxLatPoint, maxLonPoint;
private double referencePointX, referencePointY;
private Group raceBorder = new Group();
/* Note that if either of these is null then values for it have not been added and the other /* Note that if either of these is null then values for it have not been added and the other
should be used as the limits of the map. */ should be used as the limits of the map. */
private List<Limit> borderPoints;
private Map<Mark, Marker3D> markerObjects; private Map<Mark, Marker3D> markerObjects;
private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>(); private Map<ClientYacht, BoatObject> boatObjects = new HashMap<>();
private BoatObject selectedBoat = null; private BoatObject selectedBoat = null;
private Group wakesGroup = new Group(); private Group wakesGroup = new Group();
private Group boatObjectGroup = new Group(); private Group boatObjectGroup = new Group();
private Group markers = new Group();
private Group tokens = new Group();
private List<CompoundMark> course = new ArrayList<>();
private List<Node> mapTokens; private List<Node> mapTokens;
private AnimationTimer playerBoatAnimationTimer; private AnimationTimer playerBoatAnimationTimer;
private Group trail = new Group(); private Group trail = new Group();
private Double windDir; private Double windDir;
private enum ScaleDirection {
HORIZONTAL,
VERTICAL
}
public GameView3D () { public GameView3D () {
isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y); isometricCam = new IsometricCamera(DEFAULT_CAMERA_X, DEFAULT_CAMERA_Y);
topDownCam = new TopDownCamera(); topDownCam = new TopDownCamera();
chaseCam = new ChaseCamera(); chaseCam = new ChaseCamera();
canvasWidth = canvasHeight = 300;
for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) { for (PerspectiveCamera pc : Arrays.asList(isometricCam, topDownCam, chaseCam)) {
pc.setFarClip(600); pc.setFarClip(600);
pc.setNearClip(0.1); pc.setNearClip(0.1);
@@ -124,10 +101,14 @@ public class GameView3D {
scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement); scene.addEventHandler(KeyEvent.KEY_PRESSED, this::cameraMovement);
} }
}); });
} }
@Override
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) { public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
markerObjects = new HashMap<>(); markerObjects = new HashMap<>();
compoundMarks = newCourse;
for (Corner corner : sequence) { //Makes course out of all compound marks. for (Corner corner : sequence) { //Makes course out of all compound marks.
for (CompoundMark compoundMark : newCourse) { for (CompoundMark compoundMark : newCourse) {
@@ -178,11 +159,13 @@ public class GameView3D {
//Scale race to markers if there is no border. //Scale race to markers if there is no border.
if (borderPoints == null) { if (borderPoints == null) {
rescaleRace(new ArrayList<>(markerObjects.keySet())); scaledPoint = ScaledPoint.makeScaledPoint(
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), true
);
} }
//Move the Markers to initial position. //Move the Markers to initial position.
markerObjects.forEach(((mark, marker) -> { markerObjects.forEach(((mark, marker) -> {
Point2D p2d = findScaledXY(mark.getLat(), mark.getLng()); Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
marker.setLayoutX(p2d.getX()); marker.setLayoutX(p2d.getX());
marker.setLayoutY(p2d.getY()); marker.setLayoutY(p2d.getY());
})); }));
@@ -202,7 +185,7 @@ public class GameView3D {
private void makeAndBindMarker(Mark observableMark, ModelType markerType) { private void makeAndBindMarker(Mark observableMark, ModelType markerType) {
markerObjects.put(observableMark, new Marker3D(markerType)); markerObjects.put(observableMark, new Marker3D(markerType));
observableMark.addPositionListener((mark, lat, lon) -> { observableMark.addPositionListener((mark, lat, lon) -> {
Point2D p2d = findScaledXY(lat, lon); Point2D p2d = scaledPoint.findScaledXY(lat, lon);
markerObjects.get(mark).setLayoutX(p2d.getX()); markerObjects.get(mark).setLayoutX(p2d.getX());
markerObjects.get(mark).setLayoutY(p2d.getY()); markerObjects.get(mark).setLayoutY(p2d.getY());
}); });
@@ -217,8 +200,8 @@ public class GameView3D {
* @return the new gate. * @return the new gate.
*/ */
private Group makeGate(Mark m1, Mark m2, ModelType gateType) { private Group makeGate(Mark m1, Mark m2, ModelType gateType) {
Point2D m1Location = findScaledXY(m1); Point2D m1Location = scaledPoint.findScaledXY(m1);
Point2D m2Location = findScaledXY(m2); Point2D m2Location = scaledPoint.findScaledXY(m2);
Group barrier = ModelFactory.importModel(gateType).getAssets(); Group barrier = ModelFactory.importModel(gateType).getAssets();
barrier.getTransforms().addAll( barrier.getTransforms().addAll(
@@ -276,171 +259,31 @@ public class GameView3D {
} }
} }
/**
* Sets the class variables minLatPoint, maxLatPoint, minLonPoint, maxLonPoint to the point with
* the leftmost point, rightmost point, southern most point and northern most point
* respectively.
*/
private void findMinMaxPoint(List<GeoPoint> points) {
List<GeoPoint> sortedPoints = new ArrayList<>(points);
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLat));
minLatPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLat = sortedPoints.get(sortedPoints.size() - 1);
maxLatPoint = new GeoPoint(maxLat.getLat(), maxLat.getLng());
sortedPoints.sort(Comparator.comparingDouble(GeoPoint::getLng));
minLonPoint = new GeoPoint(sortedPoints.get(0).getLat(), sortedPoints.get(0).getLng());
GeoPoint maxLon = sortedPoints.get(sortedPoints.size() - 1);
maxLonPoint = new GeoPoint(maxLon.getLat(), maxLon.getLng());
if (maxLonPoint.getLng() - minLonPoint.getLng() > 180) {
horizontalInversion = true;
}
}
/**
* Calculates the location of a reference point, this is always the point with minimum latitude,
* in relation to the canvas.
*
* @param minLonToMaxLon The horizontal distance between the point of minimum longitude to
* maximum longitude.
*/
private void calculateReferencePointLocation(double minLonToMaxLon) {
GeoPoint referencePoint = minLatPoint;
double referenceAngle;
if (scaleDirection == ScaleDirection.HORIZONTAL) {
referenceAngle = Math.abs(
GeoUtility.getBearingRad(referencePoint, minLonPoint)
);
referencePointX =
-100 + distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
.getDistance(referencePoint, minLonPoint);
referenceAngle = Math.abs(GeoUtility.getDistance(referencePoint, maxLatPoint));
referencePointY = -100 + canvasHeight - (bufferSize + bufferSize);
referencePointY -= distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
.getDistance(referencePoint, maxLatPoint);
referencePointY = referencePointY / 2;
referencePointY += bufferSize;
referencePointY += distanceScaleFactor * Math.cos(referenceAngle) * GeoUtility
.getDistance(referencePoint, maxLatPoint);
} else {
referencePointY = -100 + canvasHeight - bufferSize;
referenceAngle = Math.abs(
Math.toRadians(
GeoUtility.getDistance(referencePoint, minLonPoint)
)
);
referencePointX = -100 + bufferSize;
referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * GeoUtility
.getDistance(referencePoint, minLonPoint);
referencePointX +=
((canvasWidth - (bufferSize + bufferSize)) - (minLonToMaxLon * distanceScaleFactor))
/ 2;
}
if (horizontalInversion) {
referencePointX = -100 + canvasWidth - bufferSize - (referencePointX - bufferSize);
}
}
/**
* Finds the scale factor necessary to fit all race markers within the onscreen map and assigns
* it to distanceScaleFactor Returns the max horizontal distance of the map.
*/
private double scaleRaceExtremities() {
double vertAngle = Math.abs(
GeoUtility.getBearingRad(minLatPoint, maxLatPoint)
);
double vertDistance =
Math.cos(vertAngle) * GeoUtility.getDistance(minLatPoint, maxLatPoint);
double horiAngle = Math.abs(
GeoUtility.getBearingRad(minLonPoint, maxLonPoint)
);
if (horiAngle <= (Math.PI / 2)) {
horiAngle = (Math.PI / 2) - horiAngle;
} else {
horiAngle = horiAngle - (Math.PI / 2);
}
double horiDistance =
Math.cos(horiAngle) * GeoUtility.getDistance(minLonPoint, maxLonPoint);
double vertScale = (canvasHeight - (bufferSize + bufferSize)) / vertDistance;
if ((horiDistance * vertScale) > (canvasWidth - (bufferSize + bufferSize))) {
distanceScaleFactor = (canvasWidth - (bufferSize + bufferSize)) / horiDistance;
scaleDirection = ScaleDirection.HORIZONTAL;
} else {
distanceScaleFactor = vertScale;
scaleDirection = ScaleDirection.VERTICAL;
}
return horiDistance;
}
private Point2D findScaledXY(GeoPoint unscaled) {
return findScaledXY(unscaled.getLat(), unscaled.getLng());
}
private Point2D findScaledXY(double unscaledLat, double unscaledLon) {
double distanceFromReference;
double angleFromReference;
double xAxisLocation = referencePointX;
double yAxisLocation = referencePointY;
angleFromReference = GeoUtility.getBearingRad(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
);
distanceFromReference = GeoUtility.getDistance(
minLatPoint, new GeoPoint(unscaledLat, unscaledLon)
);
if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) {
xAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
} else if (angleFromReference >= 0) {
angleFromReference = angleFromReference - Math.PI / 2;
xAxisLocation += distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
} else if (angleFromReference < 0 && angleFromReference >= -Math.PI / 2) {
angleFromReference = Math.abs(angleFromReference);
xAxisLocation -= distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
yAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
} else {
angleFromReference = Math.abs(angleFromReference) - Math.PI / 2;
xAxisLocation -= distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference;
yAxisLocation += distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference;
}
if (horizontalInversion) {
xAxisLocation = canvasWidth - bufferSize - (xAxisLocation - bufferSize);
}
return new Point2D(xAxisLocation, yAxisLocation);
}
public void cameraMovement(KeyEvent event) { public void cameraMovement(KeyEvent event) {
GameKeyBind keyBinds = GameKeyBind.getInstance(); GameKeyBind keyBinds = GameKeyBind.getInstance();
KeyAction keyPressed = keyBinds.getKeyAction(event.getCode()); KeyAction keyPressed = keyBinds.getKeyAction(event.getCode());
if (keyPressed != null) { switch (keyPressed) {
switch (keyPressed) { case ZOOM_IN:
case ZOOM_IN: ((RaceCamera) view.getCamera()).zoomIn();
((RaceCamera) view.getCamera()).zoomIn(); break;
break; case ZOOM_OUT:
case ZOOM_OUT: ((RaceCamera) view.getCamera()).zoomOut();
((RaceCamera) view.getCamera()).zoomOut(); break;
break; case FORWARD:
case FORWARD: ((RaceCamera) view.getCamera()).panUp();
((RaceCamera) view.getCamera()).panUp(); break;
break; case BACKWARD:
case BACKWARD: ((RaceCamera) view.getCamera()).panDown();
((RaceCamera) view.getCamera()).panDown(); break;
break; case LEFT:
case LEFT: ((RaceCamera) view.getCamera()).panLeft();
((RaceCamera) view.getCamera()).panLeft(); break;
break; case RIGHT:
case RIGHT: ((RaceCamera) view.getCamera()).panRight();
((RaceCamera) view.getCamera()).panRight(); break;
break; case VIEW:
case VIEW: toggleCamera();
toggleCamera(); break;
break;
}
} }
} }
@@ -456,19 +299,6 @@ public class GameView3D {
} }
} }
/**
* Rescales the race to the size of the window.
*
* @param limitingCoordinates the set of geo points that contains the extremities of the race.
*/
private void rescaleRace(List<GeoPoint> limitingCoordinates) {
//Check is called once to avoid unnecessarily change the course limits once the race is running
findMinMaxPoint(limitingCoordinates);
double minLonToMaxLon = scaleRaceExtremities();
calculateReferencePointLocation(minLonToMaxLon);
// drawGoogleMap();
}
/** /**
* Draws all the boats. * Draws all the boats.
* @param yachts The yachts to set in the race * @param yachts The yachts to set in the race
@@ -484,8 +314,11 @@ public class GameView3D {
wakesGroup.getChildren().add(newBoat.getWake()); wakesGroup.getChildren().add(newBoat.getWake());
wakes.add(newBoat.getWake()); wakes.add(newBoat.getWake());
boatObjectGroup.getChildren().add(newBoat); boatObjectGroup.getChildren().add(newBoat);
clientYacht.addLocationListener(this::updateBoatLocation); clientYacht.addLocationListener((boat, lat, lon, heading, sailIn, velocity) -> {
clientYacht.addColorChangeListener(this::updateBoatColor); BoatObject bo = boatObjects.get(boat);
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
});
if (clientYacht.getSourceId().equals( if (clientYacht.getSourceId().equals(
ViewManager.getInstance().getGameClient().getServerThread().getClientId())) { ViewManager.getInstance().getGameClient().getServerThread().getClientId())) {
@@ -503,23 +336,6 @@ public class GameView3D {
return view; return view;
} }
/**
* Updates the boatObjects color with that of the clientYachts object. Used in notification from
* a listener on this attribute in clientYacht to re paint the boat mesh
*
* @param clientYacht The yacht to update the colour for
*/
private void updateBoatColor(ClientYacht clientYacht) {
boatObjects.get(clientYacht).setFill(clientYacht.getColour());
}
private void updateBoatLocation(ClientYacht boat, Double lat, Double lon, Double heading,
Boolean sailIn, Double velocity) {
BoatObject bo = boatObjects.get(boat);
Point2D p2d = findScaledXY(lat, lon);
bo.moveTo(p2d.getX(), p2d.getY(), heading, velocity, sailIn, windDir);
}
/** /**
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a * Adds a border to the GameView and rescales to the size of the border, does not rescale if a
* border already exists. Assumes the border is larger than the course. * border already exists. Assumes the border is larger than the course.
@@ -529,18 +345,20 @@ public class GameView3D {
public void updateBorder(List<Limit> border) { public void updateBorder(List<Limit> border) {
if (borderPoints == null) { if (borderPoints == null) {
borderPoints = border; borderPoints = border;
rescaleRace(new ArrayList<>(borderPoints)); scaledPoint = ScaledPoint.makeScaledPoint(
canvasWidth, canvasHeight, new ArrayList<>(borderPoints), true
);
} }
List<Node> boundaryAssets = new ArrayList<>(); List<Node> boundaryAssets = new ArrayList<>();
Point2D lastLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng()); Point2D lastLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets(); Group pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
pylon.setLayoutX(lastLocation.getX()); pylon.setLayoutX(lastLocation.getX());
pylon.setLayoutY(lastLocation.getY()); pylon.setLayoutY(lastLocation.getY());
boundaryAssets.add(pylon); boundaryAssets.add(pylon);
for (int i=1; i<border.size(); i++) { for (int i=1; i<border.size(); i++) {
Point2D location = findScaledXY(border.get(i).getLat(), border.get(i).getLng()); Point2D location = scaledPoint.findScaledXY(border.get(i).getLat(), border.get(i).getLng());
pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets(); pylon = ModelFactory.importModel(ModelType.BORDER_PYLON).getAssets();
pylon.setLayoutX(location.getX()); pylon.setLayoutX(location.getX());
pylon.setLayoutY(location.getY()); pylon.setLayoutY(location.getY());
@@ -566,7 +384,7 @@ public class GameView3D {
boundaryAssets.add(pylon); boundaryAssets.add(pylon);
} }
Point2D firstLocation = findScaledXY(border.get(0).getLat(), border.get(0).getLng()); Point2D firstLocation = scaledPoint.findScaledXY(border.get(0).getLat(), border.get(0).getLng());
Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets(); Group barrier = ModelFactory.importModel(ModelType.BORDER_BARRIER).getAssets();
barrier.getTransforms().addAll( barrier.getTransforms().addAll(
new Rotate( new Rotate(
@@ -594,28 +412,8 @@ public class GameView3D {
public void updateTokens(List<Token> newTokens) { public void updateTokens(List<Token> newTokens) {
mapTokens = new ArrayList<>(); mapTokens = new ArrayList<>();
for (Token token : newTokens) { for (Token token : newTokens) {
Point2D location = findScaledXY(token.getLat(), token.getLng()); Point2D location = scaledPoint.findScaledXY(token.getLat(), token.getLng());
Node tokenObject = ModelFactory.importModel(ModelType.VELOCITY_PICKUP).getAssets();
ModelType modelType = null;
switch (token.getTokenType()) {
case BOOST:
modelType = ModelType.VELOCITY_PICKUP;
break;
case HANDLING:
modelType = ModelType.HANDLING_PICKUP;
break;
case BUMPER:
modelType = ModelType.BUMPER_PICKUP;
break;
case RANDOM:
modelType = ModelType.RANDOM_PICKUP;
break;
case WIND_WALKER:
modelType = ModelType.WIND_WALKER_PICKUP;
break;
}
Node tokenObject = ModelFactory.importModel(modelType).getAssets();
tokenObject.setLayoutX(location.getX()); tokenObject.setLayoutX(location.getX());
tokenObject.setLayoutY(location.getY()); tokenObject.setLayoutY(location.getY());
mapTokens.add(tokenObject); mapTokens.add(tokenObject);
@@ -630,19 +428,17 @@ public class GameView3D {
playerYacht.toggleSail(); playerYacht.toggleSail();
playerBoatAnimationTimer = new AnimationTimer() { playerBoatAnimationTimer = new AnimationTimer() {
double count = 60; Point2D lastLocation = scaledPoint.findScaledXY(playerYacht.getLocation());
Point2D lastLocation = findScaledXY(playerYacht.getLocation());
@Override @Override
public void handle(long now) { public void handle(long now) {
if (--count == 0) { Point2D location = scaledPoint.findScaledXY(playerYacht.getLocation());
count = 60; if (Math.abs(lastLocation.distance(location)) > 2) {
Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets(); Node segment = ModelFactory.importModel(ModelType.TRAIL_SEGMENT).getAssets();
Point2D location = findScaledXY(playerYacht.getLocation()); location = scaledPoint.findScaledXY(playerYacht.getLocation());
segment.getTransforms().addAll( segment.getTransforms().addAll(
new Translate(location.getX(), location.getY(), 0), new Translate(location.getX(), location.getY(), 0),
new Rotate(playerYacht.getHeading(), new Point3D(0,0,1)), new Rotate(playerYacht.getHeading(), new Point3D(0,0,1))
new Scale(1, lastLocation.distance(location) / 5, 1)
); );
trail.getChildren().add(segment); trail.getChildren().add(segment);
if (trail.getChildren().size() > 50) { if (trail.getChildren().size() > 50) {
@@ -0,0 +1,120 @@
package seng302.visualiser;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.Node;
import javafx.util.Pair;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.model.stream.xml.generator.RaceXMLTemplate;
import seng302.model.stream.xml.generator.RegattaXMLTemplate;
import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.stream.xml.parser.RegattaXMLData;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
/**
* Makes maps from map definition xml files.
*/
public class MapMaker {
private List<MapPreview> mapPreviews = new ArrayList<>();
private List<RaceXMLData> races = new ArrayList<>();
private List<RegattaXMLData> regattas = new ArrayList<>();
private List<String> filePaths = new ArrayList<>();
private List<Integer> maxPlayers = new ArrayList<>();
private static MapMaker instance;
private int index = 0;
private XMLGenerator xmlGenerator = new XMLGenerator();
public static MapMaker getInstance() {
if (instance == null) {
instance = new MapMaker();
}
return instance;
}
private MapMaker() {
File dir = new File(MapMaker.class.getResource("/maps/").getPath());
File[] directoryListing = dir.listFiles();
if (directoryListing != null) {
for (File child : directoryListing) {
Pair<RegattaXMLTemplate, RaceXMLTemplate> regattaRace = XMLParser.parseRaceDef(
child.getAbsolutePath(), "", 1, null, false
);
filePaths.add(child.getAbsolutePath());
RegattaXMLTemplate regattaTemplate = regattaRace.getKey();
regattas.add(new RegattaXMLData(
regattaTemplate.getRegattaId(),
regattaTemplate.getName(),
regattaTemplate.getCourseName(),
regattaTemplate.getLatitude(),
regattaTemplate.getLongitude(),
regattaTemplate.getUtcOffset()
));
RaceXMLTemplate raceTemplate = regattaRace.getValue();
xmlGenerator.setRaceTemplate(raceTemplate);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
}
RaceXMLData race = XMLParser.parseRace(doc);
maxPlayers.add(XMLParser.getMaxPlayers(doc));
mapPreviews.add(new MapPreview(
new ArrayList<>(race.getCompoundMarks().values()),
race.getMarkSequence(), race.getCourseLimit()
));
races.add(race);
}
}
}
public void next() {
index += 1;
if (index >= mapPreviews.size()) {
index = 0;
}
}
public void previous() {
index -= 1;
if (index < 0) {
index = mapPreviews.size() - 1;
}
}
public Node getCurrentGameView() {
return mapPreviews.get(index).getAssets();
}
public RaceXMLData getCurrentRace() {
return races.get(index);
}
public RegattaXMLData getCurrentRegatta() {
return regattas.get(index);
}
public String getCurrentRacePath() {
return filePaths.get(index);
}
public Integer getMaxPlayers() {
return maxPlayers.get(index);
}
}
@@ -0,0 +1,283 @@
package seng302.visualiser;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Platform;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Polygon;
import seng302.gameServer.messages.RoundingSide;
import seng302.model.GeoPoint;
import seng302.model.Limit;
import seng302.model.ScaledPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner;
import seng302.model.mark.Mark;
import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.MarkArrowFactory;
import seng302.visualiser.fxObjects.assets_2D.CourseBoundary;
import seng302.visualiser.fxObjects.assets_2D.Gate;
import seng302.visualiser.fxObjects.assets_2D.Marker2D;
/**
* Created by cir27 on 20/07/17.
*/
public class MapPreview extends GameView {
private Polygon raceBorder = new CourseBoundary();
private Map<Mark, Marker2D> markerObjects;
public MapPreview(List<CompoundMark> marks, List<Corner> course, List<Limit> border) {
this.compoundMarks = marks;
this.courseOrder = course;
this.borderPoints = border;
gameObjects.getChildren().addAll(raceBorder, markers, tokens);
gameObjects.parentProperty().addListener((obs, old, parent) -> {
if (parent != null) {
canvasWidth = parent.prefWidth(1);
canvasHeight = parent.prefHeight(1);
updateBorder(borderPoints);
updateCourse(compoundMarks, courseOrder);
}
});
}
@Override
public Node getAssets() {
return gameObjects;
}
public void setSize(double width, double height) {
canvasHeight = height;
canvasWidth = width;
updateBorder(borderPoints);
updateCourse(compoundMarks, courseOrder);
}
/**
* Adds a course to the GameView. The view is scaled accordingly unless a border is set in which
* case the course is added relative ot the border.
*
* @param newCourse the mark objects that make up the course.
* @param sequence The sequence the marks travel through
*/
@Override
public void updateCourse(List<CompoundMark> newCourse, List<Corner> sequence) {
if (newCourse.size() == 0) {
return;
}
compoundMarks = newCourse;
markerObjects = new HashMap<>();
courseOrder = sequence;
for (Corner corner : courseOrder) { //Makes course out of all compound marks.
for (CompoundMark compoundMark : newCourse) {
if (corner.getCompoundMarkID() == compoundMark.getId()) {
course.add(compoundMark);
}
}
}
// TODO: 16/08/17 Updating mark roundings here. It should not happen here. Nor should it be done this way.
for (Corner corner : sequence){
CompoundMark compoundMark = course.get(corner.getSeqID() - 1);
compoundMark.setRoundingSide(
RoundingSide.getRoundingSide(corner.getRounding())
);
}
final List<Gate> gates = new ArrayList<>();
Paint colour = Color.BLACK;
//Creates new markers
for (CompoundMark cMark : newCourse) {
//Set start and end colour
if (cMark.getId() == sequence.get(0).getCompoundMarkID()) {
colour = Color.GREEN;
} else if (cMark.getId() == sequence.get(sequence.size() - 1).getCompoundMarkID()) {
colour = Color.RED;
}
//Create mark dots
for (Mark mark : cMark.getMarks()) {
makeAndBindMarker(mark, colour);
}
//Create gate line
if (cMark.isGate()) {
for (int i = 1; i < cMark.getMarks().size(); i++) {
gates.add(
makeAndBindGate(
markerObjects.get(cMark.getSubMark(i)),
markerObjects.get(cMark.getSubMark(i + 1)),
colour
)
);
}
}
colour = Color.BLACK;
}
createMarkArrows(sequence);
//Scale race to markers if there is no border.
if (borderPoints == null) {
scaledPoint = ScaledPoint.makeScaledPoint(
canvasWidth, canvasHeight, new ArrayList<>(markerObjects.keySet()), false
);
}
//Move the Markers to initial position.
markerObjects.forEach(((mark, marker2D) -> {
Point2D p2d = scaledPoint.findScaledXY(mark.getLat(), mark.getLng());
marker2D.setLayoutX(p2d.getX());
marker2D.setLayoutY(p2d.getY());
}));
Platform.runLater(() -> {
markers.getChildren().clear();
markers.getChildren().addAll(gates);
markers.getChildren().addAll(markerObjects.values());
});
}
/**
* Calculates all the data needed for to create mark arrows. Requires that a course has been
* added to the gameview.
* @param sequence The order in which marks are traversed.
*/
private void createMarkArrows (List<Corner> sequence) {
for (int i=1; i < sequence.size()-1; i++) { //General case.
double averageLat = 0;
double averageLng = 0;
int numMarks = course.get(i-1).getMarks().size();
for (Mark mark : course.get(i-1).getMarks()) {
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint lastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
numMarks = course.get(i+1).getMarks().size();
averageLat = 0;
averageLng = 0;
for (Mark mark : course.get(i+1).getMarks()) {
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint nextMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
// TODO: 16/08/17 This comparison doesn't need to exist but the alternative is to user server enum client side.
for (Mark mark : course.get(i).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
GeoUtility.getBearing(lastMarkAv, mark),
GeoUtility.getBearing(mark, nextMarkAv)
);
}
}
createStartLineArrows();
createFinishLineArrows();
}
private void createStartLineArrows () {
double averageLat = 0;
double averageLng = 0;
int numMarks = 0;
for (Mark mark : course.get(1).getMarks()) {
numMarks += 1;
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint firstMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
for (Mark mark : course.get(0).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
0d, //90
GeoUtility.getBearing(mark, firstMarkAv)
);
}
}
private void createFinishLineArrows () {
double numMarks = 0;
double averageLat = 0;
double averageLng = 0;
for (Mark mark : course.get(course.size()-2).getMarks()) {
numMarks += 1;
averageLat += mark.getLat();
averageLng += mark.getLng();
}
GeoPoint secondToLastMarkAv = new GeoPoint(averageLat / numMarks, averageLng / numMarks);
for (Mark mark : course.get(course.size()-1).getMarks()) {
markerObjects.get(mark).addArrows(
mark.getRoundingSide() == RoundingSide.STARBOARD ? MarkArrowFactory.RoundingSide.STARBOARD : MarkArrowFactory.RoundingSide.PORT,
GeoUtility.getBearing(secondToLastMarkAv, mark),
GeoUtility.getBearing(mark, mark)
);
}
}
/**
* Creates a new Marker and binds it's position to the given Mark.
*
* @param observableMark The mark to bind the marker to.
* @param colour The desired colour of the mark
*/
private void makeAndBindMarker(Mark observableMark, Paint colour) {
Marker2D marker2D = new Marker2D(colour);
// marker.addArrows(MarkArrowFactory.RoundingSide.PORT, ThreadLocalRandom.current().nextDouble(91, 180), ThreadLocalRandom.current().nextDouble(1, 90));
markerObjects.put(observableMark, marker2D);
observableMark.addPositionListener((mark, lat, lon) -> {
Point2D p2d = scaledPoint.findScaledXY(lat, lon);
markerObjects.get(mark).setLayoutX(p2d.getX());
markerObjects.get(mark).setLayoutY(p2d.getY());
});
}
/**
* Creates a new gate connecting the given marks.
*
* @param m1 The first Mark of the gate.
* @param m2 The second Mark of the gate.
* @param colour The desired colour of the gate.
* @return the new gate.
*/
private Gate makeAndBindGate(Marker2D m1, Marker2D m2, Paint colour) {
Gate gate = new Gate(colour);
gate.startXProperty().bind(
m1.layoutXProperty()
);
gate.startYProperty().bind(
m1.layoutYProperty()
);
gate.endXProperty().bind(
m2.layoutXProperty()
);
gate.endYProperty().bind(
m2.layoutYProperty()
);
return gate;
}
/**
* Adds a border to the GameView and rescales to the size of the border, does not rescale if a
* border already exists. Assumes the border is larger than the course.
*
* @param border the race border to be drawn.
*/
@Override
public void updateBorder(List<Limit> border) {
if (border.size() == 0) {
return;
}
borderPoints = border;
scaledPoint = ScaledPoint.makeScaledPoint(canvasWidth, canvasHeight, border, false);
List<Double> boundaryPoints = new ArrayList<>();
for (Limit limit : border) {
Point2D location = scaledPoint.findScaledXY(limit.getLat(), limit.getLng());
boundaryPoints.add(location.getX());
boundaryPoints.add(location.getY());
}
raceBorder.getPoints().setAll(boundaryPoints);
}
}
@@ -2,6 +2,12 @@ package seng302.visualiser.controllers;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog; import com.jfoenix.controls.JFXDialog;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@@ -9,7 +15,7 @@ import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
@@ -23,20 +29,15 @@ import seng302.model.mark.CompoundMark;
import seng302.model.mark.Corner; import seng302.model.mark.Corner;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameView; import seng302.visualiser.MapPreview;
import seng302.visualiser.controllers.cells.PlayerCell; import seng302.visualiser.controllers.cells.PlayerCell;
import seng302.visualiser.controllers.dialogs.BoatCustomizeController; import seng302.visualiser.controllers.dialogs.BoatCustomizeController;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
public class LobbyController implements Initializable { public class LobbyController implements Initializable {
private final double INITIAL_MAP_HEIGHT = 770d;
private final double INITIAL_MAP_WIDTH = 574d;
//--------FXML BEGIN--------// //--------FXML BEGIN--------//
@FXML @FXML
private VBox playerListVBox; private VBox playerListVBox;
@@ -51,15 +52,15 @@ public class LobbyController implements Initializable {
@FXML @FXML
private Label mapName; private Label mapName;
@FXML @FXML
private Pane serverMap; private AnchorPane serverMap;
//---------FXML END---------// //---------FXML END---------//
private RaceState raceState; private RaceState raceState;
private JFXDialog customizationDialog; private JFXDialog customizationDialog;
public Color playersColor; public Color playersColor;
private Map<Integer, ClientYacht> playerBoats; private Map<Integer, ClientYacht> playerBoats;
private Double mapWidth, mapHeight; private Double mapWidth = INITIAL_MAP_WIDTH, mapHeight = INITIAL_MAP_HEIGHT;
private GameView gameView; private MapPreview mapPreview;
@Override @Override
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
@@ -136,44 +137,29 @@ public class LobbyController implements Initializable {
return customizationDialog; return customizationDialog;
} }
/**
*
*/
private void refreshMapView(){
RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData();
List<Limit> border = raceData.getCourseLimit();
List<CompoundMark> marks = new ArrayList<CompoundMark>(raceData.getCompoundMarks().values());
List<Corner> corners = raceData.getMarkSequence();
gameView.setSize(mapWidth, mapHeight);
// Update game view
gameView.updateBorder(border);
gameView.updateCourse(marks, corners);
}
/** /**
* Initializes a top down preview of the race course map. * Initializes a top down preview of the race course map.
*/ */
private void initMapPreview() { private void initMapPreview() {
gameView = new GameView(); RaceXMLData raceData = ViewManager.getInstance().getGameClient().getCourseData();
gameView.setHorizontalBuffer(330d); List<Limit> border = raceData.getCourseLimit();
List<CompoundMark> marks = new ArrayList<>(raceData.getCompoundMarks().values());
List<Corner> corners = raceData.getMarkSequence();
mapWidth = 770d; mapPreview = new MapPreview(marks, corners, border);
mapHeight = 574d;
// Add game view
serverMap.getChildren().clear(); serverMap.getChildren().clear();
serverMap.getChildren().add(gameView); serverMap.getChildren().add(mapPreview.getAssets());
mapPreview.setSize(mapWidth, mapHeight);
serverMap.widthProperty().addListener((observable, oldValue, newValue) -> { serverMap.widthProperty().addListener((observable, oldValue, newValue) -> {
mapWidth = newValue.doubleValue(); mapWidth = newValue.doubleValue();
refreshMapView(); mapPreview.setSize(mapWidth, mapHeight);
}); });
//
serverMap.heightProperty().addListener((observable, oldValue, newValue) -> { serverMap.heightProperty().addListener((observable, oldValue, newValue) -> {
mapHeight = newValue.doubleValue(); mapHeight = newValue.doubleValue();
refreshMapView(); mapPreview.setSize(mapWidth, mapHeight);
}); });
} }
@@ -12,22 +12,16 @@ import java.util.concurrent.TimeUnit;
import javafx.animation.Timeline; import javafx.animation.Timeline;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener; import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.geometry.Point2D; import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.SubScene; import javafx.scene.SubScene;
import javafx.scene.chart.LineChart; import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis; import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series; import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.CheckBox; import javafx.scene.control.CheckBox;
@@ -48,15 +42,11 @@ import javafx.scene.shape.Polyline;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.stage.Stage; import javafx.stage.Stage;
import javafx.stage.StageStyle; import javafx.stage.StageStyle;
import javax.swing.ImageIcon;
import seng302.model.ClientYacht; import seng302.model.ClientYacht;
import seng302.model.ClientYacht.PowerUpListener;
import seng302.model.RaceState; import seng302.model.RaceState;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark; import seng302.model.mark.Mark;
import seng302.model.stream.xml.parser.RaceXMLData; import seng302.model.stream.xml.parser.RaceXMLData;
import seng302.model.token.Token;
import seng302.model.token.TokenType;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.GameView3D; import seng302.visualiser.GameView3D;
import seng302.visualiser.controllers.annotations.ImportantAnnotationController; import seng302.visualiser.controllers.annotations.ImportantAnnotationController;
@@ -66,8 +56,6 @@ import seng302.visualiser.controllers.dialogs.FinishDialogController;
import seng302.visualiser.fxObjects.ChatHistory; import seng302.visualiser.fxObjects.ChatHistory;
import seng302.visualiser.fxObjects.assets_2D.WindArrow; import seng302.visualiser.fxObjects.assets_2D.WindArrow;
import seng302.visualiser.fxObjects.assets_3D.BoatObject; import seng302.visualiser.fxObjects.assets_3D.BoatObject;
import seng302.visualiser.fxObjects.assets_3D.ModelFactory;
import seng302.visualiser.fxObjects.assets_3D.ModelType;
/** /**
* Controller class that manages the display of a race * Controller class that manages the display of a race
@@ -75,8 +63,6 @@ import seng302.visualiser.fxObjects.assets_3D.ModelType;
public class RaceViewController extends Thread implements ImportantAnnotationDelegate { public class RaceViewController extends Thread implements ImportantAnnotationDelegate {
private final int CHAT_LIMIT = 128; private final int CHAT_LIMIT = 128;
private static final Double ICON_BLINK_TIMEOUT_RATIO = 0.6;
private static final Integer ICON_BLINK_PERIOD = 500;
@FXML @FXML
private Pane basePane; private Pane basePane;
@@ -120,8 +106,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private Label windSpeedLabel; private Label windSpeedLabel;
@FXML @FXML
private Label positionLabel, boatSpeedLabel, boatHeadingLabel; private Label positionLabel, boatSpeedLabel, boatHeadingLabel;
@FXML
private ImageView velocityIcon, handlingIcon, windWalkerIcon, bumperIcon, badRandomIcon;
//Race Data //Race Data
private Map<Integer, ClientYacht> participants; private Map<Integer, ClientYacht> participants;
@@ -142,40 +126,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
private JFXDialog finishScreenDialog; private JFXDialog finishScreenDialog;
private FinishDialogController finishDialogController; private FinishDialogController finishDialogController;
//Icon stuff
private Timer blinkingTimer = new Timer();
private ImageView iconToDisplay;
public void initialize() { public void initialize() {
Sounds.stopMusic(); Sounds.stopMusic();
Sounds.playRaceMusic(); Sounds.playRaceMusic();
// Load a default important annotation state
//importantAnnotations = new ImportantAnnotationsState();
//Formatting the y axis of the sparkline
// raceSparkLine.getYAxis().setRotate(180);
// raceSparkLine.getYAxis().setTickLabelRotation(180);
// raceSparkLine.getYAxis().setTranslateX(-5);
//raceSparkLine.visibleProperty().setValue(false);
//raceSparkLine.getYAxis().setAutoRanging(false);
//sparklineYAxis.setTickMarkVisible(false);
//positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
// raceSparkLine.visibleProperty().setValue(false);
// raceSparkLine.getYAxis().setAutoRanging(false);
// sparklineYAxis.setTickMarkVisible(false);
// positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString());
//selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
// rvAnchorPane.prefWidthProperty().bind(ViewManager.getInstance().getDecorator().widthProperty());
// rvAnchorPane.prefHeightProperty().bind(ViewManager.getInstance().getDecorator().heightProperty());
// selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
// windArrowHolder.getChildren().addAll(windArrow);
// windArrow.setLayoutX(windArrowHolder.getWidth() / 2);
// windArrow.setLayoutY(windArrowHolder.getHeight() / 2);
// selectAnnotationBtn.setOnAction(event -> loadSelectAnnotationView());
chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> { chatInput.lengthProperty().addListener((obs, oldLen, newLen) -> {
if (newLen.intValue() > CHAT_LIMIT) { if (newLen.intValue() > CHAT_LIMIT) {
chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT)); chatInput.setText(chatInput.getText().substring(0, CHAT_LIMIT));
@@ -189,26 +143,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
chatHistory.prefHeightProperty().bind( chatHistory.prefHeightProperty().bind(
chatHistoryHolder.heightProperty() chatHistoryHolder.heightProperty()
); );
// chatHistory.setFitToWidth(true);
// chatHistory.setFitToHeight(true);
// chatHistory.textProperty().addListener((obs, oldValue, newValue) -> {
// chatHistory.setScrollTop(Double.MAX_VALUE);
// });
contentStackPane.setOnMouseClicked(event -> { contentStackPane.setOnMouseClicked(event -> {
contentStackPane.requestFocus(); contentStackPane.requestFocus();
}); });
Platform.runLater(contentStackPane::requestFocus);
//Makes the chat history non transparent when clicked on //Makes the chat history non transparent when clicked on
chatInput.focusedProperty().addListener(new ChangeListener<Boolean>() { chatInput.focusedProperty().addListener((observable, oldValue, newValue) -> {
@Override if (newValue) {
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, chatHistory.increaseOpacity();
Boolean newValue) { } else {
if (newValue) { chatHistory.decreaseOpacity();
chatHistory.increaseOpacity();
} else {
chatHistory.decreaseOpacity();
}
} }
}); });
} }
@@ -238,7 +183,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
}); });
} }
public void loadRace ( public void loadRace (
Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState, Map<Integer, ClientYacht> participants, RaceXMLData raceData, RaceState raceState,
ClientYacht player) { ClientYacht player) {
@@ -253,17 +197,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
while (c.next()) { while (c.next()) {
if (c.wasPermutated()) { if (c.wasPermutated()) {
updateOrder(raceState.getPlayerPositions()); updateOrder(raceState.getPlayerPositions());
updateSparkLine();
} }
} }
}); });
player.addPowerUpListener(this::displayPowerUpIcon);
player.addPowerDownListener(this::removeIcon);
updateOrder(raceState.getPlayerPositions()); updateOrder(raceState.getPlayerPositions());
gameView = new GameView3D(); gameView = new GameView3D();
// gameView.setFrameRateFXText(fpsDisplay);
Platform.runLater(() -> { Platform.runLater(() -> {
contentStackPane.getChildren().add(0, gameView.getAssets()); contentStackPane.getChildren().add(0, gameView.getAssets());
((SubScene) gameView.getAssets()).widthProperty() ((SubScene) gameView.getAssets()).widthProperty()
@@ -277,11 +216,10 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
gameView.updateCourse( gameView.updateCourse(
new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence() new ArrayList<>(raceData.getCompoundMarks().values()), raceData.getMarkSequence()
); );
// gameView.enableZoom();
gameView.setBoatAsPlayer(player); gameView.setBoatAsPlayer(player);
// gameView.startRace();
// raceState.addCollisionListener(gameView::drawCollision); // raceState.addCollisionListener(gameView::drawCollision);
raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> { raceState.windDirectionProperty().addListener((obs, oldDirection, newDirection) -> {
gameView.setWindDir(newDirection.doubleValue()); gameView.setWindDir(newDirection.doubleValue());
Platform.runLater(() -> updateWindDirection(newDirection.doubleValue())); Platform.runLater(() -> updateWindDirection(newDirection.doubleValue()));
@@ -294,73 +232,9 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
updateWindSpeed(raceState.getWindSpeed()); updateWindSpeed(raceState.getWindSpeed());
}); });
gameView.setWindDir(raceState.windDirectionProperty().doubleValue()); gameView.setWindDir(raceState.windDirectionProperty().doubleValue());
Platform.runLater(() -> { Platform.runLater(this::initializeUpdateTimer);
initializeUpdateTimer();
});
} }
/**
* Displays the relevant icon, starts blinking it when it is close to turning off and then
* switches it off after the tokens time out
*
* @param yacht The yacht only for which we are displaying the icon
* @param tokenType The type of token, indicating what icon needs to be displayed
*/
private void displayPowerUpIcon(ClientYacht yacht, TokenType tokenType) {
if (yacht == player) {
if (iconToDisplay != null) {
iconToDisplay.setVisible(false);
}
switch (tokenType) {
case BOOST:
iconToDisplay = velocityIcon;
break;
case HANDLING:
iconToDisplay = handlingIcon;
break;
case WIND_WALKER:
iconToDisplay = windWalkerIcon;
break;
case BUMPER:
iconToDisplay = bumperIcon;
break;
case RANDOM:
iconToDisplay = badRandomIcon;
break;
default:
iconToDisplay = velocityIcon;
}
//Turn icon on
iconToDisplay.setVisible(true);
//Start blinking icon towards end
if (blinkingTimer != null) {
blinkingTimer.cancel();
}
blinkingTimer = new Timer("Blinking Timer");
blinkingTimer.schedule(new TimerTask() {
Boolean isVisible = true;
@Override
public void run() {
isVisible = !isVisible;
iconToDisplay.setVisible(isVisible);
}
}, (int) (tokenType.getTimeout() * ICON_BLINK_TIMEOUT_RATIO), ICON_BLINK_PERIOD);
}
}
public void removeIcon(ClientYacht yacht) {
if (yacht == player) {
blinkingTimer.cancel();
iconToDisplay.setVisible(false);
iconToDisplay = null;
}
}
/** /**
* The important annotations have been changed, update this view * The important annotations have been changed, update this view
* *
@@ -399,137 +273,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel
} }
} }
private void initialiseFPSCheckBox() {
// toggleFps.selectedProperty().addListener((obs, oldVal, newVal) ->
// gameView.setFPSVisibility(toggleFps.isSelected())
// );
}
private void initialiseAnnotationSlider() {
// annotationSlider.setLabelFormatter(new StringConverter<Double>() {
// @Override
// public String toString(Double n) {
// if (n == 0) {
// return "None";
// }
// if (n == 1) {
// return "Important";
// }
// if (n == 2) {
// return "All";
// }
// return "All";
// }
//
// @Override
// public Double fromString(String s) {
// switch (s) {
// case "None":
// return 0d;
// case "Important":
// return 1d;
// case "All":
// return 2d;
//
// default:
// return 2d;
// }
// }
// });
// annotationSlider.setValue(2);
// annotationSlider.valueProperty().addListener((obs, oldVal, newVal) ->
// setAnnotations((int) annotationSlider.getValue())
// );
}
/**
* Used to add any new yachts into the race that may have started late or not have had data received yet
*/
private void updateSparkLine(){
// // TODO: 2/08/17 there is about 0 chance of this working. Once we are keeping track of boat positions it can be fixed.
// // Collect the racing yachts that aren't already in the chart
// sparkLineData.clear();
// List<ClientYacht> sparkLineCandidates = new ArrayList<>(participants.values());
// // Create a new data series for new yachts
// sparkLineCandidates
// .stream()
// .filter(yacht -> yacht.getPosition() != null)
// .forEach(yacht -> {
// Series<String, Double> yachtData = new Series<>();
// yachtData.setName(yacht.getSourceId().toString());
// yachtData.getData().add(
// new Data<>(
// Integer.toString(yacht.getLegNumber()),
// 1.0 + participants.size() - yacht.getPosition()
// )
// );
// sparkLineData.add(yachtData);
// });
//
// // Lambda function to sort the series in order of leg (later legs shown more to the right)
// sparkLineData.sort((o1, o2) -> {
// Integer leg1 = Integer.parseInt(o1.getData().get(o1.getData().size()-1).getXValue());
// Integer leg2 = Integer.parseInt(o2.getData().get(o2.getData().size()-1).getXValue());
// if (leg2 < leg1){
// return 1;
// } else {
// return -1;
// }
// });
//
// // Adds the new data series to the sparkline (and set the colour of the series)
// Platform.runLater(() -> {
// sparkLineData
// .stream()
// .filter(spark -> !raceSparkLine.getData().contains(spark))
// .forEach(spark -> {
// raceSparkLine.getData().add(spark);
// spark.getNode().lookup(".chart-series-line").setStyle("-fx-stroke:" + getBoatColorAsRGB(spark.getName()));
// });
// });
}
private void initialiseSparkLine() {
// sparklineYAxis.setUpperBound(participants.size() + 1);
// raceSparkLine.setCreateSymbols(false);
}
/**
* Updates the yachts sparkline of the desired yacht and using the new leg number
* @param yacht The yacht to be updated on the sparkline
* @param legNumber the leg number that the position will be assigned to
*/
void updateYachtPositionSparkline(ClientYacht yacht, Integer legNumber){
for (XYChart.Series<String, Double> positionData : sparkLineData) {
positionData.getData().add(
new Data<>(
Integer.toString(legNumber),
1.0 + participants.size() - yacht.getPlacing()
)
);
}
}
/**
* gets the rgb string of the yachts colour to use for the chart via css
* @param yachtId id of yacht passed in to get the yachts colour
* @return the colour as an rgb string
*/
private String getBoatColorAsRGB(String yachtId){
Color color = participants.get(Integer.valueOf(yachtId)).getColour();
if (color == null){
return String.format("#%02X%02X%02X",255,255,255);
}
return String.format( "#%02X%02X%02X",
(int)( color.getRed() * 255 ),
(int)( color.getGreen() * 255 ),
(int)( color.getBlue() * 255 )
);
}
/** /**
* Initialises a timer which updates elements of the RaceView such as wind direction, yacht * Initialises a timer which updates elements of the RaceView such as wind direction, yacht
* orderings etc.. which are dependent on the info from the stream parser constantly. * orderings etc.. which are dependent on the info from the stream parser constantly.
@@ -7,7 +7,6 @@ import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator; import com.jfoenix.validation.RequiredFieldValidator;
import java.io.IOException; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@@ -28,7 +27,6 @@ import seng302.utilities.Sounds;
import seng302.visualiser.ServerListener; import seng302.visualiser.ServerListener;
import seng302.visualiser.ServerListenerDelegate; import seng302.visualiser.ServerListenerDelegate;
import seng302.visualiser.controllers.cells.ServerCell; import seng302.visualiser.controllers.cells.ServerCell;
import seng302.visualiser.controllers.dialogs.ServerCreationController;
import seng302.visualiser.validators.HostNameFieldValidator; import seng302.visualiser.validators.HostNameFieldValidator;
import seng302.visualiser.validators.NumberRangeValidator; import seng302.visualiser.validators.NumberRangeValidator;
import seng302.visualiser.validators.ValidationTools; import seng302.visualiser.validators.ValidationTools;
@@ -57,14 +55,6 @@ public class ServerListController implements Initializable, ServerListenerDelega
private Label noServersFound; private Label noServersFound;
private Logger logger = LoggerFactory.getLogger(ServerListController.class); private Logger logger = LoggerFactory.getLogger(ServerListController.class);
private JFXDialog serverCreationDialog;
private List<ServerCreationDialogListener> serverCreationDialogListeners = new ArrayList<>();
@FunctionalInterface
public interface ServerCreationDialogListener {
void notifyClosure();
}
// TODO: 12/09/17 ajm412: break this method down, its way too long. // TODO: 12/09/17 ajm412: break this method down, its way too long.
@Override @Override
@@ -125,8 +115,6 @@ public class ServerListController implements Initializable, ServerListenerDelega
serverListHostButton.setOnAction(action -> { serverListHostButton.setOnAction(action -> {
showServerCreationDialog(); showServerCreationDialog();
}); });
addServerCreationDialogListener(this::closeServerCreationDialog);
} }
/** /**
@@ -137,22 +125,17 @@ public class ServerListController implements Initializable, ServerListenerDelega
FXMLLoader dialogContent = new FXMLLoader(getClass().getResource( FXMLLoader dialogContent = new FXMLLoader(getClass().getResource(
"/views/dialogs/ServerCreationDialog.fxml")); "/views/dialogs/ServerCreationDialog.fxml"));
try { try {
serverCreationDialog = new JFXDialog(serverListMainStackPane, dialogContent.load(), JFXDialog dialog = new JFXDialog(serverListMainStackPane, dialogContent.load(),
DialogTransition.CENTER); DialogTransition.CENTER);
ServerCreationController serverCreationController = dialogContent.getController(); dialog.show();
serverCreationController.setListener(serverCreationDialogListeners);
serverCreationDialog.show();
Sounds.playButtonClick(); Sounds.playButtonClick();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace();
logger.warn("Could not create Server Creation Dialog."); logger.warn("Could not create Server Creation Dialog.");
} }
}); });
} }
private void closeServerCreationDialog() {
serverCreationDialog.close();
}
/** /**
* Validates the connection and attempts to connect to a given hostname and port number. * Validates the connection and attempts to connect to a given hostname and port number.
*/ */
@@ -221,14 +204,4 @@ public class ServerListController implements Initializable, ServerListenerDelega
public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) { public void serverDetected(ServerDescription serverDescription, List<ServerDescription> servers) {
Platform.runLater(() -> refreshServers(servers)); Platform.runLater(() -> refreshServers(servers));
} }
private void addServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.add(serverCreationDialogListener);
}
private void removeServerCreationDialogListener(
ServerCreationDialogListener serverCreationDialogListener) {
serverCreationDialogListeners.remove(serverCreationDialogListener);
}
} }
@@ -102,6 +102,8 @@ public class ViewManager {
gameClient.stopGame(); gameClient.stopGame();
System.exit(0); System.exit(0);
}); });
jfxSnackbar = new JFXSnackbar(decorator);
} }
/** /**
@@ -186,7 +188,6 @@ public class ViewManager {
} }
}); });
jfxSnackbar = new JFXSnackbar(decorator);
} }
/** /**
@@ -87,7 +87,6 @@ public class KeyBindingDialogController implements Initializable {
resetBtn.setOnMouseClicked(event -> { resetBtn.setOnMouseClicked(event -> {
gameKeyBind.setToDefault(); gameKeyBind.setToDefault();
loadKeyBind(); loadKeyBind();
showSnackBar("All keys reset!", false);
}); });
closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog()); closeLabel.setOnMouseClicked(event -> ViewManager.getInstance().closeKeyBindingDialog());
@@ -1,19 +1,19 @@
package seng302.visualiser.controllers.dialogs; package seng302.visualiser.controllers.dialogs;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXSlider; import com.jfoenix.controls.JFXSlider;
import com.jfoenix.controls.JFXTextField; import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.RequiredFieldValidator; import com.jfoenix.validation.RequiredFieldValidator;
import java.net.URL; import java.net.URL;
import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent; import javafx.scene.layout.AnchorPane;
import seng302.gameServer.ServerDescription; import seng302.gameServer.ServerDescription;
import seng302.utilities.Sounds; import seng302.utilities.Sounds;
import seng302.visualiser.controllers.ServerListController.ServerCreationDialogListener; import seng302.visualiser.MapMaker;
import seng302.visualiser.controllers.ViewManager; import seng302.visualiser.controllers.ViewManager;
import seng302.visualiser.validators.FieldLengthValidator; import seng302.visualiser.validators.FieldLengthValidator;
import seng302.visualiser.validators.ValidationTools; import seng302.visualiser.validators.ValidationTools;
@@ -30,16 +30,39 @@ public class ServerCreationController implements Initializable {
@FXML @FXML
private JFXButton submitBtn; private JFXButton submitBtn;
@FXML @FXML
private Label closeLabel; private JFXButton nextMapButton;
@FXML
private JFXButton lastMapButton;
@FXML
private Label mapNameLabel;
@FXML
private JFXSlider legsSlider;
@FXML
private Label legsSliderLabel;
@FXML
private JFXCheckBox pickupsCheckBox;
@FXML
private AnchorPane mapHolder;
private MapMaker mapMaker = MapMaker.getInstance();
//---------FXML END---------// //---------FXML END---------//
private List<ServerCreationDialogListener> serverCreationDialogListeners;
public void initialize(URL location, ResourceBundle resources) { public void initialize(URL location, ResourceBundle resources) {
maxPlayersSlider.valueProperty().addListener(
(observable, oldValue, newValue) -> updateMaxPlayerLabel()
);
maxPlayersSlider.setMax(mapMaker.getMaxPlayers());
maxPlayersSlider.setValue(mapMaker.getMaxPlayers());
legsSlider.valueProperty().addListener(
(obs, oldVal, newVal) -> updateLegSliderLabel()
);
legsSlider.setMax(10);
updateMaxPlayerLabel(); updateMaxPlayerLabel();
maxPlayersSlider.valueProperty().addListener((observable, oldValue, newValue) -> { updateLegSliderLabel();
updateMaxPlayerLabel();
});
FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40); FieldLengthValidator fieldLengthValidator = new FieldLengthValidator(40);
fieldLengthValidator.setMessage("Server name too long."); fieldLengthValidator.setMessage("Server name too long.");
@@ -54,7 +77,18 @@ public class ServerCreationController implements Initializable {
validateServerSettings(); validateServerSettings();
}); });
closeLabel.setOnMouseClicked(event -> notifyListeners()); nextMapButton.setOnMouseReleased(event -> {
Sounds.playButtonClick();
nextMap();
});
lastMapButton.setOnMouseReleased(event -> {
Sounds.playButtonClick();
lastMap();
});
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
} }
/** /**
@@ -75,7 +109,7 @@ public class ServerCreationController implements Initializable {
private void createServer() { private void createServer() {
ServerDescription serverDescription = ViewManager.getInstance().getGameClient() ServerDescription serverDescription = ViewManager.getInstance().getGameClient()
.runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider .runAsHost("localhost", 4941, serverName.getText(), (int) maxPlayersSlider
.getValue()); .getValue(), mapMaker.getCurrentRacePath(), (int) legsSlider.getValue(), pickupsCheckBox.isSelected());
ViewManager.getInstance().setProperty("serverName", serverDescription.getName()); ViewManager.getInstance().setProperty("serverName", serverDescription.getName());
ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName()); ViewManager.getInstance().setProperty("mapName", serverDescription.getMapName());
@@ -86,21 +120,35 @@ public class ServerCreationController implements Initializable {
*/ */
private void updateMaxPlayerLabel() { private void updateMaxPlayerLabel() {
maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue())); maxPlayersSlider.setValue(Math.floor(maxPlayersSlider.getValue()));
maxPlayersLabel.setText(String.format("YOU SELECTED: %.0f", maxPlayersSlider.getValue())); maxPlayersLabel.setText(String.format("Max players: %.0f", maxPlayersSlider.getValue()));
} }
public void playButtonHoverSound(MouseEvent mouseEvent) { private void updateLegSliderLabel() {
legsSlider.setValue(Math.floor(legsSlider.getValue()));
legsSliderLabel.setText(
String.format("A section of the race will repeat %.0f times", legsSlider.getValue())
);
}
public void playButtonHoverSound() {
Sounds.playHoverSound(); Sounds.playHoverSound();
} }
public void setListener(List<ServerCreationDialogListener> serverCreationDialogListeners) { private void nextMap() {
this.serverCreationDialogListeners = serverCreationDialogListeners; mapMaker.next();
updateMap();
} }
public void notifyListeners() { private void lastMap() {
for (ServerCreationDialogListener serverCreationDialogListener : serverCreationDialogListeners) { mapMaker.previous();
serverCreationDialogListener.notifyClosure(); updateMap();
}
} }
private void updateMap() {
mapHolder.getChildren().setAll(mapMaker.getCurrentGameView());
mapNameLabel.setText(mapMaker.getCurrentRegatta().getCourseName());
maxPlayersSlider.setMax(mapMaker.getMaxPlayers());
maxPlayersSlider.setValue(mapMaker.getMaxPlayers());
}
} }
@@ -156,11 +156,7 @@ public class ModelFactory {
} }
switch (tokenType) { switch (tokenType) {
case VELOCITY_PICKUP: case VELOCITY_PICKUP:
case BUMPER_PICKUP: return makeCoinPickup(assets);
case RANDOM_PICKUP:
case HANDLING_PICKUP:
case WIND_WALKER_PICKUP:
return makeTokenPickup(assets);
case FINISH_MARKER: case FINISH_MARKER:
case PLAIN_MARKER: case PLAIN_MARKER:
case START_MARKER: case START_MARKER:
@@ -189,22 +185,24 @@ public class ModelFactory {
} }
} }
private static Model makeTokenPickup(Group assets) { private static Model makeCoinPickup(Group assets){
Rotate animationRotate = new Rotate(0, new Point3D(0, 0, 1)); assets.setRotationAxis(new Point3D(1,0,0));
assets.setRotate(90);
assets.setTranslateX(0.2);
assets.setTranslateY(1);
assets.getTransforms().addAll( assets.getTransforms().addAll(
animationRotate, new Translate(0,-1,0),
new Translate(0, 0, -1) new Rotate(0 ,new Point3D(1,1,1))
); );
return new Model(new Group(assets), new AnimationTimer() { return new Model(new Group(assets), new AnimationTimer() {
private double rotation = 0; private double rotation = 0;
private Rotate rotate = animationRotate; private Group group = assets;
@Override @Override
public void handle(long now) { public void handle(long now) {
rotation += 1; rotation += 1;
rotate.setAngle(rotation); ((Rotate) group.getTransforms().get(1)).setAngle(rotation);
} }
}); });
} }
@@ -7,10 +7,6 @@ package seng302.visualiser.fxObjects.assets_3D;
public enum ModelType { public enum ModelType {
VELOCITY_PICKUP("velocity_pickup.dae"), VELOCITY_PICKUP("velocity_pickup.dae"),
HANDLING_PICKUP("turning_pickup.dae"),
WIND_WALKER_PICKUP("wind_walker_pickup.dae"),
BUMPER_PICKUP("bumper_pickup.dae"),
RANDOM_PICKUP("random_pickup.dae"),
FINISH_MARKER ("finish_marker.dae"), FINISH_MARKER ("finish_marker.dae"),
START_MARKER ("start_marker.dae"), START_MARKER ("start_marker.dae"),
PLAIN_MARKER ("plain_marker.dae"), PLAIN_MARKER ("plain_marker.dae"),
-9
View File
@@ -1,9 +0,0 @@
<?xml version="1.0" ?>
<configurations>
<race-name>AC35</race-name>
<race-size>6</race-size>
<time-scale>10.0</time-scale>
<windDir-direction>135</windDir-direction>
</configurations>
-80
View File
@@ -1,80 +0,0 @@
<?xml version="1.0" ?>
<markers>
<marks>
<gate>
<name type="start-line">Start</name>
<mark>
<name>Start1</name>
<latitude>57.6703330</latitude>
<longitude>11.8278330</longitude>
<id>122</id>
</mark>
<mark>
<name>Start2</name>
<latitude>57.6703330</latitude>
<longitude>11.8271333</longitude>
<id>123</id>
</mark>
</gate>
<mark>
<name>Mid Mark</name>
<latitude>57.6675700</latitude>
<longitude>11.8359880</longitude>
<id>131</id>
</mark>
<gate>
<name>Leeward Gate</name>
<mark>
<name>Leeward Gate1</name>
<latitude>57.6708220</latitude>
<longitude>11.8433900</longitude>
<id>124</id>
</mark>
<mark>
<name>Leeward Gate2</name>
<latitude>57.6711220</latitude>
<longitude>11.8436900</longitude>
<id>125</id>
</mark>
</gate>
<gate>
<name>Windward Gate</name>
<mark>
<name>Windward Gate1</name>
<latitude>57.6650170</latitude>
<longitude>11.8279170</longitude>
<id>126</id>
</mark>
<mark>
<name>Windward Gate2</name>
<latitude>57.6653170</latitude>
<longitude>11.8282170</longitude>
<id>127</id>
</mark>
</gate>
<gate type="finish-line">
<name>Finish</name>
<mark>
<name>Finish1</name>
<latitude>57.6715240</latitude>
<longitude>11.8444950</longitude>
<id>128</id>
</mark>
<mark>
<name>Finish2</name>
<latitude>57.6718240</latitude>
<longitude>11.8447950</longitude>
<id>129</id>
</mark>
</gate>
</marks>
<order>
<one>Start</one>
<two>Mid Mark</two>
<three>Leeward Gate</three>
<four>Windward Gate</four>
<five>Leeward Gate</five>
<six>Finish</six>
</order>
</markers>
-72
View File
@@ -1,72 +0,0 @@
<?xml version="1.0" ?>
<course>
<marks>
<gate>
<name type="start-line">Start</name>
<mark>
<name>Start1</name>
<latitude>32.296577</latitude>
<longitude>-64.854304</longitude>
</mark>
<mark>
<name>Start2</name>
<latitude>32.293771</latitude>
<longitude>-64.855242</longitude>
</mark>
</gate>
<mark>
<name>Mid Mark</name>
<latitude>32.293039</latitude>
<longitude>-64.843983</longitude>
</mark>
<gate>
<name>Leeward Gate</name>
<mark>
<name>Leeward Gate1</name>
<latitude>32.284680</latitude>
<longitude>-64.850045</longitude>
</mark>
<mark>
<name>Leeward Gate2</name>
<latitude>32.280164</latitude>
<longitude>-64.847591</longitude>
</mark>
</gate>
<gate>
<name>Windward Gate</name>
<mark>
<name>Windward Gate1</name>
<latitude>32.309693</latitude>
<longitude>-64.835249</longitude>
</mark>
<mark>
<name>Windward Gate2</name>
<latitude>32.308046</latitude>
<longitude>-64.831785</longitude>
</mark>
</gate>
<gate type="finish-line">
<name>Finish</name>
<mark>
<name>Finish1</name>
<latitude>32.317379</latitude>
<longitude>-64.839291</longitude>
</mark>
<mark>
<name>Finish2</name>
<latitude>32.317257</latitude>
<longitude>-64.836260</longitude>
</mark>
</gate>
</marks>
<order>
<one>Start</one>
<two>Mid Mark</two>
<three>Leeward Gate</three>
<four>Windward Gate</four>
<five>Leeward Gate</five>
<six>Finish</six>
</order>
</course>
-40
View File
@@ -1,40 +0,0 @@
<?xml version="1.0" ?>
<teams>
<team>
<name>Oracle Team USA</name>
<alias>USA</alias>
<currentVelocity>0.0</currentVelocity>
<id>102</id>
</team>
<team>
<name>Artemis Racing</name>
<alias>ART</alias>
<currentVelocity>0.0</currentVelocity>
<id>101</id>
</team>
<team>
<name>Emirates Team New Zealand</name>
<alias>NZL</alias>
<currentVelocity>0.0</currentVelocity>
<id>103</id>
</team>
<team>
<name>Land Rover BAR</name>
<alias>BAR</alias>
<currentVelocity>0.0</currentVelocity>
<id>104</id>
</team>
<team>
<name>SoftBank Team Japan</name>
<alias>JAP</alias>
<currentVelocity>0.0</currentVelocity>
<id>105</id>
</team>
<team>
<name>Groupama Team France</name>
<alias>FRC</alias>
<currentVelocity>0.0</currentVelocity>
<id>106</id>
</team>
</teams>
@@ -45,13 +45,3 @@
.maxPlayers { .maxPlayers {
-fx-font-size: 13px; -fx-font-size: 13px;
} }
#closeLabel {
-fx-font-size: 30;
-fx-text-fill: -fx-pp-dark-text-color;
}
#closeLabel:hover {
-fx-text-fill: red;
-fx-font-size: 33px;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<RaceDefinition>
<CourseName> El Classico </CourseName>
<CentralLat> 57.6679590 </CentralLat>
<CentralLng> 11.8503233 </CentralLng>
<MaxPlayers> 10 </MaxPlayers>
<Marks>
<CompoundMark CompoundMarkID="1">
<Mark Lat="57.670603" Lng="11.828262"/>
<Mark Lat="57.669445" Lng="11.826413"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2">
<Mark Lat="57.6675700" Lng="11.8359880"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3">
<Mark Lat="57.6708220" Lng="11.8433900"/>
<Mark Lat="57.671629" Lng="11.840951"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4">
<Mark Lat="57.664190" Lng="11.829576"/>
<Mark Lat="57.665316" Lng="11.827184"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5">
<Mark Lat="57.672350" Lng="11.842535"/>
<Mark Lat="57.6715240" Lng="11.8444950"/>
</CompoundMark>
</Marks>
<Course>
<OpeningSegment>
<Corner CompoundMarkID="1" Rounding="PS"/>
<Corner CompoundMarkID="2" Rounding="P"/>
</OpeningSegment>
<RepeatingSegment>
<Corner CompoundMarkID="3" Rounding="SP"/>
<Corner CompoundMarkID="4" Rounding="PS"/>
</RepeatingSegment>
<ClosingSegment>
<Corner CompoundMarkID="5" Rounding="PS"/>
</ClosingSegment>
</Course>
<CourseLimit>
<Limit Lat="57.6739450" Lng="11.8417100" />
<Limit Lat="57.6709520" Lng="11.8485010" />
<Limit Lat="57.6690260" Lng="11.8472790" />
<Limit Lat="57.6693140" Lng="11.8457610" />
<Limit Lat="57.6665370" Lng="11.8432910" />
<Limit Lat="57.6641400" Lng="11.8385840" />
<Limit Lat="57.6629430" Lng="11.8332030" />
<Limit Lat="57.6629480" Lng="11.8249660" />
<Limit Lat="57.6686890" Lng="11.8250920" />
<Limit Lat="57.6692230" Lng="11.8231430" />
<Limit Lat="57.6725370" Lng="11.8272480" />
<Limit Lat="57.6708220" Lng="11.8321340" />
</CourseLimit>
</RaceDefinition>
+79
View File
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<RaceDefinition>
<CourseName> HorseShoe </CourseName>
<CentralLat> -14.6457 </CentralLat>
<CentralLng> 47.612855 </CentralLng>
<MaxPlayers> 5 </MaxPlayers>
<Marks>
<CompoundMark CompoundMarkID="1">
<Mark Lat="-14.071412" Lng="47.05756"/>
<Mark Lat="-14.069914" Lng="47.058541"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2">
<Mark Lat="-14.067194" Lng="47.053818" />
</CompoundMark>
<CompoundMark CompoundMarkID="3">
<Mark Lat="-14.061248" Lng="47.058556" />
</CompoundMark>
<CompoundMark CompoundMarkID="4">
<Mark Lat="-14.060584" Lng="47.063088"/>
<Mark Lat="-14.060617" Lng="47.06374" />
</CompoundMark>
<CompoundMark CompoundMarkID="5">
<Mark Lat="-14.064637" Lng="47.060307"/>
<Mark Lat="-14.06477" Lng="47.061165"/>
</CompoundMark>
<CompoundMark CompoundMarkID="6">
<Mark Lat="-14.063839" Lng="47.06762"/>
</CompoundMark>
<CompoundMark CompoundMarkID="7">
<Mark Lat="-14.068954" Lng="47.066349"/>
</CompoundMark>
<CompoundMark CompoundMarkID="8">
<Mark Lat="-14.07025" Lng="47.060238"/>
<Mark Lat="-14.071047" Lng="47.060307"/>
</CompoundMark>
</Marks>
<Course>
<OpeningSegment>
<Corner CompoundMarkID="1" Rounding="PS"/>
<Corner CompoundMarkID="2" Rounding="S"/>
<Corner CompoundMarkID="3" Rounding="S"/>
<Corner CompoundMarkID="4" Rounding="SP"/>
</OpeningSegment>
<RepeatingSegment>
<Corner CompoundMarkID="5" Rounding="SP"/>
<Corner CompoundMarkID="4" Rounding="PS"/>
</RepeatingSegment>
<ClosingSegment>
<Corner CompoundMarkID="6" Rounding="S"/>
<Corner CompoundMarkID="7" Rounding="S"/>
<Corner CompoundMarkID="8" Rounding="SP" />
</ClosingSegment>
</Course>
<CourseLimit>
<Limit Lat="-14.073371" Lng="47.058213" />
<Limit Lat="-14.06453" Lng="47.050003" />
<Limit Lat="-14.059022" Lng="47.057286" />
<Limit Lat="-14.058723" Lng="47.064358" />
<Limit Lat="-14.06261" Lng="47.071293" />
<Limit Lat="-14.070814" Lng="47.06762" />
<Limit Lat="-14.072773" Lng="47.059689" />
<Limit Lat="-14.068323" Lng="47.059449" />
<Limit Lat="-14.064969" Lng="47.065113" />
<Limit Lat="-14.066131" Lng="47.05986" />
<Limit Lat="-14.063441" Lng="47.058419" />
<Limit Lat="-14.068091" Lng="47.059174" />
</CourseLimit>
</RaceDefinition>
-147
View File
@@ -1,147 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-19T15:47:50</created>
<modified>2017-09-19T15:47:50</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0 0 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 6.87021e-4 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5257253 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8090167 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8090116 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616991 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.1875942 0.5773453 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="60">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 38 11 33 36 11 34 41 11 35 36 12 36 9 12 37 41 12 38 41 13 39 35 13 40 40 13 41 35 14 42 8 14 43 40 14 44 40 15 45 34 15 46 39 15 47 34 16 48 7 16 49 39 16 50 39 17 51 33 17 52 37 17 53 33 18 54 6 18 55 37 18 56 37 19 57 32 19 58 38 19 59 32 20 60 10 20 61 38 20 62 23 21 63 36 21 64 10 21 65 23 22 66 30 22 67 36 22 68 30 23 69 9 23 70 36 23 71 31 24 72 35 24 73 9 24 74 31 25 75 28 25 76 35 25 77 28 26 78 8 26 79 35 26 80 29 27 81 34 27 82 8 27 83 29 28 84 26 28 85 34 28 86 26 29 87 7 29 88 34 29 89 27 30 90 33 30 91 7 30 92 27 31 93 24 31 94 33 31 95 24 32 96 6 32 97 33 32 98 25 33 99 32 33 100 6 33 101 25 34 102 22 34 103 32 34 104 22 35 105 10 35 106 32 35 107 30 36 108 21 36 109 31 36 110 21 37 111 4 37 112 31 37 113 28 38 114 20 38 115 29 38 116 20 39 117 3 39 118 29 39 119 26 40 120 18 40 121 27 40 122 18 41 123 2 41 124 27 41 125 24 42 126 14 42 127 25 42 128 14 43 129 1 43 130 25 43 131 22 44 132 15 44 133 23 44 134 15 45 135 5 45 136 23 45 137 16 46 138 21 46 139 5 46 140 16 47 141 19 47 142 21 47 143 19 48 144 4 48 145 21 48 146 19 49 147 20 49 148 4 49 149 19 50 150 17 50 151 20 50 152 17 51 153 3 51 154 20 51 155 17 52 156 18 52 157 3 52 158 17 53 159 12 53 160 18 53 161 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 15 56 168 13 56 169 16 56 170 12 57 171 14 57 172 2 57 173 12 58 174 13 58 175 14 58 176 13 59 177 1 59 178 14 59 179</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
-332
View File
@@ -1,332 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-19T15:54:38</created>
<modified>2017-09-19T15:54:38</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.8 0.6035923 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.8 0.1522076 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.01023849 0.004662884 0.64 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0 0.2456551 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_003-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">8.07677e-5 0.64 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_004-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0 0.005309466 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_005-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0 0 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.5 0.5 0.5 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
<material id="Material_001-material" name="Material_001">
<instance_effect url="#Material_001-effect"/>
</material>
<material id="Material_002-material" name="Material_002">
<instance_effect url="#Material_002-effect"/>
</material>
<material id="Material_003-material" name="Material_003">
<instance_effect url="#Material_003-effect"/>
</material>
<material id="Material_004-material" name="Material_004">
<instance_effect url="#Material_004-effect"/>
</material>
<material id="Material_005-material" name="Material_005">
<instance_effect url="#Material_005-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5350354 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8183268 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8183217 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.570192 0.7464457 -0.3430743 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.6991799 0.2635454 0.6645987 0.05184978 0.746441 0.6634285 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.185151 0.569826 0.8006358 -0.4685443 0.5765037 0.6694099 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.009833872 0.9466192 0.3222044 -0.2904988 0.9398801 0.1795436 -0.5345759 0.7778646 0.3303867 -0.9071158 0.2635452 0.3281539 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7989099 0.5698285 -0.1924537 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.2925817 0.9466192 -0.1353079 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.8082743 0.5765079 0.1197141 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="15">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>36 12 36 9 12 37 41 12 38 35 14 42 8 14 43 40 14 44 34 16 48 7 16 49 39 16 50 33 18 54 6 18 55 37 18 56 32 20 60 10 20 61 38 20 62 30 23 69 9 23 70 36 23 71 28 26 78 8 26 79 35 26 80 26 29 87 7 29 88 34 29 89 24 32 96 6 32 97 33 32 98 22 35 105 10 35 106 32 35 107 16 47 141 19 47 142 21 47 143 19 50 150 17 50 151 20 50 152 17 53 159 12 53 160 18 53 161 15 56 168 13 56 169 16 56 170 12 58 174 13 58 175 14 58 176</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
<polylist material="Material_001-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>23 22 66 30 22 67 36 22 68 31 25 75 28 25 76 35 25 77 29 28 84 26 28 85 34 28 86 27 31 93 24 31 94 33 31 95 25 34 102 22 34 103 32 34 104 30 36 108 21 36 109 31 36 110 28 38 114 20 38 115 29 38 116 26 40 120 18 40 121 27 40 122 24 42 126 14 42 127 25 42 128 22 44 132 15 44 133 23 44 134</p>
</polylist>
<polylist material="Material_002-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 23 21 63 36 21 64 10 21 65 31 24 72 35 24 73 9 24 74 29 27 81 34 27 82 8 27 83 27 30 90 33 30 91 7 30 92 25 33 99 32 33 100 6 33 101</p>
</polylist>
<polylist material="Material_003-material" count="5">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 </vcount>
<p>38 11 33 36 11 34 41 11 35 41 13 39 35 13 40 40 13 41 40 15 45 34 15 46 39 15 47 39 17 51 33 17 52 37 17 53 37 19 57 32 19 58 38 19 59</p>
</polylist>
<polylist material="Material_004-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 16 46 138 21 46 139 5 46 140 19 49 147 20 49 148 4 49 149 17 52 156 18 52 157 3 52 158 12 57 171 14 57 172 2 57 173</p>
</polylist>
<polylist material="Material_005-material" count="10">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 </vcount>
<p>21 37 111 4 37 112 31 37 113 20 39 117 3 39 118 29 39 119 18 41 123 2 41 124 27 41 125 14 43 129 1 43 130 25 43 131 15 45 135 5 45 136 23 45 137 19 48 144 4 48 145 21 48 146 17 51 153 3 51 154 20 51 155 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 13 59 177 1 59 178 14 59 179</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
<instance_material symbol="Material_001-material" target="#Material_001-material"/>
<instance_material symbol="Material_002-material" target="#Material_002-material"/>
<instance_material symbol="Material_003-material" target="#Material_003-material"/>
<instance_material symbol="Material_004-material" target="#Material_004-material"/>
<instance_material symbol="Material_005-material" target="#Material_005-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
+7 -7
View File
@@ -5,8 +5,8 @@
<author>Blender User</author> <author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool> <authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor> </contributor>
<created>2017-09-11T16:51:03</created> <created>2017-09-26T01:05:25</created>
<modified>2017-09-11T16:51:03</modified> <modified>2017-09-26T01:05:25</modified>
<unit name="meter" meter="1"/> <unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis> <up_axis>Z_UP</up_axis>
</asset> </asset>
@@ -48,7 +48,7 @@
<geometry id="Plane_004-mesh" name="Plane.004"> <geometry id="Plane_004-mesh" name="Plane.004">
<mesh> <mesh>
<source id="Plane_004-mesh-positions"> <source id="Plane_004-mesh-positions">
<float_array id="Plane_004-mesh-positions-array" count="240">-1 -0.09999954 0.01554524 1 -0.09999954 0.01554524 -1 0.1000005 0.01554524 1 0.1000005 0.01554524 1 0.1000005 0.01554524 1 -0.09999954 0.01554524 1.019509 -0.09807801 0.01554524 1.038269 -0.09238743 0.01554524 1.055557 -0.08314645 0.01554524 1.070711 -0.07071018 0.01554524 1.083147 -0.05555653 0.01554524 1.092388 -0.03826785 0.01554524 1.098079 -0.01950848 0.01554524 1.1 5.96046e-7 0.01554524 1.098079 0.01950955 0.01554524 1.092388 0.03826892 0.01554524 1.083147 0.0555576 0.01554524 1.070711 0.07071125 0.01554524 1.055557 0.08314752 0.01554524 1.038269 0.09238851 0.01554524 1.019509 0.09807896 0.01554524 -1 0.1000005 0.01554524 -1.019509 0.0980789 0.01554524 -1.038268 0.09238833 0.01554524 -1.055557 0.08314734 0.01554524 -1.070711 0.07071107 0.01554524 -1.083147 0.05555742 0.01554524 -1.092388 0.03826874 0.01554524 -1.098078 0.01950937 0.01554524 -1.1 4.56348e-7 0.01554524 -1.098078 -0.0195086 0.01554524 -1.092388 -0.03826785 0.01554524 -1.083147 -0.05555653 0.01554524 -1.070711 -0.07071018 0.01554524 -1.055557 -0.08314645 0.01554524 -1.038268 -0.09238755 0.01554524 -1.019509 -0.09807813 0.01554524 -0.9999997 -0.09999954 0.01554524 1 4.76837e-7 0.01554524 -1 4.76837e-7 0.01554524 -1 4.76837e-7 0.04452204 -1 0.1000005 0.04452204 -1 -0.09999954 0.04452204 1 -0.09999954 0.04452204 1 0.1000005 0.04452204 1.019509 -0.09807801 0.04452204 1 -0.09999954 0.04452204 1.038269 -0.09238743 0.04452204 1.055557 -0.08314645 0.04452204 1.070711 -0.07071018 0.04452204 1.083147 -0.05555653 0.04452204 1.092388 -0.03826785 0.04452204 1.098079 -0.01950848 0.04452204 1.1 5.96046e-7 0.04452204 1.098079 0.01950955 0.04452204 1.092388 0.03826892 0.04452204 1.083147 0.0555576 0.04452204 1.070711 0.07071125 0.04452204 1.055557 0.08314752 0.04452204 1.038269 0.09238851 0.04452204 1.019509 0.09807896 0.04452204 1 0.1000005 0.04452204 -1.019509 0.0980789 0.04452204 -1 0.1000005 0.04452204 -1.038268 0.09238833 0.04452204 -1.055557 0.08314734 0.04452204 -1.070711 0.07071107 0.04452204 -1.083147 0.05555742 0.04452204 -1.092388 0.03826874 0.04452204 -1.098078 0.01950937 0.04452204 -1.1 4.56348e-7 0.04452204 -1.098078 -0.0195086 0.04452204 -1.092388 -0.03826785 0.04452204 -1.083147 -0.05555653 0.04452204 -1.070711 -0.07071018 0.04452204 -1.055557 -0.08314645 0.04452204 -1.038268 -0.09238755 0.04452204 -1.019509 -0.09807813 0.04452204 -0.9999997 -0.09999954 0.04452204 1 4.76837e-7 0.04452204</float_array> <float_array id="Plane_004-mesh-positions-array" count="240">-1 -0.09999954 0.01554518 1 -0.09999954 0.01554518 -1 0.1000005 0.01554518 1 0.1000005 0.01554518 1 0.1000005 0.01554518 1 -0.09999954 0.01554518 1.019509 -0.09807801 0.01554518 1.038269 -0.09238743 0.01554518 1.055557 -0.08314645 0.01554518 1.070711 -0.07071018 0.01554518 1.083147 -0.05555647 0.01554518 1.092388 -0.03826785 0.01554518 1.098079 -0.01950848 0.01554518 1.1 5.96046e-7 0.01554518 1.098079 0.01950955 0.01554518 1.092388 0.03826892 0.01554518 1.083147 0.05555754 0.01554518 1.070711 0.07071125 0.01554518 1.055557 0.08314752 0.01554518 1.038269 0.09238851 0.01554518 1.019509 0.09807896 0.01554518 -1 0.1000005 0.01554518 -1.019509 0.0980789 0.01554518 -1.038268 0.09238833 0.01554518 -1.055557 0.08314734 0.01554518 -1.070711 0.07071107 0.01554518 -1.083147 0.05555737 0.01554518 -1.092388 0.03826874 0.01554518 -1.098078 0.01950937 0.01554518 -1.1 4.56348e-7 0.01554518 -1.098078 -0.0195086 0.01554518 -1.092388 -0.03826785 0.01554518 -1.083147 -0.05555647 0.01554518 -1.070711 -0.07071018 0.01554518 -1.055557 -0.08314645 0.01554518 -1.038268 -0.09238755 0.01554518 -1.019509 -0.09807813 0.01554518 -0.9999997 -0.09999954 0.01554518 1 4.76837e-7 0.01554518 -1 4.76837e-7 0.01554518 -1 4.76837e-7 0.04452198 -1 0.1000005 0.04452198 -1 -0.09999954 0.04452198 1 -0.09999954 0.04452198 1 0.1000005 0.04452198 1.019509 -0.09807801 0.04452198 1 -0.09999954 0.04452198 1.038269 -0.09238743 0.04452198 1.055557 -0.08314645 0.04452198 1.070711 -0.07071018 0.04452198 1.083147 -0.05555647 0.04452198 1.092388 -0.03826785 0.04452198 1.098079 -0.01950848 0.04452198 1.1 5.96046e-7 0.04452198 1.098079 0.01950955 0.04452198 1.092388 0.03826892 0.04452198 1.083147 0.05555754 0.04452198 1.070711 0.07071125 0.04452198 1.055557 0.08314752 0.04452198 1.038269 0.09238851 0.04452198 1.019509 0.09807896 0.04452198 1 0.1000005 0.04452198 -1.019509 0.0980789 0.04452198 -1 0.1000005 0.04452198 -1.038268 0.09238833 0.04452198 -1.055557 0.08314734 0.04452198 -1.070711 0.07071107 0.04452198 -1.083147 0.05555737 0.04452198 -1.092388 0.03826874 0.04452198 -1.098078 0.01950937 0.04452198 -1.1 4.56348e-7 0.04452198 -1.098078 -0.0195086 0.04452198 -1.092388 -0.03826785 0.04452198 -1.083147 -0.05555647 0.04452198 -1.070711 -0.07071018 0.04452198 -1.055557 -0.08314645 0.04452198 -1.038268 -0.09238755 0.04452198 -1.019509 -0.09807813 0.04452198 -0.9999997 -0.09999954 0.04452198 1 4.76837e-7 0.04452198</float_array>
<technique_common> <technique_common>
<accessor source="#Plane_004-mesh-positions-array" count="80" stride="3"> <accessor source="#Plane_004-mesh-positions-array" count="80" stride="3">
<param name="X" type="float"/> <param name="X" type="float"/>
@@ -58,9 +58,9 @@
</technique_common> </technique_common>
</source> </source>
<source id="Plane_004-mesh-normals"> <source id="Plane_004-mesh-normals">
<float_array id="Plane_004-mesh-normals-array" count="342">0 0 -1 0 0 -1 0 0 -1 0 0 -1 1.19345e-7 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1 -1.19344e-7 0 -1 0 0 1 -1.19345e-7 0 1 0 0 1 1.19344e-7 0 1 -4.77372e-7 0 1 0 0 1 0 0 1 0 0 1 -2.38688e-7 0 1 0 0 1 2.3869e-7 0 1 1.19345e-7 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 -2.3869e-7 0 1 0 0 1 -0.6343874 0.7730153 0 -1 0 0 0.9569399 -0.2902863 0 1 0 0 -0.7730182 0.6343839 0 0.9951848 -0.09801703 0 -0.8819218 0.4713957 0 0.9951835 0.09803056 0 -1 -5.14244e-6 0 -0.9569436 0.2902743 0 0.9569399 0.2902863 0 -0.9951834 0.09803056 0 0.8819165 0.4714059 0 0.9238785 0.3826861 0 -0.9951835 -0.09802997 0 0.7730053 0.6343997 0 0.3826843 -0.9238792 0 0 -1 0 -0.9569393 -0.2902879 0 0.6344003 0.7730048 0 0 1 0 -0.8819164 -0.4714059 0 0.4713947 0.8819224 0 0.09802103 -0.9951844 0 -0.7730182 -0.6343839 0 1 3.85683e-6 0 0.2902728 0.9569441 0 -0.2902856 0.9569401 0 -0.6343874 -0.7730153 0 0.09802168 0.9951844 0 -0.4713947 0.8819224 0 -0.4713994 -0.8819198 0 -0.09802168 0.9951844 0 0.6344003 -0.7730048 0 -0.2902857 -0.9569401 0 1 2.57122e-6 0 -0.2902857 0.9569401 0 0.7730085 -0.6343957 0 -0.0980131 -0.9951851 0 -0.4713975 0.881921 0 0.8819219 -0.4713957 0 0.9569398 -0.2902863 0 -0.7730182 0.634384 0 0.9951835 -0.09802997 0 -0.8819165 0.4714059 0 0.9951847 0.09801757 0 -1 -3.85683e-6 0 -0.9569399 0.2902863 0 0.9569398 0.2902863 0 -0.9951834 0.09803056 0 0.8819218 0.4713957 0 0.9238789 0.3826851 0 0.7730085 0.6343957 0 0.3826831 -0.9238798 0 -0.956943 -0.2902759 0 0.6344001 0.7730049 0 -0.8819219 -0.4713957 0 0.4713975 0.881921 0 0.09802103 -0.9951844 0 -0.7730182 -0.634384 0 1 3.85683e-6 0 -0.2902855 0.9569401 0 0.09802103 0.9951844 0 -0.4714021 -0.8819184 0 -0.09802103 0.9951844 0 0.6344001 -0.7730049 0 -0.2902856 -0.9569401 0 1 2.57122e-6 0 -0.2902856 0.9569401 0 0.7730054 -0.6343996 0 -0.09801179 -0.9951853 0 -0.4713947 0.8819224 0 0.8819164 -0.471406 0</float_array> <float_array id="Plane_004-mesh-normals-array" count="270">0 0 -1 1.19345e-7 0 -1 0 0 -1 0 0 -1 -1.19344e-7 0 -1 -1.19343e-7 0 -1 0 0 -1 0 0 -1 -1.19343e-7 0 -1 0 0 1 1.19345e-7 0 1 0 0 1 -4.77394e-7 0 1 -1.19344e-7 0 1 -4.77375e-7 0 1 4.77387e-7 0 1 0 0 1 -1.19345e-7 0 1 2.38692e-7 0 1 2.38687e-7 0 1 -2.38687e-7 0 1 -0.6343871 0.7730156 0 -1 0 0 0.9569398 -0.2902864 0 1 0 0 -0.7730116 0.6343919 0 0.9951861 -0.09800404 0 -0.8819217 0.4713962 0 0.9951872 0.09799164 0 -0.9569509 0.2902504 0 0.9569326 0.2903105 0 -0.9951821 0.09804385 0 0.8819217 0.471396 0 0.923877 0.3826896 0 -0.9951823 -0.09804314 0 0.773018 0.6343841 0 0.3826818 -0.9238802 0 0 -1 0 -0.9569467 -0.2902641 0 0.6343807 0.7730209 0 0 1 0 -0.8819217 -0.4713962 0 0.4714139 0.8819121 0 0.09802061 -0.9951844 0 -0.7730181 -0.6343839 0 1 3.85683e-6 0 0.2902668 0.9569458 0 -0.2902731 0.9569439 0 -0.6343807 -0.7730209 0 0.09802073 0.9951844 0 -0.4714134 0.8819125 0 -0.4713908 -0.8819245 0 -0.09802436 0.995184 0 0.6343871 -0.7730156 0 -0.2902895 -0.956939 0 -0.2902888 0.9569392 0 0.7730117 -0.6343918 0 -0.09801268 -0.9951853 0 -0.4713921 0.8819237 0 0.8819217 -0.4713962 0 -0.6343807 0.7730209 0 0.9569326 -0.2903105 0 -0.7730181 0.634384 0 0.9951873 -0.0979911 0 0.995186 0.09800463 0 -0.9569472 0.2902624 0 0.9569398 0.2902864 0 -0.9951821 0.09804385 0 0.923877 0.3826897 0 0.7730115 0.634392 0 0.3826841 -0.9238793 0 -0.9569503 -0.2902522 0 0.6343871 0.7730156 0 0.4714112 0.8819137 0 0.09801995 -0.9951846 0 -0.7730117 -0.6343919 0 1 2.57122e-6 0 0.2902686 0.9569453 0 -0.2902749 0.9569434 0 -0.6343871 -0.7730156 0 0.09802132 0.9951844 0 -0.4714105 0.8819139 0 -0.4713962 -0.8819217 0 -0.09802371 0.9951841 0 0.6343807 -0.7730209 0 -0.2902895 -0.956939 0 -0.2902888 0.9569392 0 0.7730181 -0.634384 0 -0.09801262 -0.9951853 0 -0.4713866 0.8819267 0</float_array>
<technique_common> <technique_common>
<accessor source="#Plane_004-mesh-normals-array" count="114" stride="3"> <accessor source="#Plane_004-mesh-normals-array" count="90" stride="3">
<param name="X" type="float"/> <param name="X" type="float"/>
<param name="Y" type="float"/> <param name="Y" type="float"/>
<param name="Z" type="float"/> <param name="Z" type="float"/>
@@ -74,7 +74,7 @@
<input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/> <input semantic="VERTEX" source="#Plane_004-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Plane_004-mesh-normals" offset="1"/> <input semantic="NORMAL" source="#Plane_004-mesh-normals" offset="1"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount> <vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>38 0 0 0 39 0 6 0 5 0 38 0 8 1 6 1 38 1 9 2 38 2 10 2 8 0 38 0 9 0 10 0 38 0 11 0 11 0 38 0 12 0 12 3 38 3 13 3 4 0 20 0 38 0 19 0 38 0 20 0 18 4 38 4 19 4 17 0 38 0 18 0 16 0 38 0 17 0 15 0 38 0 16 0 14 0 38 0 15 0 13 0 38 0 14 0 37 5 36 5 39 5 35 6 39 6 36 6 21 7 39 7 22 7 34 8 39 8 35 8 33 9 39 9 34 9 32 10 39 10 33 10 31 11 39 11 32 11 30 12 39 12 31 12 29 13 39 13 30 13 28 14 39 14 29 14 27 15 39 15 28 15 26 16 39 16 27 16 25 17 39 17 26 17 22 18 39 18 23 18 23 19 39 19 24 19 24 20 39 20 25 20 40 21 43 21 79 21 45 21 79 21 46 21 48 21 79 21 45 21 49 21 50 21 79 21 48 21 49 21 79 21 50 22 51 22 79 22 51 21 52 21 79 21 52 23 53 23 79 23 61 21 79 21 60 21 59 21 60 21 79 21 58 21 59 21 79 21 57 21 58 21 79 21 56 21 57 21 79 21 55 21 56 21 79 21 54 24 55 24 79 24 53 21 54 21 79 21 78 25 40 25 77 25 76 26 77 26 40 26 63 27 62 27 40 27 75 28 76 28 40 28 74 29 75 29 40 29 73 30 74 30 40 30 72 31 73 31 40 31 71 32 72 32 40 32 70 33 71 33 40 33 69 34 70 34 40 34 68 35 69 35 40 35 67 36 68 36 40 36 66 37 67 37 40 37 62 38 64 38 40 38 64 39 65 39 40 39 65 40 66 40 40 40 25 41 65 41 24 41 38 42 61 42 4 42 12 43 51 43 11 43 38 44 43 44 1 44 26 45 66 45 25 45 13 46 52 46 12 46 0 42 40 42 39 42 27 47 67 47 26 47 14 48 53 48 13 48 5 49 79 49 38 49 28 50 68 50 27 50 15 51 54 51 14 51 29 52 69 52 28 52 16 53 55 53 15 53 38 54 47 54 7 54 39 42 41 42 2 42 30 55 70 55 29 55 17 56 56 56 16 56 8 57 45 57 6 57 1 58 42 58 0 58 31 59 71 59 30 59 18 60 57 60 17 60 2 61 44 61 3 61 32 62 72 62 31 62 19 63 58 63 18 63 6 64 46 64 5 64 33 65 73 65 32 65 37 66 40 66 78 66 20 67 59 67 19 67 6 68 47 68 7 68 34 69 74 69 33 69 4 70 60 70 20 70 7 71 48 71 8 71 35 72 75 72 34 72 22 73 63 73 21 73 9 74 48 74 8 74 36 75 76 75 35 75 21 76 40 76 39 76 23 77 62 77 22 77 10 78 49 78 9 78 37 79 77 79 36 79 24 80 64 80 23 80 11 81 50 81 10 81 3 44 79 44 38 44 39 0 2 0 3 0 38 0 1 0 0 0 39 0 3 0 38 0 44 21 41 21 40 21 40 21 42 21 43 21 79 21 44 21 40 21 25 41 66 41 65 41 38 42 79 42 61 42 12 82 52 82 51 82 38 44 79 44 43 44 26 83 67 83 66 83 13 84 53 84 52 84 0 42 42 42 40 42 27 85 68 85 67 85 14 86 54 86 53 86 5 87 46 87 79 87 28 88 69 88 68 88 15 89 55 89 54 89 29 90 70 90 69 90 16 91 56 91 55 91 38 92 79 92 47 92 39 42 40 42 41 42 30 55 71 55 70 55 17 93 57 93 56 93 8 94 48 94 45 94 1 58 43 58 42 58 31 95 72 95 71 95 18 96 58 96 57 96 2 61 41 61 44 61 32 97 73 97 72 97 19 98 59 98 58 98 6 99 45 99 46 99 33 100 74 100 73 100 37 101 39 101 40 101 20 67 60 67 59 67 6 102 45 102 47 102 34 69 75 69 74 69 4 103 61 103 60 103 7 80 47 80 48 80 35 104 76 104 75 104 22 105 62 105 63 105 9 106 49 106 48 106 36 107 77 107 76 107 21 108 63 108 40 108 23 109 64 109 62 109 10 110 50 110 49 110 37 111 78 111 77 111 24 112 65 112 64 112 11 113 51 113 50 113 3 44 44 44 79 44</p> <p>38 0 0 0 39 0 6 1 5 1 38 1 8 0 6 0 38 0 9 2 38 2 10 2 8 0 38 0 9 0 10 0 38 0 11 0 11 0 38 0 12 0 12 3 38 3 13 3 4 0 20 0 38 0 19 0 38 0 20 0 18 0 38 0 19 0 17 0 38 0 18 0 16 0 38 0 17 0 15 0 38 0 16 0 14 0 38 0 15 0 13 0 38 0 14 0 37 4 36 4 39 4 35 0 39 0 36 0 21 0 39 0 22 0 34 0 39 0 35 0 33 5 39 5 34 5 32 0 39 0 33 0 31 0 39 0 32 0 30 0 39 0 31 0 29 0 39 0 30 0 28 6 39 6 29 6 27 0 39 0 28 0 26 0 39 0 27 0 25 7 39 7 26 7 22 0 39 0 23 0 23 0 39 0 24 0 24 8 39 8 25 8 40 9 43 9 79 9 45 9 79 9 46 9 48 9 79 9 45 9 49 9 50 9 79 9 48 9 49 9 79 9 50 10 51 10 79 10 51 9 52 9 79 9 52 11 53 11 79 11 61 9 79 9 60 9 59 9 60 9 79 9 58 12 59 12 79 12 57 9 58 9 79 9 56 9 57 9 79 9 55 9 56 9 79 9 54 13 55 13 79 13 53 9 54 9 79 9 78 14 40 14 77 14 76 15 77 15 40 15 63 9 62 9 40 9 75 9 76 9 40 9 74 9 75 9 40 9 73 9 74 9 40 9 72 9 73 9 40 9 71 9 72 9 40 9 70 9 71 9 40 9 69 16 70 16 40 16 68 9 69 9 40 9 67 17 68 17 40 17 66 18 67 18 40 18 62 9 64 9 40 9 64 19 65 19 40 19 65 20 66 20 40 20 25 21 65 21 24 21 38 22 61 22 4 22 12 23 51 23 11 23 38 24 43 24 1 24 26 25 66 25 25 25 13 26 52 26 12 26 0 22 40 22 39 22 27 27 67 27 26 27 14 28 53 28 13 28 5 22 79 22 38 22 28 29 68 29 27 29 15 30 54 30 14 30 29 31 69 31 28 31 16 32 55 32 15 32 38 33 47 33 7 33 39 22 41 22 2 22 30 34 70 34 29 34 17 35 56 35 16 35 8 36 45 36 6 36 1 37 42 37 0 37 31 38 71 38 30 38 18 39 57 39 17 39 2 40 44 40 3 40 32 41 72 41 31 41 19 42 58 42 18 42 6 43 46 43 5 43 33 44 73 44 32 44 37 45 40 45 78 45 20 46 59 46 19 46 6 47 47 47 7 47 34 48 74 48 33 48 4 49 60 49 20 49 7 50 48 50 8 50 35 51 75 51 34 51 22 52 63 52 21 52 9 53 48 53 8 53 36 54 76 54 35 54 21 24 40 24 39 24 23 55 62 55 22 55 10 56 49 56 9 56 37 57 77 57 36 57 24 58 64 58 23 58 11 59 50 59 10 59 3 24 79 24 38 24 39 0 2 0 3 0 38 0 1 0 0 0 39 0 3 0 38 0 44 9 41 9 40 9 40 9 42 9 43 9 79 9 44 9 40 9 25 60 66 60 65 60 38 22 79 22 61 22 12 61 52 61 51 61 38 24 79 24 43 24 26 62 67 62 66 62 13 63 53 63 52 63 0 22 42 22 40 22 27 27 68 27 67 27 14 64 54 64 53 64 5 22 46 22 79 22 28 65 69 65 68 65 15 66 55 66 54 66 29 67 70 67 69 67 16 32 56 32 55 32 38 68 79 68 47 68 39 22 40 22 41 22 30 34 71 34 70 34 17 69 57 69 56 69 8 70 48 70 45 70 1 37 43 37 42 37 31 71 72 71 71 71 18 72 58 72 57 72 2 40 41 40 44 40 32 41 73 41 72 41 19 73 59 73 58 73 6 74 45 74 46 74 33 75 74 75 73 75 37 76 39 76 40 76 20 77 60 77 59 77 6 78 45 78 47 78 34 79 75 79 74 79 4 80 61 80 60 80 7 81 47 81 48 81 35 82 76 82 75 82 22 83 62 83 63 83 9 84 49 84 48 84 36 85 77 85 76 85 21 24 63 24 40 24 23 86 64 86 62 86 10 87 50 87 49 87 37 88 78 88 77 88 24 89 65 89 64 89 11 59 51 59 50 59 3 24 44 24 79 24</p>
</polylist> </polylist>
</mesh> </mesh>
</geometry> </geometry>
@@ -83,7 +83,7 @@
<library_visual_scenes> <library_visual_scenes>
<visual_scene id="Scene" name="Scene"> <visual_scene id="Scene" name="Scene">
<node id="Plane" name="Plane" type="NODE"> <node id="Plane" name="Plane" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 -4.76837e-7 0 0 1 0 0 0 0 1</matrix> <matrix sid="transform">0.4856636 0 0 0 0 0.6802911 0 -4.76837e-7 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Plane_004-mesh" name="Plane"> <instance_geometry url="#Plane_004-mesh" name="Plane">
<bind_material> <bind_material>
<technique_common> <technique_common>
@@ -1,147 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-26T19:13:35</created>
<modified>2017-09-26T19:13:35</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.01630632 0.52949 0.0134405 1</color>
</diffuse>
<specular>
<color sid="specular">0.125 0.125 0.125 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0.5334254 0 1</color>
</diffuse>
<specular>
<color sid="specular">0.125 0.125 0.125 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5257253 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8090167 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8090116 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284252 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616992 0.7240421 0.1947362 0.6616954 0.4911194 0.356821 0.7946576 0.4089462 0.6284253 0.6616984 -0.1875943 0.5773454 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875943 -0.5773454 0.7946577 0.03853034 -0.7487788 0.6616992 0.4911193 -0.356821 0.7946577 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875943 0.5773454 -0.7946577 -0.0385304 0.7487789 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911193 0.356821 -0.7946577 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911194 -0.356821 -0.7946576 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487789 -0.6616991 0.1875943 -0.5773454 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150898 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150899 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="60">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 38 11 33 36 11 34 41 11 35 36 12 36 9 12 37 41 12 38 41 13 39 35 13 40 40 13 41 35 14 42 8 14 43 40 14 44 40 15 45 34 15 46 39 15 47 34 16 48 7 16 49 39 16 50 39 17 51 33 17 52 37 17 53 33 18 54 6 18 55 37 18 56 37 19 57 32 19 58 38 19 59 32 20 60 10 20 61 38 20 62 23 21 63 36 21 64 10 21 65 23 22 66 30 22 67 36 22 68 30 23 69 9 23 70 36 23 71 31 24 72 35 24 73 9 24 74 31 25 75 28 25 76 35 25 77 28 26 78 8 26 79 35 26 80 29 27 81 34 27 82 8 27 83 29 28 84 26 28 85 34 28 86 26 29 87 7 29 88 34 29 89 27 30 90 33 30 91 7 30 92 27 31 93 24 31 94 33 31 95 24 32 96 6 32 97 33 32 98 25 33 99 32 33 100 6 33 101 25 34 102 22 34 103 32 34 104 22 35 105 10 35 106 32 35 107 30 36 108 21 36 109 31 36 110 21 37 111 4 37 112 31 37 113 28 38 114 20 38 115 29 38 116 20 39 117 3 39 118 29 39 119 26 40 120 18 40 121 27 40 122 18 41 123 2 41 124 27 41 125 24 42 126 14 42 127 25 42 128 14 43 129 1 43 130 25 43 131 22 44 132 15 44 133 23 44 134 15 45 135 5 45 136 23 45 137 16 46 138 21 46 139 5 46 140 16 47 141 19 47 142 21 47 143 19 48 144 4 48 145 21 48 146 19 49 147 20 49 148 4 49 149 19 50 150 17 50 151 20 50 152 17 51 153 3 51 154 20 51 155 17 52 156 18 52 157 3 52 158 17 53 159 12 53 160 18 53 161 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 15 56 168 13 56 169 16 56 170 12 57 171 14 57 172 2 57 173 12 58 174 13 58 175 14 58 176 13 59 177 1 59 178 14 59 179</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
@@ -1,147 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
<asset>
<contributor>
<author>Blender User</author>
<authoring_tool>Blender 2.78.0 commit date:2016-09-26, commit time:12:42, hash:4bb1e22</authoring_tool>
</contributor>
<created>2017-09-19T15:46:34</created>
<modified>2017-09-19T15:46:34</modified>
<unit name="meter" meter="1"/>
<up_axis>Z_UP</up_axis>
</asset>
<library_images/>
<library_effects>
<effect id="Material_001_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.03920602 0.04758029 0.8 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
<effect id="Material_002_001-effect">
<profile_COMMON>
<technique sid="common">
<phong>
<emission>
<color sid="emission">0 0 0 1</color>
</emission>
<ambient>
<color sid="ambient">0 0 0 1</color>
</ambient>
<diffuse>
<color sid="diffuse">0.64 0.5287738 0.5454956 1</color>
</diffuse>
<specular>
<color sid="specular">0.25 0.25 0.25 1</color>
</specular>
<shininess>
<float sid="shininess">50</float>
</shininess>
<index_of_refraction>
<float sid="index_of_refraction">1</float>
</index_of_refraction>
</phong>
</technique>
</profile_COMMON>
</effect>
</library_effects>
<library_materials>
<material id="Material_001_001-material" name="Material_001_001">
<instance_effect url="#Material_001_001-effect"/>
</material>
<material id="Material_002_001-material" name="Material_002_001">
<instance_effect url="#Material_002_001-effect"/>
</material>
</library_materials>
<library_geometries>
<geometry id="Icosphere_001-mesh" name="Icosphere.001">
<mesh>
<source id="Icosphere_001-mesh-positions">
<float_array id="Icosphere_001-mesh-positions-array" count="126">0 0 -1 0.7236073 -0.5257253 -0.4472195 -0.276388 -0.8506492 -0.4472199 -0.8944262 0 -0.4472156 -0.276388 0.8506492 -0.4472199 0.7236073 0.5257253 -0.4472195 0.276388 -0.8506492 0.4472199 -0.7236073 -0.5257253 0.4472195 -0.7236073 0.5257253 0.4472195 0.276388 0.8506492 0.4472199 0.8944262 0 0.4472156 0 0 1 -0.1624554 -0.4999952 -0.8506544 0.4253227 -0.3090114 -0.8506542 0.2628688 -0.8090116 -0.5257377 0.8506479 0 -0.5257359 0.4253227 0.3090114 -0.8506542 -0.5257298 0 -0.8506517 -0.6881894 -0.4999969 -0.5257362 -0.1624554 0.4999952 -0.8506544 -0.6881894 0.4999969 -0.5257362 0.2628688 0.8090116 -0.5257377 0.9510579 -0.3090126 0 0.9510579 0.3090126 0 0 -1 0 0.5877856 -0.8090167 0 -0.9510579 -0.3090126 0 -0.5877856 -0.8090167 0 -0.5877856 0.8090167 0 -0.9510579 0.3090126 0 0.5877856 0.8090167 0 0 1 0 0.6881894 -0.4999969 0.5257362 -0.2628688 -0.8090116 0.5257377 -0.8506479 0 0.5257359 -0.2628688 0.8090116 0.5257377 0.6881894 0.4999969 0.5257362 0.1624554 -0.4999952 0.8506544 0.5257298 0 0.8506517 -0.4253227 -0.3090114 0.8506542 -0.4253227 0.3090114 0.8506542 0.1624554 0.4999952 0.8506544</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-positions-array" count="42" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-normals">
<float_array id="Icosphere_001-mesh-normals-array" count="240">0.7002241 -0.2680317 -0.6616988 0.9049891 -0.2680316 -0.3303847 0.02474653 -0.9435215 -0.330386 -0.8896973 -0.3150947 -0.3303849 -0.5746018 0.7487837 -0.3303875 0.5345759 0.7778646 -0.3303867 0.4089462 -0.6284253 0.6616985 -0.4712997 -0.5831224 0.6616985 -0.7002241 0.2680317 0.6616988 0.03853034 0.7487788 0.6616991 0.7240421 0.1947362 0.6616954 0.4911195 0.356821 0.7946575 0.4089463 0.6284252 0.6616985 -0.1875942 0.5773453 0.7946577 -0.4712997 0.5831224 0.6616985 -0.6070605 0 0.7946557 -0.7002241 -0.2680318 0.6616988 -0.1875942 -0.5773453 0.7946577 0.03853034 -0.7487788 0.6616991 0.4911194 -0.356821 0.7946576 0.7240421 -0.1947363 0.6616954 0.8896973 0.3150946 0.3303849 0.7946556 0.5773479 0.1875951 0.5746018 0.7487836 0.3303875 -0.02474653 0.9435214 0.3303861 -0.3035309 0.9341714 0.1875976 -0.5345759 0.7778646 0.3303867 -0.9049891 0.2680316 0.3303846 -0.9822458 0 0.1875985 -0.9049891 -0.2680316 0.3303846 -0.5345759 -0.7778646 0.3303867 -0.3035309 -0.9341714 0.1875975 -0.02474653 -0.9435214 0.3303861 0.5746018 -0.7487836 0.3303875 0.7946556 -0.5773479 0.1875951 0.8896973 -0.3150946 0.3303849 0.3035309 0.9341714 -0.1875975 0.02474653 0.9435215 -0.330386 -0.7946556 0.5773479 -0.1875951 -0.8896973 0.3150945 -0.3303849 -0.7946556 -0.5773479 -0.1875951 -0.5746018 -0.7487836 -0.3303875 0.3035309 -0.9341714 -0.1875976 0.5345759 -0.7778645 -0.3303867 0.9822458 0 -0.1875985 0.9049891 0.2680316 -0.3303847 0.4712997 0.5831224 -0.6616986 0.1875942 0.5773453 -0.7946577 -0.0385304 0.7487788 -0.6616991 -0.4089462 0.6284252 -0.6616984 -0.4911194 0.356821 -0.7946576 -0.7240421 0.1947362 -0.6616954 -0.7240421 -0.1947362 -0.6616954 -0.4911195 -0.356821 -0.7946575 -0.4089462 -0.6284252 -0.6616984 0.7002241 0.2680318 -0.6616988 0.6070605 0 -0.7946556 -0.0385304 -0.7487788 -0.6616991 0.1875942 -0.5773453 -0.7946577 0.4712997 -0.5831224 -0.6616986 0.1023808 -0.3150898 -0.9435235 -0.2680341 -0.1947365 -0.9435229 -0.2680341 0.1947365 -0.9435229 0.1023808 0.3150898 -0.9435235 0.802609 -0.5831265 -0.1256273 -0.306569 -0.9435216 -0.1256289 -0.9920774 0 -0.1256284 -0.306569 0.9435216 -0.1256289 0.802609 0.5831265 -0.1256273 0.2680341 0.1947365 0.9435229 -0.1023808 0.3150899 0.9435235 -0.3313045 0 0.943524 -0.1023808 -0.3150898 0.9435235 0.2680341 -0.1947365 0.9435229 0.306569 0.9435216 0.1256289 -0.802609 0.5831265 0.1256274 -0.802609 -0.5831265 0.1256274 0.306569 -0.9435216 0.1256289 0.9920774 0 0.1256284 0.3313045 0 -0.943524</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-normals-array" count="80" stride="3">
<param name="X" type="float"/>
<param name="Y" type="float"/>
<param name="Z" type="float"/>
</accessor>
</technique_common>
</source>
<source id="Icosphere_001-mesh-map-0">
<float_array id="Icosphere_001-mesh-map-0-array" count="480">0.1891562 0.4353454 0.2201194 0.3408505 0.2923961 0.4111046 0.1891562 0.4353454 0.2923961 0.4111046 0.2610388 0.5272238 0.06585121 0.2636542 0.1202549 0.3546833 1.02655e-4 0.3599037 0.1891674 0.09197556 0.120263 0.1726311 0.07693755 0.06042814 0.3900915 0.1577098 0.2924051 0.1162222 0.3863589 0.0410583 0.3900838 0.3696232 0.3989981 0.2636671 0.4998953 0.3296785 0.6099237 0.1577003 0.7076132 0.1162198 0.6911104 0.216345 0.6099155 0.3696137 0.6010091 0.2636568 0.6911069 0.3109756 0.8108381 0.4353509 0.7076001 0.4111025 0.779882 0.3408538 0.934156 0.263669 0.8797454 0.354694 0.833759 0.263666 0.8108526 0.09198099 0.8797511 0.1726418 0.7798885 0.1864736 0.7798885 0.1864736 0.8797511 0.1726418 0.833759 0.263666 0.8797511 0.1726418 0.934156 0.263669 0.833759 0.263666 0.833759 0.263666 0.8797454 0.354694 0.779882 0.3408538 0.8797454 0.354694 0.8108381 0.4353509 0.779882 0.3408538 0.779882 0.3408538 0.7076001 0.4111025 0.6911069 0.3109756 0.7076001 0.4111025 0.6099155 0.3696137 0.6911069 0.3109756 0.6911069 0.3109756 0.6010091 0.2636568 0.6911104 0.216345 0.6010091 0.2636568 0.6099237 0.1577003 0.6911104 0.216345 0.6911104 0.216345 0.7076132 0.1162198 0.7798885 0.1864736 0.7076132 0.1162198 0.8108526 0.09198099 0.7798885 0.1864736 0.923085 0.06044203 0.8797511 0.1726418 0.8108526 0.09198099 0.923085 0.06044203 0.9998974 0.16742 0.8797511 0.1726418 0.9998974 0.16742 0.934156 0.263669 0.8797511 0.1726418 0.9998974 0.3599234 0.8797454 0.354694 0.934156 0.263669 0.9998974 0.3599234 0.923074 0.4668999 0.8797454 0.354694 0.923074 0.4668999 0.8108381 0.4353509 0.8797454 0.354694 0.7389487 0.527224 0.7076001 0.4111025 0.8108381 0.4353509 0.7389487 0.527224 0.6136447 0.4862654 0.7076001 0.4111025 0.6136447 0.4862654 0.6099155 0.3696137 0.7076001 0.4111025 0.5001069 0.3296607 0.6010091 0.2636568 0.6099155 0.3696137 0.5001069 0.3296607 0.5001106 0.1976431 0.6010091 0.2636568 0.5001106 0.1976431 0.6099237 0.1577003 0.6010091 0.2636568 0.613665 0.041049 0.7076132 0.1162198 0.6099237 0.1577003 0.613665 0.041049 0.7389741 1.02655e-4 0.7076132 0.1162198 0.7389741 1.02655e-4 0.8108526 0.09198099 0.7076132 0.1162198 0.4998953 0.3296785 0.3989981 0.2636671 0.4999017 0.1976609 0.3989981 0.2636671 0.3900915 0.1577098 0.4999017 0.1976609 0.3863589 0.0410583 0.2924051 0.1162222 0.2610529 1.02655e-4 0.2924051 0.1162222 0.1891674 0.09197556 0.2610529 1.02655e-4 0.07693755 0.06042814 0.120263 0.1726311 1.17172e-4 0.1674003 0.120263 0.1726311 0.06585121 0.2636542 1.17172e-4 0.1674003 1.02655e-4 0.3599037 0.1202549 0.3546833 0.07691794 0.466886 0.1202549 0.3546833 0.1891562 0.4353454 0.07691794 0.466886 0.2610388 0.5272238 0.2923961 0.4111046 0.3863458 0.4862747 0.2923961 0.4111046 0.3900838 0.3696232 0.3863458 0.4862747 0.3088967 0.3109791 0.3989981 0.2636671 0.3900838 0.3696232 0.3088967 0.3109791 0.3089004 0.2163485 0.3989981 0.2636671 0.3089004 0.2163485 0.3900915 0.1577098 0.3989981 0.2636671 0.3089004 0.2163485 0.2924051 0.1162222 0.3900915 0.1577098 0.3089004 0.2163485 0.2201245 0.1864705 0.2924051 0.1162222 0.2201245 0.1864705 0.1891674 0.09197556 0.2924051 0.1162222 0.2201245 0.1864705 0.120263 0.1726311 0.1891674 0.09197556 0.2201245 0.1864705 0.1662483 0.2636588 0.120263 0.1726311 0.1662483 0.2636588 0.06585121 0.2636542 0.120263 0.1726311 0.2923961 0.4111046 0.3088967 0.3109791 0.3900838 0.3696232 0.2923961 0.4111046 0.2201194 0.3408505 0.3088967 0.3109791 0.1662483 0.2636588 0.1202549 0.3546833 0.06585121 0.2636542 0.1662483 0.2636588 0.2201194 0.3408505 0.1202549 0.3546833 0.2201194 0.3408505 0.1891562 0.4353454 0.1202549 0.3546833 0.2038319 0.6020938 0.07803589 0.775239 2.88122e-4 0.5359594 0.2038319 0.6020938 2.88122e-4 0.5359594 0.2038319 0.3880734 0.2038319 0.6020938 0.2038319 0.3880734 0.4073758 0.5359594 0.2038319 0.6020938 0.4073758 0.5359594 0.329628 0.775239 0.8690316 0.364753 0.791095 0.5663278 0.6529134 0.364753 0.5301482 0.1791203 0.6523408 0.3573763 0.407952 0.3573763 0.5301446 0.5663277 0.407952 0.3880734 0.6523372 0.3880734 0.20244 0.9919336 0.20244 0.7758153 0.4040137 0.9139961 0.4079523 0.566904 0.6095281 0.6448412 0.407952 0.7830209 0.203883 2.88122e-4 0.4073758 0.1482443 0.2038091 0.2143085 0.4073758 0.1482443 0.3295453 0.3874972 0.2038091 0.2143085 0.3295453 0.3874972 0.07795333 0.3874103 0.2038091 0.2143085 0.07795333 0.3874103 2.88122e-4 0.1481037 0.2038091 0.2143085 2.88122e-4 0.1481037 0.203883 2.88122e-4 0.2038091 0.2143085 0.6523409 0.178544 0.407952 0.1785441 0.5301446 2.88122e-4 0.7910969 0.2018641 0.6529171 2.88122e-4 0.8690339 2.88122e-4 0.8116793 0.6448401 0.6101047 0.7830221 0.6101044 0.566904 2.88169e-4 0.7758153 0.2018638 0.9139932 2.88122e-4 0.9919315 0.407952 0.7835971 0.6095241 0.9217739 0.407952 0.999712 0.07803589 0.775239 0.2038319 0.6020938 0.329628 0.775239</float_array>
<technique_common>
<accessor source="#Icosphere_001-mesh-map-0-array" count="240" stride="2">
<param name="S" type="float"/>
<param name="T" type="float"/>
</accessor>
</technique_common>
</source>
<vertices id="Icosphere_001-mesh-vertices">
<input semantic="POSITION" source="#Icosphere_001-mesh-positions"/>
</vertices>
<polylist material="Material_001_001-material" count="60">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>1 0 0 13 0 1 15 0 2 1 1 3 15 1 4 22 1 5 2 2 6 14 2 7 24 2 8 3 3 9 18 3 10 26 3 11 4 4 12 20 4 13 28 4 14 5 5 15 21 5 16 30 5 17 6 6 18 32 6 19 37 6 20 7 7 21 33 7 22 39 7 23 8 8 24 34 8 25 40 8 26 9 9 27 35 9 28 41 9 29 10 10 30 36 10 31 38 10 32 38 11 33 36 11 34 41 11 35 36 12 36 9 12 37 41 12 38 41 13 39 35 13 40 40 13 41 35 14 42 8 14 43 40 14 44 40 15 45 34 15 46 39 15 47 34 16 48 7 16 49 39 16 50 39 17 51 33 17 52 37 17 53 33 18 54 6 18 55 37 18 56 37 19 57 32 19 58 38 19 59 32 20 60 10 20 61 38 20 62 23 21 63 36 21 64 10 21 65 23 22 66 30 22 67 36 22 68 30 23 69 9 23 70 36 23 71 31 24 72 35 24 73 9 24 74 31 25 75 28 25 76 35 25 77 28 26 78 8 26 79 35 26 80 29 27 81 34 27 82 8 27 83 29 28 84 26 28 85 34 28 86 26 29 87 7 29 88 34 29 89 27 30 90 33 30 91 7 30 92 27 31 93 24 31 94 33 31 95 24 32 96 6 32 97 33 32 98 25 33 99 32 33 100 6 33 101 25 34 102 22 34 103 32 34 104 22 35 105 10 35 106 32 35 107 30 36 108 21 36 109 31 36 110 21 37 111 4 37 112 31 37 113 28 38 114 20 38 115 29 38 116 20 39 117 3 39 118 29 39 119 26 40 120 18 40 121 27 40 122 18 41 123 2 41 124 27 41 125 24 42 126 14 42 127 25 42 128 14 43 129 1 43 130 25 43 131 22 44 132 15 44 133 23 44 134 15 45 135 5 45 136 23 45 137 16 46 138 21 46 139 5 46 140 16 47 141 19 47 142 21 47 143 19 48 144 4 48 145 21 48 146 19 49 147 20 49 148 4 49 149 19 50 150 17 50 151 20 50 152 17 51 153 3 51 154 20 51 155 17 52 156 18 52 157 3 52 158 17 53 159 12 53 160 18 53 161 12 54 162 2 54 163 18 54 164 15 55 165 16 55 166 5 55 167 15 56 168 13 56 169 16 56 170 12 57 171 14 57 172 2 57 173 12 58 174 13 58 175 14 58 176 13 59 177 1 59 178 14 59 179</p>
</polylist>
<polylist material="Material_002_001-material" count="20">
<input semantic="VERTEX" source="#Icosphere_001-mesh-vertices" offset="0"/>
<input semantic="NORMAL" source="#Icosphere_001-mesh-normals" offset="1"/>
<input semantic="TEXCOORD" source="#Icosphere_001-mesh-map-0" offset="2" set="0"/>
<vcount>3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 </vcount>
<p>0 60 180 13 60 181 12 60 182 0 61 183 12 61 184 17 61 185 0 62 186 17 62 187 19 62 188 0 63 189 19 63 190 16 63 191 1 64 192 22 64 193 25 64 194 2 65 195 24 65 196 27 65 197 3 66 198 26 66 199 29 66 200 4 67 201 28 67 202 31 67 203 5 68 204 30 68 205 23 68 206 38 69 207 41 69 208 11 69 209 41 70 210 40 70 211 11 70 212 40 71 213 39 71 214 11 71 215 39 72 216 37 72 217 11 72 218 37 73 219 38 73 220 11 73 221 30 74 222 31 74 223 9 74 224 28 75 225 29 75 226 8 75 227 26 76 228 27 76 229 7 76 230 24 77 231 25 77 232 6 77 233 22 78 234 23 78 235 10 78 236 13 79 237 0 79 238 16 79 239</p>
</polylist>
</mesh>
</geometry>
</library_geometries>
<library_controllers/>
<library_visual_scenes>
<visual_scene id="Scene" name="Scene">
<node id="Icosphere" name="Icosphere" type="NODE">
<matrix sid="transform">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix>
<instance_geometry url="#Icosphere_001-mesh" name="Icosphere">
<bind_material>
<technique_common>
<instance_material symbol="Material_001_001-material" target="#Material_001_001-material"/>
<instance_material symbol="Material_002_001-material" target="#Material_002_001-material"/>
</technique_common>
</bind_material>
</instance_geometry>
</node>
</visual_scene>
</library_visual_scenes>
<scene>
<instance_visual_scene url="#Scene"/>
</scene>
</COLLADA>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-171
View File
@@ -1,171 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<BoatConfig>
<Modified>2015-08-28T17:32:59+0100</Modified>
<Version>12</Version>
<Snapshot>219</Snapshot>
<Settings>
<RaceBoatType Type="AC45"/>
<BoatDimension BoatLength="14.019" HullLength="13.449"/>
<ZoneSize MarkZoneSize="40.347" CourseZoneSize="53.796"/>
<ZoneLimits Limit1="200" Limit2="100" Limit3="53.796" Limit4="0" Limit5="-100"/>
</Settings>
<BoatShapes>
<BoatShape ShapeID="0">
<Vertices>
<Vtx Seq="3" Y="25" X="0"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="14">
<Vertices>
<Vtx Seq="1" Y="0" X="-1"/>
<Vtx Seq="2" Y="0.75" X="-1"/>
<Vtx Seq="3" Y="0.75" X="-0.25"/>
<Vtx Seq="4" Y="3.5" X="-0.25"/>
<Vtx Seq="5" Y="4.5" X="-1"/>
<Vtx Seq="6" Y="6.5" X="-1"/>
<Vtx Seq="7" Y="7" X="-0.5"/>
<Vtx Seq="8" Y="7" X="0.5"/>
<Vtx Seq="9" Y="6.5" X="1"/>
<Vtx Seq="10" Y="4.5" X="1"/>
<Vtx Seq="11" Y="3.5" X="0.25"/>
<Vtx Seq="12" Y="0.75" X="0.25"/>
<Vtx Seq="13" Y="0.75" X="1"/>
<Vtx Seq="14" Y="0" X="1"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="15">
<Vertices>
<Vtx Seq="1" Y="0" X="-3.46"/>
<Vtx Seq="2" Y="13.449" X="-3.46"/>
<Vtx Seq="3" Y="14.019" X="0"/>
<Vtx Seq="4" Y="13.449" X="3.46"/>
<Vtx Seq="5" Y="0" X="3.46"/>
</Vertices>
<Catamaran>
<Vtx Seq="1" Y="1.769" X="-2.752"/>
<Vtx Seq="2" Y="0" X="-2.813"/>
<Vtx Seq="3" Y="0" X="-3.34"/>
<Vtx Seq="4" Y="5.351" X="-3.46"/>
<Vtx Seq="5" Y="10.544" X="-3.387"/>
<Vtx Seq="6" Y="13.449" X="-3.075"/>
<Vtx Seq="7" Y="10.851" X="-2.793"/>
<Vtx Seq="8" Y="6.669" X="-2.699"/>
<Vtx Seq="9" Y="6.669" X="2.699"/>
<Vtx Seq="10" Y="10.851" X="2.793"/>
<Vtx Seq="11" Y="13.449" X="3.075"/>
<Vtx Seq="12" Y="10.544" X="3.387"/>
<Vtx Seq="13" Y="5.351" X="3.46"/>
<Vtx Seq="14" Y="0" X="3.34"/>
<Vtx Seq="15" Y="0" X="2.813"/>
<Vtx Seq="16" Y="1.769" X="2.752"/>
</Catamaran>
<Bowsprit>
<Vtx Seq="1" Y="6.669" X="-0.2"/>
<Vtx Seq="2" Y="11.377" X="-0.2"/>
<Vtx Seq="3" Y="14.019" X="0"/>
<Vtx Seq="4" Y="11.377" X="0.2"/>
<Vtx Seq="5" Y="6.669" X="0.2"/>
</Bowsprit>
<Trampoline>
<Vtx Seq="1" Y="2" X="-2.699"/>
<Vtx Seq="2" Y="6.438" X="-2.699"/>
<Vtx Seq="3" Y="6.438" X="2.699"/>
<Vtx Seq="4" Y="2" X="2.699"/>
</Trampoline>
</BoatShape>
<BoatShape ShapeID="18">
<Vertices>
<Vtx Seq="1" Y="0" X="-1.04"/>
<Vtx Seq="2" Y="0.11" X="-1.18"/>
<Vtx Seq="3" Y="0.42" X="-1.28"/>
<Vtx Seq="4" Y="3.74" X="-1.29"/>
<Vtx Seq="5" Y="5.36" X="-1.21"/>
<Vtx Seq="6" Y="6.29" X="-1.08"/>
<Vtx Seq="7" Y="7.15" X="-0.84"/>
<Vtx Seq="8" Y="7.63" X="-0.62"/>
<Vtx Seq="9" Y="7.94" X="-0.34"/>
<Vtx Seq="10" Y="8.06" X="0"/>
<Vtx Seq="11" Y="7.94" X="0.34"/>
<Vtx Seq="12" Y="7.63" X="0.62"/>
<Vtx Seq="13" Y="7.15" X="0.84"/>
<Vtx Seq="14" Y="6.29" X="1.08"/>
<Vtx Seq="15" Y="5.36" X="1.21"/>
<Vtx Seq="16" Y="3.74" X="1.29"/>
<Vtx Seq="17" Y="0.42" X="1.28"/>
<Vtx Seq="18" Y="0.11" X="1.18"/>
<Vtx Seq="19" Y="0" X="1.04"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="24">
<Vertices>
<Vtx Seq="1" Y="0" X="-2.5"/>
<Vtx Seq="2" Y="7" X="-2.5"/>
<Vtx Seq="3" Y="12.6" X="-2.2"/>
<Vtx Seq="4" Y="12.6" X="2.2"/>
<Vtx Seq="5" Y="7" X="2.5"/>
<Vtx Seq="6" Y="0" X="2.5"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="34">
<Vertices>
<Vtx Seq="1" Y="0" X="-1.16"/>
<Vtx Seq="2" Y="5.51" X="-1.16"/>
<Vtx Seq="3" Y="5.846" X="-0.84"/>
<Vtx Seq="4" Y="5.846" X="0.84"/>
<Vtx Seq="5" Y="5.51" X="1.16"/>
<Vtx Seq="6" Y="0" X="1.16"/>
</Vertices>
</BoatShape>
<BoatShape ShapeID="35">
<Vertices>
<Vtx Seq="1" Y="0" X="-1.461"/>
<Vtx Seq="2" Y="6" X="-1.461"/>
<Vtx Seq="3" Y="7" X="-1.44"/>
<Vtx Seq="4" Y="8" X="-1.38"/>
<Vtx Seq="5" Y="9" X="-1.17"/>
<Vtx Seq="6" Y="10" X="-0.76"/>
<Vtx Seq="7" Y="10.6" X="-0.34"/>
<Vtx Seq="8" Y="10.61" X="0"/>
<Vtx Seq="9" Y="10.6" X="0.34"/>
<Vtx Seq="10" Y="10" X="0.76"/>
<Vtx Seq="11" Y="9" X="1.17"/>
<Vtx Seq="12" Y="8" X="1.38"/>
<Vtx Seq="13" Y="7" X="1.44"/>
<Vtx Seq="14" Y="6" X="1.461"/>
<Vtx Seq="15" Y="0" X="1.461"/>
</Vertices>
</BoatShape>
</BoatShapes>
<Boats>
<Boat Type="Yacht" SourceID="101" ShapeID="15" StoweName="USA" ShortName="ORACLE" ShorterName="USA" BoatName="ORACLE TEAM USA" HullNum="AC4515" Skipper="SPITHILL" Helmsman="SPITHILL" Country="USA" PeliID="101" RadioIP="172.20.2.101">
<GPSposition Z="1.78" Y="-0.331" X="-0.006"/>
<MastTop Z="21.496" Y="3.7" X="0"/>
<FlagPosition Z="0" Y="6.2" X="0"/>
</Boat>
<Boat Type="Yacht" SourceID="102" ShapeID="15" StoweName="SWE" ShortName="ARTEMIS" ShorterName="SWE" BoatName="ARTEMIS RACING" HullNum="AC4517" Skipper="OUTTERIDGE" Helmsman="OUTTERIDGE" Country="SWE" PeliID="102" RadioIP="172.20.2.102">
<GPSposition Z="1.727" Y="-0.359" X="-0.0121"/>
<MastTop Z="21.496" Y="3.7" X="0"/>
<FlagPosition Z="0" Y="6.2" X="0"/>
</Boat>
<Boat Type="Yacht" SourceID="103" ShapeID="15" StoweName="NZL" ShortName="ETNZ" ShorterName="NZL" BoatName="EMIRATES TEAM NZ" HullNum="AC4503" Skipper="ASHBY" Helmsman="BURLING" Country="NZL" PeliID="103" RadioIP="172.20.2.103">
<GPSposition Z="1.881" Y="-0.291" X="-0.003"/>
<MastTop Z="21.496" Y="3.7" X="0"/>
<FlagPosition Z="0" Y="6.2" X="0"/>
</Boat>
<Boat Type="Yacht" SourceID="104" ShapeID="15" StoweName="JPN" ShortName="JAPAN" ShorterName="JPN" BoatName="SOFTBANK TEAM JAPAN" HullNum="AC4504" Skipper="BARKER" Helmsman="BARKER" Country="JPN" PeliID="104" RadioIP="172.20.2.104">
<GPSposition Z="1.805" Y="-0.322" X="-0.003"/>
<MastTop Z="21.496" Y="3.7" X="0"/>
<FlagPosition Z="0" Y="6.2" X="0"/>
</Boat>
<Boat Type="Yacht" SourceID="105" ShapeID="15" StoweName="FRA" ShortName="FRANCE" ShorterName="FRA" BoatName="GROUPAMA TEAM FRANCE" HullNum="AC4505" Skipper="CAMMAS" Helmsman="CAMMAS" Country="FRA" PeliID="105" RadioIP="172.20.2.105">
<GPSposition Z="1.863" Y="-0.3" X="-0.003"/>
<MastTop Z="21.496" Y="3.7" X="0"/>
<FlagPosition Z="0" Y="6.2" X="0"/>
</Boat>
<Boat Type="Yacht" SourceID="106" ShapeID="15" StoweName="GBR" ShortName="GBR" ShorterName="GBR" BoatName="LAND ROVER BAR" HullNum="AC4516" Skipper="ANSLIE" Helmsman="ANSLIE" Country="GBR" PeliID="106" RadioIP="172.20.2.106">
<GPSposition Z="1.734" Y="-0.352" X="0"/>
<MastTop Z="21.496" Y="3.7" X="0"/>
<FlagPosition Z="0" Y="6.2" X="0"/>
</Boat>
</Boats>
</BoatConfig>
@@ -1,105 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Race>
<CreationTimeDate>2015-08-29T13:12:40+02:00</CreationTimeDate>
<RaceStartTime Start="2015-08-29T13:10:00+02:00" Postpone="False"/>
<RaceID>15082901</RaceID>
<RaceType>Fleet</RaceType>
<Participants>
<Yacht SourceID="101"/>
<Yacht SourceID="102"/>
<Yacht SourceID="103"/>
<Yacht SourceID="104"/>
<Yacht SourceID="105"/>
<Yacht SourceID="106"/>
</Participants>
<Course>
<CompoundMark CompoundMarkID="1" Name="Mark0">
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.6703330" TargetLng="11.8278330"
SourceID="122"/>
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.6703330" TargetLng="11.8278330"
SourceID="123"/>
</CompoundMark>
<CompoundMark CompoundMarkID="2" Name="Mark1">
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131"/>
</CompoundMark>
<CompoundMark CompoundMarkID="3" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="4" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="5" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="6" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="7" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="8" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="9" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="124"/>
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.6708220" TargetLng="11.8433900"
SourceID="125"/>
</CompoundMark>
<CompoundMark CompoundMarkID="10" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="126"/>
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.6650170" TargetLng="11.8279170"
SourceID="127"/>
</CompoundMark>
<CompoundMark CompoundMarkID="11" Name="Mark4">
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.6715240" TargetLng="11.8444950"
SourceID="128"/>
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950"
SourceID="129"/>
</CompoundMark>
</Course>
<CompoundMarkSequence>
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3"/>
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="5" CompoundMarkID="5" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="6" CompoundMarkID="6" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="7" CompoundMarkID="7" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="8" CompoundMarkID="8" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="9" CompoundMarkID="9" Rounding="SP" ZoneSize="3"/>
<Corner SeqID="10" CompoundMarkID="10" Rounding="PS" ZoneSize="3"/>
<Corner SeqID="11" CompoundMarkID="11" Rounding="PS" ZoneSize="3"/>
</CompoundMarkSequence>
<CourseLimit>
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100"/>
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010"/>
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790"/>
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610"/>
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910"/>
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840"/>
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030"/>
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660"/>
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920"/>
<Limit SeqID="10" Lat="57.6708220" Lon="11.8321340"/>
</CourseLimit>
</Race>
@@ -4,62 +4,39 @@
<RaceStartTime Start="${raceStartTime}" Postpone="False" /> <RaceStartTime Start="${raceStartTime}" Postpone="False" />
<RaceID>15082901</RaceID> <RaceID>15082901</RaceID>
<RaceType>Fleet</RaceType> <RaceType>Fleet</RaceType>
<Participants>
<Participants MaxPlayers="${maxPlayers}">
<#list boats as boat> <#list boats as boat>
<Yacht SourceID="${boat.sourceId}"/> <Yacht SourceID="${boat.sourceId}"/>
</#list> </#list>
</Participants> </Participants>
<Tokens>
<Tokens Enabled="${tokensEnabled}">
<#list tokens as token> <#list tokens as token>
<Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/> <Token TokenType="${token.tokenType}" TargetLat="${token.lat?c}" TargetLng="${token.lng?c}"/>
</#list> </#list>
</Tokens> </Tokens>
<Course> <Course>
<CompoundMark CompoundMarkID="1" Name="Mark0"> <#list compoundMarks as compoundMark>
<Mark SeqID="1" Name="Start Line 1" TargetLat="57.670603" TargetLng="11.828262" SourceID="122" /> <CompoundMark CompoundMarkID="${compoundMark.id?c}" Name="${compoundMark.name}">
<Mark SeqID="2" Name="Start Line 2" TargetLat="57.669445" TargetLng="11.826413" SourceID="123" /> <#list compoundMark.marks as mark>
</CompoundMark> <Mark SeqID="${mark.seqID?c}" Name="${mark.name}" TargetLat="${mark.lat?c}" TargetLng="${mark.lng?c}" SourceID="${mark.sourceID?c}" />
<CompoundMark CompoundMarkID="2" Name="Mark1"> </#list>
<Mark SeqID="1" Name="Mark1" TargetLat="57.6675700" TargetLng="11.8359880" SourceID="131" /> </CompoundMark>
</CompoundMark> </#list>
<CompoundMark CompoundMarkID="3" Name="Mark2">
<Mark SeqID="1" Name="Lee Gate 1" TargetLat="57.6708220" TargetLng="11.8433900" SourceID="124" />
<Mark SeqID="2" Name="Lee Gate 2" TargetLat="57.671629" TargetLng="11.840951" SourceID="125" />
</CompoundMark>
<CompoundMark CompoundMarkID="4" Name="Mark3">
<Mark SeqID="1" Name="Wind Gate 1" TargetLat="57.664190" TargetLng="11.829576" SourceID="126" />
<Mark SeqID="2" Name="Wind Gate 2" TargetLat="57.665316" TargetLng="11.827184" SourceID="127" />
</CompoundMark>
<CompoundMark CompoundMarkID="5" Name="Mark4">
<Mark SeqID="1" Name="Finish Line 1" TargetLat="57.672350" TargetLng="11.842535" SourceID="128" />
<Mark SeqID="2" Name="Finish Line 2" TargetLat="57.6715240" TargetLng="11.8444950" SourceID="129" />
</CompoundMark>
</Course> </Course>
<CompoundMarkSequence> <CompoundMarkSequence>
<Corner SeqID="1" CompoundMarkID="1" Rounding="PS" ZoneSize="3" /> <#list roundings as corner>
<Corner SeqID="2" CompoundMarkID="2" Rounding="Port" ZoneSize="3" /> <Corner SeqID="${corner.seqID?c}" CompoundMarkID="${corner.compoundMarkID?c}" Rounding="${corner.rounding}" ZoneSize="${corner.zoneSize?c}" />
<Corner SeqID="3" CompoundMarkID="3" Rounding="SP" ZoneSize="3" /> </#list>
<Corner SeqID="4" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
<Corner SeqID="5" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
<Corner SeqID="6" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
<Corner SeqID="7" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
<Corner SeqID="8" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
<Corner SeqID="9" CompoundMarkID="3" Rounding="SP" ZoneSize="3" />
<Corner SeqID="10" CompoundMarkID="4" Rounding="PS" ZoneSize="3" />
<Corner SeqID="11" CompoundMarkID="5" Rounding="PS" ZoneSize="3" />
</CompoundMarkSequence> </CompoundMarkSequence>
<CourseLimit> <CourseLimit>
<Limit SeqID="1" Lat="57.6739450" Lon="11.8417100" /> <#list courseLimit as limit>
<Limit SeqID="2" Lat="57.6709520" Lon="11.8485010" /> <Limit SeqID="${limit.seqID?c}" Lat="${limit.lat?c}" Lon="${limit.lng?c}" />
<Limit SeqID="3" Lat="57.6690260" Lon="11.8472790" /> </#list>
<Limit SeqID="4" Lat="57.6693140" Lon="11.8457610" />
<Limit SeqID="5" Lat="57.6665370" Lon="11.8432910" />
<Limit SeqID="6" Lat="57.6641400" Lon="11.8385840" />
<Limit SeqID="7" Lat="57.6629430" Lon="11.8332030" />
<Limit SeqID="8" Lat="57.6629480" Lon="11.8249660" />
<Limit SeqID="9" Lat="57.6686890" Lon="11.8250920" />
<Limit SeqID="10" Lat="57.6692230" Lon="11.8231430" />
<Limit SeqID="11" Lat="57.6725370" Lon="11.8272480" />
<Limit SeqID="12" Lat="57.6708220" Lon="11.8321340" />
</CourseLimit> </CourseLimit>
</Race> </Race>
+15 -13
View File
@@ -5,14 +5,15 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.ScrollPane?> <?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.StackPane?> <?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
<StackPane fx:id="serverListMainStackPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.LobbyController">
<children> <children>
<GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"> <GridPane fx:id="serverListMainGridPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308">
<children> <children>
@@ -37,8 +38,7 @@
</GridPane> </GridPane>
<GridPane> <GridPane>
<children> <children>
<Label fx:id="serverName" text="Party Parrots In Space" <Label fx:id="serverName" text="Party Parrots In Space" GridPane.valignment="CENTER">
GridPane.valignment="CENTER">
<font> <font>
<Font size="31.0" /> <Font size="31.0" />
</font> </font>
@@ -46,8 +46,7 @@
<Insets left="35.0" top="10.0" /> <Insets left="35.0" top="10.0" />
</padding> </padding>
</Label> </Label>
<Label fx:id="mapName" text="This is a map, it's called Haoming" <Label fx:id="mapName" text="This is a map, it's called Haoming" GridPane.rowIndex="1">
GridPane.rowIndex="1">
<padding> <padding>
<Insets left="35.0" top="-15.0" /> <Insets left="35.0" top="-15.0" />
</padding> </padding>
@@ -73,17 +72,20 @@
<children> <children>
<ScrollPane fx:id="playerListScrollPane" hbarPolicy="NEVER" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <ScrollPane fx:id="playerListScrollPane" hbarPolicy="NEVER" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<content> <content>
<VBox fx:id="playerListVBox" prefHeight="200.0" prefWidth="100.0"/> <VBox fx:id="playerListVBox" prefHeight="200.0" prefWidth="100.0" />
</content> </content>
<GridPane.margin> <GridPane.margin>
<Insets bottom="15.0" left="7.0" right="15.0" top="15.0" /> <Insets bottom="15.0" left="7.0" right="15.0" top="15.0" />
</GridPane.margin> </GridPane.margin>
</ScrollPane> </ScrollPane>
<Pane fx:id="serverMap" style="-fx-background-color: skyblue;"> <AnchorPane fx:id="serverMap" style="-fx-background-color: skyblue;">
<GridPane.margin> <opaqueInsets>
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" /> <Insets />
</GridPane.margin> </opaqueInsets>
</Pane> <GridPane.margin>
<Insets bottom="15.0" left="15.0" right="7.0" top="15.0" />
</GridPane.margin>
</AnchorPane>
</children> </children>
</GridPane> </GridPane>
</children> </children>
@@ -96,7 +98,7 @@
<RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" /> <RowConstraints maxHeight="80.0" minHeight="80.0" prefHeight="80.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<stylesheets> <stylesheets>
<String fx:value="/css/Master.css"/> <String fx:value="/css/Master.css" />
<String fx:value="/css/LobbyView.css" /> <String fx:value="/css/LobbyView.css" />
</stylesheets> </stylesheets>
</GridPane> </GridPane>
-65
View File
@@ -1,14 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.*?>
<?import javafx.scene.shape.*?>
<?import com.jfoenix.controls.*?>
<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import com.jfoenix.controls.JFXButton?> <?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.lang.String?> <?import java.lang.String?>
@@ -233,62 +224,6 @@
<Insets bottom="10.0" left="10.0" top="40.0"/> <Insets bottom="10.0" left="10.0" top="40.0"/>
</GridPane.margin> </GridPane.margin>
</GridPane> </GridPane>
<GridPane GridPane.columnIndex="1" GridPane.rowIndex="2">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="152.0"
vgrow="SOMETIMES"/>
<RowConstraints maxHeight="118.0" minHeight="10.0" prefHeight="98.0"
vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<ImageView fx:id="velocityIcon" fitHeight="88.0" fitWidth="106.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.halignment="CENTER" GridPane.rowIndex="1">
<image>
<Image url="@../icons/velocity.png"/>
</image>
</ImageView>
<ImageView fx:id="handlingIcon" fitHeight="87.0" fitWidth="98.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="1" GridPane.halignment="CENTER"
GridPane.rowIndex="1">
<image>
<Image url="@../icons/handlingIcon.png"/>
</image>
</ImageView>
<ImageView fx:id="windWalkerIcon" fitHeight="83.0" fitWidth="100.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="2" GridPane.halignment="CENTER"
GridPane.rowIndex="1">
<image>
<Image url="@../icons/windWalkerIcon.png"/>
</image>
</ImageView>
<ImageView fx:id="bumperIcon" fitHeight="83.0" fitWidth="88.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="3" GridPane.halignment="CENTER"
GridPane.rowIndex="1">
<image>
<Image url="@../icons/bumperIcon.png"/>
</image>
</ImageView>
<ImageView fx:id="badRandomIcon" fitHeight="69.0" fitWidth="103.0"
pickOnBounds="true" preserveRatio="true" visible="false"
GridPane.columnIndex="4" GridPane.halignment="CENTER"
GridPane.rowIndex="1" GridPane.valignment="CENTER">
<image>
<Image url="@../icons/ayy_lmao.gif"/>
</image>
</ImageView>
</children>
</GridPane>
</children> </children>
</GridPane> </GridPane>
</children> </children>
@@ -1,75 +1,178 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXButton?> <?import com.jfoenix.controls.JFXButton?>
<?import com.jfoenix.controls.JFXCheckBox?>
<?import com.jfoenix.controls.JFXDialogLayout?> <?import com.jfoenix.controls.JFXDialogLayout?>
<?import com.jfoenix.controls.JFXSlider?> <?import com.jfoenix.controls.JFXSlider?>
<?import com.jfoenix.controls.JFXTextField?> <?import com.jfoenix.controls.JFXTextField?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?> <?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" <JFXDialogLayout maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/8.0.112" xmlns:fx="http://javafx.com/fxml/1" fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController">
minWidth="-Infinity" prefWidth="550.0" xmlns="http://javafx.com/javafx/8.0.111" <children>
xmlns:fx="http://javafx.com/fxml/1" <GridPane>
fx:controller="seng302.visualiser.controllers.dialogs.ServerCreationController"> <children>
<children> <JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="SUBMIT" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER">
<GridPane> <font>
<columnConstraints> <Font name="System Bold" size="13.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> </font></JFXButton>
</columnConstraints> <GridPane GridPane.rowIndex="1">
<rowConstraints>
<RowConstraints maxHeight="90.0" minHeight="90.0" prefHeight="90.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label fx:id="hostDialogHeader" text="HOST A GAME SERVER" GridPane.halignment="CENTER" GridPane.valignment="CENTER" />
<JFXButton fx:id="submitBtn" onMouseEntered="#playButtonHoverSound" prefHeight="55.0" prefWidth="250.0" text="SUBMIT" GridPane.halignment="CENTER" GridPane.rowIndex="3" GridPane.valignment="CENTER" />
<JFXTextField fx:id="serverName" promptText="SERVER NAME" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="30.0" right="30.0" />
</GridPane.margin></JFXTextField>
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="2">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints> </columnConstraints>
<rowConstraints> <rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints> </rowConstraints>
<children> <children>
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP"> <GridPane>
<GridPane.margin> <columnConstraints>
<Insets right="30.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</GridPane.margin></Label> </columnConstraints>
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM"> <rowConstraints>
<GridPane.margin> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<Insets left="30.0" top="20.0" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</GridPane.margin> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</Label> </rowConstraints>
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER"> <children>
<children> <JFXTextField fx:id="serverName" promptText="SERVER NAME">
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" /> <padding>
</children> <Insets left="15.0" right="15.0" />
<GridPane.margin> </padding>
<Insets bottom="10.0" right="30.0" /> <GridPane.margin>
</GridPane.margin> <Insets left="35.0" right="35.0" />
</VBox> </GridPane.margin>
</JFXTextField>
<GridPane fx:id="maxPlayersGridPane" GridPane.rowIndex="1">
<children>
<Label fx:id="maxPlayersLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
<GridPane.margin>
<Insets right="30.0" />
</GridPane.margin>
</Label>
<Label fx:id="maxPlayerPromptLabel" text="MAX PLAYERS" GridPane.halignment="LEFT" GridPane.valignment="BOTTOM">
<GridPane.margin>
<Insets left="30.0" top="20.0" />
</GridPane.margin>
</Label>
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<children>
<JFXSlider fx:id="maxPlayersSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
</children>
<GridPane.margin>
<Insets bottom="10.0" right="30.0" />
</GridPane.margin>
</VBox>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
<GridPane fx:id="maxPlayersGridPane1" GridPane.rowIndex="2">
<children>
<Label fx:id="legsSliderLabel" text="20" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.rowIndex="1" GridPane.valignment="TOP">
<GridPane.margin>
<Insets right="30.0" />
</GridPane.margin>
</Label>
<VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<children>
<JFXSlider fx:id="legsSlider" blockIncrement="1.0" majorTickUnit="2.0" max="20.0" min="1.0" minorTickCount="1" snapToTicks="true" styleClass="maxPlayers" value="11.0" />
</children>
<GridPane.margin>
<Insets bottom="10.0" right="30.0" />
</GridPane.margin>
</VBox>
<GridPane>
<children>
<Label alignment="CENTER" text="NUMBER OF" GridPane.halignment="CENTER" />
<Label alignment="CENTER" text="REPEATING LEGS" GridPane.halignment="CENTER" GridPane.rowIndex="1" />
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
<JFXCheckBox fx:id="pickupsCheckBox" text="Enable Pickups" GridPane.rowIndex="1">
<GridPane.margin>
<Insets left="5.0" />
</GridPane.margin>
</JFXCheckBox>
</children>
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" percentWidth="30.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="100.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" percentHeight="60.0" prefHeight="10.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" percentHeight="40.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</children>
</GridPane>
<GridPane GridPane.columnIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="35.0" prefWidth="35.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="35.0" minWidth="35.0" prefWidth="35.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<JFXButton fx:id="lastMapButton" maxHeight="300.0" minHeight="300.0" prefHeight="300.0" prefWidth="35.0" style="-fx-border-color: lightgrey; -fx-border-radius: 5;" text="&lt;" textFill="#5b5b5b" GridPane.halignment="CENTER" GridPane.valignment="CENTER">
<font>
<Font name="System Bold" size="13.0" />
</font></JFXButton>
<JFXButton fx:id="nextMapButton" maxHeight="300.0" minHeight="300.0" minWidth="35.0" prefHeight="300.0" style="-fx-border-color: lightgrey; -fx-border-radius: 5;" text="&gt;" textFill="#5b5b5b" GridPane.columnIndex="2" GridPane.valignment="CENTER">
<font>
<Font name="System Bold" size="13.0" />
</font></JFXButton>
<GridPane style="-fx-background-color: lightblue; -fx-border-color: grey; -fx-border-radius: 5; -fx-background-radius: 5;" GridPane.columnIndex="1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="25.0" minHeight="25.0" prefHeight="25.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="342.0" minHeight="10.0" prefHeight="336.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label fx:id="mapNameLabel" text="MAP NAME" GridPane.halignment="CENTER" />
<AnchorPane fx:id="mapHolder" prefHeight="333.0" prefWidth="404.0" GridPane.rowIndex="1" />
</children>
</GridPane>
</children>
</GridPane>
</children> </children>
</GridPane> </GridPane>
<Label fx:id="closeLabel" text="✖" GridPane.halignment="RIGHT" <Label fx:id="hostDialogHeader" text="HOST A GAME SERVER" GridPane.halignment="CENTER">
GridPane.valignment="TOP"/> <font>
</children> <Font size="20.0" />
</GridPane> </font></Label>
</children> </children>
<stylesheets> <columnConstraints>
<URL value="@../../css/dialogs/ServerCreation.css"/> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<URL value="@../../css/Master.css"/> </columnConstraints>
</stylesheets> <rowConstraints>
<RowConstraints maxHeight="100.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="511.0" minHeight="90.0" prefHeight="370.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="102.0" minHeight="100.0" prefHeight="100.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</children>
</JFXDialogLayout> </JFXDialogLayout>
+17
View File
@@ -0,0 +1,17 @@
Feature: Multiple Maps
Scenario:
Given that the game has multiple race xml files
Then all of them can be seen
Scenario:
Given that I choose a race
Then that race's course is received by clients
Scenario:
Given that I choose a name for the server
Then that name is sent to the client
Scenario:
Given that the client has received a race
Then the name of that race shown to the host is the course name
@@ -31,7 +31,7 @@ public class ChatCommandsTest {
} }
try { try {
dcSent = false; dcSent = false;
new GameState("localhost"); new GameState();
mst = new MainServerThread(); mst = new MainServerThread();
host = new ClientToServerThread("localhost", 4942); host = new ClientToServerThread("localhost", 4942);
host.addStreamObserver(() -> { host.addStreamObserver(() -> {
@@ -85,7 +85,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
new GameState("localhost"); new GameState();
mst = new MainServerThread(); mst = new MainServerThread();
host = null; host = null;
try { try {
@@ -110,7 +110,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
Assert.assertEquals(5.0, GameState.getServerSpeedMultiplier(), 0.00001); Assert.assertEquals(5.0, GameState.getSpeedMultiplier(), 0.00001);
mst.terminate(); mst.terminate();
try { try {
Thread.sleep(200); Thread.sleep(200);
@@ -129,7 +129,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
new GameState("localhost"); new GameState();
mst = new MainServerThread(); mst = new MainServerThread();
host = null; host = null;
try { try {
@@ -150,7 +150,7 @@ public class ChatCommandsTest {
ie.printStackTrace(); ie.printStackTrace();
} }
mst.terminate(); mst.terminate();
Assert.assertEquals(1.0, GameState.getServerSpeedMultiplier(), 0.00001); Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
try { try {
Thread.sleep(2000); Thread.sleep(2000);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
@@ -194,7 +194,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
Assert.assertEquals(1.0, GameState.getServerSpeedMultiplier(), 0.00001); Assert.assertEquals(1.0, GameState.getSpeedMultiplier(), 0.00001);
mst.terminate(); mst.terminate();
host.setSocketToClose(); host.setSocketToClose();
client.setSocketToClose(); client.setSocketToClose();
@@ -212,7 +212,7 @@ public class ChatCommandsTest {
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
ie.printStackTrace(); ie.printStackTrace();
} }
new GameState("localhost"); new GameState();
dcSent = false; dcSent = false;
mst = new MainServerThread(); mst = new MainServerThread();
host = null; host = null;
@@ -1,5 +1,7 @@
package seng302.model; package seng302.model;
import static seng302.gameServer.GameState.checkCollision;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -7,8 +9,6 @@ import seng302.gameServer.GameState;
import seng302.utilities.GeoUtility; import seng302.utilities.GeoUtility;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import static seng302.gameServer.GameState.checkCollision;
/** /**
* Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0 * Test update function in Yacht.java to make sure yacht will not be collide each other within 25.0
* meters. * meters.
@@ -24,10 +24,10 @@ public class UpdateYachtTest {
@Before @Before
public void setUpRace() { public void setUpRace() {
new GameState(""); new GameState();
GameState.addYacht(1, yacht1); GameState.addYacht(1, yacht1);
GameState.addYacht(2, yacht2); GameState.addYacht(2, yacht2);
PolarTable.parsePolarFile(getClass().getResourceAsStream("/config/acc_polars.csv")); PolarTable.parsePolarFile(getClass().getResourceAsStream("/server_config/acc_polars.csv"));
} }
@Test @Test
@@ -4,11 +4,21 @@ import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse; import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue; import static junit.framework.TestCase.assertTrue;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import seng302.model.mark.CompoundMark; import seng302.model.mark.CompoundMark;
import seng302.model.mark.MarkOrder; import seng302.model.mark.MarkOrder;
import seng302.utilities.XMLGenerator;
import seng302.utilities.XMLParser;
public class MarkOrderTest { public class MarkOrderTest {
private static MarkOrder markOrder; private static MarkOrder markOrder;
@@ -16,7 +26,37 @@ public class MarkOrderTest {
@BeforeClass @BeforeClass
public static void setup(){ public static void setup(){
markOrder = new MarkOrder(); /*
%%%%%%
%%%% = =
%%C >
_)' _( .' ,
__/ |_/\ " *. o
/` \_\ \/ %`= '_ .
/ ) \/| .^',*. ,
/' /- o/ - " % '_
/\_/ < = , ^ ~ .
)_o|----'| .` '
___// (_ - (\
///-( \' \\
*/
XMLGenerator xmlGenerator = new XMLGenerator();
xmlGenerator.setRaceTemplate(
XMLParser.parseRaceDef(
"/maps/default.xml", "test", 2, null, false
).getValue()
);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
Document doc = null;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(xmlGenerator.getRaceAsXml())));
} catch (ParserConfigurationException | IOException | SAXException e) {
e.printStackTrace();
}
markOrder = new MarkOrder(XMLParser.parseRace(doc));
currentSeqID = 0; currentSeqID = 0;
} }
+3 -2
View File
@@ -5,6 +5,7 @@ import org.junit.BeforeClass;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.model.ServerYacht; import seng302.model.ServerYacht;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType; import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
import seng302.visualiser.fxObjects.assets_3D.BoatMeshType;
public class YachtTest { public class YachtTest {
@@ -17,9 +18,9 @@ public class YachtTest {
@BeforeClass @BeforeClass
public static void setUp() { public static void setUp() {
new GameState("localhost"); new GameState();
y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1"); y1 = new ServerYacht(BoatMeshType.DINGHY, 1, "Y1", "Y1", "Yacht 1", "C1");
gs = new GameState("localhost"); gs = new GameState();
} }
//Commented out until can fix the weird non-deterministic bug. //Commented out until can fix the weird non-deterministic bug.
@@ -1,50 +0,0 @@
package seng302.utilities;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import seng302.model.GeoPoint;
import seng302.model.mark.CompoundMark;
import seng302.model.mark.Mark;
import seng302.model.token.Token;
/**
* Created by wmu16 on 27/09/17.
*/
public class RandomSpawnTest {
private RandomSpawn randomSpawn;
Mark mark1 = new Mark("mark1", 0, 57.670333, 11.827833, 0);
Mark mark2 = new Mark("mark2", 1, 57.671829, 11.842049, 1);
CompoundMark compoundMark1 = new CompoundMark(0, "mark1",
new ArrayList<>(Arrays.asList(mark1)));
CompoundMark compoundMark2 = new CompoundMark(0, "mark1",
new ArrayList<>(Arrays.asList(mark2)));
List<CompoundMark> markOrder = new ArrayList<>(Arrays.asList(compoundMark1, compoundMark2));
@Before
public void setup() {
randomSpawn = new RandomSpawn(markOrder);
}
@Test
public void testGetRandomTokenLocation() {
GeoPoint testMidPoint = GeoUtility
.getDirtyMidPoint(compoundMark1.getMidPoint(), compoundMark2.getMidPoint());
Double maxDistance = GeoUtility.getDistance(testMidPoint, compoundMark2.getMidPoint());
for (int i = 0; i < 1000; i++) {
Token token = randomSpawn.getRandomTokenLocation();
Double distanceFromCentreRadius = GeoUtility.getDistance(testMidPoint, token);
assertTrue("Out of bounds token", distanceFromCentreRadius <= maxDistance);
}
}
}
@@ -1,15 +1,11 @@
package seng302.visualiser.ClientToServerTests; package seng302.visualiser.ClientToServerTests;
import java.util.ArrayList;
import org.junit.After; import org.junit.After;
import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import seng302.gameServer.GameStages; import seng302.gameServer.GameStages;
import seng302.gameServer.GameState; import seng302.gameServer.GameState;
import seng302.gameServer.MainServerThread; import seng302.gameServer.MainServerThread;
import seng302.gameServer.messages.BoatAction;
import seng302.model.ServerYacht;
import seng302.visualiser.ClientToServerThread; import seng302.visualiser.ClientToServerThread;
/** /**
@@ -22,7 +18,7 @@ public class RegularPacketsTest {
@Before @Before
public void setup() throws Exception { public void setup() throws Exception {
new GameState("localhost"); new GameState();
serverThread = new MainServerThread(); serverThread = new MainServerThread();
clientThread = new ClientToServerThread("localhost", 4942); clientThread = new ClientToServerThread("localhost", 4942);
GameState.setCurrentStage(GameStages.RACING); GameState.setCurrentStage(GameStages.RACING);
+69
View File
@@ -0,0 +1,69 @@
package steps;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import java.io.File;
import org.junit.Assert;
import seng302.visualiser.MapMaker;
/**
* Created by cir27 on 26/09/17.
*/
public class CustomMapsSteps {
MapMaker mapMaker;
@Given("^that the game has multiple race xml files$")
public void that_the_game_has_multiple_race_xml_files() throws Throwable {
mapMaker = MapMaker.getInstance();
String firstMap = mapMaker.getCurrentRacePath();
int numMaps = 0;
do {
mapMaker.next();
numMaps++;
} while (!mapMaker.getCurrentRacePath().equals(firstMap));
Assert.assertTrue(numMaps >= 2);
}
@Then("^all of them can be seen$")
public void all_of_them_can_be_seen() throws Throwable {
File[] files = new File(this.getClass().getResource("/maps/").getPath()).listFiles();
for (File file : files) {
if (file.isFile()) {
Assert.assertTrue(file.getAbsolutePath().equals(mapMaker.getCurrentRacePath()));
mapMaker.next();
System.out.println(file.getAbsolutePath());
}
}
}
@Given("^that I choose a race$")
public void that_I_choose_a_race() throws Throwable {
}
@Then("^that race's course is received by clients$")
public void that_race_s_course_is_received_by_clients() throws Throwable {
}
@Given("^that I choose a name for the server$")
public void that_I_choose_a_name_for_the_server() throws Throwable {
}
@Then("^that name is sent to the client$")
public void that_name_is_sent_to_the_client() throws Throwable {
}
@Given("^that the client has received a race$")
public void that_the_client_has_received_a_race() throws Throwable {
}
@Then("^the name of that race shown to the host is the course name$")
public void the_name_of_that_race_shown_to_the_host_is_the_course_name() throws Throwable {
}
}