←  Problemy

AMXX.pl: Support AMX Mod X i SourceMod

»

[ROZWIĄZANE] Usuwanie stworzonego 'ent...


Najlepsza odpowiedź sebul 15.01.2015 23:06

Spróbuj w tej funkcji zaraz przed usunięciem entu, usunąć także taska "killBox". Przejdź do postu
Zablokowany

  • +
  • -
psilocybe - zdjęcie psilocybe 15.01.2015

Nie mogę znaleźć dobrego przykładu.

 

Sprawa wygląda tak:

 

Na mapie tworzy się jakaś liczba entity 'info_target' ze zmienionym stringiem 'classname', na koniec rundy usuwam w pętli enty z tym 'classname' i wszystko jest ok.

 

Teraz chcę napisać funkcję która usunie mi mój entity np. 5 sekund po jego spawnie, myślałem że to proste będzie ale coś jest bardzo nie tak :D

 

 

Moment utworzenia entity:

new ent = create_entity("info_target")
entity_set_string(ent, EV_SZ_classname, "w_box")

No i tu dałem taska za 5 sekund, a funkcja którą uruchamiał to coś takiego:

public killBox(ent)
{
    if(is_valid_ent(ent))
    {
        remove_entity(ent);
    }
}

Funkcja usuwała wybranego enta który "uruchomił" task, ale np. w losowym momencie (ok. 1-2 minut od startu mapy) crash serwera, brak logów a w konsoli serwera tylko 'Segmentation Fault'.

 

Jeszcze raz w skrócie, tworzę enta (create_entity), nadaję mu swój classname (w_box) i nakazuje mu za 5 sekund (set_task) zniknąć z mapy (remove_entity)

 

Jak to wykonać? :D

Odpowiedz

  • +
  • -
MAGNET - zdjęcie MAGNET 15.01.2015

A jak pobierasz id enta?

Była taka fajna funkcja od pobierania id enta przez nazwę i było to w klasie Replikant CODMOD. Piszę z tel i nie mam jak tam to podejrzeć.
Odpowiedz

  • +
  • -
DarkGL - zdjęcie DarkGL 15.01.2015

Pokaż utworzenie taska i pełny kod tworzenia entity , jesteś pewny ze to przez to ;P ?
Odpowiedz

  • +
  • -
psilocybe - zdjęcie psilocybe 15.01.2015

Dark'u na pewno przez to, sprawdziłem.

 

Co do tworzenia samego enta to ciekawego nic tam nie ma:      

        new Float:fVelocity[3], Float:fOrigin[3]
        entity_get_vector(id, EV_VEC_origin, fOrigin)
        VelocityByAim(id, 34, fVelocity)
    
        fOrigin[0] += fVelocity[0]
        fOrigin[1] += fVelocity[1]

        VelocityByAim(id, 300, fVelocity)
    
        new ent = create_entity("info_target")
        entity_set_string(ent, EV_SZ_classname, "w_box")
        entity_set_model(ent, "models/w_box3.mdl")
    
        entity_set_int(ent, EV_INT_movetype, MOVETYPE_TOSS)
        entity_set_int(ent, EV_INT_solid, SOLID_TRIGGER)
        entity_set_vector(ent, EV_VEC_origin, fOrigin)
        entity_set_vector(ent, EV_VEC_velocity, fVelocity)
        entity_set_float(ent, EV_FL_nextthink, halflife_time() + 0.01)
        
        set_task( 2.0, "killBox", ent )

Teraz w tasku killBox dałem sprawdzenie współrzędnych enta który powstał.

public killBox(ent)
{
    if(is_valid_ent(ent)){
    new vec[3];
    entity_get_vector(ent,EV_VEC_origin,Float:vec);
    
    client_print(0, print_chat, "[ORIGIN] x: %f y: %f z: %f",vec[0], vec[1], vec[2]);
    }
}

No i śmieszna sytuacja bo współrzędne mi pokazuje prawidłowe, za każdym razem inne, czyli zakładam że prawidłowo pobiera origins entity który uruchomił task.

 

Wystarczy że dodam pod client_print funkcję remove_entity(ent) i usuwa mi tego ent'a - ale serwer za chwile crashuje, losowo ale nigdy od razu.

Odpowiedz

  • +
  • -
wooDy. - zdjęcie wooDy. 15.01.2015

public killBox(ent)
{
    if(is_valid_ent(ent)){
         new Float:vec[3];
         entity_get_vector(ent,EV_VEC_origin,vec);
    
         client_print(0, print_chat, "[ORIGIN] x: %.2f y: %.2f z: %.2f",vec[0], vec[1], vec[2]);
         remove_entity(ent);
    }
}

Nie tak powinno być? ;)
Odpowiedz

  • +
  • -
