/**
* Copyright 2014
* SMEdit https://github.com/StarMade/SMEdit
* SMTools https://github.com/StarMade/SMTools
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
**/
package jo.sm.plugins.ship.fill;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import jo.sm.data.BlockTypes;
import jo.sm.data.BooleanMatrix3D;
import jo.sm.data.CubeIterator;
import jo.sm.data.SparseMatrix;
import jo.sm.data.StarMade;
import jo.sm.mods.IBlocksPlugin;
import jo.sm.mods.IPluginCallback;
import jo.sm.ship.data.Block;
import jo.sm.ship.logic.HullLogic;
import jo.vecmath.Point3i;
/**
* @Auther Jo Jaquinta for SMEdit Classic - version 1.0
**/
public class DeckPlugin implements IBlocksPlugin {
public static final String NAME = "Decks";
public static final String DESC = "Fill Ship Interior with Decks";
public static final String AUTH = "Jo Jaquinta";
public static final int[][] CLASSIFICATIONS
= {
{TYPE_SHIP, SUBTYPE_MODIFY},
{TYPE_STATION, SUBTYPE_MODIFY},};
@Override
public String getName() {
return NAME;
}
@Override
public String getDescription() {
return DESC;
}
@Override
public String getAuthor() {
return AUTH;
}
@Override
public Object newParameterBean() {
return new DeckParameters();
}
@Override
public void initParameterBean(SparseMatrix<Block> original, Object params,
StarMade sm, IPluginCallback cb) {
}
@Override
public int[][] getClassifications() {
return CLASSIFICATIONS;
}
@Override
public SparseMatrix<Block> modify(SparseMatrix<Block> original,
Object p, StarMade sm, IPluginCallback cb) {
DeckParameters params;
params = (DeckParameters) p;
SparseMatrix<Block> modified;
modified = new SparseMatrix<>(original);
Point3i lower;
lower = new Point3i();
Point3i upper;
upper = new Point3i();
List<Point3i> interior;
interior = new ArrayList<>();
findInterior(original, sm, cb, modified, lower, upper, interior);
Set<Integer> deckYs;
deckYs = new HashSet<>();
placeDecks(cb, params, modified, lower, upper, interior, deckYs);
if (params.getStairwellWidth() > 0) {
placeStairs(cb, params, modified, lower, upper, interior, deckYs);
}
return modified;
}
private void placeStairs(IPluginCallback cb, DeckParameters params,
SparseMatrix<Block> modified, Point3i lower, Point3i upper,
List<Point3i> interior, Set<Integer> deckYs) {
int sx;
sx = params.getStairwellWidth();
int sy;
sy = params.getSpace() + params.getThickness();
int sz;
sz = sy;
Set<Integer> xs;
xs = new HashSet<>();
int firstX;
firstX = 8 - params.getStairwellXGap() / 2 - sx;
for (int x = firstX; x < upper.x; x += sx + params.getStairwellXGap()) {
xs.add(x);
}
for (int x = firstX - sx - params.getStairwellXGap(); x >= lower.x; x -= sx + params.getStairwellXGap()) {
xs.add(x);
}
Set<Integer> zs = new HashSet<>();
int firstZ = 8 - params.getStairwellZGap() / 2 - sz;
for (int z = firstZ; z < upper.z; z += sz + params.getStairwellZGap()) {
zs.add(z);
}
for (int z = firstZ - sz - params.getStairwellZGap(); z >= lower.z; z -= sz + params.getStairwellZGap()) {
zs.add(z);
}
cb.setStatus("Placing stairs");
cb.startTask(deckYs.size());
short tred = params.getMaterial();
if (BlockTypes.isAnyHull(tred)) {
tred = BlockTypes.getColoredBlock(BlockTypes.HULL_COLOR_WEDGE_GREY_ID, BlockTypes.getColor(tred));
} else {
tred = BlockTypes.HULL_COLOR_WEDGE_GREY_ID;
}
for (Integer y : deckYs) {
if (y + sy >= upper.y) {
continue;
}
for (Integer x : xs) {
for (Integer z : zs) {
placeStair(modified, x, y + params.getThickness(), z, interior, tred, sx, sy, sz);
}
}
cb.workTask(1);
}
cb.endTask();
}
private void placeStair(SparseMatrix<Block> grid, int baseX, int baseY,
int baseZ, List<Point3i> interior, short material, int sizeX, int sizeY,
int sizeZ) {
for (int y = 0; y < sizeY; y++) {
for (int x = 0; x < sizeX; x++) {
Point3i p;
p = new Point3i(baseX + x, baseY + y, baseZ + y);
placeIfInterior(grid, p, interior, material);
for (int v = y + 1; v < sizeY; v++) {
p.y = baseY + v;
removeIfInterior(grid, p, interior);
}
}
}
}
private void placeIfInterior(SparseMatrix<Block> grid, Point3i p,
List<Point3i> interior, short material) {
if (interior.contains(p)) {
grid.set(p, new Block(material));
}
}
private void removeIfInterior(SparseMatrix<Block> grid, Point3i p,
List<Point3i> interior) {
if (interior.contains(p)) {
grid.set(p, null);
}
}
private void findInterior(SparseMatrix<Block> original, StarMade sm,
IPluginCallback cb, SparseMatrix<Block> modified, Point3i lower,
Point3i upper, List<Point3i> interior) {
if ((sm.getSelectedLower() != null) && (sm.getSelectedUpper() != null)) {
lower.set(sm.getSelectedLower());
upper.set(sm.getSelectedUpper());
for (Iterator<Point3i> i = new CubeIterator(lower, upper); i.hasNext();) {
Point3i xyz = i.next();
if (!original.contains(xyz)) {
interior.add(xyz);
}
}
} else {
BooleanMatrix3D exterior = HullLogic.findExteriorMatrix(original, cb);
//Set<Point3i> exterior;
//exterior = HullLogic.findExterior(original, cb);
original.getBounds(lower, upper);
scopeInterior(modified, interior, exterior, lower, upper, cb);
}
}
private void placeDecks(IPluginCallback cb, DeckParameters params,
SparseMatrix<Block> modified, Point3i lower, Point3i upper,
List<Point3i> interior, Set<Integer> ys) {
int firstY;
firstY = 8 - params.getSpace() / 2 - params.getThickness();
// upper decks
for (int y = firstY; y < upper.y; y += params.getThickness() + params.getSpace()) {
ys.add(y);
}
// lower decks
for (int y = firstY - params.getThickness() - params.getSpace(); y >= lower.y; y -= params.getThickness() + params.getSpace()) {
ys.add(y);
}
cb.setStatus("Placing decks");
cb.startTask(ys.size());
for (Integer y : ys) {
for (int t = 0; t < params.getThickness(); t++) {
placeDeck(modified, y, interior, params.getMaterial());
}
cb.workTask(1);
}
cb.endTask();
}
private void placeDeck(SparseMatrix<Block> grid, int y,
List<Point3i> interior, short material) {
for (Point3i p : interior) {
if (p.y == y) {
grid.set(p, new Block(material));
}
}
}
private void scopeInterior(SparseMatrix<Block> grid, List<Point3i> interior,
BooleanMatrix3D exterior, Point3i lower, Point3i upper,
IPluginCallback cb) {
cb.setStatus("Calculating interior");
cb.startTask(grid.size());
for (Iterator<Point3i> i = grid.iterator(); i.hasNext();) {
Point3i p = i.next();
if (exterior.contains(p)) {
continue;
}
Block b = grid.get(p);
if (b == null) {
interior.add(p);
}
}
cb.endTask();
}
}