Restructure

This commit is contained in:
Jesse Boyd 2016-04-24 06:41:07 +10:00
parent 00c9e40b1d
commit 053d7a6482
56 changed files with 4808 additions and 210 deletions

9
.gitignore vendored
View File

@ -10,8 +10,11 @@
/target/
/.gradle
/.idea
/forge/build
forge/.gradle/gradle.log
*.log
gradle.log
/lib
/core/build
/core/build
/forge189/build
/forge1710/build
/sponge/build
/bukkit/build

View File

@ -10,7 +10,7 @@ buildscript {
}
group = 'com.boydti.fawe'
version = '3.3.21'
version = '3.4.0'
description = """FastAsyncWorldEdit"""
subprojects {
@ -35,7 +35,6 @@ subprojects {
maven {url "http://maven.sk89q.com/repo/"}
maven {url "http://nexus.theyeticave.net/content/repositories/pub_releases"}
maven {url "http://repo.maven.apache.org/maven2"}
maven {url "http://repo.techcable.net/content/groups/public/"}
maven {url "http://hub.spigotmc.org/nexus/content/groups/public/"}
maven {url "http://ci.frostcast.net/plugin/repository/everything"}
maven {url "http://maven.sk89q.com/artifactory/repo/"}

View File

@ -1,6 +1,6 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.FaweBukkit
version: 3.3.21
version: 3.4.0
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]

View File

@ -28,13 +28,12 @@ import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -121,15 +120,6 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
debug("&6Metrics enabled.");
}
@Override
public Set<FawePlayer> getPlayers() {
HashSet<FawePlayer> players = new HashSet<>();
for (Player player : Bukkit.getServer().getOnlinePlayers()) {
players.add(wrap(player));
}
return players;
}
/**
* Kinda a really messy class I just copied over from an old project<br>
* - Still works, so cbf cleaning it up<br>
@ -239,6 +229,11 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
return new BukkitQueue_All(world);
}
@Override
public String getWorldName(World world) {
return world.getName();
}
/**
* The EditSessionWrapper should have the same functionality as the normal EditSessionWrapper but with some optimizations
*/
@ -358,7 +353,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
FawePlayer fp = FawePlayer.wrap(player);
if (Settings.STORE_HISTORY_ON_DISK) {
fp.getSession().clearHistory();
fp.loadSessionFromDisk(fp.getWorld());
fp.loadSessionsFromDisk(fp.getWorld());
}
}

View File

@ -43,7 +43,6 @@ public class LoggingExtent extends AbstractDelegateExtent {
* @param changeSet the change set
* @param api
* @param player
* @param thread
*/
public LoggingExtent(final Extent extent, final ChangeSet changeSet, final FawePlayer<Player> player, final IBlocksHubApi api) {
super(extent);

View File

@ -246,7 +246,9 @@ public class BukkitQueue_1_8 extends BukkitQueue_All {
}
return true;
} catch (final Throwable e) {
e.printStackTrace();
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}

View File

@ -1,6 +1,6 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.FaweBukkit
version: 3.3.21
version: 3.4.0
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]

View File

