#pragma once #include "worker.h" #include #include #include #include #include #include #include class CharacterCreationWorker : public Worker { public: CharacterCreationWorker(ConnectionPool &pool, MessageBroker &broker); ~CharacterCreationWorker() override; protected: void run() override; private: std::mt19937 gen; std::uniform_int_distribution dist; std::unordered_map> first_name_cache; std::unordered_set last_name_cache; std::atomic deathCheckRunning{true}; std::thread deathThread; bool isTodayCharacterCreated(); void createCharactersForToday(); void createCharactersForRegion(int region_id); void createCharacter(int region_id, const std::string &gender, int title_of_nobility); std::vector getTownRegionIds(); void loadNames(); int getRandomFromSet(const std::unordered_set &name_set); void monitorCharacterDeaths(); void handleCharacterDeath(int characterId); void notifyUser(int userId, const std::string &eventType); void markCharacterAsDeceased(int characterId); bool calculateDeathProbability(int age); static constexpr const char *QUERY_IS_PREVIOUS_DAY_CHARACTER_CREATED = R"( SELECT created_at FROM falukant_data."character" WHERE user_id IS NULL AND created_at::date = CURRENT_DATE ORDER BY created_at DESC LIMIT 1; )"; static constexpr const char *QUERY_GET_TOWN_REGION_IDS = R"( SELECT fdr.id FROM falukant_data.region fdr JOIN falukant_type.region ftr ON fdr.region_type_id = ftr.id WHERE ftr.label_tr = 'city'; )"; static constexpr const char *QUERY_LOAD_FIRST_NAMES = R"( SELECT id, gender FROM falukant_predefine.firstname; )"; static constexpr const char *QUERY_LOAD_LAST_NAMES = R"( SELECT id FROM falukant_predefine.lastname; )"; static constexpr const char *QUERY_INSERT_CHARACTER = R"( INSERT INTO falukant_data."character"( user_id, region_id, first_name, last_name, birthdate, gender, created_at, updated_at, title_of_nobility ) VALUES (NULL, $1, $2, $3, NOW(), $4, NOW(), NOW(), $5); )"; static constexpr const char *QUERY_GET_ELIGIBLE_NPC_FOR_DEATH = R"( WITH aged AS ( SELECT c.id, (current_date - c.birthdate::date) AS age, c.user_id FROM falukant_data."character" c WHERE c.user_id IS NULL AND (current_date - c.birthdate::date) > 60 ), always_sel AS ( -- Immer mitnehmen: alle über 85 Tage SELECT * FROM aged WHERE age > 85 ), random_sel AS ( -- Zufallsstichprobe: alle zwischen 61 und 85 Tagen, hier beispielhaft auf 10 limitiert SELECT * FROM aged WHERE age <= 85 ORDER BY random() LIMIT 10 -- <-- hier die gewünschte Anzahl anpassen ) -- Zusammenführen der beiden Mengen SELECT * FROM always_sel UNION ALL SELECT * FROM random_sel; )"; static constexpr const char *QUERY_DELETE_DIRECTOR = R"( DELETE FROM falukant_data.director WHERE director_character_id = $1 RETURNING employer_user_id; )"; static constexpr const char *QUERY_DELETE_RELATIONSHIP = R"( WITH deleted AS ( DELETE FROM falukant_data.relationship WHERE character1_id = $1 OR character2_id = $1 RETURNING CASE WHEN character1_id = $1 THEN character2_id ELSE character1_id END AS related_character_id, relationship_type_id ) SELECT c.user_id AS related_user_id FROM deleted d JOIN falukant_data."character" c ON c.id = d.related_character_id; )"; static constexpr const char *QUERY_DELETE_CHILD_RELATION = R"( WITH deleted AS ( DELETE FROM falukant_data.child_relation WHERE child_character_id = $1 RETURNING father_character_id, mother_character_id ) SELECT cf.user_id AS father_user_id, cm.user_id AS mother_user_id FROM deleted d JOIN falukant_data."character" cf ON cf.id = d.father_character_id JOIN falukant_data."character" cm ON cm.id = d.mother_character_id; )"; static constexpr const char *QUERY_INSERT_NOTIFICATION = R"( INSERT INTO falukant_log.notification (user_id, tr, shown, created_at, updated_at) VALUES ($1, 'director_death', false, NOW(), NOW()); )"; static constexpr const char *QUERY_MARK_CHARACTER_DECEASED = R"( DELETE FROM falukant_data."character" WHERE id = $1; )"; };