diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000000..db361119ad
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..9251ca7e61
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,47 @@
+.DS_Store
+/BuildAll/nbproject/private/
+/EssentialsProtect/nbproject/private/
+/EssentialsChat/nbproject/private/
+/EssentialsGroupBridge/nbproject/private/
+/EssentialsGeoIP/nbproject/private/
+/EssentialsSpawn/nbproject/private/
+/EssentialsXMPP/nbproject/private/
+/EssentialsGroupManager/nbproject/private/
+/BuildAll/build/
+/EssentialsGroupBridge/dist/
+/EssentialsGroupBridge/build/
+/EssentialsGeoIP/dist/
+/EssentialsGeoIP/build/
+/EssentialsGroupManager/build/
+/EssentialsGroupManager/dist/
+/BuildAll/dist/
+/EssentialsChat/build/
+/EssentialsChat/dist/
+/EssentialsSpawn/build/
+/EssentialsSpawn/dist/
+/EssentialsXMPP/dist/
+/EssentialsXMPP/build/
+/EssentialsProtect/dist/
+/EssentialsProtect/build/
+/EssentialsPermissionsCommands/nbproject/private/
+/EssentialsPermissionsCommands/build/
+/EssentialsPermissionsCommands/dist/
+/Essentials/nbproject/private/
+/Essentials/dist/
+/Essentials/build/
+/YamlAnnotations/
+/EssentialsUpdate/nbproject/private/
+/EssentialsRelease/
+/EssentialsUpdate/dist/
+/EssentialsUpdate/build/
+/WebPush/apikey.php
+/WebPush/nbproject/private
+/.idea
+*.iml
+/EssentialsGroupManager/bin
+/EssentialsGroupManager/.externalToolBuilders
+/EssentialsAntiBuild/nbproject/private/
+/EssentialsAntiBuild/dist/
+/EssentialsAntiBuild/build/
+/jars
+/out
\ No newline at end of file
diff --git a/.project b/.project
new file mode 100644
index 0000000000..2c69e05606
--- /dev/null
+++ b/.project
@@ -0,0 +1,17 @@
+
+
+ Essentials
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000000..b68a6c4952
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,17 @@
+language: java
+jdk:
+ - oraclejdk7
+ - openjdk7
+ - openjdk6
+script: ant collect
+notifications:
+ irc:
+ channels:
+ - "irc.esper.net#lain"
+ on_success: change
+ on_failure: always
+ email:
+ recipients:
+ - "khobbits@ess3.net"
+ on_success: change
+ on_failure: always
\ No newline at end of file
diff --git a/BuildAll/build.xml b/BuildAll/build.xml
new file mode 100644
index 0000000000..d41b561fde
--- /dev/null
+++ b/BuildAll/build.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project BuildAll.
+
+
+
diff --git a/BuildAll/nbproject/build-impl.xml b/BuildAll/nbproject/build-impl.xml
new file mode 100644
index 0000000000..3c7d317da7
--- /dev/null
+++ b/BuildAll/nbproject/build-impl.xml
@@ -0,0 +1,1537 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set test.src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No tests executed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set JVM to use for profiling in profiler.info.jvm
+ Must set profiler agent JVM arguments in profiler.info.jvmargs.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+
+
+
+
+
+ java -cp "${run.classpath.with.dist.jar}" ${main.class}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ java -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set profile.class
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+ Must select some files in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+ Must select one file in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BuildAll/nbproject/genfiles.properties b/BuildAll/nbproject/genfiles.properties
new file mode 100644
index 0000000000..b95cd73c29
--- /dev/null
+++ b/BuildAll/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=cab45985
+build.xml.script.CRC32=7a797370
+build.xml.stylesheet.CRC32=28e38971@1.50.3.46
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=b4df970c
+nbproject/build-impl.xml.script.CRC32=8905537e
+nbproject/build-impl.xml.stylesheet.CRC32=6ddba6b6@1.53.1.46
diff --git a/BuildAll/nbproject/project.properties b/BuildAll/nbproject/project.properties
new file mode 100644
index 0000000000..a18e718e52
--- /dev/null
+++ b/BuildAll/nbproject/project.properties
@@ -0,0 +1,129 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=BuildAll
+application.vendor=
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=true
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=2
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=2
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=2
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=120
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineAnnotationArgs=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineArrayInit=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineAssignment=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineBinaryOp=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineCallArgs=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineDisjunctiveCatchTypes=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineFor=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineImplements=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineMethodParams=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineParenthesized=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineTernaryOp=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineThrows=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineTryResources=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesAfterClassHeader=0
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesBeforeClass=2
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement=NEW_LINE
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width=4
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indentCasesFromSwitch=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement=NEW_LINE
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement=NEW_LINE
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeCatchOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeElseOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeFinallyOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeWhileOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceAfterTypeCast=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab=4
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size=4
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/BuildAll.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+includes=**
+jar.compress=true
+javac.classpath=\
+ ${reference.Essentials.jar}:\
+ ${reference.EssentialsChat.jar}:\
+ ${reference.EssentialsAntiBuild.jar}:\
+ ${reference.EssentialsProtect.jar}:\
+ ${reference.EssentialsSpawn.jar}:\
+ ${reference.EssentialsGeoIP.jar}:\
+ ${reference.EssentialsXMPP.jar}:\
+ ${reference.EssentialsGroupManager.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.6
+javac.target=1.6
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+project.Essentials=../Essentials
+project.EssentialsChat=../EssentialsChat
+project.EssentialsGeoIP=../EssentialsGeoIP
+project.EssentialsGroupManager=../EssentialsGroupManager
+project.EssentialsAntiBuild=../EssentialsAntiBuild
+project.EssentialsProtect=../EssentialsProtect
+project.EssentialsSpawn=../EssentialsSpawn
+project.EssentialsXMPP=../EssentialsXMPP
+reference.Essentials.jar=${project.Essentials}/dist/Essentials.jar
+reference.EssentialsChat.jar=${project.EssentialsChat}/dist/EssentialsChat.jar
+reference.EssentialsGeoIP.jar=${project.EssentialsGeoIP}/dist/EssentialsGeoIP.jar
+reference.EssentialsGroupManager.jar=${project.EssentialsGroupManager}/dist/EssentialsGroupManager.jar
+reference.EssentialsAntiBuild.jar=${project.EssentialsAntiBuild}/dist/EssentialsAntiBuild.jar
+reference.EssentialsProtect.jar=${project.EssentialsProtect}/dist/EssentialsProtect.jar
+reference.EssentialsSpawn.jar=${project.EssentialsSpawn}/dist/EssentialsSpawn.jar
+reference.EssentialsXMPP.jar=${project.EssentialsXMPP}/dist/EssentialsXMPP.jar
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/BuildAll/nbproject/project.xml b/BuildAll/nbproject/project.xml
new file mode 100644
index 0000000000..a7afa7da68
--- /dev/null
+++ b/BuildAll/nbproject/project.xml
@@ -0,0 +1,84 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ BuildAll
+
+
+
+
+
+
+
+
+ ..\lib\nblibraries.properties
+
+
+
+ Essentials
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsChat
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsGeoIP
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsGroupManager
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsAntiBuild
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsProtect
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsSpawn
+ jar
+
+ jar
+ clean
+ jar
+
+
+ EssentialsXMPP
+ jar
+
+ jar
+ clean
+ jar
+
+
+
+
diff --git a/Essentials/build.xml b/Essentials/build.xml
new file mode 100644
index 0000000000..a0a5a2fa2c
--- /dev/null
+++ b/Essentials/build.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+ Builds, tests, and runs the project Essentials.
+
+
+
+
diff --git a/Essentials/nbproject/build-impl.xml b/Essentials/nbproject/build-impl.xml
new file mode 100644
index 0000000000..7a011527b1
--- /dev/null
+++ b/Essentials/nbproject/build-impl.xml
@@ -0,0 +1,1450 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set src.dir
+ Must set test.src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set build.classes.dir
+ Must set dist.javadoc.dir
+ Must set build.test.classes.dir
+ Must set build.test.results.dir
+ Must set build.classes.excludes
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No tests executed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set JVM to use for profiling in profiler.info.jvm
+ Must set profiler agent JVM arguments in profiler.info.jvmargs.agent
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+
+
+
+
+
+ java -cp "${run.classpath.with.dist.jar}" ${main.class}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To run this application from the command line without Ant, try:
+
+ java -jar "${dist.jar.resolved}"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must select one file in the IDE or set debug.class
+
+
+
+
+ Must set fix.includes
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set profile.class
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+ This target only works when run from inside the NetBeans IDE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+
+ Must select one file in the IDE or set run.class
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set test.includes
+
+
+
+ Some tests failed; see details above.
+
+
+
+ Must select some files in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+ Some tests failed; see details above.
+
+
+
+
+ Must select one file in the IDE or set test.class
+
+
+
+ Must select one file in the IDE or set test.class
+ Must select some method in the IDE or set test.method
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+ Must select one file in the IDE or set applet.url
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Essentials/nbproject/genfiles.properties b/Essentials/nbproject/genfiles.properties
new file mode 100644
index 0000000000..8b1c292649
--- /dev/null
+++ b/Essentials/nbproject/genfiles.properties
@@ -0,0 +1,11 @@
+build.xml.data.CRC32=7d758acf
+build.xml.script.CRC32=3233ee78
+build.xml.stylesheet.CRC32=28e38971@1.38.2.45
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=a830bc14
+nbproject/build-impl.xml.script.CRC32=21ffdddf
+nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46
+nbproject/profiler-build-impl.xml.data.CRC32=ab78ce15
+nbproject/profiler-build-impl.xml.script.CRC32=abda56ed
+nbproject/profiler-build-impl.xml.stylesheet.CRC32=f10cf54c@1.11.1
diff --git a/Essentials/nbproject/pmd.settings b/Essentials/nbproject/pmd.settings
new file mode 100644
index 0000000000..29baf7ea1b
--- /dev/null
+++ b/Essentials/nbproject/pmd.settings
@@ -0,0 +1,3 @@
+DoNotUseThreads
+LongVariable
+SignatureDeclareThrowsException
diff --git a/Essentials/nbproject/project.properties b/Essentials/nbproject/project.properties
new file mode 100644
index 0000000000..7537d98125
--- /dev/null
+++ b/Essentials/nbproject/project.properties
@@ -0,0 +1,150 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=true
+annotation.processing.processors.list=lombok.core.AnnotationProcessor
+annotation.processing.run.all.processors=false
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=Essentials
+application.vendor=
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=true
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=2
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=2
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=2
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=120
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap=none
+auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineAnnotationArgs=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineArrayInit=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineAssignment=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineBinaryOp=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineCallArgs=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineDisjunctiveCatchTypes=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineFor=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineImplements=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineMethodParams=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineParenthesized=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineTernaryOp=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineThrows=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.alignMultilineTryResources=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesAfterClassHeader=0
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.blankLinesBeforeClass=2
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement=NEW_LINE
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder=*
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width=4
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indentCasesFromSwitch=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement=NEW_LINE
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement=NEW_LINE
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeCatchOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeElseOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeFinallyOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.placeWhileOnNewLine=true
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.separateImportGroups=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceAfterTypeCast=false
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab=4
+auxiliary.org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size=4
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+ ${run.classpath}
+debug.test.classpath=\
+ ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/Essentials.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+file.reference.BOSEconomy7.jar=../lib/BOSEconomy7.jar
+file.reference.bpermissions2.jar=../lib/bpermissions2.jar
+file.reference.bukkit.jar=../lib/bukkit.jar
+file.reference.iCo5.jar=../lib/iCo5.jar
+file.reference.iCo6.jar=../lib/iCo6.jar
+file.reference.lombok.jar=../lib/lombok-0.10.8.jar
+file.reference.MultiCurrency.jar=../lib/MultiCurrency.jar
+file.reference.PermissionsBukkit-1.2.jar=../lib/PermissionsBukkit-1.2.jar
+file.reference.PermissionsEx.jar=../lib/PermissionsEx.jar
+file.reference.Privileges.jar=..\\lib\\Privileges.jar
+file.reference.Vault.jar=../lib/Vault.jar
+file.reference.SimplyPerms.jar=../lib/SimplyPerms.jar
+file.reference.zPermissions.jar=../lib/zPermissions.jar
+includes=**
+jar.archive.disabled=${jnlp.enabled}
+jar.compress=true
+jar.index=${jnlp.enabled}
+javac.classpath=\
+ ${file.reference.iCo5.jar}:\
+ ${file.reference.iCo6.jar}:\
+ ${file.reference.MultiCurrency.jar}:\
+ ${file.reference.BOSEconomy7.jar}:\
+ ${file.reference.PermissionsEx.jar}:\
+ ${file.reference.PermissionsBukkit-1.2.jar}:\
+ ${file.reference.lombok.jar}:\
+ ${reference.EssentialsGroupManager.jar}:\
+ ${file.reference.bukkit.jar}:\
+ ${file.reference.Vault.jar}:\
+ ${file.reference.Privileges.jar}:\
+ ${file.reference.bpermissions2.jar}:\
+ ${file.reference.SimplyPerms.jar}:\
+ ${file.reference.zPermissions.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=-Xlint:unchecked
+javac.deprecation=false
+javac.processorpath=\
+ ${javac.classpath}
+javac.source=1.6
+javac.target=1.6
+javac.test.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}:\
+ ${libs.junit_4.10.classpath}
+javac.test.processorpath=\
+ ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.reference.PermissionsEx.jar=../lib/PermissionsEx-javadoc.jar
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+jnlp.codebase.type=no.codebase
+jnlp.descriptor=application
+jnlp.enabled=false
+jnlp.mixed.code=default
+jnlp.offline-allowed=false
+jnlp.signed=false
+jnlp.signing=
+jnlp.signing.alias=
+jnlp.signing.keystore=
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=true
+platform.active=default_platform
+project.EssentialsGroupManager=../EssentialsGroupManager
+reference.EssentialsGroupManager.jar=../EssentialsGroupManager/dist/EssentialsGroupManager.jar
+run.classpath=\
+ ${javac.classpath}:\
+ ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=-Djline.terminal=jline.UnsupportedTerminal
+run.test.classpath=\
+ ${javac.test.classpath}:\
+ ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/Essentials/nbproject/project.xml b/Essentials/nbproject/project.xml
new file mode 100644
index 0000000000..ac9690fc3b
--- /dev/null
+++ b/Essentials/nbproject/project.xml
@@ -0,0 +1,28 @@
+
+
+ org.netbeans.modules.java.j2seproject
+
+
+ Essentials
+
+
+
+
+
+
+
+
+ ../lib/nblibraries.properties
+
+
+
+ EssentialsGroupManager
+ jar
+
+ jar
+ clean
+ jar
+
+
+
+
diff --git a/Essentials/src/book.txt b/Essentials/src/book.txt
new file mode 100644
index 0000000000..164910fb7e
--- /dev/null
+++ b/Essentials/src/book.txt
@@ -0,0 +1,18 @@
+This is the book file.
+
+This file format works similar to the info.txt, motd.txt and rules.txt
+
+Place content in here that you would like to be used by books ingame.
+
+You can use this content by using the book: meta option in kits or item spawning.
+
+#Colors
+Minecraft colors:
+&0 &&0 &1 &&1 &2 &&2 &3 &&3
+&4 &&4 &5 &&5 &6 &&6 &7 &&7
+&8 &&8 &9 &&9 &a &&a &b &&b
+&c &&c &d &&d &e &&e &f &&f
+&0
+&&k &kMagic&r &&l &lBold
+&&m &mStrike&r &&n &nUline
+&&o &oItalic&r &&r &rReset
\ No newline at end of file
diff --git a/Essentials/src/com/earth2me/essentials/AlternativeCommandsHandler.java b/Essentials/src/com/earth2me/essentials/AlternativeCommandsHandler.java
new file mode 100644
index 0000000000..59eb5326b5
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/AlternativeCommandsHandler.java
@@ -0,0 +1,139 @@
+package com.earth2me.essentials;
+
+import net.ess3.api.IEssentials;
+import java.util.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bukkit.command.Command;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.command.PluginCommandYamlParser;
+import org.bukkit.plugin.Plugin;
+
+
+public class AlternativeCommandsHandler
+{
+ private static final Logger LOGGER = Logger.getLogger("Minecraft");
+ private final transient Map> altcommands = new HashMap>();
+ private final transient Map disabledList = new HashMap();
+ private final transient IEssentials ess;
+
+ public AlternativeCommandsHandler(final IEssentials ess)
+ {
+ this.ess = ess;
+ for (Plugin plugin : ess.getServer().getPluginManager().getPlugins())
+ {
+ if (plugin.isEnabled())
+ {
+ addPlugin(plugin);
+ }
+ }
+ }
+
+ public final void addPlugin(final Plugin plugin)
+ {
+ if (plugin.getDescription().getMain().contains("com.earth2me.essentials"))
+ {
+ return;
+ }
+ final List commands = PluginCommandYamlParser.parse(plugin);
+ final String pluginName = plugin.getDescription().getName().toLowerCase(Locale.ENGLISH);
+
+ for (Command command : commands)
+ {
+ final PluginCommand pc = (PluginCommand)command;
+ final List labels = new ArrayList(pc.getAliases());
+ labels.add(pc.getName());
+
+ PluginCommand reg = ess.getServer().getPluginCommand(pluginName + ":" + pc.getName().toLowerCase(Locale.ENGLISH));
+ if (reg == null)
+ {
+ reg = ess.getServer().getPluginCommand(pc.getName().toLowerCase(Locale.ENGLISH));
+ }
+ if (reg == null || !reg.getPlugin().equals(plugin))
+ {
+ continue;
+ }
+ for (String label : labels)
+ {
+ List plugincommands = altcommands.get(label.toLowerCase(Locale.ENGLISH));
+ if (plugincommands == null)
+ {
+ plugincommands = new ArrayList();
+ altcommands.put(label.toLowerCase(Locale.ENGLISH), plugincommands);
+ }
+ boolean found = false;
+ for (PluginCommand pc2 : plugincommands)
+ {
+ if (pc2.getPlugin().equals(plugin))
+ {
+ found = true;
+ }
+ }
+ if (!found)
+ {
+ plugincommands.add(reg);
+ }
+ }
+ }
+ }
+
+ public void removePlugin(final Plugin plugin)
+ {
+ final Iterator>> iterator = altcommands.entrySet().iterator();
+ while (iterator.hasNext())
+ {
+ final Map.Entry> entry = iterator.next();
+ final Iterator pcIterator = entry.getValue().iterator();
+ while (pcIterator.hasNext())
+ {
+ final PluginCommand pc = pcIterator.next();
+ if (pc.getPlugin() == null || pc.getPlugin().equals(plugin))
+ {
+ pcIterator.remove();
+ }
+ }
+ if (entry.getValue().isEmpty())
+ {
+ iterator.remove();
+ }
+ }
+ }
+
+ public PluginCommand getAlternative(final String label)
+ {
+ final List commands = altcommands.get(label);
+ if (commands == null || commands.isEmpty())
+ {
+ return null;
+ }
+ if (commands.size() == 1)
+ {
+ return commands.get(0);
+ }
+ // return the first command that is not an alias
+ for (PluginCommand command : commands)
+ {
+ if (command.getName().equalsIgnoreCase(label))
+ {
+ return command;
+ }
+ }
+ // return the first alias
+ return commands.get(0);
+ }
+
+ public void executed(final String label, final PluginCommand pc)
+ {
+ final String altString = pc.getPlugin().getName() + ":" + pc.getLabel();
+ if (ess.getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Essentials: Alternative command " + label + " found, using " + altString);
+ }
+ disabledList.put(label, altString);
+ }
+
+ public Map disabledCommands()
+ {
+ return disabledList;
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Backup.java b/Essentials/src/com/earth2me/essentials/Backup.java
new file mode 100644
index 0000000000..0c47c48001
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Backup.java
@@ -0,0 +1,155 @@
+package com.earth2me.essentials;
+
+import net.ess3.api.IEssentials;
+import static com.earth2me.essentials.I18n._;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bukkit.Server;
+import org.bukkit.command.CommandSender;
+
+
+public class Backup implements Runnable
+{
+ private static final Logger LOGGER = Logger.getLogger("Minecraft");
+ private transient final Server server;
+ private transient final IEssentials ess;
+ private transient boolean running = false;
+ private transient int taskId = -1;
+ private transient boolean active = false;
+
+ public Backup(final IEssentials ess)
+ {
+ this.ess = ess;
+ server = ess.getServer();
+ if (server.getOnlinePlayers().length > 0)
+ {
+ ess.runTaskAsynchronously(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ startTask();
+ }
+ });
+ }
+ }
+
+ public void onPlayerJoin()
+ {
+ startTask();
+ }
+
+ public synchronized void stopTask()
+ {
+ running = false;
+ if (taskId != -1)
+ {
+ server.getScheduler().cancelTask(taskId);
+ }
+ taskId = -1;
+ }
+
+ private synchronized void startTask()
+ {
+ if (!running)
+ {
+ final long interval = ess.getSettings().getBackupInterval() * 1200; // minutes -> ticks
+ if (interval < 1200)
+ {
+ return;
+ }
+ taskId = ess.scheduleSyncRepeatingTask(this, interval, interval);
+ running = true;
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ if (active)
+ {
+ return;
+ }
+ active = true;
+ final String command = ess.getSettings().getBackupCommand();
+ if (command == null || "".equals(command))
+ {
+ return;
+ }
+ if ("save-all".equalsIgnoreCase(command))
+ {
+ final CommandSender cs = server.getConsoleSender();
+ server.dispatchCommand(cs, "save-all");
+ active = false;
+ return;
+ }
+ LOGGER.log(Level.INFO, _("backupStarted"));
+ final CommandSender cs = server.getConsoleSender();
+ server.dispatchCommand(cs, "save-all");
+ server.dispatchCommand(cs, "save-off");
+
+ ess.runTaskAsynchronously(
+ new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ final ProcessBuilder childBuilder = new ProcessBuilder(command);
+ childBuilder.redirectErrorStream(true);
+ childBuilder.directory(ess.getDataFolder().getParentFile().getParentFile());
+ final Process child = childBuilder.start();
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(child.getInputStream()));
+ try
+ {
+ child.waitFor();
+ String line;
+ do
+ {
+ line = reader.readLine();
+ if (line != null)
+ {
+ LOGGER.log(Level.INFO, line);
+ }
+ }
+ while (line != null);
+ }
+ finally
+ {
+ reader.close();
+ }
+ }
+ catch (InterruptedException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ finally
+ {
+ ess.scheduleSyncDelayedTask(
+ new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ server.dispatchCommand(cs, "save-on");
+ if (server.getOnlinePlayers().length == 0)
+ {
+ stopTask();
+ }
+ active = false;
+ LOGGER.log(Level.INFO, _("backupFinished"));
+ }
+ });
+ }
+ }
+ });
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/ChargeException.java b/Essentials/src/com/earth2me/essentials/ChargeException.java
new file mode 100644
index 0000000000..2fa4c7289a
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/ChargeException.java
@@ -0,0 +1,15 @@
+package com.earth2me.essentials;
+
+
+public class ChargeException extends Exception
+{
+ public ChargeException(final String message)
+ {
+ super(message);
+ }
+
+ public ChargeException(final String message, final Throwable throwable)
+ {
+ super(message, throwable);
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Console.java b/Essentials/src/com/earth2me/essentials/Console.java
new file mode 100644
index 0000000000..d07171c63f
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Console.java
@@ -0,0 +1,38 @@
+package com.earth2me.essentials;
+
+import org.bukkit.Server;
+import org.bukkit.command.CommandSender;
+
+
+public final class Console implements IReplyTo
+{
+ private static Console instance = new Console();
+ private CommandSender replyTo;
+ public final static String NAME = "Console";
+
+ private Console()
+ {
+ }
+
+ public static CommandSender getCommandSender(Server server) throws Exception
+ {
+ return server.getConsoleSender();
+ }
+
+ @Override
+ public void setReplyTo(CommandSender user)
+ {
+ replyTo = user;
+ }
+
+ @Override
+ public CommandSender getReplyTo()
+ {
+ return replyTo;
+ }
+
+ public static Console getConsoleReplyTo()
+ {
+ return instance;
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Enchantments.java b/Essentials/src/com/earth2me/essentials/Enchantments.java
new file mode 100644
index 0000000000..e688355a83
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Enchantments.java
@@ -0,0 +1,166 @@
+package com.earth2me.essentials;
+
+import com.earth2me.essentials.utils.NumberUtil;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.bukkit.enchantments.Enchantment;
+
+
+public class Enchantments
+{
+ private static final Map ENCHANTMENTS = new HashMap();
+ private static final Map ALIASENCHANTMENTS = new HashMap();
+
+ static
+ {
+ ENCHANTMENTS.put("alldamage", Enchantment.DAMAGE_ALL);
+ ALIASENCHANTMENTS.put("alldmg", Enchantment.DAMAGE_ALL);
+ ENCHANTMENTS.put("sharpness", Enchantment.DAMAGE_ALL);
+ ALIASENCHANTMENTS.put("sharp", Enchantment.DAMAGE_ALL);
+ ALIASENCHANTMENTS.put("dal", Enchantment.DAMAGE_ALL);
+
+ ENCHANTMENTS.put("ardmg", Enchantment.DAMAGE_ARTHROPODS);
+ ENCHANTMENTS.put("baneofarthropods", Enchantment.DAMAGE_ARTHROPODS);
+ ALIASENCHANTMENTS.put("baneofarthropod", Enchantment.DAMAGE_ARTHROPODS);
+ ALIASENCHANTMENTS.put("arthropod", Enchantment.DAMAGE_ARTHROPODS);
+ ALIASENCHANTMENTS.put("dar", Enchantment.DAMAGE_ARTHROPODS);
+
+ ENCHANTMENTS.put("undeaddamage", Enchantment.DAMAGE_UNDEAD);
+ ENCHANTMENTS.put("smite", Enchantment.DAMAGE_UNDEAD);
+ ALIASENCHANTMENTS.put("du", Enchantment.DAMAGE_UNDEAD);
+
+ ENCHANTMENTS.put("digspeed", Enchantment.DIG_SPEED);
+ ENCHANTMENTS.put("efficiency", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("minespeed", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("cutspeed", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("ds", Enchantment.DIG_SPEED);
+ ALIASENCHANTMENTS.put("eff", Enchantment.DIG_SPEED);
+
+ ENCHANTMENTS.put("durability", Enchantment.DURABILITY);
+ ALIASENCHANTMENTS.put("dura", Enchantment.DURABILITY);
+ ENCHANTMENTS.put("unbreaking", Enchantment.DURABILITY);
+ ALIASENCHANTMENTS.put("d", Enchantment.DURABILITY);
+
+ ENCHANTMENTS.put("thorns", Enchantment.THORNS);
+ ENCHANTMENTS.put("highcrit", Enchantment.THORNS);
+ ALIASENCHANTMENTS.put("thorn", Enchantment.THORNS);
+ ALIASENCHANTMENTS.put("highercrit", Enchantment.THORNS);
+ ALIASENCHANTMENTS.put("t", Enchantment.THORNS);
+
+ ENCHANTMENTS.put("fireaspect", Enchantment.FIRE_ASPECT);
+ ENCHANTMENTS.put("fire", Enchantment.FIRE_ASPECT);
+ ALIASENCHANTMENTS.put("meleefire", Enchantment.FIRE_ASPECT);
+ ALIASENCHANTMENTS.put("meleeflame", Enchantment.FIRE_ASPECT);
+ ALIASENCHANTMENTS.put("fa", Enchantment.FIRE_ASPECT);
+
+ ENCHANTMENTS.put("knockback", Enchantment.KNOCKBACK);
+ ALIASENCHANTMENTS.put("kback", Enchantment.KNOCKBACK);
+ ALIASENCHANTMENTS.put("kb", Enchantment.KNOCKBACK);
+ ALIASENCHANTMENTS.put("k", Enchantment.KNOCKBACK);
+
+ ALIASENCHANTMENTS.put("blockslootbonus", Enchantment.LOOT_BONUS_BLOCKS);
+ ENCHANTMENTS.put("fortune", Enchantment.LOOT_BONUS_BLOCKS);
+ ALIASENCHANTMENTS.put("fort", Enchantment.LOOT_BONUS_BLOCKS);
+ ALIASENCHANTMENTS.put("lbb", Enchantment.LOOT_BONUS_BLOCKS);
+
+ ALIASENCHANTMENTS.put("mobslootbonus", Enchantment.LOOT_BONUS_MOBS);
+ ENCHANTMENTS.put("mobloot", Enchantment.LOOT_BONUS_MOBS);
+ ENCHANTMENTS.put("looting", Enchantment.LOOT_BONUS_MOBS);
+ ALIASENCHANTMENTS.put("lbm", Enchantment.LOOT_BONUS_MOBS);
+
+ ALIASENCHANTMENTS.put("oxygen", Enchantment.OXYGEN);
+ ENCHANTMENTS.put("respiration", Enchantment.OXYGEN);
+ ALIASENCHANTMENTS.put("breathing", Enchantment.OXYGEN);
+ ENCHANTMENTS.put("breath", Enchantment.OXYGEN);
+ ALIASENCHANTMENTS.put("o", Enchantment.OXYGEN);
+
+ ENCHANTMENTS.put("protection", Enchantment.PROTECTION_ENVIRONMENTAL);
+ ALIASENCHANTMENTS.put("prot", Enchantment.PROTECTION_ENVIRONMENTAL);
+ ENCHANTMENTS.put("protect", Enchantment.PROTECTION_ENVIRONMENTAL);
+ ALIASENCHANTMENTS.put("p", Enchantment.PROTECTION_ENVIRONMENTAL);
+
+ ALIASENCHANTMENTS.put("explosionsprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("explosionprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("expprot", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("blastprotection", Enchantment.PROTECTION_EXPLOSIONS);
+ ENCHANTMENTS.put("blastprotect", Enchantment.PROTECTION_EXPLOSIONS);
+ ALIASENCHANTMENTS.put("pe", Enchantment.PROTECTION_EXPLOSIONS);
+
+ ALIASENCHANTMENTS.put("fallprotection", Enchantment.PROTECTION_FALL);
+ ENCHANTMENTS.put("fallprot", Enchantment.PROTECTION_FALL);
+ ENCHANTMENTS.put("featherfall", Enchantment.PROTECTION_FALL);
+ ALIASENCHANTMENTS.put("featherfalling", Enchantment.PROTECTION_FALL);
+ ALIASENCHANTMENTS.put("pfa", Enchantment.PROTECTION_FALL);
+
+ ALIASENCHANTMENTS.put("fireprotection", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("flameprotection", Enchantment.PROTECTION_FIRE);
+ ENCHANTMENTS.put("fireprotect", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("flameprotect", Enchantment.PROTECTION_FIRE);
+ ENCHANTMENTS.put("fireprot", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("flameprot", Enchantment.PROTECTION_FIRE);
+ ALIASENCHANTMENTS.put("pf", Enchantment.PROTECTION_FIRE);
+
+ ENCHANTMENTS.put("projectileprotection", Enchantment.PROTECTION_PROJECTILE);
+ ENCHANTMENTS.put("projprot", Enchantment.PROTECTION_PROJECTILE);
+ ALIASENCHANTMENTS.put("pp", Enchantment.PROTECTION_PROJECTILE);
+
+ ENCHANTMENTS.put("silktouch", Enchantment.SILK_TOUCH);
+ ALIASENCHANTMENTS.put("softtouch", Enchantment.SILK_TOUCH);
+ ALIASENCHANTMENTS.put("st", Enchantment.SILK_TOUCH);
+
+ ENCHANTMENTS.put("waterworker", Enchantment.WATER_WORKER);
+ ENCHANTMENTS.put("aquaaffinity", Enchantment.WATER_WORKER);
+ ALIASENCHANTMENTS.put("watermine", Enchantment.WATER_WORKER);
+ ALIASENCHANTMENTS.put("ww", Enchantment.WATER_WORKER);
+
+ ALIASENCHANTMENTS.put("firearrow", Enchantment.ARROW_FIRE);
+ ENCHANTMENTS.put("flame", Enchantment.ARROW_FIRE);
+ ENCHANTMENTS.put("flamearrow", Enchantment.ARROW_FIRE);
+ ALIASENCHANTMENTS.put("af", Enchantment.ARROW_FIRE);
+
+ ENCHANTMENTS.put("arrowdamage", Enchantment.ARROW_DAMAGE);
+ ENCHANTMENTS.put("power", Enchantment.ARROW_DAMAGE);
+ ALIASENCHANTMENTS.put("arrowpower", Enchantment.ARROW_DAMAGE);
+ ALIASENCHANTMENTS.put("ad", Enchantment.ARROW_DAMAGE);
+
+ ENCHANTMENTS.put("arrowknockback", Enchantment.ARROW_KNOCKBACK);
+ ALIASENCHANTMENTS.put("arrowkb", Enchantment.ARROW_KNOCKBACK);
+ ENCHANTMENTS.put("punch", Enchantment.ARROW_KNOCKBACK);
+ ALIASENCHANTMENTS.put("arrowpunch", Enchantment.ARROW_KNOCKBACK);
+ ALIASENCHANTMENTS.put("ak", Enchantment.ARROW_KNOCKBACK);
+
+ ALIASENCHANTMENTS.put("infinitearrows", Enchantment.ARROW_INFINITE);
+ ENCHANTMENTS.put("infarrows", Enchantment.ARROW_INFINITE);
+ ENCHANTMENTS.put("infinity", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("infinite", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("unlimited", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("unlimitedarrows", Enchantment.ARROW_INFINITE);
+ ALIASENCHANTMENTS.put("ai", Enchantment.ARROW_INFINITE);
+ }
+
+ public static Enchantment getByName(String name) {
+ Enchantment enchantment;
+ if (NumberUtil.isInt(name)) {
+ enchantment = Enchantment.getById(Integer.parseInt(name));
+ } else {
+ enchantment = Enchantment.getByName(name.toUpperCase(Locale.ENGLISH));
+ }
+ if (enchantment == null)
+ {
+ enchantment = ENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
+ }
+ if (enchantment == null)
+ {
+ enchantment = ALIASENCHANTMENTS.get(name.toLowerCase(Locale.ENGLISH));
+ }
+ return enchantment;
+ }
+
+ public static Set> entrySet()
+ {
+ return ENCHANTMENTS.entrySet();
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/Essentials.java b/Essentials/src/com/earth2me/essentials/Essentials.java
new file mode 100644
index 0000000000..86ba3c48d8
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/Essentials.java
@@ -0,0 +1,878 @@
+/*
+ * Essentials - a bukkit plugin
+ * Copyright (C) 2011 Essentials Team
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.earth2me.essentials;
+
+import net.ess3.api.ISettings;
+import net.ess3.api.IEssentials;
+import static com.earth2me.essentials.I18n._;
+import net.ess3.api.Economy;
+import net.ess3.api.IJails;
+import com.earth2me.essentials.commands.EssentialsCommand;
+import com.earth2me.essentials.commands.IEssentialsCommand;
+import com.earth2me.essentials.commands.NoChargeException;
+import com.earth2me.essentials.commands.NotEnoughArgumentsException;
+import com.earth2me.essentials.metrics.Metrics;
+import com.earth2me.essentials.metrics.MetricsListener;
+import com.earth2me.essentials.metrics.MetricsStarter;
+import com.earth2me.essentials.perm.PermissionsHandler;
+import com.earth2me.essentials.register.payment.Methods;
+import com.earth2me.essentials.signs.SignBlockListener;
+import com.earth2me.essentials.signs.SignEntityListener;
+import com.earth2me.essentials.signs.SignPlayerListener;
+import com.earth2me.essentials.textreader.IText;
+import com.earth2me.essentials.textreader.KeywordReplacer;
+import com.earth2me.essentials.textreader.SimpleTextInput;
+import com.earth2me.essentials.utils.DateUtil;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.ess3.api.IItemDb;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Server;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.command.BlockCommandSender;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.command.SimpleCommandMap;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.command.defaults.VanillaCommand;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.world.WorldLoadEvent;
+import org.bukkit.event.world.WorldUnloadEvent;
+import org.bukkit.plugin.InvalidDescriptionException;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.PluginManager;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.scheduler.BukkitTask;
+import org.yaml.snakeyaml.error.YAMLException;
+
+
+public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials
+{
+ public static final int BUKKIT_VERSION = 2812;
+ private static final Logger LOGGER = Logger.getLogger("Minecraft");
+ private transient ISettings settings;
+ private final transient TNTExplodeListener tntListener = new TNTExplodeListener(this);
+ private transient Jails jails;
+ private transient Warps warps;
+ private transient Worth worth;
+ private transient List confList;
+ private transient Backup backup;
+ private transient ItemDb itemDb;
+ private transient final Methods paymentMethod = new Methods();
+ private transient PermissionsHandler permissionsHandler;
+ private transient AlternativeCommandsHandler alternativeCommandsHandler;
+ private transient UserMap userMap;
+ private transient ExecuteTimer execTimer;
+ private transient I18n i18n;
+ private transient Metrics metrics;
+ private transient EssentialsTimer timer;
+ private transient List vanishedPlayers = new ArrayList();
+ private transient SimpleCommandMap scm;
+
+ @Override
+ public ISettings getSettings()
+ {
+ return settings;
+ }
+
+ public void setupForTesting(final Server server) throws IOException, InvalidDescriptionException
+ {
+ final File dataFolder = File.createTempFile("essentialstest", "");
+ if (!dataFolder.delete())
+ {
+ throw new IOException();
+ }
+ if (!dataFolder.mkdir())
+ {
+ throw new IOException();
+ }
+ i18n = new I18n(this);
+ i18n.onEnable();
+ LOGGER.log(Level.INFO, _("usingTempFolderForTesting"));
+ LOGGER.log(Level.INFO, dataFolder.toString());
+ this.initialize(null, server, new PluginDescriptionFile(new FileReader(new File("src" + File.separator + "plugin.yml"))), dataFolder, null, null);
+ settings = new Settings(this);
+ i18n.updateLocale("en");
+ userMap = new UserMap(this);
+ permissionsHandler = new PermissionsHandler(this, false);
+ Economy.setEss(this);
+ }
+
+ @Override
+ public void onEnable()
+ {
+ try
+ {
+ execTimer = new ExecuteTimer();
+ execTimer.start();
+ i18n = new I18n(this);
+ i18n.onEnable();
+ execTimer.mark("I18n1");
+ scm = new SimpleCommandMap(this.getServer());
+ final PluginManager pm = getServer().getPluginManager();
+ for (Plugin plugin : pm.getPlugins())
+ {
+ if (plugin.getDescription().getName().startsWith("Essentials")
+ && !plugin.getDescription().getVersion().equals(this.getDescription().getVersion())
+ && !plugin.getDescription().getName().equals("EssentialsAntiCheat"))
+ {
+ LOGGER.log(Level.WARNING, _("versionMismatch", plugin.getDescription().getName()));
+ }
+ }
+ final Matcher versionMatch = Pattern.compile("git-Bukkit-(?:(?:[0-9]+)\\.)+[0-9]+-R[\\.0-9]+-(?:[0-9]+-g[0-9a-f]+-)?b([0-9]+)jnks.*").matcher(getServer().getVersion());
+ if (versionMatch.matches())
+ {
+ final int versionNumber = Integer.parseInt(versionMatch.group(1));
+ if (versionNumber < BUKKIT_VERSION && versionNumber > 100)
+ {
+ LOGGER.log(Level.SEVERE, " * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! *");
+ LOGGER.log(Level.SEVERE, _("notRecommendedBukkit"));
+ LOGGER.log(Level.SEVERE, _("requiredBukkit", Integer.toString(BUKKIT_VERSION)));
+ LOGGER.log(Level.SEVERE, " * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! * ! *");
+ this.setEnabled(false);
+ return;
+ }
+ }
+ else
+ {
+ LOGGER.log(Level.INFO, _("bukkitFormatChanged"));
+ LOGGER.log(Level.INFO, getServer().getVersion());
+ LOGGER.log(Level.INFO, getServer().getBukkitVersion());
+ }
+ execTimer.mark("BukkitCheck");
+ try
+ {
+ final EssentialsUpgrade upgrade = new EssentialsUpgrade(this);
+ upgrade.beforeSettings();
+ execTimer.mark("Upgrade");
+ confList = new ArrayList();
+ settings = new Settings(this);
+ confList.add(settings);
+ execTimer.mark("Settings");
+ upgrade.afterSettings();
+ execTimer.mark("Upgrade2");
+ i18n.updateLocale(settings.getLocale());
+ userMap = new UserMap(this);
+ confList.add(userMap);
+ execTimer.mark("Init(Usermap)");
+ warps = new Warps(getServer(), this.getDataFolder());
+ confList.add(warps);
+ execTimer.mark("Init(Spawn/Warp)");
+ worth = new Worth(this.getDataFolder());
+ confList.add(worth);
+ itemDb = new ItemDb(this);
+ confList.add(itemDb);
+ execTimer.mark("Init(Worth/ItemDB)");
+ jails = new Jails(this);
+ confList.add(jails);
+ reload();
+ }
+ catch (YAMLException exception)
+ {
+ if (pm.getPlugin("EssentialsUpdate") != null)
+ {
+ LOGGER.log(Level.SEVERE, _("essentialsHelp2"));
+ }
+ else
+ {
+ LOGGER.log(Level.SEVERE, _("essentialsHelp1"));
+ }
+ handleCrash(exception);
+ return;
+ }
+ backup = new Backup(this);
+ permissionsHandler = new PermissionsHandler(this, settings.useBukkitPermissions());
+ alternativeCommandsHandler = new AlternativeCommandsHandler(this);
+
+ timer = new EssentialsTimer(this);
+ scheduleSyncRepeatingTask(timer, 1000, 50);
+
+ Economy.setEss(this);
+ execTimer.mark("RegHandler");
+
+ final MetricsStarter metricsStarter = new MetricsStarter(this);
+ if (metricsStarter.getStart() != null && metricsStarter.getStart() == true)
+ {
+ runTaskLaterAsynchronously(metricsStarter, 1);
+ }
+ else if (metricsStarter.getStart() != null && metricsStarter.getStart() == false)
+ {
+ final MetricsListener metricsListener = new MetricsListener(this, metricsStarter);
+ pm.registerEvents(metricsListener, this);
+ }
+
+ final String timeroutput = execTimer.end();
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Essentials load " + timeroutput);
+ }
+ }
+ catch (Exception ex)
+ {
+ handleCrash(ex);
+ }
+ catch (Error ex)
+ {
+ handleCrash(ex);
+ throw ex;
+ }
+ }
+
+ @Override
+ public void saveConfig()
+ {
+ // We don't use any of the bukkit config writing, as this breaks our config file formatting.
+ }
+
+ private void registerListeners(PluginManager pm)
+ {
+ HandlerList.unregisterAll(this);
+
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.INFO, "Registering Listeners");
+ }
+
+ final EssentialsPluginListener serverListener = new EssentialsPluginListener(this);
+ pm.registerEvents(serverListener, this);
+ confList.add(serverListener);
+
+ final EssentialsPlayerListener playerListener = new EssentialsPlayerListener(this);
+ pm.registerEvents(playerListener, this);
+
+ final EssentialsBlockListener blockListener = new EssentialsBlockListener(this);
+ pm.registerEvents(blockListener, this);
+
+ final SignBlockListener signBlockListener = new SignBlockListener(this);
+ pm.registerEvents(signBlockListener, this);
+
+ final SignPlayerListener signPlayerListener = new SignPlayerListener(this);
+ pm.registerEvents(signPlayerListener, this);
+
+ final SignEntityListener signEntityListener = new SignEntityListener(this);
+ pm.registerEvents(signEntityListener, this);
+
+ final EssentialsEntityListener entityListener = new EssentialsEntityListener(this);
+ pm.registerEvents(entityListener, this);
+
+ final EssentialsWorldListener worldListener = new EssentialsWorldListener(this);
+ pm.registerEvents(worldListener, this);
+
+ pm.registerEvents(tntListener, this);
+
+ jails.resetListener();
+ }
+
+ @Override
+ public void onDisable()
+ {
+ for (Player p : getServer().getOnlinePlayers())
+ {
+ User user = getUser(p);
+ if (user.isVanished())
+ {
+ user.setVanished(false);
+ user.sendMessage(_("unvanishedReload"));
+ }
+ }
+ cleanupOpenInventories();
+ if (i18n != null)
+ {
+ i18n.onDisable();
+ }
+ if (backup != null)
+ {
+ backup.stopTask();
+ }
+ Economy.setEss(null);
+ Trade.closeLog();
+ }
+
+ @Override
+ public void reload()
+ {
+ Trade.closeLog();
+
+ for (IConf iConf : confList)
+ {
+ iConf.reloadConfig();
+ execTimer.mark("Reload(" + iConf.getClass().getSimpleName() + ")");
+ }
+
+ i18n.updateLocale(settings.getLocale());
+
+ final PluginManager pm = getServer().getPluginManager();
+ registerListeners(pm);
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender,
+ Command command,
+ String commandLabel,
+ String[] args)
+ {
+ // Allow plugins to override the command via onCommand
+ if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName())))
+ {
+ final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
+ if (pc != null)
+ {
+ try
+ {
+ TabCompleter completer = pc.getTabCompleter();
+ if (completer != null)
+ {
+ return completer.onTabComplete(sender, command, commandLabel, args);
+ }
+ }
+ catch (final Exception ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean onCommand(final CommandSender sender, final Command command, final String commandLabel, final String[] args)
+ {
+ return onCommandEssentials(sender, command, commandLabel, args, Essentials.class.getClassLoader(), "com.earth2me.essentials.commands.Command", "essentials.", null);
+ }
+
+ @Override
+ public boolean onCommandEssentials(final CommandSender sender, final Command command, final String commandLabel, final String[] args, final ClassLoader classLoader, final String commandPath, final String permissionPrefix, final IEssentialsModule module)
+ {
+ // Allow plugins to override the command via onCommand
+ if (!getSettings().isCommandOverridden(command.getName()) && (!commandLabel.startsWith("e") || commandLabel.equalsIgnoreCase(command.getName())))
+ {
+ final PluginCommand pc = alternativeCommandsHandler.getAlternative(commandLabel);
+ if (pc != null)
+ {
+ alternativeCommandsHandler.executed(commandLabel, pc);
+ try
+ {
+ return pc.execute(sender, commandLabel, args);
+ }
+ catch (final Exception ex)
+ {
+ Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex);
+ sender.sendMessage(ChatColor.RED + "An internal error occurred while attempting to perform this command");
+ return true;
+ }
+ }
+ }
+
+ try
+ {
+ User user = null;
+ Block bSenderBlock = null;
+ if (sender instanceof Player)
+ {
+ user = getUser(sender);
+ }
+ else if (sender instanceof BlockCommandSender)
+ {
+ BlockCommandSender bsender = (BlockCommandSender)sender;
+ bSenderBlock = bsender.getBlock();
+ }
+
+ if (bSenderBlock != null)
+ {
+ Bukkit.getLogger().log(Level.INFO, "CommandBlock at {0},{1},{2} issued server command: /{3} {4}", new Object[]
+ {
+ bSenderBlock.getX(), bSenderBlock.getY(), bSenderBlock.getZ(), commandLabel, EssentialsCommand.getFinalArg(args, 0)
+ });
+ }
+ else if (user == null)
+ {
+ Bukkit.getLogger().log(Level.INFO, "{0} issued server command: /{1} {2}", new Object[]
+ {
+ sender.getName(), commandLabel, EssentialsCommand.getFinalArg(args, 0)
+ });
+ }
+
+
+ // New mail notification
+ if (user != null && !getSettings().isCommandDisabled("mail") && !command.getName().equals("mail") && user.isAuthorized("essentials.mail"))
+ {
+ final List mail = user.getMails();
+ if (mail != null && !mail.isEmpty())
+ {
+ user.sendMessage(_("youHaveNewMail", mail.size()));
+ }
+ }
+
+ //Print version even if admin command is not available #easteregg
+ if (commandLabel.equalsIgnoreCase("essversion"))
+ {
+ sender.sendMessage("This server is running Essentials " + getDescription().getVersion());
+ return true;
+ }
+
+ // Check for disabled commands
+ if (getSettings().isCommandDisabled(commandLabel))
+ {
+ if (scm != null)
+ {
+ for (VanillaCommand cmd : scm.getFallbackCommands())
+ {
+ if (cmd.matches(commandLabel))
+ {
+ cmd.execute(sender, commandLabel, args);
+ }
+ }
+ }
+ return true;
+ }
+
+ IEssentialsCommand cmd;
+ try
+ {
+ cmd = (IEssentialsCommand)classLoader.loadClass(commandPath + command.getName()).newInstance();
+ cmd.setEssentials(this);
+ cmd.setEssentialsModule(module);
+ }
+ catch (Exception ex)
+ {
+ sender.sendMessage(_("commandNotLoaded", commandLabel));
+ LOGGER.log(Level.SEVERE, _("commandNotLoaded", commandLabel), ex);
+ return true;
+ }
+
+ // Check authorization
+ if (user != null && !user.isAuthorized(cmd, permissionPrefix))
+ {
+ LOGGER.log(Level.INFO, _("deniedAccessCommand", user.getName()));
+ user.sendMessage(_("noAccessCommand"));
+ return true;
+ }
+
+ if (user != null && user.isJailed() && !user.isAuthorized(cmd, "essentials.jail.allow."))
+ {
+ if (user.getJailTimeout() > 0)
+ {
+ user.sendMessage(_("playerJailedFor", user.getName(), DateUtil.formatDateDiff(user.getJailTimeout())));
+ }
+ else
+ {
+ user.sendMessage(_("jailMessage"));
+ }
+ return true;
+ }
+
+ // Run the command
+ try
+ {
+ if (user == null)
+ {
+ cmd.run(getServer(), sender, commandLabel, command, args);
+ }
+ else
+ {
+ cmd.run(getServer(), user, commandLabel, command, args);
+ }
+ return true;
+ }
+ catch (NoChargeException ex)
+ {
+ return true;
+ }
+ catch (NotEnoughArgumentsException ex)
+ {
+ sender.sendMessage(command.getDescription());
+ sender.sendMessage(command.getUsage().replaceAll("", commandLabel));
+ if (!ex.getMessage().isEmpty())
+ {
+ sender.sendMessage(ex.getMessage());
+ }
+ return true;
+ }
+ catch (Throwable ex)
+ {
+ showError(sender, ex, commandLabel);
+ return true;
+ }
+ }
+ catch (Throwable ex)
+ {
+ LOGGER.log(Level.SEVERE, _("commandFailed", commandLabel), ex);
+ return true;
+ }
+ }
+
+ public void cleanupOpenInventories()
+ {
+ for (Player player : getServer().getOnlinePlayers())
+ {
+ User user = getUser(player);
+ if (user.isRecipeSee())
+ {
+ user.getBase().getOpenInventory().getTopInventory().clear();
+ user.getBase().getOpenInventory().close();
+ user.setRecipeSee(false);
+ }
+ if (user.isInvSee() || user.isEnderSee())
+ {
+ user.getBase().getOpenInventory().close();
+ user.setInvSee(false);
+ user.setEnderSee(false);
+ }
+ }
+ }
+
+ @Override
+ public void showError(final CommandSender sender, final Throwable exception, final String commandLabel)
+ {
+ sender.sendMessage(_("errorWithMessage", exception.getMessage()));
+ if (getSettings().isDebug())
+ {
+ LOGGER.log(Level.WARNING, _("errorCallingCommand", commandLabel), exception);
+ }
+ }
+
+ @Override
+ public BukkitScheduler getScheduler()
+ {
+ return this.getServer().getScheduler();
+ }
+
+ @Override
+ public IJails getJails()
+ {
+ return jails;
+ }
+
+ @Override
+ public Warps getWarps()
+ {
+ return warps;
+ }
+
+ @Override
+ public Worth getWorth()
+ {
+ return worth;
+ }
+
+ @Override
+ public Backup getBackup()
+ {
+ return backup;
+ }
+
+ public Metrics getMetrics()
+ {
+ return metrics;
+ }
+
+ public void setMetrics(Metrics metrics)
+ {
+ this.metrics = metrics;
+ }
+
+ @Override
+ public User getUser(final Object base)
+ {
+ if (base instanceof Player)
+ {
+ return getUser((Player)base);
+ }
+ if (base instanceof String)
+ {
+ return getOfflineUser((String)base);
+ }
+ return null;
+ }
+
+ @Override
+ public User getOfflineUser(final String name)
+ {
+ final User user = userMap.getUser(name);
+ if (user != null && user.getBase() instanceof OfflinePlayer)
+ {
+ ((OfflinePlayer)user.getBase()).setName(name);
+ }
+ return user;
+ }
+
+ private User getUser(final T base)
+ {
+ if (base == null)
+ {
+ return null;
+ }
+
+ if (base instanceof User)
+ {
+ return (User)base;
+ }
+
+ if (userMap == null)
+ {
+ LOGGER.log(Level.WARNING, "Essentials userMap not initialized");
+ return null;
+ }
+
+ User user = userMap.getUser(base.getName());
+
+ if (user == null)
+ {
+ user = new User(base, this);
+ }
+ else
+ {
+ user.update(base);
+ }
+ return user;
+ }
+
+ private void handleCrash(Throwable exception)
+ {
+ final PluginManager pm = getServer().getPluginManager();
+ LOGGER.log(Level.SEVERE, exception.toString());
+ pm.registerEvents(new Listener()
+ {
+ @EventHandler(priority = EventPriority.LOW)
+ public void onPlayerJoin(final PlayerJoinEvent event)
+ {
+ event.getPlayer().sendMessage("Essentials failed to load, read the log file.");
+ }
+ }, this);
+ for (Player player : getServer().getOnlinePlayers())
+ {
+ player.sendMessage("Essentials failed to load, read the log file.");
+ }
+ this.setEnabled(false);
+ }
+
+ @Override
+ public World getWorld(final String name)
+ {
+ if (name.matches("[0-9]+"))
+ {
+ final int worldId = Integer.parseInt(name);
+ if (worldId < getServer().getWorlds().size())
+ {
+ return getServer().getWorlds().get(worldId);
+ }
+ }
+ return getServer().getWorld(name);
+ }
+
+ @Override
+ public void addReloadListener(final IConf listener)
+ {
+ confList.add(listener);
+ }
+
+ @Override
+ public Methods getPaymentMethod()
+ {
+ return paymentMethod;
+ }
+
+ @Override
+ public int broadcastMessage(final String message)
+ {
+ return broadcastMessage(null, null, message, true);
+ }
+
+ @Override
+ public int broadcastMessage(final IUser sender, final String message)
+ {
+ return broadcastMessage(sender, null, message, false);
+ }
+
+ @Override
+ public int broadcastMessage(final String permission, final String message)
+ {
+ return broadcastMessage(null, permission, message, false);
+ }
+
+ private int broadcastMessage(final IUser sender, final String permission, final String message, final boolean keywords)
+ {
+ if (sender != null && sender.isHidden())
+ {
+ return 0;
+ }
+
+ IText broadcast = new SimpleTextInput(message);
+
+ final Player[] players = getServer().getOnlinePlayers();
+
+ for (Player player : players)
+ {
+ final User user = getUser(player);
+ if ((permission == null && (sender == null || !user.isIgnoredPlayer(sender)))
+ || (permission != null && user.isAuthorized(permission)))
+ {
+ if (keywords)
+ {
+ broadcast = new KeywordReplacer(broadcast, player, this, false);
+ }
+ for (String messageText : broadcast.getLines())
+ {
+ user.sendMessage(messageText);
+ }
+ }
+ }
+
+ return players.length;
+ }
+
+ @Override
+ public BukkitTask runTaskAsynchronously(final Runnable run)
+ {
+ return this.getScheduler().runTaskAsynchronously(this, run);
+ }
+
+ @Override
+ public BukkitTask runTaskLaterAsynchronously(final Runnable run, final long delay)
+ {
+ return this.getScheduler().runTaskLaterAsynchronously(this, run, delay);
+ }
+
+ @Override
+ public int scheduleSyncDelayedTask(final Runnable run)
+ {
+ return this.getScheduler().scheduleSyncDelayedTask(this, run);
+ }
+
+ @Override
+ public int scheduleSyncDelayedTask(final Runnable run, final long delay)
+ {
+ return this.getScheduler().scheduleSyncDelayedTask(this, run, delay);
+ }
+
+ @Override
+ public int scheduleSyncRepeatingTask(final Runnable run, final long delay, final long period)
+ {
+ return this.getScheduler().scheduleSyncRepeatingTask(this, run, delay, period);
+ }
+
+ @Override
+ public TNTExplodeListener getTNTListener()
+ {
+ return tntListener;
+ }
+
+ @Override
+ public PermissionsHandler getPermissionsHandler()
+ {
+ return permissionsHandler;
+ }
+
+ @Override
+ public AlternativeCommandsHandler getAlternativeCommandsHandler()
+ {
+ return alternativeCommandsHandler;
+ }
+
+ @Override
+ public IItemDb getItemDb()
+ {
+ return itemDb;
+ }
+
+ @Override
+ public UserMap getUserMap()
+ {
+ return userMap;
+ }
+
+ @Override
+ public I18n getI18n()
+ {
+ return i18n;
+ }
+
+ @Override
+ public EssentialsTimer getTimer()
+ {
+ return timer;
+ }
+
+ @Override
+ public List getVanishedPlayers()
+ {
+ return vanishedPlayers;
+ }
+
+
+ private static class EssentialsWorldListener implements Listener, Runnable
+ {
+ private transient final IEssentials ess;
+
+ public EssentialsWorldListener(final IEssentials ess)
+ {
+ this.ess = ess;
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ public void onWorldLoad(final WorldLoadEvent event)
+ {
+ ess.getJails().onReload();
+ ess.getWarps().reloadConfig();
+ for (IConf iConf : ((Essentials)ess).confList)
+ {
+ if (iConf instanceof IEssentialsModule)
+ {
+ iConf.reloadConfig();
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.LOW)
+ public void onWorldUnload(final WorldUnloadEvent event)
+ {
+ ess.getJails().onReload();
+ ess.getWarps().reloadConfig();
+ for (IConf iConf : ((Essentials)ess).confList)
+ {
+ if (iConf instanceof IEssentialsModule)
+ {
+ iConf.reloadConfig();
+ }
+ }
+ }
+
+ @Override
+ public void run()
+ {
+ ess.reload();
+ }
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/EssentialsBlockListener.java b/Essentials/src/com/earth2me/essentials/EssentialsBlockListener.java
new file mode 100644
index 0000000000..890b8e248c
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/EssentialsBlockListener.java
@@ -0,0 +1,71 @@
+package com.earth2me.essentials;
+
+import net.ess3.api.IEssentials;
+import com.earth2me.essentials.utils.LocationUtil;
+import java.util.Locale;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.CreatureSpawner;
+import org.bukkit.entity.EntityType;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.inventory.ItemStack;
+
+
+public class EssentialsBlockListener implements Listener
+{
+ private final transient IEssentials ess;
+
+ public EssentialsBlockListener(final IEssentials ess)
+ {
+ this.ess = ess;
+ }
+
+ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
+ public void onBlockPlace(final BlockPlaceEvent event)
+ {
+ // Do not rely on getItemInHand();
+ // http://leaky.bukkit.org/issues/663
+ final ItemStack is = LocationUtil.convertBlockToItem(event.getBlockPlaced());
+ if (is == null)
+ {
+ return;
+ }
+
+ if (is.getType() == Material.MOB_SPAWNER && event.getItemInHand() != null && event.getPlayer() != null
+ && event.getItemInHand().getType() == Material.MOB_SPAWNER)
+ {
+ final BlockState blockState = event.getBlockPlaced().getState();
+ if (blockState instanceof CreatureSpawner)
+ {
+ final CreatureSpawner spawner = (CreatureSpawner)blockState;
+ final EntityType type = EntityType.fromId(event.getItemInHand().getData().getData());
+ if (type != null && Mob.fromBukkitType(type) != null)
+ {
+ if (ess.getUser(event.getPlayer()).isAuthorized("essentials.spawnerconvert." + Mob.fromBukkitType(type).name().toLowerCase(Locale.ENGLISH)))
+ {
+ spawner.setSpawnedType(type);
+ }
+ }
+ }
+ }
+
+ final User user = ess.getUser(event.getPlayer());
+ if (user.hasUnlimited(is) && user.getGameMode() == GameMode.SURVIVAL)
+ {
+ ess.scheduleSyncDelayedTask(
+ new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ user.getBase().getInventory().addItem(is);
+ user.getBase().updateInventory();
+ }
+ });
+ }
+ }
+}
diff --git a/Essentials/src/com/earth2me/essentials/EssentialsConf.java b/Essentials/src/com/earth2me/essentials/EssentialsConf.java
new file mode 100644
index 0000000000..2827332eb4
--- /dev/null
+++ b/Essentials/src/com/earth2me/essentials/EssentialsConf.java
@@ -0,0 +1,813 @@
+package com.earth2me.essentials;
+
+import static com.earth2me.essentials.I18n._;
+
+import net.ess3.api.InvalidWorldException;
+import com.google.common.io.Files;
+import java.io.*;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bukkit.*;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.InvalidConfigurationException;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.util.Vector;
+
+
+public class EssentialsConf extends YamlConfiguration
+{
+ private static final Logger LOGGER = Logger.getLogger("Minecraft");
+ private final File configFile;
+ private String templateName = null;
+ private Class> resourceClass = EssentialsConf.class;
+ private static final Charset UTF8 = Charset.forName("UTF-8");
+ private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
+ private final AtomicInteger pendingDiskWrites = new AtomicInteger(0);
+
+ public EssentialsConf(final File configFile)
+ {
+ super();
+ this.configFile = configFile.getAbsoluteFile();
+ }
+ private final byte[] bytebuffer = new byte[1024];
+
+ public synchronized void load()
+ {
+ if (pendingDiskWrites.get() != 0)
+ {
+ LOGGER.log(Level.INFO, "File " + configFile + " not read, because it's not yet written to disk.");
+ return;
+ }
+ if (!configFile.getParentFile().exists())
+ {
+ if (!configFile.getParentFile().mkdirs())
+ {
+ LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString()));
+ }
+ }
+ // This will delete files where the first character is 0. In most cases they are broken.
+ if (configFile.exists() && configFile.length() != 0)
+ {
+ try
+ {
+ final InputStream input = new FileInputStream(configFile);
+ try
+ {
+ if (input.read() == 0)
+ {
+ input.close();
+ configFile.delete();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ finally
+ {
+ try
+ {
+ input.close();
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+ catch (FileNotFoundException ex)
+ {
+ LOGGER.log(Level.SEVERE, null, ex);
+ }
+ }
+
+ if (!configFile.exists())
+ {
+ if (templateName != null)
+ {
+ LOGGER.log(Level.INFO, _("creatingConfigFromTemplate", configFile.toString()));
+ createFromTemplate();
+ }
+ else
+ {
+ return;
+ }
+ }
+
+
+ try
+ {
+ final FileInputStream inputStream = new FileInputStream(configFile);
+ try
+ {
+ long startSize = configFile.length();
+ if (startSize > Integer.MAX_VALUE) {
+ throw new InvalidConfigurationException("File too big");
+ }
+ ByteBuffer buffer = ByteBuffer.allocate((int)startSize);
+ int length;
+ while ((length = inputStream.read(bytebuffer)) != -1)
+ {
+ if (length > buffer.remaining()) {
+ ByteBuffer resize = ByteBuffer.allocate(buffer.capacity()+length-buffer.remaining());
+ int resizePosition = buffer.position();
+ buffer.rewind();
+ resize.put(buffer);
+ resize.position(resizePosition);
+ buffer = resize;
+ }
+ buffer.put(bytebuffer, 0, length);
+ }
+ buffer.rewind();
+ final CharBuffer data = CharBuffer.allocate(buffer.capacity());
+ CharsetDecoder decoder = UTF8.newDecoder();
+ CoderResult result = decoder.decode(buffer, data, true);
+ if (result.isError())
+ {
+ buffer.rewind();
+ data.clear();
+ LOGGER.log(Level.INFO, "File " + configFile.getAbsolutePath().toString() + " is not utf-8 encoded, trying " + Charset.defaultCharset().displayName());
+ decoder = Charset.defaultCharset().newDecoder();
+ result = decoder.decode(buffer, data, true);
+ if (result.isError())
+ {
+ throw new InvalidConfigurationException("Invalid Characters in file " + configFile.getAbsolutePath().toString());
+ }
+ else
+ {
+ decoder.flush(data);
+ }
+ }
+ else
+ {
+ decoder.flush(data);
+ }
+ final int end = data.position();
+ data.rewind();
+ super.loadFromString(data.subSequence(0, end).toString());
+ }
+ finally
+ {
+ inputStream.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ catch (InvalidConfigurationException ex)
+ {
+ File broken = new File(configFile.getAbsolutePath() + ".broken." + System.currentTimeMillis());
+ configFile.renameTo(broken);
+ LOGGER.log(Level.SEVERE, "The file " + configFile.toString() + " is broken, it has been renamed to " + broken.toString(), ex.getCause());
+ }
+ }
+
+ private void createFromTemplate()
+ {
+ InputStream istr = null;
+ OutputStream ostr = null;
+ try
+ {
+ istr = resourceClass.getResourceAsStream(templateName);
+ if (istr == null)
+ {
+ LOGGER.log(Level.SEVERE, _("couldNotFindTemplate", templateName));
+ return;
+ }
+ ostr = new FileOutputStream(configFile);
+ byte[] buffer = new byte[1024];
+ int length = 0;
+ length = istr.read(buffer);
+ while (length > 0)
+ {
+ ostr.write(buffer, 0, length);
+ length = istr.read(buffer);
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, _("failedToWriteConfig", configFile.toString()), ex);
+ }
+ finally
+ {
+ try
+ {
+ if (istr != null)
+ {
+ istr.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.getLogger(EssentialsConf.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ try
+ {
+ if (ostr != null)
+ {
+ ostr.close();
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, _("failedToCloseConfig", configFile.toString()), ex);
+ }
+ }
+ }
+
+ public void setTemplateName(final String templateName)
+ {
+ this.templateName = templateName;
+ }
+
+ public File getFile()
+ {
+ return configFile;
+ }
+
+ public void setTemplateName(final String templateName, final Class> resClass)
+ {
+ this.templateName = templateName;
+ this.resourceClass = resClass;
+ }
+
+ public void save()
+ {
+ try
+ {
+ save(configFile);
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+
+ public void saveWithError() throws IOException
+ {
+ save(configFile);
+ }
+
+ @Override
+ public synchronized void save(final File file) throws IOException
+ {
+ delayedSave(file);
+ }
+
+ public synchronized void forceSave()
+ {
+ try
+ {
+ Future> future = delayedSave(configFile);
+ if (future != null)
+ {
+ future.get();
+ }
+ }
+ catch (InterruptedException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ catch (ExecutionException ex)
+ {
+ LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
+ }
+ }
+
+ private Future> delayedSave(final File file)
+ {
+ //long startTime = System.nanoTime();
+ if (file == null)
+ {
+ throw new IllegalArgumentException("File cannot be null");
+ }
+
+ final String data = saveToString();
+
+ if (data.length() == 0)
+ {
+ return null;
+ }
+
+ pendingDiskWrites.incrementAndGet();
+
+ Future> future = EXECUTOR_SERVICE.submit(new WriteRunner(configFile, data, pendingDiskWrites));
+
+ //LOGGER.log(Level.INFO, configFile + " prepared for writing in " + (System.nanoTime() - startTime) + " nsec.");
+
+ return future;
+ }
+
+
+ private static class WriteRunner implements Runnable
+ {
+ private final File configFile;
+ private final String data;
+ private final AtomicInteger pendingDiskWrites;
+
+ private WriteRunner(final File configFile, final String data, final AtomicInteger pendingDiskWrites)
+ {
+ this.configFile = configFile;
+ this.data = data;
+ this.pendingDiskWrites = pendingDiskWrites;
+ }
+
+ @Override
+ public void run()
+ {
+ //long startTime = System.nanoTime();
+ synchronized (configFile)
+ {
+ if (pendingDiskWrites.get() > 1)
+ {
+ // Writes can be skipped, because they are stored in a queue (in the executor).
+ // Only the last is actually written.
+ pendingDiskWrites.decrementAndGet();
+ //LOGGER.log(Level.INFO, configFile + " skipped writing in " + (System.nanoTime() - startTime) + " nsec.");
+ return;
+ }
+ try
+ {
+ Files.createParentDirs(configFile);
+
+ if (!configFile.exists())
+ {
+ try
+ {
+ LOGGER.log(Level.INFO, _("creatingEmptyConfig", configFile.toString()));
+ if (!configFile.createNewFile())
+ {
+ LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString()));
+ return;
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.log(Level.SEVERE, _("failedToCreateConfig", configFile.toString()), ex);
+ return;
+ }
+ }
+
+ final FileOutputStream fos = new FileOutputStream(configFile);
+ try
+ {
+ final OutputStreamWriter writer = new OutputStreamWriter(fos, UTF8);
+
+ try
+ {
+ writer.write(data);
+ }
+ finally
+ {
+ writer.close();
+ }
+ }
+ finally
+ {
+ fos.close();
+ }
+ }
+ catch (IOException e)
+ {
+ LOGGER.log(Level.SEVERE, e.getMessage(), e);
+ }
+ finally
+ {
+ //LOGGER.log(Level.INFO, configFile + " written to disk in " + (System.nanoTime() - startTime) + " nsec.");
+ pendingDiskWrites.decrementAndGet();
+ }
+ }
+ }
+ }
+
+ public boolean hasProperty(final String path)
+ {
+ return isSet(path);
+ }
+
+ public Location getLocation(final String path, final Server server) throws InvalidWorldException
+ {
+ final String worldName = getString((path == null ? "" : path + ".") + "world");
+ if (worldName == null || worldName.isEmpty())
+ {
+ return null;
+ }
+ final World world = server.getWorld(worldName);
+ if (world == null)
+ {
+ throw new InvalidWorldException(worldName);
+ }
+ return new Location(world,
+ getDouble((path == null ? "" : path + ".") + "x", 0),
+ getDouble((path == null ? "" : path + ".") + "y", 0),
+ getDouble((path == null ? "" : path + ".") + "z", 0),
+ (float)getDouble((path == null ? "" : path + ".") + "yaw", 0),
+ (float)getDouble((path == null ? "" : path + ".") + "pitch", 0));
+ }
+
+ public void setProperty(final String path, final Location loc)
+ {
+ set((path == null ? "" : path + ".") + "world", loc.getWorld().getName());
+ set((path == null ? "" : path + ".") + "x", loc.getX());
+ set((path == null ? "" : path + ".") + "y", loc.getY());
+ set((path == null ? "" : path + ".") + "z", loc.getZ());
+ set((path == null ? "" : path + ".") + "yaw", loc.getYaw());
+ set((path == null ? "" : path + ".") + "pitch", loc.getPitch());
+ }
+
+ @Override
+ public ItemStack getItemStack(final String path)
+ {
+ final ItemStack stack = new ItemStack(
+ Material.valueOf(getString(path + ".type", "AIR")),
+ getInt(path + ".amount", 1),
+ (short)getInt(path + ".damage", 0));
+ final ConfigurationSection enchants = getConfigurationSection(path + ".enchant");
+ if (enchants != null)
+ {
+ for (String enchant : enchants.getKeys(false))
+ {
+ final Enchantment enchantment = Enchantment.getByName(enchant.toUpperCase(Locale.ENGLISH));
+ if (enchantment == null)
+ {
+ continue;
+ }
+ final int level = getInt(path + ".enchant." + enchant, enchantment.getStartLevel());
+ stack.addUnsafeEnchantment(enchantment, level);
+ }
+ }
+ return stack;
+ /*
+ * ,
+ * (byte)getInt(path + ".data", 0)
+ */
+ }
+
+ public void setProperty(final String path, final ItemStack stack)
+ {
+ final Map map = new HashMap();
+ map.put("type", stack.getType().toString());
+ map.put("amount", stack.getAmount());
+ map.put("damage", stack.getDurability());
+ Map enchantments = stack.getEnchantments();
+ if (!enchantments.isEmpty())
+ {
+ Map enchant = new HashMap();
+ for (Map.Entry entry : enchantments.entrySet())
+ {
+ enchant.put(entry.getKey().getName().toLowerCase(Locale.ENGLISH), entry.getValue());
+ }
+ map.put("enchant", enchant);
+ }
+ // getData().getData() is broken
+ //map.put("data", stack.getDurability());
+ set(path, map);
+ }
+
+ public void setProperty(String path, List object)
+ {
+ set(path, new ArrayList(object));
+ }
+
+ public void setProperty(String path, Map object)
+ {
+ set(path, new LinkedHashMap(object));
+ }
+
+ public Object getProperty(String path)
+ {
+ return get(path);
+ }
+
+ public void setProperty(final String path, final BigDecimal bigDecimal)
+ {
+ set(path, bigDecimal.toString());
+ }
+
+ public void setProperty(String path, Object object)
+ {
+ set(path, object);
+ }
+
+ public void removeProperty(String path)
+ {
+ set(path, null);
+ }
+
+ @Override
+ public synchronized Object get(String path)
+ {
+ return super.get(path);
+ }
+
+ @Override
+ public synchronized Object get(String path, Object def)
+ {
+ return super.get(path, def);
+ }
+
+
+ public synchronized BigDecimal getBigDecimal(final String path, final BigDecimal def)
+ {
+ final String input = super.getString(path);
+ return toBigDecimal(input, def);
+ }
+
+ public static BigDecimal toBigDecimal(final String input, final BigDecimal def)
+ {
+ if (input == null || input.isEmpty())
+ {
+ return def;
+ }
+ else
+ {
+ try
+ {
+ return new BigDecimal(input, MathContext.DECIMAL128);
+ }
+ catch (NumberFormatException e)
+ {
+ return def;
+ }
+ catch (ArithmeticException e)
+ {
+ return def;
+ }
+ }
+ }
+
+ @Override
+ public synchronized boolean getBoolean(String path)
+ {
+ return super.getBoolean(path);
+ }
+
+ @Override
+ public synchronized boolean getBoolean(String path, boolean def)
+ {
+ return super.getBoolean(path, def);
+ }
+
+ @Override
+ public synchronized List getBooleanList(String path)
+ {
+ return super.getBooleanList(path);
+ }
+
+ @Override
+ public synchronized List getByteList(String path)
+ {
+ return super.getByteList(path);
+ }
+
+ @Override
+ public synchronized List getCharacterList(String path)
+ {
+ return super.getCharacterList(path);
+ }
+
+ @Override
+ public synchronized ConfigurationSection getConfigurationSection(String path)
+ {
+ return super.getConfigurationSection(path);
+ }
+
+ @Override
+ public synchronized double getDouble(String path)
+ {
+ return super.getDouble(path);
+ }
+
+ @Override
+ public synchronized double getDouble(final String path, final double def)
+ {
+ return super.getDouble(path, def);
+ }
+
+ @Override
+ public synchronized List getDoubleList(String path)
+ {
+ return super.getDoubleList(path);
+ }
+
+ @Override
+ public synchronized List getFloatList(String path)
+ {
+ return super.getFloatList(path);
+ }
+
+ @Override
+ public synchronized int getInt(String path)
+ {
+ return super.getInt(path);
+ }
+
+ @Override
+ public synchronized int getInt(String path, int def)
+ {
+ return super.getInt(path, def);
+ }
+
+ @Override
+ public synchronized List getIntegerList(String path)
+ {
+ return super.getIntegerList(path);
+ }
+
+ @Override
+ public synchronized ItemStack getItemStack(String path, ItemStack def)
+ {
+ return super.getItemStack(path, def);
+ }
+
+ @Override
+ public synchronized Set getKeys(boolean deep)
+ {
+ return super.getKeys(deep);
+ }
+
+ @Override
+ public synchronized List> getList(String path)
+ {
+ return super.getList(path);
+ }
+
+ @Override
+ public synchronized List> getList(String path, List> def)
+ {
+ return super.getList(path, def);
+ }
+
+ @Override
+ public synchronized long getLong(String path)
+ {
+ return super.getLong(path);
+ }
+
+ @Override
+ public synchronized long getLong(final String path, final long def)
+ {
+ return super.getLong(path, def);
+ }
+
+ @Override
+ public synchronized List getLongList(String path)
+ {
+ return super.getLongList(path);
+ }
+
+ public synchronized Map getMap()
+ {
+ return map;
+ }
+
+ @Override
+ public synchronized List