Офлайн-лаунчер Minecraft: аккаунты без Microsoft, установка версий и лоадеров (Fabric, Quilt, Forge, NeoForge), каталог модпаков Modrinth, поиск и обновление модов, разбор вылетов, системный трей, автозагрузка, плагины, прокси и зеркала.
91 lines
3.3 KiB
Python
91 lines
3.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Разбор логов вылетов Minecraft.
|
|
|
|
Ищет в логе последний exception-блок и определяет причину:
|
|
нехватка ОЗУ, проблемы с Java, конкретный мод или «неизвестно».
|
|
"""
|
|
|
|
import re
|
|
|
|
# "java.lang.NullPointerException: ..." / "Caused by: ...Exception: ..."
|
|
_EXC = re.compile(
|
|
r"^(?:Caused by: |Exception in thread [^\s]+ )?"
|
|
r"([\w.$]+(?:Exception|Error|Throwable))(?::\s*(.*))?$")
|
|
|
|
_MOD_JAR = re.compile(r"mods[/\\]([\w.\- ]+\.jar)")
|
|
_MOD_AT = re.compile(r"\(([\w\-]+)@[\d.]+\)") # SomeMod@1.2.3 в кадрах
|
|
_XMX = re.compile(r"-xmx(\d+)([mg])")
|
|
|
|
|
|
def analyze(text=None, path=None, tail=600):
|
|
"""Разбирает лог. Возвращает dict:
|
|
|
|
kind — "crash" | "oom" | "java" | "unknown"
|
|
exc — класс исключения (без пакета)
|
|
msg — сообщение исключения
|
|
culprit — имя файла мода (mods/xxx.jar) или id мода, если найдено
|
|
hints — подсказки ("oom", "xmx=2048", "classver", ...)
|
|
"""
|
|
res = {"kind": "unknown", "exc": "", "msg": "", "culprit": None,
|
|
"hints": []}
|
|
lines = []
|
|
if text is not None:
|
|
lines = text.splitlines()[-tail:]
|
|
elif path:
|
|
try:
|
|
with open(path, encoding="utf-8", errors="replace") as f:
|
|
lines = f.readlines()[-tail:]
|
|
except OSError:
|
|
pass
|
|
joined = "\n".join(lines)
|
|
if not joined.strip():
|
|
return res
|
|
low = joined.lower()
|
|
|
|
# --- нехватка ОЗУ
|
|
if ("outofmemoryerror" in low
|
|
or "could not reserve enough space" in low
|
|
or "gc overhead limit exceeded" in low):
|
|
res["kind"] = "oom"
|
|
res["exc"] = "OutOfMemoryError"
|
|
res["hints"].append("oom")
|
|
m = _XMX.search(low)
|
|
if m:
|
|
res["hints"].append("xmx=" + m.group(1) + m.group(2))
|
|
return res
|
|
|
|
# --- проблемы с Java
|
|
for pat, tag in ((r"unsupported class file major version (\d+)",
|
|
"classver"),
|
|
(r"unsupportedclassversionerror", "classver"),
|
|
(r"could not create the java virtual machine", "jvm"),
|
|
(r"invalid java runtime|no jvm could be found",
|
|
"java")):
|
|
if re.search(pat, low):
|
|
res["kind"] = "java"
|
|
res["exc"] = tag
|
|
res["hints"].append(tag)
|
|
return res
|
|
|
|
# --- последний exception-блок
|
|
idx = [i for i, ln in enumerate(lines) if _EXC.match(ln.strip())]
|
|
if not idx:
|
|
return res
|
|
caused = [i for i in idx if lines[i].strip().startswith("Caused by:")]
|
|
# корневая причина — последний Caused by в цепочке
|
|
m = _EXC.match(lines[caused[-1] if caused else idx[0]].strip())
|
|
res["kind"] = "crash"
|
|
if m:
|
|
res["exc"] = m.group(1).split(".")[-1]
|
|
res["msg"] = (m.group(2) or "")[:200]
|
|
|
|
# --- виновник: файл мода в тексте или mixin-кадр с mod id
|
|
m2 = _MOD_JAR.search(joined)
|
|
if m2:
|
|
res["culprit"] = m2.group(1)
|
|
else:
|
|
m3 = _MOD_AT.search(joined)
|
|
if m3:
|
|
res["culprit"] = m3.group(1)
|
|
return res
|