Browse Source

Initial Commit

master
Kilobyte22 2 years ago
commit
d03be38868
8 changed files with 1036 additions and 0 deletions
  1. +2
    -0
      .gitignore
  2. +29
    -0
      .idea/codeStyles/Project.xml
  3. +6
    -0
      .idea/vcs.xml
  4. +374
    -0
      Cargo.lock
  5. +13
    -0
      Cargo.toml
  6. +347
    -0
      src/data.rs
  7. +217
    -0
      src/main.rs
  8. +48
    -0
      src/render.rs

+ 2
- 0
.gitignore View File

@ -0,0 +1,2 @@
/target
**/*.rs.bk

+ 29
- 0
.idea/codeStyles/Project.xml View File

@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

+ 6
- 0
.idea/vcs.xml View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

+ 374
- 0
Cargo.lock View File

@ -0,0 +1,374 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mc-server-ping"
version = "0.1.0"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "numtoa"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "termion"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "uuid"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum ryu 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "b96a9549dc8d48f2c283938303c4b5a77aa29bfbc5b54b084fb1630408899a8f"
"checksum serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "32746bf0f26eab52f06af0d0aa1984f641341d06d8d673c693871da2d188c9be"
"checksum serde_derive 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)" = "46a3223d0c9ba936b61c0d2e3e559e3217dbfb8d65d06d26e8b3c25de38bae3e"
"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.36 (registry+https://github.com/rust-lang/crates.io-index)" = "8b4f551a91e2e3848aeef8751d0d4eec9489b6474c720fd4c55958d8d31a430c"
"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 13
- 0
Cargo.toml View File

@ -0,0 +1,13 @@
[package]
name = "mc-server-ping"
version = "0.1.0"
authors = ["Kilobyte22 <stiepen22@gmx.de>"]
edition = "2018"
[dependencies]
byteorder = "1.3.2"
clap = "2.33.0"
serde_json = "1.0.39"
serde = { version = "1.0.92", features = ["derive"] }
uuid = { version = "0.7", features = ["serde", "v4"] }
ansi_term = "0.11.0"

+ 347
- 0
src/data.rs View File

@ -0,0 +1,347 @@
use serde::{Serialize, Deserialize};
use uuid::Uuid;
use std::borrow::Cow;
use std::mem;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VersionInfo {
pub name: String,
pub protocol: u32
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerInfo {
pub max: u32,
pub online: u32,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub sample: Vec<PlayerSampleEntry>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlayerSampleEntry {
pub name: String,
pub id: Uuid
}
#[derive(Debug, Clone, Serialize, Deserialize, Copy)]
pub enum ColorSpec {
#[serde(alias = "black")]
Black,
#[serde(alias = "dark_blue")]
DarkBlue,
#[serde(alias = "dark_green")]
DarkGreen,
#[serde(alias = "dark_aqua")]
DarkAqua,
#[serde(alias = "dark_red")]
DarkRed,
#[serde(alias = "dark_purple")]
DarkPurple,
#[serde(alias = "gold")]
Gold,
#[serde(alias = "gray")]
Gray,
#[serde(alias = "dark_gray")]
DarkGray,
#[serde(alias = "blue")]
Blue,
#[serde(alias = "green")]
Green,
#[serde(alias = "aqua")]
Aqua,
#[serde(alias = "red")]
Red,
#[serde(alias = "light_purple")]
LightPurple,
#[serde(alias = "yellow")]
Yellow,
#[serde(alias = "white")]
White
}
impl ColorSpec {
fn as_legacy_code(&self) -> char {
match &self {
ColorSpec::Black => '0',
ColorSpec::DarkBlue => '1',
ColorSpec::DarkGreen => '2',
ColorSpec::DarkAqua => '3',
ColorSpec::DarkRed => '4',
ColorSpec::DarkPurple => '5',
ColorSpec::Gold => '6',
ColorSpec::Gray => '7',
ColorSpec::DarkGray => '8',
ColorSpec::Blue => '9',
ColorSpec::Green => 'a',
ColorSpec::Aqua => 'b',
ColorSpec::Red => 'c',
ColorSpec::LightPurple => 'd',
ColorSpec::Yellow => 'e',
ColorSpec::White => 'f',
}
}
fn from_legacy(c: char) -> Option<Self> {
match c {
'0' => Some(ColorSpec::Black),
'1' => Some(ColorSpec::DarkBlue),
'2' => Some(ColorSpec::DarkGreen),
'3' => Some(ColorSpec::DarkAqua),
'4' => Some(ColorSpec::DarkRed),
'5' => Some(ColorSpec::DarkPurple),
'6' => Some(ColorSpec::Gold),
'7' => Some(ColorSpec::Gray),
'8' => Some(ColorSpec::DarkGray),
'9' => Some(ColorSpec::Blue),
'a' => Some(ColorSpec::Green),
'b' => Some(ColorSpec::Aqua),
'c' => Some(ColorSpec::Red),
'd' => Some(ColorSpec::LightPurple),
'e' => Some(ColorSpec::Yellow),
'f' => Some(ColorSpec::White),
_ => None
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "action", content = "value")]
pub enum ClickEvent {
#[serde(alias = "open_url")]
OpenURL(String),
#[serde(alias = "open_file")]
OpenFile(String),
#[serde(alias = "run_command")]
RunCommand(String),
#[serde(alias = "twitch_user_info")]
TwitchUserInfo(String),
#[serde(alias = "suggest_command")]
SuggestCommand(String),
#[serde(alias = "change_page")]
ChangePage(u32)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "action", content = "value")]
pub enum HoverEvent {
#[serde(alias = "show_text")]
ShowText(String),
#[serde(alias = "show_item")]
ShowItem(String),
#[serde(alias = "show_entity")]
ShowEntity(String),
#[serde(alias = "show_archivement")]
ShowArchivement(String)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatComponent {
pub text: String,
#[serde(flatten)]
pub format: FormatSpec,
#[serde(skip_serializing_if = "Option::is_none")]
pub insertion: Option<String>,
#[serde(rename = "clickEvent", skip_serializing_if = "Option::is_none")]
pub click_event: Option<ClickEvent>,
#[serde(rename = "hoverEvent", skip_serializing_if = "Option::is_none")]
pub hover_event: Option<HoverEvent>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub extra: Vec<ChatComponent>
}
impl ChatComponent {
fn new(s: String) -> ChatComponent {
ChatComponent::with_format(s, Default::default())
}
fn with_format(text: String, format: FormatSpec) -> ChatComponent {
ChatComponent {
text,
format,
insertion: None,
click_event: None,
hover_event: None,
extra: Vec::new(),
}
}
fn with_siblings(text: String, extra: Vec<ChatComponent>) -> ChatComponent {
ChatComponent {
text,
format: Default::default(),
insertion: None,
click_event: None,
hover_event: None,
extra
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, Copy)]
pub struct FormatSpec {
#[serde(default, skip_serializing_if = "is_false")]
pub bold: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub italic: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub underlined: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub strikethrough: bool,
#[serde(default, skip_serializing_if = "is_false")]
pub obfuscated: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<ColorSpec>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Mod {
pub modid: String,
pub version: String
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ModInfo {
#[serde(rename = "type")]
pub ty: String,
#[serde(rename = "modList")]
pub mod_list: Vec<Mod>
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DescriptionInfo {
Legacy(String),
ChatComponent(ChatComponent)
}
impl DescriptionInfo {
pub fn to_legacy(&self) -> Cow<str> {
match &self {
DescriptionInfo::ChatComponent(c) => {
fn fmt(buf: &mut String, c: char, cond: bool) {
if cond {
buf.push('§');
buf.push(c);
}
}
fn inner(buf: &mut String, c: &ChatComponent) {
let f = c.format;
fmt(buf, 'k', f.obfuscated);
fmt(buf, 'l', f.bold);
fmt(buf, 'm', f.strikethrough);
fmt(buf, 'n', f.underlined);
fmt(buf, 'o', f.italic);
if let Some(col) = f.color {
fmt(buf, col.as_legacy_code(), true);
}
buf.push_str(&c.text);
if f.obfuscated || f.bold || f.strikethrough || f.underlined || f.italic || f.color.is_some() {
fmt(buf, 'r', true);
}
// TODO: Check if parent flags should apply to childs
for sibling in &c.extra {
inner(buf, sibling);
}
}
let mut buf = String::new();
inner(&mut buf, c);
Cow::Owned(buf)
}
DescriptionInfo::Legacy(s) => Cow::Borrowed(s)
}
}
pub fn to_chat_component(&self) -> Cow<ChatComponent> {
match &self {
DescriptionInfo::ChatComponent(c) => Cow::Borrowed(c),
DescriptionInfo::Legacy(s) => {
if s.contains('§') {
let mut siblings = Vec::new();
let mut temp_str = None;
let mut format = FormatSpec::default();
let mut formatting_code = false;
fn append_tmp(s: &mut Option<String>, c: char) {
if s.is_none() {
*s = Some(String::new());
}
match s {
Some(st) => st.push(c),
None => unreachable!()
}
}
fn finish_tmp(s: &mut Option<String>, sib: &mut Vec<ChatComponent>, format: &FormatSpec) {
let mut my_str = None;
mem::swap(&mut my_str, s);
match my_str {
Some(st) => {
sib.push(ChatComponent::with_format(st, format.clone()))
},
None => ()
};
}
for c in s.chars() {
if formatting_code {
formatting_code = false;
match c {
'r' => format = Default::default(),
'0' ... '9' | 'a' ... 'f' => format.color = ColorSpec::from_legacy(c),
'k' => format.obfuscated ^= true,
'l' => format.bold ^= true,
'm' => format.strikethrough ^= true,
'n' => format.underlined ^= true,
'o' => format.italic ^= true,
_ => ()
}
} else {
if c == '§' {
formatting_code = true;
finish_tmp(&mut temp_str, &mut siblings, &format)
} else {
append_tmp(&mut temp_str, c)
}
}
}
Cow::Owned(ChatComponent::with_siblings("".to_owned(), siblings))
} else {
Cow::Owned(ChatComponent::new(s.to_owned()))
}
}
}
}
pub fn is_legacy(&self) -> bool {
match &self {
DescriptionInfo::Legacy(_) => true,
_ => false
}
}
pub fn is_chat_component(&self) -> bool {
match &self {
DescriptionInfo::ChatComponent(_) => true,
_ => false
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerInfo {
pub version: VersionInfo,
pub players: PlayerInfo,
pub description: DescriptionInfo,
#[serde(skip_serializing_if = "Option::is_none")]
pub favicon: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub modinfo: Option<ModInfo>
}
fn is_false(value: &bool) -> bool { !value }

+ 217
- 0
src/main.rs View File

@ -0,0 +1,217 @@
extern crate byteorder;
#[macro_use]
extern crate clap;
extern crate serde_json;
extern crate serde;
extern crate uuid;
extern crate ansi_term;
extern crate core;
mod data;
mod render;
use std::io::{self, Read, Write, Cursor};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::net::TcpStream;
use ansi_term::ANSIStrings;
use ansi_term::Colour;
use core::borrow::Borrow;
fn read_var_int<R: Read>(r: &mut R) -> io::Result<i32> {
let mut num_read = 0;
let mut result = 0;
while {
let read = r.read_u8()?;
let value = (read & 0b0111_1111) as u32;
result |= value << (7 * num_read);
num_read += 1;
if num_read > 5 {
panic!("VarInt too long")
}
read & 0b1000_0000 != 0
} {}
Ok(result as i32)
}
fn write_var_int<W: Write>(w: &mut W, value: i32) -> io::Result<()> {
let mut data = value as u32;
while {
let mut tmp = (data & 0b0111_1111) as u8;
data >>= 7;
if data != 0 {
tmp |= 0b10000000;
}
w.write_u8(tmp)?;
data != 0
} {}
Ok(())
}
fn read_string<R: Read>(r: &mut R) -> io::Result<String> {
let len = read_var_int(r)?;
let mut buf = Vec::with_capacity(len as usize);
buf.resize(len as usize, 0);
r.read_exact(&mut buf)?;
Ok(String::from_utf8(buf).unwrap())
}
fn write_string<W: Write>(w: &mut W, value: &str) -> io::Result<()> {
let buf = value.as_bytes();
write_var_int(w, buf.len() as i32)?;
w.write(buf)?;
Ok(())
}
fn get_args<'a, 'b>() -> clap::App<'a, 'b> {
clap_app!(mc_server_ping =>
(version: "0.1")
(author: "Stephan Henrichs <kilobyte@kilobyte22.de>")
(about: "Does a Server List Ping on a minecraft server")
(@arg nosrv: --nosrv "Do not perform DNS SRV lookup")
(@arg json: -j --json "Output as JSON")
(@arg desc_format: +takes_value --descformat "Convert the Format of the description to either of (chat_component|legacy)")
(@arg hidemods: --hidemods "Hide the list of mods, as it can get quite lengthy")
(@arg SERVER: +required "The server to ping")
)
}
fn main() {
let matches = get_args().get_matches();
let addr = matches.value_of("SERVER").unwrap();
let mut addr_parts = addr.splitn(2, ':');
let host = addr_parts.next().unwrap();
let port = addr_parts.next().unwrap_or("25565").parse().unwrap();
let res = ping_server(host, port);
match res {
Ok(info) => {
if matches.is_present("json") {
let mut data = info.clone();
match matches.value_of("desc_format") {
Some("chat_component") => if data.description.is_legacy() {
data.description = data::DescriptionInfo::ChatComponent(data.description.to_chat_component().into_owned())
},
Some("legacy") => if data.description.is_chat_component() {
data.description = data::DescriptionInfo::Legacy(data.description.to_legacy().into_owned())
},
None => (),
Some(s) => panic!(format!("Invalid value \"{}\" for --desc-format", s))
}
println!("{}", serde_json::to_string(&data).unwrap())
} else {
let chat_component = info.description.to_chat_component();
let motd_data = render::render_component(chat_component.borrow());
let legacy_flag = if info.description.is_legacy() { " (legacy)" } else { "" };
println!("MOTD{}: \n{}", legacy_flag, ANSIStrings(&motd_data));
let pinfo = info.players;
let pratio = pinfo.online as f32 / pinfo.max as f32;
let pdiff = pinfo.max - pinfo.online;
let fg = if pratio > 0.6 || pdiff < 7 {
if pratio > 0.8 || pdiff < 3 {
Colour::Red
} else {
Colour::Yellow
}
} else {
Colour::Green
};
println!(
"Online Players: {}/{}",
fg.paint(format!("{}", pinfo.online)),
Colour::Blue.paint(format!("{}", pinfo.max))
);
for player in pinfo.sample {
println!(" - {} [{}]", Colour::Green.paint(player.name), player.id);
}
print!("Modded: ");
match info.modinfo {
Some(modinfo) => {
print!("{}, {} mods", Colour::Green.paint(modinfo.ty), modinfo.mod_list.len());
if !matches.is_present("hidemods") {
println!();
for m in modinfo.mod_list {
println!(" - {} {}", m.modid, m.version);
}
} else {
println!(" (hidden)");
}
}
None => {
println!("{}", Colour::Red.paint("No"));
}
}
}
},
Err(e) => {
if matches.is_present("json") {
println!("{}", "{error: \"Could not reach server\"}");
} else {
eprintln!("Error: Could not reach server [{:?}]", e);
}
}
}
}
fn write_packet<W: Write, F>(w: &mut W, packet_id: u32, cb: F) -> io::Result<()> where F: FnOnce(&mut Cursor<Vec<u8>>) -> io::Result<()> {
let mut cursor = Cursor::new(Vec::new());
write_var_int(&mut cursor, packet_id as i32)?;
cb(&mut cursor)?;
let buf = cursor.into_inner();
write_var_int(w, buf.len() as i32)?;
w.write(&buf)?;
Ok(())
}
fn read_packet<R: Read, T, F>(r: &mut R, cb: F) -> io::Result<T> where F: FnOnce(i32, &mut Cursor<Vec<u8>>) -> io::Result<T> {
let len = read_var_int(r)?;
let mut buf = Vec::with_capacity(len as usize);
buf.resize(len as usize, 0);
r.read_exact(&mut buf)?;
let mut cur = Cursor::new(buf);
let id = read_var_int(&mut cur)?;
cb(id, &mut cur)
}
fn ping_server(host: &str, port: u16) -> io::Result<data::ServerInfo> {
let addr = (host, port);
let mut sock = TcpStream::connect(addr)?;
// Handshake
write_packet(&mut sock, 0, |packet| {
write_var_int(packet, -1)?;
write_string(packet, host)?;
packet.write_u16::<BigEndian>(port)?;
write_var_int(packet, 1)?;
Ok(())
})?;
write_packet(&mut sock, 0, |_| Ok(()))?;
let data = read_packet(&mut sock, |id, packet| {
assert_eq!(id, 0);
read_string(packet)
})?;
Ok(serde_json::from_str(&data).unwrap())
}

+ 48
- 0
src/render.rs View File

@ -0,0 +1,48 @@
use crate::data::{self, ChatComponent};
use ansi_term::{Style, Colour, ANSIGenericString};
pub fn render_component(c: &ChatComponent) -> Vec<ANSIGenericString<str>> {
let mut style = Style::new();
let f = c.format;
if let Some(color) = &f.color {
style.foreground = Some(to_term_color(color));
}
style.is_bold = f.bold;
style.is_italic = f.italic;
style.is_underline = f.underlined;
style.is_hidden = f.obfuscated;
style.is_strikethrough = f.strikethrough;
let ftext = style.paint(&c.text);
Some(ftext)
.into_iter()
.chain(
c.extra
.iter()
.flat_map(render_component)
)
.collect()
}
fn to_term_color(input: &data::ColorSpec) -> Colour {
match input {
data::ColorSpec::Black => Colour::RGB(0, 0, 0),
data::ColorSpec::DarkBlue => Colour::RGB(0, 0, 170),
data::ColorSpec::DarkGreen => Colour::RGB(0, 170, 0),
data::ColorSpec::DarkAqua => Colour::RGB(0, 170, 170),
data::ColorSpec::DarkRed => Colour::RGB(170, 0, 0),
data::ColorSpec::DarkPurple => Colour::RGB(170, 170, 0),
data::ColorSpec::Gold => Colour::RGB(170, 170, 0),
data::ColorSpec::Gray => Colour::RGB(170, 170, 170),
data::ColorSpec::DarkGray => Colour::RGB(85, 85, 85),
data::ColorSpec::Blue => Colour::RGB(85, 85, 255),
data::ColorSpec::Green => Colour::RGB(85, 255, 85),
data::ColorSpec::Aqua => Colour::RGB(85, 255, 255),
data::ColorSpec::Red => Colour::RGB(255, 85, 85),
data::ColorSpec::LightPurple => Colour::RGB(255, 85, 255),
data::ColorSpec::Yellow => Colour::RGB(255, 255, 85),
data::ColorSpec::White => Colour::RGB(255, 255, 255),
}
}

Loading…
Cancel
Save