Skocz do zawartości
  • 0

BungeeTask - błędy w konsoli


Szymoon202

Pytanie

Cześć, napisałem krótki plugin BungeeCord na blokadę czatu. Trzeba grać conajmniej 30min, aby móc pisać na chacie, lecz przy wywoływaniu taska pokazuje się taki błąd w konsoli:

[21:10:50 ERROR]: Task BungeeTask(sched=net.md_5.bungee.scheduler.BungeeScheduler@40499e4f, id=0, owner=pl.szymoon202.chatblocker.Main@1c7fd41f, task=pl.szymoon202.chatblocker.Main$1@51cd7ffc, delay=60000, period=60000, running=true) encountered an exception
java.util.ConcurrentModificationException: null
        at java.util.HashMap.forEach(HashMap.java:1291) ~[?:1.8.0_144]
        at pl.szymoon202.chatblocker.Main$1.run(Main.java:22) ~[?:?]
        at net.md_5.bungee.scheduler.BungeeTask.run(BungeeTask.java:63) [Waterfall.jar:git:Waterfall-Bootstrap:1.12-SNAPSHOT:261741a:155]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_144]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_144]
        at java.lang.Thread.run(Thread.java:748) [?:1.8.0_144]

Klasa Main:

public class Main extends Plugin{
	
	public static HashMap<ProxiedPlayer, Integer> players = new HashMap<ProxiedPlayer, Integer>();
	
	@Override
	public void onEnable() {
		getProxy().getPluginManager().registerListener(this, new LoginListener());
		getProxy().getPluginManager().registerListener(this, new ChatListener());
		
		getProxy().getScheduler().schedule(this, new Runnable() {
			public void run(){
				players.forEach((player, minutes) -> {
					ProxiedPlayer p = player;
					if(p.isConnected()) {
						int i = minutes;
					    if(i != 0) {
					    	i--;
					    	players.remove(p);
					    	players.put(p, i);
					    }
					}
				});
			}
		}, 1, 1, TimeUnit.MINUTES);
	}
	
}

Własnie przy tym tasku pokazuje się błąd. Mam również dwa inne listenery, jeden na czat a drugi na logowanie, ale one działają bez problemu. Ktoś pomoże wyjaśnić ten problem?

Odnośnik do komentarza
Udostępnij na innych stronach

6 odpowiedzi na to pytanie

Rekomendowane odpowiedzi

  • 0

No widzisz, bungee to już nie taka prosta apka jak spigot, tutaj istnieje wiele wątków, a HashMapa to skomplikowany typ danych - w środku jest całkiem sporo logiki, i gdyby 2 wątki jednocześnie chciały coś na niej zarobić, np oba dodać lub jeden dodać a drugi odczytać - to mogłoby się dziać dziwne rzeczy, więc w domyślne kolekcje javy są zbudowane zabezpieczenia które upewniają się że takie błędy nie wystąpią - zamiast tego jest wyrzucony wyjątkiem będący znakiem dla developera że spie po całości.
I u ciebie jest też drugi problem, bo z tego samego powodu nie można edytować kolekcji w trakcie iteracji po niej - bo dodając element też można zmienić się wewnętrzna struktura danych i kolejność iteracji mogłaby nie zostać zachowana.

Do tego nie ogarniam po co robisz:

players.remove(p);
players.put(p, i);

możesz zostawić samo put, a najlepiej to...

 

Zapisać czas wejścia na serwer i tylko obliczać ile gracz już jest na serwerze - taki task tylko niepotrzebne zamula i powoduje problemy.

Do tego wtedy albo należy użyć mapy synchronizowanej, albo concurrent, w synchronizowanej wątki będą czekać aż inny skończy robić swoje z mapą - co może spowolnić wątek, ale bardzo mało i zazwyczaj nie ma to znaczenia znacznego, a concurrent pozwala na edycje z wielu wątków - jednak mogą wystąpić drobne problemy, np jak doda się element w trakcie interacji po mapie - nawet w tym samym wątku - to nie masz żadnej pewności czy ten element też będzie iterowany w tej pętli. czyli np masz mapę z kluczami [d,b,a,c] (pamiętaj że kolejność też nie jest gwarantowana w hash mapie, tutaj przykładowa), iterujesz i w momencie jak jesteś na "b" to dodajesz jeszcze element z kluczem "e" i "f", i teraz cała pętla np przeiteruje po [d,b,a,c,f] - czyli tutaj bez "e" bo algorytm hashmapy dodał ten element przed "b". Dodatkowo concurrent zjada więcej pamięci.

Edytowane przez GotoFinal
Odnośnik do komentarza
Udostępnij na innych stronach

  • 0

Okej, innym sposobem, tak jak powiedziałeś. Ustawiam czas wejścia na serwer, a potem przy evencie sprawdzam, czy 30 min już minęło, ale co jak gracz jest offline? Daty przecież nie zmienię, więc jak inaczej mam to zrobić? (Dla mnie jest już późno i trochę nie myślę :D)

Odnośnik do komentarza
Udostępnij na innych stronach

  • 0
14 minut temu, Szymoon202 napisał:

Okej, innym sposobem, tak jak powiedziałeś. Ustawiam czas wejścia na serwer, a potem przy evencie sprawdzam, czy 30 min już minęło, ale co jak gracz jest offline? Daty przecież nie zmienię, więc jak inaczej mam to zrobić? (Dla mnie jest już późno i trochę nie myślę :D)

no jak gracz wyjdzie to możesz go z tej mapy usunąć - i jak chcesz liczyć kompletny czas online to musisz też to zapisywać do jakiegoś pliku lub bazy bo przecież bungee może być gdzieś resetowane, paść itd. np czasy wejścia i wyjścia każdego gracza w bazie i wtedy pobierasz i podliczasz cały czas - lub tylko zapisywać kompletny czas do bazy/pliku, no ale daty mogą być pomocniejsze, możesz potem więcej stworzyć, np czas online w ostatnim tygodniu itd.

Edytowane przez GotoFinal
Odnośnik do komentarza
Udostępnij na innych stronach

  • 0
6 godzin temu, KrejzolekPRO napisał:

Ja bym zrobił object usera, i przy wejściu zapisał czas w milisekundach przy wyjsciu odjął obecny od zapisanego i roznice dodal do jakies mapki <Player, long>.

po co obiekt tylko do przetrzymywania czasu skoro wystarczy jedna mapka..

 

17 godzin temu, Szymoon202 napisał:

Okej, innym sposobem, tak jak powiedziałeś. Ustawiam czas wejścia na serwer, a potem przy evencie sprawdzam, czy 30 min już minęło, ale co jak gracz jest offline? Daty przecież nie zmienię, więc jak inaczej mam to zrobić? (Dla mnie jest już późno i trochę nie myślę :D)

Chcesz zrobić tak ,że gracz musi grać na serwerze przez te 30 minut, czy tylko po prostu może wbić i wyjść i po wyjściu czas dalej ma lecieć?

Odnośnik do komentarza
Udostępnij na innych stronach

Nieaktywny
Ten temat został zamknięty. Brak możliwości dodania odpowiedzi.
  • Ostatnio przeglądający   0 użytkowników

    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...