<commit_before>#include "MPC.h"
#include <cppad/cppad.hpp>
#include <cppad/ipopt/solve.hpp>
#include "Eigen-3.3/Eigen/Core"

using CppAD::AD;

// TODO: Set the timestep length and duration

// We set the number of timesteps to 25
// and the timestep evaluation frequency or evaluation
// period to 0.05.
size_t N = 25;
double dt = 0.05;

// This value assumes the model presented in the classroom is used.
//
// It was obtained by measuring the radius formed by running the vehicle in the
// simulator around in a circle with a constant steering angle and velocity on a
// flat terrain.
//
// Lf was tuned until the the radius formed by the simulating the model
// presented in the classroom matched the previous radius.
//
// This is the length from front to CoG that has a similar radius.
const double Lf = 2.67;

// Both the reference cross track and orientation errors are 0.
// The reference velocity is set to 40 mph.
double ref_cte = 0;
double ref_epsi = 0;
double ref_v = 40;

// The solver takes all the state variables and actuator
// variables in a singular vector. Thus, we should to establish
// when one variable starts and another ends to make our lifes easier.
size_t x_start = 0;
size_t y_start = x_start + N;
size_t psi_start = y_start + N;
size_t v_start = psi_start + N;
size_t cte_start = v_start + N;
size_t epsi_start = cte_start + N;
size_t delta_start = epsi_start + N;
size_t a_start = delta_start + N - 1;

class FG_eval {
 public:
  // Fitted polynomial coefficients
  Eigen::VectorXd coeffs;
  FG_eval(Eigen::VectorXd coeffs) { this->coeffs = coeffs; }

  typedef CPPAD_TESTVECTOR(AD<double>) ADvector;
  void operator()(ADvector& fg, const ADvector& vars) {
    // TODO: implement MPC
    // fg a vector of constraints, x is a vector of constraints.
    // NOTE: You'll probably go back and forth between this function and
    // the Solver function below.

    // The cost is stored is the first element of `fg`.
    // Any additions to the cost should be added to `fg[0]`.
    fg[0] = 0;

    // The part of the cost based on the reference state.
    for (int i = 0; i < N; i++) {
      fg[0] += CppAD::pow(vars[cte_start + i] - ref_cte, 2);
      fg[0] += CppAD::pow(vars[epsi_start + i] - ref_epsi, 2);
      fg[0] += CppAD::pow(vars[v_start + i] - ref_v, 2);
    }

    // Minimize the use of actuators.
    for (int i = 0; i < N - 1; i++) {
      fg[0] += CppAD::pow(vars[delta_start + i], 2);
      fg[0] += CppAD::pow(vars[a_start + i], 2);
    }

    // Minimize the value gap between sequential actuations.
    for (int i = 0; i < N - 2; i++) {
      fg[0] += CppAD::pow(vars[delta_start + i + 1] - vars[delta_start + i], 2);
      fg[0] += CppAD::pow(vars[a_start + i + 1] - vars[a_start + i], 2);
    }

    //
    // Setup Constraints
    //
    // NOTE: In this section you'll setup the model constraints.

    // Initial constraints
    //
    // We add 1 to each of the starting indices due to cost being located at
    // index 0 of `fg`.
    // This bumps up the position of all the other values.
    fg[1 + x_start] = vars[x_start];
    fg[1 + y_start] = vars[y_start];
    fg[1 + psi_start] = vars[psi_start];
    fg[1 + v_start] = vars[v_start];
    fg[1 + cte_start] = vars[cte_start];
    fg[1 + epsi_start] = vars[epsi_start];

    // The rest of the constraints
    for (int i = 0; i < N - 1; i++) {
      // The state at time t+1 .
      AD<double> x1 = vars[x_start + i + 1];
      AD<double> y1 = vars[y_start + i + 1];
      AD<double> psi1 = vars[psi_start + i + 1];
      AD<double> v1 = vars[v_start + i + 1];
      AD<double> cte1 = vars[cte_start + i + 1];
      AD<double> epsi1 = vars[epsi_start + i + 1];

      // The state at time t.
      AD<double> x0 = vars[x_start + i];
      AD<double> y0 = vars[y_start + i];
      AD<double> psi0 = vars[psi_start + i];
      AD<double> v0 = vars[v_start + i];
      AD<double> cte0 = vars[cte_start + i];
      AD<double> epsi0 = vars[epsi_start + i];

      // Only consider the actuation at time t.
      AD<double> delta0 = vars[delta_start + i];
      AD<double> a0 = vars[a_start + i];

      AD<double> f0 = coeffs[0] + coeffs[1] * x0;
      AD<double> psides0 = CppAD::atan(coeffs[1]);

      // Here's `x` to get you started.
      // The idea here is to constraint this value to be 0.
      //
      // Recall the equations for the model:
      // x_[t+1] = x[t] + v[t] * cos(psi[t]) * dt
      // y_[t+1] = y[t] + v[t] * sin(psi[t]) * dt
      // psi_[t+1] = psi[t] + v[t] / Lf * delta[t] * dt
      // v_[t+1] = v[t] + a[t] * dt
      // cte[t+1] = f(x[t]) - y[t] + v[t] * sin(epsi[t]) * dt
      // epsi[t+1] = psi[t] - psides[t] + v[t] * delta[t] / Lf * dt
      fg[2 + x_start + i] = x1 - (x0 + v0 * CppAD::cos(psi0) * dt);
      fg[2 + y_start + i] = y1 - (y0 + v0 * CppAD::sin(psi0) * dt);
      fg[2 + psi_start + i] = psi1 - (psi0 + v0 * delta0 / Lf * dt);
      fg[2 + v_start + i] = v1 - (v0 + a0 * dt);
      fg[2 + cte_start + i] =
          cte1 - ((f0 - y0) + (v0 * CppAD::sin(epsi0) * dt));
      fg[2 + epsi_start + i] =
          epsi1 - ((psi0 - psides0) + v0 * delta0 / Lf * dt);
    }
  }
};

//
// MPC class definition implementation.
//
MPC::MPC() {}
MPC::~MPC() {}

vector<double> MPC::Solve(Eigen::VectorXd state, Eigen::VectorXd coeffs) {
  bool ok = true;
  size_t i;
  typedef CPPAD_TESTVECTOR(double) Dvector;

  double x = x0[0];
  double y = x0[1];
  double psi = x0[2];
  double v = x0[3];
  double cte = x0[4];
  double epsi = x0[5];

  // TODO: Set the number of model variables (includes both states and inputs).
  // For example: If the state is a 4 element vector, the actuators is a 2
  // element vector and there are 10 timesteps. The number of variables is:
  //
  // 4 * 10 + 2 * 9
  size_t n_vars = N * 6 + (N - 1) * 2;
  // TODO: Set the number of constraints
  size_t n_constraints = N * 6;

  // Initial value of the independent variables.
  // SHOULD BE 0 besides initial state.
  Dvector vars(n_vars);
  for (int i = 0; i < n_vars; i++) {
    vars[i] = 0;
  }

  // Set the initial variable values
  vars[x_start] = x;
  vars[y_start] = y;
  vars[psi_start] = psi;
  vars[v_start] = v;
  vars[cte_start] = cte;
  vars[epsi_start] = epsi;

  Dvector vars_lowerbound(n_vars);
  Dvector vars_upperbound(n_vars);

  // TODO: Set lower and upper limits for variables.

  // Set all non-actuators upper and lowerlimits
  // to the max negative and positive values.
  for (int i = 0; i < delta_start; i++) {
    vars_lowerbound[i] = -1.0e19;
    vars_upperbound[i] = 1.0e19;
  }

  // The upper and lower limits of delta are set to -25 and 25
  // degrees (values in radians).
  // NOTE: Feel free to change this to something else.
  for (int i = delta_start; i < a_start; i++) {
    vars_lowerbound[i] = -0.436332;
    vars_upperbound[i] = 0.436332;
  }

  // Acceleration/decceleration upper and lower limits.
  // NOTE: Feel free to change this to something else.
  for (int i = a_start; i < n_vars; i++) {
    vars_lowerbound[i] = -1.0;
    vars_upperbound[i] = 1.0;
  }

  // Lower and upper limits for the constraints
  // Should be 0 besides initial state.
  Dvector constraints_lowerbound(n_constraints);
  Dvector constraints_upperbound(n_constraints);
  for (int i = 0; i < n_constraints; i++) {
    constraints_lowerbound[i] = 0;
    constraints_upperbound[i] = 0;
  }

  constraints_lowerbound[x_start] = x;
  constraints_lowerbound[y_start] = y;
  constraints_lowerbound[psi_start] = psi;
  constraints_lowerbound[v_start] = v;
  constraints_lowerbound[cte_start] = cte;
  constraints_lowerbound[epsi_start] = epsi;

  constraints_upperbound[x_start] = x;
  constraints_upperbound[y_start] = y;
  constraints_upperbound[psi_start] = psi;
  constraints_upperbound[v_start] = v;
  constraints_upperbound[cte_start] = cte;
  constraints_upperbound[epsi_start] = epsi;

  // object that computes objective and constraints
  FG_eval fg_eval(coeffs);

  //
  // NOTE: You don't have to worry about these options
  //
  // options for IPOPT solver
  std::string options;
  // Uncomment this if you'd like more print information
  options += "Integer print_level  0\n";
  // NOTE: Setting sparse to true allows the solver to take advantage
  // of sparse routines, this makes the computation MUCH FASTER. If you
  // can uncomment 1 of these and see if it makes a difference or not but
  // if you uncomment both the computation time should go up in orders of
  // magnitude.
  options += "Sparse  true        forward\n";
  options += "Sparse  true        reverse\n";
  // NOTE: Currently the solver has a maximum time limit of 0.5 seconds.
  // Change this as you see fit.
  options += "Numeric max_cpu_time          0.5\n";

  // place to return solution
  CppAD::ipopt::solve_result<Dvector> solution;

  // solve the problem
  CppAD::ipopt::solve<Dvector, FG_eval>(
      options, vars, vars_lowerbound, vars_upperbound, constraints_lowerbound,
      constraints_upperbound, fg_eval, solution);

  // Check some of the solution values
  ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;

  // Cost
  auto cost = solution.obj_value;
  std::cout << "Cost " << cost << std::endl;

  // TODO: Return the first actuator values. The variables can be accessed with
  // `solution.x[i]`.
  //
  // {...} is shorthand for creating a vector, so auto x1 = {1.0,2.0}
  // creates a 2 element double vector.
  return {solution.x[x_start + 1],   solution.x[y_start + 1],
          solution.x[psi_start + 1], solution.x[v_start + 1],
          solution.x[cte_start + 1], solution.x[epsi_start + 1],
          solution.x[delta_start],   solution.x[a_start]};
}
<commit_msg>fix: Undeclared variable is function solve()<commit_after>#include "MPC.h"
#include <cppad/cppad.hpp>
#include <cppad/ipopt/solve.hpp>
#include "Eigen-3.3/Eigen/Core"

using CppAD::AD;

// TODO: Set the timestep length and duration

// We set the number of timesteps to 25
// and the timestep evaluation frequency or evaluation
// period to 0.05.
size_t N = 25;
double dt = 0.05;

// This value assumes the model presented in the classroom is used.
//
// It was obtained by measuring the radius formed by running the vehicle in the
// simulator around in a circle with a constant steering angle and velocity on a
// flat terrain.
//
// Lf was tuned until the the radius formed by the simulating the model
// presented in the classroom matched the previous radius.
//
// This is the length from front to CoG that has a similar radius.
const double Lf = 2.67;

// Both the reference cross track and orientation errors are 0.
// The reference velocity is set to 40 mph.
double ref_cte = 0;
double ref_epsi = 0;
double ref_v = 40;

// The solver takes all the state variables and actuator
// variables in a singular vector. Thus, we should to establish
// when one variable starts and another ends to make our lifes easier.
size_t x_start = 0;
size_t y_start = x_start + N;
size_t psi_start = y_start + N;
size_t v_start = psi_start + N;
size_t cte_start = v_start + N;
size_t epsi_start = cte_start + N;
size_t delta_start = epsi_start + N;
size_t a_start = delta_start + N - 1;

class FG_eval {
 public:
  // Fitted polynomial coefficients
  Eigen::VectorXd coeffs;
  FG_eval(Eigen::VectorXd coeffs) { this->coeffs = coeffs; }

