forked from elliot/TimingsBot
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
20 KiB
366 lines
20 KiB
import discord
|
|
from discord.ext import commands
|
|
import requests
|
|
import yaml
|
|
|
|
TIMINGS_CHECK = None
|
|
YAML_ERROR = None
|
|
with open("cogs/timings_check.yml", 'r') as stream:
|
|
try:
|
|
TIMINGS_CHECK = yaml.safe_load(stream)
|
|
except yaml.YAMLError as exc:
|
|
print(exc)
|
|
YAML_ERROR = exc
|
|
|
|
class Timings(commands.Cog):
|
|
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
self.TIMINGS_TITLE = "Timings Analysis"
|
|
self.TIMINGS_TITLE_COLOR = 0x55ffff
|
|
|
|
# Use @commands.Cog.listener() instead of event and use @commands.command() for commands
|
|
|
|
async def analyze_timings(self, message):
|
|
words = message.content.replace("\n", " ").split(" ")
|
|
timings_url = ""
|
|
embed_var = discord.Embed(title=self.TIMINGS_TITLE, color=self.TIMINGS_TITLE_COLOR)
|
|
|
|
for word in words:
|
|
if word.startswith("https://timings.") and "/?id=" in word:
|
|
timings_url = word
|
|
break
|
|
if word.startswith("https://www.spigotmc.org/go/timings?url=") or word.startswith(
|
|
"https://timings.spigotmc.org/?url="):
|
|
embed_var.add_field(name="❌ Spigot",
|
|
value="Upgrade to [Purpur](https://purpur.pl3x.net/downloads/#1.16.4).")
|
|
embed_var.set_footer(text="Requested by " + message.author.name, icon_url=message.author.avatar_url)
|
|
embed_var.url = timings_url
|
|
await message.reply(embed=embed_var)
|
|
return
|
|
|
|
if timings_url == "":
|
|
return
|
|
if "#" in timings_url:
|
|
timings_url = timings_url.split("#")[0]
|
|
if "?id=" not in timings_url:
|
|
return
|
|
|
|
timings_host, timings_id = timings_url.split("?id=")
|
|
timings_json = timings_host + "data.php?id=" + timings_id
|
|
|
|
r = requests.get(timings_json).json()
|
|
if r is None:
|
|
embed_var.add_field(name="❌ Invalid report",
|
|
value="Create a new timings report.")
|
|
embed_var.set_footer(text="Requested by " + message.author.name, icon_url=message.author.avatar_url)
|
|
embed_var.url = timings_url
|
|
await message.reply(embed=embed_var)
|
|
return
|
|
|
|
embed_var.set_footer(text="Requested by " + message.author.name, icon_url=message.author.avatar_url)
|
|
embed_var.url = timings_url
|
|
unchecked = 0
|
|
try:
|
|
try:
|
|
version = r["timingsMaster"]["version"].lower()
|
|
if "version" in TIMINGS_CHECK:
|
|
if TIMINGS_CHECK["version"] in version:
|
|
embed_var.add_field(name="❌ Legacy Build",
|
|
value="Update to " + TIMINGS_CHECK["server"]["version"])
|
|
if "servers" in TIMINGS_CHECK:
|
|
for server in TIMINGS_CHECK["servers"]:
|
|
if server["name"] in version:
|
|
embed_var.add_field(**create_field(server))
|
|
break
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
if "config" in TIMINGS_CHECK:
|
|
server_properties = None
|
|
bukkit = None
|
|
spigot = None
|
|
paper = None
|
|
purpur = None
|
|
if "server.properties" in r["timingsMaster"]["config"]:
|
|
server_properties = r["timingsMaster"]["config"]["server.properties"]
|
|
if "bukkit" in r["timingsMaster"]["config"]:
|
|
bukkit = r["timingsMaster"]["config"]["bukkit"]
|
|
if "spigot" in r["timingsMaster"]["config"]:
|
|
spigot = r["timingsMaster"]["config"]["spigot"]
|
|
if "paper" in r["timingsMaster"]["config"]:
|
|
paper = r["timingsMaster"]["config"]["paper"]
|
|
if "purpur" in r["timingsMaster"]["config"]:
|
|
purpur = r["timingsMaster"]["config"]["purpur"]
|
|
|
|
for config_name in TIMINGS_CHECK["config"]:
|
|
config = TIMINGS_CHECK["config"][config_name]
|
|
for option_name in config:
|
|
option = config[option_name]
|
|
for expression in option["expressions"]:
|
|
if not eval(expression):
|
|
continue
|
|
embed_var.add_field(**create_field({**{"name": option_name}, **option}))
|
|
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
timing_cost = int(r["timingsMaster"]["system"]["timingcost"])
|
|
if timing_cost > 300:
|
|
embed_var.add_field(name="❌ Timingcost",
|
|
value="Your timingcost is " + str(timing_cost) + ". Find a [better host](https://www.birdflop.com).")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
jvm_version = r["timingsMaster"]["system"]["jvmversion"]
|
|
if jvm_version.startswith("1.8.") or jvm_version.startswith("9.") or jvm_version.startswith("10."):
|
|
embed_var.add_field(name="❌ Java Version",
|
|
value="You are using Java " + jvm_version + ". Update to [Java 11](https://adoptopenjdk.net/installation.html).")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
flags = r["timingsMaster"]["system"]["flags"]
|
|
if "-XX:+UseZGC" in flags:
|
|
jvm_version = r["timingsMaster"]["system"]["jvmversion"]
|
|
java_version = jvm_version.split(".")[0]
|
|
if int(java_version) < 14:
|
|
embed_var.add_field(name="❌ Java " + java_version,
|
|
value="If you are going to use ZGC, you should also use Java 14+.")
|
|
elif "-Daikars.new.flags=true" in flags:
|
|
if "-XX:+PerfDisableSharedMem" not in flags:
|
|
embed_var.add_field(name="❌ Outdated Flags",
|
|
value="Add `-XX:+PerfDisableSharedMem` to flags")
|
|
if "XX:G1MixedGCCountTarget=4" not in flags:
|
|
embed_var.add_field(name="❌ Outdated Flags",
|
|
value="Add `-XX:G1MixedGCCountTarget=4` to flags")
|
|
if "-Xmx" in flags:
|
|
max_mem = 0
|
|
flaglist = flags.split(" ")
|
|
for flag in flaglist:
|
|
if flag.startswith("-Xmx"):
|
|
max_mem = flag.split("-Xmx")[1]
|
|
max_mem = max_mem.replace("G", "000")
|
|
max_mem = max_mem.replace("M", "")
|
|
max_mem = max_mem.replace("g", "000")
|
|
max_mem = max_mem.replace("m", "")
|
|
if int(max_mem) < 5400:
|
|
embed_var.add_field(name="❌ Low Memory",
|
|
value="Allocate at least 6-10GB of ram to your server if you can afford it.")
|
|
if "-Xms" in flags:
|
|
min_mem = 0
|
|
flaglist = flags.split(" ")
|
|
for flag in flaglist:
|
|
if flag.startswith("-Xms"):
|
|
min_mem = flag.split("-Xms")[1]
|
|
min_mem = min_mem.replace("G", "000")
|
|
min_mem = min_mem.replace("M", "")
|
|
min_mem = min_mem.replace("g", "000")
|
|
min_mem = min_mem.replace("m", "")
|
|
if min_mem != max_mem:
|
|
embed_var.add_field(name="❌ Aikar's Flags",
|
|
value="Your Xmx and Xms values should be equivalent when using Aikar's flags.")
|
|
elif "-Dusing.aikars.flags=mcflags.emc.gs" in flags:
|
|
embed_var.add_field(name="❌ Outdated Flags",
|
|
value="Update [Aikar's flags](https://aikar.co/2018/07/02/tuning-the-jvm-g1gc-garbage-collector-flags-for-minecraft/).")
|
|
else:
|
|
embed_var.add_field(name="❌ Aikar's Flags",
|
|
value="Use [Aikar's flags](https://aikar.co/2018/07/02/tuning-the-jvm-g1gc-garbage-collector-flags-for-minecraft/).")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
try:
|
|
cpu = int(r["timingsMaster"]["system"]["cpu"])
|
|
if cpu == 1:
|
|
embed_var.add_field(name="❌ Threads",
|
|
value="You have only " + str(cpu) + " thread. Find a [better host](https://www.birdflop.com).")
|
|
if cpu == 2:
|
|
embed_var.add_field(name="❌ Threads",
|
|
value="You have only " + str(cpu) + " threads. Find a [better host](https://www.birdflop.com).")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
plugins = r["timingsMaster"]["plugins"]
|
|
if not YAML_ERROR:
|
|
for server_name in TIMINGS_CHECK["plugins"]:
|
|
if server_name in r["timingsMaster"]["config"]:
|
|
for plugin in plugins:
|
|
for plugin_name in TIMINGS_CHECK["plugins"][server_name]:
|
|
if plugin == plugin_name:
|
|
stored_plugin = TIMINGS_CHECK["plugins"][server_name][plugin_name]
|
|
stored_plugin["name"] = plugin_name
|
|
embed_var.add_field(**create_field(stored_plugin))
|
|
else:
|
|
embed_var.add_field(name="Error loading YAML file",
|
|
value=YAML_ERROR)
|
|
for plugin in plugins:
|
|
if "songoda" in r["timingsMaster"]["plugins"][plugin]["authors"].casefold():
|
|
if plugin == "EpicHeads":
|
|
embed_var.add_field(name="❌ EpicHeads",
|
|
value="This plugin was made by Songoda. Songoda resources are poorly developed and often cause problems. You should find an alternative such as [HeadsPlus](spigotmc.org/resources/headsplus-»-1-8-1-16-4.40265/) or [HeadDatabase](https://www.spigotmc.org/resources/head-database.14280/).")
|
|
elif plugin == "UltimateStacker":
|
|
embed_var.add_field(name="❌ UltimateStacker",
|
|
value="Stacking plugins actually causes more lag. "
|
|
"Remove UltimateStacker.")
|
|
else:
|
|
embed_var.add_field(name="❌ " + plugin,
|
|
value="This plugin was made by Songoda. Songoda resources are poorly developed and often cause problems. You should find an alternative.")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
plugins = r["timingsMaster"]["plugins"]
|
|
if "PhantomSMP" in plugins:
|
|
phantoms_only_insomniacs = r["timingsMaster"]["config"]["paper"]["world-settings"]["default"][
|
|
"phantoms-only-attack-insomniacs"]
|
|
if phantoms_only_insomniacs == "false":
|
|
embed_var.add_field(name="❌ PhantomSMP",
|
|
value="You probably don't need PhantomSMP as Paper already has its features. "
|
|
"Remove PhantomSMP.")
|
|
else:
|
|
embed_var.add_field(name="❌ PhantomSMP",
|
|
value="You probably don't need PhantomSMP as Paper already has its features. "
|
|
"Enable phantoms-only-attack-insomniacs in paper.yml.")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
network_compression_threshold = int(
|
|
r["timingsMaster"]["config"]["server.properties"]["network-compression-threshold"])
|
|
bungeecord = r["timingsMaster"]["config"]["spigot"]["settings"]["bungeecord"]
|
|
if network_compression_threshold <= 256 and bungeecord == "false":
|
|
embed_var.add_field(name="❌ network-compression-threshold",
|
|
value="Increase this in server.properties. Recommended: 512.")
|
|
if network_compression_threshold != -1 and bungeecord == "true":
|
|
embed_var.add_field(name="❌ network-compression-threshold",
|
|
value="Set this to -1 in server.properties for a bungee server like yours.")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
mob_spawn_range = int(r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["mob-spawn-range"])
|
|
spigot_view_distance = r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["view-distance"]
|
|
if spigot_view_distance == "default":
|
|
view_distance = int(r["timingsMaster"]["config"]["server.properties"]["view-distance"])
|
|
if mob_spawn_range >= 8 and view_distance <= 6:
|
|
embed_var.add_field(name="❌ mob-spawn-range",
|
|
value="Decrease this in spigot.yml. "
|
|
"Recommended: " + str(view_distance - 1) + ".")
|
|
elif mob_spawn_range >= 8 and int(spigot_view_distance) <= 6:
|
|
embed_var.add_field(name="❌ mob-spawn-range",
|
|
value="Decrease this in spigot.yml. "
|
|
"Recommended: " + str(int(spigot_view_distance) - 1) + ".")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
raiders_entity_activation_range = int(
|
|
r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["entity-activation-range"][
|
|
"raiders"])
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
flying_monsters_entity_activation_range = int(
|
|
r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["entity-activation-range"][
|
|
"flying-monsters"])
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
wake_up_inactive_villagers_every = int(
|
|
r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["entity-activation-range"][
|
|
"wake-up-inactive"]["villagers-every"])
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
|
|
try:
|
|
wake_up_inactive_animals_every = int(
|
|
r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["entity-activation-range"][
|
|
"wake-up-inactive"]["animals-every"])
|
|
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
|
|
|
|
try:
|
|
wake_up_inactive_flying_monsters_every = int(
|
|
r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["entity-activation-range"][
|
|
"wake-up-inactive"]["flying-monsters-every"])
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
wake_up_inactive_monsters_every = int(
|
|
r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"]["entity-activation-range"][
|
|
"wake-up-inactive"]["monsters-every"])
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
no_tick_view_distance = int(
|
|
r["timingsMaster"]["config"]["paper"]["world-settings"]["default"]["viewdistances"][
|
|
"no-tick-view-distance"])
|
|
if no_tick_view_distance == -1:
|
|
spigot_view_distance = r["timingsMaster"]["config"]["spigot"]["world-settings"]["default"][
|
|
"view-distance"]
|
|
if spigot_view_distance == "default":
|
|
view_distance = int(r["timingsMaster"]["config"]["server.properties"]["view-distance"])
|
|
if view_distance >= 4:
|
|
embed_var.add_field(name="❌ no-tick-view-distance",
|
|
value="Set a value in paper.yml. "
|
|
"Recommended: " + str(view_distance) + ". And reduce view-distance in server.properties. Recommended: 3.")
|
|
elif int(spigot_view_distance) >= 4:
|
|
embed_var.add_field(name="❌ no-tick-view-distance",
|
|
value="Set a value in paper.yml. "
|
|
"Recommended: " + spigot_view_distance + ". And reduce view-distance in spigot.yml. Recommended: 3.")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
try:
|
|
use_alternate_keepalive = r["timingsMaster"]["config"]["purpur"]["settings"]["use-alternate-keepalive"]
|
|
plugins = r["timingsMaster"]["plugins"]
|
|
if use_alternate_keepalive == "false" and "TCPShield" not in plugins:
|
|
embed_var.add_field(name="❌ use-alternate-keepalive",
|
|
value="Enable this in purpur.yml.")
|
|
if use_alternate_keepalive == "true" and "TCPShield" in plugins:
|
|
embed_var.add_field(name="❌ use-alternate-keepalive",
|
|
value="Disable this in purpur.yml. It causes issues with TCPShield.")
|
|
except KeyError:
|
|
unchecked = unchecked + 1
|
|
|
|
except ValueError:
|
|
embed_var.add_field(name="❌ Invalid Configuration",
|
|
value="At least one of your configuration files had an invalid data type.")
|
|
|
|
if len(embed_var.fields) == 0:
|
|
embed_var.add_field(name="✅ All good",
|
|
value="Analyzed with no issues")
|
|
await message.reply(embed=embed_var)
|
|
return
|
|
|
|
issue_count = len(embed_var.fields)
|
|
if issue_count >= 25:
|
|
embed_var.insert_field_at(index=24, name="Plus " + str(issue_count - 24) + " more recommendations", value="Create a new timings report after resolving some of the above issues to see more.")
|
|
if unchecked > 0:
|
|
embed_var.description = "||" + str(unchecked) + " missing configuration optimizations due to your server version.||"
|
|
await message.reply(embed=embed_var)
|
|
|
|
def create_field(option):
|
|
field = {"name": option["name"],
|
|
"value": option["value"]}
|
|
if "prefix" in option:
|
|
field["name"] = option["prefix"] + field["name"]
|
|
if "suffix" in option:
|
|
field["name"] = field["name"] + option["suffix"]
|
|
if "inline" in option:
|
|
field["inline"] = option["inline"]
|
|
return field
|
|
|
|
def setup(bot):
|
|
bot.add_cog(Timings(bot))
|