Improving terrible spells: Mordenkainen’s sword


The problem

In my answer to “Is the Mordenkainen’s Sword spell underpowered?”, I concluded that the spell is terrible. Critiquing a spell is one thing; improving it is another. So, can the sword be fixed, or is it doomed to rot in spellbooks forever, never to be copied?

First, the original:

Mordenkainen’s Sword

7th-level evocation

Casting Time: 1 action
Range: 60 feet
Components: V, S, M (a miniature platinum sword with a grip and pommel of copper and zinc, worth 250 gp)
Duration: Concentration, 1 minute

You create a sword-shaped plane of force that hovers within range. It lasts for the duration.

When the sword appears, you make a melee spell attack against a target of your choice within 5 feet of the sword. On a hit, the target takes 3d10 force damage. Until the spell ends, you can use a bonus action on each of your turns to move the sword up to 20 feet to a spot you can see and repeat this attack against the same target or a different one.

Mordenkainen’s sword has several notable problems:

  • The sword’s damage is bad for a concentration spell. Over three rounds (assuming all attacks hit), the sword deals 66 damage, while Bigby’s hand deals 108 damage (when upcast to 7th level).
  • The sword’s damage is bad for a non-concentration spell. Crown of stars from Xanathar’s has an hour duration and requires no concentration, but still deals 78 damage over 3 rounds.
  • The sword is inferior to non-damaging options. Why waste a 7th-level slot dealing (terrible) damage to a single target, when you could put most creatures in a forcecage with no save? The sword’s 20 feet of movement each turn also means that it can’t reach mobile high-level enemies, like dragons.

Mordenkainen’s sword also has several features that make it unique:

  • The sword is the highest-level spell that targets a single creature, requires concentration, and purely deals damage. Even if we relax the concentration requirement, only crown of stars (also 7th-level) meets the remaining requirements.
  • The sword allows two attacks on the first turn, but only one thereafter. Getting damage out early is usually better than spreading it across multiple turns, but this may complicate attempts to rebalance the sword.
  • The sword is one of only four leveled wizard spells that only require a melee spell attack. The others are vampiric touch, Mordenkainen’s faithful hound, and steel wind strike.

A solution?

My goal is to keep what makes the spell unique, while fixing its glaring balance issues. With that in mind, the spell remains the same, except for the second paragraph and the new “at higher levels”, which now read:

When the sword appears, you make a melee spell attack against a target of your choice within 5 feet of the sword. On a hit, the target takes 7d10 force damage. Until the spell ends, you can use a bonus action on each of your turns to move the sword up to 60 feet to a spot you can see and repeat this attack against the same target or a different one.

At Higher Levels. When you cast this spell using a spell slot of 8th level or higher, the damage increases by 2d10 for each slot level above 7th.

Do these changes make Mordenkainen’s sword a reasonable, balanced choice for bards and wizards? Would a controller ever consider taking it? Would a blaster ever use anything else?

Improving rendering performance of 3D Voxel Game


Improving rendering performance of 3D Voxel Game

Technical features added:

  • Perlin Noise Generator
  • 3D Explorable World (You can’t break or place blocks)
  • Free camera, you can fly and go through blocks

Quick overview of implemented optimizations:

  • Asynchronous (Multi-threaded) chunks system.
  • Render only visible faces and cubes.
  • Textures cache and texture atlas
  • Instead of rendering block by block, render the whole chunk at once.
  • Use VBO and Indices

My problems:

  • The framerate is sort of correct, but I think it can still be optimized, because when i’m comparing my game performance to Minecraft for exemple, Minecraft is much much more optimized.

  • The camera takes few seconds to move (I think this is due to Mouse Input, I am not sure, too)

Code:

Main class:

package me.minkizz.whitata;  import java.awt.Toolkit; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set;  import org.lwjgl.glfw.Callbacks; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWErrorCallback; import org.lwjgl.glfw.GLFWVidMode; import org.lwjgl.opengl.GL; import org.lwjgl.opengl.GL11; import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryUtil;  import me.minkizz.whitata.entities.Camera; import me.minkizz.whitata.entities.Entity; import me.minkizz.whitata.maths.PerlinNoiseGenerator; import me.minkizz.whitata.maths.Vector2f; import me.minkizz.whitata.maths.Vector3f; import me.minkizz.whitata.rendering.Loader; import me.minkizz.whitata.rendering.MasterRenderer; import me.minkizz.whitata.rendering.models.ModelTexture; import me.minkizz.whitata.rendering.models.RawModel; import me.minkizz.whitata.rendering.models.TexturedModel; import me.minkizz.whitata.world.Block; import me.minkizz.whitata.world.Chunk; import me.minkizz.whitata.world.ChunkMesh;  public class Whitata implements Runnable {      private boolean running;     private int latestFps;     private static int width, height;     private Timer timer = new Timer(64f);     private long window;     private MasterRenderer masterRenderer;     private Loader loader;     private int latestKey;     private int latestAction;     private Camera camera;     private PerlinNoiseGenerator generator;      private static final int CHUNK_SIZE = 24;     private static final int WORLD_SIZE = 6 * CHUNK_SIZE;     private static final float BLOCK_SCALE = 0.7f;      public static int getWidth() {         return width;     }      public static int getHeight() {         return height;     }      private List<ChunkMesh> chunks = Collections.synchronizedList(new ArrayList<>());     private List<Entity> entities = new ArrayList<>();      private void init() throws Exception {         width = (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth();         height = (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight();          GLFWErrorCallback.createPrint(System.err).set();          if (!GLFW.glfwInit()) {             throw new IllegalStateException("Unable to initialize GLFW!");         }          GLFW.glfwDefaultWindowHints();         GLFW.glfwWindowHint(GLFW.GLFW_VISIBLE, GLFW.GLFW_FALSE);         GLFW.glfwWindowHint(GLFW.GLFW_RESIZABLE, GLFW.GLFW_TRUE);          window = GLFW.glfwCreateWindow(width, height, "Whitata", GLFW.glfwGetPrimaryMonitor(), MemoryUtil.NULL);          if (window == MemoryUtil.NULL) {             throw new RuntimeException("Failed to create the GLFW window!");         }          GLFW.glfwSetInputMode(window, GLFW.GLFW_STICKY_MOUSE_BUTTONS, GLFW.GLFW_TRUE);         GLFW.glfwSetInputMode(window, GLFW.GLFW_STICKY_KEYS, GLFW.GLFW_TRUE);         GLFW.glfwSetCursorPosCallback(window, new Mouse());          GLFW.glfwSetKeyCallback(window, (window, key, scancode, action, mods) -> {             latestKey = key;             latestAction = action;              if (key == GLFW.GLFW_KEY_ESCAPE && action == GLFW.GLFW_RELEASE) {                 GLFW.glfwSetWindowShouldClose(window, true);             }          });          try (MemoryStack stack = MemoryStack.stackPush()) {             IntBuffer pWidth = stack.mallocInt(1);             IntBuffer pHeight = stack.mallocInt(1);              GLFW.glfwGetWindowSize(window, pWidth, pHeight);             GLFWVidMode vidmode = GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor());             GLFW.glfwSetWindowPos(window, (vidmode.width() - pWidth.get(0)) / 2,                     (vidmode.height() - pHeight.get(0)) / 2);          }          GLFW.glfwMakeContextCurrent(window);         GLFW.glfwSwapInterval(1);         GLFW.glfwShowWindow(window);         GLFW.glfwSetInputMode(window, GLFW.GLFW_CURSOR, GLFW.GLFW_CURSOR_DISABLED);         GL.createCapabilities();         GL11.glViewport(0, 0, width, height);          loader = new Loader();         masterRenderer = new MasterRenderer();         texture = new ModelTexture(loader.loadTexture("DefaultPack.png"));         camera = new Camera(new Vector3f(0, 0, 0), 0, 0, 0);          generator = new PerlinNoiseGenerator();          new Thread(new Runnable() {              @Override             public void run() {                  while (!GLFW.glfwWindowShouldClose(window)) {                      for (int x = (int) (((cameraPosition.x - WORLD_SIZE) / CHUNK_SIZE)                             / BLOCK_SCALE); x < ((cameraPosition.x + WORLD_SIZE) / CHUNK_SIZE) / BLOCK_SCALE; x++) {                          for (int z = (int) (((cameraPosition.z - WORLD_SIZE) / CHUNK_SIZE)                                 / BLOCK_SCALE); z < ((cameraPosition.z + WORLD_SIZE) / CHUNK_SIZE) / BLOCK_SCALE; z++) {                              if (!usedPositions.contains(new Vector2f(x * CHUNK_SIZE, z * CHUNK_SIZE))) {                                 Set<Block> blocks = new HashSet<Block>();                                  for (int i = 0; i < CHUNK_SIZE; i++) {                                      for (int j = 0; j < CHUNK_SIZE; j++) {                                         int generatedY = (int) generator.generateHeight(i + (x * CHUNK_SIZE),                                                 j + (z * CHUNK_SIZE)) + 25;                                         blocks.add(new Block(i, generatedY, j, Block.Type.GRASS));                                     }                                  }                                  Chunk chunk = new Chunk(blocks,                                         new Vector3f(x * CHUNK_SIZE, 0 * CHUNK_SIZE, z * CHUNK_SIZE));                                 ChunkMesh chunkMesh = new ChunkMesh(chunk);                                 chunks.add(chunkMesh);                                 usedPositions.add(new Vector2f(x * CHUNK_SIZE, z * CHUNK_SIZE));                             }                          }                      }                  }              }          }).start();      }      private ModelTexture texture;      private void tick(int index) {         camera.move(latestKey);         cameraPosition = camera.getPosition();     }      private int index;      @Override     public void run() {         running = true;          try {             init();         } catch (Exception exception) {             exception.printStackTrace();         }          long lastTime = System.currentTimeMillis();         int frames = 0;         index = 0;          while (running) {              if (GLFW.glfwWindowShouldClose(window)) {                 running = false;             }              timer.advanceTime();              for (int i = 0; i < timer.ticks; ++i) {                 tick(index);             }              latestKey = 0;             latestAction = 0;             render(timer.a);              ++frames;             while (System.currentTimeMillis() >= lastTime + 1000L) {                 latestFps = frames;                 lastTime += 1000L;                 frames = 0;             }          }          Callbacks.glfwFreeCallbacks(window);         GLFW.glfwDestroyWindow(window);         GLFW.glfwTerminate();         GLFW.glfwSetErrorCallback(null).free();         loader.cleanUp();         masterRenderer.cleanUp();         System.exit(0);     }      private Vector3f cameraPosition = new Vector3f();     private List<Vector2f> usedPositions = Collections.synchronizedList(new ArrayList<>());      private void render(float a) {          if (index < chunks.size()) {             ChunkMesh mesh = chunks.get(index);             RawModel model123 = loader.loadToVAO(mesh.positions, mesh.uvs);             TexturedModel texturedModel123 = new TexturedModel(model123, texture);             Entity entity123 = new Entity(texturedModel123, mesh.chunk.getOrigin().multiply(BLOCK_SCALE), 0, 0, 0,                     BLOCK_SCALE);             entities.add(entity123);              mesh.positions = null;             mesh.normals = null;             mesh.uvs = null;              index++;         }          for (int i = 0; i < entities.size(); i++) {             Vector3f origin = entities.get(i).getPosition();             int distX = Math.abs((int) (cameraPosition.x - origin.x));             int distZ = Math.abs((int) (cameraPosition.z - origin.z));              if (distX <= WORLD_SIZE && distZ <= WORLD_SIZE) {                 masterRenderer.addEntity(entities.get(i));             }          }          masterRenderer.prepare();         masterRenderer.render(camera);         GLFW.glfwSwapBuffers(window);         GLFW.glfwPollEvents();     }      public static void main(String[] args) {         new Thread(new Whitata()).start();     }  } 

Timer class:

package me.minkizz.whitata;  public class Timer {     private static final long NS_PER_SECOND = 1000000000L;     private static final long MAX_NS_PER_UPDATE = 1000000000L;     private static final int MAX_TICKS_PER_UPDATE = 100;     private float ticksPerSecond;     private long lastTime;     public int ticks;     public float a;     public float timeScale = 1.0f;     public float fps = 0.0f;     public float passedTime = 0.0f;      public Timer(float ticksPerSecond) {         this.ticksPerSecond = ticksPerSecond;         lastTime = System.nanoTime();     }      public void advanceTime() {         long now = System.nanoTime();         long passedNs = now - lastTime;          lastTime = now;          if (passedNs <= 0L) {             return;         }          if (passedNs > MAX_NS_PER_UPDATE) {             passedNs = MAX_NS_PER_UPDATE;         }          fps = NS_PER_SECOND / passedNs;         passedTime += (float) passedNs * timeScale * ticksPerSecond / 1.0E9f;          ticks = (int) passedTime;          if (ticks > MAX_TICKS_PER_UPDATE) {             ticks = MAX_TICKS_PER_UPDATE;         }          passedTime -= (float) ticks;         a = passedTime;     }  } 

Mouse class:

package me.minkizz.whitata;  import org.lwjgl.glfw.GLFWCursorPosCallback;  public class Mouse extends GLFWCursorPosCallback {     private static double oldMouseX, oldMouseY;     private static double newMouseX, newMouseY;     private static double mouseDX, mouseDY;     private static boolean wasFirst;      @Override     public void invoke(long window, double xpos, double ypos) {          if (!wasFirst) {             wasFirst = true;         } else {             oldMouseX = newMouseX;             oldMouseY = newMouseY;             newMouseX = xpos;             newMouseY = ypos;              mouseDX = newMouseX - oldMouseX;             mouseDY = newMouseY - oldMouseY;         }      }      public static double getMouseDX() {         double result = mouseDX;         mouseDX = 0;         return result;     }      public static double getMouseDY() {         double result = -mouseDY;         mouseDY = 0;         return result;     }  } 

Camera class:

package me.minkizz.whitata.entities;  import org.lwjgl.glfw.GLFW;  import me.minkizz.whitata.Mouse; import me.minkizz.whitata.maths.Vector3f;  public class Camera {      private Vector3f position = new Vector3f();     private float rotX, rotY, rotZ;     private float speed = 0.2f;     private float turnSpeed = 0.07f;     private float moveAt_ = 0f;     private float moveAt = 0f;     private boolean doGravity = true;      private static final boolean USE_GRAVITY = true;      public Camera(Vector3f position, float rotX, float rotY, float rotZ) {         this.position = position;         this.rotX = rotX;         this.rotY = rotY;         this.rotZ = rotZ;     }      public void move(int key) {          if (USE_GRAVITY) {             boolean hasMoved = false;              if (key == GLFW.GLFW_KEY_W) {                 moveAt_ = -speed;                 hasMoved = true;             } else if (key == GLFW.GLFW_KEY_S) {                 moveAt_ = speed;                 hasMoved = true;             } else {                 moveAt_ = 0f;             }              if (hasMoved) {                 moveAt = moveAt_;                 doGravity = true;             } else if (!hasMoved && doGravity) {                 calculateGravity();             }          } else {              if (key == GLFW.GLFW_KEY_W) {                 moveAt = -speed;             } else if (key == GLFW.GLFW_KEY_S) {                 moveAt = speed;             } else {                 moveAt = 0f;             }          }          rotX += -Mouse.getMouseDY() * turnSpeed;         rotY += Mouse.getMouseDX() * turnSpeed;          float dx = (float) -(moveAt * Math.sin(Math.toRadians(rotY)));         float dy = (float) (moveAt * Math.sin(Math.toRadians(rotX)));         float dz = (float) (moveAt * Math.cos(Math.toRadians(rotY)));          position.x += dx;         position.y += dy;         position.z += dz;     }      private void calculateGravity() {          if (moveAt > 0) {             moveAt -= 0.0020;             moveAt /= 1.09;              if (moveAt <= 0.0005) {                 moveAt = 0f;                 doGravity = false;             }          } else {             moveAt += 0.0020;             moveAt /= 1.09;              if (moveAt >= -0.0005) {                 moveAt = 0f;                 doGravity = false;             }          }      }      public Vector3f getPosition() {         return position;     }      public void setPosition(Vector3f position) {         this.position = position;     }      public float getRotX() {         return rotX;     }      public void setRotX(float rotX) {         this.rotX = rotX;     }      public float getRotY() {         return rotY;     }      public void setRotY(float rotY) {         this.rotY = rotY;     }      public float getRotZ() {         return rotZ;     }      public void setRotZ(float rotZ) {         this.rotZ = rotZ;     }  } 

Entity class:

package me.minkizz.whitata.entities;  import me.minkizz.whitata.maths.Vector3f; import me.minkizz.whitata.rendering.models.TexturedModel;  public class Entity {      private TexturedModel model;     private Vector3f position;     private float rotX, rotY, rotZ;     private float scale;      public Entity(TexturedModel model, Vector3f position, float rotX, float rotY, float rotZ, float scale) {         this.model = model;         this.position = position;         this.rotX = rotX;         this.rotY = rotY;         this.rotZ = rotZ;         this.scale = scale;     }      public void increasePosition(float dx, float dy, float dz) {         this.position.x += dx;         this.position.y += dy;         this.position.z += dz;     }      public void increaseRotation(float dx, float dy, float dz) {         this.rotX += dx;         this.rotY += dy;         this.rotZ += dz;     }      public void increaseScale(float scale) {         this.scale += scale;     }      public TexturedModel getModel() {         return model;     }      public void setModel(TexturedModel model) {         this.model = model;     }      public Vector3f getPosition() {         return position;     }      public void setPosition(Vector3f position) {         this.position = position;     }      public float getRotX() {         return rotX;     }      public void setRotX(float rotX) {         this.rotX = rotX;     }      public float getRotY() {         return rotY;     }      public void setRotY(float rotY) {         this.rotY = rotY;     }      public float getRotZ() {         return rotZ;     }      public void setRotZ(float rotZ) {         this.rotZ = rotZ;     }      public float getScale() {         return scale;     }      public void setScale(float scale) {         this.scale = scale;     }  } 

Perlin Noise Generator class:

package me.minkizz.whitata.maths;  import java.util.Random;  public class PerlinNoiseGenerator {      public static float AMPLITUDE = 30f;     public static int OCTAVES = 6;     public static float ROUGHNESS = 0.3f;      private Random random = new Random();     private int seed;     private int xOffset = 0;     private int zOffset = 0;      public PerlinNoiseGenerator() {         this.seed = 0;     }      // only works with POSITIVE gridX and gridZ values!     public PerlinNoiseGenerator(int gridX, int gridZ, int vertexCount, int seed) {         this.seed = seed;         xOffset = gridX * (vertexCount - 1);         zOffset = gridZ * (vertexCount - 1);     }      public float generateHeight(int x, int z) {          x = x < 0 ? -x : x;         z = z < 0 ? -z : z;          float total = 0;         float d = (float) Math.pow(2, OCTAVES - 1);          for (int i = 0; i < OCTAVES; i++) {             float freq = (float) (Math.pow(2, i) / d);             float amp = (float) Math.pow(ROUGHNESS, i) * AMPLITUDE;             total += getInterpolatedNoise((x + xOffset) * freq, (z + zOffset) * freq) * amp;         }          return (float) (int) total;      }      private float getInterpolatedNoise(float x, float z) {         int intX = (int) x;         int intZ = (int) z;         float fracX = x - intX;         float fracZ = z - intZ;          float v1 = getSmoothNoise(intX, intZ);         float v2 = getSmoothNoise(intX + 1, intZ);         float v3 = getSmoothNoise(intX, intZ + 1);         float v4 = getSmoothNoise(intX + 1, intZ + 1);         float i1 = interpolate(v1, v2, fracX);         float i2 = interpolate(v3, v4, fracX);         return interpolate(i1, i2, fracZ);     }      private float interpolate(float a, float b, float blend) {         double theta = blend * Math.PI;         float f = (float) (1f - Math.cos(theta)) * 0.5f;         return a * (1f - f) + b * f;     }      private float getSmoothNoise(int x, int z) {         float corners = (getNoise(x - 1, z - 1) + getNoise(x + 1, z - 1) + getNoise(x - 1, z + 1)                 + getNoise(x + 1, z + 1)) / 16f;         float sides = (getNoise(x - 1, z) + getNoise(x + 1, z) + getNoise(x, z - 1) + getNoise(x, z + 1)) / 8f;         float center = getNoise(x, z) / 4f;         return corners + sides + center;     }      private float getNoise(int x, int z) {         random.setSeed(x * 49632 + z * 325176 + seed);         return random.nextFloat() * 2f - 1f;     }  } 

Entity Renderer class:

package me.minkizz.whitata.rendering;  import java.util.List; import java.util.Map;  import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30;  import me.minkizz.whitata.entities.Entity; import me.minkizz.whitata.maths.Maths; import me.minkizz.whitata.maths.Matrix4f; import me.minkizz.whitata.rendering.models.TexturedModel; import me.minkizz.whitata.rendering.shaders.StaticShader;  public class EntityRenderer {      private StaticShader shader = new StaticShader();      public void render(Map<TexturedModel, List<Entity>> entities) {          for (TexturedModel model : entities.keySet()) {             GL30.glBindVertexArray(model.getModel().getVaoID());             GL20.glEnableVertexAttribArray(0);             GL20.glEnableVertexAttribArray(1);             GL13.glActiveTexture(GL13.GL_TEXTURE0);             GL11.glBindTexture(GL11.GL_TEXTURE_2D, model.getTexture().getTextureID());              List<Entity> batch = entities.get(model);              for (Entity entity : batch) {                 Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), entity.getRotX(),                         entity.getRotY(), entity.getRotZ(), entity.getScale());                 shader.loadTransformationMatrix(transformationMatrix);                 GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, model.getModel().getVertexCount() / 3);             }              GL20.glDisableVertexAttribArray(0);             GL20.glDisableVertexAttribArray(1);             GL30.glBindVertexArray(0);         }      }  } 