  typedef CPPAD_TESTVECTOR(AD<double>) ADvector;
  void operator()(ADvector& fg, const ADvector& vars) {
    // TODO: implement MPC
    // fg a vector of constraints, x is a vector of constraints.
    // NOTE: You'll probably go back and forth between this function and
    // the Solver function below.

    // The cost is stored is the first element of `fg`.
    // Any additions to the cost should be added to `fg[0]`.
    fg[0] = 0;

    // The part of the cost based on the reference state.
    for (int i = 0; i < N; i++) {
      fg[0] += CppAD::pow(vars[cte_start + i] - ref_cte, 2);
      fg[0] += CppAD::pow(vars[epsi_start + i] - ref_epsi, 2);
      fg[0] += CppAD::pow(vars[v_start + i] - ref_v, 2);
    }

    // Minimize the use of actuators.
    for (int i = 0; i < N - 1; i++) {
      fg[0] += CppAD::pow(vars[delta_start + i], 2);
      fg[0] += CppAD::pow(vars[a_start + i], 2);
    }

    // Minimize the value gap between sequential actuations.
    for (int i = 0; i < N - 2; i++) {
      fg[0] += CppAD::pow(vars[delta_start + i + 1] - vars[delta_start + i], 2);
      fg[0] += CppAD::pow(vars[a_start + i + 1] - vars[a_start + i], 2);
    }

    //
    // Setup Constraints
    //
    // NOTE: In this section you'll setup the model constraints.

    // Initial constraints
    //
    // We add 1 to each of the starting indices due to cost being located at
    // index 0 of `fg`.
    // This bumps up the position of all the other values.
    fg[1 + x_start] = vars[x_start];
    fg[1 + y_start] = vars[y_start];
    fg[1 + psi_start] = vars[psi_start];
    fg[1 + v_start] = vars[v_start];
    fg[1 + cte_start] = vars[cte_start];
    fg[1 + epsi_start] = vars[epsi_start];

    // The rest of the constraints
    for (int i = 0; i < N - 1; i++) {
      // The state at time t+1 .
      AD<double> x1 = vars[x_start + i + 1];
      AD<double> y1 = vars[y_start + i + 1];
      AD<double> psi1 = vars[psi_start + i + 1];
      AD<double> v1 = vars[v_start + i + 1];
      AD<double> cte1 = vars[cte_start + i + 1];
      AD<double> epsi1 = vars[epsi_start + i + 1];

      // The state at time t.
      AD<double> x0 = vars[x_start + i];
      AD<double> y0 = vars[y_start + i];
      AD<double> psi0 = vars[psi_start + i];
      AD<double> v0 = vars[v_start + i];
      AD<double> cte0 = vars[cte_start + i];
      AD<double> epsi0 = vars[epsi_start + i];

      // Only consider the actuation at time t.
      AD<double> delta0 = vars[delta_start + i];
      AD<double> a0 = vars[a_start + i];

      AD<double> f0 = coeffs[0] + coeffs[1] * x0;
      AD<double> psides0 = CppAD::atan(coeffs[1]);

      // Here's `x` to get you started.
      // The idea here is to constraint this value to be 0.
      //
      // Recall the equations for the model:
      // x_[t+1] = x[t] + v[t] * cos(psi[t]) * dt
      // y_[t+1] = y[t] + v[t] * sin(psi[t]) * dt
      // psi_[t+1] = psi[t] + v[t] / Lf * delta[t] * dt
      // v_[t+1] = v[t] + a[t] * dt
      // cte[t+1] = f(x[t]) - y[t] + v[t] * sin(epsi[t]) * dt
      // epsi[t+1] = psi[t] - psides[t] + v[t] * delta[t] / Lf * dt
      fg[2 + x_start + i] = x1 - (x0 + v0 * CppAD::cos(psi0) * dt);
      fg[2 + y_start + i] = y1 - (y0 + v0 * CppAD::sin(psi0) * dt);
      fg[2 + psi_start + i] = psi1 - (psi0 + v0 * delta0 / Lf * dt);
      fg[2 + v_start + i] = v1 - (v0 + a0 * dt);
      fg[2 + cte_start + i] =
          cte1 - ((f0 - y0) + (v0 * CppAD::sin(epsi0) * dt));
      fg[2 + epsi_start + i] =
          epsi1 - ((psi0 - psides0) + v0 * delta0 / Lf * dt);
    }
  }
};

//
// MPC class definition implementation.
//
MPC::MPC() {}
MPC::~MPC() {}

vector<double> MPC::Solve(Eigen::VectorXd state, Eigen::VectorXd coeffs) {
  bool ok = true;
  size_t i;
  typedef CPPAD_TESTVECTOR(double) Dvector;

  double x = state[0];
  double y = state[1];
  double psi = state[2];
  double v = state[3];
  double cte = state[4];
  double epsi = state[5];

  // TODO: Set the number of model variables (includes both states and inputs).
  // For example: If the state is a 4 element vector, the actuators is a 2
  // element vector and there are 10 timesteps. The number of variables is:
  //
  // 4 * 10 + 2 * 9
  size_t n_vars = N * 6 + (N - 1) * 2;
  // TODO: Set the number of constraints
  size_t n_constraints = N * 6;

  // Initial value of the independent variables.
  // SHOULD BE 0 besides initial state.
  Dvector vars(n_vars);
  for (int i = 0; i < n_vars; i++) {
    vars[i] = 0;
  }

  // Set the initial variable values
  vars[x_start] = x;
  vars[y_start] = y;
  vars[psi_start] = psi;
  vars[v_start] = v;
  vars[cte_start] = cte;
  vars[epsi_start] = epsi;

  Dvector vars_lowerbound(n_vars);
  Dvector vars_upperbound(n_vars);

  // TODO: Set lower and upper limits for variables.

  // Set all non-actuators upper and lowerlimits
  // to the max negative and positive values.
  for (int i = 0; i < delta_start; i++) {
    vars_lowerbound[i] = -1.0e19;
    vars_upperbound[i] = 1.0e19;
  }

  // The upper and lower limits of delta are set to -25 and 25
  // degrees (values in radians).
  // NOTE: Feel free to change this to something else.
  for (int i = delta_start; i < a_start; i++) {
    vars_lowerbound[i] = -0.436332;
    vars_upperbound[i] = 0.436332;
  }

  // Acceleration/decceleration upper and lower limits.
  // NOTE: Feel free to change this to something else.
  for (int i = a_start; i < n_vars; i++) {
    vars_lowerbound[i] = -1.0;
    vars_upperbound[i] = 1.0;
  }

  // Lower and upper limits for the constraints
  // Should be 0 besides initial state.
  Dvector constraints_lowerbound(n_constraints);
  Dvector constraints_upperbound(n_constraints);
  for (int i = 0; i < n_constraints; i++) {
    constraints_lowerbound[i] = 0;
    constraints_upperbound[i] = 0;
  }

  constraints_lowerbound[x_start] = x;
  constraints_lowerbound[y_start] = y;
  constraints_lowerbound[psi_start] = psi;
  constraints_lowerbound[v_start] = v;
  constraints_lowerbound[cte_start] = cte;
  constraints_lowerbound[epsi_start] = epsi;

  constraints_upperbound[x_start] = x;
  constraints_upperbound[y_start] = y;
  constraints_upperbound[psi_start] = psi;
  constraints_upperbound[v_start] = v;
  constraints_upperbound[cte_start] = cte;
  constraints_upperbound[epsi_start] = epsi;

  // object that computes objective and constraints
  FG_eval fg_eval(coeffs);

  //
  // NOTE: You don't have to worry about these options
  //
  // options for IPOPT solver
  std::string options;
  // Uncomment this if you'd like more print information
  options += "Integer print_level  0\n";
  // NOTE: Setting sparse to true allows the solver to take advantage
  // of sparse routines, this makes the computation MUCH FASTER. If you
  // can uncomment 1 of these and see if it makes a difference or not but
  // if you uncomment both the computation time should go up in orders of
  // magnitude.
  options += "Sparse  true        forward\n";
  options += "Sparse  true        reverse\n";
  // NOTE: Currently the solver has a maximum time limit of 0.5 seconds.
  // Change this as you see fit.
  options += "Numeric max_cpu_time          0.5\n";

  // place to return solution
  CppAD::ipopt::solve_result<Dvector> solution;

  // solve the problem
  CppAD::ipopt::solve<Dvector, FG_eval>(
      options, vars, vars_lowerbound, vars_upperbound, constraints_lowerbound,
      constraints_upperbound, fg_eval, solution);

  // Check some of the solution values
  ok &= solution.status == CppAD::ipopt::solve_result<Dvector>::success;

  // Cost
  auto cost = solution.obj_value;
  std::cout << "Cost " << cost << std::endl;

  // TODO: Return the first actuator values. The variables can be accessed with
  // `solution.x[i]`.
  //
  // {...} is shorthand for creating a vector, so auto x1 = {1.0,2.0}
  // creates a 2 element double vector.
  return {solution.x[x_start + 1],   solution.x[y_start + 1],
          solution.x[psi_start + 1], solution.x[v_start + 1],
          solution.x[cte_start + 1], solution.x[epsi_start + 1],
          solution.x[delta_start],   solution.x[a_start]};
}
<|endoftext|>


<commit_before>
#include "model_gltf_save.hpp"
#include "file_saver.hpp"
#include "model_topology_converter.hpp"

#include <algorithm>
#include <stdexcept>
#include <string_view>
#include <type_traits>

#include "fx/gltf.h"
#include <fmt/format.h>
#include <gsl/gsl>

using namespace std::literals;

