Skocz do zawartości

Rekomendowane odpowiedzi

DataPacki

Przeważnie podczas tworzenia funkcji definiujemy pożądaną liczbę parametrów, którą chcemy użyć. Przykład:

int Mnozenie(int a, int b) {
  return a * b;
}

///////////////

void JakasFunkcja() {
  PrintToChatAll("5x6 = %d", Mnozenie(5,6));
}

Aby zrobić tutaj użytek z funkcji Mnozenie() konieczne było przekazanie dwóch argumentów.

 

Niestety, w niektórych sytuacjach nie mamy komfortu przekazywania dowolnej ilości argumentów - jesteśmy ograniczeni tylko do...jednego!

Dotyczy to chociażby asynchronicznych zapytać SQL lub timerów. Przykład:

void JakasFunkcja(int client) {
  int a = 5;
  int b = 6;
  CreateTimer(10.0, PomnozCosPozniej, /*TUTAJ TYLKO JEDEN ARGUMENT!*/);
}

public Action PomnozCosPozniej(Handle timer, any data) {
  /// co tu zrobic ?! 
}

Gdybyśmy chcieli wykonać operację mnożenia w tym przypadku, niezbędne jest przekazanie dwóch zmiennych. Co robić w takiej sytuacji?

Z pomocą przychodzą nam DataPacki!
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!

Umożliwiają nam one "upakowanie" dowolnej liczby zmiennych o dowolnym typie do jednego ciągu danych. Cały proces zaczyna się od stworzenia uchwytu do DataPacka:

DataPack data = new DataPack();

jesteśmy gotowi do załadowania go danymi. Do tego celu wykorzystuje się kolejno WriteCell
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!, WriteFloat
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!, WriteFunction
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!, WriteString
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!

W naszym przykładzie poza dwiema zmiennymi przekażemy dodatkowo komunikat do wyświetlenia, aby pokazać jak posługiwać się ciągami znaków. Nasza funkcja będzie teraz wyglądać tak:

void JakasFunkcja(int client) {
  char helloString[128];
  Format(helloString, sizeof(helloString), "Siemanko %N!", client);
  DataPack data = new DataPack();
  data.WriteCell(5);
  data.WriteString(helloString);
  data.WriteCell(6);
  CreateTimer(10.0, PomnozCosPozniej, data);
}

Celowo umieściłem stringa pomiędzy dwiema liczbami, aby pokazać, że odczyt jest odrobinę bardziej skomplikowany niż zapis.

Po pierwsze, każdy DataPack posiada swój specjalny wskaźnik, który pokazuje w którym miejscu ma być przeprowadzany odczyt/zapis. Przeanalizujmy proces zapisu informacji w naszej funkcji JakasFunkcja(int client). Po stworzeniu DataPacka mamy pustą strukturę i wskaźnik znajdujący się na początku:

[|]
Znak '|' to właśnie nasz wskaźnik

Po wywołaniu żądania umieszczenia piątki, proces zaczął się w miejscu gdzie stał nasz wskaźnik - czyli na samym początku:

[5|]
Po dodaniu inta, wskaźnik przesunął się (troche jak wskaźnik podczas pisania na klawiaturze)

Kolejny w kolejce jest string:

[5string|]

I ostatnia już wartość - 6:

[5string6|]

W tym miejscu mamy już przygotowanego do wysyłki DataPacka. Zauważmy jednak, że nasz wskaźnik nie zmienił swojej pozycji - jest cały czas ustawiony na końcu struktury. Czy domyślacie się, jak wyglądałby odczyt tych danych? Bez przesunięcia wskaźnika na początek pliku ten proces jest niemożliwy...

Na szczęście, istnieje operacja, która może tego dokonać. Nazywa się ona Reset
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!:

// zauważmy, że drugi argument funkcji zmienił się na nasz DataPack :)
public Action PomnozCosPozniej(Handle timer, DataPack data) {
  data.Reset();
}

Od tego momentu struktura DataPacka wygląda tak:

[|5string6]

Oznacza to, że jesteśmy gotowi do odczytu ?

 

Istnieje jednak jeszcze jeden haczyk. Wspomniałem wcześniej, że dane w DataPacku przyjmują forme ciągu danych. Oznacza to, że SourceMod widzi je jako swoisty strumień. Właśnie do nas należy zadanie zapanowania nad tym haosem.

 