Loader class:

package me.minkizz.whitata.rendering;  import java.io.IOException; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry;  import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL14; import org.lwjgl.opengl.GL15; import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL30;  import me.minkizz.whitata.rendering.models.RawModel; import me.minkizz.whitata.rendering.textures.Texture; import me.minkizz.whitata.rendering.textures.TextureLoader;  public class Loader {      private List<Integer> vaos = new ArrayList<>();     private List<Integer> vbos = new ArrayList<>();      public RawModel loadToVAO(float[] vertices, int[] indices, float[] uv) {         int vaoID = createVAO();         storeDataInAttributeList(vertices, 0, 3);         storeDataInAttributeList(uv, 1, 2);         bindIndicesBuffer(indices);         GL30.glBindVertexArray(0);         return new RawModel(vaoID, indices.length);     }      public RawModel loadToVAO(float[] vertices, float[] uv) {         int vaoID = createVAO();         storeDataInAttributeList(vertices, 0, 3);         storeDataInAttributeList(uv, 1, 2);         GL30.glBindVertexArray(0);         return new RawModel(vaoID, vertices.length);     }      private int createVAO() {         int vaoID = GL30.glGenVertexArrays();         vaos.add(vaoID);         GL30.glBindVertexArray(vaoID);         return vaoID;     }      private Map<String, Integer> textureCache = new HashMap<>();      public int loadTexture(String fileName) {          if (textureCache.containsKey(fileName)) {             return textureCache.get(fileName);         }          Texture texture = null;          try {             texture = TextureLoader.getTexture("/res/" + fileName);             GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);             GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);             GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);             GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, -4);         } catch (IOException exception) {             exception.printStackTrace();         }          int textureID = texture.getTextureID();         textureCache.put(fileName, textureID);         return textureID;     }      private void storeDataInAttributeList(float[] data, int attributeNumber, int dimensions) {         int vboID = GL15.glGenBuffers();         vbos.add(vboID);         GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);         FloatBuffer buffer = storeDataInFloatBuffer(data);         GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);         GL20.glVertexAttribPointer(attributeNumber, dimensions, GL11.GL_FLOAT, false, 0, 0);         GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);     }      private void bindIndicesBuffer(int[] indices) {         int vboID = GL15.glGenBuffers();         vbos.add(vboID);         GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboID);         IntBuffer buffer = storeDataInIntBuffer(indices);         GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);     }      private IntBuffer storeDataInIntBuffer(int[] data) {         IntBuffer buffer = BufferUtils.createIntBuffer(data.length);         buffer.put(data);         buffer.flip();         return buffer;     }      private FloatBuffer storeDataInFloatBuffer(float[] data) {         FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);         buffer.put(data);         buffer.flip();         return buffer;     }      public void cleanUp() {          for (int vao : vaos) {             GL30.glDeleteVertexArrays(vao);         }          for (int vbo : vbos) {             GL15.glDeleteBuffers(vbo);         }          for (Entry<String, Integer> entry : textureCache.entrySet()) {             GL11.glDeleteTextures(entry.getValue());         }      }  } 