namespace model::gltf {

namespace {

constexpr bool GLTF_EXPORT_SKIN = false; // todo: Implement glTF skin support.

auto unstripfy_scene_nodes_topologies(std::vector<scene::Node>& nodes)
{
   for (auto& node : nodes) {
      if (node.geometry) {
         switch (node.geometry->topology) {
            // Not sure why but blender doesn't seam to like the triangle strips from the
            // game's models, so we convert them to lists here.
         case Primitive_topology::triangle_strip:
         case Primitive_topology::triangle_strip_ps2:
            node.geometry->indices =
               convert_topology(node.geometry->indices, node.geometry->topology,
                                Primitive_topology::triangle_list);
            node.geometry->topology = Primitive_topology::triangle_list;
            break;
         }
      }
   }
}

auto map_primitive_topology(const Primitive_topology primitive_topology)
   -> fx::gltf::Primitive::Mode
{
   using Mode = fx::gltf::Primitive::Mode;

   switch (primitive_topology) {
   case Primitive_topology::point_list:
      return Mode::Points;
   case Primitive_topology::line_list:
      return Mode::Lines;
   case Primitive_topology::line_loop:
      return Mode::LineLoop;
   case Primitive_topology::line_strip:
      return Mode::LineStrip;
   case Primitive_topology::triangle_list:
      return Mode::Triangles;
   case Primitive_topology::triangle_strip:
      return Mode::TriangleStrip;
   case Primitive_topology::triangle_fan:
      return Mode::TriangleFan;
   case Primitive_topology::undefined:
   case Primitive_topology::triangle_strip_ps2:
      throw std::runtime_error{"Attempt to save model to glTF format that contains "
                               "unsupported primitive topology."};
   default:
      std::terminate();
   }
}

auto align_buffer(std::vector<std::uint8_t>& buffer, const std::size_t multiple)
{
   const auto size = buffer.size();
   const auto remainder = size % multiple;

   if (remainder != 0) buffer.resize(size + (multiple - remainder));
}

auto make_node_matrix(const glm::mat4x3 matrix) noexcept -> std::array<float, 16>
{
   const glm::mat4 mat4x4 = matrix;
   std::array<float, 16> dest;

   std::memcpy(dest.data(), &mat4x4, sizeof(glm::mat4));

   return dest;
}

auto make_node_children_list(const std::string_view name,
                             const std::vector<scene::Node>& nodes)
   -> std::vector<std::int32_t>
{
   std::vector<std::int32_t> children;
   children.reserve(32);

   for (std::int32_t i = 0; i < nodes.size(); ++i) {
      if (nodes[i].parent == name) children.push_back(i);
   }

   return children;
}

auto make_gltf_tangents(const Vertices& vertices) -> std::unique_ptr<glm::vec4[]>
{
   if (!vertices.normals || !vertices.tangents || vertices.bitangents) {
      return nullptr;
   }

   auto packed = std::make_unique<glm::vec4[]>(vertices.size);

   for (std::size_t i = 0; i < vertices.size; ++i) {
      packed[i] = {
         vertices.tangents[i],
         glm::sign(glm::dot(vertices.bitangents[i],
                            glm::cross(vertices.normals[i], vertices.tangents[i])))};
   }

   return packed;
}

auto make_extended_bone_indices(const Vertices& vertices)
   -> std::unique_ptr<glm::u8vec4[]>
{
   if (!vertices.bones) return nullptr;

   auto extended = std::make_unique<glm::u8vec4[]>(vertices.size);

   std::transform(vertices.bones.get(), vertices.bones.get() + vertices.size,
                  extended.get(), [](const glm::u8vec3 v) {
                     return glm::u8vec4{v, 0};
                  });

   return extended;
}

auto make_normalized_bone_weights(const Vertices& vertices)
   -> std::unique_ptr<glm::vec4[]>
{
   if (!vertices.weights) return nullptr;

   auto normalized = std::make_unique<glm::vec4[]>(vertices.size);

   std::transform(vertices.weights.get(), vertices.weights.get() + vertices.size,
                  normalized.get(), [](const glm::vec3 v) {
                     const auto total = v.x + v.y + v.z;

                     return glm::u8vec4{v / total, 0};
                  });

   return normalized;
}

template<typename T>
auto add_to_buffer(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                   const gsl::span<const T> span) -> std::int32_t
{
   align_buffer(buffer, sizeof(T));

   const auto offset = buffer.size();
   const auto span_bytes_size = (span.size() * sizeof(T));

   buffer.resize(buffer.size() + span_bytes_size);

   std::memcpy(buffer.data() + offset, span.data(), span_bytes_size);

   const auto view_index = doc.bufferViews.size();
   doc.bufferViews.push_back({.buffer = 0,
                              .byteOffset = static_cast<std::uint32_t>(offset),
                              .byteLength = static_cast<std::uint32_t>(span_bytes_size)});

   return static_cast<std::int32_t>(view_index);
}

auto add_primitve_indices(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                          const Indices& indices) -> std::int32_t
{
   const auto accessor_index = static_cast<std::int32_t>(doc.accessors.size());

   doc.accessors.push_back(
      {.bufferView = add_to_buffer(doc, buffer, gsl::make_span(indices)),
       .count = static_cast<std::uint32_t>(indices.size()),
       .componentType = fx::gltf::Accessor::ComponentType::UnsignedShort,
       .type = fx::gltf::Accessor::Type::Scalar});

   return accessor_index;
}

template<typename T>
auto add_attribute_accessor(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                            const gsl::span<const T> span,
                            [[maybe_unused]] const bool add_min_max = false)
   -> std::uint32_t
{
   constexpr auto type = []() {
      if (T::length() == 2) return fx::gltf::Accessor::Type::Vec2;
      if (T::length() == 3) return fx::gltf::Accessor::Type::Vec3;
      if (T::length() == 4) return fx::gltf::Accessor::Type::Vec4;
   }();

   constexpr auto component_type = []() {
      if (std::is_same_v<T::value_type, float>)
         return fx::gltf::Accessor::ComponentType::Float;
      if (std::is_same_v<T::value_type, glm::uint8>)
         return fx::gltf::Accessor::ComponentType::UnsignedByte;
   }();

   const auto accessor_index = doc.accessors.size();

   doc.accessors.push_back({.bufferView = add_to_buffer(doc, buffer, span),
                            .count = static_cast<std::uint32_t>(span.size()),
                            .componentType = component_type,
                            .type = type});

   if constexpr (std::is_same_v<typename T::value_type, float>) {
      if (add_min_max) {
         auto& min = doc.accessors.back().min;
         auto& max = doc.accessors.back().max;
         min.assign(T::length(), std::numeric_limits<float>::max());
         max.assign(T::length(), std::numeric_limits<float>::lowest());

         for (auto& v : span) {
            for (auto i = 0; i < T::length(); ++i) {
               min[i] = std::min(min[i], v[i]);
               max[i] = std::max(max[i], v[i]);
            }
         }
      }
   }

   return static_cast<std::uint32_t>(accessor_index);
}

auto add_primitve_attributes(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                             const Vertices& vertices) -> fx::gltf::Attributes
{
   fx::gltf::Attributes attribs;

   const auto add_attrib = [&](const std::string& name, const auto* const data,
                               const bool add_min_max = false) {
      if (!data) return;

      attribs[name] = add_attribute_accessor(
         doc, buffer, gsl::make_span(data, vertices.size), add_min_max);
   };

   add_attrib("POSITION"s, vertices.positions.get(), true);
   add_attrib("NORMAL"s, vertices.normals.get());
   add_attrib("TANGENT"s, make_gltf_tangents(vertices).get());
   add_attrib("TEXCOORD_0"s, vertices.texcoords.get());
   add_attrib("COLOR_0"s, vertices.colors.get());

   if constexpr (GLTF_EXPORT_SKIN) {
      add_attrib("JOINTS_0"s, make_extended_bone_indices(vertices).get());

      if (vertices.bones && vertices.weights) {
         add_attrib("WEIGHTS_0"s, make_normalized_bone_weights(vertices).get());
      }
      else if (vertices.bones) {
         add_attrib(
            "WEIGHTS_0"s,
            std::vector<glm::vec4>{vertices.size, glm::vec4{1.0f, 0.0f, 0.0f, 0.0f}}
               .data());
      }
   }

   return attribs;
}

auto add_mesh_primitve(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                       const scene::Geometry& geometry) -> fx::gltf::Primitive
{
   return {.indices = add_primitve_indices(doc, buffer, geometry.indices),
           .mode = map_primitive_topology(geometry.topology),
           .attributes = add_primitve_attributes(doc, buffer, geometry.vertices)};
}

auto add_node_mesh(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                   const scene::Node& node) -> std::int32_t
{
   if (!node.geometry) return -1;

   const auto index = static_cast<std::int32_t>(doc.meshes.size());

   doc.meshes.push_back({.name = node.name,
                         .primitives = {add_mesh_primitve(doc, buffer, *node.geometry)}});

   return index;
}

auto add_skin_inverse_bind_matrices(fx::gltf::Document& doc,
                                    std::vector<std::uint8_t>& buffer,
                                    [[maybe_unused]] const scene::Scene& scene,
                                    const std::vector<std::uint8_t>& unified_bone_map)
   -> std::int32_t
{
   const auto accessor_index = doc.accessors.size();

   std::vector martices{unified_bone_map.size(), glm::identity<glm::mat4>()};

   doc.accessors.push_back(
      {.bufferView = add_to_buffer(doc, buffer, gsl::make_span(std::as_const(martices))),
       .count = static_cast<std::uint32_t>(martices.size()),
       .componentType = fx::gltf::Accessor::ComponentType::Float,
       .type = fx::gltf::Accessor::Type::Mat4});

   return static_cast<std::uint32_t>(accessor_index);
}

}

void save_scene(scene::Scene scene, File_saver& file_saver)
{
   const auto unified_bone_map = scene::unify_bone_maps(scene);
   unstripfy_scene_nodes_topologies(scene.nodes);

   fx::gltf::Document doc{};
   std::vector<std::uint8_t> buffer;
   buffer.reserve(1000000);

   for (const auto& node : scene.nodes) {
      doc.nodes.push_back(
         {.name = node.name,
          .mesh = add_node_mesh(doc, buffer, node),
          .skin = (GLTF_EXPORT_SKIN && scene::has_skinned_geometry(node)) ? 0 : -1,
          .matrix = make_node_matrix(node.transform),
          .children = make_node_children_list(node.name, scene.nodes)});
   }

   if constexpr (GLTF_EXPORT_SKIN && scene::has_skinned_geometry(scene)) {
      doc.skins.push_back(
         {.inverseBindMatrices =
             add_skin_inverse_bind_matrices(doc, buffer, scene, unified_bone_map),
          .skeleton = 0,
          .joints = {unified_bone_map.cbegin(), unified_bone_map.cend()}});
   }

   doc.scene = 0;
   doc.scenes.push_back({.name = scene.name, .nodes = {0}});
   doc.buffers.push_back({.byteLength = gsl::narrow<std::uint32_t>(buffer.size()),
                          .data = std::move(buffer)});

   fx::gltf::Save(doc, file_saver.build_file_path(""sv, scene.name, ".glb"sv).string(),
                  true);
}

}
<commit_msg>add material saving to glTF files<commit_after>
#include "model_gltf_save.hpp"
#include "file_saver.hpp"
#include "model_topology_converter.hpp"

#include <algorithm>
#include <stdexcept>
#include <string_view>
#include <type_traits>

#include "fx/gltf.h"
#include <fmt/format.h>
#include <gsl/gsl>

using namespace std::literals;

namespace model::gltf {

namespace {

constexpr bool GLTF_EXPORT_SKIN = false; // todo: Implement glTF skin support.

auto unstripfy_scene_nodes_topologies(std::vector<scene::Node>& nodes)
{
   for (auto& node : nodes) {
      if (node.geometry) {
         switch (node.geometry->topology) {
            // Not sure why but blender doesn't seam to like the triangle strips from the
            // game's models, so we convert them to lists here.
         case Primitive_topology::triangle_strip:
         case Primitive_topology::triangle_strip_ps2:
            node.geometry->indices =
               convert_topology(node.geometry->indices, node.geometry->topology,
                                Primitive_topology::triangle_list);
            node.geometry->topology = Primitive_topology::triangle_list;
            break;
         }
      }
   }
}

auto map_primitive_topology(const Primitive_topology primitive_topology)
   -> fx::gltf::Primitive::Mode
{
   using Mode = fx::gltf::Primitive::Mode;

   switch (primitive_topology) {
   case Primitive_topology::point_list:
      return Mode::Points;
   case Primitive_topology::line_list:
      return Mode::Lines;
   case Primitive_topology::line_loop:
      return Mode::LineLoop;
   case Primitive_topology::line_strip:
      return Mode::LineStrip;
   case Primitive_topology::triangle_list:
      return Mode::Triangles;
   case Primitive_topology::triangle_strip:
      return Mode::TriangleStrip;
   case Primitive_topology::triangle_fan:
      return Mode::TriangleFan;
   case Primitive_topology::undefined:
   case Primitive_topology::triangle_strip_ps2:
      throw std::runtime_error{"Attempt to save model to glTF format that contains "
                               "unsupported primitive topology."};
   default:
      std::terminate();
   }
}

auto align_buffer(std::vector<std::uint8_t>& buffer, const std::size_t multiple)
{
   const auto size = buffer.size();
   const auto remainder = size % multiple;

   if (remainder != 0) buffer.resize(size + (multiple - remainder));
}

auto make_node_matrix(const glm::mat4x3 matrix) noexcept -> std::array<float, 16>
{
   const glm::mat4 mat4x4 = matrix;
   std::array<float, 16> dest;

   std::memcpy(dest.data(), &mat4x4, sizeof(glm::mat4));

   return dest;
}

auto make_node_children_list(const std::string_view name,
                             const std::vector<scene::Node>& nodes)
   -> std::vector<std::int32_t>
{
   std::vector<std::int32_t> children;
   children.reserve(32);

   for (std::int32_t i = 0; i < nodes.size(); ++i) {
      if (nodes[i].parent == name) children.push_back(i);
   }

   return children;
}

auto make_gltf_tangents(const Vertices& vertices) -> std::unique_ptr<glm::vec4[]>
{
   if (!vertices.normals || !vertices.tangents || vertices.bitangents) {
      return nullptr;
   }

   auto packed = std::make_unique<glm::vec4[]>(vertices.size);

   for (std::size_t i = 0; i < vertices.size; ++i) {
      packed[i] = {
         vertices.tangents[i],
         glm::sign(glm::dot(vertices.bitangents[i],
                            glm::cross(vertices.normals[i], vertices.tangents[i])))};
   }

   return packed;
}

auto make_extended_bone_indices(const Vertices& vertices)
   -> std::unique_ptr<glm::u8vec4[]>
{
   if (!vertices.bones) return nullptr;

   auto extended = std::make_unique<glm::u8vec4[]>(vertices.size);

   std::transform(vertices.bones.get(), vertices.bones.get() + vertices.size,
                  extended.get(), [](const glm::u8vec3 v) {
                     return glm::u8vec4{v, 0};
                  });

   return extended;
}

auto make_normalized_bone_weights(const Vertices& vertices)
   -> std::unique_ptr<glm::vec4[]>
{
   if (!vertices.weights) return nullptr;

   auto normalized = std::make_unique<glm::vec4[]>(vertices.size);

   std::transform(vertices.weights.get(), vertices.weights.get() + vertices.size,
                  normalized.get(), [](const glm::vec3 v) {
                     const auto total = v.x + v.y + v.z;

                     return glm::u8vec4{v / total, 0};
                  });

   return normalized;
}

template<typename T>
auto add_to_buffer(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                   const gsl::span<const T> span) -> std::int32_t
{
   align_buffer(buffer, sizeof(T));

   const auto offset = buffer.size();
   const auto span_bytes_size = (span.size() * sizeof(T));

   buffer.resize(buffer.size() + span_bytes_size);

   std::memcpy(buffer.data() + offset, span.data(), span_bytes_size);

   const auto view_index = doc.bufferViews.size();
   doc.bufferViews.push_back({.buffer = 0,
                              .byteOffset = static_cast<std::uint32_t>(offset),
                              .byteLength = static_cast<std::uint32_t>(span_bytes_size)});

   return static_cast<std::int32_t>(view_index);
}

auto add_primitve_indices(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                          const Indices& indices) -> std::int32_t
{
   const auto accessor_index = static_cast<std::int32_t>(doc.accessors.size());

   doc.accessors.push_back(
      {.bufferView = add_to_buffer(doc, buffer, gsl::make_span(indices)),
       .count = static_cast<std::uint32_t>(indices.size()),
       .componentType = fx::gltf::Accessor::ComponentType::UnsignedShort,
       .type = fx::gltf::Accessor::Type::Scalar});

   return accessor_index;
}

template<typename T>
auto add_attribute_accessor(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                            const gsl::span<const T> span,
                            [[maybe_unused]] const bool add_min_max = false)
   -> std::uint32_t
{
   constexpr auto type = []() {
      if (T::length() == 2) return fx::gltf::Accessor::Type::Vec2;
      if (T::length() == 3) return fx::gltf::Accessor::Type::Vec3;
      if (T::length() == 4) return fx::gltf::Accessor::Type::Vec4;
   }();

   constexpr auto component_type = []() {
      if (std::is_same_v<T::value_type, float>)
         return fx::gltf::Accessor::ComponentType::Float;
      if (std::is_same_v<T::value_type, glm::uint8>)
         return fx::gltf::Accessor::ComponentType::UnsignedByte;
   }();

   const auto accessor_index = doc.accessors.size();

   doc.accessors.push_back({.bufferView = add_to_buffer(doc, buffer, span),
                            .count = static_cast<std::uint32_t>(span.size()),
                            .componentType = component_type,
                            .type = type});

   if constexpr (std::is_same_v<typename T::value_type, float>) {
      if (add_min_max) {
         auto& min = doc.accessors.back().min;
         auto& max = doc.accessors.back().max;
         min.assign(T::length(), std::numeric_limits<float>::max());
         max.assign(T::length(), std::numeric_limits<float>::lowest());

         for (auto& v : span) {
            for (auto i = 0; i < T::length(); ++i) {
               min[i] = std::min(min[i], v[i]);
               max[i] = std::max(max[i], v[i]);
            }
         }
      }
   }

   return static_cast<std::uint32_t>(accessor_index);
}

auto add_primitve_attributes(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                             const Vertices& vertices) -> fx::gltf::Attributes
{
   fx::gltf::Attributes attribs;

   const auto add_attrib = [&](const std::string& name, const auto* const data,
                               const bool add_min_max = false) {
      if (!data) return;

      attribs[name] = add_attribute_accessor(
         doc, buffer, gsl::make_span(data, vertices.size), add_min_max);
   };

   add_attrib("POSITION"s, vertices.positions.get(), true);
   add_attrib("NORMAL"s, vertices.normals.get());
   add_attrib("TANGENT"s, make_gltf_tangents(vertices).get());
   add_attrib("TEXCOORD_0"s, vertices.texcoords.get());
   add_attrib("COLOR_0"s, vertices.colors.get());

   if constexpr (GLTF_EXPORT_SKIN) {
      add_attrib("JOINTS_0"s, make_extended_bone_indices(vertices).get());

      if (vertices.bones && vertices.weights) {
         add_attrib("WEIGHTS_0"s, make_normalized_bone_weights(vertices).get());
      }
      else if (vertices.bones) {
         add_attrib(
            "WEIGHTS_0"s,
            std::vector<glm::vec4>{vertices.size, glm::vec4{1.0f, 0.0f, 0.0f, 0.0f}}
               .data());
      }
   }

   return attribs;
}

auto add_mesh_primitve(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                       const scene::Geometry& geometry, const std::int32_t material_index)
   -> fx::gltf::Primitive
{
   return {.indices = add_primitve_indices(doc, buffer, geometry.indices),
           .material = material_index,
           .mode = map_primitive_topology(geometry.topology),
           .attributes = add_primitve_attributes(doc, buffer, geometry.vertices)};
}

auto add_node_mesh(fx::gltf::Document& doc, std::vector<std::uint8_t>& buffer,
                   const scene::Node& node) -> std::int32_t
{
   if (!node.geometry) return -1;

   const auto index = static_cast<std::int32_t>(doc.meshes.size());

   doc.meshes.push_back({.name = node.name,
                         .primitives = {add_mesh_primitve(doc, buffer, *node.geometry,
                                                          node.material_index)}});

   return index;
}

auto add_texture_image(fx::gltf::Document& doc, const std::string_view name)
   -> std::int32_t
{
   const auto index = static_cast<std::int32_t>(doc.images.size());

   doc.images.push_back(
      {.name = std::string{name}, .uri = fmt::format("./{}.png"sv, name)});

   return index;
}

auto add_material_texture(fx::gltf::Document& doc, const std::string_view name)
   -> std::int32_t
{
   const auto index = static_cast<std::int32_t>(doc.textures.size());

   doc.textures.push_back(
      {.name = std::string{name}, .source = add_texture_image(doc, name)});

   return index;
}

auto add_material_normal_texture(fx::gltf::Document& doc, const scene::Material& material)
   -> fx::gltf::Material::NormalTexture
{
   if ((material.rendertype != Render_type::bumpmap &&
        material.rendertype != Render_type::bumpmap_specular) ||
       material.textures[1].empty()) {
      return {};
   }

   fx::gltf::Material::NormalTexture tex;

   tex.index = add_material_texture(doc, material.textures[1]);

   return tex;
}

auto add_material_pbr(fx::gltf::Document& doc, const scene::Material& material)
   -> fx::gltf::Material::PBRMetallicRoughness
{
   fx::gltf::Material::PBRMetallicRoughness pbr;

   pbr.baseColorFactor = {material.diffuse_colour[0], material.diffuse_colour[1],
                          material.diffuse_colour[2], material.diffuse_colour[3]};

   if (!material.textures[0].empty()) {
      pbr.baseColorTexture.index = add_material_texture(doc, material.textures[0]);
   }

   // Guess with extreme disregard for reality what the roughness and metallic factors
   // should be.
   if (const float spec_strength =
          glm::clamp(glm::dot(glm::vec3{material.specular_colour},
                              glm::vec3{0.2126f, 0.7152f, 0.0722f}),
                     0.0f, 1.0f);
       are_flags_set(material.flags, Render_flags::specular) ||
       material.rendertype == Render_type::specular ||
       material.rendertype == Render_type::bumpmap_specular) {
      pbr.roughnessFactor = 1.0f - ((1.0f - 0.4f) * spec_strength);
   }
   else if (material.rendertype == Render_type::env_map) {
      pbr.roughnessFactor = 1.0f - spec_strength;
      pbr.metallicFactor = 1.0f - ((1.0f - 0.4f) * spec_strength);
   }

   return pbr;
}

auto add_material(fx::gltf::Document& doc, const scene::Material& material)
   -> fx::gltf::Material

{
   return {.alphaCutoff = 0.5f,
           .alphaMode = are_flags_set(material.flags, Render_flags::hardedged)
                           ? fx::gltf::Material::AlphaMode::Mask
                           : are_flags_set(material.flags, Render_flags::transparent)
                                ? fx::gltf::Material::AlphaMode::Blend
                                : fx::gltf::Material::AlphaMode::Opaque,
           .doubleSided = are_flags_set(material.flags, Render_flags::doublesided),
           .normalTexture = add_material_normal_texture(doc, material),
           .pbrMetallicRoughness = add_material_pbr(doc, material),
           .name = material.name};
}

auto add_skin_inverse_bind_matrices(fx::gltf::Document& doc,
                                    std::vector<std::uint8_t>& buffer,
                                    [[maybe_unused]] const scene::Scene& scene,
                                    const std::vector<std::uint8_t>& unified_bone_map)
   -> std::int32_t
{
   const auto accessor_index = doc.accessors.size();

   std::vector martices{unified_bone_map.size(), glm::identity<glm::mat4>()};

   doc.accessors.push_back(
      {.bufferView = add_to_buffer(doc, buffer, gsl::make_span(std::as_const(martices))),
       .count = static_cast<std::uint32_t>(martices.size()),
       .componentType = fx::gltf::Accessor::ComponentType::Float,
       .type = fx::gltf::Accessor::Type::Mat4});

   return static_cast<std::uint32_t>(accessor_index);
}

}

void save_scene(scene::Scene scene, File_saver& file_saver)
{
   const auto unified_bone_map = scene::unify_bone_maps(scene);
   unstripfy_scene_nodes_topologies(scene.nodes);

   fx::gltf::Document doc{};

   doc.buffers.emplace_back(); // embedded buffer

   std::vector<std::uint8_t> buffer;
   buffer.reserve(1000000);

   for (const auto& node : scene.nodes) {
      doc.nodes.push_back(
         {.name = node.name,
          .mesh = add_node_mesh(doc, buffer, node),
          .skin = (GLTF_EXPORT_SKIN && scene::has_skinned_geometry(node)) ? 0 : -1,
          .matrix = make_node_matrix(node.transform),
          .children = make_node_children_list(node.name, scene.nodes)});
   }

   for (const auto& material : scene.materials) {
      doc.materials.push_back(add_material(doc, material));
   }

   if constexpr (GLTF_EXPORT_SKIN && scene::has_skinned_geometry(scene)) {
      doc.skins.push_back(
         {.inverseBindMatrices =
             add_skin_inverse_bind_matrices(doc, buffer, scene, unified_bone_map),
          .skeleton = 0,
          .joints = {unified_bone_map.cbegin(), unified_bone_map.cend()}});
   }

   doc.scene = 0;
   doc.scenes.push_back({.name = scene.name, .nodes = {0}});
   doc.buffers.front() = {.byteLength = gsl::narrow<std::uint32_t>(buffer.size()),
                          .data = std::move(buffer)};

   fx::gltf::Save(doc, file_saver.build_file_path(""sv, scene.name, ".glb"sv).string(),
                  true);
}

}
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "MonitorStore.h"
#include "common/Clock.h"
#include "common/run_cmd.h"

#include "config.h"

#define DOUT_SUBSYS mon
#undef dout_prefix
#define dout_prefix _prefix(dir)
static ostream& _prefix(const string& dir) {
  return *_dout << "store(" << dir << ") ";
}

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sstream>
#include <sys/file.h>

MonitorStore::Error MonitorStore::Error::
FromErrno(const char *prefix, const char *prefix2, int errno_)
{
  char buf[128];
  const char *b2 = strerror_r(errno_, buf, sizeof(buf));
  ostringstream oss;
  oss << prefix << prefix2 << ": " << b2 << " (" << errno_ << ")";
  return MonitorStore::Error(oss.str());
}

MonitorStore::Error::
Error(const std::string &str_) : str(str_) { }

MonitorStore::Error::
~Error() throw () { }

const char *MonitorStore::Error::
what() const throw ()
{
  return str.c_str();
}

int MonitorStore::mount()
{
  char t[1024];

  dout(1) << "mount" << dendl;
  // verify dir exists
  DIR *d = ::opendir(dir.c_str());
  if (!d) {
    dout(1) << "basedir " << dir << " dne" << dendl;
    return -ENOENT;
  }
  ::closedir(d);

  // open lockfile
  snprintf(t, sizeof(t), "%s/lock", dir.c_str());
  lock_fd = ::open(t, O_CREAT|O_RDWR, 0600);
  if (lock_fd < 0)
    return -errno;
  struct flock l;
  memset(&l, 0, sizeof(l));
  l.l_type = F_WRLCK;
  l.l_whence = SEEK_SET;
  l.l_start = 0;
  l.l_len = 0;
  int r = ::fcntl(lock_fd, F_SETLK, &l);
  if (r < 0) {
    dout(0) << "failed to lock " << t << ", is another cmon still running?" << dendl;
    return -errno;
  }

  if (g_conf.chdir && g_conf.chdir[0] && dir[0] != '/') {
    // combine it with the cwd, in case fuse screws things up (i.e. fakefuse)
    string old = dir;
    char cwd[1024];
    getcwd(cwd, sizeof(cwd));
    dir = cwd;
    dir += "/";
    dir += old;
  }
  return 0;
}

int MonitorStore::umount()
{
  ::close(lock_fd);
  return 0;
}

int MonitorStore::mkfs()
{
  int ret = run_cmd("rm", "-rf", dir.c_str(), NULL);
  if (ret) {
    derr << "MonitorStore::mkfs: failed to remove " << dir
	 << ": rm returned " << ret << dendl;
    return ret;
  }

  ret = run_cmd("mkdir", "-p", dir.c_str(), NULL);
  if (ret) {
    derr << "MonitorStore::mkfs: failed to mkdir -p " << dir
	 << ": mkdir returned " << ret << dendl;
    return ret;
  }

  dout(0) << "created monfs at " << dir.c_str() << " for " << g_conf.id << dendl;
  return 0;
}

void MonitorStore::sync()
{
  dout(10) << "sync" << dendl;
  ::sync();
}

version_t MonitorStore::get_int(const char *a, const char *b)
{
  char fn[1024];
  if (b)
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  else
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);

  FILE *f = ::fopen(fn, "r");
  if (!f)
    return 0;

  char buf[20];
  ::fgets(buf, 20, f);
  ::fclose(f);

  version_t val = atoi(buf);

  if (b) {
    dout(15) << "get_int " << a << "/" << b << " = " << val << dendl;
  } else {
    dout(15) << "get_int " << a << " = " << val << dendl;
  }
  return val;
}

void MonitorStore::put_int(version_t val, const char *a, const char *b, bool sync)
{
  char fn[1024];
  snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  if (b) {
    ::mkdir(fn, 0755);
    dout(15) << "set_int " << a << "/" << b << " = " << val << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "set_int " << a << " = " << val << dendl;
  }

  char vs[30];
  snprintf(vs, sizeof(vs), "%lld\n", (unsigned long long)val);

  char tfn[1024];
  snprintf(tfn, sizeof(tfn), "%s.new", fn);

  int fd = ::open(tfn, O_WRONLY|O_CREAT, 0644);
  assert(fd >= 0);
  ::write(fd, vs, strlen(vs));
  if (sync)
    ::fsync(fd);
  ::close(fd);
  ::rename(tfn, fn);
}

// ----------------------------------------
// buffers

bool MonitorStore::exists_bl_ss(const char *a, const char *b)
{
  char fn[1024];
  if (b) {
    dout(15) << "exists_bl " << a << "/" << b << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "exists_bl " << a << dendl;
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  }

  struct stat st;
  int r = ::stat(fn, &st);
  //char buf[80];
  //dout(15) << "exists_bl stat " << fn << " r=" << r << " errno " << errno << " " << strerror_r(errno, buf, sizeof(buf)) << dendl;
  return r == 0;
}

int MonitorStore::erase_ss(const char *a, const char *b)
{
  char fn[1024];
  if (b) {
    dout(15) << "erase_ss " << a << "/" << b << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "erase_ss " << a << dendl;
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  }
  return ::unlink(fn);
}

int MonitorStore::get_bl_ss(bufferlist& bl, const char *a, const char *b)
{
  char fn[1024];
  if (b) {
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  }

  int fd = ::open(fn, O_RDONLY);
  if (fd < 0) {
    char buf[80];
    if (b) {
      dout(15) << "get_bl " << a << "/" << b << " " << strerror_r(errno, buf, sizeof(buf)) << dendl;
    } else {
      dout(15) << "get_bl " << a << " " << strerror_r(errno, buf, sizeof(buf)) << dendl;
    }
    return -errno;
  }

  // get size
  struct stat st;
  int rc = ::fstat(fd, &st);
  assert(rc == 0);
  __int32_t len = st.st_size;

  // read buffer
  bl.clear();
  bufferptr bp(len);
  int off = 0;
  while (off < len) {
    dout(20) << "reading at off " << off << " of " << len << dendl;
    int r = ::read(fd, bp.c_str()+off, len-off);
    if (r < 0) {
      char buf[80];
      dout(0) << "errno on read " << strerror_r(errno, buf, sizeof(buf)) << dendl;
    }
    assert(r>0);
    off += r;
  }
  bl.append(bp);
  ::close(fd);

  if (b) {
    dout(15) << "get_bl " << a << "/" << b << " = " << bl.length() << " bytes" << dendl;
  } else {
    dout(15) << "get_bl " << a << " = " << bl.length() << " bytes" << dendl;
  }

  return len;
}

int MonitorStore::write_bl_ss(bufferlist& bl, const char *a, const char *b, bool append, bool sync)
{
  char fn[1024];
  snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  if (b) {
    ::mkdir(fn, 0755);
    dout(15) << "put_bl " << a << "/" << b << " = " << bl.length() << " bytes" << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "put_bl " << a << " = " << bl.length() << " bytes" << dendl;
  }

  char tfn[1024];
  int err = 0;
  int fd;
  if (append) {
    fd = ::open(fn, O_WRONLY|O_CREAT|O_APPEND, 0644);
    if (fd < 0)
      throw Error::FromErrno("failed to open for append: ", fn, errno);
  } else {
    snprintf(tfn, sizeof(tfn), "%s.new", fn);
    fd = ::open(tfn, O_WRONLY|O_CREAT, 0644);
    if (fd < 0)
      throw Error::FromErrno("failed to open: ", tfn, errno);
  }

  err = bl.write_fd(fd);

  if (sync && !err)
    ::fsync(fd);
  ::close(fd);
  if (!append && !err) {
    ::rename(tfn, fn);
  }

  assert(!err);  // for now

  return err;
}

<commit_msg>monitorstore: check return values<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "MonitorStore.h"
#include "common/Clock.h"
#include "common/run_cmd.h"

#include "config.h"

#define DOUT_SUBSYS mon
#undef dout_prefix
#define dout_prefix _prefix(dir)
static ostream& _prefix(const string& dir) {
  return *_dout << "store(" << dir << ") ";
}

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sstream>
#include <sys/file.h>

MonitorStore::Error MonitorStore::Error::
FromErrno(const char *prefix, const char *prefix2, int errno_)
{
  char buf[128];
  const char *b2 = strerror_r(errno_, buf, sizeof(buf));
  ostringstream oss;
  oss << prefix << prefix2 << ": " << b2 << " (" << errno_ << ")";
  return MonitorStore::Error(oss.str());
}

MonitorStore::Error::
Error(const std::string &str_) : str(str_) { }

MonitorStore::Error::
~Error() throw () { }

const char *MonitorStore::Error::
what() const throw ()
{
  return str.c_str();
}

int MonitorStore::mount()
{
  char t[1024];

  dout(1) << "mount" << dendl;
  // verify dir exists
  DIR *d = ::opendir(dir.c_str());
  if (!d) {
    dout(1) << "basedir " << dir << " dne" << dendl;
    return -ENOENT;
  }
  ::closedir(d);

  // open lockfile
  snprintf(t, sizeof(t), "%s/lock", dir.c_str());
  lock_fd = ::open(t, O_CREAT|O_RDWR, 0600);
  if (lock_fd < 0)
    return -errno;
  struct flock l;
  memset(&l, 0, sizeof(l));
  l.l_type = F_WRLCK;
  l.l_whence = SEEK_SET;
  l.l_start = 0;
  l.l_len = 0;
  int r = ::fcntl(lock_fd, F_SETLK, &l);
  if (r < 0) {
    dout(0) << "failed to lock " << t << ", is another cmon still running?" << dendl;
    return -errno;
  }

  if (g_conf.chdir && g_conf.chdir[0] && dir[0] != '/') {
    // combine it with the cwd, in case fuse screws things up (i.e. fakefuse)
    string old = dir;
    char cwd[PATH_MAX];
    char *p = getcwd(cwd, sizeof(cwd));
    dir = p;
    dir += "/";
    dir += old;
  }
  return 0;
}

int MonitorStore::umount()
{
  ::close(lock_fd);
  return 0;
}

int MonitorStore::mkfs()
{
  int ret = run_cmd("rm", "-rf", dir.c_str(), NULL);
  if (ret) {
    derr << "MonitorStore::mkfs: failed to remove " << dir
	 << ": rm returned " << ret << dendl;
    return ret;
  }

  ret = run_cmd("mkdir", "-p", dir.c_str(), NULL);
  if (ret) {
    derr << "MonitorStore::mkfs: failed to mkdir -p " << dir
	 << ": mkdir returned " << ret << dendl;
    return ret;
  }

  dout(0) << "created monfs at " << dir.c_str() << " for " << g_conf.id << dendl;
  return 0;
}

void MonitorStore::sync()
{
  dout(10) << "sync" << dendl;
  ::sync();
}

version_t MonitorStore::get_int(const char *a, const char *b)
{
  char fn[1024];
  if (b)
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  else
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);

  int fd = ::open(fn, O_RDONLY);
  if (fd < 0)
    return 0;

  char buf[20];
  int r = ::read(fd, buf, sizeof(buf));
  assert(r >= 0);
  ::close(fd);

  version_t val = atoi(buf);

  if (b) {
    dout(15) << "get_int " << a << "/" << b << " = " << val << dendl;
  } else {
    dout(15) << "get_int " << a << " = " << val << dendl;
  }
  return val;
}

void MonitorStore::put_int(version_t val, const char *a, const char *b, bool sync)
{
  char fn[1024];
  snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  if (b) {
    ::mkdir(fn, 0755);
    dout(15) << "set_int " << a << "/" << b << " = " << val << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "set_int " << a << " = " << val << dendl;
  }

  char vs[30];
  snprintf(vs, sizeof(vs), "%lld\n", (unsigned long long)val);

  char tfn[1024];
  snprintf(tfn, sizeof(tfn), "%s.new", fn);

  int fd = ::open(tfn, O_WRONLY|O_CREAT, 0644);
  assert(fd >= 0);
  int r = ::write(fd, vs, strlen(vs));
  assert(r >= 0);
  if (sync)
    ::fsync(fd);
  ::close(fd);
  ::rename(tfn, fn);
}

// ----------------------------------------
// buffers

bool MonitorStore::exists_bl_ss(const char *a, const char *b)
{
  char fn[1024];
  if (b) {
    dout(15) << "exists_bl " << a << "/" << b << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "exists_bl " << a << dendl;
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  }

  struct stat st;
  int r = ::stat(fn, &st);
  //char buf[80];
  //dout(15) << "exists_bl stat " << fn << " r=" << r << " errno " << errno << " " << strerror_r(errno, buf, sizeof(buf)) << dendl;
  return r == 0;
}

int MonitorStore::erase_ss(const char *a, const char *b)
{
  char fn[1024];
  if (b) {
    dout(15) << "erase_ss " << a << "/" << b << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "erase_ss " << a << dendl;
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  }
  return ::unlink(fn);
}

int MonitorStore::get_bl_ss(bufferlist& bl, const char *a, const char *b)
{
  char fn[1024];
  if (b) {
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  }

  int fd = ::open(fn, O_RDONLY);
  if (fd < 0) {
    char buf[80];
    if (b) {
      dout(15) << "get_bl " << a << "/" << b << " " << strerror_r(errno, buf, sizeof(buf)) << dendl;
    } else {
      dout(15) << "get_bl " << a << " " << strerror_r(errno, buf, sizeof(buf)) << dendl;
    }
    return -errno;
  }

  // get size
  struct stat st;
  int rc = ::fstat(fd, &st);
  assert(rc == 0);
  __int32_t len = st.st_size;

  // read buffer
  bl.clear();
  bufferptr bp(len);
  int off = 0;
  while (off < len) {
    dout(20) << "reading at off " << off << " of " << len << dendl;
    int r = ::read(fd, bp.c_str()+off, len-off);
    if (r < 0) {
      char buf[80];
      dout(0) << "errno on read " << strerror_r(errno, buf, sizeof(buf)) << dendl;
    }
    assert(r>0);
    off += r;
  }
  bl.append(bp);
  ::close(fd);

  if (b) {
    dout(15) << "get_bl " << a << "/" << b << " = " << bl.length() << " bytes" << dendl;
  } else {
    dout(15) << "get_bl " << a << " = " << bl.length() << " bytes" << dendl;
  }

  return len;
}

int MonitorStore::write_bl_ss(bufferlist& bl, const char *a, const char *b, bool append, bool sync)
{
  char fn[1024];
  snprintf(fn, sizeof(fn), "%s/%s", dir.c_str(), a);
  if (b) {
    ::mkdir(fn, 0755);
    dout(15) << "put_bl " << a << "/" << b << " = " << bl.length() << " bytes" << dendl;
    snprintf(fn, sizeof(fn), "%s/%s/%s", dir.c_str(), a, b);
  } else {
    dout(15) << "put_bl " << a << " = " << bl.length() << " bytes" << dendl;
  }

  char tfn[1024];
  int err = 0;
  int fd;
  if (append) {
    fd = ::open(fn, O_WRONLY|O_CREAT|O_APPEND, 0644);
    if (fd < 0)
      throw Error::FromErrno("failed to open for append: ", fn, errno);
  } else {
    snprintf(tfn, sizeof(tfn), "%s.new", fn);
    fd = ::open(tfn, O_WRONLY|O_CREAT, 0644);
    if (fd < 0)
      throw Error::FromErrno("failed to open: ", tfn, errno);
  }

  err = bl.write_fd(fd);

  if (sync && !err)
    ::fsync(fd);
  ::close(fd);
  if (!append && !err) {
    ::rename(tfn, fn);
  }

  assert(!err);  // for now

  return err;
}

<|endoftext|>


<commit_before>/*
Copyright (c) 2016 AscEmu Team <http://www.ascemu.org/>
This file is released under the MIT license. See README-MIT for more information.
*/

#include "Setup.h"
#include "Instance_TheVioletHold.h"

struct Location EventPreGuardSP[] = //PortalGuard spwns
{
    { 1888.046265f, 761.654053f, 47.667f, 2.2332f }, // [0] left
    { 1928.545532f, 803.849731f, 52.411f, 3.1223f }, // [1] center
    { 1878.080933f, 844.850281f, 43.334f, 4.2376f }  // [2] right
};