@ -44,6 +44,7 @@ import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryUsage;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@ -154,14 +155,11 @@ public class Fawe {
this.setupConfigs();
MainUtil.deleteOlder(new File(IMP.getDirectory(), "history"), TimeUnit.DAYS.toMillis(Settings.DELETE_HISTORY_AFTER_DAYS));
this.setupCommands();
// TODO command event - queue?
TaskManager.IMP = this.IMP.getTaskManager();
if (Settings.METRICS) {
this.IMP.startMetrics();
}
this.setupCommands();
// Delayed setup
TaskManager.IMP.later(new Runnable() {
@ -337,6 +335,10 @@ public class Fawe {
return players.get(name);
}
public Collection<FawePlayer> getCachedPlayers() {
return players.values();
}
/*
* TODO FIXME
* - Async packet sending

View File

@ -87,6 +87,15 @@ public class FaweAPI {
return SetQueue.IMP.getNewQueue(worldName, autoqueue);
}
public static World getWorld(String worldName) {
for (World current : WorldEdit.getInstance().getServer().getWorlds()) {
if (Fawe.imp().getWorldName(current).equals(worldName)) {
return current;
}
}
return null;
}
/**
* Get a list of supported protection plugin masks.
* @return Set of FaweMaskManager
@ -155,13 +164,7 @@ public class FaweAPI {
}
String worldName = path[path.length - 3];
String uuidString = path[path.length - 2];
World world = null;
for (World current : WorldEdit.getInstance().getServer().getWorlds()) {
if (current.getName().equals(worldName)) {
world = current;
break;
}
}
World world = getWorld(worldName);
if (world == null) {
throw new IllegalArgumentException("Corresponding world does not exist: " + worldName);
}

View File

@ -7,9 +7,9 @@ import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.util.Collection;
import java.util.Set;
import java.util.UUID;
public interface IFawe {
@ -31,14 +31,14 @@ public interface IFawe {
public FaweQueue getNewQueue(String world);
public String getWorldName(World world);
public EditSessionWrapper getEditSessionWrapper(final EditSession session);
public Collection<FaweMaskManager> getMaskManagers();
public void startMetrics();
public Set<FawePlayer> getPlayers();
public String getPlatform();
public UUID getUUID(String name);

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FaweLocation;
@ -158,7 +159,7 @@ public class Rollback extends FaweCommand {
}
}
FaweLocation origin = player.getLocation();
List<DiskStorageHistory> edits = MainUtil.getBDFiles(origin, user, radius, time, shallow);
List<DiskStorageHistory> edits = FaweAPI.getBDFiles(origin, user, radius, time, shallow);
if (edits == null) {
player.sendMessage("&cToo broad, try refining your search!");
return;

View File

@ -30,7 +30,7 @@ public class Stream extends FaweCommand {
BBC.SCHEMATIC_NOT_FOUND.send(player, args[0]);
return false;
}
FaweAPI.streamSchematicAsync(file, player.getLocation());
FaweAPI.streamSchematic(file, player.getLocation());
BBC.SCHEMATIC_PASTING.send(player);
return true;
}

View File

@ -0,0 +1,148 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.yaml.snakeyaml;
import java.util.HashMap;
import java.util.Map;
import org.yaml.snakeyaml.nodes.Tag;
/**
* Provides additional runtime information necessary to create a custom Java
* instance.
*/
public final class TypeDescription {
private final Class<? extends Object> type;
private Tag tag;
private Map<String, Class<? extends Object>> listProperties;
private Map<String, Class<? extends Object>> keyProperties;
private Map<String, Class<? extends Object>> valueProperties;
public TypeDescription(Class<? extends Object> clazz, Tag tag) {
this.type = clazz;
this.tag = tag;
listProperties = new HashMap<String, Class<? extends Object>>();
keyProperties = new HashMap<String, Class<? extends Object>>();
valueProperties = new HashMap<String, Class<? extends Object>>();
}
public TypeDescription(Class<? extends Object> clazz, String tag) {
this(clazz, new Tag(tag));
}
public TypeDescription(Class<? extends Object> clazz) {
this(clazz, (Tag) null);
}
/**
* Get tag which shall be used to load or dump the type (class).
*
* @return tag to be used. It may be a tag for Language-Independent Types
* (http://www.yaml.org/type/)
*/
public Tag getTag() {
return tag;
}
/**
* Set tag to be used to load or dump the type (class).
*
* @param tag
* local or global tag
*/
public void setTag(Tag tag) {
this.tag = tag;
}
public void setTag(String tag) {
setTag(new Tag(tag));
}
/**
* Get represented type (class)
*
* @return type (class) to be described.
*/
public Class<? extends Object> getType() {
return type;
}
/**
* Specify that the property is a type-safe <code>List</code>.
*
* @param property
* name of the JavaBean property
* @param type
* class of List values
*/
public void putListPropertyType(String property, Class<? extends Object> type) {
listProperties.put(property, type);
}
/**
* Get class of List values for provided JavaBean property.
*
* @param property
* property name
* @return class of List values
*/
public Class<? extends Object> getListPropertyType(String property) {
return listProperties.get(property);
}
/**
* Specify that the property is a type-safe <code>Map</code>.
*
* @param property
* property name of this JavaBean
* @param key
* class of keys in Map
* @param value
* class of values in Map
*/
public void putMapPropertyType(String property, Class<? extends Object> key,
Class<? extends Object> value) {
keyProperties.put(property, key);
valueProperties.put(property, value);
}
/**
* Get keys type info for this JavaBean
*
* @param property
* property name of this JavaBean
* @return class of keys in the Map
*/
public Class<? extends Object> getMapKeyType(String property) {
return keyProperties.get(property);
}
/**
* Get values type info for this JavaBean
*
* @param property
* property name of this JavaBean
* @return class of values in the Map
*/
public Class<? extends Object> getMapValueType(String property) {
return valueProperties.get(property);
}
@Override
public String toString() {
return "TypeDescription for " + getType() + " (tag='" + getTag() + "')";
}
}

View File

@ -0,0 +1,661 @@
/**
* Copyright (c) 2008, http://www.snakeyaml.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.yaml.snakeyaml;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.composer.Composer;
import org.yaml.snakeyaml.constructor.BaseConstructor;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.emitter.Emitable;
import org.yaml.snakeyaml.emitter.Emitter;
import org.yaml.snakeyaml.error.YAMLException;
import org.yaml.snakeyaml.events.Event;
import org.yaml.snakeyaml.introspector.BeanAccess;
import org.yaml.snakeyaml.nodes.Node;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.parser.Parser;
import org.yaml.snakeyaml.parser.ParserImpl;
import org.yaml.snakeyaml.reader.StreamReader;
import org.yaml.snakeyaml.reader.UnicodeReader;
import org.yaml.snakeyaml.representer.Representer;
import org.yaml.snakeyaml.resolver.Resolver;
import org.yaml.snakeyaml.serializer.Serializer;
/**
* Public YAML interface. Each Thread must have its own instance.
*/
public class Yaml {
protected final Resolver resolver;
private String name;
protected BaseConstructor constructor;
protected Representer representer;
protected DumperOptions dumperOptions;
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*/
public Yaml() {
this(new Constructor(), new Representer(), new DumperOptions(), new Resolver());
}
/**
* Create Yaml instance.
*
* @param dumperOptions
* DumperOptions to configure outgoing objects
*/
public Yaml(DumperOptions dumperOptions) {
this(new Constructor(), new Representer(), dumperOptions);
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param representer
* Representer to emit outgoing objects
*/
public Yaml(Representer representer) {
this(new Constructor(), representer);
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
*/
public Yaml(BaseConstructor constructor) {
this(constructor, new Representer());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
*/
public Yaml(BaseConstructor constructor, Representer representer) {
this(constructor, representer, new DumperOptions());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
*/
public Yaml(Representer representer, DumperOptions dumperOptions) {
this(new Constructor(), representer, dumperOptions, new Resolver());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
*/
public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions) {
this(constructor, representer, dumperOptions, new Resolver());
}
/**
* Create Yaml instance. It is safe to create a few instances and use them
* in different Threads.
*
* @param constructor
* BaseConstructor to construct incoming documents
* @param representer
* Representer to emit outgoing objects
* @param dumperOptions
* DumperOptions to configure outgoing objects
* @param resolver
* Resolver to detect implicit type
*/
public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions,
Resolver resolver) {
if (!constructor.isExplicitPropertyUtils()) {
constructor.setPropertyUtils(representer.getPropertyUtils());
} else if (!representer.isExplicitPropertyUtils()) {
representer.setPropertyUtils(constructor.getPropertyUtils());
}
this.constructor = constructor;
representer.setDefaultFlowStyle(dumperOptions.getDefaultFlowStyle());
representer.setDefaultScalarStyle(dumperOptions.getDefaultScalarStyle());
representer.getPropertyUtils().setAllowReadOnlyProperties(
dumperOptions.isAllowReadOnlyProperties());
representer.setTimeZone(dumperOptions.getTimeZone());
this.representer = representer;
this.dumperOptions = dumperOptions;
this.resolver = resolver;
this.name = "Yaml:" + System.identityHashCode(this);
}
/**
* Serialize a Java object into a YAML String.
*
* @param data
* Java object to be Serialized to YAML
* @return YAML String
*/
public String dump(Object data) {
List<Object> list = new ArrayList<Object>(1);
list.add(data);
return dumpAll(list.iterator());
}
/**
* Produce the corresponding representation tree for a given Object.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
* Overview</a>
* @param data
* instance to build the representation tree for
* @return representation tree
*/
public Node represent(Object data) {
return representer.represent(data);
}
/**
* Serialize a sequence of Java objects into a YAML String.
*
* @param data
* Iterator with Objects
* @return YAML String with all the objects in proper sequence
*/
public String dumpAll(Iterator<? extends Object> data) {
StringWriter buffer = new StringWriter();
dumpAll(data, buffer, null);
return buffer.toString();
}
/**
* Serialize a Java object into a YAML stream.
*
* @param data
* Java object to be serialized to YAML
* @param output
* stream to write to
*/
public void dump(Object data, Writer output) {
List<Object> list = new ArrayList<Object>(1);
list.add(data);
dumpAll(list.iterator(), output, null);
}
/**
* Serialize a sequence of Java objects into a YAML stream.
*
* @param data
* Iterator with Objects
* @param output
* stream to write to
*/
public void dumpAll(Iterator<? extends Object> data, Writer output) {
dumpAll(data, output, null);
}
private void dumpAll(Iterator<? extends Object> data, Writer output, Tag rootTag) {
Serializer serializer = new Serializer(new Emitter(output, dumperOptions), resolver,
dumperOptions, rootTag);
try {
serializer.open();
while (data.hasNext()) {
Node node = representer.represent(data.next());
serializer.serialize(node);
}
serializer.close();
} catch (IOException e) {
throw new YAMLException(e);
}
}
/**
* <p>
* Serialize a Java object into a YAML string. Override the default root tag
* with <code>rootTag</code>.
* </p>
*
* <p>
* This method is similar to <code>Yaml.dump(data)</code> except that the
* root tag for the whole document is replaced with the given tag. This has
* two main uses.
* </p>
*
* <p>
* First, if the root tag is replaced with a standard YAML tag, such as
* <code>Tag.MAP</code>, then the object will be dumped as a map. The root
* tag will appear as <code>!!map</code>, or blank (implicit !!map).
* </p>
*
* <p>
* Second, if the root tag is replaced by a different custom tag, then the
* document appears to be a different type when loaded. For example, if an
* instance of MyClass is dumped with the tag !!YourClass, then it will be
* handled as an instance of YourClass when loaded.
* </p>
*
* @param data
* Java object to be serialized to YAML
* @param rootTag
* the tag for the whole YAML document. The tag should be Tag.MAP
* for a JavaBean to make the tag disappear (to use implicit tag
* !!map). If <code>null</code> is provided then the standard tag
* with the full class name is used.
* @param flowStyle
* flow style for the whole document. See Chapter 10. Collection
* Styles http://yaml.org/spec/1.1/#id930798. If
* <code>null</code> is provided then the flow style from
* DumperOptions is used.
*
* @return YAML String
*/
public String dumpAs(Object data, Tag rootTag, FlowStyle flowStyle) {
FlowStyle oldStyle = representer.getDefaultFlowStyle();
if (flowStyle != null) {
representer.setDefaultFlowStyle(flowStyle);
}
List<Object> list = new ArrayList<Object>(1);
list.add(data);
StringWriter buffer = new StringWriter();
dumpAll(list.iterator(), buffer, rootTag);
representer.setDefaultFlowStyle(oldStyle);
return buffer.toString();
}
/**
* <p>
* Serialize a Java object into a YAML string. Override the default root tag
* with <code>Tag.MAP</code>.
* </p>
* <p>
* This method is similar to <code>Yaml.dump(data)</code> except that the
* root tag for the whole document is replaced with <code>Tag.MAP</code> tag
* (implicit !!map).
* </p>
* <p>
* Block Mapping is used as the collection style. See 10.2.2. Block Mappings
* (http://yaml.org/spec/1.1/#id934537)
* </p>
*
* @param data
* Java object to be serialized to YAML
* @return YAML String
*/
public String dumpAsMap(Object data) {
return dumpAs(data, Tag.MAP, FlowStyle.BLOCK);
}
/**
* Serialize the representation tree into Events.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
* @param data
* representation tree
* @return Event list
*/
public List<Event> serialize(Node data) {
SilentEmitter emitter = new SilentEmitter();
Serializer serializer = new Serializer(emitter, resolver, dumperOptions, null);
try {
serializer.open();
serializer.serialize(data);
serializer.close();
} catch (IOException e) {
throw new YAMLException(e);
}
return emitter.getEvents();
}
private static class SilentEmitter implements Emitable {
private List<Event> events = new ArrayList<Event>(100);
public List<Event> getEvents() {
return events;
}
public void emit(Event event) throws IOException {
events.add(event);
}
}
/**
* Parse the only YAML document in a String and produce the corresponding
* Java object. (Because the encoding in known BOM is not respected.)
*
* @param yaml
* YAML data to load from (BOM must not be present)
* @return parsed object
*/
public Object load(String yaml) {
return loadFromReader(new StreamReader(yaml), Object.class);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param io
* data to load from (BOM is respected and removed)
* @return parsed object
*/
public Object load(InputStream io) {
return loadFromReader(new StreamReader(new UnicodeReader(io)), Object.class);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param io
* data to load from (BOM must not be present)
* @return parsed object
*/
public Object load(Reader io) {
return loadFromReader(new StreamReader(io), Object.class);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param <T>
* Class is defined by the second argument
* @param io
* data to load from (BOM must not be present)
* @param type
* Class of the object to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T loadAs(Reader io, Class<T> type) {
return (T) loadFromReader(new StreamReader(io), type);
}
/**
* Parse the only YAML document in a String and produce the corresponding
* Java object. (Because the encoding in known BOM is not respected.)
*
* @param <T>
* Class is defined by the second argument
* @param yaml
* YAML data to load from (BOM must not be present)
* @param type
* Class of the object to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T loadAs(String yaml, Class<T> type) {
return (T) loadFromReader(new StreamReader(yaml), type);
}
/**
* Parse the only YAML document in a stream and produce the corresponding
* Java object.
*
* @param <T>
* Class is defined by the second argument
* @param input
* data to load from (BOM is respected and removed)
* @param type
* Class of the object to be created
* @return parsed object
*/
@SuppressWarnings("unchecked")
public <T> T loadAs(InputStream input, Class<T> type) {
return (T) loadFromReader(new StreamReader(new UnicodeReader(input)), type);
}
private Object loadFromReader(StreamReader sreader, Class<?> type) {
Composer composer = new Composer(new ParserImpl(sreader), resolver);
constructor.setComposer(composer);
return constructor.getSingleData(type);
}
/**
* Parse all YAML documents in a String and produce corresponding Java
* objects. The documents are parsed only when the iterator is invoked.
*
* @param yaml
* YAML data to load from (BOM must not be present)
* @return an iterator over the parsed Java objects in this String in proper
* sequence
*/
public Iterable<Object> loadAll(Reader yaml) {
Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
constructor.setComposer(composer);
Iterator<Object> result = new Iterator<Object>() {
public boolean hasNext() {
return constructor.checkData();
}
public Object next() {
return constructor.getData();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
return new YamlIterable(result);
}
private static class YamlIterable implements Iterable<Object> {
private Iterator<Object> iterator;
public YamlIterable(Iterator<Object> iterator) {
this.iterator = iterator;
}
public Iterator<Object> iterator() {
return iterator;
}
}
/**
* Parse all YAML documents in a String and produce corresponding Java
* objects. (Because the encoding in known BOM is not respected.) The
* documents are parsed only when the iterator is invoked.
*
* @param yaml
* YAML data to load from (BOM must not be present)
* @return an iterator over the parsed Java objects in this String in proper
* sequence
*/
public Iterable<Object> loadAll(String yaml) {
return loadAll(new StringReader(yaml));
}
/**
* Parse all YAML documents in a stream and produce corresponding Java
* objects. The documents are parsed only when the iterator is invoked.
*
* @param yaml
* YAML data to load from (BOM is respected and ignored)
* @return an iterator over the parsed Java objects in this stream in proper
* sequence
*/
public Iterable<Object> loadAll(InputStream yaml) {
return loadAll(new UnicodeReader(yaml));
}
/**
* Parse the first YAML document in a stream and produce the corresponding
* representation tree. (This is the opposite of the represent() method)
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
* Overview</a>
* @param yaml
* YAML document
* @return parsed root Node for the specified YAML document
*/
public Node compose(Reader yaml) {
Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
constructor.setComposer(composer);
return composer.getSingleNode();
}
/**
* Parse all YAML documents in a stream and produce corresponding
* representation trees.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
* @param yaml
* stream of YAML documents
* @return parsed root Nodes for all the specified YAML documents
*/
public Iterable<Node> composeAll(Reader yaml) {
final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
constructor.setComposer(composer);
Iterator<Node> result = new Iterator<Node>() {
public boolean hasNext() {
return composer.checkNode();
}
public Node next() {
return composer.getNode();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
return new NodeIterable(result);
}
private static class NodeIterable implements Iterable<Node> {
private Iterator<Node> iterator;
public NodeIterable(Iterator<Node> iterator) {
this.iterator = iterator;
}
public Iterator<Node> iterator() {
return iterator;
}
}
/**
* Add an implicit scalar detector. If an implicit scalar value matches the
* given regexp, the corresponding tag is assigned to the scalar.
*
* @param tag
* tag to assign to the node
* @param regexp
* regular expression to match against
* @param first
* a sequence of possible initial characters or null (which means
* any).
*/
public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
resolver.addImplicitResolver(tag, regexp, first);
}
@Override
public String toString() {
return name;
}
/**
* Get a meaningful name. It simplifies debugging in a multi-threaded
* environment. If nothing is set explicitly the address of the instance is
* returned.
*
* @return human readable name
*/
public String getName() {
return name;
}
/**
* Set a meaningful name to be shown in toString()
*
* @param name
* human readable name
*/
public void setName(String name) {
this.name = name;
}
/**
* Parse a YAML stream and produce parsing events.
*
* @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
* @param yaml
* YAML document(s)
* @return parsed events
*/
public Iterable<Event> parse(Reader yaml) {
final Parser parser = new ParserImpl(new StreamReader(yaml));
Iterator<Event> result = new Iterator<Event>() {
public boolean hasNext() {
return parser.peekEvent() != null;
}
public Event next() {
return parser.getEvent();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
return new EventIterable(result);
}
private static class EventIterable implements Iterable<Event> {
private Iterator<Event> iterator;
public EventIterable(Iterator<Event> iterator) {
this.iterator = iterator;
}
public Iterator<Event> iterator() {
return iterator;
}
}
public void setBeanAccess(BeanAccess beanAccess) {
constructor.getPropertyUtils().setBeanAccess(beanAccess);
representer.getPropertyUtils().setBeanAccess(beanAccess);
}
}

View File

@ -1,6 +1,6 @@
package com.boydti.fawe.object;
import com.sk89q.worldedit.WorldEdit;
import com.boydti.fawe.FaweAPI;
import com.sk89q.worldedit.world.World;
/**
@ -36,12 +36,7 @@ public class FaweLocation {
}
public World getWorld() {
for (World world : WorldEdit.getInstance().getServer().getWorlds()) {
if (world.getName().equals(this.world)) {
return world;
}
}
return null;
return FaweAPI.getWorld(world);
}
@Override

View File

@ -1,10 +1,13 @@
package com.boydti.fawe.object;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager;
import com.boydti.fawe.wrappers.PlayerWrapper;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
@ -50,16 +53,27 @@ public abstract class FawePlayer<T> {
}
if (obj instanceof Player) {
Player actor = (Player) obj;
try {
Field fieldBasePlayer = actor.getClass().getDeclaredField("basePlayer");
fieldBasePlayer.setAccessible(true);
Player player = (Player) fieldBasePlayer.get(actor);
Field fieldPlayer = player.getClass().getDeclaredField("player");
fieldPlayer.setAccessible(true);
return Fawe.imp().wrap(fieldPlayer.get(player));
} catch (Throwable e) {
e.printStackTrace();
return Fawe.imp().wrap(actor.getName());
if (obj.getClass().getSimpleName().equals("PlayerProxy")) {
try {
Field fieldBasePlayer = actor.getClass().getDeclaredField("basePlayer");
fieldBasePlayer.setAccessible(true);
Player player = (Player) fieldBasePlayer.get(actor);
return wrap(player);
} catch (Throwable e) {
e.printStackTrace();
return Fawe.imp().wrap(actor.getName());
}
} else if (obj instanceof PlayerWrapper){
return wrap(((PlayerWrapper) obj).getParent());
} else {
try {
Field fieldPlayer = actor.getClass().getDeclaredField("player");
fieldPlayer.setAccessible(true);
return wrap(fieldPlayer.get(actor));
} catch (Throwable e) {
e.printStackTrace();
return Fawe.imp().wrap(actor.getName());
}
}
}
return Fawe.imp().wrap(obj);
@ -92,13 +106,7 @@ public abstract class FawePlayer<T> {
* @return
*/
public World getWorld() {
String currentWorldName = getLocation().world;
for (World world : WorldEdit.getInstance().getServer().getWorlds()) {
if (world.getName().equals(currentWorldName)) {
return world;
}
}
return null;
return FaweAPI.getWorld(getLocation().world);
}
/**
@ -106,30 +114,39 @@ public abstract class FawePlayer<T> {
* - Usually already called when a player joins or changes world
* @param world
*/
public void loadSessionsFromDisk(World world) {
public void loadSessionsFromDisk(final World world) {
if (world == null) {
return;
}
UUID uuid = getUUID();
List<Integer> editIds = new ArrayList<>();
File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + world.getName() + File.separator + uuid);
if (folder.isDirectory()) {
for (File file : folder.listFiles()) {
if (file.getName().endsWith(".bd")) {
int index = Integer.parseInt(file.getName().split("\\.")[0]);
editIds.add(index);
TaskManager.IMP.async(new Runnable() {
@Override
public void run() {
UUID uuid = getUUID();
List<Integer> editIds = new ArrayList<>();
File folder = new File(Fawe.imp().getDirectory(), "history" + File.separator + world.getName() + File.separator + uuid);
if (folder.isDirectory()) {
for (File file : folder.listFiles()) {
if (file.getName().endsWith(".bd")) {
int index = Integer.parseInt(file.getName().split("\\.")[0]);
editIds.add(index);
}
}
}
Collections.sort(editIds);
if (editIds.size() > 0) {
Fawe.debug(BBC.PREFIX.s() + " Indexing " + editIds.size() + " history objects for " + getName());
for (int index : editIds) {
DiskStorageHistory set = new DiskStorageHistory(world, uuid, index);
EditSession edit = set.toEditSession(getPlayer());
if (world.equals(getWorld())) {
session.remember(edit);
} else {
return;
}
}
}
}
}
Collections.sort(editIds);
if (editIds.size() > 0) {
Fawe.debug(BBC.PREFIX.s() + " Indexing " + editIds.size() + " history objects for " + getName());
for (int index : editIds) {
DiskStorageHistory set = new DiskStorageHistory(world, uuid, index);
EditSession edit = set.toEditSession(getPlayer());
session.remember(edit);
}
}
});
}
/**

View File

@ -27,7 +27,7 @@ public class MainUtil {
}
public static void sendAdmin(final String s) {
for (final FawePlayer<?> player : Fawe.imp().getPlayers()) {
for (final FawePlayer<?> player : Fawe.get().getCachedPlayers()) {
if (player.hasPermission("fawe.admin")) {
player.sendMessage(s);
}

View File

@ -34,6 +34,10 @@ public class PlayerWrapper implements Player {
this.parent = parent;
}
public Player getParent() {
return parent;
}
@Override
public World getWorld() {
return new WorldWrapper((AbstractWorld) parent.getWorld());

View File

@ -235,7 +235,7 @@ public class EditSession implements Extent {
return;
}
this.actor = event.getActor();
this.queue = SetQueue.IMP.getNewQueue(world.getName(), true);
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true);
// Set the world of the event to the actual world (workaround for CoreProtect)
try {
Class<? extends EditSessionEvent> eventClass = event.getClass();
@ -266,8 +266,7 @@ public class EditSession implements Extent {
}
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : new MemoryOptimizedHistory(actor);
Extent extent;
final String name = actor.getName();
final FawePlayer<Object> fp = FawePlayer.wrap(name);
final FawePlayer<Object> fp = FawePlayer.wrap(actor);
final LocalSession session = fp.getSession();
this.fastmode = session.hasFastMode();
if (fp.hasWorldEditBypass()) {
@ -372,6 +371,12 @@ public class EditSession implements Extent {
final Extent toReturn = event.getExtent();
if (toReturn != extent) {
String className = toReturn.getClass().getName().toLowerCase();
if (className.contains("coreprotect")) {
Fawe.debug("&cUnsafe extent detected: " + toReturn.getClass().getCanonicalName() + " !");
Fawe.debug("&8 - &7Use BlocksHub instead");
Fawe.debug("&8 - &7Or use FAWE rollback");
return extent;
}
for (String allowed : Settings.ALLOWED_3RDPARTY_EXTENTS) {
if (className.contains(allowed.toLowerCase())) {
return toReturn;

View File

@ -1,13 +0,0 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.object.EditSessionWrapper;
import com.sk89q.worldedit.EditSession;
/**
* Created by Jesse on 4/2/2016.
*/
public class SpongeEditSessionWrapper_0 extends EditSessionWrapper {
public SpongeEditSessionWrapper_0(EditSession session) {
super(session);
}
}

77
forge1710/build.gradle Normal file
View File

@ -0,0 +1,77 @@
buildscript {
repositories {
jcenter()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/"}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
}
}
apply plugin: 'forge'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile project(':core')
compile 'org.mcstats.sponge:metrics:R8-SNAPSHOT'
compile 'com.sk89q.worldedit:worldedit-forge-mc1.7.10:6.1.1-20151030.011615-19'
compile 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
repositories {
maven {
name = 'forge'
url = 'http://files.minecraftforge.net/maven'
}
}
minecraft {
version = "10.13.4.1614-1.7.10"
runDir = 'run'
}
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraft.version}"
processResources {
from(sourceSets.main.resources.srcDirs) {
expand 'version': project.version,
'mcVersion': project.minecraft.version
exclude 'mcmod.info'
}
}
shadowJar {
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
dependencies {
include(dependency(':core'))
include(dependency('org.yaml:snakeyaml:1.16'))
}
archiveName = "${parent.name}-${project.name}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
reobf.reobf(shadowJar) { spec ->
spec.classpath = sourceSets.main.compileClasspath;
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'dev'
}
artifacts {
archives deobfJar
}
build.dependsOn(shadowJar)

View File

@ -0,0 +1,159 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.forge.v0.ForgeQueue_All;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.forge.ForgeWorld;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.management.InstanceAlreadyExistsException;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Logger;
public class FaweForge implements IFawe {
private final ForgeMain parent;
private final File directory;
private final Logger logger;
public FaweForge(ForgeMain plugin, Logger logger, File directory) {
this.parent = plugin;
this.logger = logger;
this.directory = directory;
try {
Fawe.set(this);
} catch (InstanceAlreadyExistsException e) {
e.printStackTrace();
}
}
@Override
public void debug(String s) {
logger.error(s);
}
@Override
public File getDirectory() {
return directory;
}
@Override
public void setupCommand(final String label, final FaweCommand cmd) {
if (TaskManager.IMP != null) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
ServerCommandManager scm = (ServerCommandManager) MinecraftServer.getServer().getCommandManager();
scm.registerCommand(new ForgeCommand(label, cmd));
}
});
}
}
@Override
public FawePlayer wrap(Object obj) {
EntityPlayerMP player = null;
if (obj instanceof String) {
MinecraftServer server = MinecraftServer.getServer();
List<EntityPlayerMP> list = server.getConfigurationManager().getPlayerList((String) obj);
player = list.size() == 1 ? list.get(0) : null;
} else if (obj instanceof EntityPlayerMP) {
player = (EntityPlayerMP) obj;
}
if (player == null) {
return null;
}
FawePlayer existing = Fawe.get().getCachedPlayer(player.getCommandSenderName());
return existing != null ? existing : new ForgePlayer(player);
}
@Override
public void setupWEListener() {
// Do nothing
}
@Override
public void setupVault() {
// Do nothing
}
@Override
public TaskManager getTaskManager() {
return new ForgeTaskMan(512);
}
@Override
public int[] getVersion() {
String[] version = MinecraftServer.getServer().getMinecraftVersion().split("\\.");
return new int[] {Integer.parseInt(version[0]), Integer.parseInt(version[1]), Integer.parseInt(version[2])};
}
@Override
public String getWorldName(World world) {
if (world instanceof WorldWrapper) {
world = ((WorldWrapper) world).getParent();
}
return ((ForgeWorld) world).getWorld().provider.getDimensionName();
}
@Override
public FaweQueue getNewQueue(String world) {
return new ForgeQueue_All(world);
}
@Override
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
return new EditSessionWrapper(session);
}
@Override
public Collection<FaweMaskManager> getMaskManagers() {
return new ArrayList<>();
}
@Override
public void startMetrics() {
try {
ForgeMetrics metrics = new ForgeMetrics("FastAsyncWorldEdit", "3.4.0");
metrics.start();
debug("[FAWE] &6Metrics enabled.");
} catch (Throwable e) {
debug("[FAWE] &cFailed to load up metrics.");
}
}
@Override
public String getPlatform() {
return "forge";
}
@Override
public UUID getUUID(String name) {
try {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
} catch (Throwable e) {
return null;
}
}
@Override
public String getName(UUID uuid) {
return uuid.toString();
}
}

View File

@ -0,0 +1,41 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
public class ForgeCommand extends CommandBase {
private final String name;
private final FaweCommand cmd;
public ForgeCommand(String name, FaweCommand cmd) {
this.name = name;
this.cmd = cmd;
}
@Override
public String getCommandName() {
return name;
}
@Override
public String getCommandUsage(ICommandSender iCommandSender) {
return "/" + name;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if ((sender instanceof EntityPlayerMP)) {
EntityPlayerMP player = (EntityPlayerMP) sender;
if (player.worldObj.isRemote) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
cmd.executeSafe(fp, args);
}
}
}

View File

@ -0,0 +1,76 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.event.FMLServerStoppingEvent;
import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.PlayerEvent;
import java.io.File;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.4.0", acceptableRemoteVersions = "*")
public class ForgeMain {
private static FaweForge IMP;
private Logger logger;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
this.logger = event.getModLog();
File directory = new File(event.getModConfigurationDirectory() + File.separator + "FastAsyncWorldEdit");
MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);
this.IMP = new FaweForge(this, event.getModLog(), directory);
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerEvent.PlayerLoggedOutEvent event) {
if (event.player.worldObj.isRemote) {
return;
}
handleQuit((EntityPlayerMP) event.player);
}
@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
for (EntityPlayerMP player : (List<EntityPlayerMP>)MinecraftServer.getServer().getConfigurationManager().playerEntityList) {
handleQuit(player);
}
}
public void handleQuit(EntityPlayerMP player) {
FawePlayer fp = FawePlayer.wrap(player);
fp.unregister();
Fawe.get().unregister(player.getCommandSenderName());
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerChangedWorld(EntityJoinWorldEvent event) {
Entity entity = event.entity;
if (!(entity instanceof EntityPlayerMP)) {
return;
}
EntityPlayerMP player = (EntityPlayerMP) entity;
if (player.worldObj.isRemote) {
return;
}
FawePlayer fp = FawePlayer.wrap(player);
if (fp.getMeta("lastWorld") != event.world) {
fp.setMeta("lastWorld", event.world);
if (Settings.STORE_HISTORY_ON_DISK) {
fp.getSession().clearHistory();
fp.loadSessionsFromDisk(fp.getWorld());
}
}
}
}

View File

@ -0,0 +1,479 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
* Ported to Minecraft Forge by Mike Primm
* 1.7.x update by Dries007
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.boydti.fawe.forge;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.FMLLog;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.config.Configuration;
public class ForgeMetrics {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 15;
/**
* The mod this metrics submits for
*/
private final String modName;
private final String modVersion;
/**
* The metrics configuration file
*/
private final Configuration configuration;
/**
* The metrics configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
private Thread thread = null;
private boolean firstPost = true;
int tickCount;
public ForgeMetrics(final String modName, final String modVersion) throws IOException {
if (modName == null || modVersion == null) {
throw new IllegalArgumentException("modName and modVersion cannot be null");
}
this.modName = modName;
this.modVersion = modVersion;
// load the config
configurationFile = getConfigFile();
configuration = new Configuration(configurationFile);
// Get values, and add some defaults, if needed
configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false, "Set to true to disable all reporting");
guid = configuration.get(Configuration.CATEGORY_GENERAL, "guid", UUID.randomUUID().toString(), "Server unique ID").getString();
debug = configuration.get(Configuration.CATEGORY_GENERAL, "debug", false, "Set to true for verbose debug").getBoolean(false);
configuration.save();
}
/**
* Start measuring statistics. This will immediately create an async
* repeating task as the plugin and send the initial data to the metrics
* backend, and then after that it will post in increments of PING_INTERVAL
* * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
// Did we opt out?
if (isOptOut()) {
return false;
}
FMLCommonHandler.instance().bus().register(this);
return true;
}
@SubscribeEvent
public void tick(TickEvent.ServerTickEvent tick) {
if (tick.phase != TickEvent.Phase.END) return;
if (tickCount++ % (PING_INTERVAL * 1200) != 0) return;
if (thread == null) {
thread = new Thread(new Runnable() {
public void run() {
try {
// Disable Task, if it is running and the server owner decided
// to opt-out
if (isOptOut()) {
FMLCommonHandler.instance().bus().unregister(ForgeMetrics.this);
return;
}
// We use the inverse of firstPost because if it
// is the first time we are posting,
// it is not a interval ping, so it evaluates to
// FALSE
// Each time thereafter it will evaluate to
// TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to
// false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
FMLLog.info("[Metrics] Exception - %s", e.getMessage());
}
} finally {
thread = null;
}
}
});
thread.start();
}
}
/**
* Stop processing
*/
public void stop() {
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
// Reload the metrics file
configuration.load();
return configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false).getBoolean(false);
}
/**
* Enables metrics for the server by setting "opt-out" to false in the
* config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("false");
configuration.save();
}
// Enable Task, if it is not running
FMLCommonHandler.instance().bus().register(this);
}
/**
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("true");
configuration.save();
}
FMLCommonHandler.instance().bus().unregister(this);
}
/**
* Gets the File object of the config file that should be used to store data
* such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
return new File(Loader.instance().getConfigDir(), "PluginMetrics.cfg");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
String pluginName = modName;
boolean onlineMode = MinecraftServer.getServer().isServerInOnlineMode();
String pluginVersion = modVersion;
String serverVersion;
if (MinecraftServer.getServer().isDedicatedServer()) {
serverVersion = "MinecraftForge (MC: " + MinecraftServer.getServer().getMinecraftVersion() + ")";
} else {
serverVersion = "MinecraftForgeSSP (MC: " + MinecraftServer.getServer().getMinecraftVersion() + ")";
}
int playersOnline = MinecraftServer.getServer().getCurrentPlayerCount();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws java.io.UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -0,0 +1,66 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import java.util.UUID;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.World;
public class ForgePlayer extends FawePlayer<EntityPlayerMP> {
public ForgePlayer(EntityPlayerMP parent) {
super(parent);
}
@Override
public String getName() {
return parent.getCommandSenderName();
}
@Override
public UUID getUUID() {
return parent.getUniqueID();
}
@Override
public boolean hasPermission(String perm) {
Object meta = getMeta(perm);
return meta instanceof Boolean ? (boolean) meta : ForgeWorldEdit.inst.getPermissionsProvider().hasPermission(parent, perm);
}
@Override
public void setPermission(String perm, boolean flag) {
setMeta(perm, flag);
}
@Override
public void sendMessage(String msg) {
for (String part : msg.split("\n")) {
part = EnumChatFormatting.getTextWithoutFormattingCodes(msg);
ChatComponentText component = new ChatComponentText(part);
component.getChatStyle().setColor(EnumChatFormatting.LIGHT_PURPLE);
this.parent.addChatMessage(component);
}
}
@Override
public void executeCommand(String substring) {
throw new UnsupportedOperationException("NOT IMPLEMENTED");
}
@Override
public FaweLocation getLocation() {
World world = parent.worldObj;
ChunkCoordinates pos = parent.getPlayerCoordinates();
return new FaweLocation(world.provider.getDimensionName(), pos.posX, pos.posY, pos.posZ);
}
@Override
public Player getPlayer() {
return ForgeWorldEdit.inst.wrap(this.parent);
}
}

View File

@ -0,0 +1,165 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.util.TaskManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent;
public class ForgeTaskMan extends TaskManager {
private final ConcurrentLinkedDeque<Runnable> syncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentLinkedDeque<Runnable> asyncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentHashMap<Integer, Runnable> taskIdMap = new ConcurrentHashMap<>();
private final AtomicInteger taskId = new AtomicInteger();
private final ExecutorService executor;
public ForgeTaskMan(int size) {
this.executor = Executors.newFixedThreadPool(size);
FMLCommonHandler.instance().bus().register(this);
}
@Override
public int repeat(final Runnable r, final int interval) {
if (r == null) {
return -1;
}
final int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
task(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
e.printStackTrace();
}
later(this, interval);
}
});
return id;
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onServerTick(TickEvent.ServerTickEvent event) {
int asyncSize = asyncTasks.size();
for (int i = 0; i < asyncSize; i++) {
Runnable item = asyncTasks.poll();
if (item != null) {
async(item);
}
}
int syncSize = syncTasks.size();
for (int i = 0; i < syncSize; i++) {
Runnable item = syncTasks.poll();
if (item != null) {
try {
item.run();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}
@Override
public int repeatAsync(final Runnable r, final int interval) {
if (r == null) {
return -1;
}
final int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
async(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
e.printStackTrace();
}
laterAsync(this, interval);
}
});
return id;
}
@Override
public void async(Runnable r) {
if (r == null) {
return;
}
executor.execute(r);
}
@Override
public void task(Runnable r) {
if (r == null) {
return;
}
syncTasks.add(r);
}
@Override
public void later(final Runnable r, final int delay) {
if (r == null) {
return;
}
final AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
r.run();
} catch (Throwable e) {
e.printStackTrace();
}
return;
}
task(this);
}
});
}
@Override
public void laterAsync(final Runnable r, final int delay) {
if (r == null) {
return;
}
final AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
async(r);
} catch (Throwable e) {
e.printStackTrace();
}
return;
}
task(this);
}
});
}
@Override
public void cancel(int task) {
taskIdMap.remove(task);
}
}

View File

@ -0,0 +1,254 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.NibbleArray;
public class ForgeChunk_All extends FaweChunk<Chunk> {
public byte[][] ids;
public NibbleArray[] datas;
public short[] count;
public short[] air;
public short[] relight;
public byte[][] biomes;
public Chunk chunk;
public ForgeChunk_All(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new byte[16][];
this.datas = new NibbleArray[16];
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public Chunk getChunk() {
if (this.chunk == null) {
World world = ((ForgeQueue_All) getParent()).getWorld();
this.chunk = world.getChunkProvider().provideChunk(getX(), getZ());
}
return this.chunk;
}
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
this.chunk = null;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
/**
* Get the raw data for a section.
* @param i
* @return
*/
public byte[] getIdArray(int i) {
return this.ids[i];
}
public NibbleArray getDataArray(int i) {
return datas[i];
}
@Override
public void setBlock(int x, int y, int z, int id, byte data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
byte[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new byte[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = -1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.relight[i]++;
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 55:
case 56:
case 57:
case 58:
case 60:
case 7:
case 8:
case 9:
case 73:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 121:
case 129:
case 133:
case 165:
case 166:
case 170:
case 172:
case 173:
case 174:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
vs[j] = (byte) (id);
return;
case 130:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
case 50:
if (data < 2) {
data = 2;
}
default:
vs[j] = (byte) id;
NibbleArray dataArray = datas[i];
if (dataArray == null) {
datas[i] = dataArray = new NibbleArray(4096, 4);
}
dataArray.set(x, y & 15, z, data);
return;
}
}
@Override
public void setBiome(int x, int z, BaseBiome biome) {
if (this.biomes == null) {
this.biomes = new byte[16][];
}
byte[] index = this.biomes[x];
if (index == null) {
index = this.biomes[x] = new byte[16];
}
index[z] = (byte) biome.getId();
}
@Override
public FaweChunk clone() {
ForgeChunk_All toReturn = new ForgeChunk_All(getParent(), getX(), getZ());
toReturn.air = this.air.clone();
toReturn.count = this.count.clone();
toReturn.relight = this.relight.clone();
toReturn.ids = new byte[this.ids.length][];
for (int i = 0; i < this.ids.length; i++) {
byte[] matrix = this.ids[i];
if (matrix != null) {
toReturn.ids[i] = new byte[matrix.length];
System.arraycopy(matrix, 0, toReturn.ids[i], 0, matrix.length);
}
}
toReturn.datas = new NibbleArray[16];
for (int i = 0; i < this.datas.length; i++) {
if (datas[i] != null) {
toReturn.datas[i] = datas[i];
}
}
return toReturn;
}
}

View File

@ -0,0 +1,597 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.forge.ForgePlayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.play.server.S21PacketChunkData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.util.LongHashMap;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
public class ForgeQueue_All extends FaweQueue {
private World forgeWorld;
private ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk<Chunk>> chunks = new LinkedBlockingDeque<>();
public ForgeQueue_All(final String world) {
super(world);
}
@Override
public boolean isChunkLoaded(int x, int z) {
return getWorld().getChunkProvider().chunkExists(x, z);
}
public World getWorld() {
if (forgeWorld != null) {
return forgeWorld;
}
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(world)) {
return forgeWorld = ws;
}
}
return null;
}
@Override
public boolean regenerateChunk(int x, int z) {
try {
IChunkProvider provider = getWorld().getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
Field u;
try {
u = ChunkProviderServer.class.getDeclaredField("field_73248_b"); // chunksToUnload
} catch(NoSuchFieldException e) {
u = ChunkProviderServer.class.getDeclaredField("chunksToUnload");
}
u.setAccessible(true);
Set<?> unloadQueue = (Set<?>) u.get(chunkServer);
Field m;
try {
m = ChunkProviderServer.class.getDeclaredField("field_73244_f"); // loadedChunkHashMap
} catch(NoSuchFieldException e) {
m = ChunkProviderServer.class.getDeclaredField("loadedChunkHashMap");
}
m.setAccessible(true);
LongHashMap loadedMap = (LongHashMap) m.get(chunkServer);
Field lc;
try {
lc = ChunkProviderServer.class.getDeclaredField("field_73245_g"); // loadedChunkHashMap
} catch(NoSuchFieldException e) {
lc = ChunkProviderServer.class.getDeclaredField("loadedChunks");
}
lc.setAccessible(true);
@SuppressWarnings("unchecked") List<Chunk> loaded = (List<Chunk>) lc.get(chunkServer);
Field p;
try {
p = ChunkProviderServer.class.getDeclaredField("field_73246_d"); // currentChunkProvider
} catch(NoSuchFieldException e) {
p = ChunkProviderServer.class.getDeclaredField("currentChunkProvider");
}
p.setAccessible(true);
IChunkProvider chunkProvider = (IChunkProvider) p.get(chunkServer);
long pos = ChunkCoordIntPair.chunkXZ2Int(x, z);
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
unloadQueue.remove(pos);
loadedMap.remove(pos);
mcChunk = chunkProvider.provideChunk(x, z);
loadedMap.add(pos, mcChunk);
loaded.add(mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkProvider, chunkProvider, x, z);
}
} catch (Throwable t) {
t.printStackTrace();
return false;
}
return true;
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
}
private int lcx = Integer.MIN_VALUE;
private int lcz = Integer.MIN_VALUE;
private int lcy = Integer.MIN_VALUE;
private net.minecraft.world.chunk.Chunk lc;
private ExtendedBlockStorage ls;
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair loc) {
Chunk chunk = getWorld().getChunkProvider().provideChunk(loc.x, loc.z);
if (chunk != null && !chunk.isChunkLoaded) {
chunk.onChunkLoad();
}
}
};
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lcx || cz != lcz) {
World world = getWorld();
lcx = cx;
lcz = cz;
IChunkProvider provider = world.getChunkProvider();
Chunk chunk;
if (!provider.chunkExists(cx, cz)) {
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
chunk = provider.provideChunk(cx, cz);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
if (!provider.chunkExists(cx, cz)) {
throw new FaweException.FaweChunkLoadException();
}
chunk = provider.provideChunk(cx, cz);
} else {
return 0;
}
} else {
chunk = provider.provideChunk(cx, cz);
}
lc = chunk;
ls = lc.getBlockStorageArray()[cy];
} else if (cy != lcy) {
if (lc == null) {
return 0;
}
ls = lc.getBlockStorageArray()[cy];
}
if (ls == null) {
ls = null;
return 0;
}
byte[] ids = ls.getBlockLSBArray();
NibbleArray datasNibble = ls.getBlockMSBArray();
int i = FaweCache.CACHE_J[y & 15][x & 15][z & 15];
int combined = (ids[i] << 4) + (datasNibble == null ? 0 : datasNibble.get(x & 15, y & 15, z & 15));
return combined;
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastChunk = this.blocks.get(pair);
if (lastChunk == null) {
lastChunk = this.getChunk(x >> 4, z >> 4);
lastChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk<Chunk> previous = this.blocks.put(pair, lastChunk);
if (previous == null) {
chunks.add(lastChunk);
return true;
}
this.blocks.put(pair, previous);
lastChunk = previous;
}
}
lastChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
} else {
chunks.add(result);
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk<Chunk> chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk<Chunk>> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk<Chunk> fc) {
if (fc == null) {
return false;
}
// Load chunk
Chunk chunk = fc.getChunk();
if (!chunk.isChunkLoaded) {
chunk.onChunkLoad();
}
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
}
@Override
public void setChunk(FaweChunk<?> chunk) {
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk<Chunk>) chunk);
}
public void sendChunk(final FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
if (!chunk.isChunkLoaded) {
return;
}
World world = chunk.worldObj;
ChunkCoordIntPair pos = chunk.getChunkCoordIntPair();
int cx = pos.chunkXPos;
int cz = pos.chunkZPos;
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
ForgePlayer forgePlayer = (ForgePlayer) fp;
EntityPlayerMP player = forgePlayer.parent;
if (!player.worldObj.equals(world)) {
continue;
}
int view = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
ChunkCoordinates loc = player.getPlayerCoordinates();
int px = loc.posX >> 4;
int pz = loc.posZ >> 4;
int dx = Math.abs(cx - (loc.posX >> 4));
int dz = Math.abs(cz - (loc.posZ >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
con.sendPacket(new S21PacketChunkData(chunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
public boolean setComponents(FaweChunk<Chunk> fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc;
Chunk forgeChunk = fc.getChunk();
net.minecraft.world.World nmsWorld = forgeChunk.worldObj;
try {
boolean flag = !nmsWorld.provider.hasNoSky;
// Sections
ExtendedBlockStorage[] sections = forgeChunk.getBlockStorageArray();
Map<ChunkPosition, TileEntity> tiles = forgeChunk.chunkTileEntityMap;
List[] entities = forgeChunk.entityLists;
// Trim tiles
Set<Map.Entry<ChunkPosition, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<ChunkPosition, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Map.Entry<ChunkPosition, TileEntity> tile = iterator.next();
ChunkPosition pos = tile.getKey();
int lx = pos.chunkPosX & 15;
int ly = pos.chunkPosY;
int lz = pos.chunkPosZ & 15;
int j = FaweCache.CACHE_I[ly][lx][lz];
int k = FaweCache.CACHE_J[ly][lx][lz];
byte[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
iterator.remove();
}
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
continue;
}
byte[] newIdArray = fs.getIdArray(j);
if (newIdArray == null) {
continue;
}
NibbleArray newDataArray = fs.getDataArray(j);
ExtendedBlockStorage section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
sections[j] = section = new ExtendedBlockStorage(j << 4, !getWorld().provider.hasNoSky);
section.setBlockLSBArray(newIdArray);
section.setBlockMetadataArray(newDataArray);
continue;
}
// id + data << 8
byte[] currentIdArray = section.getBlockLSBArray();
NibbleArray currentDataArray = section.getMetadataArray();
boolean data = currentDataArray != null;
if (!data) {
section.setBlockMetadataArray(newDataArray);
}
boolean fill = true;
for (int k = 0; k < newIdArray.length; k++) {
byte n = newIdArray[k];
switch (n) {
case 0:
fill = false;
continue;
case -1:
fill = false;
currentIdArray[k] = 0;
continue;
default:
currentIdArray[k] = n;
if (data) {
int x = FaweCache.CACHE_X[j][k];
int y = FaweCache.CACHE_Y[j][k];
int z = FaweCache.CACHE_Z[j][k];
int newData = newDataArray == null ? 0 : newDataArray.get(x, y, z);
int currentData = currentDataArray == null ? 0 : currentDataArray.get(x, y, z);
if (newData != currentData) {
currentDataArray.set(x, y, z, newData);
}
}
continue;
}
}
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// // Clear
} catch (Throwable e) {
e.printStackTrace();
}
byte[][] biomes = fs.biomes;
if (biomes != null) {
for (int x = 0; x < 16; x++) {
byte[] array = biomes[x];
if (array == null) {
continue;
}
for (int z = 0; z < 16; z++) {
byte biome = array[z];
if (biome == 0) {
continue;
}
forgeChunk.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = biome;
}
}
}
sendChunk(fs);
return true;
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
return new ForgeChunk_All(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk<?> chunk, boolean fixAll) {
try {
ForgeChunk_All fc = (ForgeChunk_All) chunk;
Chunk forgeChunk = fc.getChunk();
if (!forgeChunk.isChunkLoaded) {
forgeChunk.onChunkLoad();
}
forgeChunk.generateSkylightMap();
if (fc.getTotalRelight() == 0 && !fixAll) {
return true;
}
ExtendedBlockStorage[] sections = forgeChunk.getBlockStorageArray();
net.minecraft.world.World nmsWorld = forgeChunk.worldObj;
int X = fc.getX() << 4;
int Z = fc.getZ() << 4;
for (int j = 0; j < sections.length; j++) {
ExtendedBlockStorage section = sections[j];
if (section == null) {
continue;
}
if ((fc.getRelight(j) == 0 && !fixAll) || fc.getCount(j) == 0 || (fc.getCount(j) >= 4096 && fc.getAir(j) == 0)) {
continue;
}
byte[] array = section.getBlockLSBArray();
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
short id = (short) (i);
switch (id) { // Lighting
default:
if (!fixAll) {
continue;
}
if ((k & 1) == l) {
l = 1 - l;
continue;
}
case 10:
case 11:
case 39:
case 40:
case 50:
case 51:
case 62:
case 74:
case 76:
case 89:
case 122:
case 124:
case 130:
case 138:
case 169:
int x = FaweCache.CACHE_X[j][k];
int y = FaweCache.CACHE_Y[j][k];
int z = FaweCache.CACHE_Z[j][k];
if (isSurrounded(sections, x, y, z)) {
continue;
}
nmsWorld.func_147451_t(X + x, y, Z + z);
}
}
}
return true;
} catch (Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
public boolean isSurrounded(ExtendedBlockStorage[] sections, int x, int y, int z) {
return isSolid(getId(sections, x, y + 1, z))
&& isSolid(getId(sections, x + 1, y - 1, z))
&& isSolid(getId(sections, x - 1, y, z))
&& isSolid(getId(sections, x, y, z + 1))
&& isSolid(getId(sections, x, y, z - 1));
}
public boolean isSolid(int i) {
return i != 0 && Block.getBlockById(i).isOpaqueCube();
}
public int getId(ExtendedBlockStorage[] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
}
if (y < 0 || y > 255) {
return 1;
}
int i = FaweCache.CACHE_I[y][x][z];
ExtendedBlockStorage section = sections[i];
if (section == null) {
return 0;
}
byte[] array = section.getBlockLSBArray();
int j = FaweCache.CACHE_J[y][x][z];
return array[j];
}
}

View File

@ -0,0 +1,10 @@
[{
"modid": "com.boydti.fawe",
"name": "FastAsyncWorldEdit",
"description": "Extreme WorldEdit optimizations, no lag, low memory usage, area + tile + entity limits, block logging + rollback",
"version": "3.4.0",
"mcVersion": "1.7.10",
"dependencies": [
"WorldEdit"
]
}]

View File

@ -5,15 +5,14 @@ buildscript {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {url = "http://repo.minecrell.net/snapshots"}
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/"}
}
dependencies {
classpath 'net.minecrell:VanillaGradle:2.0.3-SNAPSHOT'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.1-SNAPSHOT'
}
}
apply plugin: 'net.minecrell.vanilla.server.library'
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
@ -41,7 +40,7 @@ repositories {
}
}
minecraft {
version = "1.8.9"
version = "1855"
mappings = "stable_22"
runDir = 'run'
}
@ -52,15 +51,16 @@ processResources {
from(sourceSets.main.resources.srcDirs) {
expand 'version': project.version,
'mcVersion': project.minecraft.version
exclude 'mcmod.info'
}
}
shadowJar {
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
dependencies {
include(dependency(':core'))
include(dependency('org.mcstats.sponge:metrics:R8-SNAPSHOT'))
include(dependency('org.yaml:snakeyaml:1.16'))
}
relocate 'org.mcstats', 'com.boydti.fawe.stats'
archiveName = "${parent.name}-${project.name}.jar"
destinationDir = file '../target'
}
@ -69,6 +69,7 @@ shadowJar.doLast {
ant.checksum file: task.archivePath
}
reobf {
shadowJar {
mappingType = 'SEARGE'
@ -80,4 +81,8 @@ task deobfJar(type: Jar) {
classifier = 'dev'
}
artifacts {
archives deobfJar
}
build.dependsOn(shadowJar)

View File

@ -0,0 +1,166 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.forge.v0.ForgeQueue_All;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.mojang.authlib.GameProfile;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.forge.ForgeWorld;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
import javax.management.InstanceAlreadyExistsException;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.Logger;
public class FaweForge implements IFawe {
private final ForgeMain parent;
private final File directory;
private final Logger logger;
public FaweForge(ForgeMain plugin, Logger logger, File directory) {
this.parent = plugin;
this.logger = logger;
this.directory = directory;
try {
Fawe.set(this);
} catch (InstanceAlreadyExistsException e) {
e.printStackTrace();
}
}
@Override
public void debug(String s) {
logger.debug(s);
}
@Override
public File getDirectory() {
return directory;
}
@Override
public void setupCommand(String label, FaweCommand cmd) {
if (TaskManager.IMP != null) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
ServerCommandManager scm = (ServerCommandManager) MinecraftServer.getServer().getCommandManager();
scm.registerCommand(new ForgeCommand(label, cmd));
}
});
}
}
@Override
public FawePlayer wrap(Object obj) {
EntityPlayerMP player = null;
if (obj instanceof String) {
MinecraftServer server = MinecraftServer.getServer();
player = server.getConfigurationManager().getPlayerByUsername((String) obj);
} else if (obj instanceof UUID) {
MinecraftServer server = MinecraftServer.getServer();
player = server.getConfigurationManager().getPlayerByUUID((UUID) obj);
} else if (obj instanceof EntityPlayerMP) {
player = (EntityPlayerMP) obj;
}
if (player == null) {
return null;
}
FawePlayer existing = Fawe.get().getCachedPlayer(player.getName());
return existing != null ? existing : new ForgePlayer(player);
}
@Override
public void setupWEListener() {
// Do nothing
}
@Override
public void setupVault() {
// Do nothing
}
@Override
public TaskManager getTaskManager() {
return new com.boydti.fawe.forge.ForgeTaskMan(512);
}
@Override
public int[] getVersion() {
String[] version = MinecraftServer.getServer().getMinecraftVersion().split("\\.");
return new int[] {Integer.parseInt(version[0]), Integer.parseInt(version[1]), Integer.parseInt(version[2])};
}
@Override
public String getWorldName(World world) {
if (world instanceof WorldWrapper) {
world = ((WorldWrapper) world).getParent();
}
return ((ForgeWorld) world).getWorld().provider.getDimensionName();
}
@Override
public FaweQueue getNewQueue(String world) {
return new ForgeQueue_All(world);
}
@Override
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
return new EditSessionWrapper(session);
}
@Override
public Collection<FaweMaskManager> getMaskManagers() {
return new ArrayList<>();
}
@Override
public void startMetrics() {
try {
com.boydti.fawe.forge.ForgeMetrics metrics = new com.boydti.fawe.forge.ForgeMetrics("FastAsyncWorldEdit", "3.4.0");
metrics.start();
debug("[FAWE] &6Metrics enabled.");
} catch (Throwable e) {
debug("[FAWE] &cFailed to load up metrics.");
}
}
@Override
public String getPlatform() {
return "forge";
}
@Override
public UUID getUUID(String name) {
try {
GameProfile profile = MinecraftServer.getServer().getPlayerProfileCache().getGameProfileForUsername(name);
return profile.getId();
} catch (Throwable e) {
return null;
}
}
@Override
public String getName(UUID uuid) {
try {
GameProfile profile = MinecraftServer.getServer().getPlayerProfileCache().getProfileByUUID(uuid);
return profile.getName();
} catch (Throwable e) {
return null;
}
}
}

