All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.llbit.chunky.world.ChunkSelectionTracker Maven / Gradle / Ivy

There is a newer version: 1.4.5
Show newest version
/* Copyright (c) 2012 Jesper Öqvist 
 *
 * This file is part of Chunky.
 *
 * Chunky is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Chunky is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with Chunky.  If not, see .
 */
package se.llbit.chunky.world;

import se.llbit.chunky.world.listeners.ChunkDeletionListener;
import se.llbit.chunky.world.listeners.ChunkUpdateListener;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * Tracks chunk selections.
 *
 * @author Jesper Öqvist 
 */
public class ChunkSelectionTracker implements ChunkDeletionListener {

  private final Set selected = new HashSet<>();
  private final Collection chunkUpdateListeners = new LinkedList<>();
  private final Collection selectionListeners = new LinkedList<>();

  /**
   * Add a chunk update listener to listen for selection changes.
   */
  public void addChunkUpdateListener(ChunkUpdateListener listener) {
    synchronized (chunkUpdateListeners) {
      chunkUpdateListeners.add(listener);
    }
  }

  /**
   * Add a chunk update listener to listen for selection changes.
   */
  public void addSelectionListener(ChunkSelectionListener listener) {
    synchronized (chunkUpdateListeners) {
      selectionListeners.add(listener);
    }
  }

  /**
   * Remove a chunk update listener.
   */
  public synchronized void removeSelectionListener(ChunkSelectionListener listener) {
    synchronized (chunkUpdateListeners) {
      selectionListeners.remove(listener);
    }
  }

  /**
   * Notify the chunk update listeners that chunks have been updated
   *
   * @param chunks the updated chunks
   */
  private void notifyChunksUpdated(Collection chunks) {
    for (ChunkPosition chunk : chunks) {
      notifyChunkUpdated(chunk);
    }
  }

  /**
   * Notify the chunk update listeners that a chunk has been updated.
   *
   * @param chunk the updated chunk
   */
  private void notifyChunkUpdated(ChunkPosition chunk) {
    for (ChunkUpdateListener listener : chunkUpdateListeners) {
      listener.chunkUpdated(chunk);
    }
  }

  private void notifyChunkSelectionChange() {
    for (ChunkSelectionListener listener : selectionListeners) {
      listener.chunkSelectionChanged();
    }
  }

  @Override public void chunkDeleted(ChunkPosition chunk) {
    selected.remove(chunk);
    notifyChunkUpdated(chunk);
    notifyChunkSelectionChange();
  }

  /**
   * Toggle the selected status of the chunk at the given coordinates.
   *
   * @param cx    chunk x-position
   * @param cz    chunk z-position
   */
  public synchronized void toggleChunk(World world, int cx, int cz) {
    ChunkPosition chunk = ChunkPosition.get(cx, cz);
    if (selected.contains(chunk)) {
      selected.remove(chunk);
      notifyChunkUpdated(chunk);
      notifyChunkSelectionChange();
    } else if (!world.getChunk(chunk).isEmpty()) {
      selected.add(chunk);
      notifyChunkUpdated(chunk);
      notifyChunkSelectionChange();
    }
  }

  /**
   * Adds a chunk to the selection.
   *
   * @param cx    chunk x-position
   * @param cz    chunk z-position
   */
  public synchronized void selectChunk(World world, int cx, int cz) {
    ChunkPosition chunk = ChunkPosition.get(cx, cz);
    if (!selected.contains(chunk) && !world.getChunk(chunk).isEmpty()) {
      selected.add(chunk);
      notifyChunkUpdated(chunk);
      notifyChunkSelectionChange();
    }
  }

  /**
   * Select the region containing the given chunk.
   *
   * @param cx    chunk x-position
   * @param cz    chunk z-position
   */
  public synchronized void selectRegion(World world, int cx, int cz) {
    ChunkPosition chunk = ChunkPosition.get(cx, cz);
    int rx = cx >> 5;
    int rz = cz >> 5;
    if (selected.contains(chunk)) {
      deselectChunks(rx * 32, rz * 32, rx * 32 + 31, rz * 32 + 31);
    } else {
      selectChunks(world, rx * 32, rz * 32, rx * 32 + 31, rz * 32 + 31);
    }
  }

  /**
   * Select chunks within rectangle.
   */
  public synchronized void selectChunks(World world, int cx0, int cz0, int cx1, int cz1) {
    boolean selectionChanged = false;
    for (int cx = cx0; cx <= cx1; ++cx) {
      for (int cz = cz0; cz <= cz1; ++cz) {
        ChunkPosition chunk = ChunkPosition.get(cx, cz);
        if (!selected.contains(chunk) && !world.getChunk(chunk).isEmpty()) {
          selected.add(chunk);
          selectionChanged = true;
          notifyChunkUpdated(chunk);
        }
      }
    }
    if (selectionChanged) {
      notifyChunkSelectionChange();
    }
  }

  /**
   * Deselect chunks within rectangle.
   */
  public synchronized void deselectChunks(int cx0, int cz0, int cx1, int cz1) {
    boolean selectionChanged = false;
    for (int cx = cx0; cx <= cx1; ++cx) {
      for (int cz = cz0; cz <= cz1; ++cz) {
        ChunkPosition chunk = ChunkPosition.get(cx, cz);
        if (selected.contains(chunk)) {
          selected.remove(chunk);
          selectionChanged = true;
          notifyChunkUpdated(chunk);
        }
      }
    }
    if (selectionChanged) {
      notifyChunkSelectionChange();
    }
  }

  /**
   * Deselect all chunks.
   */
  public void clearSelection() {
    if (!selected.isEmpty()) {
      Set prev = new HashSet<>(selected);
      selected.clear();
      notifyChunksUpdated(prev);
      notifyChunkSelectionChange();
    }
  }

  /**
   * @return true if the given chunk position is selected
   */
  public boolean isSelected(ChunkPosition chunk) {
    return selected.contains(chunk);
  }

  /**
   * @return The currently selected chunks
   */
  public synchronized Collection getSelection() {
    return new LinkedList<>(selected);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy