diff --git a/.circleci/config.yml b/.circleci/config.yml
new file mode 100644
index 0000000..c9c926e
--- /dev/null
+++ b/.circleci/config.yml
@@ -0,0 +1,27 @@
+version: 2
+
+jobs:
+ build:
+ docker:
+ - image: circleci/openjdk:8-jdk-stretch
+
+ steps:
+ - checkout
+
+ - restore_cache:
+ keys:
+ - v1-dependencies-{{ checksum "pom.xml" }}
+
+ - run:
+ command: |
+ mvn dependency:go-offline
+ mvn clean package
+ mkdir artifact
+ cp target/*.jar artifact
+ - save_cache:
+ paths:
+ - ~/.m2
+ key: v1-dependencies-{{ checksum "pom.xml" }}
+
+ - store_artifacts:
+ path: artifact
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8147bf8
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+*.java text=auto eol=lf
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..643f9f3
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,35 @@
+name: Java CI
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+
+ - name: Cache dependencies
+ uses: actions/cache@v1
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+ - name: Build with Maven
+ run: mvn clean package
+
+ - name: Copy artifacts
+ run: |
+ mkdir artifact
+ cp target/*.jar artifact
+ - name: Archive artifacts
+ uses: actions/upload-artifact@v1
+ with:
+ name: artifacts
+ path: artifact
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5a92ac2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,225 @@
+# Created by https://www.gitignore.io/api/java,maven,eclipse,netbeans,intellij+all
+# Edit at https://www.gitignore.io/?templates=java,maven,eclipse,netbeans,intellij+all
+
+### Eclipse ###
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# CDT- autotools
+.autotools
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+
+# Annotation Processing
+.apt_generated/
+
+# Scala IDE specific (Scala & Java development for Eclipse)
+.cache-main
+.scala_dependencies
+.worksheet
+
+### Eclipse Patch ###
+# Eclipse Core
+.project
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Annotation Processing
+.apt_generated
+
+.sts4-cache/
+
+### Intellij+all ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### Intellij+all Patch ###
+# Ignores the whole .idea folder and all .iml files
+# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
+
+.idea/
+
+# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
+
+*.iml
+modules.xml
+.idea/misc.xml
+*.ipr
+
+# Sonarlint plugin
+.idea/sonarlint
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Maven ###
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+
+### NetBeans ###
+**/nbproject/private/
+**/nbproject/Makefile-*.mk
+**/nbproject/Package-*.bash
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+# End of https://www.gitignore.io/api/java,maven,eclipse,netbeans,intellij+all
+
+# Windows
+desktop.ini
+*/desktop.ini
+Thumbs.db
+*/Thumbs.db
+ehthumbs.db
+*/ehthumbs.db
+
+# Mac
+.DS_Store
+*/.DS_Store
+__MACOSX
+__MACOSX/*
+*/__MACOSX
+*/__MACOSX/*
+
+# Java
+*.MF
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..af9aba3
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: java
+
+jdk:
+ - openjdk8
+
+install:
+ - mvn clean package
+
+cache:
+ directories:
+ - '$HOME/.m2/repository'
diff --git a/README.md b/README.md
index 1fead45..4248118 100644
--- a/README.md
+++ b/README.md
@@ -1,48 +1,76 @@
-# GeoIP
-[![](https://i.loli.net/2019/08/11/g9PU5ufFoqmeKjp.png)](http://www.mcbbs.net/thread-900823-1-1.html "IP定位")
-
-GeoIP plugin for Nukkit.
+# GeoIP for Nukkit
+[![Nukkit](https://img.shields.io/badge/Nukkit-1.0-green)](https://github.com/NukkitX/Nukkit)
+[![Build](https://img.shields.io/circleci/build/github/wode490390/GeoIP/master)](https://circleci.com/gh/wode490390/GeoIP/tree/master)
+[![Release](https://img.shields.io/github/v/release/wode490390/GeoIP)](https://github.com/wode490390/GeoIP/releases)
+[![Release date](https://img.shields.io/github/release-date/wode490390/GeoIP)](https://github.com/wode490390/GeoIP/releases)
+
GeoIP provides an approximate lookup of where your players come from, based on their public IP and public geographical databases.
-Please see [mcbbs](http://www.mcbbs.net/thread-900823-1-1.html) for more information.
-## Permissions
+If you found any bugs or have any suggestions, please open an issue on [GitHub Issues](https://github.com/wode490390/GeoIP/issues).
+
+If you like this plugin, please star it on [GitHub](https://github.com/wode490390/GeoIP).
+
+## Commands
| Command | Permission | Description | Default |
| - | - | - | - |
| `/geoip` | geoip.show | Shows the GeoIP location of a player. | OP |
| `/geoip` | geoip.show.fullip | Shows the full ip address of a player. | false |
| | geoip.hide | Allows player to hide player's country and city from people who have permission geoip.show | false |
-## config.yml
+
+## Configuration
+
+config.yml
+
```yaml
database:
show-cities: false
download-if-missing: true
# Url for country
- download-url: "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz"
+ lzma-download-url: "https://cdn.jsdelivr.net/gh/wodeBot/geoipdb@lzma/country.mmdb.lzma"
# Url for cities
- download-url-city: "https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz"
- update:
- enable: true
- by-every-x-days: 30
+ lzma-download-url-city: "https://cdn.jsdelivr.net/gh/wodeBot/geoipdb@lzma/city.mmdb.lzma"
show-on-login: true
# "enable-locale" enables locale on geolocation display.
enable-locale: true
# Not all languages are supported. See https://dev.maxmind.com/geoip/geoip2/web-services/#Languages
locale: en
```
+
+
+## Download
+- [Releases](https://github.com/wode490390/GeoIP/releases)
+- [Snapshots](https://circleci.com/gh/wode490390/GeoIP)
+
## API Usage
+
+example code
+
```java
-import cn.nukkit.Player;
-import cn.nukkit.Server;
import cn.wode490390.nukkit.geoip.GeoIP;
+import java.util.UUID;
class Example {
Example() {
- Player player = Server.getInstance().getPlayer("wode490390");
- if (player != null) {
- String geoLocation = GeoIP.query(player); //Our API :)
- player.sendMessage("Your location: " + geoLocation);
- }
+ UUID uuid = UUID.fromString("ecb32467-6cee-4a59-b3c0-5468fec58ed4");
+ String geoLocation = GeoIP.query(uuid); //Our API :)
+ System.out.println("Location: " + geoLocation);
}
}
```
+
+
+## Compiling
+1. Install [Maven](https://maven.apache.org/).
+2. Fork and clone the repo.
+3. Run `mvn clean package`. The compiled JAR can be found in the `target/` directory.
+
+## Metrics Collection
+
+This plugin uses [bStats](https://github.com/wode490390/bStats-Nukkit). You can opt out using the global bStats config; see the [official website](https://bstats.org/getting-started) for more details.
+
+
+
+###### If I have any grammar and/or term errors, please correct them :)
diff --git a/pom.xml b/pom.xml
index ccedd43..d8dc85d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,14 +1,18 @@
-
+
4.0.0
+
cn.wode490390.nukkit
geoip
- 1.0.0
+ jar
+ 1.1.0
GeoIP
GeoIP plugin for Nukkit
- 2018
http://wode490390.cn/
- jar
+ 2018
+
GNU General Public License, Version 3.0
@@ -16,17 +20,44 @@
repo
+
+
+ GitHub
+ https://github.com/wode490390/GeoIP/issues
+
+
+
+ CircleCI
+ https://circleci.com/gh/wode490390/GeoIP
+
+
+
+ scm:git:https://github.com/wode490390/GeoIP.git
+ scm:git:git@github.com:wode490390/GeoIP.git
+ https://github.com/wode490390/GeoIP
+
+
+
+
+ github
+ github-releases
+ https://maven.pkg.github.com/wode490390/GeoIP
+
+
+
1.8
1.8
UTF-8
+
- nukkitx
- http://repo.nukkitx.com/main/
+ nukkitx-repo
+ https://repo.nukkitx.com/main/
+
cn.nukkit
@@ -37,14 +68,11 @@
com.maxmind.geoip2
geoip2
- 2.12.0
-
-
- javatar
- javatar
- 2.5
+ 2.14.0
+ compile
+
wodeGeoIP-${project.version}
clean package
@@ -62,7 +90,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.2.1
+ 3.2.4
package
@@ -81,6 +109,51 @@
+
+ pl.project13.maven
+ git-commit-id-plugin
+ 4.0.1
+
+
+ get-the-git-infos
+
+ revision
+
+
+
+
+ ${project.basedir}/.git
+ git
+ yyyy.MM.dd '@' HH:mm:ss z
+ ${user.timezone}
+ true
+ true
+ ${project.build.outputDirectory}/git.properties
+ properties
+ true
+ false
+ false
+ false
+ false
+ true
+
+ git.user.*
+
+
+ false
+ 7
+ flat
+
+ false
+ false
+ 7
+ -dirty
+ *
+ false
+ false
+
+
+
diff --git a/src/main/java/SevenZip/Compression/LZ/OutWindow.java b/src/main/java/SevenZip/Compression/LZ/OutWindow.java
new file mode 100644
index 0000000..2fd2832
--- /dev/null
+++ b/src/main/java/SevenZip/Compression/LZ/OutWindow.java
@@ -0,0 +1,85 @@
+// LZ.OutWindow
+
+package SevenZip.Compression.LZ;
+
+import java.io.IOException;
+
+public class OutWindow
+{
+ byte[] _buffer;
+ int _pos;
+ int _windowSize = 0;
+ int _streamPos;
+ java.io.OutputStream _stream;
+
+ public void Create(int windowSize)
+ {
+ if (_buffer == null || _windowSize != windowSize)
+ _buffer = new byte[windowSize];
+ _windowSize = windowSize;
+ _pos = 0;
+ _streamPos = 0;
+ }
+
+ public void SetStream(java.io.OutputStream stream) throws IOException
+ {
+ ReleaseStream();
+ _stream = stream;
+ }
+
+ public void ReleaseStream() throws IOException
+ {
+ Flush();
+ _stream = null;
+ }
+
+ public void Init(boolean solid)
+ {
+ if (!solid)
+ {
+ _streamPos = 0;
+ _pos = 0;
+ }
+ }
+
+ public void Flush() throws IOException
+ {
+ int size = _pos - _streamPos;
+ if (size == 0)
+ return;
+ _stream.write(_buffer, _streamPos, size);
+ if (_pos >= _windowSize)
+ _pos = 0;
+ _streamPos = _pos;
+ }
+
+ public void CopyBlock(int distance, int len) throws IOException
+ {
+ int pos = _pos - distance - 1;
+ if (pos < 0)
+ pos += _windowSize;
+ for (; len != 0; len--)
+ {
+ if (pos >= _windowSize)
+ pos = 0;
+ _buffer[_pos++] = _buffer[pos++];
+ if (_pos >= _windowSize)
+ Flush();
+ }
+ }
+
+ public void PutByte(byte b) throws IOException
+ {
+ _buffer[_pos++] = b;
+ if (_pos >= _windowSize)
+ Flush();
+ }
+
+ public byte GetByte(int distance)
+ {
+ int pos = _pos - distance - 1;
+ if (pos < 0)
+ pos += _windowSize;
+ return _buffer[pos];
+ }
+}
diff --git a/src/main/java/SevenZip/Compression/LZMA/Base.java b/src/main/java/SevenZip/Compression/LZMA/Base.java
new file mode 100644
index 0000000..b4f2fb5
--- /dev/null
+++ b/src/main/java/SevenZip/Compression/LZMA/Base.java
@@ -0,0 +1,88 @@
+// Base.java
+
+package SevenZip.Compression.LZMA;
+
+public class Base
+{
+ public static final int kNumRepDistances = 4;
+ public static final int kNumStates = 12;
+
+ public static final int StateInit()
+ {
+ return 0;
+ }
+
+ public static final int StateUpdateChar(int index)
+ {
+ if (index < 4)
+ return 0;
+ if (index < 10)
+ return index - 3;
+ return index - 6;
+ }
+
+ public static final int StateUpdateMatch(int index)
+ {
+ return (index < 7 ? 7 : 10);
+ }
+
+ public static final int StateUpdateRep(int index)
+ {
+ return (index < 7 ? 8 : 11);
+ }
+
+ public static final int StateUpdateShortRep(int index)
+ {
+ return (index < 7 ? 9 : 11);
+ }
+
+ public static final boolean StateIsCharState(int index)
+ {
+ return index < 7;
+ }
+
+ public static final int kNumPosSlotBits = 6;
+ public static final int kDicLogSizeMin = 0;
+ // public static final int kDicLogSizeMax = 28;
+ // public static final int kDistTableSizeMax = kDicLogSizeMax * 2;
+
+ public static final int kNumLenToPosStatesBits = 2; // it's for speed optimization
+ public static final int kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
+
+ public static final int kMatchMinLen = 2;
+
+ public static final int GetLenToPosState(int len)
+ {
+ len -= kMatchMinLen;
+ if (len < kNumLenToPosStates)
+ return len;
+ return (int)(kNumLenToPosStates - 1);
+ }
+
+ public static final int kNumAlignBits = 4;
+ public static final int kAlignTableSize = 1 << kNumAlignBits;
+ public static final int kAlignMask = (kAlignTableSize - 1);
+
+ public static final int kStartPosModelIndex = 4;
+ public static final int kEndPosModelIndex = 14;
+ public static final int kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
+
+ public static final int kNumFullDistances = 1 << (kEndPosModelIndex / 2);
+
+ public static final int kNumLitPosStatesBitsEncodingMax = 4;
+ public static final int kNumLitContextBitsMax = 8;
+
+ public static final int kNumPosStatesBitsMax = 4;
+ public static final int kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
+ public static final int kNumPosStatesBitsEncodingMax = 4;
+ public static final int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
+
+ public static final int kNumLowLenBits = 3;
+ public static final int kNumMidLenBits = 3;
+ public static final int kNumHighLenBits = 8;
+ public static final int kNumLowLenSymbols = 1 << kNumLowLenBits;
+ public static final int kNumMidLenSymbols = 1 << kNumMidLenBits;
+ public static final int kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
+ (1 << kNumHighLenBits);
+ public static final int kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
+}
diff --git a/src/main/java/SevenZip/Compression/LZMA/Decoder.java b/src/main/java/SevenZip/Compression/LZMA/Decoder.java
new file mode 100644
index 0000000..16ee249
--- /dev/null
+++ b/src/main/java/SevenZip/Compression/LZMA/Decoder.java
@@ -0,0 +1,329 @@
+package SevenZip.Compression.LZMA;
+
+import SevenZip.Compression.RangeCoder.BitTreeDecoder;
+import SevenZip.Compression.LZMA.Base;
+import SevenZip.Compression.LZ.OutWindow;
+import java.io.IOException;
+
+public class Decoder
+{
+ class LenDecoder
+ {
+ short[] m_Choice = new short[2];
+ BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
+ BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
+ BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
+ int m_NumPosStates = 0;
+
+ public void Create(int numPosStates)
+ {
+ for (; m_NumPosStates < numPosStates; m_NumPosStates++)
+ {
+ m_LowCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumLowLenBits);
+ m_MidCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumMidLenBits);
+ }
+ }
+
+ public void Init()
+ {
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Choice);
+ for (int posState = 0; posState < m_NumPosStates; posState++)
+ {
+ m_LowCoder[posState].Init();
+ m_MidCoder[posState].Init();
+ }
+ m_HighCoder.Init();
+ }
+
+ public int Decode(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, int posState) throws IOException
+ {
+ if (rangeDecoder.DecodeBit(m_Choice, 0) == 0)
+ return m_LowCoder[posState].Decode(rangeDecoder);
+ int symbol = Base.kNumLowLenSymbols;
+ if (rangeDecoder.DecodeBit(m_Choice, 1) == 0)
+ symbol += m_MidCoder[posState].Decode(rangeDecoder);
+ else
+ symbol += Base.kNumMidLenSymbols + m_HighCoder.Decode(rangeDecoder);
+ return symbol;
+ }
+ }
+
+ class LiteralDecoder
+ {
+ class Decoder2
+ {
+ short[] m_Decoders = new short[0x300];
+
+ public void Init()
+ {
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Decoders);
+ }
+
+ public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder) throws IOException
+ {
+ int symbol = 1;
+ do
+ symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);
+ while (symbol < 0x100);
+ return (byte)symbol;
+ }
+
+ public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, byte matchByte) throws IOException
+ {
+ int symbol = 1;
+ do
+ {
+ int matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ int bit = rangeDecoder.DecodeBit(m_Decoders, ((1 + matchBit) << 8) + symbol);
+ symbol = (symbol << 1) | bit;
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ return (byte)symbol;
+ }
+ }
+
+ Decoder2[] m_Coders;
+ int m_NumPrevBits;
+ int m_NumPosBits;
+ int m_PosMask;
+
+ public void Create(int numPosBits, int numPrevBits)
+ {
+ if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
+ return;
+ m_NumPosBits = numPosBits;
+ m_PosMask = (1 << numPosBits) - 1;
+ m_NumPrevBits = numPrevBits;
+ int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
+ m_Coders = new Decoder2[numStates];
+ for (int i = 0; i < numStates; i++)
+ m_Coders[i] = new Decoder2();
+ }
+
+ public void Init()
+ {
+ int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
+ for (int i = 0; i < numStates; i++)
+ m_Coders[i].Init();
+ }
+
+ Decoder2 GetDecoder(int pos, byte prevByte)
+ {
+ return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))];
+ }
+ }
+
+ OutWindow m_OutWindow = new OutWindow();
+ SevenZip.Compression.RangeCoder.Decoder m_RangeDecoder = new SevenZip.Compression.RangeCoder.Decoder();
+
+ short[] m_IsMatchDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
+ short[] m_IsRepDecoders = new short[Base.kNumStates];
+ short[] m_IsRepG0Decoders = new short[Base.kNumStates];
+ short[] m_IsRepG1Decoders = new short[Base.kNumStates];
+ short[] m_IsRepG2Decoders = new short[Base.kNumStates];
+ short[] m_IsRep0LongDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
+
+ BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
+ short[] m_PosDecoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex];
+
+ BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
+
+ LenDecoder m_LenDecoder = new LenDecoder();
+ LenDecoder m_RepLenDecoder = new LenDecoder();
+
+ LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
+
+ int m_DictionarySize = -1;
+ int m_DictionarySizeCheck = -1;
+
+ int m_PosStateMask;
+
+ public Decoder()
+ {
+ for (int i = 0; i < Base.kNumLenToPosStates; i++)
+ m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
+ }
+
+ boolean SetDictionarySize(int dictionarySize)
+ {
+ if (dictionarySize < 0)
+ return false;
+ if (m_DictionarySize != dictionarySize)
+ {
+ m_DictionarySize = dictionarySize;
+ m_DictionarySizeCheck = Math.max(m_DictionarySize, 1);
+ m_OutWindow.Create(Math.max(m_DictionarySizeCheck, (1 << 12)));
+ }
+ return true;
+ }
+
+ boolean SetLcLpPb(int lc, int lp, int pb)
+ {
+ if (lc > Base.kNumLitContextBitsMax || lp > 4 || pb > Base.kNumPosStatesBitsMax)
+ return false;
+ m_LiteralDecoder.Create(lp, lc);
+ int numPosStates = 1 << pb;
+ m_LenDecoder.Create(numPosStates);
+ m_RepLenDecoder.Create(numPosStates);
+ m_PosStateMask = numPosStates - 1;
+ return true;
+ }
+
+ void Init() throws IOException
+ {
+ m_OutWindow.Init(false);
+
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsMatchDecoders);
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRep0LongDecoders);
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepDecoders);
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG0Decoders);
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG1Decoders);
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG2Decoders);
+ SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_PosDecoders);
+
+ m_LiteralDecoder.Init();
+ int i;
+ for (i = 0; i < Base.kNumLenToPosStates; i++)
+ m_PosSlotDecoder[i].Init();
+ m_LenDecoder.Init();
+ m_RepLenDecoder.Init();
+ m_PosAlignDecoder.Init();
+ m_RangeDecoder.Init();
+ }
+
+ public boolean Code(java.io.InputStream inStream, java.io.OutputStream outStream,
+ long outSize) throws IOException
+ {
+ m_RangeDecoder.SetStream(inStream);
+ m_OutWindow.SetStream(outStream);
+ Init();
+
+ int state = Base.StateInit();
+ int rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
+
+ long nowPos64 = 0;
+ byte prevByte = 0;
+ while (outSize < 0 || nowPos64 < outSize)
+ {
+ int posState = (int)nowPos64 & m_PosStateMask;
+ if (m_RangeDecoder.DecodeBit(m_IsMatchDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)
+ {
+ LiteralDecoder.Decoder2 decoder2 = m_LiteralDecoder.GetDecoder((int)nowPos64, prevByte);
+ if (!Base.StateIsCharState(state))
+ prevByte = decoder2.DecodeWithMatchByte(m_RangeDecoder, m_OutWindow.GetByte(rep0));
+ else
+ prevByte = decoder2.DecodeNormal(m_RangeDecoder);
+ m_OutWindow.PutByte(prevByte);
+ state = Base.StateUpdateChar(state);
+ nowPos64++;
+ }
+ else
+ {
+ int len;
+ if (m_RangeDecoder.DecodeBit(m_IsRepDecoders, state) == 1)
+ {
+ len = 0;
+ if (m_RangeDecoder.DecodeBit(m_IsRepG0Decoders, state) == 0)
+ {
+ if (m_RangeDecoder.DecodeBit(m_IsRep0LongDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)
+ {
+ state = Base.StateUpdateShortRep(state);
+ len = 1;
+ }
+ }
+ else
+ {
+ int distance;
+ if (m_RangeDecoder.DecodeBit(m_IsRepG1Decoders, state) == 0)
+ distance = rep1;
+ else
+ {
+ if (m_RangeDecoder.DecodeBit(m_IsRepG2Decoders, state) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ if (len == 0)
+ {
+ len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
+ state = Base.StateUpdateRep(state);
+ }
+ }
+ else
+ {
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
+ state = Base.StateUpdateMatch(state);
+ int posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
+ if (posSlot >= Base.kStartPosModelIndex)
+ {
+ int numDirectBits = (posSlot >> 1) - 1;
+ rep0 = ((2 | (posSlot & 1)) << numDirectBits);
+ if (posSlot < Base.kEndPosModelIndex)
+ rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
+ rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
+ else
+ {
+ rep0 += (m_RangeDecoder.DecodeDirectBits(
+ numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
+ rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
+ if (rep0 < 0)
+ {
+ if (rep0 == -1)
+ break;
+ return false;
+ }
+ }
+ }
+ else
+ rep0 = posSlot;
+ }
+ if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck)
+ {
+ // m_OutWindow.Flush();
+ return false;
+ }
+ m_OutWindow.CopyBlock(rep0, len);
+ nowPos64 += len;
+ prevByte = m_OutWindow.GetByte(0);
+ }
+ }
+ m_OutWindow.Flush();
+ m_OutWindow.ReleaseStream();
+ m_RangeDecoder.ReleaseStream();
+ return true;
+ }
+
+ public boolean SetDecoderProperties(byte[] properties)
+ {
+ if (properties.length < 5)
+ return false;
+ int val = properties[0] & 0xFF;
+ int lc = val % 9;
+ int remainder = val / 9;
+ int lp = remainder % 5;
+ int pb = remainder / 5;
+ int dictionarySize = 0;
+ for (int i = 0; i < 4; i++)
+ dictionarySize += ((int)(properties[1 + i]) & 0xFF) << (i * 8);
+ if (!SetLcLpPb(lc, lp, pb))
+ return false;
+ return SetDictionarySize(dictionarySize);
+ }
+}
diff --git a/src/main/java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java b/src/main/java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
new file mode 100644
index 0000000..7698581
--- /dev/null
+++ b/src/main/java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
@@ -0,0 +1,55 @@
+package SevenZip.Compression.RangeCoder;
+
+public class BitTreeDecoder
+{
+ short[] Models;
+ int NumBitLevels;
+
+ public BitTreeDecoder(int numBitLevels)
+ {
+ NumBitLevels = numBitLevels;
+ Models = new short[1 << numBitLevels];
+ }
+
+ public void Init()
+ {
+ Decoder.InitBitModels(Models);
+ }
+
+ public int Decode(Decoder rangeDecoder) throws java.io.IOException
+ {
+ int m = 1;
+ for (int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--)
+ m = (m << 1) + rangeDecoder.DecodeBit(Models, m);
+ return m - (1 << NumBitLevels);
+ }
+
+ public int ReverseDecode(Decoder rangeDecoder) throws java.io.IOException
+ {
+ int m = 1;
+ int symbol = 0;
+ for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+ {
+ int bit = rangeDecoder.DecodeBit(Models, m);
+ m <<= 1;
+ m += bit;
+ symbol |= (bit << bitIndex);
+ }
+ return symbol;
+ }
+
+ public static int ReverseDecode(short[] Models, int startIndex,
+ Decoder rangeDecoder, int NumBitLevels) throws java.io.IOException
+ {
+ int m = 1;
+ int symbol = 0;
+ for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
+ {
+ int bit = rangeDecoder.DecodeBit(Models, startIndex + m);
+ m <<= 1;
+ m += bit;
+ symbol |= (bit << bitIndex);
+ }
+ return symbol;
+ }
+}
diff --git a/src/main/java/SevenZip/Compression/RangeCoder/Decoder.java b/src/main/java/SevenZip/Compression/RangeCoder/Decoder.java
new file mode 100644
index 0000000..85b3150
--- /dev/null
+++ b/src/main/java/SevenZip/Compression/RangeCoder/Decoder.java
@@ -0,0 +1,88 @@
+package SevenZip.Compression.RangeCoder;
+import java.io.IOException;
+
+public class Decoder
+{
+ static final int kTopMask = ~((1 << 24) - 1);
+
+ static final int kNumBitModelTotalBits = 11;
+ static final int kBitModelTotal = (1 << kNumBitModelTotalBits);
+ static final int kNumMoveBits = 5;
+
+ int Range;
+ int Code;
+
+ java.io.InputStream Stream;
+
+ public final void SetStream(java.io.InputStream stream)
+ {
+ Stream = stream;
+ }
+
+ public final void ReleaseStream()
+ {
+ Stream = null;
+ }
+
+ public final void Init() throws IOException
+ {
+ Code = 0;
+ Range = -1;
+ for (int i = 0; i < 5; i++)
+ Code = (Code << 8) | Stream.read();
+ }
+
+ public final int DecodeDirectBits(int numTotalBits) throws IOException
+ {
+ int result = 0;
+ for (int i = numTotalBits; i != 0; i--)
+ {
+ Range >>>= 1;
+ int t = ((Code - Range) >>> 31);
+ Code -= Range & (t - 1);
+ result = (result << 1) | (1 - t);
+
+ if ((Range & kTopMask) == 0)
+ {
+ Code = (Code << 8) | Stream.read();
+ Range <<= 8;
+ }
+ }
+ return result;
+ }
+
+ public int DecodeBit(short []probs, int index) throws IOException
+ {
+ int prob = probs[index];
+ int newBound = (Range >>> kNumBitModelTotalBits) * prob;
+ if ((Code ^ 0x80000000) < (newBound ^ 0x80000000))
+ {
+ Range = newBound;
+ probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));
+ if ((Range & kTopMask) == 0)
+ {
+ Code = (Code << 8) | Stream.read();
+ Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ Range -= newBound;
+ Code -= newBound;
+ probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));
+ if ((Range & kTopMask) == 0)
+ {
+ Code = (Code << 8) | Stream.read();
+ Range <<= 8;
+ }
+ return 1;
+ }
+ }
+
+ public static void InitBitModels(short []probs)
+ {
+ for (int i = 0; i < probs.length; i++)
+ probs[i] = (kBitModelTotal >>> 1);
+ }
+}
diff --git a/src/main/java/cn/wode490390/nukkit/geoip/GeoIP.java b/src/main/java/cn/wode490390/nukkit/geoip/GeoIP.java
index 301327c..684cd35 100644
--- a/src/main/java/cn/wode490390/nukkit/geoip/GeoIP.java
+++ b/src/main/java/cn/wode490390/nukkit/geoip/GeoIP.java
@@ -3,11 +3,15 @@
import cn.nukkit.Player;
import cn.nukkit.plugin.PluginBase;
import cn.nukkit.utils.Config;
+import cn.wode490390.nukkit.geoip.command.GeoIPCommand;
+import cn.wode490390.nukkit.geoip.util.LZMALib;
+import cn.wode490390.nukkit.geoip.util.MetricsLite;
import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
import com.google.common.collect.Maps;
-import com.ice.tar.TarEntry;
-import com.ice.tar.TarInputStream;
import com.maxmind.geoip2.DatabaseReader;
+
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -19,25 +23,39 @@
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
-import java.util.zip.GZIPInputStream;
+import java.util.UUID;
public class GeoIP extends PluginBase {
- private static final Map cache = Maps.newHashMap();
+ private static final Map cache = Maps.newHashMap();
+
+ /**
+ * Querys player's geographical location.
+ *
+ * @param uuid
+ * @return geographical location or null
+ */
+ public static String query(UUID uuid) {
+ Preconditions.checkNotNull(uuid, "UUID cannot be null");
+ return cache.get(uuid);
+ }
/**
* Querys player's geographical location.
*
- * @param palyer
+ * @param player
* @return geographical location or null
+ *
+ * @see #query(UUID)
*/
- public static String query(Player palyer) {
- Preconditions.checkNotNull(palyer, "Player cannot be null");
- return cache.get(palyer);
+ @Deprecated
+ public static String query(Player player) {
+ Preconditions.checkNotNull(player, "Player cannot be null");
+ return query(player.getUniqueId());
}
- static void setGeoLocation(Player palyer, String location) {
- cache.put(palyer, location);
+ static void setGeoLocation(UUID uuid, String location) {
+ cache.put(uuid, location);
}
Config config;
@@ -46,10 +64,11 @@ static void setGeoLocation(Player palyer, String location) {
@Override
public void onEnable() {
try {
- new MetricsLite(this);
- } catch (Exception ignore) {
+ new MetricsLite(this, 5375);
+ } catch (Throwable ignore) {
}
+
this.saveDefaultConfig();
this.config = this.getConfig();
if (this.config.getBoolean("database.show-cities", false)) {
@@ -94,11 +113,11 @@ private void downloadDatabase() {
try {
String url;
if (this.config.getBoolean("database.show-cities", false)) {
- url = this.config.getString("database.download-url-city");
+ url = this.config.getString("database.lzma-download-url-city", "https://cdn.jsdelivr.net/gh/wodeBot/geoipdb@lzma/city.mmdb.lzma");
} else {
- url = this.config.getString("database.download-url");
+ url = this.config.getString("database.lzma-download-url", "https://cdn.jsdelivr.net/gh/wodeBot/geoipdb@lzma/country.mmdb.lzma");
}
- if (url == null || url.isEmpty()) {
+ if (Strings.isNullOrEmpty(url)) {
this.getLogger().warning("GeoIP download url is empty.");
return;
}
@@ -106,33 +125,12 @@ private void downloadDatabase() {
URL downloadUrl = new URL(url);
URLConnection conn = downloadUrl.openConnection();
conn.setConnectTimeout(10000);
+ conn.setRequestProperty("User-agent", "Mozilla/5.0 (iPad; CPU OS 13_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Mobile/15E148 Safari/604.1");
conn.connect();
- InputStream input = conn.getInputStream();
+ InputStream input = new BufferedInputStream(conn.getInputStream());
OutputStream output = new FileOutputStream(this.databaseFile);
- byte[] buffer = new byte[2048];
- if (url.endsWith(".gz")) {
- input = new GZIPInputStream(input);
- if (url.endsWith(".tar.gz")) {
- // The new GeoIP2 uses tar.gz to pack the db file along with some other txt. So it makes things a bit complicated here.
- String filename;
- TarInputStream tarInputStream = new TarInputStream(input);
- TarEntry entry;
- while ((entry = tarInputStream.getNextEntry()) != null) {
- if (!entry.isDirectory()) {
- filename = entry.getName();
- if (filename.substring(filename.length() - 5).equalsIgnoreCase(".mmdb")) {
- input = tarInputStream;
- break;
- }
- }
- }
- }
- }
- int length = input.read(buffer);
- while (length >= 0) {
- output.write(buffer, 0, length);
- length = input.read(buffer);
- }
+ LZMALib.decode(input, output);
+ output.flush();
output.close();
input.close();
} catch (MalformedURLException ex) {
diff --git a/src/main/java/cn/wode490390/nukkit/geoip/GeoIPListener.java b/src/main/java/cn/wode490390/nukkit/geoip/GeoIPListener.java
index f67cd37..e395a7f 100644
--- a/src/main/java/cn/wode490390/nukkit/geoip/GeoIPListener.java
+++ b/src/main/java/cn/wode490390/nukkit/geoip/GeoIPListener.java
@@ -84,7 +84,7 @@ private void delayedJoin(Player player) throws UnknownHostException {
// GeoIP2 API forced this when address not found in their DB. jar will not complied without this.
this.plugin.getLogger().warning("Failed to read GeoIP database: " + ex.getLocalizedMessage());
}
- GeoIP.setGeoLocation(player, sb.toString());
+ GeoIP.setGeoLocation(player.getUniqueId(), sb.toString());
if (this.plugin.config.getBoolean("show-on-login", true)) {
String template = TextFormat.colorize("&6Player &c" + player.getDisplayName() + " &6comes from &c" + sb.toString() + "&6. (IP:&c%ip%&6)");
String[] ip = player.getAddress().split("\\.");
diff --git a/src/main/java/cn/wode490390/nukkit/geoip/GeoIPCommand.java b/src/main/java/cn/wode490390/nukkit/geoip/command/GeoIPCommand.java
similarity index 93%
rename from src/main/java/cn/wode490390/nukkit/geoip/GeoIPCommand.java
rename to src/main/java/cn/wode490390/nukkit/geoip/command/GeoIPCommand.java
index e00faef..2b12409 100644
--- a/src/main/java/cn/wode490390/nukkit/geoip/GeoIPCommand.java
+++ b/src/main/java/cn/wode490390/nukkit/geoip/command/GeoIPCommand.java
@@ -1,4 +1,4 @@
-package cn.wode490390.nukkit.geoip;
+package cn.wode490390.nukkit.geoip.command;
import cn.nukkit.Player;
import cn.nukkit.Server;
@@ -10,6 +10,7 @@
import cn.nukkit.lang.TranslationContainer;
import cn.nukkit.plugin.Plugin;
import cn.nukkit.utils.TextFormat;
+import cn.wode490390.nukkit.geoip.GeoIP;
public class GeoIPCommand extends Command implements PluginIdentifiableCommand {
@@ -33,7 +34,7 @@ public boolean execute(CommandSender sender, String label, String[] args) {
if (args.length > 0) {
Player player = Server.getInstance().getPlayer(args[0]);
if (player != null) {
- String geoLocation = GeoIP.query(player);
+ String geoLocation = GeoIP.query(player.getUniqueId());
if (geoLocation != null) {
String[] ip = player.getAddress().split("\\.");
try {
diff --git a/src/main/java/cn/wode490390/nukkit/geoip/util/LZMALib.java b/src/main/java/cn/wode490390/nukkit/geoip/util/LZMALib.java
new file mode 100644
index 0000000..b39beb0
--- /dev/null
+++ b/src/main/java/cn/wode490390/nukkit/geoip/util/LZMALib.java
@@ -0,0 +1,37 @@
+package cn.wode490390.nukkit.geoip.util;
+
+import SevenZip.Compression.LZMA.Decoder;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class LZMALib {
+
+ public static void decode(InputStream inputStream, OutputStream outputStream) throws IOException {
+ int propertiesSize = 5;
+ byte[] properties = new byte[propertiesSize];
+ if (inputStream.read(properties, 0, propertiesSize) != propertiesSize) {
+ throw new IOException("input .lzma file is too short");
+ }
+ Decoder decoder = new Decoder();
+ if (!decoder.SetDecoderProperties(properties)) {
+ throw new IOException("Incorrect stream properties");
+ }
+ long outSize = 0;
+ for (int i = 0; i < 8; i++) {
+ int v = inputStream.read();
+ if (v < 0) {
+ throw new IOException("Can't read stream size");
+ }
+ outSize |= ((long) v) << (8 * i);
+ }
+ if (!decoder.Code(inputStream, outputStream, outSize)) {
+ throw new IOException("Error in data stream");
+ }
+ }
+
+ private LZMALib() {
+
+ }
+}
diff --git a/src/main/java/cn/wode490390/nukkit/geoip/MetricsLite.java b/src/main/java/cn/wode490390/nukkit/geoip/util/MetricsLite.java
similarity index 95%
rename from src/main/java/cn/wode490390/nukkit/geoip/MetricsLite.java
rename to src/main/java/cn/wode490390/nukkit/geoip/util/MetricsLite.java
index 56eba67..02ac339 100644
--- a/src/main/java/cn/wode490390/nukkit/geoip/MetricsLite.java
+++ b/src/main/java/cn/wode490390/nukkit/geoip/util/MetricsLite.java
@@ -1,4 +1,4 @@
-package cn.wode490390.nukkit.geoip;
+package cn.wode490390.nukkit.geoip.util;
import cn.nukkit.Server;
import cn.nukkit.plugin.Plugin;
@@ -17,7 +17,6 @@
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
@@ -60,7 +59,7 @@ public class MetricsLite {
private static final String URL = "https://bStats.org/submitData/bukkit";
// Is bStats enabled on this server?
- private boolean enabled;
+ private final boolean enabled;
// Should failed requests be logged?
private static boolean logFailedRequests;
@@ -77,14 +76,20 @@ public class MetricsLite {
// The plugin
private final Plugin plugin;
+ // The plugin id
+ private final int pluginId;
+
/**
* Class constructor.
*
* @param plugin The plugin which stats should be submitted.
+ * @param pluginId The id of the plugin.
+ * It can be found at What is my plugin id?
*/
- public MetricsLite(Plugin plugin) {
+ public MetricsLite(Plugin plugin, int pluginId) {
Preconditions.checkNotNull(plugin);
this.plugin = plugin;
+ this.pluginId = pluginId;
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
@@ -193,6 +198,7 @@ public JsonObject getPluginData() {
String pluginVersion = plugin.getDescription().getVersion();
data.addProperty("pluginName", pluginName); // Append the name of the plugin
+ data.addProperty("id", pluginId); // Append the id of the plugin
data.addProperty("pluginVersion", pluginVersion); // Append the version of the plugin
JsonArray customCharts = new JsonArray();
@@ -258,7 +264,7 @@ private void submitData() {
Field handle = NKServiceManager.class.getDeclaredField("handle");
field.setInt(handle, handle.getModifiers() & ~Modifier.FINAL);
handle.setAccessible(true);
- providers = ((Map, List>>) handle.get((NKServiceManager) (Server.getInstance().getServiceManager()))).get(service);
+ providers = ((Map, List>>) handle.get(Server.getInstance().getServiceManager())).get(service);
} catch(IllegalAccessException | IllegalArgumentException | SecurityException e) {
// Something went wrong! :(
if (logFailedRequests) {
@@ -308,7 +314,7 @@ private static void sendData(Plugin plugin, JsonObject data) throws Exception {
throw new IllegalAccessException("This method must not be called from the main thread!");
}
if (logSentData) {
- plugin.getLogger().info("Sending data to bStats: " + data.toString());
+ plugin.getLogger().info("Sending data to bStats: " + data);
}
HttpsURLConnection connection = (HttpsURLConnection) new URL(URL).openConnection();
@@ -328,20 +334,18 @@ private static void sendData(Plugin plugin, JsonObject data) throws Exception {
connection.setDoOutput(true);
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
outputStream.write(compressedData);
- outputStream.flush();
}
- InputStream inputStream = connection.getInputStream();
- StringBuilder builder;
- try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
- builder = new StringBuilder();
+ StringBuilder builder = new StringBuilder();
+ try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
builder.append(line);
}
}
+
if (logResponseStatusText) {
- plugin.getLogger().info("Sent data to bStats and received response: " + builder.toString());
+ plugin.getLogger().info("Sent data to bStats and received response: " + builder);
}
}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index e08551f..caed4cc 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -2,12 +2,9 @@ database:
show-cities: false
download-if-missing: true
# Url for country
- download-url: "https://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.tar.gz"
+ lzma-download-url: "https://cdn.jsdelivr.net/gh/wodeBot/geoipdb@lzma/country.mmdb.lzma"
# Url for cities
- download-url-city: "https://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz"
- update:
- enable: true
- by-every-x-days: 30
+ lzma-download-url-city: "https://cdn.jsdelivr.net/gh/wodeBot/geoipdb@lzma/city.mmdb.lzma"
show-on-login: true
# "enable-locale" enables locale on geolocation display.
enable-locale: true
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index eb94f84..b018e57 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -6,6 +6,7 @@ website: "http://wode490390.cn/"
version: "${pom.version}"
api: ["1.0.0"]
load: POSTWORLD
+
permissions:
geoip.hide:
description: "Allows player to hide player's country and city from people who have permission geoip.show"