View File

@ -0,0 +1,41 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
public class ForgeCommand extends CommandBase {
private final String name;
private final FaweCommand cmd;
public ForgeCommand(String name, FaweCommand cmd) {
this.name = name;
this.cmd = cmd;
}
@Override
public String getCommandName() {
return name;
}
@Override
public String getCommandUsage(ICommandSender iCommandSender) {
return "/" + name;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if ((sender instanceof EntityPlayerMP)) {
EntityPlayerMP player = (EntityPlayerMP) sender;
if (player.worldObj.isRemote) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
cmd.executeSafe(fp, args);
}
}
}

View File

@ -0,0 +1,76 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import java.io.File;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.4.0", acceptableRemoteVersions = "*")
public class ForgeMain {
private static com.boydti.fawe.forge.FaweForge IMP;
private Logger logger;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
this.logger = event.getModLog();
File directory = new File(event.getModConfigurationDirectory() + File.separator + "FastAsyncWorldEdit");
MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);
this.IMP = new com.boydti.fawe.forge.FaweForge(this, event.getModLog(), directory);
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerEvent.PlayerLoggedOutEvent event) {
if (event.player.worldObj.isRemote) {
return;
}
handleQuit((EntityPlayerMP) event.player);
}
@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
for (EntityPlayerMP player : (List<EntityPlayerMP>)MinecraftServer.getServer().getConfigurationManager().playerEntityList) {
handleQuit(player);
}
}
public void handleQuit(EntityPlayerMP player) {
FawePlayer fp = FawePlayer.wrap(player);
fp.unregister();
Fawe.get().unregister(player.getName());
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerChangedWorld(EntityJoinWorldEvent event) {
Entity entity = event.entity;
if (!(entity instanceof EntityPlayerMP)) {
return;
}
EntityPlayerMP player = (EntityPlayerMP) entity;
if (player.worldObj.isRemote) {
return;
}
FawePlayer fp = FawePlayer.wrap(player);
if (fp.getMeta("lastWorld") != event.world) {
fp.setMeta("lastWorld", event.world);
if (Settings.STORE_HISTORY_ON_DISK) {
fp.getSession().clearHistory();
fp.loadSessionsFromDisk(fp.getWorld());
}
}
}
}