Master Renderer class:

package me.minkizz.whitata.rendering;  import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;  import org.lwjgl.opengl.GL11;  import me.minkizz.whitata.Whitata; import me.minkizz.whitata.entities.Camera; import me.minkizz.whitata.entities.Entity; import me.minkizz.whitata.maths.Matrix4f; import me.minkizz.whitata.rendering.models.TexturedModel; import me.minkizz.whitata.rendering.shaders.StaticShader;  public class MasterRenderer {      private Matrix4f projectionMatrix = new Matrix4f();     private static final float FOV = 70f;     private static final float NEAR_PLANE = 0.1f;     private static final float FAR_PLANE = 10000f;      private StaticShader shader = new StaticShader();     private EntityRenderer renderer = new EntityRenderer();     private Map<TexturedModel, List<Entity>> entities = new HashMap<>();      public MasterRenderer() {         createProjectionMatrix();         shader.start();         shader.loadProjectionMatrix(projectionMatrix);         shader.stop();     }      public void prepare() {         GL11.glClearColor(0.4f, 0.7f, 1.0f, 1);         GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);         GL11.glEnable(GL11.GL_DEPTH_TEST);         GL11.glDepthFunc(GL11.GL_LEQUAL);     }      public void render(Camera camera) {         prepare();         shader.start();         shader.loadViewMatrix(camera);         renderer.render(entities);         shader.stop();         entities.clear();     }      public void addEntity(Entity entity) {         TexturedModel model = entity.getModel();         List<Entity> batch = entities.get(model);          if (batch != null) {             batch.add(entity);         } else {             List<Entity> newBatch = new ArrayList<>();             newBatch.add(entity);             entities.put(model, newBatch);         }      }      public void createProjectionMatrix() {         float aspect = (float) Whitata.getWidth() / (float) Whitata.getHeight();         float yScale = (float) (1f / Math.tan(Math.toRadians(FOV / 2F)));         float xScale = yScale / aspect;         float zp = FAR_PLANE + NEAR_PLANE;         float zm = FAR_PLANE - NEAR_PLANE;          projectionMatrix.m00 = xScale;         projectionMatrix.m11 = yScale;         projectionMatrix.m22 = -zp / zm;         projectionMatrix.m23 = -1;         projectionMatrix.m32 = -(2 * FAR_PLANE * NEAR_PLANE) / zm;         projectionMatrix.m33 = 0;     }      public void cleanUp() {         shader.cleanUp();     }  } 

