Repository: MegaMek/megamek
Pull request #6971: fix: adds padding in between maps if they are of odd width size, making it possible to tile those. Small performance improvements.
Author: login: Scoppio
Labels: name: Performance
description: Any issues or PR related to performance of the project
name: For New Dev Cycle
description: This PR should be merged at the beginning of a dev cycle
name: Severity: Critical
description: Issues described as critical as per the new issue form
name: Map and Board
description: Specific Issues related to a Map, Board or Tileset
Created: 2025-05-03T06:08:07Z | Merged: 2025-05-19T21:21:19Z

# What it does?

Adds padding in between maps if they are of odd size, making it possible to tile odd width boards, a few perf improvements when rendering the board and when making changes in the Select Map Tab.

4 maps 15x15 with 3 column padding in between

![image](https://github.com/user-attachments/assets/9cd66518-26a2-442b-9909-4f9167f78300)

4 maps 11x11 with 3 column padding in between (before I added pavement to the padding generator)
![image](https://github.com/user-attachments/assets/09119493-14fa-4f3c-bf62-d996cde80749)

Here we can see in detail the "lerp" functionality added, it averages the height in between both sides.
![image](https://github.com/user-attachments/assets/45cda328-7cf0-4fcc-bfe1-f0403cb22a8e)


## All changes

- Added option for high performance graphics, which changes the interpolation to nearest neighbor and uses rendering which values speed.
- Changed the `Board#getTags` function to stop when it finds the first `hex` intead of going until the end of the file.
- Added a map padding generator which averages the hexes between maps and creates a filler to fill the void, it is configurable and is currently set to 1 hex width padding when needed.

## What it doesnt do

I does not make possible to rotate maps with odd number of columns, to do that the original board has to recreated with one extra column, it's possible and this makes it easier to do that.

# Closes

- Closes #6947 and whichever more.

Linked issue #6947: [Issue] When Tiling Maps (2x2) Right Side Maps Hexes Appear Scrambled
### Brief Description *

[Princess is stuck deploying](https://i.imgur.com/RwRr9WQ.png)

### 3. Steps to Reproduce

1. Start a new game. Create the map as seen. Import my militia .mul list. Generate the army for Princess via "Create Random Army"
_For ease, I have already included a pre-game save file. See "Pregame.sav.gz"_
2. Load in and start deploying. I guess at some point I forgot to turn on ghost targets for my single ECM equipped mech and turned that on (as well as ghost targets for the communications equipment) on my side. You can see my most recent deployment in "Stuck.sav.gz"

Basically all I did was get in and start deploying as normal and the moment it got to Princess turn, she was stuck. The only fix I had was to kick her from game, /skip her turn, and then replace her back into the bot.

### Attach Files

[Pregame.sav.gz](https://github.com/user-attachments/files/19940194/Pregame.sav.gz)
_The Pregame setup_

[Stuck.sav.gz](https://github.com/user-attachments/files/19940197/Stuck.sav.gz)
_The current turn where she is stuck_

[megamek.log](https://github.com/user-attachments/files/19940314/megamek.log)
_megamek log_

[Militia List.zip](https://github.com/user-attachments/files/19940399/Militia.List.zip)
_My custom militia list .mul I imported from .04. Not included is the camo I made_

![Image](https://github.com/user-attachments/assets/18843040-86bb-438a-8dd8-f985560decf4)
_The Camo I made, if that is relevant(?)_

CUSTOM UNITS
[Custom Units.zip](https://github.com/user-attachments/files/19940350/Custom.Units.zip)
_so you can load the save game_

### Severity *

High (Major Disruption): A major feature is broken or incorrect, but a workaround exists.

### MegaMek Suite Version *

0.50.05

### Operating System *

Windows 11

### Java Version *

Java Version: 18

### Final Verification

- [x] I confirm this is a single, unique issue that hasn't been reported before
- [x] I have included all necessary information and files to help reproduce this issue
- [x] I have asked on MegaMek Discord about this issue
- [x] I have confirmed this issue is being opened on the correct repository: MegaMek, MegaMekLab, or MekHQ
Linked issue comments: user: login: psikomonkie
created_at: 2025-04-28T15:43:14Z
body: One of these maps may be invalid. Princess is throwing an error when trying to run the `BulldozerMovePath`. It is finding a hex that has "Building CF" but doesn't have a building. I believe this means one of these maps is broken. 

EDIT: It's Endo Steel City - the buildings are all kinds of messed up, take a look at it. The map looks totally fine on its own though, this just gets weirder...

EDIT 2: Okay, I'll stop looking into this now, but something is going wrong when combining map sheets. If you switch Rectortown Reloaded and Endosteel City, Rectortown Reloaded becomes messed up.

![Image](https://github.com/user-attachments/assets/0fe0cf7b-f288-4f29-8055-879fa8527bab)
author_association: MEMBER
user: login: Scoppio
created_at: 2025-04-30T17:39:46Z
body: @psikomonkie can you open a new issue, blocker type, for when loading multi board maps?
author_association: COLLABORATOR
user: login: psikomonkie
created_at: 2025-04-30T17:57:13Z
body: > @psikomonkie can you open a new issue, blocker type, for when loading multi board maps?

Do we need a separate issue or should this be renamed? From what I saw Princess can't be expected to work when the internal building map is broken and hexes don't correctly count as buildings. IMO the bug here is just loading multi board maps. 
author_association: MEMBER
user: login: SimonLandmine
created_at: 2025-05-02T17:33:26Z
body: The base problem appears to be obvious - they are attempting to tile maps with odd numbers of columns. This raises the same issue as trying to rotate maps with odd numbers of columns - a forced realignment of the columns. This is why we do not recommend maps with odd numbers of columns.

Suggested solution would be a warning message when attempting to tile maps with an odd number of columns.
author_association: NONE
user: login: Scoppio
created_at: 2025-05-02T19:38:28Z
body: I will see if I can do ANYTHING about it before adding the warning.
author_association: COLLABORATOR
user: login: SimonLandmine
created_at: 2025-05-02T19:43:57Z
body: I think, becuase of the simple geometrics of hex maps, you would have to either ...
a) add an additional column in between each map
b) remove the rightmost column of any map that is not the rightmost map
Both of these could well have obvious, and unintended, consequences with regard to the design of the maps.
author_association: NONE
user: login: Scoppio
created_at: 2025-05-02T21:40:44Z
body: Adding an extra column would be the least problematic of the two, because I wont have to deal with problems like removing half a building
author_association: COLLABORATOR
user: login: Sleet01
created_at: 2025-05-02T21:47:30Z
body: @Scoppio I wonder if we could do a left-side/right-side average of terrain type and level, so that if there are e.g. roads, hills, or buildings, the seam won't be as discontinuous.
author_association: COLLABORATOR
user: login: SimonLandmine
created_at: 2025-05-02T21:51:18Z
body: @Sleet01 - Yeah, if the maps have an odd number of columns, they weren't built to be tiled, so artificial connectors could be interesting.
author_association: NONE
user: login: Scoppio
created_at: 2025-05-03T00:55:28Z
body: > [@Scoppio](https://github.com/Scoppio) I wonder if we could do a left-side/right-side average of terrain type and level, so that if there are e.g. roads, hills, or buildings, the seam won't be as discontinuous.

I will at first just add a nag saying its a bad idea to tile odd width sized maps, and I will follow up with a type of autogenerated connection, but first the thing that will make sure people at least know about the problem.

But an autogenerated connector may be an amount of work that isnt "worth" being called a mere fix... lets see...
author_association: COLLABORATOR
user: login: Scoppio
created_at: 2025-05-05T15:23:12Z
body: So, turns out I was able to do that @SimonLandmine. It works fine and can be updated to allow oddsized maps to be flipped. But it is a whole new feature and not very simple, so will be postponed to 50.07 since we are doing only bug fixes and this is a long-standing problem on how offset coordinates odd-q hexgrid maps work.

<!-- Uploading "Screenshot 2025-05-03 at 00.45.30.png"... –>

So for now we will have the nag warning against using odd width maps for tiling.
author_association: COLLABORATOR
user: login: SimonLandmine
created_at: 2025-05-05T16:31:09Z
body: Nice one.

I'm wondering whether the 'Blocker' classification should be removed from this Issue, as it's not actually a blocker, nor 'Severity: Critical', just resulting from a misunderstanding about how hex maps tile.
author_association: NONE
user: login: Scoppio
created_at: 2025-05-07T17:46:42Z
body: > Nice one.
> 
> I'm wondering whether the 'Blocker' classification should be removed from this Issue, as it's not actually a blocker, nor 'Severity: Critical', just resulting from a misunderstanding about how hex maps tile.

I think it is a sever bug, it breaks things and there isnt anything in the MM that stops it from happening, so it is serious. We just know of it and we need to communicate it to the user until it is fixed.

I will close this issue once the proper solution is merged.
author_association: COLLABORATOR

Diff:
diff --git a/megamek/i18n/megamek/client/messages.properties b/megamek/i18n/megamek/client/messages.properties
index 4d269f270f4..f51f8ffbb58 100644
--- a/megamek/i18n/megamek/client/messages.properties
+++ b/megamek/i18n/megamek/client/messages.properties
@@ -1112,6 +1112,8 @@ CommonMenuBar.moveLAMaircraftMode=Transform to aerospace fighter mode
 CommonSettingsDialog.aOHexSHadows=Show ambient-occlusion-like hex shadows at the base of hills
 CommonSettingsDialog.advanced=Advanced
 CommonSettingsDialog.animateMove=Animate movement.
+CommonSettingsDialog.highPerformanceGraphics=High Speed Graphics
+CommonSettingsDialog.highPerformanceGraphics.tooltip=Enables nearest neighbor interpolation and other performance improving options. 
 CommonSettingsDialog.highQualityGraphics=High Quality Graphics
 CommonSettingsDialog.highQualityGraphics.tooltip=Enables anti-aliasing and other high quality graphics options, improving graphics quality at the price of performance
 CommonSettingsDialog.armorMiniArmorChar.tooltip=The character representing blocks of armor when hovering the mouse over a unit.
diff --git a/megamek/src/megamek/client/ui/swing/BoardEditor.java b/megamek/src/megamek/client/ui/swing/BoardEditor.java
index fb41caa2b8c..3c6cb2e17ba 100644
--- a/megamek/src/megamek/client/ui/swing/BoardEditor.java
+++ b/megamek/src/megamek/client/ui/swing/BoardEditor.java
@@ -1529,7 +1529,6 @@ public void loadBoard(File file) {
                   1,
                   1,
                   new Board[] { board },
-                  Collections.singletonList(false),
                   MapSettings.MEDIUM_GROUND);
             game.setBoard(board);
             // BoardUtilities.combine does not preserve tags, so add them back
diff --git a/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java b/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java
index 77cb52068ff..1636e7bd8f3 100644
--- a/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java
+++ b/megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java
@@ -186,6 +186,8 @@ private <T> void moveElement(DefaultListModel<T> srcModel, int srcIndex, int trg
     private final JCheckBox showWrecks = new JCheckBox(Messages.getString("CommonSettingsDialog.showWrecks"));
     private final JCheckBox chkHighQualityGraphics = new JCheckBox(Messages.getString(
           "CommonSettingsDialog.highQualityGraphics"));
+    private final JCheckBox chkHighPerformanceGraphics = new JCheckBox(Messages.getString(
+          "CommonSettingsDialog.highPerformanceGraphics"));
     private final JCheckBox showWpsinTT = new JCheckBox(Messages.getString("CommonSettingsDialog.showWpsinTT"));
     private final JCheckBox showWpsLocinTT = new JCheckBox(Messages.getString("CommonSettingsDialog.showWpsLocinTT"));
     private final JCheckBox showArmorMiniVisTT = new JCheckBox(Messages.getString(
@@ -763,7 +765,8 @@ private JPanel getGameBoardPanel() {
         comps.add(checkboxEntry(showWrecks, null));
         comps.add(checkboxEntry(chkHighQualityGraphics,
               Messages.getString("CommonSettingsDialog.highQualityGraphics.tooltip")));
-
+        comps.add(checkboxEntry(chkHighPerformanceGraphics,
+              Messages.getString("CommonSettingsDialog.highPerformanceGraphics.tooltip")));
         showMapsheets.addItemListener(this);
         row = new ArrayList<>();
         row.add(showMapsheets);
@@ -2085,6 +2088,7 @@ public void setVisible(boolean visible) {
 
             showMapsheets.setSelected(GUIP.getShowMapsheets());
             chkHighQualityGraphics.setSelected(GUIP.getHighQualityGraphics());
+            chkHighPerformanceGraphics.setSelected(GUIP.getHighPerformanceGraphics());
             showDamageLevel.setSelected(GUIP.getShowDamageLevel());
             showDamageDecal.setSelected(GUIP.getShowDamageDecal());
             aOHexShadows.setSelected(GUIP.getAOHexShadows());
@@ -2970,6 +2974,8 @@ public void itemStateChanged(ItemEvent event) {
             GUIP.setShowDamageLevel(showDamageLevel.isSelected());
         } else if (source.equals(chkHighQualityGraphics)) {
             GUIP.setHighQualityGraphics(chkHighQualityGraphics.isSelected());
+        } else if (source.equals(chkHighPerformanceGraphics)) {
+            GUIP.setHighPerformanceGraphics(chkHighPerformanceGraphics.isSelected());
         } else if (source.equals(drawFacingArrowsOnMiniMap)) {
             GUIP.setDrawFacingArrowsOnMiniMap(drawFacingArrowsOnMiniMap.isSelected());
         } else if (source.equals(drawSensorRangeOnMiniMap)) {
diff --git a/megamek/src/megamek/client/ui/swing/GUIPreferences.java b/megamek/src/megamek/client/ui/swing/GUIPreferences.java
index ed7b7bf82f3..5193eae7648 100644
--- a/megamek/src/megamek/client/ui/swing/GUIPreferences.java
+++ b/megamek/src/megamek/client/ui/swing/GUIPreferences.java
@@ -295,6 +295,7 @@ public class GUIPreferences extends PreferenceStoreProxy {
     public static final String MINI_MAP_MOVE_PATH_PERSISTENCE = "MinimapMovePathPersistence";
     public static final String FIRE_DISPLAY_TAB_DURING_PHASES = "FireDisplayTabDuringPhases";
     public static final String MOVE_DISPLAY_TAB_DURING_PHASES = "MoveDisplayTabDuringPhases";
+    public static final String HIGH_PERFORMANCE_GRAPHICS = "HighPerformanceGraphics";
     public static final String MINIMUM_SIZE_HEIGHT = "MinimumSizeHeight";
     public static final String MINIMUM_SIZE_WIDTH = "MinimumSizeWidth";
     public static final String MOUSE_WHEEL_ZOOM = "MouseWheelZoom";
@@ -701,6 +702,7 @@ protected GUIPreferences() {
         store.setDefault(MINIMUM_SIZE_HEIGHT, 200);
         store.setDefault(MINIMUM_SIZE_WIDTH, 120);
 
+        store.setDefault(HIGH_PERFORMANCE_GRAPHICS, false);
         store.setDefault(MINI_REPORT_POS_X, 200);
         store.setDefault(MINI_REPORT_POS_Y, 150);
         store.setDefault(MINI_REPORT_SIZE_HEIGHT, 300);
@@ -3502,6 +3504,14 @@ public void setMovePathPersistenceOnMiniMap(int rounds) {
         store.setValue(MINI_MAP_MOVE_PATH_PERSISTENCE, rounds);
     }
 
+    public boolean getHighPerformanceGraphics() {
+        return getBoolean(HIGH_PERFORMANCE_GRAPHICS);
+    }
+
+    public void setHighPerformanceGraphics(boolean value) {
+        store.setValue(HIGH_PERFORMANCE_GRAPHICS, value);
+    }
+  
     public boolean getNagForOddSizedBoard() {
         return getBoolean(NAG_FOR_ODD_SIZED_BOARD);
     }
diff --git a/megamek/src/megamek/client/ui/swing/boardview/BoardView.java b/megamek/src/megamek/client/ui/swing/boardview/BoardView.java
index 9a423180c7a..196622a4523 100644
--- a/megamek/src/megamek/client/ui/swing/boardview/BoardView.java
+++ b/megamek/src/megamek/client/ui/swing/boardview/BoardView.java
@@ -981,13 +981,11 @@ public void draw(Graphics graphics) {
         if (!(graphics instanceof Graphics2D graphics2D)) {
             return;
         }
-
         if (GUIP.getShowFPS()) {
             paintCompsStartTime = System.nanoTime();
         }
 
         UIUtil.setHighQualityRendering(graphics2D);
-
         Rectangle viewRect = scrollPane.getVisibleRect();
 
         if (!isTileImagesLoaded()) {
diff --git a/megamek/src/megamek/client/ui/swing/lobby/ChatLounge.java b/megamek/src/megamek/client/ui/swing/lobby/ChatLounge.java
index 0e681e01701..4ac8d39f3e9 100644
--- a/megamek/src/megamek/client/ui/swing/lobby/ChatLounge.java
+++ b/megamek/src/megamek/client/ui/swing/lobby/ChatLounge.java
@@ -1123,7 +1123,7 @@ private void refreshBoardsAvailable() {
         java.util.List<String> availBoards = new ArrayList<>();
         availBoards.add(MapSettings.BOARD_GENERATED);
         availBoards.addAll(mapSettings.getBoardsAvailableVector());
-        refreshBoardTags();
+        refreshBoardTags(); // is this necessary?
         refreshBoardsAvailable(availBoards);
     }
 
diff --git a/megamek/src/megamek/client/ui/swing/util/UIUtil.java b/megamek/src/megamek/client/ui/swing/util/UIUtil.java
index 69dee5f1c24..a1809696698 100644
--- a/megamek/src/megamek/client/ui/swing/util/UIUtil.java
+++ b/megamek/src/megamek/client/ui/swing/util/UIUtil.java
@@ -675,10 +675,16 @@ public static void keepOnScreen(JFrame component) {
     public static void setHighQualityRendering(Graphics graph) {
         if (GUIPreferences.getInstance().getHighQualityGraphics()) {
             ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+            ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
             ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
                   RenderingHints.VALUE_FRACTIONALMETRICS_ON);
-            ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+        }
+        if (GUIPreferences.getInstance().getHighPerformanceGraphics()) {
+            ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
+            ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+                  RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+        } else if (GUIPreferences.getInstance().getHighQualityGraphics()) {
+            ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
             ((Graphics2D) graph).setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                   RenderingHints.VALUE_INTERPOLATION_BILINEAR);
         }
diff --git a/megamek/src/megamek/common/Board.java b/megamek/src/megamek/common/Board.java
index 2bbd2574e66..3a15a028dcd 100644
--- a/megamek/src/megamek/common/Board.java
+++ b/megamek/src/megamek/common/Board.java
@@ -871,6 +871,8 @@ public static Set<String> getTags(final File filepath) {
                     }
                 } else if ((st.ttype == StreamTokenizer.TT_WORD) && st.sval.equalsIgnoreCase("end")) {
                     break;
+                } else if ((st.ttype == StreamTokenizer.TT_WORD) && st.sval.equalsIgnoreCase("hex")) {
+                    break;
                 }
             }
         } catch (IOException ex) {
diff --git a/megamek/src/megamek/common/Hex.java b/megamek/src/megamek/common/Hex.java
index 2f28fcf04eb..18160e1c2e7 100644
--- a/megamek/src/megamek/common/Hex.java
+++ b/megamek/src/megamek/common/Hex.java
@@ -118,7 +118,12 @@ public void setTheme(String theme) {
      * @return An array that contains an id for each terrain present in this hex.
      */
     public int[] getTerrainTypes() {
-        return terrains.keySet().stream().mapToInt(Integer::intValue).toArray();
+        int[] result = new int[terrains.size()];
+        int i = 0;
+        for (Integer key : terrains.keySet()) {
+            result[i++] = key.intValue();
+        }
+        return result;
     }
 
     /**
diff --git a/megamek/src/megamek/common/board/postprocess/TWBoardTransformer.java b/megamek/src/megamek/common/board/postprocess/TWBoardTransformer.java
index 53999969911..53b67731b9f 100644
--- a/megamek/src/megamek/common/board/postprocess/TWBoardTransformer.java
+++ b/megamek/src/megamek/common/board/postprocess/TWBoardTransformer.java
@@ -44,10 +44,10 @@ public static Board instantiateBoard(MapSettings sourceMapSettings, PlanetaryCon
     private static Board setupBoardFromMapSettings(MapSettings mapSettings) {
         mapSettings.chooseSurpriseBoards();
         Board[] sheetBoards = new Board[mapSettings.getMapWidth() * mapSettings.getMapHeight()];
-        List<Boolean> rotateBoard = rotateBoards(mapSettings, sheetBoards);
+        rotateBoards(mapSettings, sheetBoards);
         return BoardUtilities.combine(mapSettings.getBoardWidth(),
             mapSettings.getBoardHeight(), mapSettings.getMapWidth(),
-            mapSettings.getMapHeight(), sheetBoards, rotateBoard,
+            mapSettings.getMapHeight(), sheetBoards,
             mapSettings.getMedium());
     }
 
@@ -68,8 +68,7 @@ private static void setupOptions(IGameOptions options, Board newBoard) {
         }
     }
 
-    private static List<Boolean> rotateBoards(MapSettings mapSettings, Board[] sheetBoards) {
-        List<Boolean> rotateBoard = new ArrayList<>();
+    private static void rotateBoards(MapSettings mapSettings, Board[] sheetBoards) {
         for (int i = 0; i < (mapSettings.getMapWidth() * mapSettings.getMapHeight()); i++) {
             sheetBoards[i] = new Board();
             // Need to set map type prior to loading to adjust foliage height, etc.
@@ -90,9 +89,7 @@ private static List<Boolean> rotateBoards(MapSettings mapSettings, Board[] sheet
                 sheetBoards[i].load(new MegaMekFile(Configuration.boardsDir(), name + ".board").getFile());
                 BoardUtilities.flip(sheetBoards[i], isRotated, isRotated);
             }
-            rotateBoard.add(isRotated);
         }
-        return rotateBoard;
     }
 
 }
diff --git a/megamek/src/megamek/common/jacksonadapters/BoardDeserializer.java b/megamek/src/megamek/common/jacksonadapters/BoardDeserializer.java
index 4273fdee589..41b121ea242 100644
--- a/megamek/src/megamek/common/jacksonadapters/BoardDeserializer.java
+++ b/megamek/src/megamek/common/jacksonadapters/BoardDeserializer.java
@@ -170,10 +170,7 @@ public static Board parseSingleBoard(JsonNode mapNode, File basePath) {
             if (boardsList.size() != columns * rows) {
                 throw new IllegalArgumentException("The number of given boards must give full rows!");
             }
-            List<Boolean> isRotatedList = new ArrayList<>();
-            Collections.fill(isRotatedList, Boolean.FALSE);
-            board = BoardUtilities.combine(mapWidth, mapHeight, columns, rows, boardsList, isRotatedList,
-                    Board.T_GROUND);
+            board = BoardUtilities.combine(mapWidth, mapHeight, columns, rows, boardsList.toArray(new Board[0]), Board.T_GROUND);
         }
         parseBoardProcessors(board, mapNode);
         return board;
diff --git a/megamek/src/megamek/common/scenario/ScenarioV1.java b/megamek/src/megamek/common/scenario/ScenarioV1.java
index 1c35064a8dd..f39badcacac 100644
--- a/megamek/src/megamek/common/scenario/ScenarioV1.java
+++ b/megamek/src/megamek/common/scenario/ScenarioV1.java
@@ -1027,7 +1027,6 @@ private Board createBoard(ScenarioV1 scenarioV1) throws ScenarioLoaderException
         Board[] ba = new Board[nWidth * nHeight];
         Queue<String> maps = new LinkedList<>(Arrays.asList(scenarioV1.getString(PARAM_MAPS)
                                                                   .split(SEPARATOR_COMMA, -1)));
-        List<Boolean> rotateBoard = new ArrayList<>();
         for (int x = 0; x < nWidth; x++) {
             for (int y = 0; y < nHeight; y++) {
                 int n = (y * nWidth) + x;
@@ -1067,7 +1066,6 @@ private Board createBoard(ScenarioV1 scenarioV1) throws ScenarioLoaderException
                 }
 
                 BoardUtilities.flip(ba[n], isRotated, isRotated);
-                rotateBoard.add(isRotated);
             }
         }
 
@@ -1077,7 +1075,7 @@ private Board createBoard(ScenarioV1 scenarioV1) throws ScenarioLoaderException
         }
 
         // construct the big board
-        return BoardUtilities.combine(mapWidth, mapHeight, nWidth, nHeight, ba, rotateBoard, MapSettings.MEDIUM_GROUND);
+        return BoardUtilities.combine(mapWidth, mapHeight, nWidth, nHeight, ba, MapSettings.MEDIUM_GROUND);
     }
 
     /**
diff --git a/megamek/src/megamek/common/util/BoardUtilities.java b/megamek/src/megamek/common/util/BoardUtilities.java
index 3c62b49a355..a0559b936ae 100644
--- a/megamek/src/megamek/common/util/BoardUtilities.java
+++ b/megamek/src/megamek/common/util/BoardUtilities.java
@@ -48,10 +48,27 @@ public static int getAmountElevationGenerators() {
      * @param boards a list of the boards to be combined
      * @param isRotated Flag that determines if any of the maps are rotated
      * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @deprecated Use the {{@link #combine(int, int, int, int, Board[], int)}
      */
+    @Deprecated(since="0.50.06", forRemoval = true)
     public static Board combine(int width, int height, int sheetWidth, int sheetHeight,
                                 List<Board> boards, List<Boolean> isRotated, int medium) {
-        return combine(width, height, sheetWidth, sheetHeight, boards.toArray(new Board[0]), isRotated, medium);
+        return combine(width, height, sheetWidth, sheetHeight, boards.toArray(new Board[0]), medium);
+    }
+
+    /**
+     * Combines one or more boards into one huge megaboard!
+     *
+     * @param width the width of each individual board, before the combine
+     * @param height the height of each individual board, before the combine
+     * @param sheetWidth how many sheets wide the combined map is
+     * @param sheetHeight how many sheets tall the combined map is
+     * @param boards an array of the boards to be combined
+     * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     */
+    public static Board combine(int width, int height, int sheetWidth, int sheetHeight,
+          Board[] boards, int medium) {
+        return combine(width, height, sheetWidth, sheetHeight, boards, medium, 1);
     }
 
     /**
@@ -64,34 +81,85 @@ public static Board combine(int width, int height, int sheetWidth, int sheetHeig
      * @param boards an array of the boards to be combined
      * @param isRotated Flag that determines if any of the maps are rotated
      * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @deprecated Use the {{@link #combine(int, int, int, int, Board[], int)}}
+     */
+    @Deprecated(since="0.50.06", forRemoval = true)
+    public static Board combine(int width, int height, int sheetWidth, int sheetHeight, Board[] boards,
+          List<Boolean> isRotated, int medium) {
+        return combine(width, height, sheetWidth, sheetHeight, boards, medium, 1);
+    }
+
+    private record PaddingArea(int startX, int startY, int columnPadding, int height){};
+
+    /**
+     * Combines one or more boards into one huge megaboard!
+     *
+     * @param width the width of each individual board, before the combine
+     * @param height the height of each individual board, before the combine
+     * @param sheetWidth how many sheets wide the combined map is
+     * @param sheetHeight how many sheets tall the combined map is
+     * @param boards an array of the boards to be combined
+     * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @param columnPaddingWidth Sets the padding width for the combined map
      */
     public static Board combine(int width, int height, int sheetWidth, int sheetHeight,
-                                Board[] boards, List<Boolean> isRotated, int medium) {
+          Board[] boards, int medium, int columnPaddingWidth) {
+
+        if (width < 1 || height < 1 || sheetWidth < 1 || sheetHeight < 1) {
+            throw new IllegalArgumentException("width, height, sheetWidth and sheetHeight must be >= 1");
+        }
+
+        final boolean widthIsOdd = width % 2 != 0;
+
+        // If width is odd, make sure padding is odd to maintain even starting positions
+        final int columnPadding = widthIsOdd ?
+                                        (columnPaddingWidth % 2 == 0 ? columnPaddingWidth + 1 : columnPaddingWidth) : 0;
+
+        // Calculate the total width with padding between boards
+        int paddingColumns = widthIsOdd ? (sheetWidth - 1) * columnPadding : 0;
+        List<PaddingArea> paddingAreas = new ArrayList<>();
+        int resultWidth = width * sheetWidth + paddingColumns;
 
-        int resultWidth = width * sheetWidth;
         int resultHeight = height * sheetHeight;
 
         Hex[] resultData = new Hex[resultWidth * resultHeight];
         boolean roadsAutoExit = true;
+
         // Copy the data from the sub-boards.
         for (int i = 0; i < sheetHeight; i++) {
             for (int j = 0; j < sheetWidth; j++) {
                 Board b = boards[i * sheetWidth + j];
                 if ((b.getWidth() != width) || (b.getHeight() != height)) {
                     throw new IllegalArgumentException(
-                            "board is the wrong size, expected " + width + "x"
-                                    + height + ", got " + b.getWidth() + "x"
-                                    + b.getHeight());
+                          "board is the wrong size, expected " + width + "x"
+                                + height + ", got " + b.getWidth() + "x"
+                                + b.getHeight());
                 }
-                copyBoardInto(resultData, resultWidth, j * width, i * height,
-                        boards[i * sheetWidth + j]);
+
+                // Calculate the x offset including padding
+                int xOffset = j * width;
+                if (widthIsOdd) {
+                    xOffset += j * columnPadding;
+                }
+
+                copyBoardInto(resultData, resultWidth, xOffset, i * height, b);
+
                 // Copy in the other board's options.
-                if (!boards[i * sheetWidth + j].getRoadsAutoExit()) {
+                if (!b.getRoadsAutoExit()) {
                     roadsAutoExit = false;
                 }
+                // Fill the padding area with generated terrain if needed
+                if (widthIsOdd && j < sheetWidth - 1) {
+                    paddingAreas.add(new PaddingArea(xOffset + width, i*height, columnPadding, height));
+                }
             }
         }
 
+        for (var paddingArea : paddingAreas) {
+            fillPaddingArea(resultData, resultWidth, paddingArea.startX(), paddingArea.startY(),
+                  paddingArea.columnPadding(), paddingArea.height());
+        }
+
         Board result = new Board();
         result.setRoadsAutoExit(roadsAutoExit);
         // Initialize all hexes - buildings, exits, etc
@@ -103,6 +171,147 @@ public static Board combine(int width, int height, int sheetWidth, int sheetHeig
         return result;
     }
 
+    /**
+     * Fills the padding area between boards with generated terrain.
+     *
+     * @param resultData The combined board data array
+     * @param resultWidth The width of the combined board
+     * @param startX The starting X coordinate of the padding area
+     * @param startY The starting Y coordinate of the padding area
+     * @param paddingWidth The width of the padding area
+     * @param height The height of the padding area
+     */
+    private static void fillPaddingArea(Hex[] resultData, int resultWidth, int startX, int startY,
+          int paddingWidth, int height) {
+        // For each row
+        for (int y = 0; y < height; y++) {
+            // Get hexes at both sides of the padding area for this row
+            int leftIndex = (startY + y) * resultWidth + (startX - 1);
+            int rightIndex = (startY + y) * resultWidth + (startX + paddingWidth);
+
+            Hex leftHex = (leftIndex >= 0 && leftIndex < resultData.length) ? resultData[leftIndex] : null;
+            Hex rightHex = (rightIndex >= 0 && rightIndex < resultData.length) ? resultData[rightIndex] : null;
+
+            // Skip if both sides are null (shouldn't happen in normal cases), never any of those should be null, but
+            // whatever.
+            if (leftHex == null && rightHex == null) {
+                continue;
+            }
+
+            // Determine base elevation for interpolation
+            int leftElev = leftHex != null ? leftHex.getLevel() : 0;
+            int rightElev = rightHex != null ? rightHex.getLevel() : 0;
+
+            // Check for water on both sides
+            boolean leftHasWater = leftHex != null && leftHex.containsTerrain(Terrains.WATER);
+            boolean rightHasWater = rightHex != null && rightHex.containsTerrain(Terrains.WATER);
+            int leftWaterDepth = leftHasWater ? leftHex.depth() : 0;
+            int rightWaterDepth = rightHasWater ? rightHex.depth() : 0;
+
+            // Collect terrain types from adjacent boards (excluding buildings and other restricted terrains)
+            Set<Integer> availableTerrains = new HashSet<>();
+            if (leftHex != null) {
+                for (int terrainType : leftHex.getTerrainTypes()) {
+                    // Skip buildings, bridges, fuel tanks, etc.
+                    if (!Terrains.HAZARDS.contains(terrainType)) {
+                        availableTerrains.add(terrainType);
+                    }
+                }
+            }
+            if (rightHex != null) {
+                for (int terrainType : rightHex.getTerrainTypes()) {
+                    // Skip buildings, bridges, fuel tanks, etc.
+                    if (!Terrains.HAZARDS.contains(terrainType)) {
+                        availableTerrains.add(terrainType);
+                    }
+                }
+            }
+
+            // Fill the padding for this row
+            for (int x = 0; x < paddingWidth; x++) {
+                int index = (startY + y) * resultWidth + (startX + x);
+
+                // Create a new hex
+                Hex hex = new Hex();
+
+                // Linear interpolation of elevation
+                double lerpFactor = (double) (x + 1) / (paddingWidth + 1);
+                int elevDiff = rightElev - leftElev;
+                int interpolatedElev = leftElev + (int) Math.round(elevDiff * lerpFactor);
+                hex.setLevel(interpolatedElev);
+
+                // Handle water terrain
+                if (leftHasWater && rightHasWater) {
+                    // Interpolate water depth if both sides have water
+                    int waterDepthDiff = rightWaterDepth - leftWaterDepth;
+                    int interpolatedDepth = leftWaterDepth + (int) Math.round(waterDepthDiff * lerpFactor);
+                    hex.addTerrain(new Terrain(Terrains.WATER, interpolatedDepth));
+                } else if (leftHasWater) {
+                    // Extend water from left side with decreasing depth
+                    int adjustedDepth = Math.max(1, leftWaterDepth - (int) Math.round(leftWaterDepth * lerpFactor));
+                    hex.addTerrain(new Terrain(Terrains.WATER, adjustedDepth));
+                } else if (rightHasWater) {
+                    // Extend water from right side with decreasing depth
+                    int adjustedDepth = Math.max(1, rightWaterDepth - (int) Math.round(rightWaterDepth * (1 - lerpFactor)));
+                    hex.addTerrain(new Terrain(Terrains.WATER, adjustedDepth));
+                } else {
+                    // Add some standard terrain types based on available terrains from adjacent boards
+                    boolean terrainAdded = false;
+
+                    // Try to add a terrain from the available terrains (with 60% chance)
+                    if (!availableTerrains.isEmpty() && Compute.randomInt(100) < 60) {
+                        // Convert set to array and pick a random terrain type
+                        Integer[] terrainArray = availableTerrains.toArray(new Integer[0]);
+                        int randomTerrainType = terrainArray[Compute.randomInt(terrainArray.length)];
+
+                        // For specific terrain types, add them with appropriate levels
+                        switch (randomTerrainType) {
+                            case Terrains.WOODS:
+                                hex.addTerrain(new Terrain(Terrains.WOODS, 1));
+                                hex.addTerrain(new Terrain(Terrains.FOLIAGE_ELEV, 2));
+                                terrainAdded = true;
+                                break;
+                            case Terrains.ROUGH:
+                                hex.addTerrain(new Terrain(Terrains.ROUGH, 1));
+                                terrainAdded = true;
+                                break;
+                            case Terrains.SAND:
+                            case Terrains.SNOW:
+                            case Terrains.MUD:
+                            case Terrains.TUNDRA:
+                            case Terrains.SWAMP:
+                            case Terrains.ICE:
+                            case Terrains.PAVEMENT:
+                            case Terrains.FIELDS:
+                                hex.addTerrain(new Terrain(randomTerrainType, 1));
+                                terrainAdded = true;
+                                break;
+                            case Terrains.JUNGLE:
+                                hex.addTerrain(new Terrain(Terrains.JUNGLE, 1));
+                                hex.addTerrain(new Terrain(Terrains.FOLIAGE_ELEV, 2));
+                                terrainAdded = true;
+                                break;
+                        }
+                    }
+
+                    // If no terrain was added, consider adding a random basic terrain
+                    if (!terrainAdded) {
+                        if (Compute.randomInt(100) < 20) {
+                            // 20% chance of woods
+                            hex.addTerrain(new Terrain(Terrains.WOODS, 1));
+                            hex.addTerrain(new Terrain(Terrains.FOLIAGE_ELEV, 2));
+                        } else if (Compute.randomInt(100) < 15) {
+                            // 15% chance of rough
+                            hex.addTerrain(new Terrain(Terrains.ROUGH, 1));
+                        }
+                    }
+                }
+
+                resultData[index] = hex;
+            }
+        }
+    }
+
     /**
      * Copies the data of another board into given array of Hexes, offset by the
      * specified x and y.
diff --git a/megamek/src/megamek/server/ServerBoardHelper.java b/megamek/src/megamek/server/ServerBoardHelper.java
index ef13934437d..c86999d650d 100644
--- a/megamek/src/megamek/server/ServerBoardHelper.java
+++ b/megamek/src/megamek/server/ServerBoardHelper.java
@@ -34,6 +34,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -109,7 +110,7 @@ private static void scanForBoardsInDir(final File boardDir, final String basePat
     public static Board getPossibleGameBoard(MapSettings mapSettings, boolean onlyFixedBoards) {
         mapSettings.replaceBoardWithRandom(MapSettings.BOARD_SURPRISE);
         Board[] sheetBoards = new Board[mapSettings.getMapWidth() * mapSettings.getMapHeight()];
-        List<Boolean> rotateBoard = new ArrayList<>();
+
         for (int i = 0; i < (mapSettings.getMapWidth() * mapSettings.getMapHeight()); i++) {
             sheetBoards[i] = new Board();
 
@@ -143,8 +144,7 @@ public static Board getPossibleGameBoard(MapSettings mapSettings, boolean onlyFi
         Board finalBoard;
         try {
             finalBoard = BoardUtilities.combine(mapSettings.getBoardWidth(), mapSettings.getBoardHeight(),
-                  mapSettings.getMapWidth(), mapSettings.getMapHeight(), sheetBoards, rotateBoard,
-                  mapSettings.getMedium());
+                  mapSettings.getMapWidth(), mapSettings.getMapHeight(), sheetBoards, mapSettings.getMedium());
         } catch (IllegalArgumentException ex) {
             int totalWidth = mapSettings.getMapWidth() * mapSettings.getBoardWidth();
             int totalHeight = mapSettings.getMapHeight() * mapSettings.getBoardHeight();
@@ -159,4 +159,4 @@ public static Board getPossibleGameBoard(MapSettings mapSettings, boolean onlyFi
     }
 
     private ServerBoardHelper() { }
-}
\ No newline at end of file
+}
diff --git a/megamek/src/megamek/server/totalwarfare/TWGameManager.java b/megamek/src/megamek/server/totalwarfare/TWGameManager.java
index 2219be9c566..a5e614ac94c 100644
--- a/megamek/src/megamek/server/totalwarfare/TWGameManager.java
+++ b/megamek/src/megamek/server/totalwarfare/TWGameManager.java
@@ -2329,7 +2329,6 @@ public void applyBoardSettings() {
         MapSettings mapSettings = game.getMapSettings();
         mapSettings.chooseSurpriseBoards();
         Board[] sheetBoards = new Board[mapSettings.getMapWidth() * mapSettings.getMapHeight()];
-        List<Boolean> rotateBoard = new ArrayList<>();
         for (int i = 0; i < (mapSettings.getMapWidth() * mapSettings.getMapHeight()); i++) {
             sheetBoards[i] = new Board();
             // Need to set map type prior to loading to adjust foliage height, etc.
@@ -2349,14 +2348,12 @@ public void applyBoardSettings() {
                 sheetBoards[i].load(new MegaMekFile(Configuration.boardsDir(), name + ".board").getFile());
                 BoardUtilities.flip(sheetBoards[i], isRotated, isRotated);
             }
-            rotateBoard.add(isRotated);
         }
         Board newBoard = BoardUtilities.combine(mapSettings.getBoardWidth(),
               mapSettings.getBoardHeight(),
               mapSettings.getMapWidth(),
               mapSettings.getMapHeight(),
               sheetBoards,
-              rotateBoard,
               mapSettings.getMedium());
         if (game.getOptions().getOption(OptionsConstants.BASE_BRIDGECF).intValue() > 0) {
             newBoard.setBridgeCF(game.getOptions().getOption(OptionsConstants.BASE_BRIDGECF).intValue());


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR enhances board handling by adding configurable padding between maps when board widths are odd, ensuring proper tiling, and also includes minor performance improvements and UI updates.  
- Removed obsolete rotateBoard lists and updated calls to BoardUtilities.combine to use the new padding approach.  
- Added support for a high performance graphics option with its associated UI elements.  
- Made minor adjustments in Hex grid handling and additional cleanup in deployment and UI dialogs.

### Reviewed Changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 2 comments.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| TWGameManager.java | Removed rotateBoard list usage in board combining. |
| ServerBoardHelper.java | Adjusted combine() call to drop rotateBoard list. |
| BoardUtilities.java | Added new combine() overload with padding support and deprecated legacy methods. |
| ScenarioV1.java | Removed rotateBoard list from board creation. |
| BoardDeserializer.java | Updated combine call to array-based version. |
| TWBoardTransformer.java | Removed rotateBoards return value and refactored accordingly. |
| Hex.java | Replaced stream-based map-to-array conversion with an explicit loop. |
| Board.java | Added early break when “hex” tag is encountered in getTags(). |
| UIUtil.java | Updated rendering hints handling with separate paths for high quality and high performance graphics. |
| ChatLounge.java | Minor change to board tag refresh call (with inline comment “is this necessary?”). |
| BoardView.java | Removed redundant blank line before drawing. |
| GUIPreferences.java | Added new HIGH_PERFORMANCE_GRAPHICS setting with corresponding getter/setter. |
| CommonSettingsDialog.java | Added checkbox for high performance graphics with tooltip and updated layout. |
| BoardEditor.java | Updated combine() call to remove unused rotateBoard parameter. |
</details>


<details>
<summary>Files not reviewed (1)</summary>

* **megamek/i18n/megamek/client/messages.properties**: Language not supported
</details>



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-03T06:08:53Z
user: login: Scoppio
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-03T06:19:12Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-03T06:19:50Z
user: login: Scoppio
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-03T20:03:44Z
user: login: rjhancock
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-03T20:41:29Z

Review comments:
diff_hunk: @@ -2966,6 +2970,8 @@ public void itemStateChanged(ItemEvent event) {
             GUIP.setShowDamageLevel(showDamageLevel.isSelected());
         } else if (source.equals(chkHighQualityGraphics)) {
             GUIP.setHighQualityGraphics(chkHighQualityGraphics.isSelected());
+        } else if (source.equals(chkHighPerformanceGraphics)) {
+            GUIP.setHighQualityGraphics(chkHighPerformanceGraphics.isSelected());
path: megamek/src/megamek/client/ui/swing/CommonSettingsDialog.java
user: login: Copilot
body: The high performance graphics checkbox is currently setting high quality graphics. Please update this call to use 'GUIP.setHighPerformanceGraphics(chkHighPerformanceGraphics.isSelected())' so that the correct graphics mode is applied.
```suggestion
            GUIP.setHighPerformanceGraphics(chkHighPerformanceGraphics.isSelected());
```
created_at: 2025-05-03T06:08:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1120,7 +1120,7 @@ private void refreshBoardsAvailable() {
         java.util.List<String> availBoards = new ArrayList<>();
         availBoards.add(MapSettings.BOARD_GENERATED);
         availBoards.addAll(mapSettings.getBoardsAvailableVector());
-        refreshBoardTags();
+        refreshBoardTags(); // is this necessary?
path: megamek/src/megamek/client/ui/swing/lobby/ChatLounge.java
user: login: Copilot
body: [nitpick] Consider removing or clarifying the 'is this necessary?' comment if the refreshBoardTags() call is essential for functionality, to keep the codebase clean.
```suggestion
        // Update board tags to ensure they are in sync with the available boards.
        refreshBoardTags();
```
created_at: 2025-05-03T06:08:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,34 +81,85 @@ public static Board combine(int width, int height, int sheetWidth, int sheetHeig
      * @param boards an array of the boards to be combined
      * @param isRotated Flag that determines if any of the maps are rotated
      * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @deprecated Use the {{@link #combine(int, int, int, int, Board[], int)}}
+     */
+    @Deprecated(since="0.50.06", forRemoval = true)
+    public static Board combine(int width, int height, int sheetWidth, int sheetHeight, Board[] boards,
+          List<Boolean> isRotated, int medium) {
+        return combine(width, height, sheetWidth, sheetHeight, boards, medium, 1);
+    }
+
+    private record PaddingArea(int startX, int startY, int columnPadding, int height){};
+
+    /**
+     * Combines one or more boards into one huge megaboard!
+     *
+     * @param width the width of each individual board, before the combine
+     * @param height the height of each individual board, before the combine
+     * @param sheetWidth how many sheets wide the combined map is
+     * @param sheetHeight how many sheets tall the combined map is
+     * @param boards an array of the boards to be combined
+     * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @param columnPaddingWidth Sets the padding width for the combined map
      */
     public static Board combine(int width, int height, int sheetWidth, int sheetHeight,
-                                Board[] boards, List<Boolean> isRotated, int medium) {
path: megamek/src/megamek/common/util/BoardUtilities.java
user: login: Scoppio
body: isRotated was not used by this function, apparently it's just an old appendage that made sense sometime in the past.
created_at: 2025-05-03T06:19:11Z
author_association: COLLABORATOR
diff_hunk: @@ -64,34 +81,85 @@
      * @param boards an array of the boards to be combined
      * @param isRotated Flag that determines if any of the maps are rotated
      * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @deprecated Use the {{@link #combine(int, int, int, int, Board[], int)}}
+     */
+    @Deprecated(since="0.50.06", forRemoval = true)
+    public static Board combine(int width, int height, int sheetWidth, int sheetHeight, Board[] boards,
+          List<Boolean> isRotated, int medium) {
path: megamek/src/megamek/common/util/BoardUtilities.java
user: login: github-advanced-security[bot]
body: ## Useless parameter

The parameter 'isRotated' is never used.

[Show more details](https://github.com/MegaMek/megamek/security/code-scanning/8353)
created_at: 2025-05-03T06:19:50Z
author_association: NONE
diff_hunk: @@ -64,34 +81,85 @@
      * @param boards an array of the boards to be combined
      * @param isRotated Flag that determines if any of the maps are rotated
      * @param medium Sets the medium the map is in (ie., ground, atmo, space)
+     * @deprecated Use the {{@link #combine(int, int, int, int, Board[], int)}}
+     */
+    @Deprecated(since="0.50.06", forRemoval = true)
+    public static Board combine(int width, int height, int sheetWidth, int sheetHeight, Board[] boards,
+          List<Boolean> isRotated, int medium) {
path: megamek/src/megamek/common/util/BoardUtilities.java
user: login: Scoppio
body: Known issue, which is why this is marked as deprecated
created_at: 2025-05-03T20:03:44Z
author_association: COLLABORATOR

PR comments:
user: login: codecov[bot]
created_at: 2025-05-03T06:18:09Z
body: ## [Codecov](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) Report
Attention: Patch coverage is `0.82645%` with `120 lines` in your changes missing coverage. Please review.
> Project coverage is 30.31%. Comparing base [(`aa956ee`)](https://app.codecov.io/gh/MegaMek/megamek/commit/aa956ee3f18db5c2a1df3f584656d26a84289059?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) to head [(`598329c`)](https://app.codecov.io/gh/MegaMek/megamek/commit/598329cd0f36e003786a27bc4646297585cfa0b5?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek).
> Report is 231 commits behind head on master.

| [Files with missing lines](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) | Patch % | Lines |
|---|---|---|
| [...egamek/src/megamek/common/util/BoardUtilities.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fcommon%2Futil%2FBoardUtilities.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jb21tb24vdXRpbC9Cb2FyZFV0aWxpdGllcy5qYXZh) | 0.00% | [91 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [.../megamek/client/ui/swing/CommonSettingsDialog.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fclient%2Fui%2Fswing%2FCommonSettingsDialog.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jbGllbnQvdWkvc3dpbmcvQ29tbW9uU2V0dGluZ3NEaWFsb2cuamF2YQ==) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [...gamek/src/megamek/client/ui/swing/util/UIUtil.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fclient%2Fui%2Fswing%2Futil%2FUIUtil.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jbGllbnQvdWkvc3dpbmcvdXRpbC9VSVV0aWwuamF2YQ==) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [megamek/src/megamek/common/Hex.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fcommon%2FHex.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jb21tb24vSGV4LmphdmE=) | 0.00% | [6 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [...ek/src/megamek/client/ui/swing/GUIPreferences.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fclient%2Fui%2Fswing%2FGUIPreferences.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jbGllbnQvdWkvc3dpbmcvR1VJUHJlZmVyZW5jZXMuamF2YQ==) | 25.00% | [3 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [megamek/src/megamek/common/Board.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fcommon%2FBoard.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jb21tb24vQm9hcmQuamF2YQ==) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [...k/common/board/postprocess/TWBoardTransformer.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fcommon%2Fboard%2Fpostprocess%2FTWBoardTransformer.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jb21tb24vYm9hcmQvcG9zdHByb2Nlc3MvVFdCb2FyZFRyYW5zZm9ybWVyLmphdmE=) | 0.00% | [2 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [.../src/megamek/client/ui/swing/lobby/ChatLounge.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fclient%2Fui%2Fswing%2Flobby%2FChatLounge.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jbGllbnQvdWkvc3dpbmcvbG9iYnkvQ2hhdExvdW5nZS5qYXZh) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [...amek/common/jacksonadapters/BoardDeserializer.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fcommon%2Fjacksonadapters%2FBoardDeserializer.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jb21tb24vamFja3NvbmFkYXB0ZXJzL0JvYXJkRGVzZXJpYWxpemVyLmphdmE=) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| [...egamek/src/megamek/common/scenario/ScenarioV1.java](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&filepath=megamek%2Fsrc%2Fmegamek%2Fcommon%2Fscenario%2FScenarioV1.java&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek#diff-bWVnYW1lay9zcmMvbWVnYW1lay9jb21tb24vc2NlbmFyaW8vU2NlbmFyaW9WMS5qYXZh) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) |
| ... and [1 more](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek) | |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##             master    #6971      +/-   ##
============================================
- Coverage     30.32%   30.31%   -0.02%     
+ Complexity    15855    15849       -6     
============================================
  Files          2890     2890              
  Lines        283352   283447      +95     
  Branches      49313    49348      +35     
============================================
- Hits          85927    85913      -14     
- Misses       191799   191912     +113     
+ Partials       5626     5622       -4     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/MegaMek/megamek/pull/6971?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MegaMek).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: rjhancock
created_at: 2025-05-03T20:42:35Z
body: Im hesitant to merge this one for the .06 release. These are nice additions but it's also adding a new feature, so to speak.
author_association: COLLABORATOR
user: login: Scoppio
created_at: 2025-05-04T05:30:54Z
body: > Im hesitant to merge this one for the .06 release. These are nice additions but it's also adding a new feature, so to speak.

In that case, I am reopening my previous PR which added the warning nag for users advising them for not selecting odd width boards for tiling maps together.
author_association: COLLABORATOR