Optymalizacja serwera Minecraft
Serwer zawieszający się przy 10 graczach, TPS lecący do 8, lagi przy spawnie mobów — to problemy, które da się wyeliminować. Ten przewodnik pokazuje krok po kroku, jak skonfigurować serwer Minecraft żeby działał płynnie, nawet przy dużym obciążeniu.
Czym jest TPS i dlaczego to ważne
TPS (Ticks Per Second, ticki na sekundę) to miara tego, jak szybko pracuje silnik serwera Minecraft. Idealna wartość to 20 TPS — każdy tick dzieje się co dokładnie 50 milisekund. Przy 20 TPS czas dnia płynie normalnie, moby zachowują się przewidywalnie, redstone działa bez opóźnień.
Gdy serwer jest przeciążony, nie pomija ticków — zwalnia. Każdy tick trwa dłużej niż 50 ms, więc 20 ticków na sekundę staje się niemożliwe. Przy 15 TPS czas gry płynie o 25% wolniej. Przy 10 TPS — o połowę. Gracze odczuwają to jako „gumowe nogi", moby zamierające w miejscu i opóźnienia przy interakcjach.
TPS możesz sprawdzić na bieżąco poleceniem /tps (dostępne w Spigot/Paper). Wyniki powyżej 19.5 TPS są akceptowalne. Poniżej 18 TPS — czas zacząć optymalizację.
Co obciąża serwer?
Najczęstsze przyczyny niskiego TPS to:
- Zbyt duże view-distance — serwer renderuje ogromne obszary dla każdego gracza
- Za dużo entityk — setki krów, owiec, itemów na ziemi, strzał
- Nieoptymalne pluginy — źle napisany plugin może sam zjadać połowę mocy procesora
- Nieskończone chunki — gracze eksplorujący nieznane obszary zmuszają serwer do nieustannego generowania terenu
- Skomplikowane redstone — duże farmy automatyczne, zegary 0-tick
- Brak pre-generacji — każdy nowy gracz generuje nowe chunki w czasie rzeczywistym
Diagnostyka — Timings i Spark
Zanim zaczniesz cokolwiek zmieniać, musisz wiedzieć, co konkretnie obciąża Twój serwer. Strzelanie na oślep w konfigurację bez danych to strata czasu.
Timings v2
Timings to wbudowane narzędzie Papera. Uruchamiasz je poleceniem /timings on, odczekujesz kilka minut przy normalnym obciążeniu serwera, a potem wpisujesz /timings paste. Paper generuje link do interaktywnego raportu na stronie timings.aikar.co.
W raporcie szukaj sekcji World Timings — tam znajdziesz, które operacje zjadają najwięcej czasu. Zwróć uwagę na entityTick (tickowanie entityk), tileEntityTick (kontenery, piece, dispensery) i konkretne nazwy pluginów zajmujące dużo milisekund.
Spark — profiler dla zaawansowanych
Spark to plugin open-source dający głębszą analizę niż Timings. Instalujesz go jak każdy inny plugin, a potem uruchamiasz profilowanie: /spark profiler start, odczekujesz minutę przy obciążeniu, /spark profiler stop. Wygenerowany raport pokazuje stack trace procesora — dokładnie które metody w kodzie zjadają czas.
Spark jest szczególnie przydatny do identyfikacji problematycznych pluginów. Jeśli widzisz, że 40% czasu CPU pochłania jakiś listener eventu z konkretnego pluginu — masz winowajcę.
Pobierz Spark z oficjalnej strony: spark.lucko.me. Plugin jest bezpłatny i aktywnie rozwijany.
Wybór silnika serwera
Vanilla Minecraft to najgorszy wybór dla każdego serwera z więcej niż 2–3 graczami. Vanilla nie ma żadnych opcji optymalizacyjnych i jest jednowątkowa w kluczowych operacjach. Przejście na zoptymalizowany fork to pierwszy i najważniejszy krok.
Paper — standard branży
Paper to fork Spigota z setkami poprawek wydajnościowych. Każdy powinien używać Papera. Oferuje rozbudowaną konfigurację (paper-global.yml, paper-world-defaults.yml), wbudowany Timings, naprawione duperbugi i znacznie lepsze zarządzanie chunkami niż vanilla czy Spigot.
Purpur — Paper z jeszcze więcej opcji
Purpur to fork Papera dodający purpur.yml z kilkudziesięcioma dodatkowymi opcjami konfiguracyjnymi, w tym możliwością dostosowania zachowania prawie każdego moba. Dla serwerów, które chcą maksymalnej kontroli nad mechanikami gry, Purpur to wybór oczywisty.
Folia — wielowątkowe tickowanie
Folia to eksperymentalny fork Papera, który dzieli mapę na regionalne wątki. Zamiast jednego wątku tickującego cały świat, Folia używa wielu wątków — każdy region mapy tworzy własny wątek. Efektem jest drastycznie lepsza skalowalność na serwerach z 50+ graczami rozrzuconymi po mapie.
Folia ma jednak ograniczenia: część pluginów nie jest z nią kompatybilna (szczególnie starsze pluginy operujące na globalnych danych). Przed przejściem na Folię sprawdź kompatybilność wszystkich swoich pluginów.
Flagi JVM — Aikar's Flags
Sposób, w jaki uruchamiasz Javę, ma ogromny wpływ na wydajność serwera. Domyślne ustawienia JVM nie są zoptymalizowane pod Minecraft. Flagi Aikara to zestaw parametrów JVM stworzony przez głównego dewelopera Papera, który znacząco redukuje pauzy garbage collectora (GC).
Flagi dla Java 11–17 (G1GC)
Poniżej pełny skrypt startowy z flagami Aikara. Zamień 6G na ilość RAM, którą chcesz przydzielić serwerowi:
java -Xms6G -Xmx6G \
-XX:+UseG1GC \
-XX:+ParallelRefProcEnabled \
-XX:MaxGCPauseMillis=200 \
-XX:+UnlockExperimentalVMOptions \
-XX:+DisableExplicitGC \
-XX:+AlwaysPreTouch \
-XX:G1NewSizePercent=30 \
-XX:G1MaxNewSizePercent=40 \
-XX:G1HeapRegionSize=8M \
-XX:G1ReservePercent=20 \
-XX:G1HeapWastePercent=5 \
-XX:G1MixedGCCountTarget=4 \
-XX:InitiatingHeapOccupancyPercent=15 \
-XX:G1MixedGCLiveThresholdPercent=90 \
-XX:G1RSetUpdatingPauseTimePercent=5 \
-XX:SurvivorRatio=32 \
-XX:+PerfDisableSharedMem \
-XX:MaxTenuringThreshold=1 \
-Dusing.aikars.flags=https://mcflags.emc.gs \
-Daikars.new.flags=true \
-jar paper.jar --nogui Flagi dla Java 21+ (ZGC)
Java 21 przyniosła ZGC (Z Garbage Collector) w wersji produkcyjnej. ZGC ma jeszcze krótsze pauzy GC niż G1GC i lepiej radzi sobie z dużymi stertami. Jeśli używasz Java 21 lub nowszej, rozważ przejście na ZGC:
java -Xms6G -Xmx6G \
-XX:+UseZGC \
-XX:+ZGenerational \
-XX:+AlwaysPreTouch \
-XX:+DisableExplicitGC \
-XX:+PerfDisableSharedMem \
-Dusing.aikars.flags=https://mcflags.emc.gs \
-jar paper.jar --nogui Ważna zasada: Xms = Xmx
Zawsze ustawiaj -Xms (minimalna sterta) i -Xmx (maksymalna sterta) na tę samą wartość. Dlaczego? Gdy Xms jest mniejsze niż Xmx, JVM musi dynamicznie powiększać stertę — każde powiększenie to pauza. Stała wielkość sterty eliminuje te pauzy całkowicie.
Ile RAM przydzielić?
- 5–10 graczy: 2–4 GB
- 10–30 graczy: 4–8 GB
- 30–60 graczy: 8–12 GB
- 60+ graczy: 12–16 GB (lub Folia)
Nie przydzielaj więcej niż potrzebujesz. Bardzo duże sterty (powyżej 12–14 GB) paradoksalnie pogarszają wydajność, bo GC musi przeszukać więcej pamięci. Lepiej zoptymalizować konfigurację niż dokładać RAM.
Konfiguracja server.properties
Plik server.properties to punkt wyjścia. Kilka kluczowych parametrów ma bezpośredni wpływ na wydajność:
# Odległość renderowania chunków — KLUCZOWE
# Każdy dodatkowy chunk to eksponencjalny wzrost obciążenia
# Dla serwerów survival z mniejszą liczbą graczy: 8-10
# Dla serwerów z wieloma graczami: 6-8
view-distance=8
# Symulacja chunków (aktywna fizyka, mobs, redstone)
# Może być niższe niż view-distance
# Gracze widzą dalej, ale fizyka działa tylko blisko
simulation-distance=6
# Synchronizacja chunkow z klientem
# Zostawić domyślnie (10) lub zmniejszyć do 6-8
network-compression-threshold=256
# Nie używaj synchronicznego zapisu chunków
# async-chunks jest domyślnie włączone w Paper
sync-chunk-writes=false Najważniejszy parametr to view-distance. Przy view-distance=10 serwer renderuje 441 chunków na gracza (21x21). Przy view-distance=6 — tylko 169 (13x13). To ponad 2,5x mniej pracy przy każdym ticku. Gracze rzadko zauważają różnicę między 8 a 10 view-distance, ale serwer — owszem.
Konfiguracja spigot.yml
Spigot.yml zawiera ustawienia dotyczące głównie mobów i mergowania entityk. Paper dziedziczy te ustawienia.
world-settings:
default:
# Zasięg w blokach, w którym moby spawują się wokół graczy
# Zmniejszenie redukuje liczbę aktywnych mobów
mob-spawn-range: 6 # domyślnie 8
# Mergowanie itemów leżących na ziemi — BARDZO ważne
# Duże farmy mogą generować setki itemów — merge je łączy
merge-radius:
item: 3.5 # domyślnie 2.5
exp: 6.0 # domyślnie 3.0
# Ile chunków zapisuje się automatycznie per tick
# Wyższe = szybszy zapis, ale krótkie piki obciążenia
max-auto-save-chunks-per-tick: 8 # domyślnie 24 — to za dużo!
# Aktywacja entityk — jak daleko od gracza entity jest aktywnie tickowana
entity-activation-range:
animals: 32 # domyślnie 32
monsters: 32 # domyślnie 32
raiders: 48 # domyślnie 48
misc: 16 # domyślnie 16
water: 16 # domyślnie 16
villagers: 32 # domyślnie 32
flying-monsters: 32 # domyślnie 32
# Czy nieaktywne entity są tickowane rzadziej
tick-inactive-villagers: false # domyślnie true — wieśniacy to jeden z największych pożeraczy CPU!
# Throttle AI entityk poza zasięgiem aktywacji
entity-tracking-range:
players: 48
animals: 48
monsters: 48
misc: 32
other: 64 Szczególną uwagę zwróć na max-auto-save-chunks-per-tick — domyślna wartość 24 powoduje regularne szarpnięcia TPS co kilka minut. Zmniejszenie do 6–8 rozłoży zapis równomiernie.
Wieśniacy (tick-inactive-villagers: false) to często pomijana optymalizacja. Aktywne tickowanie nieaktywnych wieśniaków to jeden z największych pożeraczy CPU w vanilla i Spigot. Paper ma własne, lepsze zarządzanie wieśniakami.
Konfiguracja paper-global.yml i paper-world-defaults.yml
Paper dzieli konfigurację na dwa pliki: config/paper-global.yml (ustawienia globalne) i config/paper-world-defaults.yml (domyślne ustawienia per-świat, nadpisywane przez config/worlds/NAZWA_ŚWIATA/paper-world.yml).
paper-global.yml
chunk-loading-basic:
# Ile chunków można załadować na sekundę per gracz
# Zmniejszenie redukuje lag przy szybkim locie
player-max-chunk-load-rate: 100.0 # domyślnie -1.0 (bez limitu)
global-max-chunk-load-rate: -1.0
chunk-system:
# Wątki do generowania chunków (nie więcej niż połowa rdzeni)
gen-parallelism: default # lub liczba jak "4"
misc:
# Wyłącz kompresję pakietów dla LAN (niepotrzebna)
# Zostaw domyślnie dla serwerów publicznych
use-display-entity-for-experience-orb: false paper-world-defaults.yml — kluczowe opcje
chunks:
# Auto-zapisywanie chunków co N sekund (0 = wyłączone, Paper używa własnego systemu)
auto-save-interval: -1 # Pozwól Paperowi zarządzać
entities:
spawning:
# Czy sprawdzać spawn podczas oświetlenia (droższe, ale dokładniejsze)
count-all-mobs-for-spawning: false
# Limit ślimacich pocisków (znany jako lag source)
behavior:
baby-zombie-movement-modifier: 0.5
environment:
# Anti-xray — BARDZO ważne dla serwerów PvP/survival
# Tryb 2 (enginemode) jest wolniejszy, ale skuteczniejszy
anticheat:
anti-xray:
enabled: true
engine-mode: 1 # Tryb 1 = szybki, tryb 2 = wolniejszy ale lepszy
max-block-height: 64
update-radius: 2
use-permission: false
hidden-blocks:
- copper_ore
- deepslate_copper_ore
- gold_ore
- deepslate_gold_ore
- iron_ore
- deepslate_iron_ore
- coal_ore
- deepslate_coal_ore
- lapis_ore
- deepslate_lapis_ore
- mossy_cobblestone
- obsidian
- chest
- diamond_ore
- deepslate_diamond_ore
- redstone_ore
- deepslate_redstone_ore
- clay
- emerald_ore
- deepslate_emerald_ore
- ender_chest
replacement-blocks:
- stone
- oak_planks
- deepslate
misc:
# Throttle wieśniaków poza zasięgiem gracza — OGROMNA optymalizacja
update-pathfinding-on-block-place: false
# Opóźnienie aktualizacji sąsiadujących chunków
delay-chunk-unloads-by: 10s Anti-Xray — tryb 1 vs tryb 2
Anti-Xray w Paperze to jedyna naprawdę skuteczna metoda ochrony przed X-rayem po stronie serwera. Tryb 1 (engine-mode: 1) ukrywa wybrane bloki, zastępując je kamieniem — szybki, ale dający się obejść przez sprytnych cheaterów. Tryb 2 (engine-mode: 2) wysyła klientowi fałszywe bloki wypełniające całą okolicę — dużo skuteczniejszy, ale kosztuje więcej CPU i przepustowości. Na serverze PvP/economy rekomendujemy tryb 2.
Konfiguracja purpur.yml
Jeśli używasz Purpura, purpur.yml daje dodatkowe opcje niedostępne w Paperze:
settings:
# Ilość wątków do kompresji pakietów sieciowych
# Na serwerach z wieloma graczami warto ustawić 1-2
network-compression-threads: -1 # -1 = off (wolniejsze CPU), >=0 = wątki
# Wyłącz strzały śmietnikowe po jakimś czasie
# entities-with-no-players-in-range
entity-per-chunk-save-limit:
experience_orb: 16
arrow: 16
dragon_fireball: 3
egg: 8
ender_pearl: 8
eye_of_ender: 8
fireball: 8
small_fireball: 8
firework_rocket: 8
llama_spit: 3
shulker_bullet: 8
snowball: 8
spectral_arrow: 16
wither_skull: 4
wind_charge: 8
# Limit entityk w jednym chunku — hard cap
mobs:
cow:
max-per-chunk: 10 # domyślnie brak limitu
sheep:
max-per-chunk: 10
pig:
max-per-chunk: 10
chicken:
max-per-chunk: 10 Opcja entity-per-chunk-save-limit w Purpurze to twarda granica entityk zapisywanych do chunku. Gdy serwer ładuje chunk z 500 strzałami (np. z fabryki strzał bez czyszczenia), normalnie tickowałby je wszystkie. Z limitem — zapisuje i tickuje tylko 16. To ratuje serwery z farmami strzelców.
Pre-generowanie chunków
Generowanie nowych chunków to jedna z najdroższych operacji w Minecraft. Gdy gracz eksploruje nieznane obszary, serwer musi w czasie rzeczywistym generować teren, struktury, biomy i spawnować mobleki startowe. Przy wielu graczach eksplorujących jednocześnie TPS spada dramatycznie.
Rozwiązanie: pre-generuj mapę zanim gracze zaczną grać. Plugin Chunky pozwala wygenerować cały obszar mapy z wyprzedzeniem.
Chunky — plugin do pre-generacji
Pobierz Chunky z Modrinth. Instalacja jak każdy plugin — wrzuć .jar do folderu plugins/ i zrestartuj serwer.
# Ustaw środek generacji (tu: 0,0) i promień (tu: 5000 bloków)
/chunky center 0 0
/chunky radius 5000
/chunky start
# Sprawdź postęp
/chunky status
# Pre-generacja 5000 bloków promienia = obszar 10000x10000 bloków
# To ok. 10 000 chunków — może zająć od kilku minut do godzin
# zależnie od maszyny i złożoności terenu Ile generować?
Dla typowego serwera survival z granicą świata 5000 bloków od centrum — pre-generuj dokładnie ten obszar. Gracze rzadko wychodzą poza granicę, więc nie ma sensu generować więcej. Jeśli nie masz granicy świata (World Border), rozważ jej ustawienie — bez granicy gracze rozchodzą się w nieskończoność, co powoduje generowanie nieskończonych obszarów i wykładniczy wzrost rozmiaru pliku mapy.
# Ustaw granicę świata na 10000 bloków od centrum (promień)
/worldborder set 20000
# Centrum granicy
/worldborder center 0 0 Kompresja mapy po pre-generacji
Po pre-generacji możesz skompresować pliki mapy narzędziem Slime World Manager lub po prostu poczekać — Paper kompresuje chunki automatycznie przy zapisie. Pre-generowana mapa 5000x5000 bloków zajmuje zwykle 1–3 GB.
Pluginy a wydajność
Każdy plugin to dodatkowy kod wykonywany podczas tickowania serwera. Kilka złych pluginów może łatwo zeżreć połowę CPU. Zasada jest prosta: mniej pluginów = szybszy serwer. Ale nie każdy plugin jest równie kosztowny.
Jak znaleźć winowajcę?
Użyj Sparka (/spark profiler start) lub Timings (/timings paste) podczas obciążenia serwera. W raporcie szukaj pluginów zajmujących nieproporcjonalnie dużo czasu. Typowi winowajcy:
- Pluginy ekonomii z bazą danych bez cache — każda transakcja to zapytanie SQL
- Pluginy anti-cheat — dobre anty-cheaty muszą analizować każdy ruch gracza; tanie lub źle napisane są mordercami TPS
- Pluginy chat/format z przetwarzaniem per-pakiet
- Pluginy do ochrony terenu bez przestrzennego indeksowania (sprawdzają każdy region dla każdego bloku)
- Pluginy hologramów ze zbyt częstym odświeżaniem
Rekomendowane zastępstwa
- EssentialsX → zamiast starych wersji Essentials (wolniejszych)
- LuckPerms → zamiast GroupManager, PermissionsEx (znacznie szybszy, asynchr. ładowanie)
- GriefDefender lub RedProtect → zamiast Towny z domyślną konfiguracją
- Spark → zamiast lagmetry lub podobnych
- Vault → zawsze upewnij się, że używasz aktualnej wersji
ClearLag — z głową
Plugin ClearLag regularnie usuwa leżące na ziemi itemy i strzały. Pomaga, ale ma pułapkę: jeśli gracze mają farmy itemów, ClearLag niszczy ich produkty. Skonfiguruj białą listę itemów i ustaw rozsądny interwał (co 10–15 minut).
Alternatywa: zamiast ClearLagga, popraw merge-radius w spigot.yml i ustaw limity entityk w Paper/Purpur. To rozwiązuje problem u źródła, a nie zamiatanie pod dywan.
Zarządzanie entitykami i mobbami
Zbyt wiele entityk to najczęstszy powód niskiego TPS na większych serwerach. Każda entity — mob, item, strzała, boat, armorstands — musi być tickowana co 50 ms. 2000 entityk w jednym chunku to katastrofa.
Limity w bukkit.yml
Plik bukkit.yml kontroluje globalne limity spawnu mobów per chunk:
spawn-limits:
monsters: 70 # domyślnie 70
animals: 10 # domyślnie 10
water-animals: 5 # domyślnie 5
water-ambient: 20 # domyślnie 20
water-underground-creature: 5
axolotls: 5
ambient: 15 # domyślnie 15
chunk-gc:
period-in-ticks: 600 # Jak często GC czyści nieużywane chunki Zmniejszenie monsters do 50–60 jest bezpieczne na większości serwerów — gracze rzadko zauważają różnicę w gęstości moblów.
Entity culling — przycinanie niewidocznych entityk
Plugin EntityCulling (dostępny na Modrinth) zatrzymuje wysyłanie aktualizacji entityk do graczy, którzy ich nie widzą (np. po drugiej stronie ściany). Nie zmniejsza liczby tickowanych entityk po stronie serwera, ale redukuje ruch sieciowy i obciążenie klientów. Szczególnie pomocny na serwerach PvP/minigry.
Farmy zwierząt — pułapka na TPS
Nieograniczone farmy zwierząt to bomba zegarowa. Gracz hodujący 300 krów w jednym zagrodzie tworzy więcej lagów niż 10 normalnie grających osób. Rozwiązania:
- Ustaw
max-per-chunkw purpur.yml (jeśli używasz Purpura) - Zainstaluj plugin z limitami entityk per gracz (np. EntityLimiter)
- Ustaw w regulaminie limit hodowli i egzekwuj go moderatorami
- Plugin Stacker łączy mobleki tego samego rodzaju w stosik — wizualnie wygląda jak jeden mob, ale zachowuje się jak wiele. Ogromna oszczędność entityk
RAM i garbage collector
Java zarządza pamięcią automatycznie przez garbage collector (GC). GC cyklicznie skanuje stertę w poszukiwaniu obiektów, do których nic już nie prowadzi, i zwalnia pamięć. Problem: podczas pełnego skanowania sterty GC zatrzymuje wątki aplikacji — to właśnie powoduje krótkie, regularne szarpnięcia TPS (GC pause).
Jak zmniejszyć pauzy GC?
- Używaj flag Aikara — G1GC z flagami Aikara jest dostrojony pod Minecrafta i minimalizuje pauzy
- Xms = Xmx — bez dynamicznego rozszerzania sterty (patrz sekcja o flagach JVM)
- Java 21 + ZGC — ZGC ma pauzy poniżej 1 ms, niezależnie od rozmiaru sterty
- Nie przydzielaj za dużo RAM — im większa sterta, tym dłuższe skanowanie GC. Przydziel tyle ile potrzebujesz, nie więcej
Monitorowanie GC
Spark potrafi pokazać statystyki GC: /spark gcmonitor. Zobaczysz ile razy na minutę odpala się GC i jak długo trwają pauzy. Pauzy powyżej 200 ms są niepokojące. Powyżej 500 ms — krytyczne.
Java 21 — warto zaktualizować
Paper od wersji 1.21 oficjalnie rekomenduje Java 21. ZGC w Java 21 działa w trybie generacyjnym (-XX:+ZGenerational), co daje najkrótsze możliwe pauzy GC. Jeśli wciąż używasz Java 11 lub 17 — aktualizacja do 21 to jeden z najprostszych sposobów na zmniejszenie lagów.
Co NIE pomaga
- Pluginy „anty-lag" oferujące „optymalizację RAM" — to scam. Nic co działa w Javie nie może zastąpić flag JVM ani dobrej konfiguracji
- System.gc() co minutę — wymuszanie GC pogarsza sytuację, tworząc regularne pauzy zamiast pozwolić JVM zarządzać nimi optymalnie
- Przydzielanie 32 GB RAM serwerowi dla 10 graczy — marnotrawstwo i potencjalny problem z GC