Petpat - zdjęcie Petpat 15.01.2015

public killBox(ent)
{
    if(is_valid_ent(ent)){
         new Float:vec[3];
         entity_get_vector(ent,EV_VEC_origin,vec);
    
         client_print(0, print_chat, "[ORIGIN] x: %.2f y: %.2f z: %.2f",vec[0], vec[1], vec[2]);
         remove_entity(ent);
    }
}
Nie tak powinno być? ;)


Czytaj ze zrozumieniem napisał wyraźnie

"Wystarczy że dodam pod client_print funkcję remove_entity(ent) i usuwa mi tego ent'a - ale serwer za chwile crashuje, losowo ale nigdy od razu."
Odpowiedz

  • +
  • -
wooDy. - zdjęcie wooDy. 15.01.2015

A tego, ze zmienna została źle utworzona nie zauwazyles, panie spostrzegawczy?
Odpowiedz

  • +
  • -
psilocybe - zdjęcie psilocybe 15.01.2015

@wooDy, print_chat tylko do testów używam więc tu nie ma to znaczenia.

 

Wszystko zdaje się być ok, a to że crashuje sprawdzałem i lokalnie i na serwerze, po "zablokowaniu" wykonywania funkcji która usuwa enta plugin nie crashuje (kilka godzin bez żadnego erroru już działa).

 

Poza tym, usuwam enty na koniec rundy, przy 'touch' itp. nigdy nie crashuje - problem jest z tym taskiem.

 

Mi się wydaje że po prostu brakuje tu czegoś, jakiś szczegół albo nie wiem, brak warunku else?

 

Teraz dałem taką testową funkcję:

public killBox(ent)
{
    if(is_valid_ent(ent)){
    
        new vec[3];
        entity_get_vector(ent,EV_VEC_origin,Float:vec);
    
        new name[64]; //dla pewności 64
        entity_get_string(ent,EV_SZ_classname,name,63);
    
        client_print(0, print_chat, "[TEST] x: %f y: %f z: %f name: %s",vec[0], vec[1], vec[2], name);
    
        client_print(0, print_chat, "[TEST] Usuwam entity o ID: %d", ent);
    
        remove_entity(ent);
    }
    
    else{
    
        client_print(0, print_chat, "[TEST] Nie znaleziono entity o ID: %d", ent); 

    }
    
    return PLUGIN_HANDLED
}

No i pokazuje prawidłowe współrzędne, prawidłowy 'classname', prawidłowe ID enta, usuwa, ent znika - no i crash następuje tak jak pisałem losowo w ciągu około minuty, czasem dłużej, czasem przy nowej rundzie. Brak error_log, debug włączony, w konsoli 'Segmentation Fault' :D

 

Dodam, że jeżeli stworzę 10 entów w odstępach co 1 sekundę to usuwa po kolei tak jak chciałem - nie wiem co jest nie tak. Może w końcu debug wypluje jakieś logi :(

 

 

 

Odpowiedz

  • +
  • -
sebul - zdjęcie sebul 15.01.2015

A pokaż kod, gdzie usuwasz w innych momentach te enty.
I taka uwaga, o ile to może i działa
new vec[3];
entity_get_vector(ent,EV_VEC_origin,Float:vec);
to jednak prawidłowo powinno się pisać tak
new Float:vec[3];
entity_get_vector(ent,EV_VEC_origin,vec);
Przy tworzeniu zmiennej powinno być widać jaki to będzie "typ".
Odpowiedz

  • +
  • -
psilocybe - zdjęcie psilocybe 15.01.2015

@sebul, poprawione, mój błąd ;) Wracając do usuwania w innych momentach to najczęściej tak:

register_touch("w_box", "player", "touch_box");
public touch_box(ent, id)
{
    if(!is_valid_ent(ent) || !is_user_alive(id))
        {
        return PLUGIN_CONTINUE
        }

    if(is_user_alive(id))
        {
        client_cmd(id, "spk %s", beep);
        remove_entity(ent)
        }
    
    return PLUGIN_CONTINUE
}

Kod jest bardziej uwarunkowany ale usunąłem to co nie ma znaczenia.

Odpowiedz

  • +
  • -
Najlepsza odpowiedź sebul - zdjęcie sebul 15.01.2015

Spróbuj w tej funkcji zaraz przed usunięciem entu, usunąć także taska "killBox".
Odpowiedz

  • +
  • -
psilocybe - zdjęcie psilocybe 16.01.2015

Czyli przed usunięciem enta w innych funkcjach dodaje:

if( task_exists(ent) )
            {
            remove_task(ent);
            }

Poczekałem 50 minut dla pewności, nie crashuje :)

 

Możliwe że to jest to. Raczej na pewno.

 

 

