Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FovHighlightingAndDarkening: Fixing NPEs by adding null handling and Nullable annotations #2831

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.List;
import java.util.Map;

import megamek.MegaMek;
import megamek.client.ui.swing.GUIPreferences;
import megamek.common.Compute;
import megamek.common.ComputeECM;
Expand All @@ -21,6 +22,7 @@
import megamek.common.LosEffects;
import megamek.common.MoveStep;
import megamek.common.IGame.Phase;
import megamek.common.annotations.Nullable;
import megamek.common.event.GameListener;
import megamek.common.event.GameListenerAdapter;
import megamek.common.event.GameTurnChangeEvent;
Expand All @@ -30,13 +32,8 @@

/**
* A helper class for highlighting and darkening hexes.
*
*/
class FovHighlightingAndDarkening {

/**
*
*/
private final BoardView1 boardView1;
private java.util.List<Color> ringsColors = new ArrayList<>();
private java.util.List<Integer> ringsRadii = new ArrayList<>();
Expand Down Expand Up @@ -176,6 +173,10 @@ boolean draw(Graphics boardGraph, Coords c, int drawX, int drawY,
} else if (dist < max_dist) {
LosEffects los = getCachedLosEffects(src, c);
if (null != this.boardView1.selectedEntity) {
if (los == null) {
los = LosEffects.calculateLos(boardView1.game, boardView1.selectedEntity.getId(), null);
}

if (doubleBlindOn) { // Visual Range only matters in DB
visualRange = Compute.getVisualRange(
this.boardView1.game,
Expand All @@ -195,11 +196,13 @@ boolean draw(Graphics boardGraph, Coords c, int drawX, int drawY,
minSensorRange = 0;
}
}

// Visual Range only matters in DB: ensure no effect w/o DB
if (!doubleBlindOn) {
visualRange = dist;
}
if (!los.canSee() || (dist > visualRange)) {

if (((los != null) && !los.canSee()) || (dist > visualRange)) {
if (darken) {
if (sensorsOn
&& (dist > minSensorRange)
Expand Down Expand Up @@ -252,10 +255,10 @@ private void clearCache() {
/**
* Checks for los effects, preferably from cache, if not getLosEffects
* is invoked and it's return value is cached.
* If enviroment has changed between calls to this method the cache is
* If environment has changed between calls to this method the cache is
* cleared.
*/
public LosEffects getCachedLosEffects(Coords src, Coords dest) {
public @Nullable LosEffects getCachedLosEffects(Coords src, Coords dest) {
ArrayList<StepSprite> pathSprites = boardView1.pathSprites;
StepSprite lastStepSprite = pathSprites.size() > 0 ? pathSprites
.get(pathSprites.size() - 1) : null;
Expand All @@ -275,8 +278,10 @@ public LosEffects getCachedLosEffects(Coords src, Coords dest) {

LosEffects los = losCache.get(dest);
if (los == null) {
los = this.boardView1.fovHighlightingAndDarkening.getLosEffects(
src, dest);
los = boardView1.fovHighlightingAndDarkening.getLosEffects(src, dest);
if (los == null) {
return null;
}
losCache.put(dest, los);
}
return los;
Expand Down Expand Up @@ -342,24 +347,30 @@ private void updateRingsProperties() {
* present in that hex. If no units are present, the GUIPreference
* 'mechInSecond' is used.
*/
private LosEffects getLosEffects(Coords src, Coords dest) {
private @Nullable LosEffects getLosEffects(final Coords src, final Coords dest) {
/*
* The getCachedLos method depends that this method uses only
* information from src, dest, game, selectedEntity and the last
* stepSprite from path Sprites. If this behavior changes, please
* change
* getCachedLos method accordingly.
* change the getCachedLos method accordingly.
*/
GUIPreferences guip = GUIPreferences.getInstance();
IBoard board = this.boardView1.game.getBoard();
IHex srcHex = board.getHex(src);
if (srcHex == null) {
MegaMek.getLogger().error("Cannot process line of sight effects with a null source hex.");
return null;
}
IHex dstHex = board.getHex(dest);
if (dstHex == null) {
MegaMek.getLogger().error("Cannot process line of sight effects with a null destination hex.");
return null;
}
LosEffects.AttackInfo ai = new LosEffects.AttackInfo();
ai.attackPos = src;
ai.targetPos = dest;
// First, we check for a selected unit and use its height. If
// there's
// no selected unit we use the mechInFirst GUIPref.
// there's no selected unit we use the mechInFirst GUIPref.
if (this.boardView1.selectedEntity != null) {
ai.attackHeight = this.boardView1.selectedEntity.getHeight();
// Elevation of entity above the hex surface
Expand All @@ -380,11 +391,10 @@ private LosEffects getLosEffects(Coords src, Coords dest) {
ai.attackHeight = guip.getMechInFirst() ? 1 : 0;
ai.attackAbsHeight = srcHex.surface() + ai.attackHeight;
}
// First, we take the tallest unit in the destination hex, if no
// units
// are present we use the mechInSecond GUIPref.
// First, we take the tallest unit in the destination hex, if no units are present we use
// the mechInSecond GUIPref.
ai.targetHeight = ai.targetAbsHeight = Integer.MIN_VALUE;
for (Entity ent : this.boardView1.game.getEntitiesVector(dest)) {
for (Entity ent : boardView1.game.getEntitiesVector(dest)) {
int trAbsheight = dstHex.surface() + ent.relHeight();
if (trAbsheight > ai.targetAbsHeight) {
ai.targetHeight = ent.getHeight();
Expand All @@ -396,10 +406,6 @@ private LosEffects getLosEffects(Coords src, Coords dest) {
ai.targetHeight = guip.getMechInSecond() ? 1 : 0;
ai.targetAbsHeight = dstHex.surface() + ai.targetHeight;
}
return LosEffects.calculateLos(this.boardView1.game, ai);
return LosEffects.calculateLos(boardView1.game, ai);
}




}
31 changes: 11 additions & 20 deletions megamek/src/megamek/common/Board.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,18 +281,13 @@ public void newData(int width, int height) {
* Determines if this Board contains the (x, y) Coords, and if so, returns
* the Hex at that position.
*
* @param x
* the x Coords.
* @param y
* the y Coords.
* @return the Hex, if this Board contains the (x, y) location; null
* otherwise.
* @param x the x Coords.
* @param y the y Coords.
* @return the Hex, if this Board contains the (x, y) location; null otherwise.
*/
public IHex getHex(int x, int y) {
if (contains(x, y)) {
return data[(y * width) + x];
}
return null;
@Override
public @Nullable IHex getHex(final int x, final int y) {
return contains(x, y) ? data[(y * width) + x] : null;
}

/**
Expand Down Expand Up @@ -652,16 +647,12 @@ public boolean contains(Coords c) {
}

/**
* Returns the Hex at the specified Coords.
*
* @param c
* the Coords.
* @param c the Coords, which may be null
* @return the Hex at the specified Coords, or null if there is not a hex there
*/
public IHex getHex(Coords c) {
if (c == null) {
return null;
}
return getHex(c.getX(), c.getY());
@Override
public @Nullable IHex getHex(final @Nullable Coords c) {
return (c == null) ? null : getHex(c.getX(), c.getY());
}

/**
Expand Down
11 changes: 5 additions & 6 deletions megamek/src/megamek/common/Compute.java
Original file line number Diff line number Diff line change
Expand Up @@ -4673,10 +4673,8 @@ public static boolean calcSensorContact(IGame game, Entity ae,
return roll >= tn;
}

public static int getVisualRange(IGame game, Entity ae, LosEffects los,
boolean teIlluminated) {
int visualRange = game.getPlanetaryConditions().getVisualRange(ae,
teIlluminated);
public static int getVisualRange(IGame game, Entity ae, LosEffects los, boolean teIlluminated) {
int visualRange = game.getPlanetaryConditions().getVisualRange(ae, teIlluminated);
visualRange -= los.getLightSmoke();
visualRange -= 2 * los.getHeavySmoke();
visualRange = Math.max(1, visualRange);
Expand Down Expand Up @@ -4869,11 +4867,12 @@ public static int getSensorBracket(int check) {
* type of target. target may be null here, which gives you the range
* without target entity modifiers
*/
public static int getSensorRangeByBracket(IGame game, Entity ae,
Targetable target, LosEffects los) {
public static int getSensorRangeByBracket(IGame game, Entity ae, @Nullable Targetable target,
@Nullable LosEffects los) {
if (los == null) {
los = LosEffects.calculateLos(game, ae.getId(), target);
}

Sensor sensor = ae.getActiveSensor();
if (null == sensor) {
return 0;
Expand Down
19 changes: 7 additions & 12 deletions megamek/src/megamek/common/IBoard.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,11 @@ public interface IBoard {
* Determines if this Board contains the (x, y) Coords, and if so, returns
* the Hex at that position.
*
* @param x
* the x Coords.
* @param y
* the y Coords.
* @return the <code>Hex</code>, if this Board contains the (x, y) location;
* <code>null</code> otherwise.
* @param x the x Coords.
* @param y the y Coords.
* @return the Hex, if this Board contains the (x, y) location; null otherwise.
*/
public abstract IHex getHex(int x, int y);
@Nullable IHex getHex(int x, int y);

/**
* Gets the hex in the specified direction from the specified starting
Expand Down Expand Up @@ -143,12 +140,10 @@ public interface IBoard {
public abstract boolean contains(Coords c);

/**
* Returns the Hex at the specified Coords.
*
* @param c
* the Coords.
* @param c the Coords, which may be null
* @return the Hex at the specified Coords, or null if there is not a hex there
*/
public abstract IHex getHex(Coords c);
@Nullable IHex getHex(final @Nullable Coords c);

/**
* Determines if this Board contains the (x, y) Coords, and if so, sets the
Expand Down