mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-28 05:35:37 +01:00
Finish clipboard on disk
This commit is contained in:
parent
f5bbd59602
commit
57696f25f4
25
README.md
25
README.md
@ -1,4 +1,23 @@
|
|||||||
# Overview
|
# About
|
||||||
Optimize worldedit
|
FAWE is an addon for WorldEdit that has huge speed and memory improvements as well as a few extra features.
|
||||||
# Main resource page
|
|
||||||
|
# Spigot page
|
||||||
https://www.spigotmc.org/resources/13932/
|
https://www.spigotmc.org/resources/13932/
|
||||||
|
|
||||||
|
# IRC
|
||||||
|
http://webchat.esper.net/?nick=&channels=IntellectualCrafters
|
||||||
|
|
||||||
|
# Releases:
|
||||||
|
https://github.com/boy0001/FastAsyncWorldedit/releases
|
||||||
|
|
||||||
|
# Building
|
||||||
|
> FAWE uses gradle to build
|
||||||
|
|
||||||
|
gradlew setupDecompWorkspace
|
||||||
|
gradlew build
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
Have an idea for an optimization, or a cool feature?
|
||||||
|
- I'll accept most PR's
|
||||||
|
- Let me know what you've tested / what may need further testing
|
||||||
|
- If you need any help, create a ticket or discuss on IRC
|
@ -22,6 +22,7 @@ import com.sk89q.worldedit.EditSession;
|
|||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.command.ClipboardCommands;
|
||||||
import com.sk89q.worldedit.command.SchematicCommands;
|
import com.sk89q.worldedit.command.SchematicCommands;
|
||||||
import com.sk89q.worldedit.command.ScriptingCommands;
|
import com.sk89q.worldedit.command.ScriptingCommands;
|
||||||
import com.sk89q.worldedit.extension.platform.CommandManager;
|
import com.sk89q.worldedit.extension.platform.CommandManager;
|
||||||
@ -155,6 +156,7 @@ public class Fawe {
|
|||||||
*/
|
*/
|
||||||
this.setupConfigs();
|
this.setupConfigs();
|
||||||
MainUtil.deleteOlder(new File(IMP.getDirectory(), "history"), TimeUnit.DAYS.toMillis(Settings.DELETE_HISTORY_AFTER_DAYS));
|
MainUtil.deleteOlder(new File(IMP.getDirectory(), "history"), TimeUnit.DAYS.toMillis(Settings.DELETE_HISTORY_AFTER_DAYS));
|
||||||
|
MainUtil.deleteOlder(new File(IMP.getDirectory(), "clipboard"), TimeUnit.DAYS.toMillis(Settings.DELETE_CLIPBOARD_AFTER_DAYS));
|
||||||
|
|
||||||
TaskManager.IMP = this.IMP.getTaskManager();
|
TaskManager.IMP = this.IMP.getTaskManager();
|
||||||
if (Settings.METRICS) {
|
if (Settings.METRICS) {
|
||||||
@ -221,6 +223,7 @@ public class Fawe {
|
|||||||
private void setupInjector() {
|
private void setupInjector() {
|
||||||
EditSession.inject();
|
EditSession.inject();
|
||||||
Operations.inject();
|
Operations.inject();
|
||||||
|
ClipboardCommands.inject();
|
||||||
SchematicCommands.inject();
|
SchematicCommands.inject();
|
||||||
ScriptingCommands.inject();
|
ScriptingCommands.inject();
|
||||||
BreadthFirstSearch.inject();
|
BreadthFirstSearch.inject();
|
||||||
|
@ -51,6 +51,10 @@ public enum BBC {
|
|||||||
WORLDEDIT_CANCEL_REASON_MAX_FAILS("Outside allowed region", "Cancel"),
|
WORLDEDIT_CANCEL_REASON_MAX_FAILS("Outside allowed region", "Cancel"),
|
||||||
WORLDEDIT_FAILED_LOAD_CHUNK("&cSkipped loading chunk: &7%s0;%s1&c. Try increasing chunk-wait.", "Cancel"),
|
WORLDEDIT_FAILED_LOAD_CHUNK("&cSkipped loading chunk: &7%s0;%s1&c. Try increasing chunk-wait.", "Cancel"),
|
||||||
|
|
||||||
|
LOADING_CLIPBOARD("&dLoading clipboard from disk, please wait.", "History"),
|
||||||
|
INDEXING_HISTORY("&dIndexing %s history objects on disk, please wait.", "History"),
|
||||||
|
INDEXING_COMPLETE("&dIndexing complete. Took: %s seconds!", "History"),
|
||||||
|
|
||||||
WORLDEDIT_OOM_ADMIN("&cPossible options:\n&8 - &7//fast\n&8 - &7Do smaller edits\n&8 - &7Allocate more memory\n&8 - &7Disable this safeguard", "Info"),
|
WORLDEDIT_OOM_ADMIN("&cPossible options:\n&8 - &7//fast\n&8 - &7Do smaller edits\n&8 - &7Allocate more memory\n&8 - &7Disable this safeguard", "Info"),
|
||||||
NOT_PLAYER("&cYou must be a player to perform this action!", "Error"),
|
NOT_PLAYER("&cYou must be a player to perform this action!", "Error"),
|
||||||
COMPRESSED("History compressed. Saved ~ %s0b (%s1x smaller)", "Info"),
|
COMPRESSED("History compressed. Saved ~ %s0b (%s1x smaller)", "Info"),
|
||||||
|
@ -24,6 +24,7 @@ public class Settings {
|
|||||||
public static boolean STORE_CLIPBOARD_ON_DISK = false;
|
public static boolean STORE_CLIPBOARD_ON_DISK = false;
|
||||||
|
|
||||||
public static int DELETE_HISTORY_AFTER_DAYS = 7;
|
public static int DELETE_HISTORY_AFTER_DAYS = 7;
|
||||||
|
public static int DELETE_CLIPBOARD_AFTER_DAYS = 0;
|
||||||
public static int COMPRESSION_LEVEL = 0;
|
public static int COMPRESSION_LEVEL = 0;
|
||||||
public static int BUFFER_SIZE = 531441;
|
public static int BUFFER_SIZE = 531441;
|
||||||
public static boolean METRICS = true;
|
public static boolean METRICS = true;
|
||||||
@ -86,6 +87,7 @@ public class Settings {
|
|||||||
options.put("lighting.fix-all", FIX_ALL_LIGHTING);
|
options.put("lighting.fix-all", FIX_ALL_LIGHTING);
|
||||||
options.put("lighting.async", ASYNC_LIGHTING);
|
options.put("lighting.async", ASYNC_LIGHTING);
|
||||||
options.put("clipboard.use-disk", STORE_CLIPBOARD_ON_DISK);
|
options.put("clipboard.use-disk", STORE_CLIPBOARD_ON_DISK);
|
||||||
|
options.put("clipboard.delete-after-days", DELETE_CLIPBOARD_AFTER_DAYS);
|
||||||
options.put("history.use-disk", STORE_HISTORY_ON_DISK);
|
options.put("history.use-disk", STORE_HISTORY_ON_DISK);
|
||||||
options.put("history.compress", false);
|
options.put("history.compress", false);
|
||||||
options.put("history.chunk-wait-ms", CHUNK_WAIT);
|
options.put("history.chunk-wait-ms", CHUNK_WAIT);
|
||||||
@ -136,7 +138,7 @@ public class Settings {
|
|||||||
ALLOWED_3RDPARTY_EXTENTS = config.getStringList("extent.allowed-plugins");
|
ALLOWED_3RDPARTY_EXTENTS = config.getStringList("extent.allowed-plugins");
|
||||||
EXTENT_DEBUG = config.getBoolean("extent.debug");
|
EXTENT_DEBUG = config.getBoolean("extent.debug");
|
||||||
STORE_CLIPBOARD_ON_DISK = config.getBoolean("clipboard.use-disk");
|
STORE_CLIPBOARD_ON_DISK = config.getBoolean("clipboard.use-disk");
|
||||||
|
DELETE_CLIPBOARD_AFTER_DAYS = config.getInt("clipboard.delete-after-days");
|
||||||
if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) {
|
if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) {
|
||||||
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,373 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you 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 com.boydti.fawe.object;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A <code>BufferedRandomAccessFile</code> is like a
|
||||||
|
* <code>RandomAccessFile</code>, but it uses a private buffer so that most
|
||||||
|
* operations do not require a disk access.
|
||||||
|
* <P>
|
||||||
|
*
|
||||||
|
* Note: The operations on this class are unmonitored. Also, the correct
|
||||||
|
* functioning of the <code>RandomAccessFile</code> methods that are not
|
||||||
|
* overridden here relies on the implementation of those methods in the
|
||||||
|
* superclass.
|
||||||
|
* Author : Avinash Lakshman ( alakshman@facebook.com) & Prashant Malik ( pmalik@facebook.com )
|
||||||
|
*/
|
||||||
|
|
||||||
|
public final class BufferedRandomAccessFile extends RandomAccessFile
|
||||||
|
{
|
||||||
|
static final int LogBuffSz_ = 16; // 64K buffer
|
||||||
|
public static final int BuffSz_ = (1 << LogBuffSz_);
|
||||||
|
static final long BuffMask_ = ~(((long) BuffSz_) - 1L);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation is based on the buffer implementation in Modula-3's
|
||||||
|
* "Rd", "Wr", "RdClass", and "WrClass" interfaces.
|
||||||
|
*/
|
||||||
|
private boolean dirty_; // true iff unflushed bytes exist
|
||||||
|
private boolean closed_; // true iff the file is closed
|
||||||
|
private long curr_; // current position in file
|
||||||
|
private long lo_, hi_; // bounds on characters in "buff"
|
||||||
|
private byte[] buff_; // local buffer
|
||||||
|
private long maxHi_; // this.lo + this.buff.length
|
||||||
|
private boolean hitEOF_; // buffer contains last file block?
|
||||||
|
private long diskPos_; // disk position
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To describe the above fields, we introduce the following abstractions for
|
||||||
|
* the file "f":
|
||||||
|
*
|
||||||
|
* len(f) the length of the file curr(f) the current position in the file
|
||||||
|
* c(f) the abstract contents of the file disk(f) the contents of f's
|
||||||
|
* backing disk file closed(f) true iff the file is closed
|
||||||
|
*
|
||||||
|
* "curr(f)" is an index in the closed interval [0, len(f)]. "c(f)" is a
|
||||||
|
* character sequence of length "len(f)". "c(f)" and "disk(f)" may differ if
|
||||||
|
* "c(f)" contains unflushed writes not reflected in "disk(f)". The flush
|
||||||
|
* operation has the effect of making "disk(f)" identical to "c(f)".
|
||||||
|
*
|
||||||
|
* A file is said to be *valid* if the following conditions hold:
|
||||||
|
*
|
||||||
|
* V1. The "closed" and "curr" fields are correct:
|
||||||
|
*
|
||||||
|
* f.closed == closed(f) f.curr == curr(f)
|
||||||
|
*
|
||||||
|
* V2. The current position is either contained in the buffer, or just past
|
||||||
|
* the buffer:
|
||||||
|
*
|
||||||
|
* f.lo <= f.curr <= f.hi
|
||||||
|
*
|
||||||
|
* V3. Any (possibly) unflushed characters are stored in "f.buff":
|
||||||
|
*
|
||||||
|
* (forall i in [f.lo, f.curr): c(f)[i] == f.buff[i - f.lo])
|
||||||
|
*
|
||||||
|
* V4. For all characters not covered by V3, c(f) and disk(f) agree:
|
||||||
|
*
|
||||||
|
* (forall i in [f.lo, len(f)): i not in [f.lo, f.curr) => c(f)[i] ==
|
||||||
|
* disk(f)[i])
|
||||||
|
*
|
||||||
|
* V5. "f.dirty" is true iff the buffer contains bytes that should be
|
||||||
|
* flushed to the file; by V3 and V4, only part of the buffer can be dirty.
|
||||||
|
*
|
||||||
|
* f.dirty == (exists i in [f.lo, f.curr): c(f)[i] != f.buff[i - f.lo])
|
||||||
|
*
|
||||||
|
* V6. this.maxHi == this.lo + this.buff.length
|
||||||
|
*
|
||||||
|
* Note that "f.buff" can be "null" in a valid file, since the range of
|
||||||
|
* characters in V3 is empty when "f.lo == f.curr".
|
||||||
|
*
|
||||||
|
* A file is said to be *ready* if the buffer contains the current position,
|
||||||
|
* i.e., when:
|
||||||
|
*
|
||||||
|
* R1. !f.closed && f.buff != null && f.lo <= f.curr && f.curr < f.hi
|
||||||
|
*
|
||||||
|
* When a file is ready, reading or writing a single byte can be performed
|
||||||
|
* by reading or writing the in-memory buffer without performing a disk
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new <code>BufferedRandomAccessFile</code> on <code>file</code>
|
||||||
|
* in mode <code>mode</code>, which should be "r" for reading only, or
|
||||||
|
* "rw" for reading and writing.
|
||||||
|
*/
|
||||||
|
public BufferedRandomAccessFile(File file, String mode) throws IOException
|
||||||
|
{
|
||||||
|
super(file, mode);
|
||||||
|
this.init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedRandomAccessFile(File file, String mode, int size) throws IOException
|
||||||
|
{
|
||||||
|
super(file, mode);
|
||||||
|
this.init(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new <code>BufferedRandomAccessFile</code> on the file named
|
||||||
|
* <code>name</code> in mode <code>mode</code>, which should be "r" for
|
||||||
|
* reading only, or "rw" for reading and writing.
|
||||||
|
*/
|
||||||
|
public BufferedRandomAccessFile(String name, String mode) throws IOException
|
||||||
|
{
|
||||||
|
super(name, mode);
|
||||||
|
this.init(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedRandomAccessFile(String name, String mode, int size) throws FileNotFoundException
|
||||||
|
{
|
||||||
|
super(name, mode);
|
||||||
|
this.init(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(int size)
|
||||||
|
{
|
||||||
|
this.dirty_ = this.closed_ = false;
|
||||||
|
this.lo_ = this.curr_ = this.hi_ = 0;
|
||||||
|
this.buff_ = (size > BuffSz_) ? new byte[size] : new byte[BuffSz_];
|
||||||
|
this.maxHi_ = (long) BuffSz_;
|
||||||
|
this.hitEOF_ = false;
|
||||||
|
this.diskPos_ = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException
|
||||||
|
{
|
||||||
|
this.flush();
|
||||||
|
this.closed_ = true;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush any bytes in the file's buffer that have not yet been written to
|
||||||
|
* disk. If the file was created read-only, this method is a no-op.
|
||||||
|
*/
|
||||||
|
public void flush() throws IOException
|
||||||
|
{
|
||||||
|
this.flushBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush any dirty bytes in the buffer to disk. */
|
||||||
|
private void flushBuffer() throws IOException
|
||||||
|
{
|
||||||
|
if (this.dirty_)
|
||||||
|
{
|
||||||
|
if (this.diskPos_ != this.lo_)
|
||||||
|
super.seek(this.lo_);
|
||||||
|
int len = (int) (this.curr_ - this.lo_);
|
||||||
|
super.write(this.buff_, 0, len);
|
||||||
|
this.diskPos_ = this.curr_;
|
||||||
|
this.dirty_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read at most "this.buff.length" bytes into "this.buff", returning the
|
||||||
|
* number of bytes read. If the return result is less than
|
||||||
|
* "this.buff.length", then EOF was read.
|
||||||
|
*/
|
||||||
|
private int fillBuffer() throws IOException
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
int rem = this.buff_.length;
|
||||||
|
while (rem > 0)
|
||||||
|
{
|
||||||
|
int n = super.read(this.buff_, cnt, rem);
|
||||||
|
if (n < 0)
|
||||||
|
break;
|
||||||
|
cnt += n;
|
||||||
|
rem -= n;
|
||||||
|
}
|
||||||
|
if ( (cnt < 0) && (this.hitEOF_ = (cnt < this.buff_.length)) )
|
||||||
|
{
|
||||||
|
// make sure buffer that wasn't read is initialized with -1
|
||||||
|
Arrays.fill(this.buff_, cnt, this.buff_.length, (byte) 0xff);
|
||||||
|
}
|
||||||
|
this.diskPos_ += cnt;
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This method positions <code>this.curr</code> at position <code>pos</code>.
|
||||||
|
* If <code>pos</code> does not fall in the current buffer, it flushes the
|
||||||
|
* current buffer and loads the correct one.<p>
|
||||||
|
*
|
||||||
|
* On exit from this routine <code>this.curr == this.hi</code> iff <code>pos</code>
|
||||||
|
* is at or past the end-of-file, which can only happen if the file was
|
||||||
|
* opened in read-only mode.
|
||||||
|
*/
|
||||||
|
public void seek(long pos) throws IOException
|
||||||
|
{
|
||||||
|
if (pos >= this.hi_ || pos < this.lo_)
|
||||||
|
{
|
||||||
|
// seeking outside of current buffer -- flush and read
|
||||||
|
this.flushBuffer();
|
||||||
|
this.lo_ = pos & BuffMask_; // start at BuffSz boundary
|
||||||
|
this.maxHi_ = this.lo_ + (long) this.buff_.length;
|
||||||
|
if (this.diskPos_ != this.lo_)
|
||||||
|
{
|
||||||
|
super.seek(this.lo_);
|
||||||
|
this.diskPos_ = this.lo_;
|
||||||
|
}
|
||||||
|
int n = this.fillBuffer();
|
||||||
|
this.hi_ = this.lo_ + (long) n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// seeking inside current buffer -- no read required
|
||||||
|
if (pos < this.curr_)
|
||||||
|
{
|
||||||
|
// if seeking backwards, we must flush to maintain V4
|
||||||
|
this.flushBuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.curr_ = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFilePointer()
|
||||||
|
{
|
||||||
|
return this.curr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long length() throws IOException
|
||||||
|
{
|
||||||
|
return Math.max(this.curr_, super.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException
|
||||||
|
{
|
||||||
|
if (this.curr_ >= this.hi_)
|
||||||
|
{
|
||||||
|
// test for EOF
|
||||||
|
// if (this.hi < this.maxHi) return -1;
|
||||||
|
if (this.hitEOF_)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// slow path -- read another buffer
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
byte res = this.buff_[(int) (this.curr_ - this.lo_)];
|
||||||
|
this.curr_++;
|
||||||
|
return ((int) res) & 0xFF; // convert byte -> int
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b) throws IOException
|
||||||
|
{
|
||||||
|
return this.read(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException
|
||||||
|
{
|
||||||
|
if (this.curr_ >= this.hi_)
|
||||||
|
{
|
||||||
|
// test for EOF
|
||||||
|
// if (this.hi < this.maxHi) return -1;
|
||||||
|
if (this.hitEOF_)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// slow path -- read another buffer
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
len = Math.min(len, (int) (this.hi_ - this.curr_));
|
||||||
|
int buffOff = (int) (this.curr_ - this.lo_);
|
||||||
|
System.arraycopy(this.buff_, buffOff, b, off, len);
|
||||||
|
this.curr_ += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(int b) throws IOException
|
||||||
|
{
|
||||||
|
if (this.curr_ >= this.hi_)
|
||||||
|
{
|
||||||
|
if (this.hitEOF_ && this.hi_ < this.maxHi_)
|
||||||
|
{
|
||||||
|
// at EOF -- bump "hi"
|
||||||
|
this.hi_++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// slow path -- write current buffer; read next one
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_)
|
||||||
|
{
|
||||||
|
// appending to EOF -- bump "hi"
|
||||||
|
this.hi_++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.buff_[(int) (this.curr_ - this.lo_)] = (byte) b;
|
||||||
|
this.curr_++;
|
||||||
|
this.dirty_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b) throws IOException
|
||||||
|
{
|
||||||
|
this.write(b, 0, b.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException
|
||||||
|
{
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
int n = this.writeAtMost(b, off, len);
|
||||||
|
off += n;
|
||||||
|
len -= n;
|
||||||
|
this.dirty_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write at most "len" bytes to "b" starting at position "off", and return
|
||||||
|
* the number of bytes written.
|
||||||
|
*/
|
||||||
|
private int writeAtMost(byte[] b, int off, int len) throws IOException
|
||||||
|
{
|
||||||
|
if (this.curr_ >= this.hi_)
|
||||||
|
{
|
||||||
|
if (this.hitEOF_ && this.hi_ < this.maxHi_)
|
||||||
|
{
|
||||||
|
// at EOF -- bump "hi"
|
||||||
|
this.hi_ = this.maxHi_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// slow path -- write current buffer; read next one
|
||||||
|
this.seek(this.curr_);
|
||||||
|
if (this.curr_ == this.hi_)
|
||||||
|
{
|
||||||
|
// appending to EOF -- bump "hi"
|
||||||
|
this.hi_ = this.maxHi_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = Math.min(len, (int) (this.hi_ - this.curr_));
|
||||||
|
int buffOff = (int) (this.curr_ - this.lo_);
|
||||||
|
System.arraycopy(b, off, this.buff_, buffOff, len);
|
||||||
|
this.curr_ += len;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import com.boydti.fawe.FaweAPI;
|
|||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
|
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.boydti.fawe.util.WEManager;
|
import com.boydti.fawe.util.WEManager;
|
||||||
import com.boydti.fawe.wrappers.PlayerWrapper;
|
import com.boydti.fawe.wrappers.PlayerWrapper;
|
||||||
@ -13,10 +14,13 @@ import com.sk89q.worldedit.IncompleteRegionException;
|
|||||||
import com.sk89q.worldedit.LocalSession;
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.regions.RegionSelector;
|
import com.sk89q.worldedit.regions.RegionSelector;
|
||||||
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||||
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -95,12 +99,33 @@ public abstract class FawePlayer<T> {
|
|||||||
loadSessionsFromDisk(world);
|
loadSessionsFromDisk(world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
loadClipboardFromDisk();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
Fawe.debug("Failed to load history for: " + getName());
|
Fawe.debug("Failed to load history for: " + getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadClipboardFromDisk() {
|
||||||
|
try {
|
||||||
|
File file = new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + getUUID());
|
||||||
|
if (file.exists()) {
|
||||||
|
DiskOptimizedClipboard doc = new DiskOptimizedClipboard(file);
|
||||||
|
Player player = getPlayer();
|
||||||
|
LocalSession session = getSession();
|
||||||
|
if (player != null && session != null) {
|
||||||
|
sendMessage("&d" + BBC.PREFIX.s() + " " + BBC.LOADING_CLIPBOARD.s());
|
||||||
|
WorldData worldData = player.getWorld().getWorldData();
|
||||||
|
Clipboard clip = doc.toClipboard();
|
||||||
|
ClipboardHolder holder = new ClipboardHolder(clip, worldData);
|
||||||
|
getSession().setClipboard(holder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current World
|
* Get the current World
|
||||||
* @return
|
* @return
|
||||||
@ -118,12 +143,10 @@ public abstract class FawePlayer<T> {
|
|||||||
if (world == null) {
|
if (world == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TaskManager.IMP.async(new Runnable() {
|
final long start = System.currentTimeMillis();
|
||||||
@Override
|
final UUID uuid = getUUID();
|
||||||
public void run() {
|
final List<Integer> editIds = new ArrayList<>();
|
||||||
UUID uuid = getUUID();
|
final File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + world.getName() + File.separator + uuid);
|
||||||
List<Integer> editIds = new ArrayList<>();
|
|
||||||
File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + world.getName() + File.separator + uuid);
|
|
||||||
if (folder.isDirectory()) {
|
if (folder.isDirectory()) {
|
||||||
for (File file : folder.listFiles()) {
|
for (File file : folder.listFiles()) {
|
||||||
if (file.getName().endsWith(".bd")) {
|
if (file.getName().endsWith(".bd")) {
|
||||||
@ -132,22 +155,27 @@ public abstract class FawePlayer<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.sort(editIds);
|
|
||||||
if (editIds.size() > 0) {
|
if (editIds.size() > 0) {
|
||||||
Fawe.debug(BBC.PREFIX.s() + " Indexing " + editIds.size() + " history objects for " + getName());
|
sendMessage("&d" + BBC.PREFIX.s() + " " + BBC.INDEXING_HISTORY.format(editIds.size()));
|
||||||
for (int index : editIds) {
|
TaskManager.IMP.async(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Collections.sort(editIds);
|
||||||
|
for (int i = editIds.size() - 1; i >= 0; i--) {
|
||||||
|
int index = editIds.get(i);
|
||||||
DiskStorageHistory set = new DiskStorageHistory(world, uuid, index);
|
DiskStorageHistory set = new DiskStorageHistory(world, uuid, index);
|
||||||
EditSession edit = set.toEditSession(getPlayer());
|
EditSession edit = set.toEditSession(getPlayer());
|
||||||
if (world.equals(getWorld())) {
|
if (world.equals(getWorld())) {
|
||||||
session.remember(edit);
|
session.remember(edit, 0);
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
sendMessage("&d" + BBC.PREFIX.s() + " " + BBC.INDEXING_COMPLETE.format((System.currentTimeMillis() - start) / 1000d));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the player's limit
|
* Get the player's limit
|
||||||
|
@ -2,14 +2,19 @@ package com.boydti.fawe.object.clipboard;
|
|||||||
|
|
||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.config.Settings;
|
||||||
|
import com.boydti.fawe.object.BufferedRandomAccessFile;
|
||||||
import com.boydti.fawe.object.IntegerTrio;
|
import com.boydti.fawe.object.IntegerTrio;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
@ -28,55 +33,167 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class DiskOptimizedClipboard extends FaweClipboard {
|
public class DiskOptimizedClipboard extends FaweClipboard {
|
||||||
|
|
||||||
|
private static int HEADER_SIZE = 10;
|
||||||
|
|
||||||
|
protected int length;
|
||||||
|
protected int height;
|
||||||
|
protected int width;
|
||||||
|
protected int area;
|
||||||
|
|
||||||
private final HashMap<IntegerTrio, CompoundTag> nbtMap;
|
private final HashMap<IntegerTrio, CompoundTag> nbtMap;
|
||||||
private final HashSet<ClipboardEntity> entities;
|
private final HashSet<ClipboardEntity> entities;
|
||||||
private final File file;
|
private final File file;
|
||||||
private final byte[] buffer;
|
private final byte[] buffer;
|
||||||
|
|
||||||
private volatile RandomAccessFile raf;
|
private volatile BufferedRandomAccessFile raf;
|
||||||
private long lastAccessed;
|
private long lastAccessed;
|
||||||
private int last;
|
private int last;
|
||||||
|
|
||||||
|
public DiskOptimizedClipboard(int width, int height, int length, UUID uuid) {
|
||||||
|
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiskOptimizedClipboard(File file) {
|
||||||
|
nbtMap = new HashMap<>();
|
||||||
|
entities = new HashSet<>();this.buffer = new byte[2];
|
||||||
|
this.file = file;
|
||||||
|
this.lastAccessed = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
this.raf = new BufferedRandomAccessFile(file, "rw", Settings.BUFFER_SIZE);
|
||||||
|
raf.setLength(file.length());
|
||||||
|
long size = (raf.length() - HEADER_SIZE) / 2;
|
||||||
|
raf.seek(0);
|
||||||
|
last = -1;
|
||||||
|
raf.read(buffer);
|
||||||
|
width = (((buffer[1] & 0xFF) << 8) + ((buffer[0] & 0xFF)));
|
||||||
|
raf.read(buffer);
|
||||||
|
length = (((buffer[1] & 0xFF) << 8) + ((buffer[0] & 0xFF)));
|
||||||
|
height = (int) (size / (width * length));
|
||||||
|
area = width * length;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
autoCloseTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockArrayClipboard toClipboard() {
|
||||||
|
try {
|
||||||
|
CuboidRegion region = new CuboidRegion(new Vector(0, 0, 0), new Vector(width - 1, height - 1, length - 1)) {
|
||||||
|
@Override
|
||||||
|
public boolean contains(Vector position) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (raf == null) {
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
raf.seek(4);
|
||||||
|
last = -1;
|
||||||
|
int ox = (((byte) raf.read() << 8) | ((byte) raf.read()) & 0xFF);
|
||||||
|
int oy = (((byte) raf.read() << 8) | ((byte) raf.read()) & 0xFF);
|
||||||
|
int oz = (((byte) raf.read() << 8) | ((byte) raf.read()) & 0xFF);
|
||||||
|
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, this);
|
||||||
|
clipboard.setOrigin(new Vector(ox, oy, oz));
|
||||||
|
return clipboard;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOrigin(Vector offset) {
|
||||||
|
try {
|
||||||
|
if (raf == null) {
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
raf.seek(4);
|
||||||
|
last = -1;
|
||||||
|
raf.write((byte) (offset.getBlockX() >> 8));
|
||||||
|
raf.write((byte) (offset.getBlockX()));
|
||||||
|
|
||||||
|
raf.write((byte) (offset.getBlockY() >> 8));
|
||||||
|
raf.write((byte) (offset.getBlockY()));
|
||||||
|
|
||||||
|
raf.write((byte) (offset.getBlockZ() >> 8));
|
||||||
|
raf.write((byte) (offset.getBlockZ()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DiskOptimizedClipboard(int width, int height, int length, File file) {
|
public DiskOptimizedClipboard(int width, int height, int length, File file) {
|
||||||
super(width, height, length);
|
|
||||||
nbtMap = new HashMap<>();
|
nbtMap = new HashMap<>();
|
||||||
entities = new HashSet<>();
|
entities = new HashSet<>();
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.buffer = new byte[2];
|
this.buffer = new byte[2];
|
||||||
this.lastAccessed = System.currentTimeMillis();
|
this.lastAccessed = System.currentTimeMillis();
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.length = length;
|
||||||
|
this.area = width * length;
|
||||||
try {
|
try {
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
file.createNewFile();
|
|
||||||
}
|
}
|
||||||
|
file.createNewFile();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
raf.close();
|
||||||
|
raf = null;
|
||||||
|
file.setWritable(true);
|
||||||
|
System.gc();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public DiskOptimizedClipboard(int width, int height, int length) {
|
public DiskOptimizedClipboard(int width, int height, int length) {
|
||||||
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + UUID.randomUUID()));
|
this(width, height, length, new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + UUID.randomUUID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
|
||||||
public void open() throws IOException {
|
|
||||||
this.raf = new RandomAccessFile(file, "rw");
|
|
||||||
long size = width * height * length * 2l;
|
|
||||||
if (raf.length() != size) {
|
|
||||||
raf.setLength(size);
|
|
||||||
}
|
|
||||||
TaskManager.IMP.laterAsync(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (raf != null && System.currentTimeMillis() - lastAccessed > 10000) {
|
|
||||||
try {
|
try {
|
||||||
RandomAccessFile tmp = raf;
|
RandomAccessFile tmp = raf;
|
||||||
raf = null;
|
raf = null;
|
||||||
tmp.close();
|
tmp.close();
|
||||||
|
tmp = null;
|
||||||
|
System.gc();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open() throws IOException {
|
||||||
|
if (raf != null) {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
this.raf = new BufferedRandomAccessFile(file, "rw", Settings.BUFFER_SIZE);
|
||||||
|
long size = width * height * length * 2l;
|
||||||
|
if (raf.length() != size) {
|
||||||
|
raf.setLength(size + HEADER_SIZE);
|
||||||
|
// write length etc
|
||||||
|
raf.seek(0);
|
||||||
|
last = 0;
|
||||||
|
raf.write((width) & 0xff);
|
||||||
|
raf.write(((width) >> 8) & 0xff);
|
||||||
|
raf.write((length) & 0xff);
|
||||||
|
raf.write(((length) >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
autoCloseTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void autoCloseTask() {
|
||||||
|
TaskManager.IMP.laterAsync(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (raf != null && System.currentTimeMillis() - lastAccessed > 10000) {
|
||||||
|
close();
|
||||||
} else if (raf == null) {
|
} else if (raf == null) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@ -95,7 +212,7 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
|||||||
lastAccessed = System.currentTimeMillis();
|
lastAccessed = System.currentTimeMillis();
|
||||||
int i = x + z * width + y * area;
|
int i = x + z * width + y * area;
|
||||||
if (i != last + 1) {
|
if (i != last + 1) {
|
||||||
raf.seek(i << 1);
|
raf.seek((HEADER_SIZE) + (i << 1));
|
||||||
}
|
}
|
||||||
raf.read(buffer);
|
raf.read(buffer);
|
||||||
last = i;
|
last = i;
|
||||||
@ -129,8 +246,9 @@ public class DiskOptimizedClipboard extends FaweClipboard {
|
|||||||
lastAccessed = System.currentTimeMillis();
|
lastAccessed = System.currentTimeMillis();
|
||||||
int i = x + z * width + y * area;
|
int i = x + z * width + y * area;
|
||||||
if (i != last + 1) {
|
if (i != last + 1) {
|
||||||
raf.seek(i << 1);
|
raf.seek((HEADER_SIZE) + (i << 1));
|
||||||
}
|
}
|
||||||
|
last = i;
|
||||||
final int id = block.getId();
|
final int id = block.getId();
|
||||||
final int data = block.getData();
|
final int data = block.getData();
|
||||||
int combined = (id << 4) + data;
|
int combined = (id << 4) + data;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.boydti.fawe.object.clipboard;
|
package com.boydti.fawe.object.clipboard;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
@ -12,18 +13,6 @@ import javax.annotation.Nullable;
|
|||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
public abstract class FaweClipboard {
|
public abstract class FaweClipboard {
|
||||||
public final int length;
|
|
||||||
public final int height;
|
|
||||||
public final int width;
|
|
||||||
public final int area;
|
|
||||||
|
|
||||||
public FaweClipboard(int width, int height, int length) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.length = length;
|
|
||||||
this.area = width * length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract BaseBlock getBlock(int x, int y, int z);
|
public abstract BaseBlock getBlock(int x, int y, int z);
|
||||||
|
|
||||||
public abstract boolean setBlock(int x, int y, int z, BaseBlock block);
|
public abstract boolean setBlock(int x, int y, int z, BaseBlock block);
|
||||||
@ -34,6 +23,8 @@ public abstract class FaweClipboard {
|
|||||||
|
|
||||||
public abstract boolean remove(ClipboardEntity clipboardEntity);
|
public abstract boolean remove(ClipboardEntity clipboardEntity);
|
||||||
|
|
||||||
|
public void setOrigin(Vector offset) {} // Do nothing
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores entity data.
|
* Stores entity data.
|
||||||
*/
|
*/
|
||||||
|
@ -13,6 +13,10 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MemoryOptimizedClipboard extends FaweClipboard {
|
public class MemoryOptimizedClipboard extends FaweClipboard {
|
||||||
|
protected int length;
|
||||||
|
protected int height;
|
||||||
|
protected int width;
|
||||||
|
protected int area;
|
||||||
|
|
||||||
// x,z,y+15>>4 | y&15
|
// x,z,y+15>>4 | y&15
|
||||||
private final byte[][] ids;
|
private final byte[][] ids;
|
||||||
@ -21,10 +25,13 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
|
|||||||
private final HashSet<ClipboardEntity> entities;
|
private final HashSet<ClipboardEntity> entities;
|
||||||
|
|
||||||
public MemoryOptimizedClipboard(int width, int height, int length) {
|
public MemoryOptimizedClipboard(int width, int height, int length) {
|
||||||
super(width, height, length);
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.length = length;
|
||||||
|
this.area = width * length;
|
||||||
ids = new byte[width * length * ((height + 15) >> 4)][];
|
ids = new byte[width * length * ((height + 15) >> 4)][];
|
||||||
nbtMap = new HashMap<>();
|
nbtMap = new HashMap<>();
|
||||||
entities = new HashSet<ClipboardEntity>();
|
entities = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -35,6 +35,24 @@ public class MainUtil {
|
|||||||
Fawe.debug(s);
|
Fawe.debug(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void warnDeprecated(Class... alternatives) {
|
||||||
|
StackTraceElement[] stack = new RuntimeException().getStackTrace();
|
||||||
|
if (stack.length > 1) {
|
||||||
|
try {
|
||||||
|
StackTraceElement creatorElement = stack[stack.length - 2];
|
||||||
|
String className = creatorElement.getClassName();
|
||||||
|
Class clazz = Class.forName(className);
|
||||||
|
String creator = clazz.getSimpleName();
|
||||||
|
String packageName = clazz.getPackage().getName();
|
||||||
|
|
||||||
|
StackTraceElement deprecatedElement = stack[stack.length - 1];
|
||||||
|
String myName = Class.forName(deprecatedElement.getFileName()).getSimpleName();
|
||||||
|
Fawe.debug("@" + creator + " from " + packageName +": " + myName + " is deprecated.");
|
||||||
|
Fawe.debug(" - Alternatives: " + StringMan.getString(alternatives));
|
||||||
|
} catch (Throwable ignore) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void iterateFiles(File directory, RunnableVal<File> task) {
|
public static void iterateFiles(File directory, RunnableVal<File> task) {
|
||||||
if (directory.exists()) {
|
if (directory.exists()) {
|
||||||
File[] files = directory.listFiles();
|
File[] files = directory.listFiles();
|
||||||
|
@ -21,12 +21,14 @@ package com.sk89q.worldedit;
|
|||||||
|
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.object.IntegerTrio;
|
import com.boydti.fawe.object.IntegerTrio;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.blocks.BlockID;
|
import com.sk89q.worldedit.blocks.BlockID;
|
||||||
import com.sk89q.worldedit.command.ClipboardCommands;
|
import com.sk89q.worldedit.command.ClipboardCommands;
|
||||||
import com.sk89q.worldedit.command.SchematicCommands;
|
import com.sk89q.worldedit.command.SchematicCommands;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
@ -76,7 +78,7 @@ public class CuboidClipboard {
|
|||||||
public byte[][] ids;
|
public byte[][] ids;
|
||||||
public byte[][] datas;
|
public byte[][] datas;
|
||||||
public HashMap<IntegerTrio, CompoundTag> nbtMap;
|
public HashMap<IntegerTrio, CompoundTag> nbtMap;
|
||||||
public List<CopiedEntity> entities = new ArrayList<CopiedEntity>();
|
public List<CopiedEntity> entities = new ArrayList<>();
|
||||||
|
|
||||||
public Vector size;
|
public Vector size;
|
||||||
private int dx;
|
private int dx;
|
||||||
@ -91,6 +93,7 @@ public class CuboidClipboard {
|
|||||||
*/
|
*/
|
||||||
public CuboidClipboard(Vector size) {
|
public CuboidClipboard(Vector size) {
|
||||||
checkNotNull(size);
|
checkNotNull(size);
|
||||||
|
MainUtil.warnDeprecated(BlockArrayClipboard.class);
|
||||||
origin = new Vector();
|
origin = new Vector();
|
||||||
offset = new Vector();
|
offset = new Vector();
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
package com.sk89q.worldedit;
|
package com.sk89q.worldedit;
|
||||||
|
|
||||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||||
|
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||||
|
import com.boydti.fawe.util.FaweQueue;
|
||||||
import com.boydti.fawe.util.SetQueue;
|
import com.boydti.fawe.util.SetQueue;
|
||||||
import com.sk89q.jchronic.Chronic;
|
import com.sk89q.jchronic.Chronic;
|
||||||
import com.sk89q.jchronic.Options;
|
import com.sk89q.jchronic.Options;
|
||||||
@ -32,6 +34,8 @@ import com.sk89q.worldedit.command.tool.SinglePickaxe;
|
|||||||
import com.sk89q.worldedit.command.tool.Tool;
|
import com.sk89q.worldedit.command.tool.Tool;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
import com.sk89q.worldedit.function.mask.Masks;
|
import com.sk89q.worldedit.function.mask.Masks;
|
||||||
@ -190,11 +194,17 @@ public class LocalSession {
|
|||||||
* @param editSession the edit session
|
* @param editSession the edit session
|
||||||
*/
|
*/
|
||||||
public void remember(EditSession editSession) {
|
public void remember(EditSession editSession) {
|
||||||
checkNotNull(editSession);
|
remember(editSession, history.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remember(EditSession editSession, int index) {
|
||||||
|
// Enqueue it
|
||||||
if (editSession.getQueue() != null) {
|
if (editSession.getQueue() != null) {
|
||||||
|
FaweQueue queue = editSession.getQueue();
|
||||||
|
if (queue.size() > 0) {
|
||||||
SetQueue.IMP.enqueue(editSession.getQueue());
|
SetQueue.IMP.enqueue(editSession.getQueue());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Don't store anything if no changes were made
|
// Don't store anything if no changes were made
|
||||||
if (editSession.size() == 0) return;
|
if (editSession.size() == 0) return;
|
||||||
@ -207,7 +217,7 @@ public class LocalSession {
|
|||||||
if (set instanceof FaweChangeSet) {
|
if (set instanceof FaweChangeSet) {
|
||||||
((FaweChangeSet) set).flush();
|
((FaweChangeSet) set).flush();
|
||||||
}
|
}
|
||||||
history.add(editSession);
|
history.add(Math.max(0, Math.min(index, history.size())), editSession);
|
||||||
while (history.size() > MAX_HISTORY_SIZE) {
|
while (history.size() > MAX_HISTORY_SIZE) {
|
||||||
history.remove(0);
|
history.remove(0);
|
||||||
}
|
}
|
||||||
@ -456,6 +466,15 @@ public class LocalSession {
|
|||||||
* @param clipboard the clipboard, or null if the clipboard is to be cleared
|
* @param clipboard the clipboard, or null if the clipboard is to be cleared
|
||||||
*/
|
*/
|
||||||
public void setClipboard(@Nullable ClipboardHolder clipboard) {
|
public void setClipboard(@Nullable ClipboardHolder clipboard) {
|
||||||
|
if (this.clipboard != null && clipboard != null) {
|
||||||
|
Clipboard clip = clipboard.getClipboard();
|
||||||
|
if (clip instanceof BlockArrayClipboard) {
|
||||||
|
BlockArrayClipboard bac = (BlockArrayClipboard) clip;
|
||||||
|
if (bac.IMP instanceof DiskOptimizedClipboard) {
|
||||||
|
((DiskOptimizedClipboard) bac.IMP).flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.clipboard = clipboard;
|
this.clipboard = clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,263 @@
|
|||||||
|
/*
|
||||||
|
* WorldEdit, a Minecraft world manipulation toolkit
|
||||||
|
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||||
|
* Copyright (C) WorldEdit team and contributors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.sk89q.worldedit.command;
|
||||||
|
|
||||||
|
import com.sk89q.minecraft.util.commands.Command;
|
||||||
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
|
import com.sk89q.minecraft.util.commands.Logging;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
import com.sk89q.worldedit.LocalSession;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
|
import com.sk89q.worldedit.function.block.BlockReplace;
|
||||||
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
|
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
|
||||||
|
import com.sk89q.worldedit.function.operation.Operation;
|
||||||
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
|
import com.sk89q.worldedit.internal.annotation.Direction;
|
||||||
|
import com.sk89q.worldedit.internal.annotation.Selection;
|
||||||
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
import com.sk89q.worldedit.regions.Region;
|
||||||
|
import com.sk89q.worldedit.regions.RegionSelector;
|
||||||
|
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
|
||||||
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
|
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||||
|
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
|
||||||
|
import static com.sk89q.minecraft.util.commands.Logging.LogMode.REGION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clipboard commands.
|
||||||
|
*/
|
||||||
|
public class ClipboardCommands {
|
||||||
|
|
||||||
|
private final WorldEdit worldEdit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param worldEdit reference to WorldEdit
|
||||||
|
*/
|
||||||
|
public ClipboardCommands(WorldEdit worldEdit) {
|
||||||
|
checkNotNull(worldEdit);
|
||||||
|
this.worldEdit = worldEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/copy" },
|
||||||
|
flags = "em",
|
||||||
|
desc = "Copy the selection to the clipboard",
|
||||||
|
help = "Copy the selection to the clipboard\n" +
|
||||||
|
"Flags:\n" +
|
||||||
|
" -e controls whether entities are copied\n" +
|
||||||
|
" -m sets a source mask so that excluded blocks become air\n" +
|
||||||
|
"WARNING: Pasting entities cannot yet be undone!",
|
||||||
|
min = 0,
|
||||||
|
max = 0
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.clipboard.copy")
|
||||||
|
public void copy(Player player, LocalSession session, EditSession editSession,
|
||||||
|
@Selection Region region, @Switch('e') boolean copyEntities,
|
||||||
|
@Switch('m') Mask mask) throws WorldEditException {
|
||||||
|
|
||||||
|
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId());
|
||||||
|
|
||||||
|
|
||||||
|
clipboard.setOrigin(session.getPlacementPosition(player));
|
||||||
|
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
|
||||||
|
if (mask != null) {
|
||||||
|
copy.setSourceMask(mask);
|
||||||
|
}
|
||||||
|
Operations.completeLegacy(copy);
|
||||||
|
session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
|
||||||
|
|
||||||
|
player.print(region.getArea() + " block(s) were copied.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/cut" },
|
||||||
|
flags = "em",
|
||||||
|
usage = "[leave-id]",
|
||||||
|
desc = "Cut the selection to the clipboard",
|
||||||
|
help = "Copy the selection to the clipboard\n" +
|
||||||
|
"Flags:\n" +
|
||||||
|
" -e controls whether entities are copied\n" +
|
||||||
|
" -m sets a source mask so that excluded blocks become air\n" +
|
||||||
|
"WARNING: Cutting and pasting entities cannot yet be undone!",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.clipboard.cut")
|
||||||
|
@Logging(REGION)
|
||||||
|
public void cut(Player player, LocalSession session, EditSession editSession,
|
||||||
|
@Selection Region region, @Optional("air") Pattern leavePattern, @Switch('e') boolean copyEntities,
|
||||||
|
@Switch('m') Mask mask) throws WorldEditException {
|
||||||
|
|
||||||
|
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, player.getUniqueId());
|
||||||
|
clipboard.setOrigin(session.getPlacementPosition(player));
|
||||||
|
ForwardExtentCopy copy = new ForwardExtentCopy(editSession, region, clipboard, region.getMinimumPoint());
|
||||||
|
copy.setSourceFunction(new BlockReplace(editSession, leavePattern));
|
||||||
|
if (mask != null) {
|
||||||
|
copy.setSourceMask(mask);
|
||||||
|
}
|
||||||
|
Operations.completeLegacy(copy);
|
||||||
|
session.setClipboard(new ClipboardHolder(clipboard, editSession.getWorld().getWorldData()));
|
||||||
|
|
||||||
|
player.print(region.getArea() + " block(s) were copied.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/paste" },
|
||||||
|
usage = "",
|
||||||
|
flags = "sao",
|
||||||
|
desc = "Paste the clipboard's contents",
|
||||||
|
help =
|
||||||
|
"Pastes the clipboard's contents.\n" +
|
||||||
|
"Flags:\n" +
|
||||||
|
" -a skips air blocks\n" +
|
||||||
|
" -o pastes at the original position\n" +
|
||||||
|
" -s selects the region after pasting",
|
||||||
|
min = 0,
|
||||||
|
max = 0
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.clipboard.paste")
|
||||||
|
@Logging(PLACEMENT)
|
||||||
|
public void paste(Player player, LocalSession session, EditSession editSession,
|
||||||
|
@Switch('a') boolean ignoreAirBlocks, @Switch('o') boolean atOrigin,
|
||||||
|
@Switch('s') boolean selectPasted) throws WorldEditException {
|
||||||
|
|
||||||
|
ClipboardHolder holder = session.getClipboard();
|
||||||
|
Clipboard clipboard = holder.getClipboard();
|
||||||
|
Region region = clipboard.getRegion();
|
||||||
|
|
||||||
|
Vector to = atOrigin ? clipboard.getOrigin() : session.getPlacementPosition(player);
|
||||||
|
Operation operation = holder
|
||||||
|
.createPaste(editSession, editSession.getWorld().getWorldData())
|
||||||
|
.to(to)
|
||||||
|
.ignoreAirBlocks(ignoreAirBlocks)
|
||||||
|
.build();
|
||||||
|
Operations.completeLegacy(operation);
|
||||||
|
|
||||||
|
if (selectPasted) {
|
||||||
|
Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint()));
|
||||||
|
RegionSelector selector = new CuboidRegionSelector(player.getWorld(), to, max);
|
||||||
|
session.setRegionSelector(player.getWorld(), selector);
|
||||||
|
selector.learnChanges();
|
||||||
|
selector.explainRegionAdjust(player, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
player.print("The clipboard has been pasted at " + to);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/rotate" },
|
||||||
|
usage = "<y-axis> [<x-axis>] [<z-axis>]",
|
||||||
|
desc = "Rotate the contents of the clipboard",
|
||||||
|
help = "Non-destructively rotate the contents of the clipboard.\n" +
|
||||||
|
"Angles are provided in degrees and a positive angle will result in a clockwise rotation. " +
|
||||||
|
"Multiple rotations can be stacked. Interpolation is not performed so angles should be a multiple of 90 degrees.\n"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.clipboard.rotate")
|
||||||
|
public void rotate(Player player, LocalSession session, Double yRotate, @Optional Double xRotate, @Optional Double zRotate) throws WorldEditException {
|
||||||
|
if ((yRotate != null && Math.abs(yRotate % 90) > 0.001) ||
|
||||||
|
xRotate != null && Math.abs(xRotate % 90) > 0.001 ||
|
||||||
|
zRotate != null && Math.abs(zRotate % 90) > 0.001) {
|
||||||
|
player.printDebug("Note: Interpolation is not yet supported, so angles that are multiples of 90 is recommended.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardHolder holder = session.getClipboard();
|
||||||
|
AffineTransform transform = new AffineTransform();
|
||||||
|
transform = transform.rotateY(-(yRotate != null ? yRotate : 0));
|
||||||
|
transform = transform.rotateX(-(xRotate != null ? xRotate : 0));
|
||||||
|
transform = transform.rotateZ(-(zRotate != null ? zRotate : 0));
|
||||||
|
holder.setTransform(holder.getTransform().combine(transform));
|
||||||
|
player.print("The clipboard copy has been rotated.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/flip" },
|
||||||
|
usage = "[<direction>]",
|
||||||
|
desc = "Flip the contents of the clipboard",
|
||||||
|
help =
|
||||||
|
"Flips the contents of the clipboard across the point from which the copy was made.\n",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.clipboard.flip")
|
||||||
|
public void flip(Player player, LocalSession session, EditSession editSession,
|
||||||
|
@Optional(Direction.AIM) @Direction Vector direction) throws WorldEditException {
|
||||||
|
ClipboardHolder holder = session.getClipboard();
|
||||||
|
Clipboard clipboard = holder.getClipboard();
|
||||||
|
AffineTransform transform = new AffineTransform();
|
||||||
|
transform = transform.scale(direction.positive().multiply(-2).add(1, 1, 1));
|
||||||
|
holder.setTransform(holder.getTransform().combine(transform));
|
||||||
|
player.print("The clipboard copy has been flipped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/load" },
|
||||||
|
usage = "<filename>",
|
||||||
|
desc = "Load a schematic into your clipboard",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@Deprecated
|
||||||
|
@CommandPermissions("worldedit.clipboard.load")
|
||||||
|
public void load(Actor actor) {
|
||||||
|
actor.printError("This command is no longer used. See //schematic load.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "/save" },
|
||||||
|
usage = "<filename>",
|
||||||
|
desc = "Save a schematic into your clipboard",
|
||||||
|
min = 0,
|
||||||
|
max = 1
|
||||||
|
)
|
||||||
|
@Deprecated
|
||||||
|
@CommandPermissions("worldedit.clipboard.save")
|
||||||
|
public void save(Actor actor) {
|
||||||
|
actor.printError("This command is no longer used. See //schematic save.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = { "clearclipboard" },
|
||||||
|
usage = "",
|
||||||
|
desc = "Clear your clipboard",
|
||||||
|
min = 0,
|
||||||
|
max = 0
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.clipboard.clear")
|
||||||
|
public void clearClipboard(Player player, LocalSession session, EditSession editSession) throws WorldEditException {
|
||||||
|
session.setClipboard(null);
|
||||||
|
player.print("Clipboard cleared.");
|
||||||
|
}
|
||||||
|
public static Class<?> inject() {
|
||||||
|
return ClipboardCommands.class;
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
|||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
|
||||||
import com.sk89q.worldedit.function.operation.Operations;
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
import com.sk89q.worldedit.math.transform.Transform;
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
@ -117,9 +118,13 @@ public class SchematicCommands {
|
|||||||
final ClipboardReader reader = format.getReader(bis);
|
final ClipboardReader reader = format.getReader(bis);
|
||||||
|
|
||||||
final WorldData worldData = player.getWorld().getWorldData();
|
final WorldData worldData = player.getWorld().getWorldData();
|
||||||
final Clipboard clipboard = reader.read(player.getWorld().getWorldData());
|
final Clipboard clipboard;
|
||||||
|
if (reader instanceof SchematicReader) {
|
||||||
|
clipboard = ((SchematicReader) reader).read(player.getWorld().getWorldData(), player.getUniqueId());
|
||||||
|
} else {
|
||||||
|
clipboard = reader.read(player.getWorld().getWorldData());
|
||||||
|
}
|
||||||
session.setClipboard(new ClipboardHolder(clipboard, worldData));
|
session.setClipboard(new ClipboardHolder(clipboard, worldData));
|
||||||
|
|
||||||
log.info(player.getName() + " loaded " + filePath);
|
log.info(player.getName() + " loaded " + filePath);
|
||||||
player.print(filename + " loaded. Paste it with //paste");
|
player.print(filename + " loaded. Paste it with //paste");
|
||||||
}
|
}
|
||||||
@ -160,7 +165,7 @@ public class SchematicCommands {
|
|||||||
// If we have a transform, bake it into the copy
|
// If we have a transform, bake it into the copy
|
||||||
if (!transform.isIdentity()) {
|
if (!transform.isIdentity()) {
|
||||||
final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform, holder.getWorldData());
|
final FlattenedClipboardTransform result = FlattenedClipboardTransform.transform(clipboard, transform, holder.getWorldData());
|
||||||
target = new BlockArrayClipboard(result.getTransformedRegion());
|
target = new BlockArrayClipboard(result.getTransformedRegion(), player.getUniqueId());
|
||||||
target.setOrigin(clipboard.getOrigin());
|
target.setOrigin(clipboard.getOrigin());
|
||||||
Operations.completeLegacy(result.copyTo(target));
|
Operations.completeLegacy(result.copyTo(target));
|
||||||
} else {
|
} else {
|
||||||
|
@ -37,6 +37,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
@ -64,6 +65,17 @@ public class BlockArrayClipboard implements Clipboard {
|
|||||||
|
|
||||||
private Vector origin;
|
private Vector origin;
|
||||||
|
|
||||||
|
public BlockArrayClipboard(Region region) {
|
||||||
|
checkNotNull(region);
|
||||||
|
this.region = region.clone();
|
||||||
|
this.size = getDimensions();
|
||||||
|
this.IMP = Settings.STORE_CLIPBOARD_ON_DISK ? new DiskOptimizedClipboard(size.getBlockX(), size.getBlockY(), size.getBlockZ()) : new MemoryOptimizedClipboard(size.getBlockX(), size.getBlockY(), size.getBlockZ());
|
||||||
|
this.origin = region.getMinimumPoint();
|
||||||
|
this.mx = origin.getBlockX();
|
||||||
|
this.my = origin.getBlockY();
|
||||||
|
this.mz = origin.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance.
|
* Create a new instance.
|
||||||
*
|
*
|
||||||
@ -71,11 +83,22 @@ public class BlockArrayClipboard implements Clipboard {
|
|||||||
*
|
*
|
||||||
* @param region the bounding region
|
* @param region the bounding region
|
||||||
*/
|
*/
|
||||||
public BlockArrayClipboard(Region region) {
|
public BlockArrayClipboard(Region region, UUID clipboardId) {
|
||||||
checkNotNull(region);
|
checkNotNull(region);
|
||||||
this.region = region.clone();
|
this.region = region.clone();
|
||||||
this.size = getDimensions();
|
this.size = getDimensions();
|
||||||
this.IMP = Settings.STORE_CLIPBOARD_ON_DISK ? new DiskOptimizedClipboard(size.getBlockX(), size.getBlockY(), size.getBlockZ()) : new MemoryOptimizedClipboard(size.getBlockX(), size.getBlockY(), size.getBlockZ());
|
this.IMP = Settings.STORE_CLIPBOARD_ON_DISK ? new DiskOptimizedClipboard(size.getBlockX(), size.getBlockY(), size.getBlockZ(), clipboardId) : new MemoryOptimizedClipboard(size.getBlockX(), size.getBlockY(), size.getBlockZ());
|
||||||
|
this.origin = region.getMinimumPoint();
|
||||||
|
this.mx = origin.getBlockX();
|
||||||
|
this.my = origin.getBlockY();
|
||||||
|
this.mz = origin.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockArrayClipboard(Region region, DiskOptimizedClipboard clipboard) {
|
||||||
|
checkNotNull(region);
|
||||||
|
this.region = region.clone();
|
||||||
|
this.size = getDimensions();
|
||||||
|
this.IMP = clipboard;
|
||||||
this.origin = region.getMinimumPoint();
|
this.origin = region.getMinimumPoint();
|
||||||
this.mx = origin.getBlockX();
|
this.mx = origin.getBlockX();
|
||||||
this.my = origin.getBlockY();
|
this.my = origin.getBlockY();
|
||||||
@ -95,6 +118,7 @@ public class BlockArrayClipboard implements Clipboard {
|
|||||||
@Override
|
@Override
|
||||||
public void setOrigin(Vector origin) {
|
public void setOrigin(Vector origin) {
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
|
IMP.setOrigin(origin.subtract(region.getMinimumPoint()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,6 +44,7 @@ import java.io.IOException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@ -71,6 +72,10 @@ public class SchematicReader implements ClipboardReader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Clipboard read(WorldData data) throws IOException {
|
public Clipboard read(WorldData data) throws IOException {
|
||||||
|
return read(data, UUID.randomUUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Clipboard read(WorldData data, UUID clipboardId) throws IOException {
|
||||||
// Schematic tag
|
// Schematic tag
|
||||||
NamedTag rootTag = inputStream.readNamedTag();
|
NamedTag rootTag = inputStream.readNamedTag();
|
||||||
if (!rootTag.getName().equals("Schematic")) {
|
if (!rootTag.getName().equals("Schematic")) {
|
||||||
@ -171,7 +176,7 @@ public class SchematicReader implements ClipboardReader {
|
|||||||
tileEntitiesMap.put(vec, values);
|
tileEntitiesMap.put(vec, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
|
BlockArrayClipboard clipboard = new BlockArrayClipboard(region, clipboardId);
|
||||||
clipboard.setOrigin(origin);
|
clipboard.setOrigin(origin);
|
||||||
|
|
||||||
// Don't log a torrent of errors
|
// Don't log a torrent of errors
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#Mon Feb 22 17:40:44 PST 2016
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip
|
Loading…
Reference in New Issue
Block a user