stabilized app
This commit is contained in:
committed by
Torsten (PC)
parent
51fd9fcd13
commit
1451225978
361
src/usercharacterworker.cpp
Normal file
361
src/usercharacterworker.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
#include "usercharacterworker.h"
|
||||
#include "connection_guard.h"
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
UserCharacterWorker::UserCharacterWorker(ConnectionPool &pool, MessageBroker &broker)
|
||||
: Worker(pool, broker, "UserCharacterWorker"),
|
||||
gen(rd()), dist(0.0, 1.0) {}
|
||||
|
||||
UserCharacterWorker::~UserCharacterWorker() {}
|
||||
|
||||
void UserCharacterWorker::run() {
|
||||
using namespace std::chrono;
|
||||
|
||||
auto lastExecutionTime = steady_clock::now();
|
||||
int lastPregnancyDay = -1;
|
||||
while (runningWorker) {
|
||||
signalActivity();
|
||||
auto nowSteady = steady_clock::now();
|
||||
auto elapsed = duration_cast<seconds>(nowSteady - lastExecutionTime).count();
|
||||
if (elapsed >= 3600) {
|
||||
try {
|
||||
processCharacterEvents();
|
||||
updateCharactersMood();
|
||||
handleCredits();
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "[UserCharacterWorker] Fehler in processCharacterEvents: " << e.what() << std::endl;
|
||||
}
|
||||
lastExecutionTime = nowSteady;
|
||||
}
|
||||
{
|
||||
auto nowSys = system_clock::now();
|
||||
std::time_t t = system_clock::to_time_t(nowSys);
|
||||
std::tm local_tm;
|
||||
localtime_r(&t, &local_tm);
|
||||
if (local_tm.tm_hour == 6 && local_tm.tm_yday != lastPregnancyDay) {
|
||||
try {
|
||||
processPregnancies();
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "[UserCharacterWorker] Fehler in processPregnancies: " << e.what() << std::endl;
|
||||
}
|
||||
lastPregnancyDay = local_tm.tm_yday;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(seconds(1));
|
||||
recalculateKnowledge();
|
||||
}
|
||||
}
|
||||
|
||||
void UserCharacterWorker::processCharacterEvents() {
|
||||
setCurrentStep("Get character data");
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare(QUERY_GET_USERS_TO_UPDATE, QUERY_GET_USERS_TO_UPDATE);
|
||||
auto rows = db.execute(QUERY_GET_USERS_TO_UPDATE);
|
||||
std::vector<Character> characters;
|
||||
for (const auto &row : rows) {
|
||||
characters.push_back({ std::stoi(row.at("id")), std::stoi(row.at("age")), std::stoi(row.at("health")) });
|
||||
}
|
||||
for (auto &character : characters) {
|
||||
updateCharacterHealth(character);
|
||||
}
|
||||
}
|
||||
|
||||
void UserCharacterWorker::updateCharacterHealth(Character& character) {
|
||||
int healthChange = calculateHealthChange(character.age);
|
||||
|
||||
if (healthChange != 0) {
|
||||
character.health = std::max(0, character.health + healthChange);
|
||||
if (character.health == 0) {
|
||||
handleCharacterDeath(character.id);
|
||||
return;
|
||||
}
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_UPDATE_CHARACTERS_HEALTH", QUERY_UPDATE_CHARACTERS_HEALTH);
|
||||
db.execute("QUERY_UPDATE_CHARACTERS_HEALTH",
|
||||
{ std::to_string(character.health), std::to_string(character.id) });
|
||||
}
|
||||
}
|
||||
|
||||
void UserCharacterWorker::updateCharactersMood() {
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_UPDATE_MOOD", QUERY_UPDATE_MOOD);
|
||||
db.execute("QUERY_UPDATE_MOOD");
|
||||
}
|
||||
|
||||
int UserCharacterWorker::calculateHealthChange(int age) {
|
||||
if (age < 30) {
|
||||
return 0;
|
||||
}
|
||||
if (age >= 45) {
|
||||
double probability = std::min(1.0, 0.1 + (age - 45) * 0.02);
|
||||
if (dist(gen) < probability) {
|
||||
return -std::uniform_int_distribution<int>(1, 10)(gen);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
double probability = (age - 30) / 30.0;
|
||||
return (dist(gen) < probability) ? -1 : 0;
|
||||
}
|
||||
|
||||
void UserCharacterWorker::handleCharacterDeath(int characterId) {
|
||||
setHeir(characterId);
|
||||
|
||||
nlohmann::json deathEvent = {
|
||||
{"event", "CharacterDeath"},
|
||||
{"character_id", characterId}
|
||||
};
|
||||
|
||||
broker.publish(deathEvent.dump());
|
||||
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
|
||||
db.prepare("delete_character", "DELETE FROM falukant_data.character WHERE id = $1");
|
||||
db.execute("delete_character", { std::to_string(characterId) });
|
||||
}
|
||||
|
||||
void UserCharacterWorker::setHeir(int characterId) {
|
||||
auto falukantUserId = getFalukantUserId(characterId);
|
||||
auto heirId = getHeirFromChildren(characterId);
|
||||
auto newMoney = calculateNewMoney(falukantUserId, true);
|
||||
if (heirId < 1) {
|
||||
getRandomHeir(characterId);
|
||||
newMoney = calculateNewMoney(falukantUserId, false);
|
||||
}
|
||||
setNewCharacter(falukantUserId, heirId);
|
||||
setNewMoney(falukantUserId, newMoney);
|
||||
}
|
||||
|
||||
int UserCharacterWorker::getFalukantUserId(int characterId) {
|
||||
ConnectionGuard guard(pool);
|
||||
auto &db = guard.get();
|
||||
|
||||
db.prepare("QUERY_GET_FALUKANT_USER_ID", QUERY_GET_FALUKANT_USER_ID);
|
||||
const auto rows = db.execute("QUERY_GET_FALUKANT_USER_ID", { std::to_string(characterId) });
|
||||
if (!rows.empty() && !rows.front().at("user_id").empty()) {
|
||||
return std::stoi(rows.front().at("user_id"));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int UserCharacterWorker::getHeirFromChildren(int deceasedCharacterId) {
|
||||
ConnectionGuard guard(pool);
|
||||
auto &db = guard.get();
|
||||
|
||||
db.prepare("QUERY_GET_HEIR", QUERY_GET_HEIR);
|
||||
const auto rows = db.execute("QUERY_GET_HEIR", { std::to_string(deceasedCharacterId) });
|
||||
if (!rows.empty()) {
|
||||
return std::stoi(rows.front().at("child_character_id"));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int UserCharacterWorker::getRandomHeir(int deceasedCharacterId) {
|
||||
ConnectionGuard guard(pool);
|
||||
auto &db = guard.get();
|
||||
|
||||
db.prepare("QUERY_RANDOM_HEIR", QUERY_RANDOM_HEIR);
|
||||
const auto rows = db.execute("QUERY_RANDOM_HEIR", { std::to_string(deceasedCharacterId) });
|
||||
if (!rows.empty()) {
|
||||
return std::stoi(rows.front().at("child_character_id"));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void UserCharacterWorker::setNewCharacter(int falukantUserId, int heirCharacterId) {
|
||||
if (heirCharacterId < 1) return;
|
||||
|
||||
ConnectionGuard guard(pool);
|
||||
auto &db = guard.get();
|
||||
|
||||
db.prepare("QUERY_SET_CHARACTER_USER", QUERY_SET_CHARACTER_USER);
|
||||
db.execute("QUERY_SET_CHARACTER_USER", {
|
||||
std::to_string(falukantUserId),
|
||||
std::to_string(heirCharacterId)
|
||||
});
|
||||
}
|
||||
|
||||
void UserCharacterWorker::setNewMoney(int falukantUserId, double newAmount) {
|
||||
ConnectionGuard guard(pool);
|
||||
auto &db = guard.get();
|
||||
|
||||
db.prepare("QUERY_UPDATE_USER_MONEY", QUERY_UPDATE_USER_MONEY);
|
||||
db.execute("QUERY_UPDATE_USER_MONEY", {
|
||||
std::to_string(newAmount),
|
||||
std::to_string(falukantUserId)
|
||||
});
|
||||
}
|
||||
|
||||
void UserCharacterWorker::recalculateKnowledge() {
|
||||
setCurrentStep("Get character data");
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_UPDATE_GET_ITEMS_TO_UPDATE", QUERY_UPDATE_GET_ITEMS_TO_UPDATE);
|
||||
auto rows = db.execute("QUERY_UPDATE_GET_ITEMS_TO_UPDATE");
|
||||
for (const auto &updateItem: rows) {
|
||||
if (std::stoi(updateItem.at("quantity")) >= 10) {
|
||||
db.prepare("QUERY_UPDATE_GET_CHARACTER_IDS", QUERY_UPDATE_GET_CHARACTER_IDS);
|
||||
auto charactersData = db.execute("QUERY_UPDATE_GET_CHARACTER_IDS", { updateItem.at("producer_id") });
|
||||
for (const auto &characterRow: charactersData) {
|
||||
db.prepare("QUERY_UPDATE_KNOWLEDGE", QUERY_UPDATE_KNOWLEDGE);
|
||||
if (characterRow.at("director_id") == "") {
|
||||
db.execute("QUERY_UPDATE_KNOWLEDGE", { characterRow.at("character_id"), updateItem.at("product_id"), "2" });
|
||||
} else {
|
||||
db.execute("QUERY_UPDATE_KNOWLEDGE", { characterRow.at("character_id"), updateItem.at("product_id"), "1" });
|
||||
db.execute("QUERY_UPDATE_KNOWLEDGE", { characterRow.at("director_id"), updateItem.at("product_id"), "1" });
|
||||
}
|
||||
}
|
||||
}
|
||||
db.prepare("QUERY_DELETE_LOG_ENTRY", QUERY_DELETE_LOG_ENTRY);
|
||||
db.execute("QUERY_DELETE_LOG_ENTRY", { updateItem.at("id") });
|
||||
const nlohmann::json message = {
|
||||
{"event", "knowledge_update"},
|
||||
};
|
||||
sendMessageToFalukantUsers(std::stoi(updateItem.at("producer_id")), message);
|
||||
}
|
||||
}
|
||||
|
||||
void UserCharacterWorker::processPregnancies() {
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_AUTOBATISM", QUERY_AUTOBATISM);
|
||||
db.execute("QUERY_AUTOBATISM");
|
||||
db.prepare("get_candidates", QUERY_GET_PREGNANCY_CANDIDATES);
|
||||
auto rows = db.execute("get_candidates");
|
||||
const nlohmann::json message = {
|
||||
{"event", "children_update"},
|
||||
};
|
||||
for (auto const &row : rows) {
|
||||
int fatherCid = std::stoi(row.at("father_cid"));
|
||||
int motherCid = std::stoi(row.at("mother_cid"));
|
||||
int fatherUid = std::stoi(row.at("father_uid"));
|
||||
int motherUid = std::stoi(row.at("mother_uid"));
|
||||
int titleOfNobility = std::stoi(row.at("title_of_nobility"));
|
||||
int lastName = std::stoi(row.at("last_name"));
|
||||
int regionId = std::stoi(row.at("region_id"));
|
||||
std::string gender = (dist(gen) < 0.5) ? "male" : "female";
|
||||
db.prepare("insert_child", QUERY_INSERT_CHILD);
|
||||
auto resChild = db.execute("insert_child", {
|
||||
std::to_string(regionId), // $1
|
||||
gender, // $2
|
||||
std::to_string(lastName), // $3
|
||||
std::to_string(titleOfNobility) // $4
|
||||
});
|
||||
int childCid = std::stoi(resChild.front().at("child_cid"));
|
||||
db.prepare("insert_relation", QUERY_INSERT_CHILD_RELATION);
|
||||
auto resRel = db.execute("insert_relation", {
|
||||
std::to_string(fatherCid),
|
||||
std::to_string(motherCid),
|
||||
std::to_string(childCid)
|
||||
});
|
||||
const nlohmann::json message = {{"event", "children_update"}};
|
||||
sendMessageToFalukantUsers(fatherUid, message);
|
||||
sendMessageToFalukantUsers(motherUid, message);
|
||||
}
|
||||
}
|
||||
|
||||
void UserCharacterWorker::handleCredits() {
|
||||
ConnectionGuard connGuard(pool);
|
||||
auto &db = connGuard.get();
|
||||
db.prepare("QUERY_GET_OPEN_CREDITS", QUERY_GET_OPEN_CREDITS);
|
||||
const auto &credits = db.execute("QUERY_GET_OPEN_CREDITS");
|
||||
const nlohmann::json message = {
|
||||
{ "event", "falukantUpdateStatus" }
|
||||
};
|
||||
db.prepare("QUERY_UPDATE_CREDIT", QUERY_UPDATE_CREDIT);
|
||||
db.prepare("QUERY_ADD_CHARACTER_TO_DEBTORS_PRISM", QUERY_ADD_CHARACTER_TO_DEBTORS_PRISM);
|
||||
for (const auto &credit: credits) {
|
||||
const auto userMoney = std::stod(credit.at("money"));
|
||||
auto remainingAmount = std::stod(credit.at("remaining_amount"));
|
||||
const auto amount = std::stod(credit.at("amount"));
|
||||
const auto fee = std::stoi(credit.at("interest_rate"));
|
||||
const auto falukantUserId = std::stoi(credit.at("user_id"));
|
||||
const auto payRate = amount / 10 + amount * fee / 100;
|
||||
remainingAmount -= payRate;
|
||||
if (payRate <= userMoney - (payRate * 3)) {
|
||||
changeFalukantUserMoney(falukantUserId, -payRate, "credit pay rate", message);
|
||||
} else {
|
||||
if (credit.at("prism_started_previously") == "t") {
|
||||
changeFalukantUserMoney(falukantUserId, payRate, "debitor_prism", message);
|
||||
} else {
|
||||
db.execute("QUERY_ADD_CHARACTER_TO_DEBTORS_PRISM", { credit.at("character_id") });
|
||||
}
|
||||
}
|
||||
db.execute("QUERY_UPDATE_CREDIT", { std::to_string(remainingAmount), std::to_string(falukantUserId) });
|
||||
}
|
||||
db.prepare("QUERY_CLEANUP_CREDITS", QUERY_CLEANUP_CREDITS);
|
||||
db.execute("QUERY_CLEANUP_CREDITS");
|
||||
}
|
||||
|
||||
double UserCharacterWorker::getCurrentMoney(int falukantUserId) {
|
||||
ConnectionGuard g(pool); auto &db = g.get();
|
||||
db.prepare("GET_CURRENT_MONEY", QUERY_GET_CURRENT_MONEY);
|
||||
auto rows = db.execute("GET_CURRENT_MONEY", {std::to_string(falukantUserId)});
|
||||
return rows.empty()? 0.0 : std::stod(rows.front().at("sum"));
|
||||
}
|
||||
|
||||
double UserCharacterWorker::getHouseValue(int falukantUserId) {
|
||||
ConnectionGuard g(pool); auto &db = g.get();
|
||||
db.prepare("HOUSE_VALUE", QUERY_HOUSE_VALUE);
|
||||
auto rows = db.execute("HOUSE_VALUE", {std::to_string(falukantUserId)});
|
||||
return rows.empty()? 0.0 : std::stod(rows.front().at("sum"));
|
||||
}
|
||||
|
||||
double UserCharacterWorker::getSettlementValue(int falukantUserId) {
|
||||
ConnectionGuard g(pool); auto &db = g.get();
|
||||
db.prepare("SETTLEMENT_VALUE", QUERY_SETTLEMENT_VALUE);
|
||||
auto rows = db.execute("SETTLEMENT_VALUE", {std::to_string(falukantUserId)});
|
||||
return rows.empty()? 0.0 : std::stod(rows.front().at("sum"));
|
||||
}
|
||||
|
||||
double UserCharacterWorker::getInventoryValue(int falukantUserId) {
|
||||
ConnectionGuard g(pool); auto &db = g.get();
|
||||
db.prepare("INVENTORY_VALUE", QUERY_INVENTORY_VALUE);
|
||||
auto rows = db.execute("INVENTORY_VALUE", {std::to_string(falukantUserId)});
|
||||
return rows.empty()? 0.0 : std::stod(rows.front().at("sum"));
|
||||
}
|
||||
|
||||
double UserCharacterWorker::getCreditDebt(int falukantUserId) {
|
||||
ConnectionGuard guard(pool);
|
||||
auto &db = guard.get();
|
||||
|
||||
db.prepare("CREDIT_DEBT", QUERY_CREDIT_DEBT);
|
||||
auto rows = db.execute("CREDIT_DEBT", { std::to_string(falukantUserId) });
|
||||
return rows.empty()
|
||||
? 0.0
|
||||
: std::stod(rows.front().at("sum"));
|
||||
}
|
||||
|
||||
int UserCharacterWorker::getChildCount(int deceasedUserId) {
|
||||
ConnectionGuard g(pool); auto &db = g.get();
|
||||
db.prepare("COUNT_CHILDREN", QUERY_COUNT_CHILDREN);
|
||||
auto rows = db.execute("COUNT_CHILDREN", {std::to_string(deceasedUserId)});
|
||||
return rows.empty()? 0 : std::stoi(rows.front().at("cnt"));
|
||||
}
|
||||
|
||||
double UserCharacterWorker::calculateNewMoney(int falukantUserId, bool hasHeir) {
|
||||
if (!hasHeir) {
|
||||
return 800.0;
|
||||
}
|
||||
double cash = getCurrentMoney(falukantUserId);
|
||||
double houses = getHouseValue(falukantUserId);
|
||||
double sets = getSettlementValue(falukantUserId);
|
||||
double inv = getInventoryValue(falukantUserId);
|
||||
double debt = getCreditDebt(falukantUserId);
|
||||
double totalAssets = cash + houses + sets + inv - debt;
|
||||
int childCount = getChildCount(falukantUserId);
|
||||
bool single = (childCount <= 1);
|
||||
double heirShare = single ? totalAssets : totalAssets * 0.8;
|
||||
double net = heirShare - (houses + sets + inv + debt);
|
||||
if (net <= 1000.0) {
|
||||
return 1000.0;
|
||||
}
|
||||
return net;
|
||||
}
|
||||
Reference in New Issue
Block a user