Jeszcze dla jasności pytanie, bo na koniec rundy też usuwam wszystkie enty ale wygląda to nieco inaczej, pytanie czy dobrze dodałem usuwanie task'a? Ma to sens?

 

To jest w funkcji round_end:

new wBox = find_ent_by_class(-1, "w_box"); // Wyszukuje ID enta po classname
    
    while( wBox> 0 && is_valid_ent(wBox) )
    {
    remove_entity(wBox);
    wBox= find_ent_by_class(-1, "w_box");
    
    if( task_exists(wBox) )
            {
            remove_task(wBox);
            }    
    }

"Komplikować" to się "komplikuje" ale czy poprawnie to jest napisane? :D

Odpowiedz

  • +
  • -
sebul - zdjęcie sebul 16.01.2015

Tak krócej
new wBox = -1 // Wyszukuje ID enta po classname

while( (wBox = find_ent_by_class(wBox, "w_box")) && is_valid_ent(wBox) )
{
	remove_entity(wBox);
	remove_task(wBox);
}
ale dobrze by było, żebyś też tego taska jakoś przerobił na bardziej unikalnego, czyli daj sobie gdzieś na górę
#define TASK_KILLENT 473825
i potem tego wszędzie do taska używasz, czyli chociażby
public killBox(ent)
{
    ent -= TASK_KILLENT;
    if(is_valid_ent(ent))
    {
        remove_entity(ent);
    }
}
Odpowiedz

  • +
  • -
GwynBleidD - zdjęcie GwynBleidD 16.01.2015

Tak krócej

new wBox = -1 // Wyszukuje ID enta po classname

while( (wBox = find_ent_by_class(wBox, "w_box")) && is_valid_ent(wBox) )
{
	remove_entity(wBox);
	remove_task(wBox);
}

Nope!
remove_task powinno być PRZED remove entity. remove_entity zmienia wartość wBox na -1! Przez co nie usuniemy taska, bo taki nie istnieje.

ale dobrze by było, żebyś też tego taska jakoś przerobił na bardziej unikalnego, czyli daj sobie gdzieś na górę

#define TASK_KILLENT 473825
i potem tego wszędzie do taska używasz, czyli chociażby
public killBox(ent)
{
    ent -= TASK_KILLENT;
    if(is_valid_ent(ent))
    {
        remove_entity(ent);
    }
}


Ma to sens TYLKO wtedy, gdy mamy kolizję numerów tasków w jednym pluginie. Inne pluginy, jeśli nie szukają specjalnie, tasków obcych nie widzą. A nawet jeśli to szkoda się silić na wymyślanie cyferek typu 473825, wystarczy po prostu policzyć ile ID tasków użyjemy i zachować ciągłość. Jeśli nie jesteśmy w stanie przewidzieć (np jak w tym przypadku, entów może być naprawdę sporo i mogą mieć różne ID) to taką grupę tasków warto dać na końcu. Gorzej jeśli mamy 2 takie grupy...
Odpowiedz

  • +
  • -
sebul - zdjęcie sebul 16.01.2015

No tak, usunięcie entu musi być za usunięciem tasku. A co do id tasków, po temacie jak dla mnie widać, że jest to bardziej rozbudowany plugin, a w takich ja zawsze dodaję/odejmuję do id tasków jakąś wartość, wtedy to też ma sens przy szukaniu danego taska (więc wcale nie tylko do tego o czym napisałeś), ale zazwyczaj wtedy też to robię trochę inaczej, chociażby
enum (+= 200) {
	TASK_PIERWSZY = 2000,
	TASK_DRUGI,
	TASK_TRZECI // itd.
};

A nawet jeśli to szkoda się silić na wymyślanie cyferek typu 473825

A co to za wysiłek?
Odpowiedz

  • +
  • -
psilocybe - zdjęcie psilocybe 17.01.2015

Dzięki za wyjaśnienie, problem rozwiązany.

 

Crashe bez logów, gdzie w konsoli było tylko 'Segmentation fault' to prawdopodobnie efekt próby usunięcia entity o ID 0 lub mniejszego od 32. Nadal nie jestem pewny bo nie udało się uzyskać logów nawet przy wszystkich dostępnych komendach debugowania serwera i amx'a. Jednego jestem pewny - miało to związek z usuwaniem tych entity.

 

 

Odpowiedz

  • +
  • -
sebul - zdjęcie sebul 17.01.2015

Wiadomość wygenerowana automatycznie


Ten temat został zamknięty przez moderatora.

Powód: Pomoc udzielona

Jeśli się z tym nie zgadzasz, report.png raportuj ten post, a moderator lub administrator rozpatrzy go ponownie.


Z pozdrowieniami,
Zespół AMXX.PL
Odpowiedz
Zablokowany