void SpawnConditionManager::ReloadEvent(uint32 event_id) { string zone_short_name; _log(SPAWNS__CONDITIONS, "Requested to reload event %d from the database.", event_id); //first look for the event in our local event list vector<SpawnEvent>::iterator cur,end; cur = spawn_events.begin(); end = spawn_events.end(); for(; cur != end; cur++) { SpawnEvent &cevent = *cur; if(cevent.id == event_id) { //load the event into the old event slot if(!LoadDBEvent(event_id, cevent, zone_short_name)) { //unable to find the event in the database... _log(SPAWNS__CONDITIONS, "Failed to reload event %d from the database.", event_id); return; } //sync up our nearest event FindNearestEvent(); return; } } //if we get here, it is a new event... SpawnEvent e; if(!LoadDBEvent(event_id, e, zone_short_name)) { //unable to find the event in the database... _log(SPAWNS__CONDITIONS, "Failed to reload event %d from the database.", event_id); return; } //we might want to check the next timer like we do on //regular load events, but we are assuming this is a new event //and anyways, this will get handled (albeit not optimally) //naturally by the event handling code. spawn_events.push_back(e); //sync up our nearest event FindNearestEvent(); }
void SpawnConditionManager::Process() { if(spawn_events.empty()) return; if(minute_timer.Check()) { //check each spawn event. //get our current time TimeOfDay_Struct tod; zone->zone_time.GetCurrentEQTimeOfDay(&tod); //see if time is past our nearest event. if(EQTime::IsTimeBefore(&next_event, &tod)) return; //at least one event should get triggered, std::vector<SpawnEvent>::iterator cur,end; cur = spawn_events.begin(); end = spawn_events.end(); for(; cur != end; ++cur) { SpawnEvent &cevent = *cur; if(cevent.enabled) { if(EQTime::IsTimeBefore(&tod, &cevent.next)) { //this event has been triggered. //execute the event if(!cevent.strict || (cevent.strict && cevent.next.hour == tod.hour && cevent.next.day == tod.day && cevent.next.month == tod.month && cevent.next.year == tod.year)) ExecEvent(cevent, true); //add the period of the event to the trigger time EQTime::AddMinutes(cevent.period, &cevent.next); std::string t; EQTime::ToString(&cevent.next, t); Log(Logs::Detail, Logs::Spawns, "Event %d: Will trigger again in %d EQ minutes at %s.", cevent.id, cevent.period, t.c_str()); //save the next event time in the DB UpdateDBEvent(cevent); //find the next closest event timer. FindNearestEvent(); //minor optimization, if theres no more possible events, //then stop trying... I dunno how worth while this is. if(EQTime::IsTimeBefore(&next_event, &tod)) return; } } } } }
bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id) { char errbuf[MYSQL_ERRMSG_SIZE]; char* query = 0; MYSQL_RES *result; MYSQL_ROW row; int len; //clear out old stuff.. spawn_conditions.clear(); //load spawn conditions SpawnCondition cond; len = MakeAnyLenString(&query, "SELECT id, onchange, value FROM spawn_conditions WHERE zone='%s'", zone_name); if (database.RunQuery(query, len, errbuf, &result)) { safe_delete_array(query); while((row = mysql_fetch_row(result))) { cond.condition_id = atoi(row[0]); cond.value = atoi(row[2]); cond.on_change = (SpawnCondition::OnChange) atoi(row[1]); spawn_conditions[cond.condition_id] = cond; _log(SPAWNS__CONDITIONS, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change); } mysql_free_result(result); } else { LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf); safe_delete_array(query); return false; } //load values len = MakeAnyLenString(&query, "SELECT id, value FROM spawn_condition_values WHERE zone='%s' and instance_id=%u", zone_name, instance_id); if (database.RunQuery(query, len, errbuf, &result)) { safe_delete_array(query); while((row = mysql_fetch_row(result))) { std::map<uint16, SpawnCondition>::iterator iter = spawn_conditions.find(atoi(row[0])); if(iter != spawn_conditions.end()) { iter->second.value = atoi(row[1]); } } mysql_free_result(result); } else { LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions query '%s': %s", query, errbuf); safe_delete_array(query); spawn_conditions.clear(); return false; } //load spawn events SpawnEvent event; len = MakeAnyLenString(&query, "SELECT id,cond_id,period,next_minute,next_hour,next_day,next_month,next_year,enabled,action,argument " "FROM spawn_events WHERE zone='%s'", zone_name); if (database.RunQuery(query, len, errbuf, &result)) { safe_delete_array(query); while((row = mysql_fetch_row(result))) { event.id = atoi(row[0]); event.condition_id = atoi(row[1]); event.period = atoi(row[2]); if(event.period == 0) { LogFile->write(EQEMuLog::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id); continue; } event.next.minute = atoi(row[3]); event.next.hour = atoi(row[4]); event.next.day = atoi(row[5]); event.next.month = atoi(row[6]); event.next.year = atoi(row[7]); event.enabled = atoi(row[8])==0?false:true; event.action = (SpawnEvent::Action) atoi(row[9]); event.argument = atoi(row[10]); spawn_events.push_back(event); _log(SPAWNS__CONDITIONS, "Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d", event.enabled?"enabled":"disabled", event.id, event.condition_id, event.period, event.action, event.argument); } mysql_free_result(result); } else { LogFile->write(EQEMuLog::Error, "Error in LoadSpawnConditions events query '%s': %s", query, errbuf); safe_delete_array(query); return false; } //now we need to catch up on events that happened while we were away //and use them to alter just the condition variables. //each spawn2 will then use its correct condition value when //it decides what to do. This essentially forces a 'depop' action //on spawn points which are turned off, and a 'repop' action on //spawn points which get turned on. Im too lazy to figure out a //better solution, and I just dont care thats much. //get our current time TimeOfDay_Struct tod; zone->zone_time.getEQTimeOfDay(&tod); vector<SpawnEvent>::iterator cur,end; cur = spawn_events.begin(); end = spawn_events.end(); bool ran; for(; cur != end; cur++) { SpawnEvent &cevent = *cur; if(!cevent.enabled) continue; //watch for special case of all 0s, which means to reset next to now if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) { _log(SPAWNS__CONDITIONS, "Initial next trigger time set for spawn event %d", cevent.id); memcpy(&cevent.next, &tod, sizeof(cevent.next)); //add one period EQTime::AddMinutes(cevent.period, &cevent.next); //save it in the db. UpdateDBEvent(cevent); continue; //were done with this event. } ran = false; while(EQTime::IsTimeBefore(&tod, &cevent.next)) { _log(SPAWNS__CONDITIONS, "Catch up triggering on event %d", cevent.id); //this event has been triggered. //execute the event ExecEvent(cevent, false); //add the period of the event to the trigger time EQTime::AddMinutes(cevent.period, &cevent.next); ran = true; } //only write it out if the event actually ran if(ran) { //save the event in the DB UpdateDBEvent(cevent); } } //now our event timers are all up to date, find our closest event. FindNearestEvent(); return(true); }
void SpawnConditionManager::ToggleEvent(uint32 event_id, bool enabled, bool reset_base) { _log(SPAWNS__CONDITIONS, "Request to %s spawn event %d %sresetting trigger time", enabled?"enable":"disable", event_id, reset_base?"":"without "); //first look for the event in our local event list vector<SpawnEvent>::iterator cur,end; cur = spawn_events.begin(); end = spawn_events.end(); for(; cur != end; cur++) { SpawnEvent &cevent = *cur; if(cevent.id == event_id) { //make sure were actually changing something if(cevent.enabled != enabled || reset_base) { cevent.enabled = enabled; if(reset_base) { _log(SPAWNS__CONDITIONS, "Spawn event %d located in this zone. State set. Trigger time reset (period %d).", event_id, cevent.period); //start with the time now zone->zone_time.getEQTimeOfDay(&cevent.next); //advance the next time by our period EQTime::AddMinutes(cevent.period, &cevent.next); } else { _log(SPAWNS__CONDITIONS, "Spawn event %d located in this zone. State changed.", event_id); } //save the event in the DB UpdateDBEvent(cevent); //sync up our nearest event FindNearestEvent(); } else { _log(SPAWNS__CONDITIONS, "Spawn event %d located in this zone but no change was needed.", event_id); } //even if we dont change anything, we still found it return; } } //if we get here, the condition must be in another zone. //first figure out what zone it applies to. //update the DB and send and send an update packet to //the zone if its up //we need to load the event from the DB and then update //the values in the DB, because we do not know if the zone //is up or not. The message to the zone will just tell it to //update its in-memory event list SpawnEvent e; string zone_short_name; if(!LoadDBEvent(event_id, e, zone_short_name)) { _log(SPAWNS__CONDITIONS, "Unable to find spawn event %d in the database.", event_id); //unable to find the event in the database... return; } if(e.enabled == enabled && !reset_base) { _log(SPAWNS__CONDITIONS, "Spawn event %d is not located in this zone but no change was needed.", event_id); return; //no changes. } e.enabled = enabled; if(reset_base) { _log(SPAWNS__CONDITIONS, "Spawn event %d is in zone %s. State set. Trigger time reset (period %d). Notifying world.", event_id, zone_short_name.c_str(), e.period); //start with the time now zone->zone_time.getEQTimeOfDay(&e.next); //advance the next time by our period EQTime::AddMinutes(e.period, &e.next); } else { _log(SPAWNS__CONDITIONS, "Spawn event %d is in zone %s. State changed. Notifying world.", event_id, zone_short_name.c_str(), e.period); } //save the event in the DB UpdateDBEvent(e); //now notify the zone ServerPacket* pack = new ServerPacket(ServerOP_SpawnEvent, sizeof(ServerSpawnEvent_Struct)); ServerSpawnEvent_Struct* sse = (ServerSpawnEvent_Struct*)pack->pBuffer; sse->zoneID = database.GetZoneID(zone_short_name.c_str()); sse->event_id = event_id; worldserver.SendPacket(pack); safe_delete(pack); }
bool SpawnConditionManager::LoadSpawnConditions(const char* zone_name, uint32 instance_id) { //clear out old stuff.. spawn_conditions.clear(); std::string query = StringFormat("SELECT id, onchange, value " "FROM spawn_conditions " "WHERE zone = '%s'", zone_name); auto results = database.QueryDatabase(query); if (!results.Success()) { return false; } for (auto row = results.begin(); row != results.end(); ++row) { //load spawn conditions SpawnCondition cond; cond.condition_id = atoi(row[0]); cond.value = atoi(row[2]); cond.on_change = (SpawnCondition::OnChange) atoi(row[1]); spawn_conditions[cond.condition_id] = cond; Log(Logs::Detail, Logs::Spawns, "Loaded spawn condition %d with value %d and on_change %d", cond.condition_id, cond.value, cond.on_change); } //load values query = StringFormat("SELECT id, value FROM spawn_condition_values " "WHERE zone = '%s' AND instance_id = %u", zone_name, instance_id); results = database.QueryDatabase(query); if (!results.Success()) { spawn_conditions.clear(); return false; } for (auto row = results.begin(); row != results.end(); ++row) { auto iter = spawn_conditions.find(atoi(row[0])); if(iter != spawn_conditions.end()) iter->second.value = atoi(row[1]); } //load spawn events query = StringFormat("SELECT id, cond_id, period, next_minute, next_hour, " "next_day, next_month, next_year, enabled, action, argument, strict " "FROM spawn_events WHERE zone = '%s'", zone_name); results = database.QueryDatabase(query); if (!results.Success()) { return false; } for (auto row = results.begin(); row != results.end(); ++row) { SpawnEvent event; event.id = atoi(row[0]); event.condition_id = atoi(row[1]); event.period = atoi(row[2]); if(event.period == 0) { Log(Logs::General, Logs::Error, "Refusing to load spawn event #%d because it has a period of 0\n", event.id); continue; } event.next.minute = atoi(row[3]); event.next.hour = atoi(row[4]); event.next.day = atoi(row[5]); event.next.month = atoi(row[6]); event.next.year = atoi(row[7]); event.enabled = atoi(row[8])==0?false:true; event.action = (SpawnEvent::Action) atoi(row[9]); event.argument = atoi(row[10]); event.strict = atoi(row[11])==0?false:true; spawn_events.push_back(event); Log(Logs::Detail, Logs::Spawns, "(LoadSpawnConditions) Loaded %s spawn event %d on condition %d with period %d, action %d, argument %d, strict %d", event.enabled? "enabled": "disabled", event.id, event.condition_id, event.period, event.action, event.argument, event.strict); } //now we need to catch up on events that happened while we were away //and use them to alter just the condition variables. //each spawn2 will then use its correct condition value when //it decides what to do. This essentially forces a 'depop' action //on spawn points which are turned off, and a 'repop' action on //spawn points which get turned on. Im too lazy to figure out a //better solution, and I just dont care thats much. //get our current time TimeOfDay_Struct tod; zone->zone_time.GetCurrentEQTimeOfDay(&tod); for(auto cur = spawn_events.begin(); cur != spawn_events.end(); ++cur) { SpawnEvent &cevent = *cur; bool StrictCheck = false; if(cevent.strict && cevent.next.hour == tod.hour && cevent.next.day == tod.day && cevent.next.month == tod.month && cevent.next.year == tod.year) StrictCheck = true; //If event is disabled, or we failed the strict check, set initial spawn_condition to 0. if(!cevent.enabled || !StrictCheck) SetCondition(zone->GetShortName(), zone->GetInstanceID(),cevent.condition_id,0); if(!cevent.enabled) continue; //watch for special case of all 0s, which means to reset next to now if(cevent.next.year == 0 && cevent.next.month == 0 && cevent.next.day == 0 && cevent.next.hour == 0 && cevent.next.minute == 0) { Log(Logs::Detail, Logs::Spawns, "Initial next trigger time set for spawn event %d", cevent.id); memcpy(&cevent.next, &tod, sizeof(cevent.next)); //add one period EQTime::AddMinutes(cevent.period, &cevent.next); //save it in the db. UpdateDBEvent(cevent); continue; //were done with this event. } bool ran = false; while(EQTime::IsTimeBefore(&tod, &cevent.next)) { Log(Logs::Detail, Logs::Spawns, "Catch up triggering on event %d", cevent.id); //this event has been triggered. //execute the event if(!cevent.strict || StrictCheck) ExecEvent(cevent, false); //add the period of the event to the trigger time EQTime::AddMinutes(cevent.period, &cevent.next); ran = true; } //only write it out if the event actually ran if(ran) UpdateDBEvent(cevent); //save the event in the DB } //now our event timers are all up to date, find our closest event. FindNearestEvent(); return true; }