Java tutorial
/* * The MIT License (MIT) * * Copyright (c) 2014 The Voxel Plugineering Team * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.voxelplugineering.voxelsniper.brush.effect; import java.util.Map; import com.google.common.base.Optional; import com.google.common.collect.Maps; import com.voxelplugineering.voxelsniper.brush.AbstractBrush; import com.voxelplugineering.voxelsniper.brush.BrushKeys; import com.voxelplugineering.voxelsniper.brush.BrushPartType; import com.voxelplugineering.voxelsniper.brush.BrushVars; import com.voxelplugineering.voxelsniper.brush.ExecutionResult; import com.voxelplugineering.voxelsniper.entity.Player; import com.voxelplugineering.voxelsniper.shape.ComplexMaterialShape; import com.voxelplugineering.voxelsniper.shape.MaterialShape; import com.voxelplugineering.voxelsniper.shape.Shape; import com.voxelplugineering.voxelsniper.shape.csg.CuboidShape; import com.voxelplugineering.voxelsniper.shape.csg.PrimativeShapeFactory; import com.voxelplugineering.voxelsniper.util.math.Maths; import com.voxelplugineering.voxelsniper.util.math.Vector3i; import com.voxelplugineering.voxelsniper.world.Block; import com.voxelplugineering.voxelsniper.world.Location; import com.voxelplugineering.voxelsniper.world.World; import com.voxelplugineering.voxelsniper.world.material.Material; import com.voxelplugineering.voxelsniper.world.queue.ShapeChangeQueue; /** * The blend brush. An effect brush which performs a 'blend' operation by * setting blocks in the defined region to the mode material of the surrounding * materials. */ public class OldBlendBrush extends AbstractBrush { /** * Creates a new {@link OldBlendBrush}. */ public OldBlendBrush() { super("blend", BrushPartType.EFFECT); } @Override public ExecutionResult run(Player player, BrushVars args) { boolean excludeFluid = true; if (args.has(BrushKeys.EXCLUDE_FLUID)) { excludeFluid = args.get(BrushKeys.EXCLUDE_FLUID, Boolean.class).get(); } Optional<Shape> s = args.get(BrushKeys.SHAPE, Shape.class); if (!s.isPresent()) { return ExecutionResult.abortExecution(); } Optional<Material> m = args.get(BrushKeys.MATERIAL, Material.class); if (!m.isPresent()) { player.sendMessage("You must select a material."); return ExecutionResult.abortExecution(); } Optional<String> kernalShape = args.get(BrushKeys.KERNEL, String.class); Optional<Double> kernalSize = args.get(BrushKeys.KERNEL_SIZE, Double.class); System.out.println("Using strings " + kernalShape.or("empty") + " and " + kernalSize.or(0.0)); double size = kernalSize.or(1.0); String kernelString = kernalShape.or("voxel"); Optional<Shape> se = PrimativeShapeFactory.createShape(kernelString, size); if (!se.isPresent()) { se = Optional.<Shape>of(new CuboidShape(3, 3, 3, new Vector3i(1, 1, 1))); } Optional<Block> l = args.get(BrushKeys.TARGET_BLOCK, Block.class); MaterialShape ms = new ComplexMaterialShape(s.get(), m.get()); World world = player.getWorld(); Location loc = l.get().getLocation(); Shape shape = s.get(); Shape structElem = se.get(); // Extract the location in the world to x0, y0 and z0. for (int x = 0; x < ms.getWidth(); x++) { int x0 = loc.getFlooredX() + x - shape.getOrigin().getX(); for (int y = 0; y < ms.getHeight(); y++) { int y0 = loc.getFlooredY() + y - shape.getOrigin().getY(); for (int z = 0; z < ms.getLength(); z++) { int z0 = loc.getFlooredZ() + z - shape.getOrigin().getZ(); if (!shape.get(x, y, z, false)) { continue; } // Represents a histogram of material occurrences hit by the // structuring element. Map<Material, Integer> mats = Maps.newHashMapWithExpectedSize(10); for (int a = 0; a < structElem.getWidth(); a++) { for (int b = 0; b < structElem.getHeight(); b++) { for (int c = 0; c < structElem.getLength(); c++) { if (!structElem.get(a, b, c, false)) { continue; } int a0 = a - structElem.getOrigin().getX(); int b0 = b - structElem.getOrigin().getY(); int c0 = c - structElem.getOrigin().getZ(); // Discludes the target block from the // calculation. if (!(a0 == 0 && b0 == 0 && c0 == 0)) { // TODO: Use world bounds instead of // hardcoded magical values from Minecraft. int clampedY = Maths.clamp(y0 + b0, 0, 255); Material mat = world.getBlock(x0 + a0, clampedY, z0 + c0).get().getMaterial(); if (mats.containsKey(mat)) { mats.put(mat, mats.get(mat) + 1); } else { mats.put(mat, 1); } } } } } // Select the material which occured the most. int n = 0; Material winner = null; for (Map.Entry<Material, Integer> e : mats.entrySet()) { if (e.getValue() > n && !(excludeFluid && e.getKey().isLiquid())) { winner = e.getKey(); n = e.getValue(); } } // If multiple materials occurred the most, the tie check // will become true. boolean tie = false; for (Map.Entry<Material, Integer> e : mats.entrySet()) { if (e.getValue() == n && !(excludeFluid && e.getKey().isLiquid()) && !e.getKey().equals(winner)) { tie = true; } } // If a tie is found, no change is made. if (!tie) { ms.setMaterial(x, y, z, false, winner); } } } } new ShapeChangeQueue(player, loc, ms).flush(); return ExecutionResult.continueExecution(); } }