26 listopada 2025

Leaked instances

Znalazłem przyczynę wyciekających (okrutnie) instancji Node .... ale nie żebym od razu je wszystkie poprawił, co to to nie.

Wyciekające węzły.


Kłopotem jest to, że w ramach list rozwijalnych montuję pod poszczególnymi opcjami dodatkowe informacje w ramach klas c# zwane metadata. Żeby klasy mogły trafić do takiego typowo godotowego miejsca muszą rozszerzać typ Node ponieważ przez instrukcję SetItemMetadata(index,metadata) mogę dodać tylko coś co jest widoczne w godot i rozszerza typ Variant

Poniżej przykładowa instrukcja dodania metadanych podczas wypełniania listy rozwijalnej OptionButton dla tarcz

ShieldSelect.GetOptionButton().SetItemMetadata(index, metadata);

Klasa dodana jako metadata to dane pancerza. W tym przypadku pierwszym parametrem jest definicja tarczy z jsona, Drugim parametrem jest grupa, do której ta tarcza należy.

 var metadata = new ArmourMetadata(shield, shieldGroup.Key);

Ważna jest jednak definicja klasy ArmourMetadata a nie to co trzyma...


    public partial class ArmourMetadata : Node <-- to te nody najczęściem mi leakują
    {...pola klasy teraz nie są ważne...}

Jak widać rozszerzamy typ Node.

Jak to naprawiać

Ze względu na to, że część list rozwijalnych muszę czyścić i wypełniać na nowo per losowana postać, np. w przypadku broni gdzie chcę na liście oznaczyć, do których broni postać ma preferencyjne bonusy musze listy czyścić i wypełniać ponownie. Tworząc nowe węzły w drzewie...

Nie wystarczy wtedy przeiterować przez kolekcję dzieci dla OptionButtrona jak niżej

foreach (Node child in mentalContainer.GetChildren())
{ reszta kodu z usuwaniem dzieci }

i zrobić na poszczególnych dzieciach child.QueeFree() bo to nie zrzuca metadanych. Potrzeba oddzielnej iteracji po kolekcji metadanych i dodatkowe ich zrzucenie.

Stąd powstała metoda zrzucająca metadane zawarte pod poszczególnymi opcjami

  public void ClearOptionsMetadata()
        {
            for (int i = optionButton.GetItemCount() - 1; i >= 0; i--)
            {
//tu pobieramy metadane
                Variant metadata = optionButton.GetItemMetadata(i);

                if (metadata.VariantType == Variant.Type.Object)
                {
                    Node node = metadata.As<Node>();
                    if (node.IsInsideTree())
                    {
//tu zrzucamy jeśli są wezłem w drzewie
                        node.QueueFree();
                    }
                }
                optionButton.RemoveItem(i);
            }
        }

Podejrzewam, że będę musiał wywołać tę metodę na jakimś ogólnym Dispose() dla obiektów...

24 listopada 2025

To ja go tnę!

Udało się (prawie, patrz na koniec wpisu) dodać losowanie biegłości postaci  i wybór broni oraz pancerzy. To jest na prawdę masa kodu. Zasady w KC są niemiłosiernie skomplikowane w tym aspekcie i przerzucenie ich do postaci klas c# zajęło mi bardzo dużo czasu. 

ALE działa i jest.


Stan wyjściowy po wylosowaniu bohatera.


Dodanie broni do postaci

Podbicie specjalizacji do podwójnie biegłego

Dodanie zbroi


I cyk tarcza
    
Nie ograniczamy się też do jednej możliwej broni, można mieć ich wiele.

Albo i kilka z jednej grupy. Tu espadon i miecz półtoraręczny.



Współczynniki przeliczane są na bieżąco. 


Błędy? Jakie błędy!

Mechanizm ma jeszcze kilka wizualnych błędów, np. po dodaniu tarcz nagle przestał mi działać podgląd wybranych broni w zakładce broni i widać tylko ostatnią.  Inna niedoróbka to nie uwzględnianie wzrostu biegłości per poziom postaci czy pancerza naturalnego wynikającego ze skóry. Są to już jednak drobiazgi w porównaniu z całym mechanizmem
Ważne, że się pojawił. Błędy to rzecz pewna w tak rozbudowanym kodzie.

19 listopada 2025

Krótki wpis o broni

 Może to i mała aktualizacja ale jakże ważna w kontekście całego generatora. Do postaci można dodać broń i wylosować biegłość. Nie działa to jeszcze idealnie (miałem mało czasu na zrobienie tej zmiany), ale dzięki tak małym i działającym modyfikacjom chce się pisać dalej. 


Może i nie ma wszystkich parametrów ale ważne
jest że się pojawiają w opisie bohatera.



Leaked instance

Z niedoróbek - w kodzie często posługuję się klasami od typu `Node` i jeśli taki typ źle się zrzuca z pamięci nie używając polecania  

      public void Dispose()
        {
            QueueFree();
        }
   

dochodzi do wycieków... 

Przy zamykaniu aplikacji są ich ... dziesiątki :D. Pomyślę kiedyś czy to porawiać



16 listopada 2025

Więcej pomysłów niż dostępnego czasu

 Kilka ostatnich dni pozwoliło mi na wprowadzenie sporej ilości zmian w generatorze. Problematyczne stało się to, że rozgrzebałem jednocześnie kilka funkcjonalności i żadna nie działa tak jak powinna, a ja przeskakuję na kolejną i tu trochę kodu wrzucę, tam dodam trzy linijki... Przy takim trybie pisania ciężko kończy  się jakikolwiek projekt. Postaram się poniżej opisać co dodałem i może takie podsumowanie pozwoli mi na spojrzenie z góry na projekt i dokończenie po kolei rozgrzebanych elementów.

Dwie profesje

Dodałem możliwość wybrania dwóch profesji do generowanej postaci oraz uwzględnieniu w nich poziomów zaawansowania. Spora zmiana na plus względem poprzedniego podejścia do tego tematu. Teraz wiem skąd wynikają wartości składające się na cechy oraz raczej nie ma w tym błędów (tak mi się przynajmniej wydaje) Stworzenie opisanej wcześniej meta-profesji z dwóch było dobrym kierunkiem.

Postać dwu profesyjna z uwzględnionymi w cechach
poziomami per profesja

Na zakładce statystyk widać skąd wynika suma. Tu  
Żywotność dla poziomów 1-3 została powiększona o większą 
wartość wynikającą z profesji Wojownika a poziomy 4-5 już z Kupca

I tu pierwsza (grubsza) niedoróbka,
Na zakładce z odpornościami można dodać
bonus wnikający z poziomów ale tylko do.... odporności psychicznej

Plus jest taki że przynajmniej dobrze się liczy. 
Musze dodać jakichś... checkbox czy coś wskazujący,
w którą bazową pompujesz rzuty.


Zakładka Broni

Dodałem dwie nowe zakładki do generatora, w których będzie można dopełnić definicje postaci. Pierwsza z nich to zakładka broni.

Rzeczona zakładka

Wybór będzie standardowy - dobieramy grupę broni, dobieramy broń i losujemy biegłość. Na razie pracuję nad tym, aby w ogóle działała poprawnie, a postać prawidłowo się aktualizowała.

Wybór grup broni

Wybór broni noszonej przez postać

I efekt wyboru broni do postaci. Jak widać prace nad nim trwają.

Bez kłopotu można dobrać wiele broni.


W tej zakładce kryje się multum logiki i do tej pory pokryłem niewielką  jej część. Podstawowe problemy to oznaczenie, że broń jest preferowana w kontekście wybranej rasy i później zawodu (vide profesja Kowal i jego bonus do młotów) . Generator musi też wiedzieć jakie grupy broni wylosowano żeby per wybór np. różnych mieczy nie losował biegłości wielokrotnie, podobnie z poziomem biegłości, oburęcznością itp. itd. Znawcy zasad KC-tów wiedzą, że to ciężki kawałek charakterystyki postaci. Później trzeba do tego dodać cechy postaci, przeliczyć możliwe obrażenia (możliwe 6! rodzajów - ponieważ broń może być do walki wręcz i zasięgowa). W skrócie multum kodu. Na koniec trzeba to wyświetlić na podsumowaniu postaci w kc-towym szablonie.


Zakładka Zbroje

Tutaj na szczęście nie będzie jakichś cudów. Jest o wiele prostsza niż to co jest w zakładce broni. Wybór elementu i wrzucenie do cech w postać. Praca jest zaledwie rozgrzebana do poziomu wczytania listy pancerzy i tarcz na ekran.

Wybór pancerza

I sam efekt rozwinięcia listy. Jak łatwo zauważyć
 sama lista rozwijalna ma pewne niedoróbki.

I tyle można zrobić, wybrane elementy nigdzie nie są uwzględniane.


Podsumowując

Zostało jeszcze sporo od napisania. Z samego c# i godota zaczęły przychodzić mi z pomocą EventHandlery ponieważ zwykłe przenoszenie do głównego kontrolera informacji o zmianach na zakładce broni jest tak rozbudowane, że w przypadku próby zbudowania tego przez zwyczajne przenoszenie danych między klasami doprowadziłoby do powstania kilkudziesięciu metod mających tylko za zadanie przerzucania stanu.

Stąd też powstała klasa-singleton trzymająca definicje sygnałów (powoli skłaniam się do podzielenia jej per zakładka oraz per główne akcje na ekranie).

using Godot;
using OptionsMetadata;

partial class GeneratorSignal : Node
{
    [Signal]
    public delegate void AddLevelClickedEventHandler(int index);

    [Signal]
    public delegate void CharacterReadyEventHandler();

    [Signal]
    public delegate void ReloadCharacterEventHandler(CharacterSheet character);

    [Signal]
    public delegate void CharacterChangedEventHandler();

    [Signal]
    public delegate void WeaponGropupRemovedEventHandler(WeaponMetadata metadata);

    [Signal]
    public delegate void WeaponSkillIncreaseEventHandler(WeaponMetadata metadata);

    [Signal]
    public delegate void WeaponDoubleHandAddedEventHandler(WeaponMetadata metadata);

    [Signal]
    public delegate void WeaponSkilUpdatedEventHandler(WeaponMetadata metadata);

    private static readonly GeneratorSignal _Instance = new();

    private GeneratorSignal() { }

    public static GeneratorSignal Instance
    {
        get { return _Instance; }
    }
}

I zwykła obsługa emisji sygnałów przez Emit

    public void OnAddDoubleHandPressed()
    {
        GeneratorSignal.Instance.EmitSignal(
            GeneratorSignal.SignalName.WeaponDoubleHandAdded,
            weaponMetadata
        );
    }


i przechwytywania przez Connect i obsługa Callable

private void ConnectSignals()
    {
        GeneratorSignal.Instance.Connect(
            GeneratorSignal.SignalName.AddLevelClicked,
            new Callable(this, nameof(OnSomethingHappened))
        );

        GeneratorSignal.Instance.Connect(
            GeneratorSignal.SignalName.CharacterChanged,
            new Callable(this, nameof(CharacterChanged))
        );
    }

 

02 listopada 2025

Zmian ciąg dalszy

Udało mi się przenieść część funkcjonalności do nowego szablonu i już teraz widzę że generator jest wygodniejszy w użyciu nie tylko za sprawą  ładniejszego gui, ale jako sama baza kodu. Zrobiłem spory refaktor, przepakietowanie, jakieś poprawki nazewnictwa i namespaców. Całkowicie przebudowałem część odpowiedzialną za dobieranie cech w przypadku więcej niż jednej profesji. 

Algorytm

W poprzedniej wersji algorytmu przy dwóch profesjach losowałem dwie postacie i dobierałem wartości wylosowanych cech zgodnie z ich kolejnością losowania przy czym do końcowego podsumowania przenoszona była wyższa wartość. Jednakże bardzo trudno było sprawdzić czy cechy zostały dobrze dobrane, czy prawidłowo się połączyły i czy w ogóle końcowy efekt jest poprawny (zwykle nie był). Przeliczenie odporności stało się za skomplikowane i byłem pewien nieprawidłowych wartości w podsumowaniu postaci. Musiałem podjąć drastyczne kroki. Cały ten kod wyrzuciłem i napisałem od nowa.

Aktualna wersja działa inaczej. Przy dwóch profesjach tworzę meta profesję, do której dobieram tylko lepsze (wyższe) cechy z wybranych profesji. Dzięki temu generator cech i odporności uruchamiany jest jeden raz (tak jakby to była jedna profesja) i nie ma problemu z modyfikacjami współczynników wynikających z innych kroków generatora np. wagi postaci. Nie muszę uruchamiać algorytmu łączącego dwie wylosowane postacie i dobierającego lepsze cechy. 

Stan wyjściowy generatora


Na zrzucie widać generowanie wojownika. W logu pod przyciskiem losowania 
widać jakie cechy zostały dobrane do profesji z jakimi kostkami i takimi tam
sterującymi rzeczami. Docelowo log będzie wyświetlał postać
w szablonie znanym z kryształów.


Teraz dwie profesje - Barbarzyńca/Astrolog i zebrane cechy 
profesji. Jak widać dla barbarzyńcy 20+ to HP/SF/ZR/SZ ale już z 
astrologa 20+ dla MD/WI oraz +10 IQ/CH/UM. Podobnie zostały dobrane 
odporności - te większe. Jeśli byłaby możliwa taka konfiguracja
profesji to jedynie Elektryczność nie będzie zwiększana rzutem.
To te -1 przy parametrze BaseProfession dla tej odporności oraz D0 (dice 0 )

Testy

Ach bym prawie zapomniał - do projektu dodałem kilka prostackich testów. W c# nigdy ich nie pisałem także jest to dla mnie terra incognita. Mam nadzieję, że wspomogą mnie w pracy nad projektem ... o ile będzie mi się chciało powiększać ich bazę.