struct Location EventPreGuardWP[] = //PortalGuard WPs
{
    { 1858.386353f, 812.804993f, 42.9995f, 4.2376f }, // [0] left
    { 1861.916382f, 803.873230f, 43.6728f, 3.1223f }, // [1] center
    { 1858.678101f, 796.081970f, 43.1944f, 2.2332f }  // [2] right
};

enum DataIndex
{
    TVH_PHASE_1 = 0, // main event
    TVH_PHASE_2 = 1, // 1. portal
    TVH_PHASE_3 = 2, // 2. portal
    TVH_PHASE_4 = 3, // 3. portal
    TVH_PHASE_5 = 4, // 4. portal
    TVH_PHASE_6 = 5, // 5. portal
    TVH_PHASE_DONE = 6, // 6. portal

    TVH_END = 7
};

///////////////////////////////////////////////////////
//TheVioletHold Instance
class TheVioletHoldScript : public MoonInstanceScript
{
    friend class SinclariGossip; // Friendship forever ;-)

    private:

        int32 m_numBarrel;
        uint32 m_phaseData[TVH_END];

    public:

        MOONSCRIPT_INSTANCE_FACTORY_FUNCTION(TheVioletHoldScript, MoonInstanceScript);
        TheVioletHoldScript(MapMgr* pMapMgr) : MoonInstanceScript(pMapMgr)
        {
            m_numBarrel = 0;

            for (uint8 i = 0; i < TVH_END; ++i)
                m_phaseData[i] = State_NotStarted;
        };

        void SetData(uint32 pIndex, uint32 pData)
        {
            if (pIndex >= TVH_END)
                return;

            // If Data = MainEvent, set state "PreProgress". Gossip Sinclar 1 + 2
            if (pIndex == TVH_PHASE_1)
                mInstance->GetWorldStatesHandler().SetWorldStateForZone(0, AREA_VIOLET_HOLD, WORLDSTATE_VH, State_PreProgress);

            // If Data = second event, set state "InProgress". Gossip Sinclari Case 3
            if (pIndex == TVH_PHASE_2)
                mInstance->GetWorldStatesHandler().SetWorldStateForZone(0, AREA_VIOLET_HOLD, WORLDSTATE_VH, State_InProgress);

            m_phaseData[pIndex] = pData;
        };

        uint32 GetData(uint32 pIndex)
        {
            // If Phase = End/finishes, reset the Phases to 0
            if (pIndex >= TVH_END)
                return 0;

            return m_phaseData[pIndex];
        };

        void SetInstanceData(uint32 pType, uint32 pIndex, uint32 pData)
        {
            if (pType != Data_EncounterState || pIndex == 0)
                return;

            EncounterMap::iterator Iter = mEncounters.find(pIndex);
            if (Iter == mEncounters.end())
                return;

            (*Iter).second.mState = (EncounterState)pData;
        };

        uint32 GetInstanceData(uint32 pType, uint32 pIndex)
        {
            if (pType != Data_EncounterState || pIndex == 0)
                return 0;

            EncounterMap::iterator Iter = mEncounters.find(pIndex);
            if (Iter == mEncounters.end())
                return 0;

            return (*Iter).second.mState;
        };

        void OnGameObjectActivate(GameObject* pGameObject, Player* pPlayer)
        {};

        void OnPlayerEnter(Player* pPlayer)
        {
            TheVioletHoldScript* pInstance = (TheVioletHoldScript*)pPlayer->GetMapMgr()->GetScript();
            if (!pInstance)
                return;

            if (pInstance->GetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD) == State_NotStarted)
            {
                mEncounters.insert(EncounterMap::value_type(MAP_VIOLET_HOLD, State_NotStarted));
            }

        }
};

#define SINCLARI_SAY_1 "Prison guards, we are oleaving! These adventurers are taking over! Go go go!"
#define SINCLARY_SAY_2 "I'm locking the door. Good luck, and thank you for doing this."

#define GO_TVH_PRISON_SEAL 191723

#define SINCLARI_MAX_WP 4

///////////////////////////////////////////////////////
//Lieutnant Sinclari StartEvent
class SinclariAI : public MoonScriptCreatureAI
{
    public:

        MOONSCRIPT_FACTORY_FUNCTION(SinclariAI, MoonScriptCreatureAI);
        SinclariAI(Creature* pCreature) : MoonScriptCreatureAI(pCreature)
        {
            _unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
        }

        void OnReachWP(uint32 iWaypointId, bool bForwards)
        {
            switch (iWaypointId)
            {
                case 2:
                {
                    _unit->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, SINCLARI_SAY_1);
                    _unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_FORWARDTHENSTOP);
                }
                break;

                case 4:
                {
                    _unit->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, SINCLARY_SAY_2);
                    _unit->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
                    TheVioletHoldScript* pInstance = (TheVioletHoldScript*)_unit->GetMapMgr()->GetScript();
                    pInstance->SetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD, State_InProgress);

                    GameObject* pVioletHoldDoor = pInstance->FindClosestGameObjectOnMap(GO_TVH_PRISON_SEAL, 1822.59f, 803.93f, 44.36f);
                    if (pVioletHoldDoor != NULL)
                        pVioletHoldDoor->SetState(GO_STATE_CLOSED);
                }
                break;
            }
        }
};

enum eGossipTexts
{
    SINCLARI_ON_HELLO = 13853,
    SINCLARI_ON_FINISH = 13854,
    SINCLARI_OUTSIDE = 14271
};

enum GossipItem
{
    SINCLARI_ACTIVATE = 600,
    SINCLARI_GET_SAFETY = 601,
    SINCLARI_SEND_ME_IN = 602
};

///////////////////////////////////////////////////////
//Lieutnant Sinclari Gossip and init events
//Sinclari Gossip
class SinclariGossip : public GossipScript
{
    public:

        void GossipHello(Object* pObject, Player* pPlayer)
        {
            TheVioletHoldScript* pInstance = (TheVioletHoldScript*)pPlayer->GetMapMgr()->GetScript();
            if (!pInstance)
                return;

            GossipMenu* menu;

            //Page 1: Textid and first menu item
            if (pInstance->GetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD) == State_NotStarted)
            {
                objmgr.CreateGossipMenuForPlayer(&menu, pObject->GetGUID(), SINCLARI_ON_HELLO, pPlayer);
                menu->AddItem(GOSSIP_ICON_CHAT, pPlayer->GetSession()->LocalizedGossipOption(SINCLARI_ACTIVATE), 1);

                menu->SendTo(pPlayer);
            }

            //If VioletHold is started, Sinclari has this item for people who aould join.
            if (pInstance->GetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD) == State_InProgress)
            {
                objmgr.CreateGossipMenuForPlayer(&menu, pObject->GetGUID(), SINCLARI_OUTSIDE, pPlayer);
                menu->AddItem(GOSSIP_ICON_CHAT, pPlayer->GetSession()->LocalizedGossipOption(SINCLARI_SEND_ME_IN), 3);

                menu->SendTo(pPlayer);
            }
        };

        void GossipSelectOption(Object* pObject, Player* pPlayer, uint32 Id, uint32 IntId, const char* Code)
        {
            TheVioletHoldScript* pInstance = (TheVioletHoldScript*)pPlayer->GetMapMgr()->GetScript();

            if (!pInstance)
                return;

            if (!pObject->IsCreature())
                return;

            Creature* pCreature = static_cast<Creature*>(pObject);

            switch (IntId)
            {
                case 0:
                    GossipHello(pObject, pPlayer);
                    break;

                case 1:
                {
                    GossipMenu* menu;
                    objmgr.CreateGossipMenuForPlayer(&menu, pObject->GetGUID(), SINCLARI_ON_FINISH, pPlayer);
                    menu->AddItem(GOSSIP_ICON_CHAT, pPlayer->GetSession()->LocalizedGossipOption(SINCLARI_GET_SAFETY), 2);
                    menu->SendTo(pPlayer);

                    // New Encounter State included
                    pInstance->SetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD, State_PreProgress);
                }break;

                case 2:
                {
                    static_cast<Creature*>(pObject)->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
                    pCreature->GetAIInterface()->setMoveType(MOVEMENTTYPE_NONE);
                    //pCreature->MoveToWaypoint(1);
                    pCreature->GetAIInterface()->StopMovement(10);

                }break;

                case 3:
                {
                    Arcemu::Gossip::Menu::Complete(pPlayer);
                    pPlayer->SafeTeleport(pPlayer->GetInstanceID(), MAP_VIOLET_HOLD, 1830.531006f, 803.939758f, 44.340508f, 6.281611f);
                }break;
            }
        }
};

///////////////////////////////////////////////////////
//VH Guards
class VHGuardsAI : public MoonScriptCreatureAI
{
    public:

        MOONSCRIPT_FACTORY_FUNCTION(VHGuardsAI, MoonScriptCreatureAI);
        VHGuardsAI(Creature* pCreature) : MoonScriptCreatureAI(pCreature)
        {
            _unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
        }

        //WPs inserted in db.

};

///////////////////////////////////////////////////////
//Boss: Erekem
//class ErekemAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Moragg
//class MoraggAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Ichoron
//class IchoronAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Xevozz
//class XevozzAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Lavanthos
//class LavanthosAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Zuramat the Obliterator
//class ZuramatTheObliteratorAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Final Boss: Cyanigosa
//class CyanigosaAI : public CreatureAIScript

void SetupTheVioletHold(ScriptMgr* mgr)
{
    //Instance
    mgr->register_instance_script(MAP_VIOLET_HOLD, &TheVioletHoldScript::Create);

    //Sinclari and Guards
    mgr->register_creature_script(CN_LIEUTNANT_SINCLARI, &SinclariAI::Create);
    mgr->register_creature_script(CN_VIOLET_HOLD_GUARD, &VHGuardsAI::Create);

    //Bosses
    //mgr->register_creature_script(CN_EREKEM, &ErekemAI::Create);
    //mgr->register_creature_script(CN_MORAGG, &MoraggAI::Create);
    //mgr->register_creature_script(CN_ICHORON, &IchoronAI::Create);
    //mgr->register_creature_script(CN_XEVOZZ, &XevozzAI::Create);
    //mgr->register_creature_script(CN_LAVANTHOR, &LavanthorAI::Create);
    //mgr->register_creature_script(CN_TURAMAT_THE_OBLITERATOR, &ZuramatTheObliteratorAI::Create);
    //mgr->register_creature_script(CN_CYANIGOSA, &CyanigosaAI::Create);

    GossipScript* GSinclari = new SinclariGossip;
    mgr->register_gossip_script(CN_LIEUTNANT_SINCLARI, GSinclari);

}<commit_msg>Fixed typo for Lieutnant Sinclari say event<commit_after>/*
Copyright (c) 2016 AscEmu Team <http://www.ascemu.org/>
This file is released under the MIT license. See README-MIT for more information.
*/

#include "Setup.h"
#include "Instance_TheVioletHold.h"

struct Location EventPreGuardSP[] = //PortalGuard spwns
{
    { 1888.046265f, 761.654053f, 47.667f, 2.2332f }, // [0] left
    { 1928.545532f, 803.849731f, 52.411f, 3.1223f }, // [1] center
    { 1878.080933f, 844.850281f, 43.334f, 4.2376f }  // [2] right
};

struct Location EventPreGuardWP[] = //PortalGuard WPs
{
    { 1858.386353f, 812.804993f, 42.9995f, 4.2376f }, // [0] left
    { 1861.916382f, 803.873230f, 43.6728f, 3.1223f }, // [1] center
    { 1858.678101f, 796.081970f, 43.1944f, 2.2332f }  // [2] right
};

enum DataIndex
{
    TVH_PHASE_1 = 0, // main event
    TVH_PHASE_2 = 1, // 1. portal
    TVH_PHASE_3 = 2, // 2. portal
    TVH_PHASE_4 = 3, // 3. portal
    TVH_PHASE_5 = 4, // 4. portal
    TVH_PHASE_6 = 5, // 5. portal
    TVH_PHASE_DONE = 6, // 6. portal

    TVH_END = 7
};

///////////////////////////////////////////////////////
//TheVioletHold Instance
class TheVioletHoldScript : public MoonInstanceScript
{
    friend class SinclariGossip; // Friendship forever ;-)

    private:

        int32 m_numBarrel;
        uint32 m_phaseData[TVH_END];

    public:

        MOONSCRIPT_INSTANCE_FACTORY_FUNCTION(TheVioletHoldScript, MoonInstanceScript);
        TheVioletHoldScript(MapMgr* pMapMgr) : MoonInstanceScript(pMapMgr)
        {
            m_numBarrel = 0;

            for (uint8 i = 0; i < TVH_END; ++i)
                m_phaseData[i] = State_NotStarted;
        };