Block class:

package me.minkizz.whitata.world;  public class Block {      public int x, y, z;      public static enum Type {          GRASS(0), DIRT(1), STONE(2), TREEBARK(3), TREELEAF(4);          private int id;          Type(int id) {             this.id = id;         }          public int getId() {             return id;         }      }      public Type type;      public Block(int x, int y, int z, Type type) {         this.x = x;         this.y = y;         this.z = z;         this.type = type;     }      public void setType(Type type) {         this.type = type;     }      public Type getType() {         return type;     }  } 

Chunk class:

package me.minkizz.whitata.world;  import java.util.Set;  import me.minkizz.whitata.maths.Vector3f;  public class Chunk {      private Set<Block> blocks;     private Vector3f origin;      public Chunk(Set<Block> blocks, Vector3f origin) {         this.blocks = blocks;         this.origin = origin;     }      public Set<Block> getBlocks() {         return blocks;     }      public void setBlocks(Set<Block> blocks) {         this.blocks = blocks;     }      public Vector3f getOrigin() {         return origin;     }      public void setOrigin(Vector3f origin) {         this.origin = origin;     }  } 

Chunk Mesh class:

package me.minkizz.whitata.world;  import java.util.ArrayList; import java.util.Iterator; import java.util.List;  import me.minkizz.whitata.maths.Vector3f; import me.minkizz.whitata.maths.Vertex; import me.minkizz.whitata.rendering.models.CubeModel;  public class ChunkMesh {      private List<Vertex> vertices;      private List<Float> positionsList;     private List<Float> uvsList;     private List<Float> normalsList;      public float[] positions, uvs, normals;      public Chunk chunk;      public ChunkMesh(Chunk chunk) {         this.chunk = chunk;          vertices = new ArrayList<Vertex>();         positionsList = new ArrayList<Float>();         uvsList = new ArrayList<Float>();         normalsList = new ArrayList<Float>();          buildMesh();         populateLists();     }      public void update(Chunk chunk) {         this.chunk = chunk;          buildMesh();         populateLists();     }      public void buildMesh() {         Iterator<Block> iterator = chunk.getBlocks().iterator();          while (iterator.hasNext()) {             Block blockI = iterator.next();             boolean px = false, nx = false, py = false, ny = false, pz = false, nz = false;             Iterator<Block> iterator2 = chunk.getBlocks().iterator();              while (iterator2.hasNext()) {                 Block blockJ = iterator2.next();                  if (((blockI.x + 1) == (blockJ.x)) && ((blockI.y) == (blockJ.y)) && ((blockI.z) == (blockJ.z))) {                     px = true;                 }                  if (((blockI.x - 1) == (blockJ.x)) && ((blockI.y) == (blockJ.y)) && ((blockI.z) == (blockJ.z))) {                     nx = true;                 }                  if (((blockI.x) == (blockJ.x)) && ((blockI.y + 1) == (blockJ.y)) && ((blockI.z) == (blockJ.z))) {                     py = true;                 }                  if (((blockI.x) == (blockJ.x)) && ((blockI.y - 1) == (blockJ.y)) && ((blockI.z) == (blockJ.z))) {                     ny = true;                 }                  if (((blockI.x) == (blockJ.x)) && ((blockI.y) == (blockJ.y)) && ((blockI.z + 1) == (blockJ.z))) {                     pz = true;                 }                  if (((blockI.x) == (blockJ.x)) && ((blockI.y) == (blockJ.y)) && ((blockI.z - 1) == (blockJ.z))) {                     nz = true;                 }              }              if (!px) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.PX_POS[k].x + blockI.x, CubeModel.PX_POS[k].y + blockI.y,                                     CubeModel.PX_POS[k].z + blockI.z),                             CubeModel.UV_PX[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }              if (!px) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.PX_POS[k].x + blockI.x, CubeModel.PX_POS[k].y + blockI.y,                                     CubeModel.PX_POS[k].z + blockI.z),                             CubeModel.UV_PX[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }              if (!nx) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.NX_POS[k].x + blockI.x, CubeModel.NX_POS[k].y + blockI.y,                                     CubeModel.NX_POS[k].z + blockI.z),                             CubeModel.UV_NX[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }              if (!py) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.PY_POS[k].x + blockI.x, CubeModel.PY_POS[k].y + blockI.y,                                     CubeModel.PY_POS[k].z + blockI.z),                             CubeModel.UV_PY[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }              if (!ny) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.NY_POS[k].x + blockI.x, CubeModel.NY_POS[k].y + blockI.y,                                     CubeModel.NY_POS[k].z + blockI.z),                             CubeModel.UV_NY[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }              if (!pz) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.PZ_POS[k].x + blockI.x, CubeModel.PZ_POS[k].y + blockI.y,                                     CubeModel.PZ_POS[k].z + blockI.z),                             CubeModel.UV_PZ[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }              if (!nz) {                  for (int k = 0; k < 6; k++) {                     vertices.add(new Vertex(                             new Vector3f(CubeModel.NZ_POS[k].x + blockI.x, CubeModel.NZ_POS[k].y + blockI.y,                                     CubeModel.NZ_POS[k].z + blockI.z),                             CubeModel.UV_NZ[(blockI.type.getId() * 6) + k], CubeModel.NORMALS[k]));                 }              }          }      }      public void populateLists() {          for (int i = 0; i < vertices.size(); i++) {             Vertex vertex = vertices.get(i);             positionsList.add(vertex.positions.x);             positionsList.add(vertex.positions.y);             positionsList.add(vertex.positions.z);             normalsList.add(vertex.normals.x);             normalsList.add(vertex.normals.y);             normalsList.add(vertex.normals.z);             uvsList.add(vertex.uvs.x);             uvsList.add(vertex.uvs.y);         }          positions = new float[positionsList.size()];         uvs = new float[uvsList.size()];         normals = new float[normalsList.size()];          for (int i = 0; i < positionsList.size(); i++) {             positions[i] = positionsList.get(i);         }          for (int i = 0; i < uvsList.size(); i++) {             uvs[i] = uvsList.get(i);         }          for (int i = 0; i < normalsList.size(); i++) {             normals[i] = normalsList.get(i);         }          positionsList.clear();         uvsList.clear();         normalsList.clear();     }  } 

