Giter VIP home page Giter VIP logo

dantevg / webstats Goto Github PK

View Code? Open in Web Editor NEW
18.0 2.0 10.0 983 KB

Spigot plugin to display the scoreboard, PlaceholderAPI and other plugin statistics on the web

Home Page: https://dantevg.nl/mods-plugins/WebStats

License: MIT License

Java 69.30% JavaScript 2.21% HTML 2.65% CSS 6.08% TypeScript 19.76%
spigot-plugin placeholderapi-support minecraft-scoreboard minecraft mysql java minecraft-plugin spigot

webstats's Introduction

WebStats

WebStats is a spigot plugin that can gather player statistics from multiple sources and display it on a webpage. It can get data from the scoreboard, from any plugin that stores its data in a database, from PlaceholderAPI and player online/AFK status. It can also be used as a Discord webhook.

View demo page here

a screenshot of our server a while ago

To use WebStats, you need:

  • A Spigot Minecraft server
  • (optional) A web server (note: the plugin will not work over https, so make sure the webpage isn't served over https either)

See the wiki for installation instructions.

Plugin config file

For information about the config file, head over to the wiki page.

Contributing

If you want to help make WebStats more awesome, you can do so by reporting a bug, suggesting a feature or helping with documentation. Anything is welcome!

If you like to write something yourself, pull requests are also very much appreciated. Starting from version 1.8, WebStats uses maven and npm to build, so it should be very easy to work on the code yourself (barring sparse comments).

Contributors

Thank you to these people for helping out with the plugin by suggesting features, reporting bugs and submitting PRs!

webstats's People

Contributors

dantevg avatar olen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

webstats's Issues

MySQL Compatible

Hey, would you ever consider making this MySQL compatible? I love the idea here, but I don't use the Scoreboard and store all my Data in MySQL.

Discord webhook integration

(from draexo at the spigotmc WebStats thread)

Feature

Discord webhook that posts a (non-interactive) embed message with the top 10 (or so) sorted on a specified stat. Auto-update every minute (or so).

Implementation

Probably use inline fields. This has a problem: if there are too many columns or player names are too long, overflowing columns get put on a new row, breaking the visual connection to the player. Alternative is to use code blocks for monospaced manual table display.

image
(image from embed builder)

Resources

General help topic

Since this is my only way to contact you, can you help me with the implementation?
We have our server (purpur) and website (laravel on xampp) running on a laptop but im kinda noob with this stuff.
Is the following code right? https://pastebin.com/tQcApvkK

Placeholders compatibility

hey

Is it possible to add Placeholders compatibility? for example add faction power to the table, or mcmmo level, by adding %placeholder% to a .yml config

Use logger instead of System.err

From console:

Nag author(s): '[RedPolygon]' of 'WebStats' about their usage of System.out/err.print. Please use your plugin's logger instead (JavaPlugin#getLogger).

Mark vanished players as offline

Can use EssentialsX API to detect whether a player is vanished.

Thanks to Just4Fun on the Spigotmc forums for the suggestion!

index.html from internal web server only works on localhost

URL: http://lcorpnet.ddns.net:8094/

Keeping this up so it can be checked to see the result

Config: https://pastebin.com/ckET1DVj

Mostly just added a bunch of placeholders for testing

Doesn't seem to initialize the table. works on a localhost test server fine. when running from a hosted server (Pebblehost) I get a similar result to this but no error in console? Stats.json IS propagated from checking.
#16

Paper: 1.18.2

I'd be happy to offer other info if needed

Store offline player placeholders in text file

Feature

The ability to store the placeholders for offline players in a plain text file instead of requiring a database

Implementation

  • Storing in yaml file, similar to current player highlight ip-to-names.yml (#19), or
  • Storing in csv file, similar to Dantevg/WebStatsStorer. May be more efficient storage-wise, but may be harder to write and read

Config option boolean store-placeholders-in-file, mutually exclusive to store-placeholders-database.
Otherwise, maybe change config to:

  • store-placeholders
    • method (database or file)
    • database-name

Use TypeScript

Using TypeScript could catch some errors earlier, but it might not be useful

Thread stops responding but is alive

Problem

Sometimes randomly the web frontend stops working and stopping the server hangs on "Disabling WebStats". Score gathering still works (WebStatsStorer still saved new stats)

Output of /webstats debug command:

WebStats 1.6.1
Active sources: scoreboard
Thread status: alive
Socket status: open

Possible cause

Something in ServerSocket or HTTPConnection hangs

Possible solution

Look from here where something can hang indefinitely:

HTTPConnection.start(serverSocket.accept());

Additional solution: don't wait indefinitely on thread join here: (timeout of a couple seconds should be good)

Also maybe use Thread::getState in debug output

Resources

Crash when placeholder plugin is disabled before WebStats

(from Unkn0wn3636 at the spigotmc WebStats thread)

Problem

Minecraft version: 1.18.2

Stack trace:

[11:32:01 ERROR]: Error occurred while disabling WebStats v1.6.1 (Is it up to date?)
java.lang.IllegalStateException: zip file closed
at java.util.zip.ZipFile.ensureOpen(ZipFile.java:831) ~[?:?]
at java.util.zip.ZipFile.getEntry(ZipFile.java:330) ~[?:?]
at java.util.jar.JarFile.getEntry(JarFile.java:518) ~[?:?]
at java.util.jar.JarFile.getJarEntry(JarFile.java:473) ~[?:?]
at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:163) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:587) ~[?:?]
at org.bukkit.plugin.java.PluginClassLoader.loadClass0(PluginClassLoader.java:108) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.PluginClassLoader.loadClass(PluginClassLoader.java:103) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[?:?]
at me.vagdedes.ultimatestatistics.b.b.b.onRequest(PlaceHolder.java:46) ~[UltimateStatistics.jar:?]
at me.clip.placeholderapi.replacer.CharsReplacer.apply(CharsReplacer.java:161) ~[PlaceholderAPI-2.11.1.jar:?]
at me.clip.placeholderapi.PlaceholderAPI.setPlaceholders(PlaceholderAPI.java:70) ~[PlaceholderAPI-2.11.1.jar:?]
at nl.dantevg.webstats.placeholder.PlaceholderSource.lambda$getScoresForPlayer$1(PlaceholderSource.java:93) ~[WebStats-1.7.0-pre1.jar:?]
at java.util.LinkedHashMap.forEach(LinkedHashMap.java:721) ~[?:?]
at nl.dantevg.webstats.placeholder.PlaceholderSource.getScoresForPlayer(PlaceholderSource.java:92) ~[WebStats-1.7.0-pre1.jar:?]
at nl.dantevg.webstats.placeholder.PlaceholderStorage.save(PlaceholderStorage.java:121) ~[WebStats-1.7.0-pre1.jar:?]
at nl.dantevg.webstats.placeholder.PlaceholderStorage.saveAll(PlaceholderStorage.java:154) ~[WebStats-1.7.0-pre1.jar:?]
at nl.dantevg.webstats.placeholder.PlaceholderStorage.disconnect(PlaceholderStorage.java:59) ~[WebStats-1.7.0-pre1.jar:?]
at nl.dantevg.webstats.placeholder.PlaceholderSource.disable(PlaceholderSource.java:105) ~[WebStats-1.7.0-pre1.jar:?]
at nl.dantevg.webstats.WebStats.onDisable(WebStats.java:99) ~[WebStats-1.7.0-pre1.jar:?]
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:266) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin(JavaPluginLoader.java:399) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.disablePlugin(SimplePluginManager.java:538) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at org.bukkit.plugin.SimplePluginManager.disablePlugins(SimplePluginManager.java:515) ~[paper-api-1.18.2-R0.1-SNAPSHOT.jar:?]
at org.bukkit.craftbukkit.v1_18_R2.CraftServer.disablePlugins(CraftServer.java:493) ~[paper-1.18.2.jar:git-Paper-235]
at net.minecraft.server.MinecraftServer.stopServer(MinecraftServer.java:973) ~[paper-1.18.2.jar:git-Paper-235]
at net.minecraft.server.dedicated.DedicatedServer.stopServer(DedicatedServer.java:803) ~[paper-1.18.2.jar:git-Paper-235]
at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1272) ~[paper-1.18.2.jar:git-Paper-235]
at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:317) ~[paper-1.18.2.jar:git-Paper-235]
at java.lang.Thread.run(Thread.java:833) ~[?:?]

