void client_handler(int client_socket, server_parameters * parameters) { to_log(&logger, "Client handler started: Worker %d\n", getpid()); char buffer[1024]; int read = recv(client_socket, buffer, 1024, MSG_NOSIGNAL); while (1) { if (read == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { // should retry continue; } else if (read <= 0) { to_log(&logger, "Worker %d: client discontected\n", getpid()); break; } else { to_log(&logger, "Worker %d: received request: %s", getpid(), buffer); int response_length = 0; char * response = handle_http_request(buffer, read, &response_length, parameters->directory); to_log(&logger, "Worker %d: sending response: %s", getpid(), response); send(client_socket, response, response_length, MSG_NOSIGNAL); free(response); close(client_socket); break; } } exit(0); }
int main(int argc, char **argv) { printf("Starting Simple Http Server...\n"); struct server_parameters server_parameters; if (parse_arguments(argc, argv, &server_parameters) < 0) { printf("Failed to parse cmd arguments\n"); goto exit; } printf("Server parameters: "); print_server_parameters(&server_parameters); printf("\n"); if (daemonize() < 0) { printf("Failed to become daemon process.\n"); goto exit; } if (logger_init(&logger, LOG_FILE) < 0) { exit(-2); } to_log(&logger, "Simple http server with pid %d started logging.\n", getpid()); /* lets remove dead processes */ struct sigaction sa; sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { to_log(&logger, "Failed to set up SIGCHLD handler: %d\n", strerror(errno)); goto exit_with_logging; } accept_clients_loop(&server_parameters); sleep(3); to_log(&logger, "Simple http server is stopping.\n"); exit_with_logging: logger_close(&logger); exit: return 0; }
void run_client_handler(int client_socket, server_parameters * parameters) { pid_t pid = fork(); if (pid < 0) { to_log(&logger, "Failed to fork client handler process:\n", strerror(errno)); } else if (pid > 0) { // this is a server process, nothing to do return; } else { // this is a process to handle client client_handler(client_socket, parameters); } }
void usage_report() { if(!usage_per_30min.empty()) { // compute average: int sum = 0; for(vector<short>::const_iterator i = usage_per_30min.begin(); i != usage_per_30min.end(); ++i) sum += *i; to_log("Average presence: " + lex_cast_fl(float(sum)/usage_per_30min.size())); usage_per_30min.clear(); } }
void write_player_stats() { string fname = Config::get_config_dir() + playerfilename; ofstream file(fname.c_str(), ios_base::binary); if(!file) { to_log("ERROR: could not open player data for writing!"); return; } file.write(reinterpret_cast<const char*>(&STAT_VERSION), sizeof(short)); short numpl; if((signed int)(known_players.size()) > MAX_STORED_PLAYERS) numpl = MAX_STORED_PLAYERS; else // this is done like this 'cuz basically the size can be more than a short fits numpl = known_players.size(); // Note that when called between maps we are writing bots' stats into the // file, too! file.write(reinterpret_cast<char*>(&numpl), sizeof(short)); for(list<PlayerStats>::iterator it = known_players.begin(); it != known_players.end(); ++it) { file.write(reinterpret_cast<char*>(&it->ID), sizeof(short)); file.write(known_players.front().password, PASSW_LEN); file.write(reinterpret_cast<char*>(it->kills), MAX_WAY_TO_KILL*sizeof(long)); file.write(reinterpret_cast<char*>(&it->deaths), sizeof(long)); file.write(reinterpret_cast<char*>(&it->tks), sizeof(long)); file.write(reinterpret_cast<char*>(&it->healing_recvd), sizeof(long)); file.write(reinterpret_cast<char*>(&it->total_time), sizeof(long)); file.write(reinterpret_cast<char*>(&it->time_specced), sizeof(long)); file.write(reinterpret_cast<char*>(it->time_played), NO_CLASS*sizeof(long)); file.write(reinterpret_cast<char*>(&it->arch_hits), sizeof(long)); file.write(reinterpret_cast<char*>(&it->arch_shots), sizeof(long)); file.write(reinterpret_cast<char*>(&it->cm_hits), sizeof(long)); file.write(reinterpret_cast<char*>(&it->cm_shots), sizeof(long)); file.write(reinterpret_cast<char*>(&it->ad_lvl), sizeof(e_AdminLvl)); file.write(reinterpret_cast<char*>(&it->last_seen), sizeof(time_t)); numpl = it->last_known_as.size(); file.write(reinterpret_cast<char *>(&numpl), sizeof(short)); file.write(it->last_known_as.c_str(), numpl); } }
static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data; dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params; int ch = 0; int nodes = p->basecurve_nodes[ch]; dt_iop_basecurve_node_t *basecurve = p->basecurve[ch]; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); const int inset = DT_GUI_CURVE_EDITOR_INSET; int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; c->mouse_x = CLAMP(event->x - inset, 0, width); c->mouse_y = CLAMP(event->y - inset, 0, height); const float mx = c->mouse_x / (float)width; const float my = 1.0f - c->mouse_y / (float)height; const float linx = to_lin(mx, c->loglogscale), liny = to_lin(my, c->loglogscale); if(event->state & GDK_BUTTON1_MASK) { // got a vertex selected: if(c->selected >= 0) { basecurve[c->selected].x = linx; basecurve[c->selected].y = liny; // delete vertex if order has changed: if(nodes > 2) if((c->selected > 0 && basecurve[c->selected - 1].x >= linx) || (c->selected < nodes - 1 && basecurve[c->selected + 1].x <= linx)) { for(int k = c->selected; k < nodes - 1; k++) { basecurve[k].x = basecurve[k + 1].x; basecurve[k].y = basecurve[k + 1].y; } c->selected = -2; // avoid re-insertion of that point immediately after this p->basecurve_nodes[ch]--; } dt_dev_add_history_item(darktable.develop, self, TRUE); } else if(nodes < 20 && c->selected >= -1) { // no vertex was close, create a new one! if(basecurve[0].x > linx) c->selected = 0; else for(int k = 1; k < nodes; k++) { if(basecurve[k].x > linx) { c->selected = k; break; } } if(c->selected == -1) c->selected = nodes; for(int i = nodes; i > c->selected; i--) { basecurve[i].x = basecurve[i - 1].x; basecurve[i].y = basecurve[i - 1].y; } // found a new point basecurve[c->selected].x = linx; basecurve[c->selected].y = liny; p->basecurve_nodes[ch]++; dt_dev_add_history_item(darktable.develop, self, TRUE); } } else { // minimum area around the node to select it: float min = .04f; min *= min; // comparing against square int nearest = -1; for(int k = 0; k < nodes; k++) { float dist = (my - to_log(basecurve[k].y, c->loglogscale)) * (my - to_log(basecurve[k].y, c->loglogscale)) + (mx - to_log(basecurve[k].x, c->loglogscale)) * (mx - to_log(basecurve[k].x, c->loglogscale)); if(dist < min) { min = dist; nearest = k; } } c->selected = nearest; } gtk_widget_queue_draw(widget); return TRUE; }
static gboolean dt_iop_basecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data; dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params; int nodes = p->basecurve_nodes[0]; dt_iop_basecurve_node_t *basecurve = p->basecurve[0]; if(c->minmax_curve_type != p->basecurve_type[0] || c->minmax_curve_nodes != p->basecurve_nodes[0]) { dt_draw_curve_destroy(c->minmax_curve); c->minmax_curve = dt_draw_curve_new(0.0, 1.0, p->basecurve_type[0]); c->minmax_curve_nodes = p->basecurve_nodes[0]; c->minmax_curve_type = p->basecurve_type[0]; for(int k = 0; k < p->basecurve_nodes[0]; k++) (void)dt_draw_curve_add_point(c->minmax_curve, p->basecurve[0][k].x, p->basecurve[0][k].y); } else { for(int k = 0; k < p->basecurve_nodes[0]; k++) dt_draw_curve_set_point(c->minmax_curve, k, p->basecurve[0][k].x, p->basecurve[0][k].y); } dt_draw_curve_t *minmax_curve = c->minmax_curve; dt_draw_curve_calc_values(minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_xs, c->draw_ys); const float xm = basecurve[nodes - 1].x; const float x[4] = { 0.7f * xm, 0.8f * xm, 0.9f * xm, 1.0f * xm }; const float y[4] = { c->draw_ys[CLAMP((int)(x[0] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)], c->draw_ys[CLAMP((int)(x[1] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)], c->draw_ys[CLAMP((int)(x[2] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)], c->draw_ys[CLAMP((int)(x[3] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)] }; float unbounded_coeffs[3]; dt_iop_estimate_exp(x, y, 4, unbounded_coeffs); const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); // clear bg cairo_set_source_rgb(cr, .2, .2, .2); cairo_paint(cr); cairo_translate(cr, inset, inset); width -= 2 * inset; height -= 2 * inset; #if 0 // draw shadow around float alpha = 1.0f; for(int k=0; k<inset; k++) { cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } #else cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); cairo_set_source_rgb(cr, .1, .1, .1); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_set_source_rgb(cr, .3, .3, .3); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); cairo_translate(cr, 0, height); cairo_scale(cr, 1.0f, -1.0f); // draw grid cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.4)); cairo_set_source_rgb(cr, .1, .1, .1); if(c->loglogscale) dt_draw_loglog_grid(cr, 4, 0, 0, width, height, c->loglogscale); else dt_draw_grid(cr, 4, 0, 0, width, height); // draw nodes positions cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); for(int k = 0; k < nodes; k++) { const float x = to_log(basecurve[k].x, c->loglogscale), y = to_log(basecurve[k].y, c->loglogscale); cairo_arc(cr, x * width, y * height, DT_PIXEL_APPLY_DPI(3), 0, 2. * M_PI); cairo_stroke(cr); } // draw selected cursor cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); if(c->selected >= 0) { cairo_set_source_rgb(cr, .9, .9, .9); const float x = to_log(basecurve[c->selected].x, c->loglogscale), y = to_log(basecurve[c->selected].y, c->loglogscale); cairo_arc(cr, x * width, y * height, DT_PIXEL_APPLY_DPI(4), 0, 2. * M_PI); cairo_stroke(cr); } // draw curve cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.)); cairo_set_source_rgb(cr, .9, .9, .9); // cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_move_to(cr, 0, height * to_log(c->draw_ys[0], c->loglogscale)); for(int k = 1; k < DT_IOP_TONECURVE_RES; k++) { const float xx = k / (DT_IOP_TONECURVE_RES - 1.0); if(xx > xm) { const float yy = dt_iop_eval_exp(unbounded_coeffs, xx); const float x = to_log(xx, c->loglogscale), y = to_log(yy, c->loglogscale); cairo_line_to(cr, x * width, height * y); } else { const float yy = c->draw_ys[k]; const float x = to_log(xx, c->loglogscale), y = to_log(yy, c->loglogscale); cairo_line_to(cr, x * width, height * y); } } cairo_stroke(cr); cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }
static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params; dt_iop_basecurve_params_t *d = (dt_iop_basecurve_params_t *)self->default_params; dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data; int ch = 0; int nodes = p->basecurve_nodes[ch]; dt_iop_basecurve_node_t *basecurve = p->basecurve[ch]; if(event->button == 1) { if(event->type == GDK_BUTTON_PRESS && (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK && nodes < MAXNODES && c->selected == -1) { // if we are not on a node -> add a new node at the current x of the pointer and y of the curve at that x const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; c->mouse_x = CLAMP(event->x - inset, 0, width); c->mouse_y = CLAMP(event->y - inset, 0, height); const float mx = c->mouse_x / (float)width; const float linx = to_lin(mx, c->loglogscale); // don't add a node too close to others in x direction, it can crash dt int selected = -1; if(basecurve[0].x > linx) selected = 0; else { for(int k = 1; k < nodes; k++) { if(basecurve[k].x > linx) { selected = k; break; } } } if(selected == -1) selected = nodes; // > 0 -> check distance to left neighbour // < nodes -> check distance to right neighbour if(!((selected > 0 && linx - basecurve[selected - 1].x <= 0.025) || (selected < nodes && basecurve[selected].x - linx <= 0.025))) { // evaluate the curve at the current x position const float y = dt_draw_curve_calc_value(c->minmax_curve, linx); if(y >= 0.0 && y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards { // create a new node int selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, y); // maybe set the new one as being selected float min = .04f; min *= min; // comparing against square for(int k = 0; k < nodes; k++) { float other_y = to_log(basecurve[k].y, c->loglogscale); float dist = (y - other_y) * (y - other_y); if(dist < min) c->selected = selected; } dt_dev_add_history_item(darktable.develop, self, TRUE); gtk_widget_queue_draw(self->widget); } } return TRUE; } else if(event->type == GDK_2BUTTON_PRESS) { // reset current curve p->basecurve_nodes[ch] = d->basecurve_nodes[ch]; p->basecurve_type[ch] = d->basecurve_type[ch]; for(int k = 0; k < d->basecurve_nodes[ch]; k++) { p->basecurve[ch][k].x = d->basecurve[ch][k].x; p->basecurve[ch][k].y = d->basecurve[ch][k].y; } c->selected = -2; // avoid motion notify re-inserting immediately. dt_dev_add_history_item(darktable.develop, self, TRUE); gtk_widget_queue_draw(self->widget); return TRUE; } } return FALSE; }
int main(int argc, const char * argv[]) { std::ofstream to_log(to_log_file_path.c_str()); std::ofstream to_rpy(rpy_file_path.c_str()); std::ofstream gps_out(gps_out_path.c_str()); std::ofstream gps_filter_out(gps_filter_out_path.c_str()); std::ofstream mag_out(mag_out_path.c_str()); try { // Declaring objects used for inertial navigation ACCELEROMETER acc(acc_file_path, Captor::COLD_START); GYRO gyro(gyro_file_path, Captor::COLD_START); MAGNETOMETER mag(mag_file_path, Captor::COLD_START); GPS gps(gps_file_path,GPS::UBLOX); GPS_Filter gps_filter(&gps); EKF ekf(&gps_filter,&acc,&gyro,&mag); // Getting offset and gain for accelerometer, gyroscope and magnetometer. Getting GPS HOME field. // This routine will warn you if one of the offset couldn't be updated int ret = acc.initOffsets(); if (ret != 1) std::cout << "Couldn't get acc offsets !" << std::endl; else std::cout << "Acc offsets updated" << std::endl; ret = acc.initGain(); if (ret != 1) std::cout << "Couldn't get acc gain !" << std::endl; else std::cout << "Acc gain updated" << std::endl; // Advanced calibration for acc (offset and gain) #ifdef ADCALIBRATION ret = acc.performAdvancedAccCalibration(); if (ret !=1) std::cout << "Couldn't perform acc advanced calibration method" << std::endl; else { std::cout << "Acc advanced calibration performed" << std::endl; acc.correct_GN(); } #endif ret = gyro.initOffsets(); if (ret != 1) std::cout << "Couldn't get gyro offsets !" << std::endl; else std::cout << "Gyro offsets updated" << std::endl; ret = gyro.initGain(); if (ret != 1) std::cout << "Couldn't get gyro gain !" << std::endl; else std::cout << "Gyro gain updated" << std::endl; ret = mag.initOffsets(); if (ret != 1) std::cout << "Couldn't get magnetometer offsets !" << std::endl; else std::cout << "Mag offsets updated" << std::endl; ret = gps.setHome(); if (ret != 1) std::cout << "Couldn't get HOME !" << std::endl; else std::cout << "HOME updated" << std::endl; // Reading lines // We create the buffer for the sensor's output values Eigen::Vector3f acc_vector_buffer; Eigen::Vector3f gyro_vector_buffer; Eigen::Vector3d gps_buffer_vector; Eigen::Vector3d gps_position_vector; // We update and correct the magnetometer mag._init_earth_even_magnetic_field(); mag.update_correct(); // We initialize the state vector giving the initial heading ekf.init_state_vector(mag.getHeading()); //ekf.init_state_vector(); to_rpy << TODEG*(ekf.toRPY(ekf.get_state_vector())).transpose() << std::endl; // Storing operation while (!acc.line_end && !gyro.line_end){ // Reading from inertial captors and correcting the outputs acc.getOutput(&acc_vector_buffer); acc.correctOutput(&acc_vector_buffer, ekf.getDCM()); gyro.getOutput(&gyro_vector_buffer); gyro.correctOutput(&gyro_vector_buffer); // Updating and correcting magnetometer mag.update_correct(); // Updating GPS and storing into the &gps_buffer_vector gps.update(&gps_buffer_vector); // Predicting the state vector // Extended Kalman Filter according step is the prediction step. We first build the Jacobian matrix linearized around the current state and we then multiply the currrent state vector by such a matrix ekf.build_jacobian_matrix(&acc_vector_buffer, &gyro_vector_buffer); ekf.predict(); to_rpy << TODEG*(ekf.getRPY()).transpose() << std::endl; // Storing operation for data exploitation to_log << ekf.get_state_vector().transpose() << std::endl; // Storing operation for data exploitation //mag_out << TODEG*mag.getHeading() << std::endl; // Storing operation for data exploitation mag_out << TODEG*mag.getHeading((ekf.getRPY())(1),(ekf.getRPY())(0)) << std::endl; // Storing operation for data exploitation // Checking inf a new gps data is availaible if (gps.isAvailable()){ // If yes, we first update the GPS filter gps.calculatePositionFromHome(&gps_buffer_vector); gps_out << gps.getActualPosition().transpose() << std::endl; gps.actualizeInternDatas(&gps_buffer_vector); gps_filter.predict(); gps_filter.updateFilter(); gps_filter_out << gps_filter.getState().transpose() << std::endl; // Storing operation for data exploitation // And we then correct the EKF filter by correcting in order position, speed and quaternion attitude vector //ekf.correct(); //gps_filter.updateSpeedEKF(ekf.getCurrentSpeed()); } } } catch (std::exception const& e) { std::cout << e.what() << " file " << std::endl; } return 0; }
void accept_clients_loop(server_parameters * parameters) { int master_socket = socket(AF_INET, SOCK_STREAM, 0); if (master_socket < 0) { to_log(&logger, "Failed to create master socket: %s\n", strerror(errno)); return; } else { to_log(&logger, "Master socket created.\n"); } struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_port = htons(parameters->port); if (inet_aton(parameters->ip, &sa.sin_addr) == 0) { to_log(&logger, "Failed to convert address.\n"); goto close_master_socket; } int yes = 1; if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { to_log(&logger, "Failed setsockopt %s\n", strerror(errno)); goto close_master_socket; } if (bind(master_socket, (struct sockaddr *) &sa, sizeof(sa)) < 0) { to_log(&logger, "Failed to bind: %s\n", strerror(errno)); goto close_master_socket; } else { to_log(&logger, "Binded adderss\n"); } //set_nonblock(master_socket); if (listen(master_socket, SOMAXCONN) < 0) { to_log(&logger, "Failed to listen: %s\n", strerror(errno)); goto close_master_socket; } else { to_log(&logger, "Started listening master socket for clients\n"); } while(1) { // accept connections and handle in separate processes struct sockaddr_in client_addr; socklen_t client_addr_len; int client_socket = accept(master_socket, (struct sockaddr*) &client_addr, &client_addr_len); if (client_socket > 0) { to_log(&logger, "Accepted a new connection\n"); run_client_handler(client_socket, parameters); close(client_socket); } else { if (errno == EAGAIN) { continue; } else { to_log(&logger, "Failed to accept client connection: %s\n", strerror(errno)); break; } } } close_master_socket: if (close(master_socket) != 0) { to_log(&logger, "Failed to close master socket: %s\n", strerror(errno)); return; } else { to_log(&logger, "Closed master socket\n"); } }
// The nopurge argument indicates we are running the server with "--pstats" void init_known_players(const bool nopurge) { string fname = Config::get_config_dir() + playerfilename; ifstream file(fname.c_str(), ios_base::binary); if(!file) { to_log("Could not read player data; file missing or not readable."); return; } short numpl; file.read(reinterpret_cast<char*>(&numpl), sizeof(short)); if(numpl != STAT_VERSION) { to_log("Wrong statistics version in player data! All statistics will be cleared!"); return; } file.read(reinterpret_cast<char*>(&numpl), sizeof(short)); if(numpl < 0 || numpl > MAX_STORED_PLAYERS) { to_log("Player datafile is corrupt! Ignoring the data!"); return; } if(!nopurge) to_log("Player data contains " + lex_cast(numpl) + " entries;"); PlayerStats tmpstats; short sh; char ch; tmpstats.password[PASSW_LEN] = '\0'; int tooold; if(nopurge) tooold = 0; else // statpurge is hours, tooold seconds: tooold = 60*60*Config::int_settings[Config::IS_STATPURGE]; while(numpl--) { file.read(reinterpret_cast<char*>(&tmpstats.ID), sizeof(short)); file.read(tmpstats.password, PASSW_LEN); file.read(reinterpret_cast<char*>(tmpstats.kills), MAX_WAY_TO_KILL*sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.deaths), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.tks), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.healing_recvd), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.total_time), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.time_specced), sizeof(long)); file.read(reinterpret_cast<char*>(tmpstats.time_played), NO_CLASS*sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.arch_hits), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.arch_shots), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.cm_hits), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.cm_shots), sizeof(long)); file.read(reinterpret_cast<char*>(&tmpstats.ad_lvl), sizeof(e_AdminLvl)); file.read(reinterpret_cast<char*>(&tmpstats.last_seen), sizeof(time_t)); tmpstats.last_known_as.clear(); for(file.read(reinterpret_cast<char *>(&sh), sizeof(short)); sh > 0; --sh) { file.read(reinterpret_cast<char *>(&ch), sizeof(char)); tmpstats.last_known_as += ch; } if(!tooold || tmpstats.ad_lvl > AL_REG || (time(NULL) - tmpstats.last_seen) < tooold) known_players.push_back(tmpstats); } if(!nopurge) to_log(lex_cast(known_players.size()) + " entries accepted."); }