/** * 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.factories.planet.comp; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; 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.vecmath.Point3i; /** * @Auther Jo Jaquinta for SMEdit Classic - version 1.0 **/ public class MaterialPlugin implements IBlocksPlugin { private final MaterialDefinition mDef; private final Random mRND; private final Map<Short, MaterialEntry> mOldBlockMap; public MaterialPlugin(MaterialDefinition def) { mDef = def; mOldBlockMap = makeBlockMap(mDef.getOldBlocks()); mRND = new Random(); } private Map<Short, MaterialEntry> makeBlockMap(List<MaterialEntry> blocks) { Map<Short, MaterialEntry> blockMap = new HashMap<>(); for (MaterialEntry entry : blocks) { blockMap.put(entry.getBlockID(), entry); } return blockMap; } @Override public String getName() { return mDef.getTitle(); } @Override public String getDescription() { return mDef.getDescription(); } @Override public String getAuthor() { return mDef.getAuthor(); } @Override public Object newParameterBean() { return null; } @Override public void initParameterBean(SparseMatrix<Block> original, Object params, StarMade sm, IPluginCallback cb) { } @Override public int[][] getClassifications() { int[][] classifications = new int[][]{ {TYPE_FLOATINGROCK, SUBTYPE_GENERATE, mDef.getPriority()}, {TYPE_PLANET, SUBTYPE_GENERATE, mDef.getPriority()},}; return classifications; } @Override public SparseMatrix<Block> modify(SparseMatrix<Block> original, Object params, StarMade sm, IPluginCallback cb) { SparseMatrix<Block> modified = new SparseMatrix<>(original); Point3i lower = new Point3i(); Point3i upper = new Point3i(); original.getBounds(lower, upper); cb.setStatus("Altering Composition"); cb.startTask(upper.x - lower.x + 1); for (int x = lower.x; x <= upper.x; x++) { for (int z = lower.z; z <= upper.z; z++) { int lowY = getLowY(original, x, z, lower.y, upper.y); if (lowY < lower.y) { continue; } int highY = getHighY(original, x, z, lower.y, upper.y); if (highY > upper.y) { continue; } for (int y = lowY; y <= highY; y++) { Block b = original.get(x, y, z); if (b == null) { continue; } if (doWeReplace(y, lowY, highY, b)) { modified.set(x, y, z, replaceWith(y, lowY, highY, b)); } } } cb.workTask(1); } cb.endTask(); return modified; } private int getLowY(SparseMatrix<Block> grid, int x, int z, int y1, int y2) { for (int y = y1; y <= y2; y++) { if (grid.contains(x, y, z)) { return y; } } return y1 - 1; } private int getHighY(SparseMatrix<Block> grid, int x, int z, int y1, int y2) { for (int y = y2; y >= y1; y--) { if (grid.contains(x, y, z)) { return y; } } return y2 + 1; } private boolean doWeReplace(int y, int lowY, int highY, Block b) { MaterialEntry oldEntry = mOldBlockMap.get(b.getBlockID()); if (oldEntry == null) { oldEntry = mOldBlockMap.get(-1); if (oldEntry == null) { return false; } } if (!isWithinBounds(y, lowY, highY, oldEntry)) { return false; } return mRND.nextInt(100) <= oldEntry.getPercent(); } private Block replaceWith(int y, int lowY, int highY, Block b) { List<MaterialEntry> probs = new ArrayList<>(); int total = 0; for (MaterialEntry entry : mDef.getNewBlocks()) { if (isWithinBounds(y, lowY, highY, entry)) { probs.add(entry); total += entry.getPercent(); } } if (total == 0) { return null; } int roll = mRND.nextInt(total); for (MaterialEntry entry : probs) { roll -= entry.getPercent(); if (roll < 0) { return new Block(entry.getBlockID()); } } throw new IllegalStateException("We fell off the bottom!"); } private boolean isWithinBounds(int y, int lowY, int highY, MaterialEntry entry) { int lowLimit = getLimit(lowY, highY, entry.getLowStrategy(), entry.getLowValue()); int highLimit = getLimit(lowY, highY, entry.getHighStrategy(), entry.getHighValue()); return (y >= lowLimit) && (y <= highLimit); } private int getLimit(int lowY, int highY, int strategy, int value) { if (strategy == MaterialEntry.RELATIVE) { if (value >= 0) { return lowY + value; // offset from top } else { return highY + value; // offset from bottom } } else { int delta = highY - lowY; int abs = delta * value / 100; return lowY + abs; } } }