        void SetData(uint32 pIndex, uint32 pData)
        {
            if (pIndex >= TVH_END)
                return;

            // If Data = MainEvent, set state "PreProgress". Gossip Sinclar 1 + 2
            if (pIndex == TVH_PHASE_1)
                mInstance->GetWorldStatesHandler().SetWorldStateForZone(0, AREA_VIOLET_HOLD, WORLDSTATE_VH, State_PreProgress);

            // If Data = second event, set state "InProgress". Gossip Sinclari Case 3
            if (pIndex == TVH_PHASE_2)
                mInstance->GetWorldStatesHandler().SetWorldStateForZone(0, AREA_VIOLET_HOLD, WORLDSTATE_VH, State_InProgress);

            m_phaseData[pIndex] = pData;
        };

        uint32 GetData(uint32 pIndex)
        {
            // If Phase = End/finishes, reset the Phases to 0
            if (pIndex >= TVH_END)
                return 0;

            return m_phaseData[pIndex];
        };

        void SetInstanceData(uint32 pType, uint32 pIndex, uint32 pData)
        {
            if (pType != Data_EncounterState || pIndex == 0)
                return;

            EncounterMap::iterator Iter = mEncounters.find(pIndex);
            if (Iter == mEncounters.end())
                return;

            (*Iter).second.mState = (EncounterState)pData;
        };

        uint32 GetInstanceData(uint32 pType, uint32 pIndex)
        {
            if (pType != Data_EncounterState || pIndex == 0)
                return 0;

            EncounterMap::iterator Iter = mEncounters.find(pIndex);
            if (Iter == mEncounters.end())
                return 0;

            return (*Iter).second.mState;
        };

        void OnGameObjectActivate(GameObject* pGameObject, Player* pPlayer)
        {};

        void OnPlayerEnter(Player* pPlayer)
        {
            TheVioletHoldScript* pInstance = (TheVioletHoldScript*)pPlayer->GetMapMgr()->GetScript();
            if (!pInstance)
                return;

            if (pInstance->GetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD) == State_NotStarted)
            {
                mEncounters.insert(EncounterMap::value_type(MAP_VIOLET_HOLD, State_NotStarted));
            }

        }
};

#define SINCLARI_SAY_1 "Prison guards, we are leaving! These adventurers are taking over! Go go go!"
#define SINCLARY_SAY_2 "I'm locking the door. Good luck, and thank you for doing this."

#define GO_TVH_PRISON_SEAL 191723

#define SINCLARI_MAX_WP 4

///////////////////////////////////////////////////////
//Lieutnant Sinclari StartEvent
class SinclariAI : public MoonScriptCreatureAI
{
    public:

        MOONSCRIPT_FACTORY_FUNCTION(SinclariAI, MoonScriptCreatureAI);
        SinclariAI(Creature* pCreature) : MoonScriptCreatureAI(pCreature)
        {
            _unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
        }

        void OnReachWP(uint32 iWaypointId, bool bForwards)
        {
            switch (iWaypointId)
            {
                case 2:
                {
                    _unit->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, SINCLARI_SAY_1);
                    _unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_FORWARDTHENSTOP);
                }
                break;

                case 4:
                {
                    _unit->SendChatMessage(CHAT_MSG_MONSTER_SAY, LANG_UNIVERSAL, SINCLARY_SAY_2);
                    _unit->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
                    TheVioletHoldScript* pInstance = (TheVioletHoldScript*)_unit->GetMapMgr()->GetScript();
                    pInstance->SetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD, State_InProgress);

                    GameObject* pVioletHoldDoor = pInstance->FindClosestGameObjectOnMap(GO_TVH_PRISON_SEAL, 1822.59f, 803.93f, 44.36f);
                    if (pVioletHoldDoor != NULL)
                        pVioletHoldDoor->SetState(GO_STATE_CLOSED);
                }
                break;
            }
        }
};

enum eGossipTexts
{
    SINCLARI_ON_HELLO = 13853,
    SINCLARI_ON_FINISH = 13854,
    SINCLARI_OUTSIDE = 14271
};

enum GossipItem
{
    SINCLARI_ACTIVATE = 600,
    SINCLARI_GET_SAFETY = 601,
    SINCLARI_SEND_ME_IN = 602
};

///////////////////////////////////////////////////////
//Lieutnant Sinclari Gossip and init events
//Sinclari Gossip
class SinclariGossip : public GossipScript
{
    public:

        void GossipHello(Object* pObject, Player* pPlayer)
        {
            TheVioletHoldScript* pInstance = (TheVioletHoldScript*)pPlayer->GetMapMgr()->GetScript();
            if (!pInstance)
                return;

            GossipMenu* menu;

            //Page 1: Textid and first menu item
            if (pInstance->GetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD) == State_NotStarted)
            {
                objmgr.CreateGossipMenuForPlayer(&menu, pObject->GetGUID(), SINCLARI_ON_HELLO, pPlayer);
                menu->AddItem(GOSSIP_ICON_CHAT, pPlayer->GetSession()->LocalizedGossipOption(SINCLARI_ACTIVATE), 1);

                menu->SendTo(pPlayer);
            }

            //If VioletHold is started, Sinclari has this item for people who aould join.
            if (pInstance->GetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD) == State_InProgress)
            {
                objmgr.CreateGossipMenuForPlayer(&menu, pObject->GetGUID(), SINCLARI_OUTSIDE, pPlayer);
                menu->AddItem(GOSSIP_ICON_CHAT, pPlayer->GetSession()->LocalizedGossipOption(SINCLARI_SEND_ME_IN), 3);

                menu->SendTo(pPlayer);
            }
        };

        void GossipSelectOption(Object* pObject, Player* pPlayer, uint32 Id, uint32 IntId, const char* Code)
        {
            TheVioletHoldScript* pInstance = (TheVioletHoldScript*)pPlayer->GetMapMgr()->GetScript();

            if (!pInstance)
                return;

            if (!pObject->IsCreature())
                return;

            Creature* pCreature = static_cast<Creature*>(pObject);

            switch (IntId)
            {
                case 0:
                    GossipHello(pObject, pPlayer);
                    break;

                case 1:
                {
                    GossipMenu* menu;
                    objmgr.CreateGossipMenuForPlayer(&menu, pObject->GetGUID(), SINCLARI_ON_FINISH, pPlayer);
                    menu->AddItem(GOSSIP_ICON_CHAT, pPlayer->GetSession()->LocalizedGossipOption(SINCLARI_GET_SAFETY), 2);
                    menu->SendTo(pPlayer);

                    // New Encounter State included
                    pInstance->SetInstanceData(Data_EncounterState, MAP_VIOLET_HOLD, State_PreProgress);
                }break;

                case 2:
                {
                    static_cast<Creature*>(pObject)->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
                    pCreature->GetAIInterface()->setMoveType(MOVEMENTTYPE_NONE);
                    //pCreature->MoveToWaypoint(1);
                    pCreature->GetAIInterface()->StopMovement(10);

                }break;

                case 3:
                {
                    Arcemu::Gossip::Menu::Complete(pPlayer);
                    pPlayer->SafeTeleport(pPlayer->GetInstanceID(), MAP_VIOLET_HOLD, 1830.531006f, 803.939758f, 44.340508f, 6.281611f);
                }break;
            }
        }
};

///////////////////////////////////////////////////////
//VH Guards
class VHGuardsAI : public MoonScriptCreatureAI
{
    public:

        MOONSCRIPT_FACTORY_FUNCTION(VHGuardsAI, MoonScriptCreatureAI);
        VHGuardsAI(Creature* pCreature) : MoonScriptCreatureAI(pCreature)
        {
            _unit->GetAIInterface()->setMoveType(MOVEMENTTYPE_WANTEDWP);
        }

        //WPs inserted in db.

};

///////////////////////////////////////////////////////
//Boss: Erekem
//class ErekemAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Moragg
//class MoraggAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Ichoron
//class IchoronAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Xevozz
//class XevozzAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Lavanthos
//class LavanthosAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Boss: Zuramat the Obliterator
//class ZuramatTheObliteratorAI : public CreatureAIScript

///////////////////////////////////////////////////////
//Final Boss: Cyanigosa
//class CyanigosaAI : public CreatureAIScript

void SetupTheVioletHold(ScriptMgr* mgr)
{
    //Instance
    mgr->register_instance_script(MAP_VIOLET_HOLD, &TheVioletHoldScript::Create);

    //Sinclari and Guards
    mgr->register_creature_script(CN_LIEUTNANT_SINCLARI, &SinclariAI::Create);
    mgr->register_creature_script(CN_VIOLET_HOLD_GUARD, &VHGuardsAI::Create);

    //Bosses
    //mgr->register_creature_script(CN_EREKEM, &ErekemAI::Create);
    //mgr->register_creature_script(CN_MORAGG, &MoraggAI::Create);
    //mgr->register_creature_script(CN_ICHORON, &IchoronAI::Create);
    //mgr->register_creature_script(CN_XEVOZZ, &XevozzAI::Create);
    //mgr->register_creature_script(CN_LAVANTHOR, &LavanthorAI::Create);
    //mgr->register_creature_script(CN_TURAMAT_THE_OBLITERATOR, &ZuramatTheObliteratorAI::Create);
    //mgr->register_creature_script(CN_CYANIGOSA, &CyanigosaAI::Create);

    GossipScript* GSinclari = new SinclariGossip;
    mgr->register_gossip_script(CN_LIEUTNANT_SINCLARI, GSinclari);

}<|endoftext|>


<commit_before>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

/*
   This file contains special stubs that are needed to make certain
   things work within a user job that can't use their normal
   functionality.
*/

#include "condor_common.h"
#include "condor_io.h"
#include "condor_sys.h"
#include "condor_debug.h"
#include "exit.h"

extern	ReliSock* syscall_sock;

extern "C" {

extern	int		DebugFlags;
int		_condor_DebugFD = 0;

/*
  We need our own definition of my_ip_addr(), which is used by
  Sock::bind() to support Condor on machines with multiple network
  interfaces.  This version, instead of looking in a config file for
  magic parameters, looks at the existing syscall_sock and grabs the
  IP address off of there.
*/
unsigned int
my_ip_addr()
{
	return syscall_sock->get_ip_int();
}

/*
  _condor_dprintf_va is the real meat of dprintf().  We have different
  concerns inside the user job.  All we need to care about in here is
  making sure we have the right syscall mode.  Otherwise, we don't
  need to do anything complex with priv states, locking, etc.
*/
void
_condor_dprintf_va( int flags, char* fmt, va_list args )
{
	int scm;
	int no_fd = FALSE;

		/* See if this is one of the messages we are logging */
	if( !(flags&DebugFlags) ) {
		return;
	}

		/* If dprintf() isn't initialized, don't seg fault */
	if( ! _condor_DebugFD ) {
		_condor_DebugFD = 2; /* stderr */
		no_fd = TRUE;
	}

		/*
		  When talking to the debug fd, you are talking to an fd that
		  is not visible to the user.  It is not entered in the
		  virtual file table, and, hence, you should be in unmapped
		  mode.
		*/
	scm = SetSyscalls( SYS_LOCAL | SYS_UNMAPPED );

		/* Actually print the message */
	_condor_vfprintf_va( _condor_DebugFD, fmt, args );

		/* Restore our syscall mode */
	(void) SetSyscalls( scm );

	if( no_fd ) {
		_condor_DebugFD = 0;
	}
}

/*
   Our special version of vfprintf() that doesn't use the clib and
   doesn't call malloc(), etc.
*/
int
_condor_vfprintf_va( int fd, char* fmt, va_list args )
{
		/*
		   This is totally wrong.  It's just a stub that accomplishes
		   the old functionality until this function is replaced by a
		   real version that accomplishes the new goal. -Derek
		*/
	FILE* fp;
	fp = fdopen( fd, "a" );
	vfprintf( fp, fmt, args );
}

/*
   This is called by the dprintf_init() linked in with the user job in
   case of fatal error.  The regular _condor_dprintf_exit() has many
   more concerns.  We can just exit, though we want to use Suicide()
   so we send ourselves SIGKILL, instead of actually exiting.  If we
   exit, we leave the job queue, which isn't what we want.  Hopefully,
   we'll never get here.
*/
void
_condor_dprintf_exit( void )
{
	Suicide();
}

#if !defined(WIN32)
/*
  Can't open something because we are out of fd's.  Try to let
  somebody know what happened.  In the user job, we don't want to
  close a bunch of fds, since we'll loose our debug socket, which is
  always open.  In fact, we shouldn't have to close anything to be
  able to dprintf().  So, just dprintf(), flush the fd for good
  measure, and call Suicide() (so we don't leave the job queue).
*/
void
_condor_fd_panic( int line, char* file )
{
	dprintf( D_ALWAYS,
			 "**** PANIC -- OUT OF FILE DESCRIPTORS at line %d in %s\n",
			 line, file );
	Suicide();
}
#endif /* ! LOOSE32 */

} /* extern "C" */

