1package com.fs.starfarer.api.impl.campaign.velfield;
4import java.util.ArrayList;
6import java.util.Random;
8import org.lwjgl.opengl.GL11;
9import org.lwjgl.util.vector.Vector2f;
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamParams2;
13import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamSegment;
14import com.fs.starfarer.api.util.Misc;
15import com.fs.starfarer.api.util.WeightedRandomPicker;
19 public static enum StreamType {
87 if (
type == StreamType.NORMAL) {
92 }
else if (
type == StreamType.WIDE) {
97 }
else if (
type == StreamType.NARROW) {
123 public static class SlipstreamSection {
124 public Vector2f from =
new Vector2f();
125 public Vector2f to =
new Vector2f();
126 public Vector2f control =
new Vector2f();
133 public boolean subdivision =
false;
134 public float approxCurveLength;
137 public static class AddedSegment {
138 public SlipstreamSegment segment;
140 public Vector2f perp;
151 protected List<SlipstreamSection>
sections =
new ArrayList<SlipstreamSection>();
163 this.type =
type !=
null ?
type : StreamType.NORMAL;
170 for (
int i = 0; i < 10; i++) {
192 Vector2f p0 =
new Vector2f(
start);
193 Vector2f p1 =
new Vector2f(control);
194 Vector2f p2 =
new Vector2f(control2);
195 Vector2f p3 =
new Vector2f(to);
200 Vector2f prev =
new Vector2f(p0);
202 float length = 3000f +
random.nextInt(2000);
203 float tIncr = length / len;
212 if (wide) angle *= 0.5f;
213 if (t >= 1f) angle = 0f;
217 if (actualDist > length * 0.5f) {
229 Vector2f p0 =
new Vector2f(
start);
230 Vector2f p1 =
new Vector2f(control);
231 Vector2f p2 =
new Vector2f(to);
236 Vector2f prev =
new Vector2f(p0);
238 float length = 3000f +
random.nextInt(2000);
239 float tIncr = length / len;
249 if (wide) angle *= 0.5f;
250 if (t >= 1f) angle = 0f;
254 if (actualDist > length * 0.5f) {
266 Vector2f loc =
new Vector2f(
start);
267 Vector2f p0 =
new Vector2f(loc);
268 Vector2f p1 =
new Vector2f(to);
274 float distSoFar = 0f;
275 float prevAngle = 0f;
276 for (
int i = 0; distSoFar < len; i++) {
285 if (i % 2 == 1) angle = prevAngle;
289 float length = 3000f +
random.nextInt(2000);
293 Vector2f.add(loc, add, loc);
303 for (SlipstreamSection section :
sections) {
310 float distToAdd = len - actualDist;
313 if (distToAdd > 1000) {
316 float turnAmount = Math.min(30f, angleDiff) * turnDir;
320 float length = distToAdd;
322 loc = Vector2f.add(end, add, loc);
334 Vector2f loc =
new Vector2f(
start);
337 Vector2f p1 =
new Vector2f(loc);
347 Vector2f perp =
new Vector2f(-dir.y, dir.x);
349 float averageSection = 4000;
351 int numNoisePoints = 32;
352 while (numNoisePoints < len / averageSection) {
353 numNoisePoints *= 2f;
355 if (numNoisePoints > 2048) numNoisePoints = 2048;
356 float spikes = 0.75f;
359 noise[noise.length - 1] = 0.5f;
364 float startLength = 1500 +
random.nextFloat() * 1500f;
365 float endLength = 1500 +
random.nextFloat() * 1500f;
366 Vector2f curr =
new Vector2f(dir);
367 curr.scale(startLength);
368 Vector2f.add(curr, p0, curr);
372 float mid = len - startLength - endLength;
373 float remaining = mid;
374 float distSoFar = startLength;
378 float maxMag = 500f + mid * 0.01f + 1f * (1000f + mid * 0.025f);
380 while (remaining > 0) {
381 float segLen = 3000f +
random.nextFloat() * 2000f;
382 segLen = Math.min(segLen, remaining);
384 if (remaining < segLen * 0.5f) {
390 float t = (distSoFar - startLength) / mid;
395 }
else if (t > 0.75f) {
396 n *= (1f - t) / 0.25f;
401 curr =
new Vector2f(dir);
402 curr.scale(distSoFar);
403 Vector2f.add(curr, p0, curr);
404 curr.x += perp.x * maxMag * n;
405 curr.y += perp.y * maxMag * n;
416 Vector2f loc =
new Vector2f(
start);
417 Vector2f p0 =
new Vector2f(loc);
418 Vector2f p1 =
new Vector2f(loc);
432 Vector2f perp =
new Vector2f(-dir.y, dir.x);
435 float distSoFar = 0f;
436 float prevAngle = 0f;
437 for (
int i = 0; distSoFar < len; i++) {
438 float angle =
random.nextFloat() * 60f - 30f;
441 if (i % 2 == 1) angle = prevAngle;
445 float length = 3000f +
random.nextInt(2000);
449 Vector2f.add(loc, add, loc);
459 for (SlipstreamSection section :
sections) {
466 float distToAdd = len - actualDist;
468 if (distToAdd > 1000) {
471 float turnAmount = Math.min(30f, angleDiff) * turnDir;
475 float length = distToAdd;
477 loc = Vector2f.add(end, add, loc);
488 Vector2f loc =
new Vector2f(
start);
489 float prevAngle = 0f;
490 for (
int i = 0; i < 20; i++) {
491 float angle =
random.nextFloat() * 60f - 30f;
492 if (i % 2 == 1) angle = prevAngle;
496 float length = 3000f +
random.nextInt(2000);
499 Vector2f.add(loc, add, loc);
507 Vector2f loc =
new Vector2f(
start);
510 Vector2f p1 =
new Vector2f(loc);
520 Vector2f perp =
new Vector2f(-dir.y, dir.x);
530 float midLength = len * (0.4f +
random.nextFloat() * 0.2f);
532 Vector2f curr =
new Vector2f(dir);
533 curr.scale(1000f +
random.nextFloat() * 1000f);
534 Vector2f.add(curr, p0, curr);
537 curr =
new Vector2f(dir);
538 curr.scale(midLength);
540 float mag = 0f +
random.nextFloat() * 1000f + len * 0.05f;
541 if (
random.nextFloat() < 0.75f) {
542 if (
random.nextBoolean()) {
545 curr.x += perp.x * mag;
546 curr.y += perp.y * mag;
549 Vector2f.add(curr, p0, curr);
552 float endLength = 1000f +
random.nextFloat() * 1000f;
553 curr =
new Vector2f(dir);
554 curr.scale(len - endLength);
555 Vector2f.add(curr, p0, curr);
566 float startLength = 1500 +
random.nextFloat() * 1500f;
567 float endLength = 1500 +
random.nextFloat() * 1500f;
568 Vector2f curr =
new Vector2f(dir);
569 curr.scale(startLength);
570 Vector2f.add(curr, p0, curr);
573 float remaining = len - startLength - endLength;
574 float distSoFar = startLength;
575 while (remaining > 0) {
576 float lengthForArc = 10000f +
random.nextFloat() * 20000f;
577 lengthForArc = Math.min(lengthForArc, remaining);
578 remaining -= lengthForArc;
579 if (remaining < 10000f) {
580 lengthForArc += remaining;
584 if (
random.nextBoolean()) {
588 float maxMag = 500f +
random.nextFloat() * (2000f + lengthForArc * 0.1f);
592 float perIter = 3000f +
random.nextFloat() * 2000f;
593 float tForIter = perIter / lengthForArc;
595 if (t > 1f - tForIter * 0.5f) {
599 perIter = tForIter * lengthForArc;
600 distSoFar += perIter;
603 curr =
new Vector2f(dir);
604 curr.scale(distSoFar);
605 Vector2f.add(curr, p0, curr);
606 curr.x += perp.x * mag;
607 curr.y += perp.y * mag;
619 Vector2f loc =
new Vector2f(
start);
622 Vector2f p3 =
new Vector2f(loc);
632 Vector2f p1 = Vector2f.add(p0, p3,
new Vector2f());
634 Vector2f p2 =
new Vector2f(p1);
641 float dist1 = len * 0.5f +
random.nextFloat() * len * 0.5f;
642 float dist2 = len * 0.5f +
random.nextFloat() * len * 0.5f;
647 p1 =
new Vector2f(p0.x, p3.y);
648 p2 =
new Vector2f(p3.x, p0.y);
650 if (
random.nextBoolean()) {
656 float veryApproxPathLength = len * 1.5f;
657 float tPerIter = 8000f / (veryApproxPathLength + 1f);
661 t += tPerIter * (0.8f + 0.4f *
random.nextFloat());
662 if (t > 1f - tPerIter * 0.5f) t = 1f;
672 Vector2f loc =
new Vector2f(
start);
675 Vector2f p2 =
new Vector2f(loc);
682 Vector2f p1 = Vector2f.add(p0, p2,
new Vector2f());
688 float tPerIter = 8000f / (approxPathLength + 1f);
692 t += tPerIter * (0.8f + 0.4f *
random.nextFloat());
693 if (t > 1f - tPerIter * 0.5f) t = 1f;
704 Vector2f loc =
new Vector2f(
start);
728 Vector2f loc =
new Vector2f(
start);
729 float prevAngle = 0f;
730 for (
int i = 0; i < 20; i++) {
731 float angle =
random.nextFloat() * 60f - 30f;
732 if (i % 2 == 1) angle = prevAngle;
736 float length = 3000f +
random.nextInt(2000);
739 Vector2f.add(loc, add, loc);
768 float totalCurveLength = 0f;
769 for (SlipstreamSection curr :
sections) {
770 totalCurveLength += curr.approxCurveLength;
773 int numNoisePoints = 32;
775 numNoisePoints *= 2f;
777 if (numNoisePoints > 2048) numNoisePoints = 2048;
779 float spikes = 0.67f;
781 noiseForWidth[0] = 0.5f;
782 noiseForWidth[noiseForWidth.length - 1] = 0.5f;
791 float curveLengthSoFar = 0f;
792 for (SlipstreamSection curr :
sections) {
798 float startingWidth = width;
808 int segments = (int) (curr.approxCurveLength / desiredSpacing);
809 if (segments < 2) segments = 2;
810 float spacing = curr.approxCurveLength / segments;
812 List<AddedSegment> added =
new ArrayList<AddedSegment>();
815 if (
getPrev(curr) ==
null) startIndex = 0;
816 for (
int i = startIndex; i < segments; i++) {
817 float f = (float)i / ((
float)segments - 1f);
818 float f2 = (float)(i + 0.1f) / ((float)segments - 1f);
820 width =
Misc.
interpolate(startingWidth, goalWidth, Math.min(1f, f * f * changeRate));
821 float t = (curveLengthSoFar + f * curr.approxCurveLength) / totalCurveLength;
825 width *= (1f + wNoise);
827 Vector2f loc =
Misc.
bezier(curr.from, curr.control, curr.to, f);
828 Vector2f loc2 =
Misc.
bezier(curr.from, curr.control, curr.to, f2);
829 Vector2f dir = Vector2f.sub(loc2, loc,
new Vector2f());
831 Vector2f perp =
new Vector2f(-dir.y, dir.x);
834 AddedSegment seg =
new AddedSegment();
836 seg.dir =
new Vector2f(dir);
837 seg.perp =
new Vector2f(perp);
843 float fluctDir = Math.signum(
random.nextFloat() - 0.5f);
844 float distSoFar = 0f;
845 List<AddedSegment> temp =
new ArrayList<AddedSegment>();
846 AddedSegment prev =
null;
847 for (AddedSegment seg : added) {
854 if (distSoFar > distPerFluct && temp.size() >= 4) {
855 for (
int i = 0; i < temp.size(); i++) {
856 float t = i / (temp.size() - 1f);
857 AddedSegment seg2 = temp.get(i);
860 fluctMag *= fluctMult;
863 fluctMag *= fluctAmount * fluctDir;
865 seg2.segment.loc.x += seg2.perp.x * fluctMag;
866 seg2.segment.loc.y += seg2.perp.y * fluctMag;
873 fluctDir = Math.signum(
random.nextFloat() - 0.5f);
877 curveLengthSoFar += curr.approxCurveLength;
882 float fadeDist = 500f;
883 float distSoFar = 0f;
884 SlipstreamSegment prev =
null;
890 if (distSoFar >= fadeDist) {
894 float b = distSoFar / fadeDist;
908 if (distSoFar >= fadeDist) {
912 float b = distSoFar / fadeDist;
921 float pi = (float) Math.PI;
922 return ((
float)Math.cos(pi + 2f * pi * t) + 1f) * 0.5f;
935 Vector2f avg = Vector2f.add(prev.loc, next.loc,
new Vector2f());
969 mult *= 0.9f + 0.2f *
random.nextFloat();
986 float goalWidth =
params.baseWidth;
997 return goalWidth * mult;
1001 float angleLimit = 30f;
1002 for (SlipstreamSection curr :
sections) {
1003 SlipstreamSection prev =
getPrev(curr);
1004 SlipstreamSection next =
getNext(curr);
1007 if (prev ==
null && next ==
null) {
1008 curr.control = Vector2f.add(curr.from, curr.to,
new Vector2f());
1009 curr.control.scale(0.5f);
1010 }
else if (prev ==
null && next !=
null) {
1011 Vector2f p1 = curr.from;
1012 Vector2f p2 = curr.to;
1013 Vector2f p3 = next.to;
1016 Vector2f p2ToP1 = Vector2f.sub(p1, p2,
new Vector2f());
1018 float angleToControlAndP2toP1 = Vector2f.angle(dirP2ToControl, p2ToP1) *
Misc.
DEG_PER_RAD;
1019 if (angleToControlAndP2toP1 > angleLimit) {
1020 angleToControlAndP2toP1 = angleLimit;
1022 angleP2ToControl = angleP2toP1 + turnDir * angleToControlAndP2toP1;
1027 float h = dist * (float) Math.tan(angleToControlAndP2toP1 *
Misc.
RAD_PER_DEG);
1028 float b = (float) Math.sqrt(dist * dist + h * h);
1029 dirP2ToControl.scale(b);
1030 Vector2f.add(dirP2ToControl, p2, curr.control);
1032 Vector2f p1 = prev.control;
1033 Vector2f p2 = curr.from;
1034 Vector2f p3 = curr.to;
1037 Vector2f p2ToP3 = Vector2f.sub(p3, p2,
new Vector2f());
1039 float angleToControlAndP2toP3 = Vector2f.angle(dirP2ToControl, p2ToP3) *
Misc.
DEG_PER_RAD;
1040 if (angleToControlAndP2toP3 > angleLimit) {
1041 angleToControlAndP2toP3 = angleLimit;
1043 angleP2ToControl = angleP2ToP3 + turnDir * angleToControlAndP2toP3;
1049 float h = dist * (float) Math.tan(angleToControlAndP2toP3 *
Misc.
RAD_PER_DEG);
1050 float b = (float) Math.sqrt(dist * dist + h * h);
1051 dirP2ToControl.scale(b);
1052 Vector2f.add(dirP2ToControl, p2, curr.control);
1063 if (!alreadyPicked) {
1069 public void addSection(Vector2f to,
int width,
int wrand,
int wchange,
int fluct) {
1070 addSection(to, width, wrand, wchange, fluct, -1);
1073 public void addSection(Vector2f to,
int width,
int wrand,
int wchange,
int fluct,
int insertIndex) {
1074 SlipstreamSection s =
new SlipstreamSection();
1078 s.wchange = wchange;
1081 if (insertIndex < 0) {
1087 SlipstreamSection p =
getPrev(s);
1096 public SlipstreamSection
getPrev(SlipstreamSection s) {
1098 if (index < 1)
return null;
1101 public SlipstreamSection
getNext(SlipstreamSection s) {
1103 if (index < 0 || index >=
sections.size() - 1)
return null;
1139 float [] weights = matrix[curr];
1141 for (
int i = 0; i < weights.length; i++) {
1142 picker.
add(i, weights[i]);
1144 return picker.
pick();
1151 GL11.glDisable(GL11.GL_TEXTURE_2D);
1152 GL11.glEnable(GL11.GL_BLEND);
1153 GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
1164 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1165 GL11.glLineWidth(3f);
1166 GL11.glBegin(GL11.GL_LINE_STRIP);
1167 Vector2f p0 =
new Vector2f(0, 0);
1168 Vector2f p1 =
new Vector2f(10000, 0);
1169 Vector2f p2 =
new Vector2f(0, 10000);
1170 Vector2f p3 =
new Vector2f(10000, 10000);
1171 for (
float t = 0f; t <= 1f; t += 0.02f) {
1173 GL11.glVertex2f(p.x, p.y);
1179 GL11.glEnable(GL11.GL_POINT_SMOOTH);
1180 GL11.glPointSize(10f);
1181 GL11.glBegin(GL11.GL_POINTS);
1183 for (SlipstreamSection curr :
sections) {
1185 if (curr.subdivision) {
1188 Vector2f p = curr.from;
1189 GL11.glVertex2f(p.x, p.y);
1191 GL11.glVertex2f(p.x, p.y);
1195 GL11.glVertex2f(p.x, p.y);
1200 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1201 GL11.glLineWidth(3f);
1202 GL11.glBegin(GL11.GL_LINE_STRIP);
1203 for (SlipstreamSection curr :
sections) {
1204 for (
float t = 0f; t <= 1f; t += 0.02f) {
1205 Vector2f p =
Misc.
bezier(curr.from, curr.control, curr.to, t);
1206 GL11.glVertex2f(p.x, p.y);
1214 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1215 GL11.glLineWidth(3f);
1216 GL11.glBegin(GL11.GL_LINE_LOOP);
1218 for (Vector2f p : box.box) {
1219 GL11.glVertex2f(p.x, p.y);
1228 GL11.glPushMatrix();
1230 GL11.glTranslatef(loc.x - 1000, loc.y + 100, 0f);
1244 GL11.glEnable(GL11.GL_LINE_SMOOTH);
1245 GL11.glLineWidth(3f);
1246 GL11.glBegin(GL11.GL_LINE_STRIP);
1249 for (
int i = 0; i <
buildNoise.length; i++) {
1251 GL11.glVertex2f(i * horz, f * vert);
1262 GL11.glBegin(GL11.GL_LINES);
1263 GL11.glVertex2f(0, 0);
1264 GL11.glVertex2f(
buildNoise.length * horz, 0);
1265 GL11.glVertex2f(0, 0);
1266 GL11.glVertex2f(0, vert);
1275 int index = (int) t;
1276 if (index >= noise.length) index = noise.length - 1;
1277 if (index < 0) index = 0;
1279 int index2 = index + 1;
1280 if (index2 >= noise.length) index2 = index - 1;
1282 float f = t - index;
1293 float min = Float.MAX_VALUE;
1294 float max = -Float.MAX_VALUE;
1295 for (
float f : noise) {
1296 if (f < min) min = f;
1297 if (f > max) max = f;
1301 for (
int i = 0; i < noise.length; i++) {
1307 float range = max - min;
1308 for (
int i = 0; i < noise.length; i++) {
1309 noise[i] = (noise[i] - min) / range;
1314 float [] noise =
new float[size];
1315 for (
int i = 0; i < noise.length; i++) {
1318 noise[0] =
random.nextFloat() * spikes;
1319 noise[noise.length - 1] =
random.nextFloat() * spikes;
1327 if (x1 + 1 >= x2)
return;
1329 int midX = (x1 + x2) / 2;
1331 float avg = (noise[x1] + noise[x2]) / 2f;
1332 noise[midX] = avg + ((float) Math.pow(spikes, (iter)) * (
float) (
random.nextFloat() - .5f));
1341 for (
float f = 0; f <= 1.01f; f += 0.1f) {
1351 for (
float f = 0; f <= 1.01f; f += 0.05f) {
static SectorAPI getSector()
static void normalizeNoise1D(float[] noise)
static final int FLUCT_NONE
static float getApproximateBezierLength(Vector2f p0, Vector2f p1, Vector2f p2)
static float FLUCT_LENGTH_MAX
static final int WIDTH_WIDE
static void genNoise1DFill(Random random, float[] noise, int x1, int x2, int iter, float spikes)
void adjustSharpInflectionPoints()
static final int WCHANGE_FAST
float getWChangeMult(SlipstreamSection curr)
static float WIDTH_TO_SPACING_MULT
static float WCHANGE_FAST_T_MULT_MAX
static final int FLUCT_MEDIUM
static void genNoise1D(Random random, float[] noise, int size, float spikes)
void initTransitionMatrices()
float getMaxAngleVarianceForCurve()
float getFluctuationFunc(float t)
static float WCHANGE_MEDIUM_T_MULT_MAX
static float MAX_VERY_WIDE
SlipstreamTerrainPlugin2 plugin
static final int WRAND_LOW
int pickNext(int curr, float[][] matrix)
static float getInterpNoise(float[] noise, float t)
static final int WCHANGE_SLOW
static float WRAND_LOW_MULT
static final int WCHANGE_MEDIUM
void addSection(Vector2f to, int width, int wrand, int wchange, int fluct)
float getFluctMult(SlipstreamSection curr)
static float WCHANGE_SLOW_T_MULT_MIN_MAX
static float WCHANGE_SLOW_T_MULT_MIN
float getGoalWidth(SlipstreamSection curr)
float getMaxAngleVariance()
void addSection(Vector2f to, int width, int wrand, int wchange, int fluct, int insertIndex)
void addSection(Vector2f to, boolean alreadyPicked)
SlipstreamSection getPrev(SlipstreamSection s)
static float WRAND_HIGH_MULT
static float MIN_VERY_WIDE
void buildToDestination(Vector2f to)
static final int FLUCT_LOW
static final int WIDTH_NORMAL
void buildToDestination(Vector2f control, Vector2f to)
void setMaxAngleVariance(float maxAngleVariance)
void setMaxAngleVarianceForCurve(float maxAngleVarianceForCurve)
int pickWChange(int curr)
void computeControlPoints()
static final int FLUCT_HIGH
void buildToDestination(Vector2f control, Vector2f control2, Vector2f to)
static float FLUCT_LOW_MULT
static float WRAND_MEDIUM_MULT
static final int WIDTH_VERY_WIDE
static final int WRAND_MEDIUM
static float WCHANGE_MEDIUM_T_MULT_MIN
static final int WRAND_NONE
static float FLUCT_LENGTH_MIN
static float WCHANGE_FAST_T_MULT_MIN
List< SlipstreamSection > sections
static float FLUCT_NONE_MULT
static float FLUCT_HIGH_MULT
static final int WIDTH_NARROW
static float FLUCT_MEDIUM_MULT
static float FLUCT_MAG_MAX
void addSection(Vector2f to)
static float[] initNoise1D(Random random, int size, float spikes)
SlipstreamSection getNext(SlipstreamSection s)
static final int WRAND_HIGH
SlipstreamBuilder(Vector2f start, SlipstreamTerrainPlugin2 plugin, StreamType type, Random random)
void renderDebug(float alpha)
static float FLUCT_MAG_MIN
static float getApproximateBezierLength(Vector2f p0, Vector2f p1, Vector2f p2, Vector2f p3)
float maxAngleVarianceForCurve
static float WRAND_NONE_MULT
float getWRandMult(SlipstreamSection curr)
List< BoundingBox > getBounds()
void addSegment(Vector2f loc, float width)
SlipstreamParams2 getParams()
List< SlipstreamSegment > getSegments()
void setBuilder(SlipstreamBuilder builder)
static Vector2f getUnitVectorAtDegreeAngle(float degrees)
static Vector2f bezier(Vector2f p0, Vector2f p1, Vector2f p2, float t)
static void setColor(Color color)
static Vector2f rotateAroundOrigin(Vector2f v, float angle)
static Vector2f bezierCubic(Vector2f p0, Vector2f p1, Vector2f p2, Vector2f p3, float t)
static float getAngleDiff(float from, float to)
static float getDistance(SectorEntityToken from, SectorEntityToken to)
static Vector2f getUnitVector(Vector2f from, Vector2f to)
static float getClosestTurnDirection(float facing, float desired)
static float interpolate(float from, float to, float progress)
static Vector2f getPointAtRadius(Vector2f from, float r)
static Vector2f interpolateVector(Vector2f from, Vector2f to, float progress)
static float getAngleInDegrees(Vector2f v)
static Vector2f normalise(Vector2f v)
CampaignFleetAPI getPlayerFleet()