Resources

Possible fixes

There's nothing on the page except: Compact Hide offline players Prev Next

This server is running Purpur version git-Purpur-1449 (MC: 1.18.1) (Implementing API version 1.18.1-R0.1-SNAPSHOT) (Git: 91e3be5 on HEAD)

There's nothing on the page except:
Compact Hide offline players Prev Next

An error appears in the console:
[20:18:56 WARN]: Exception in thread "WebStats" java.lang.IllegalStateException: @NotNull method nl/dantevg/webstats/placeholder/PlaceholderStorer.getScore must not return null
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.placeholder.PlaceholderStorer.$$$reportNull$$$0(PlaceholderStorer.java)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.placeholder.PlaceholderStorer.getScore(PlaceholderStorer.java:158)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.placeholder.PlaceholderSource.lambda$getScores$0(PlaceholderSource.java:64)
[20:18:56 WARN]: at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.placeholder.PlaceholderSource.getScores(PlaceholderSource.java:56)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.placeholder.PlaceholderSource.getStats(PlaceholderSource.java:90)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.Stats.getStats(Stats.java:23)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.Stats.getAll(Stats.java:34)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.HTTPConnection.route(HTTPConnection.java:50)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.HTTPConnection.start(HTTPConnection.java:25)
[20:18:56 WARN]: at WebStats-1.6.0.jar//nl.dantevg.webstats.WebStats.run(WebStats.java:115)
[20:18:56 WARN]: at java.base/java.lang.Thread.run(Thread.java:833)