View File

@ -0,0 +1,479 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
* Ported to Minecraft Forge by Mike Primm
* 1.7.x update by Dries007
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.boydti.fawe.forge;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
public class ForgeMetrics {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 15;
/**
* The mod this metrics submits for
*/
private final String modName;
private final String modVersion;
/**
* The metrics configuration file
*/
private final Configuration configuration;
/**
* The metrics configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
private Thread thread = null;
private boolean firstPost = true;
int tickCount;
public ForgeMetrics(final String modName, final String modVersion) throws IOException {
if (modName == null || modVersion == null) {
throw new IllegalArgumentException("modName and modVersion cannot be null");
}
this.modName = modName;
this.modVersion = modVersion;
// load the config
configurationFile = getConfigFile();
configuration = new Configuration(configurationFile);
// Get values, and add some defaults, if needed
configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false, "Set to true to disable all reporting");
guid = configuration.get(Configuration.CATEGORY_GENERAL, "guid", UUID.randomUUID().toString(), "Server unique ID").getString();
debug = configuration.get(Configuration.CATEGORY_GENERAL, "debug", false, "Set to true for verbose debug").getBoolean(false);
configuration.save();
}
/**
* Start measuring statistics. This will immediately create an async
* repeating task as the plugin and send the initial data to the metrics
* backend, and then after that it will post in increments of PING_INTERVAL
* * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
// Did we opt out?
if (isOptOut()) {
return false;
}
FMLCommonHandler.instance().bus().register(this);
return true;
}
@SubscribeEvent
public void tick(TickEvent.ServerTickEvent tick) {
if (tick.phase != TickEvent.Phase.END) return;
if (tickCount++ % (PING_INTERVAL * 1200) != 0) return;
if (thread == null) {
thread = new Thread(new Runnable() {
public void run() {
try {
// Disable Task, if it is running and the server owner decided
// to opt-out
if (isOptOut()) {
FMLCommonHandler.instance().bus().unregister(ForgeMetrics.this);
return;
}
// We use the inverse of firstPost because if it
// is the first time we are posting,
// it is not a interval ping, so it evaluates to
// FALSE
// Each time thereafter it will evaluate to
// TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to
// false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
FMLLog.info("[Metrics] Exception - %s", e.getMessage());
}
} finally {
thread = null;
}
}
});
thread.start();
}
}
/**
* Stop processing
*/
public void stop() {
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
// Reload the metrics file
configuration.load();
return configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false).getBoolean(false);
}
/**
* Enables metrics for the server by setting "opt-out" to false in the
* config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("false");
configuration.save();
}
// Enable Task, if it is not running
FMLCommonHandler.instance().bus().register(this);
}
/**
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("true");
configuration.save();
}
FMLCommonHandler.instance().bus().unregister(this);
}
/**
* Gets the File object of the config file that should be used to store data
* such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
return new File(Loader.instance().getConfigDir(), "PluginMetrics.cfg");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
String pluginName = modName;
boolean onlineMode = MinecraftServer.getServer().isServerInOnlineMode();
String pluginVersion = modVersion;
String serverVersion;
if (MinecraftServer.getServer().isDedicatedServer()) {
serverVersion = "MinecraftForge (MC: " + MinecraftServer.getServer().getMinecraftVersion() + ")";
} else {
serverVersion = "MinecraftForgeSSP (MC: " + MinecraftServer.getServer().getMinecraftVersion() + ")";
}
int playersOnline = MinecraftServer.getServer().getCurrentPlayerCount();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws java.io.UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -0,0 +1,66 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import java.util.UUID;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.world.World;
public class ForgePlayer extends FawePlayer<EntityPlayerMP> {
public ForgePlayer(EntityPlayerMP parent) {
super(parent);
}
@Override
public String getName() {
return parent.getName();
}
@Override
public UUID getUUID() {
return parent.getUniqueID();
}
@Override
public boolean hasPermission(String perm) {
Object meta = getMeta(perm);
return meta instanceof Boolean ? (boolean) meta : ForgeWorldEdit.inst.getPermissionsProvider().hasPermission(parent, perm);
}
@Override
public void setPermission(String perm, boolean flag) {
setMeta(perm, flag);
}
@Override
public void sendMessage(String msg) {
for (String part : msg.split("\n")) {
part = EnumChatFormatting.getTextWithoutFormattingCodes(msg);
ChatComponentText component = new ChatComponentText(part);
component.getChatStyle().setColor(EnumChatFormatting.LIGHT_PURPLE);
this.parent.addChatMessage(component);
}
}
@Override
public void executeCommand(String substring) {
throw new UnsupportedOperationException("NOT IMPLEMENTED");
}
@Override
public FaweLocation getLocation() {
World world = parent.worldObj;
BlockPos pos = parent.getPosition();
return new FaweLocation(world.provider.getDimensionName(), pos.getX(), pos.getY(), pos.getZ());
}
@Override
public Player getPlayer() {
return ForgeWorldEdit.inst.wrap(this.parent);
}
}

View File

@ -0,0 +1,165 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.util.TaskManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
public class ForgeTaskMan extends TaskManager {
private final ConcurrentLinkedDeque<Runnable> syncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentLinkedDeque<Runnable> asyncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentHashMap<Integer, Runnable> taskIdMap = new ConcurrentHashMap<>();
private final AtomicInteger taskId = new AtomicInteger();
private final ExecutorService executor;
public ForgeTaskMan(int size) {
this.executor = Executors.newFixedThreadPool(size);
FMLCommonHandler.instance().bus().register(this);
}
@Override
public int repeat(final Runnable r, final int interval) {
if (r == null) {
return -1;
}
int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
task(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
e.printStackTrace();
}
later(this, interval);
}
});
return id;
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onServerTick(TickEvent.ServerTickEvent event) {
int asyncSize = asyncTasks.size();
for (int i = 0; i < asyncSize; i++) {
Runnable item = asyncTasks.poll();
if (item != null) {
async(item);
}
}
int syncSize = syncTasks.size();
for (int i = 0; i < syncSize; i++) {
Runnable item = syncTasks.poll();
if (item != null) {
try {
item.run();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
}
@Override
public int repeatAsync(Runnable r, int interval) {
if (r == null) {
return -1;
}
int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
async(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
e.printStackTrace();
}
laterAsync(this, interval);
}
});
return id;
}
@Override
public void async(Runnable r) {
if (r == null) {
return;
}
executor.execute(r);
}
@Override
public void task(Runnable r) {
if (r == null) {
return;
}
syncTasks.add(r);
}
@Override
public void later(Runnable r, int delay) {
if (r == null) {
return;
}
AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
r.run();
} catch (Throwable e) {
e.printStackTrace();
}
return;
}
task(this);
}
});
}
@Override
public void laterAsync(Runnable r, int delay) {
if (r == null) {
return;
}
AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
async(r);
} catch (Throwable e) {
e.printStackTrace();
}
return;
}
task(this);
}
});
}
@Override
public void cancel(int task) {
taskIdMap.remove(task);
}
}

View File

@ -0,0 +1,235 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
public class ForgeChunk_All extends FaweChunk<Chunk> {
public char[][] ids;
public short[] count;
public short[] air;
public short[] relight;
public byte[][] biomes;
public Chunk chunk;
public ForgeChunk_All(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new char[16][];
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public Chunk getChunk() {
if (this.chunk == null) {
World world = ((ForgeQueue_All) getParent()).getWorld();
this.chunk = world.getChunkProvider().provideChunk(getX(), getZ());
}
return this.chunk;
}
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
this.chunk = null;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
/**
* Get the raw data for a section.
* @param i
* @return
*/
public char[] getIdArray(int i) {
return this.ids[i];
}
@Override
public void setBlock(int x, int y, int z, int id, byte data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
char[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.relight[i]++;
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 55:
case 56:
case 57:
case 58:
case 60:
case 7:
case 8:
case 9:
case 73:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 121:
case 129:
case 133:
case 165:
case 166:
case 170:
case 172:
case 173:
case 174:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
vs[j] = (char) (id << 4);
return;
case 130:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
case 50:
if (data < 2) {
data = 2;
}
default:
vs[j] = (char) ((id << 4) + data);
return;
}
}
@Override
public void setBiome(int x, int z, BaseBiome biome) {
if (this.biomes == null) {
this.biomes = new byte[16][];
}
byte[] index = this.biomes[x];
if (index == null) {
index = this.biomes[x] = new byte[16];
}
index[z] = (byte) biome.getId();
}
@Override
public FaweChunk clone() {
ForgeChunk_All toReturn = new ForgeChunk_All(getParent(), getX(), getZ());
toReturn.air = this.air.clone();
toReturn.count = this.count.clone();
toReturn.relight = this.relight.clone();
toReturn.ids = new char[this.ids.length][];
for (int i = 0; i < this.ids.length; i++) {
char[] matrix = this.ids[i];
if (matrix != null) {
toReturn.ids[i] = new char[matrix.length];
System.arraycopy(matrix, 0, toReturn.ids[i], 0, matrix.length);
}
}
return toReturn;
}
}