You Rank Improving All In One SEO/SMM Backlinks Promotion Traffic Service for $50

Hello Client Sir, i saw your job and realized that i am very interested in this job if you give me a job then i can do it very well. if you have any questions about this, please contact me. In our Done For You Rank Improving All In One SEO/SMM Backlinks Promotion Traffic Service, we will do the best quality, non stop SEO link building and SMM promotion throughout every week, of the month, for you for as long as you want or need it for until you rank up in the Google SERPS! thanks

by: Maria02
Created: —
Category: Link Building
Viewed: 150


50 dofollow High Quality USA PR9 backlinks for improving your website for $5

I will manually create 50 USA Page Rank authority trust profile backlinks for your website. That means your website will be on the most trusted and best ranked sites on the planet. Benefits: 100% panda, penguin, and hummingbird safe100% Manual Work 100% Google safe100% customer satisfaction100% Do followHelp to increase your rankingsFast express delivery100% Quality serviceFree revision and replacement until satisfactionDetails report excel sheet Order now!! And get your website ranked Top! Thank you so much for visiting my Service…

by: asifsomebody
Created: —
Category: Link Building
Viewed: 104


Improving particle performance in P5.js

I have modified a particle system to create an effect similar to the one that I want. However, with any substantial amount of particles it performs very slowly on my laptop (around 1.7 fps at the worst when I remove the if statement limiting the creation of new particles). I’m guessing that this is because all the work is on the CPU? Can I batch together the processing somehow?