The plugin gets the information and writes it to SQL

webstats debug
[20:24:11 INFO]: WebStats 1.6.0
Active sources: scoreboard, PlaceholderAPI
Thread status: dead
Socket status: open
Placeholder storer database connection: connected
Loaded placeholders:
81ada1cc-0334-4d7d-8806-0e8e78cc2a7f (Fandorin): balance = 823.3333333333333
81ada1cc-0334-4d7d-8806-0e8e78cc2a7f (Fandorin): displayed name = Fandorin
81ada1cc-0334-4d7d-8806-0e8e78cc2a7f (Fandorin): uuid = 81ada1cc-0334-4d7d-8806-0e8e78cc2a7f

Config:

port: 8989
columns: [uuid, balance]
objectives:

  • '*'
    database:
    hostname: localhost:3306
    username: MineFS_WebStat
    password: xxxxxxx
    placeholders:
    '%cmi_user_name%': displayed name
    '%cmi_user_uuid%': uuid
    '%cmi_user_balance%': balance
    store-placeholders-database: MineFS_WebStat

Custom column ordering

Specify a custom order for the columns, in config.yml:

columns: [player, money, deaths]

For columns not in this list, either:

  • don't display
  • display in alphabetical order after all columns that are specified

(came from #5 (comment))

Column ordering does not seem to work

It could just be me, but I can't get the column-ordering to work.

I have changed config.yml and added:

tables:
    #columns: []
    columns: ['Level', 'XP', 'Total Kills', 'Death Count']

These are the display names, but I have also tried the objective name (if I understand this correctly). E.g:

> scoreboard objectives add deathCount deathCount "Death Count"

And then use deathCount in the config:

    columns: ['level', 'XP', 'totalKills', 'deathCount']

But it always displays them in alphabetical order:

image

Another little issue there is that it would be nice if empty columns could show up. It was very confusing when I started setting up this plugin that I did not see anything.

index.html not being generated?

the 'web' folder is empty for me. getting 'No connection to server. Maybe the server is offline, or the 'host' setting in index.html is incorrect.'

Placeholder database table does not remove unused placeholders

Problem

When changing the config and removing placeholders, the placeholder storage table still contains entries for these placeholders.

Possible solution

When storing all placeholders into the database, remove any rows that have a placeholder name that is not known.

Use source map

A source map is already generated, but the plugin does not serve it. Letting the plugin serve the source map allows for better debugging and minimisation of WebStats-dist.js

In-cell bar graph

Add a "bar graph" to each cell: a horizontal filled bar behind each cell, scaled by the relative score of that player for that objective. This will make it easier to compare scores at a glance, rather than having to read the numbers: 6,241 does not look a lot more than 2,243 at first, yet it is.

Store placeholders for offline players

Since some PlaceholderAPI plugins do not return placeholder data for offline players, store the data for them when they are online so we can use that stored data when they're offline.

  • Storage method: database
  • When server starts: load all data (to reduce IO)
  • When player leaves: save their data
  • When server closes: save all data

(came from #5 (comment))

Webpage accessibility

Make the webpage more accessible:

  • Add alt text to images
  • Add tabindex=0 to table column headings
  • Add onkeydown event where using only onclick now
  • ...

Folia support

Folia is a new fork of Paper centred around multithreading, and it seems to still be at an experimental stage right now. Once plugins that WebStats depends on support it, WebStats should also have support for Folia.

However, support for Folia should not come at the expense of support for Paper, as I expect the grand majority of servers will stay running Paper.

Thanks to radeon on Discord for the suggestion!

Stats sources support

  • Scoreboard: ❌ not supported

    ALL scoreboard API is considered broken (this is global state that I've not figured out how to properly implement yet)

  • Database: ✔️ probably fine
  • PlaceholderAPI: ⏳ in-progress branch

Resources

To do

  • Add folia-supported: true to plugin.yml
  • Change scheduler to use one of the Folia schedulers
  • Wait for either PlaceholderAPI or the scoreboard API to start working
  • ???

Standalone usage

Feature

Add option to serve the webpage from the plugin (like dynmap), so no external web server is required. Meant for people that do not have a web server set up.

Implementation

  • Add config option, something like enable-internal-webserver
  • Maybe integrate CSS and JS into a single HTML file so no extra http requests are needed

Highlight "you"

Feature

Like Dynmap can show player names for messages sent from the browser, WebStats should be able to highlight the row for your player.

Implementation

Probably by storing players' IPs when they are online and matching that against the request IP.

Reload command

Command to reload config without needing to restart the entire server and without using the server's unsupported /reload command

Setting up the .html and config help

Hi, I am trying to understand how to setup this exactly,

The help to setup isnt easy for me to understand (Prolly just me), but I cant seem to understand how to add in multiple columns and link them to their correct placeholder/scoreboard objective.

And as for a webpage, I do not quite understand how to set it up correctly :/

Is there an example of any of these that can help me understand it all better?

Multiple tables

(from Unkn0wn3636 at the spigotmc WebStats thread)

Feature

Add possibility to display multiple tables with different scores, on different pages.

Implementation

  • Config item tables: list or named list, each item of this list is a list of columns. Mutually exclusive with columns of course.
  • Probably specify which table/page with query string stats.json?page=1 or stats.json?page=pagename

Top Player

It would be nice if it's able to show top players (for example, top 100) in a selected stat.
Perhaps they can be placed in multiple sheets.

Btw, https can be achieved by reverse proxy.

Display error messages

Instead of just showing nothing when something goes wrong, show an error message in place of the table. Also add a message "Loading..." before any data is loaded.

Handle Discord rate limit

Problem

WebStats does not adjust to rate limiting at all. This results in getting a HTTP 429 response from Discord with this body:

{"code": 0, "message": "You are being blocked from accessing our API temporarily due to exceeding our rate limits frequently. Please read our docs at https://discord.com/developers/docs/topics/rate-limits to prevent this moving forward."}

Resources

Possible solution

TODO

Zero-values gives errors or empty cells

Just creating this as a separate issue to keep track.

If all stats for a user is 0, the stats table does not load at all, and errors out with a "Cannot read property of undefined" or something similar (the error disppeared as soon as one of the scoreboard-values was updated to 1, so I don't have the exact error message in frnt of me anymore).

If just some values are 0, the table looks a bit strange as 0-values are not shown:

image

Dont show the player

i have the plugin but when im connecting to my server my webstats dont work.

screen :
image

Separate "server" entry

(from Unkn0wn3636 at the spigotmc WebStats thread)

Feature

For non-player-specific placeholders, display them on a separate row for the server itself, instead of displaying them for every player.

Implementation

Maybe add a separate global-placeholders config entry. All placeholders specified there will not be displayed on individual players' rows but on the server's own row.

Column number units

Some values have large numbers and it can be hard to see what they mean. The option to specify per column what the unit of the values is would solve this. Possible units / categories:

  • time: milliseconds, ticks(?), seconds, minutes, hours (e.g. 12:34:56.789)
  • item count: stacks, items (note: can be confusing for 16-stackables) (e.g. 1st 23)
  • distance: meters/blocks, kilometres (e.g. 123m, 12.34km)
  • date: formatted, timestamp (regional formatting or ISO)
  • ... more?

Example config: (minutes, ticks, items, timestamp are taken as the source units, WebStats will choose best units to display)

column-units:
  Play Minutes: minutes
  Aviate: ticks
  Mine Diamond: items
  Last Seen: timestamp

Possible extra function: show original value on hover ("tooltip")

Sorting direction indicator

Add an arrow in the currently sorted column, indicating the sorting direction (ascending/descending).

The arrow can probably be an inline svg triangle.

Database help

can i convert offline uuid from uuid column to nickname in MYCUSTOMTABLE table? I configured it like this but nothing worked

database:
hostname: localhost
username: DATABASE USERNAME
password: DATABASE PASSWORD
config:
- database: DATABASE NAME
table: MYCUSTOMTABLE
convert: # Some examples, refer to documentation for explanations
- [uuid, column]

image

HTTPS support

Support serving the stats over https natively, somehow. Without relying on manual configuration.

For the internal web server, this is not needed because everything is unencrypted. For an external web server this is also not needed because you can set up a reverse proxy. Native HTTPS support is only needed for external websites created with services like Wix, Squarespace or Weebly, where you cannot set up a reverse proxy.

It is possible (and easy) to generate a self-signed certificate and use that. But, browsers will give you a big fat warning.
So, we need to somehow get a validated certificate from something like letsencrypt. The problem is that they use DV (domain validation), which seems to not be available for IPs, only domains.

Challenge types: https://letsencrypt.org/docs/challenge-types/

The HTTP-01 and TLS-ALPN-01 challenge types use port 80 or 443 to verify the certificate, which you do not have access to unless you self-host.

DNS-01 challenge

We can use the DNS-01 challenge in manual mode. Downside: need to manually renew the certificate every few months.
How to get a letsencrypt certificate with DNS validation: [IN PROGRESS]
https://eff-certbot.readthedocs.io/en/stable/using.html#manual

sudo certbot certonly --manual --preferred-challenges dns

sudo openssl pkcs12 -export -out webstats.p12 -in /etc/letsencrypt/live/tlstest.equinoxmc.nl/fullchain.pem -inkey /etc/letsencrypt/live/tlstest.equinoxmc.nl/privkey.pem -name webstats

sudo keytool -importkeystore -srckeystore webstats.p12 -srcstoretype pkcs12 -srcalias webstats -destke
ystore webstats.jks -deststoretype jks -deststorepass webstats -destalias webstats

DNS-01 with DuckDNS

DuckDNS is a free DNS provider with an API to change A and TXT records. This means you can use a DuckDNS subdomain as the domain for the WebStats plugin on your server.

DNS TXT record URL format: (https://www.duckdns.org/spec.jsp)

https://www.duckdns.org/update?domains=<SUBDOMAIN>.duckdns.org&token=<DUCKDNS_TOKEN>&txt=<DNS_CHALLENGE>

Java ACME challenge library

To automatically renew the certificate, the plugin needs to use a Java library. Acme4J is listed in the letsencrypt list of Java libraries. [IN PROGRESS]

ZeroSSL

ZeroSSL seems to be an alternative to letsencrypt that does support TLS certificates for IP addresses: https://zerossl.com/documentation/api/create-certificate/. This still does not work because we would need to get a certificate for only the WebStats port.

Resources

Sorting Refresh?

When I apply any filter in the latest build it for some reason like resets the filter and goes back to the default view after just a few moments. I assumed it was the update interval causing it but even after disabling auto updates it still seems to remove the filters on me.

I am using the default web page you made with the default index/styles.

Example below.

s1stats.mineroyalemc.com

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.