View File

@ -0,0 +1,541 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.forge.ForgePlayer;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.play.server.S21PacketChunkData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
public class ForgeQueue_All extends FaweQueue {
private World forgeWorld;
private ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk<Chunk>> chunks = new LinkedBlockingDeque<>();
public ForgeQueue_All(final String world) {
super(world);
}
@Override
public boolean isChunkLoaded(int x, int z) {
return getWorld().getChunkProvider().chunkExists(x, z);
}
public World getWorld() {
if (forgeWorld != null) {
return forgeWorld;
}
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(world)) {
return forgeWorld = ws;
}
}
return null;
}
@Override
public boolean regenerateChunk(int x, int z) {
IChunkProvider provider = getWorld().getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
IChunkProvider chunkProvider = chunkServer.serverChunkGenerator;
long pos = ChunkCoordIntPair.chunkXZ2Int(x, z);
Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
try {
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
droppedChunksSetField.setAccessible(true);
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
droppedChunksSet.remove(pos);
} catch (Throwable e) {
e.printStackTrace();
}
chunkServer.id2ChunkMap.remove(pos);
mcChunk = chunkProvider.provideChunk(x, z);
chunkServer.id2ChunkMap.add(pos, mcChunk);
chunkServer.loadedChunks.add(mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkProvider, chunkProvider, x, z);
}
return true;
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
}
private int lcx = Integer.MIN_VALUE;
private int lcz = Integer.MIN_VALUE;
private int lcy = Integer.MIN_VALUE;
private net.minecraft.world.chunk.Chunk lc;
private char[] ls;
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair loc) {
getWorld().getChunkProvider().provideChunk(loc.x, loc.z);
}
};
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lcx || cz != lcz) {
World world = getWorld();
lcx = cx;
lcz = cz;
IChunkProvider provider = world.getChunkProvider();
Chunk chunk;
if (!provider.chunkExists(lcx, lcz)) {
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
chunk = provider.provideChunk(cx, cz);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
if (!provider.chunkExists(cx, cz)) {
throw new FaweException.FaweChunkLoadException();
}
chunk = provider.provideChunk(cx, cz);
} else {
return 0;
}
} else {
chunk = provider.provideChunk(cx, cz);
}
lc = chunk;
} else if (cy == lcy) {
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;
}
ExtendedBlockStorage storage = lc.getBlockStorageArray()[cy];
if (storage == null) {
ls = null;
return 0;
}
ls = storage.getData();
return ls[FaweCache.CACHE_J[y][x & 15][z & 15]];
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastChunk = this.blocks.get(pair);
if (lastChunk == null) {
lastChunk = this.getChunk(x >> 4, z >> 4);
lastChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk<Chunk> previous = this.blocks.put(pair, lastChunk);
if (previous == null) {
chunks.add(lastChunk);
return true;
}
this.blocks.put(pair, previous);
lastChunk = previous;
}
}
lastChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
} else {
chunks.add(result);
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk<Chunk> chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk<Chunk>> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk<Chunk> fc) {
if (fc == null) {
return false;
}
// Load chunk
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
chunk.onChunkLoad();
}
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
}
@Override
public void setChunk(FaweChunk<?> chunk) {
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk<Chunk>) chunk);
}
public void sendChunk(FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
return;
}
World world = chunk.getWorld();
ChunkCoordIntPair pos = chunk.getChunkCoordIntPair();
int cx = pos.chunkXPos;
int cz = pos.chunkZPos;
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
ForgePlayer forgePlayer = (ForgePlayer) fp;
EntityPlayerMP player = forgePlayer.parent;
if (!player.worldObj.equals(world)) {
continue;
}
int view = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
BlockPos loc = player.getPosition();
int px = loc.getX() >> 4;
int pz = loc.getZ() >> 4;
int dx = Math.abs(cx - (loc.getX() >> 4));
int dz = Math.abs(cz - (loc.getZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
con.sendPacket(new S21PacketChunkData(chunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
public boolean setComponents(FaweChunk<Chunk> fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc;
Chunk forgeChunk = fc.getChunk();
net.minecraft.world.World nmsWorld = forgeChunk.getWorld();
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
// Sections
ExtendedBlockStorage[] sections = forgeChunk.getBlockStorageArray();
Map<BlockPos, TileEntity> tiles = forgeChunk.getTileEntityMap();
ClassInheritanceMultiMap<Entity>[] entities = forgeChunk.getEntityLists();
// Trim tiles
Set<Map.Entry<BlockPos, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Map.Entry<BlockPos, TileEntity> tile = iterator.next();
BlockPos pos = tile.getKey();
int lx = pos.getX() & 15;
int ly = pos.getY();
int lz = pos.getZ() & 15;
int j = FaweCache.CACHE_I[ly][lx][lz];
int k = FaweCache.CACHE_J[ly][lx][lz];
char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
iterator.remove();
}
}
// Trim entities
for (int i = 0; i < 16; i++) {
if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
entities[i] = new ClassInheritanceMultiMap<>(Entity.class);
}
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
continue;
}
char[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
ExtendedBlockStorage section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
section = new ExtendedBlockStorage(j << 4, flag);
section.setData(newArray);
sections[j] = section;
continue;
}
char[] currentArray = section.getData();
boolean fill = true;
for (int k = 0; k < newArray.length; k++) {
char n = newArray[k];
switch (n) {
case 0:
fill = false;
continue;
case 1:
fill = false;
currentArray[k] = 0;
continue;
default:
currentArray[k] = n;
continue;
}
}
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// // Clear
} catch (Throwable e) {
e.printStackTrace();
}
byte[][] biomes = fs.biomes;
if (biomes != null) {
for (int x = 0; x < 16; x++) {
byte[] array = biomes[x];
if (array == null) {
continue;
}
for (int z = 0; z < 16; z++) {
byte biome = array[z];
if (biome == 0) {
continue;
}
forgeChunk.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = biome;
}
}
}
sendChunk(fs);
return true;
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
return new ForgeChunk_All(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk<?> chunk, boolean fixAll) {
try {
ForgeChunk_All fc = (ForgeChunk_All) chunk;
Chunk forgeChunk = fc.getChunk();
if (!forgeChunk.isLoaded()) {
forgeChunk.onChunkLoad();
}
forgeChunk.generateSkylightMap();
if (fc.getTotalRelight() == 0 && !fixAll) {
return true;
}
ExtendedBlockStorage[] sections = forgeChunk.getBlockStorageArray();
net.minecraft.world.World nmsWorld = forgeChunk.getWorld();
int X = fc.getX() << 4;
int Z = fc.getZ() << 4;
for (int j = 0; j < sections.length; j++) {
ExtendedBlockStorage section = sections[j];
if (section == null) {
continue;
}
if ((fc.getRelight(j) == 0 && !fixAll) || fc.getCount(j) == 0 || (fc.getCount(j) >= 4096 && fc.getAir(j) == 0)) {
continue;
}
char[] array = section.getData();
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
short id = (short) (i >> 4);
switch (id) { // Lighting
default:
if (!fixAll) {
continue;
}
if ((k & 1) == l) {
l = 1 - l;
continue;
}
case 10:
case 11:
case 39:
case 40:
case 50:
case 51:
case 62:
case 74:
case 76:
case 89:
case 122:
case 124:
case 130:
case 138:
case 169:
int x = FaweCache.CACHE_X[j][k];
int y = FaweCache.CACHE_Y[j][k];
int z = FaweCache.CACHE_Z[j][k];
if (isSurrounded(sections, x, y, z)) {
continue;
}
BlockPos pos = new BlockPos(X + x, y, Z + z);
nmsWorld.checkLight(pos);
}
}
}
return true;
} catch (Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
public boolean isSurrounded(ExtendedBlockStorage[] sections, int x, int y, int z) {
return isSolid(getId(sections, x, y + 1, z))
&& isSolid(getId(sections, x + 1, y - 1, z))
&& isSolid(getId(sections, x - 1, y, z))
&& isSolid(getId(sections, x, y, z + 1))
&& isSolid(getId(sections, x, y, z - 1));
}
public boolean isSolid(int i) {
return i != 0 && Block.getBlockById(i).isOpaqueCube();
}
public int getId(ExtendedBlockStorage[] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
}
if (y < 0 || y > 255) {
return 1;
}
int i = FaweCache.CACHE_I[y][x][z];
ExtendedBlockStorage section = sections[i];
if (section == null) {
return 0;
}
char[] array = section.getData();
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
}

View File

View File

@ -1,3 +1,5 @@
#org.gradle.java.home=C:/PROGRA~2/Java/jdk1.7.0_79
#org.gradle.java.home=C:/PROGRA~1/Java/jdk1.8.0_51
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
org.gradle.configureondemand=true

View File

@ -8,7 +8,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<artifactId>FastAsyncWorldEdit</artifactId>
<version>3.3.21</version>
<version>3.4.0</version>
<name>FastAsyncWorldEdit</name>
<packaging>jar</packaging>
<build>

View File

@ -1,3 +1,3 @@
rootProject.name = 'FastAsyncWorldEdit'
include 'core', 'bukkit', 'forge'
include 'core', 'bukkit', 'forge189', 'forge1710', 'sponge'

94
sponge/build.gradle Normal file
View File

@ -0,0 +1,94 @@
buildscript {
repositories {
jcenter()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {
name = 'minecrell'
url = 'http://repo.minecrell.net/releases'
}
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/"}
maven {url = "http://repo.minecrell.net/snapshots"}
}
dependencies {
classpath 'net.minecrell:VanillaGradle:2.0.3_1'
classpath 'net.minecraftforge.gradle:ForgeGradle:2.1-SNAPSHOT'
}
}
apply plugin: 'net.minecrell.vanilla.server.library'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile project(':core')
compile 'org.spongepowered:spongeapi:4.+'
compile 'org.mcstats.sponge:metrics:R8-SNAPSHOT'
compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
maven {
name = 'forge'
url = 'http://files.minecraftforge.net/maven'
}
maven {
name = "Sponge"
url = "https://repo.spongepowered.org/maven"
}
maven {
name = "Sponge Metrics"
url = "http://repo.mcstats.org/content/repositories/releases/"
}
}
minecraft {
version = "1.8.9"
mappings = "stable_22"
runDir = 'run'
}
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraft.version}"
processResources {
from(sourceSets.main.resources.srcDirs) {
expand 'version': project.version,
'mcVersion': project.minecraft.version
exclude 'mcmod.info'
}
}
shadowJar {
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
dependencies {
include(dependency(':core'))
include(dependency('org.yaml:snakeyaml:1.16'))
}
archiveName = "${parent.name}-${project.name}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
reobf {
shadowJar {
mappingType = 'SEARGE'
}
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'dev'
}
artifacts {
archives deobfJar
}
build.dependsOn(shadowJar)

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge;
package com.boydti.fawe;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;

View File

@ -1,10 +1,10 @@
package com.boydti.fawe.forge;
package com.boydti.fawe.sponge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.forge.v0.SpongeEditSessionWrapper_0;
import com.boydti.fawe.forge.v1_8.SpongeQueue_1_8;
import com.boydti.fawe.SpongeCommand;
import com.boydti.fawe.v1_8.SpongeQueue_1_8;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
@ -13,12 +13,10 @@ import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.living.player.Player;
@ -118,9 +116,14 @@ public class FaweSponge implements IFawe {
return new SpongeQueue_1_8(world);
}
@Override
public String getWorldName(World world) {
return world.getName();
}
@Override
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
return new SpongeEditSessionWrapper_0(session);
return new EditSessionWrapper(session);
}
@Override
@ -134,20 +137,11 @@ public class FaweSponge implements IFawe {
SpongeMetrics metrics = new SpongeMetrics(Sponge.getGame(), Sponge.getPluginManager().fromInstance(plugin).get());
metrics.start();
debug("[FAWE] &6Metrics enabled.");
} catch (IOException e) {
} catch (Throwable e) {
debug("[FAWE] &cFailed to load up metrics.");
}
}
@Override
public Set<FawePlayer> getPlayers() {
HashSet<FawePlayer> players = new HashSet<>();
for (Player player : Sponge.getServer().getOnlinePlayers()) {
players.add(wrap(player));
}
return players;
}
@Override
public String getPlatform() {
return "sponge";

View File

@ -1,10 +1,10 @@
package com.boydti.fawe.forge;
package com.boydti.fawe.sponge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import com.google.inject.Inject;
import com.sk89q.worldedit.WorldEdit;
import org.slf4j.Logger;
import org.spongepowered.api.Game;
import org.spongepowered.api.Server;
@ -18,7 +18,7 @@ import org.spongepowered.api.plugin.PluginContainer;
import org.spongepowered.api.profile.GameProfileManager;
import org.spongepowered.api.world.World;
@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.3.21")
@Plugin(id = "com.boydti.fawe", name = "FastAsyncWorldEdit", description = "Lagless WorldEdit, Area restrictions, Memory mangement, Block logging", url = "https://github.com/boy0001/FastAsyncWorldedit", version = "3.4.0", authors = "Empire92")
public class SpongeMain {
public PluginContainer plugin;
@ -70,13 +70,10 @@ public class SpongeMain {
if (!from.equals(to)) {
Player player = event.getTargetEntity();
FawePlayer fp = FawePlayer.wrap(player);
for (com.sk89q.worldedit.world.World world : WorldEdit.getInstance().getServer().getWorlds()) {
if (world.getName().equals(to.getName())) {
fp.getSession().clearHistory();
fp.loadSessionFromDisk(world);
return;
}
}
com.sk89q.worldedit.world.World world = FaweAPI.getWorld(to.getName());
fp.getSession().clearHistory();
fp.loadSessionsFromDisk(world);
return;
}
}
}

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge;
package com.boydti.fawe.sponge;
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge;
package com.boydti.fawe.sponge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
@ -58,9 +58,4 @@ public class SpongePlayer extends FawePlayer<Player> {
public com.sk89q.worldedit.entity.Player getPlayer() {
return (com.sk89q.worldedit.entity.Player) Fawe.<FaweSponge> imp().getWorldEditPlugin().wrap((EntityPlayerMP) this.parent);
}
@Override
public boolean hasWorldEditBypass() {
return hasPermission("fawe.bypass") || getMeta("fawe.bypass") == Boolean.TRUE;
}
}

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge;
package com.boydti.fawe.sponge;
import com.boydti.fawe.util.TaskManager;
import java.util.HashMap;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge;
package com.boydti.fawe.sponge;
import com.boydti.fawe.Fawe;
import com.sk89q.worldedit.world.biome.BiomeData;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge.v0;
package com.boydti.fawe.v0;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
@ -10,9 +10,6 @@ import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.World;
/**
* Created by Jesse on 4/2/2016.
*/
public abstract class SpongeQueue_0 extends FaweQueue {
/**

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.forge.v1_8;
package com.boydti.fawe.v1_8;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;

View File

@ -1,13 +1,14 @@
package com.boydti.fawe.forge.v1_8;
package com.boydti.fawe.v1_8;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.forge.SpongeUtil;
import com.boydti.fawe.forge.v0.SpongeQueue_0;
import com.boydti.fawe.sponge.SpongeUtil;
import com.boydti.fawe.v0.SpongeQueue_0;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.TaskManager;
import com.flowpowered.math.vector.Vector3i;
@ -18,7 +19,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.LinkedBlockingDeque;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
@ -44,24 +44,20 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
public SpongeQueue_1_8(String world) {
super(world);
TaskManager.IMP.repeat(() -> {
synchronized (loadQueue) {
while (loadQueue.size() > 0) {
IntegerPair loc = loadQueue.poll();
if (spongeWorld == null) {
spongeWorld = Sponge.getServer().getWorld(world).get();
}
Chunk chunk = spongeWorld.getChunk(loc.x, 0, loc.z).orElse(null);
if (chunk == null || !chunk.isLoaded()) {
spongeWorld.loadChunk(loc.x, 0, loc.z, true);
}
}
loadQueue.notifyAll();
}
}, 1);
}
private LinkedBlockingDeque<IntegerPair> loadQueue = new LinkedBlockingDeque<>();
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair loc) {
if (spongeWorld == null) {
spongeWorld = Sponge.getServer().getWorld(world).get();
}
Chunk chunk = spongeWorld.getChunk(loc.x, 0, loc.z).orElse(null);
if (chunk == null || !chunk.isLoaded()) {
spongeWorld.loadChunk(loc.x, 0, loc.z, true);
}
}
};
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
@ -83,14 +79,8 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
if (sync) {
chunk = spongeWorld.loadChunk(cx, 0, cz, true).orElse(null);
} else if (Settings.CHUNK_WAIT > 0) {
synchronized (loadQueue) {
loadQueue.add(new IntegerPair(cx, cz));
try {
loadQueue.wait(Settings.CHUNK_WAIT);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
chunk = spongeWorld.getChunk(cx, 0, cz).orElse(null);
if (chunk == null || !chunk.isLoaded()) {
throw new FaweException.FaweChunkLoadException();
@ -125,35 +115,48 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
}
public void sendChunk(FaweChunk<Chunk> fc) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
return;
}
World world = chunk.getWorld();
Vector3i pos = chunk.getBlockMin();
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
for (Player player : Sponge.getServer().getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
return;
}
World world = chunk.getWorld();
Vector3i pos = chunk.getBlockMin();
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
for (Player player : Sponge.getServer().getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
}
int view = player.getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
Location<World> loc = player.getLocation();
int px = loc.getBlockX() >> 4;
int pz = loc.getBlockZ() >> 4;
int dx = Math.abs(cx - (loc.getBlockX() >> 4));
int dz = Math.abs(cz - (loc.getBlockZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) chunk;
con.sendPacket(new S21PacketChunkData(nmsChunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
}, false);
}
int view = player.getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
Location<World> loc = player.getLocation();
int px = loc.getBlockX() >> 4;
int pz = loc.getBlockZ() >> 4;
int dx = Math.abs(cx - (loc.getBlockX() >> 4));
int dz = Math.abs(cz - (loc.getBlockZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) chunk;
con.sendPacket(new S21PacketChunkData(nmsChunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}, Settings.ASYNC_LIGHTING);
}
private int lcx = Integer.MIN_VALUE;
@ -256,12 +259,7 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
}
}
}
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
sendChunk(fs);
}
}, 1);
sendChunk(fs);
return true;
}
@ -350,7 +348,9 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
}
return true;
} catch (Throwable e) {
e.printStackTrace();
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}

View File