<commit_msg>+ Completed implementation of _condor_vfprintf_va().<commit_after>/***************************Copyright-DO-NOT-REMOVE-THIS-LINE**
 * CONDOR Copyright Notice
 *
 * See LICENSE.TXT for additional notices and disclaimers.
 *
 * Copyright (c)1990-1998 CONDOR Team, Computer Sciences Department,
 * University of Wisconsin-Madison, Madison, WI.  All Rights Reserved.
 * No use of the CONDOR Software Program Source Code is authorized
 * without the express consent of the CONDOR Team.  For more information
 * contact: CONDOR Team, Attention: Professor Miron Livny,
 * 7367 Computer Sciences, 1210 W. Dayton St., Madison, WI 53706-1685,
 * (608) 262-0856 or miron@cs.wisc.edu.
 *
 * U.S. Government Rights Restrictions: Use, duplication, or disclosure
 * by the U.S. Government is subject to restrictions as set forth in
 * subparagraph (c)(1)(ii) of The Rights in Technical Data and Computer
 * Software clause at DFARS 252.227-7013 or subparagraphs (c)(1) and
 * (2) of Commercial Computer Software-Restricted Rights at 48 CFR
 * 52.227-19, as applicable, CONDOR Team, Attention: Professor Miron
 * Livny, 7367 Computer Sciences, 1210 W. Dayton St., Madison,
 * WI 53706-1685, (608) 262-0856 or miron@cs.wisc.edu.
****************************Copyright-DO-NOT-REMOVE-THIS-LINE**/

/*
   This file contains special stubs that are needed to make certain
   things work within a user job that can't use their normal
   functionality.
*/

#include "condor_common.h"
#include "condor_io.h"
#include "condor_sys.h"
#include "condor_debug.h"
#include "exit.h"

extern	ReliSock* syscall_sock;

extern "C" {

extern	int		DebugFlags;
int		_condor_DebugFD = 0;

static int _condor_vfprintf_va( int fd, char* fmt, va_list args );
static int _condor_itoa(int quantity, char *out, int base);
extern int SetSyscalls(int);
extern int SYSCALL(int, ...);

/*
  We need our own definition of my_ip_addr(), which is used by
  Sock::bind() to support Condor on machines with multiple network
  interfaces.  This version, instead of looking in a config file for
  magic parameters, looks at the existing syscall_sock and grabs the
  IP address off of there.
*/
unsigned int
my_ip_addr()
{
	return syscall_sock->get_ip_int();
}

/*
  _condor_dprintf_va is the real meat of dprintf().  We have different
  concerns inside the user job.  All we need to care about in here is
  making sure we have the right syscall mode.  Otherwise, we don't
  need to do anything complex with priv states, locking, etc.
*/
void
_condor_dprintf_va( int flags, char* fmt, va_list args )
{
	int scm;
	int no_fd = FALSE;

		/* See if this is one of the messages we are logging */
	if( !(flags&DebugFlags) ) {
		return;
	}

		/* If dprintf() isn't initialized, don't seg fault */
	if( ! _condor_DebugFD ) {
		_condor_DebugFD = 2; /* stderr */
		no_fd = TRUE;
	}

		/*
		  When talking to the debug fd, you are talking to an fd that
		  is not visible to the user.  It is not entered in the
		  virtual file table, and, hence, you should be in unmapped
		  mode.
		*/
	scm = SetSyscalls( SYS_LOCAL | SYS_UNMAPPED );

		/* Actually print the message */
	_condor_vfprintf_va( _condor_DebugFD, fmt, args );

		/* Restore our syscall mode */
	(void) SetSyscalls( scm );

	if( no_fd ) {
		_condor_DebugFD = 0;
	}
}

/*
   Our special version of vfprintf() that doesn't use the clib and
   doesn't call malloc(), etc.
*/
int
_condor_vfprintf_va( int fd, char* fmt, va_list args )
{
	char out[VFPRINTF_LEN + 1];	/* the output buffer passed to SYS_write */
	char *i, *o, *p; /* pointers into the fmt, out and %s, if any */
	int c = 0;		/* number of output characters from conversion of fmt */
	double f;		/* any float-like quantity from va_list */
	int d;			/* any int-like quantity from va_list */
	int index;		/* index usage in for loops */
	int signedness;	/* is the int-like quantity signed or not? */
	int val;		/* how many chars the ASCII rep is of a number */

	/* how many digits you need to represent in ASCII base 10 a 64 bit
		quantity plus a minus sign and a null character. For those interested,
		the equation is ceil(ln(numberinbase)/ln(base)) + minus sign + NULL.
		If you are wondering why I did only 64, it is because the
		values on the va_list are promoted to _at max_ that size. */
	char d64[ASCII64DECIMAL];

	/* how many ASCII digits in base 16 you need to represent a 64
		bit number */
	char x64[ASCII64HEXADECIMAL];

	/* how many ASCII digits in base 8 you need to represent a 64 bit
		number */
	char o64[ASCII64OCTAL];

	/* XXX I'm assuming I need to promote the types I use va_arg() on,
		The ANSI C spec is a little unclear about this, but compiler tests
		tell me that the promotion happens, even in "new-style" function
		declarations */

	for(index = 0; index < VFPRINTF_LEN+1; index++)
	{
		out[index] = 0;
	}

	i = fmt;
	o = out;

	while(*i != '\0' && c < VFPRINTF_LEN) /* minus one for the NULL */
	{
		/* if it isn't a conversion character delimiter, just copy it */
		if (*i != '%' && *i != '\\')
		{
			*o++ = *i++;
			c++;
			continue;
		}
		else if (*i == '\\') /* must be an escape sequence */
		{
			switch(*++i)
			{
				case 'a':
					*o = '\a';
					break;
				case 'b':
					*o = '\b';
					break;
				case 'f':
					*o = '\f';
					break;
				case 'n':
					*o = '\n';
					break;
				case 'r':
					*o = '\r';
					break;
				case 't':
					*o = '\t';
					break;
				case 'v':
					*o = '\v';
					break;
				case '\\':
					*o = '\\';
					break;
				case '?':
					*o = '?';
					break;
				case '\'':
					*o = '\'';
					break;
				case '\"':
					*o = '\"';
					break;

				/* XXX need to handle octal and hex numbers */

				default:
					/* not really correct behaviour, but close enough */
					*o = *i;
					break;
			}
			i++;
			o++;
			c++;
			continue;
		}

		/* *i is a '%' at this point in the algorithm */

		/* if it is a conversion character delimiter, then deal with it.
			XXX skip all of the justifying and precision crap for now, if
			we need it, we can add it later */
		switch(*++i)
		{
			case 'c':
				d = va_arg(args, int);
				if (c < VFPRINTF_LEN)
				{
					*o++ = (char)d;
					c++;
				}
				i++;
				break;
			case 's':
				p = va_arg(args, char *);
				while(*p != '\0' && c < VFPRINTF_LEN)
				{
					*o++ = *p++;
					c++;
				}
				i++;
				break;
			case 'f':
				f = va_arg(args, double);
				i++;
				break;
			case 'p':
			case 'x':
				d = va_arg(args, int);
				_condor_itoa(d, x64, HEXADECIMAL);
				p = x64;
				while(*p != '\0' && c < VFPRINTF_LEN)
				{
					*o++ = *p++;
					c++;
				}
				i++;
				break;
			case 'o':
				d = va_arg(args, int);
				_condor_itoa(d, o64, OCTAL);
				p = o64;
				while(*p != '\0' && c < VFPRINTF_LEN)
				{
					*o++ = *p++;
					c++;
				}
				i++;
				break;
			case 'i':
			case 'd':
				d = va_arg(args, int);
				_condor_itoa(d, d64, DECIMAL);
				p = d64;
				while(*p != '\0' && c < VFPRINTF_LEN)
				{
					*o++ = *p++;
					c++;
				}
				i++;
				break;
			case 'u':
				d = va_arg(args, int);
				_condor_itoa(d, d64, DECIMAL);
				p = d64;
				while(*p != '\0' && c < VFPRINTF_LEN)
				{
					*o++ = *p++;
					c++;
				}
				i++;
				break;
			case '%':
				*o++ = *i++;
				c++;
				break;
			default: /* not really correct behaviour, but good enough */
				*o++ = *i++;
				c++;
				break;
		}
	}

	/* return the number of bytes actually written */
	return SYSCALL(SYS_write, fd, out, c);
}

/* a helper function to _condor_vfprintf_va(). It will convert a binary
	representation into an ASCII representation based upon the axes of
	signed, unsigned, and hex, octal, decimal. If the base is
	hex or octal, the signedness is ignored. */
int
_condor_itoa(int quantity, char *out, int base)
{
	int i;
	char basemap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
						'b', 'c', 'd', 'e', 'f'};
	unsigned int mask;
	unsigned char byte, hi, lo;
	unsigned int hexquant;
	unsigned int octquant;
	int numchars;
	char *p, *q;
	int div, sum, mod, neg;

	switch(base)
	{
		case HEXADECIMAL:
			numchars = 0;
			hexquant = (unsigned int)quantity;

			mask = 0xff000000;

			/* put the number into the out array, including leading zeros */
			for(i = 0; i < sizeof(int); i++)
			{
				byte = (mask & hexquant) >> (sizeof(int)-i-1)*8;
				out[i*2] = basemap[(byte&0xf0)>>4];
				out[i*2+1] = basemap[byte&0x0f];
				mask >>= 8;
			}
			out[8] = 0;

			/* are there any leading zeros? */
			p = out;
			while(*p == '0') p++;

			/* no leading zeros */
			if (p == out)
				return 8;

			numchars = 8 - (p - out);

			/* strip out the leading zeros */
			q = out;
			while(*p != '\0')
			{
				*q++ = *p++;
			}
			*q = 0;
			return numchars;
			break;

		case OCTAL:
			octquant = (unsigned int)quantity;
			mask = 0xc0000000;
			byte = (mask & octquant) >> 30;
			out[0] = basemap[byte];
			numchars = 1;

			mask = 0x38000000;

			for (i = 27; i >= 0; i-=3)
			{
				byte = (mask & octquant) >> i;
				out[numchars++] = basemap[byte];
				mask >>= 3;
			}
			out[numchars] = 0;

			/* are there any leading zeros? */
			p = out;
			while(*p == '0') p++;

			/* no leading zeros */
			if (p == out)
				return 8;

			numchars = 8 - (p - out);

			/* strip out the leading zeros */
			q = out;
			while(*p != '\0')
			{
				*q++ = *p++;
			}
			*q = 0;
			return numchars;

			break;

		case DECIMAL:
			sum = 1;
			numchars = 0;

			/* the simple case */
			if (quantity == 0)
			{
				out[0] = '0';
				out[1] = 0;
				return 1;
			}

			/* create the ASCII representation backwards */
			for (i = 1; i < 21; i++)
			{
				out[numchars] = 0;
				div = quantity / sum;
				sum *= 10;
				mod = div % 10;
				if (div == 0) break;
				out[numchars] = basemap[ABS(mod)];
				numchars++;
			}
			if (quantity < 0)
			{
				out[numchars++] = '-';
			}
			out[numchars] = 0;

			/* now reverse the entire buffer */

			/* find the start and end of the buffer */
			p = q = out;
			while(*q != '\0') q++;
			q--;

			/* do the reversing operation, in place */
			while(p != q && q > p)
			{
				/* swap two int-like quantities */
				*p ^= *q;
				*q ^= *p;
				*p ^= *q;
				*p++; *q--;
			}

			return numchars;
			break;
		default:
			out[0] = 'N';
			out[1] = '/';
			out[2] = 'A';
			out[3] = 0;
			return 3;
			break;
	}

	/* just in case I entered this function with garbage. */
	out[0] = 'N';
	out[1] = '/';
	out[2] = 'A';
	out[3] = 0;
	return 3;
}

/*
   This is called by the dprintf_init() linked in with the user job in
   case of fatal error.  The regular _condor_dprintf_exit() has many
   more concerns.  We can just exit, though we want to use Suicide()
   so we send ourselves SIGKILL, instead of actually exiting.  If we
   exit, we leave the job queue, which isn't what we want.  Hopefully,
   we'll never get here.
*/
void
_condor_dprintf_exit( void )
{
	Suicide();
}

#if !defined(WIN32)
/*
  Can't open something because we are out of fd's.  Try to let
  somebody know what happened.  In the user job, we don't want to
  close a bunch of fds, since we'll loose our debug socket, which is
  always open.  In fact, we shouldn't have to close anything to be
  able to dprintf().  So, just dprintf(), flush the fd for good
  measure, and call Suicide() (so we don't leave the job queue).
*/
void
_condor_fd_panic( int line, char* file )
{
	dprintf( D_ALWAYS,
			 "**** PANIC -- OUT OF FILE DESCRIPTORS at line %d in %s\n",
			 line, file );
	Suicide();
}
#endif /* ! LOOSE32 */

} /* extern "C" */

<|endoftext|>