Do odczytywania danych stosujemy kolejno ReadCell
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!, ReadFloat
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!, ReadFunction
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami! i ReadString
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!.

 

W naszym DataPacku nie możemy zacząć wyciągania od np. stringa - wszystko musimy wykonywać w takiej samej kolejności, w jakiej wkładaliśmy dane! Na pierwszy ogień pójdzie więc 5, następnie komunikat, a na samym końcu - 6.

 

A więc pierwszą wartością jest int. Korzystamy z ReadCell
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!
Hej! Skorzystałeś z linku lub pobrałeś załącznik? Uhonoruj naszą pracę poprzez rejestrację na forum i rośnij razem z nami!:

// zauważmy, że drugi argument funkcji zmienił się na nasz DataPack :)
public Action PomnozCosPozniej(Handle timer, DataPack data) {
  data.Reset();
  int a = data.ReadCell();
}
// Aktualny stan DataPacka: [5|string6]

Przyszła pora na stringa. W naszym przypadku nasz łańcuch składa się z 128 znaków i dokładnie tyle zapisaliśmy w DataPacku! Pamiętajmy więc o przygotowaniu odpowiednio dużej tablicy:

char helloString[256]; // wielkość tablicy do której zapisujemy może się różnić - ważne, abyśmy pamiętali ile znaków zapisaliśmy WCZEŚNIEJ!
data.ReadString(helloString, sizeof(helloString));

 I na sam koniec ostatnia liczba:

int b = data.ReadCell();

 

Gotowe! Wszystkie dane zostały pobrane prawidłowo. Nasz efekt końcowy:

void JakasFunkcja(int client) {
  char helloString[128];
  Format(helloString, sizeof(helloString), "Siemanko %N!", client);
  DataPack data = new DataPack();
  data.WriteCell(5);
  data.WriteString(helloString);
  data.WriteCell(6);
  CreateTimer(10.0, PomnozCosPozniej, data);
}

public Action PomnozCosPozniej(Handle timer, DataPack data) {
  char helloString[256];
  data.Reset();
  int a = data.ReadCell();
  data.ReadString(helloString, sizeof(helloString));
  int b = data.ReadCell();
  PrintToChatAll("Komunikat: %s", helloString);
  PrintToChatAll("%d x %d = %d", a, b, a*b);
}
// stan DataPacka: [5string6|]

 

Oczywiście w razie pojawienia się pytań bądź wątpliwości zapraszam do dyskusji pod spodem ?

 

PS: suplementem do tego materiału jest napisany przez @Vasto_Lorde poradnik o timerach: 

 

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Odkopujemy!

 

Czy struktur Datapack nie trzeba przypadkiem usuwać?

CloseHandle / delete

Szczególnie, jeżeli odpowiednia flaga w Timer nie jest ustawiona. 😛

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dobre pytanie

 

Nigdzie nie znalazłem odpowiedzi na to pytanie. Idąc tym tropem, czy jak coś się zaalokuje przy pomocy new to później te pamięć też trzeba zwalniać?

Czy SM ma jakiś garbage collector czy jakiekolwiek inne rozwiązanie, które zapobiega wyciekom pamięci? Czy takim rozwiązaniem jest zwykła zmiana mapy?

 

Dużo pytań, a ode mnie żadnej odpowiedzi 😢

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dokumentacja SM za dużo nie mówi, ale(wszystko na podstawie oficjalnej dokumentacji):

- SM nie ma garbage collector

- Wszelkie Handle powinny być zamykane, chyba że dokumentacja danej funkcji mówi inaczej. Dotyczy to również wszelkich "obiektów" typu ArrayList

- Jeżeli do Timer'a dodasz flagę TIMER_DATA_HNDL_CLOSE, to dane przekazywane do tego timer'a powinny zostać zamknięte automatycznie.

 

Oczywiście, praktycznie nikt z "programistów" SM nie czyści pamięci. Jeszcze nie widziałem, żeby ktoś zamykał DataPack, czy Menu. 😕

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić obrazków. Dodaj lub załącz obrazki z adresu URL.


×
×
  • Dodaj nową pozycję...