Demo here.

// Based on https://github.com/benjaminmbrown/particle-system-repeller  var Repeller = function(x, y) {     this.power = 500;     this.position = createVector(x, y);      this.display = function() {         stroke(0);         strokeWeight(2);         fill(127);         ellipse(this.position.x, this.position.y, 40, 40);     }      this.repel = function(p) {         var dir = p5.Vector.sub(this.position, p.position);         var d = dir.mag();         dir.normalize(); //just want the direction         d = constrain(d, 1, 100);         var force = -1 * this.power / (d * d);         dir.mult(force);         return dir;     } }   var Attractor = function(x, y) {     this.power = 150;     this.position = createVector(x, y);      this.display = function() {         stroke(255);         strokeWeight(2);         fill(127);         ellipse(this.position.x, this.position.y, 40, 40);     }      this.attract = function(p) {         var force = p5.Vector.sub(this.position, p.position);         var distance = force.mag();         distance = constrain(distance, 5, 50);         force.normalize();         var strength = 1 * this.power / (distance * distance);         force.mult(strength);         return force;     } }  function Particle(position, velObj, color) {     this.position = position.copy();     this.acceleration = createVector(0, 0.00);     this.velocity = createVector(random(velObj.xMin, velObj.xMax), random(velObj.yMin, velObj.yMax));     color = color || {r: 0, g: 0, b: 0};      this.lifespan = 255;     this.mass = 5;      this.run = function() {         this.update();         this.display();     }      this.display = function() {         stroke(255, this.lifespan); //gets more transparent as it dies         strokeWeight(2);         fill(color.r, color.g, color.b, this.lifespan);          ellipse(this.position.x, this.position.y, 4, 4);     }      this.update = function() {         this.velocity.add(this.acceleration);         this.position.add(this.velocity);         this.acceleration.mult(0);         this.lifespan -= 1.5;     }      this.isDead = function() {         return this.lifespan < 0.0 ? true : false;     }      this.applyForce = function(force) {         var f = force.copy();         f.div(this.mass);         this.acceleration.add(f);     } }   function ParticleSystem(num, position, velObj, color) {     this.origin = position.copy();     this.particles = [];      this.run = function() {         for(var i = this.particles.length - 1; i >= 0; i--) {             var p = this.particles[i];             p.run();             if(p.isDead()) {                 this.particles.splice(i, 1);             }         }     };      this.applyForce = function(force) {         for(var i = 0; i < this.particles.length; i++) {             this.particles[i].applyForce(force);         }     }      this.applyRepeller = function(r) {         for(var i = 0; i < this.particles.length; i++) {             this.particles[i].applyForce(r.repel(this.particles[i]));         }     }      this.applyAttractor = function(r) {         for(var i = 0; i < this.particles.length; i++) {             this.particles[i].applyForce(r.attract(this.particles[i]));             var p = this.particles[i];             var force = r.attract(p);             p.applyForce(force);         }     }      this.addParticle = function() {         var r = random(1);         this.particles.push(new Particle(this.origin, velObj, color));     }; }  var particleSystems = []; var repeller, attractor;   function setup() {     createCanvas(windowWidth, windowHeight, WEBGL);     setFrameRate(60);     repeller = new Repeller(0, 0);     leftAttractor = new Attractor(0, height / 2);     rightAttractor = new Attractor(width, height / 2);      particleSystems.push(new ParticleSystem(1, createVector(width / 5, height / 2), {xMin: 0, xMax: 2, yMin: -4, yMax: 4}, {r: 0, g: 0, b: 255}));     particleSystems.push(new ParticleSystem(1, createVector(width * 4 / 5, height / 2), {xMin: -2, xMax: 0, yMin: -4, yMax: 4}, {r: 255, g: 0, b: 0}));      // Ones not affected by attractor     particleSystems.push(new ParticleSystem(1, createVector(width / 5, height / 2), {xMin: -2, xMax: 1, yMin: -2, yMax: 2}, {r: 0, g: 0, b: 255}));     particleSystems.push(new ParticleSystem(1, createVector(width * 4 / 5, height / 2), {xMin: -1, xMax: 2, yMin: -2, yMax: 2}, {r: 255, g: 0, b: 0})); }  var numDraws = 0; function draw() {     background(255);     // var gravity = createVector(0.0, 0.1);     translate(-windowWidth / 2, -windowHeight / 2);      for(var i = 0; i < particleSystems.length; i++) {         // particleSystems[i].applyForce(gravity);         particleSystems[i].applyRepeller(repeller);         if(i === 0) {             particleSystems[i].applyAttractor(rightAttractor);         } else if(i === 1) {             particleSystems[i].applyAttractor(leftAttractor);         }         // if(numDraws % 3 === 0 || i < 2)             particleSystems[i].addParticle();         particleSystems[i].run();     }     repeller.display();     numDraws++; }  function mouseMoved() {     repeller.position = createVector(mouseX, mouseY); } function touchMoved() {     repeller.position = createVector(mouseX, mouseY); } 

Any insight as to how to improve this performance is appreciated.

Improving a simple service class that returns a collection

Background

An API endpoint that returns phone numbers. I would appreciate some feedback on this very simple service class that is part of the overall solution. Here is its Interface:

public interface IPhoneNumbersService {     Task<IList<PhoneNumberViewModel>> GetAllPhoneNumbersAsync();      Task<IList<CustomerPhoneNumberViewModel>> GetCustomerPhoneNumbersAsync(int customerId); } 

And here is its implementation:

public class PhoneNumbersService : IPhoneNumbersService {     private ZetaContext context;      private readonly ILogger logger;      public PhoneNumbersService(         ZetaContext context,         ILogger<PhoneNumbersService> logger)     {         this.context = context;         this.logger = logger;     }      public async Task<IList<PhoneNumberViewModel>> GetAllPhoneNumbersAsync()     {         List<PhoneNumberViewModel> phoneNumbers = await context             .PhoneNumbers             .AsNoTracking()             .Select(x => new PhoneNumberViewModel             {                 Customer = $  "{x.Customer.Title} {x.Customer.FirstName} {x.Customer.LastName}",                 PhoneNumber = x.Value             })             .ToListAsync();          logger.LogTrace($  "{phoneNumbers.Count} phone numbers were retrieved from the database.");          return phoneNumbers;     }      public async Task<IList<CustomerPhoneNumberViewModel>> GetCustomerPhoneNumbersAsync(int customerId)     {         Customer customer = await context             .Customers             .AsNoTracking()             .Include(x => x.PhoneNumbers)             .Where(x => x.Id == customerId)             .SingleOrDefaultAsync();          if (customer == null)         {             throw new CustomerNotFoundException(customerId);         }          List<CustomerPhoneNumberViewModel> customerPhoneNumbers = customer             .PhoneNumbers             .Select(x => new CustomerPhoneNumberViewModel             {                 PhoneNumber = x.Value,                 IsActive = x.IsActive,                 CreatedAt = x.CreatedAt             })             .ToList();          return customerPhoneNumbers;     } } 

The Controller that calls the above service looks like this:

[ApiController] public class PhoneNumbersController : ControllerBase {     private readonly IPhoneNumbersService phoneNumbersService;      private readonly ILogger logger;      public PhoneNumbersController(         IPhoneNumbersService phoneNumbersService,         ILogger<PhoneNumbersController> logger)     {         this.phoneNumbersService = phoneNumbersService;         this.logger = logger;     }      [Route("api/numbers/")]     public async Task<IActionResult> GetAllPhoneNumbersAsync()     {         IList<PhoneNumberViewModel> phoneNumbers = await phoneNumbersService.GetAllPhoneNumbersAsync();          return Ok(phoneNumbers);     }      [Route("api/customers/{customerId}/numbers")]     public async Task<IActionResult> GetCustomerPhoneNumbers(int? customerId)     {         if (!customerId.HasValue || customerId.Value == 0)         {             throw new ArgumentNullException(nameof(customerId));         }          try         {             IList<CustomerPhoneNumberViewModel> customerPhoneNumbers = await phoneNumbersService.GetCustomerPhoneNumbersAsync(customerId.Value);              return Ok(customerPhoneNumbers);          }         catch (CustomerNotFoundException exception)         {             logger.LogError($  "The customer with Id: {exception.CustomerId} could not be found.");              return NotFound();         }     } } 

On thing I am not sure about. Where should one convert the Entity PhoneNumber.cs to its ViewModel PhoneNumberViewModel.cs. Should this happen in the Service class like it is now (see .Select())? Or should this happen in the controller?

If in the controller, then that means my service method GetAllPhoneNumbersAsync() should return a list (or should it be IEnumerable or ICollection) of the entities to the controller. Is that bad? Some say that is leaking my entities into the controller, others say the service should be as re-usable as possible and shouldn’t do any mapping.

For an Enterprise application, what more can you do to improve the above? Any tips and pointers would be greatly appreciated.

Improving performance of moving arrays into an array

I am loading a bunch of arrays and putting them into a single array. The loading of the data is negligible, but putting it into combinedArray takes significant time (as in this code).

import time import numpy as np start_time = time.time()     st,en = 0,0    combinedArray = np.empty(shape = (30000*30000))    #Get the array that each process wrote to    for i in range(10):        #load the array        #ex loading         X_np = np.empty(shape = (30000*30000)/10)        st = en        en += np.shape(X_np[:])[0]        #add to the array list        combinedArray[st:en] = X_np[:]     print("Array Calc:",time.time()-start_time)   

What I have found is often someone talking about not using append, so I tried with creating the array first, but just moving it is time consuming. Any advice on how to optimize this is appreciated.

Improving Performance

We run a Magento 1.9 online store. It contains 110,000 products. We are running into issue around long page load times for category pages and product pages.

Dedicated WebApp server specs: – Apache 2.4 – PHP 5.6 – PHP.ini heavily tweaked, along with an 8GB Redis cache – 6 CPU Cores – 16GB Memory – SSD Storage

Dedicated Database Server: – MySQL 5.6 (tuned with MySQL Tuner). – 6 CPU Cores – 16GB Memory – SSD Storage

The site hasn’t launched yet as we are trying to fix these performance issues.

Seems to me the bottleneck is the database. I’ve read nearly every article I could find on improving performance but we are still at 6-11s load times.

[mysqld]  innodb_buffer_pool_instances = 11 innodb_log_file_size = 1024M innodb_buffer_pool_size = 12000M query_cache_size = 64M query_cache_type = 0 query_cache_limit = 2M key_buffer_size = 36M max_heap_table_size = 16M tmp_table_size = 256M join_buffer_size = 8M max_allowed_packet = 16M innodb_lock_wait_timeout=300 innodb_read_io_threads = 8 innodb_write_io_threads = 8 innodb_thread_concurrency = 12 max_connections = 500 thread_cache_size = 32 thread_concurrency = 12 innodb_flush_log_at_trx_commit = 2 datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock symbolic-links=0 sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES  [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid 

Actual server resource usage is low. I’d love any recommendations on how we can improve the load speed and increase server resource usage of CPU and Memory.