<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2014                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/config.hpp"
#include "caf/detail/get_root_uuid.hpp"

#ifndef CAF_MACOS // not needed on Mac OS X
namespace {
constexpr char uuid_format[] = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
} // namespace <anonmyous>
#endif // CAF_MACOS

#ifdef CAF_MACOS

namespace {

inline void erase_trailing_newline(std::string& str) {
  while (!str.empty() && (*str.rbegin()) == '\n') {
    str.resize(str.size() - 1);
  }
}

constexpr const char* s_get_uuid =
  "/usr/sbin/diskutil info / | "
  "/usr/bin/awk '$0 ~ /UUID/ { print $3 }'";

} // namespace <anonymous>

namespace caf {
namespace detail {

std::string get_root_uuid() {
  char cbuf[100];
  // fetch hd serial
  std::string uuid;
  FILE* get_uuid_cmd = popen(s_get_uuid, "r");
  while (fgets(cbuf, 100, get_uuid_cmd) != 0) {
    uuid += cbuf;
  }
  pclose(get_uuid_cmd);
  erase_trailing_newline(uuid);
  return uuid;
}

} // namespace detail
} // namespace caf

#elif defined(CAF_LINUX)

#include <vector>
#include <string>
#include <cctype>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <cstring>
#include <unistd.h>
#include <iostream>

#include "caf/string_algorithms.hpp"

using std::vector;
using std::string;
using std::ifstream;

namespace caf {
namespace detail {

namespace {

struct columns_iterator : std::iterator<std::forward_iterator_tag,
                                        vector<string>> {
  columns_iterator(ifstream* s = nullptr) : fs(s) {
    // nop
  }
  vector<string>& operator*() {
    return cols;
  }
  columns_iterator& operator++() {
    string line;
    if (!std::getline(*fs, line)) {
      fs = nullptr;
    } else {
      split(cols, line, is_any_of(" "), token_compress_on);
    }
    return *this;
  }
  ifstream* fs;
  vector<string> cols;
};

bool operator==(const columns_iterator& lhs, const columns_iterator& rhs) {
  return lhs.fs == rhs.fs;
}

bool operator!=(const columns_iterator& lhs, const columns_iterator& rhs) {
  return !(lhs == rhs);
}

} // namespace <anonymous>

std::string get_root_uuid() {
  int sck = socket(AF_INET, SOCK_DGRAM, 0);
  if (sck < 0) {
    perror("socket");
    return "";
  }
  // query available interfaces
  char buf[1024];
  ifconf ifc;
  ifc.ifc_len = sizeof(buf);
  ifc.ifc_buf = buf;
  if (ioctl(sck, SIOCGIFCONF, &ifc) < 0) {
    perror("ioctl(SIOCGIFCONF)");
    return "";
  }
  vector<string> hw_addresses;
  auto ctoi = [](char c)->unsigned {
    return static_cast<unsigned char>(c);
  };
  // iterate through interfaces.
  auto ifr = ifc.ifc_req;
  size_t num_ifs = ifc.ifc_len / sizeof(ifreq);
  for (size_t i = 0; i < num_ifs; i++) {
    auto& item = ifr[i];
    // get MAC address
    if (ioctl(sck, SIOCGIFHWADDR, &item) < 0) {
      perror("ioctl(SIOCGIFHWADDR)");
      return "";
    }
    // convert MAC address to standard string representation
    std::ostringstream oss;
    oss << std::hex;
    oss.width(2);
    oss << ctoi(item.ifr_hwaddr.sa_data[0]);
    for (size_t i = 1; i < 6; ++i) {
      oss << ":";
      oss.width(2);
      oss << ctoi(item.ifr_hwaddr.sa_data[i]);
    }
    auto addr = oss.str();
    if (addr != "00:00:00:00:00:00") {
      hw_addresses.push_back(std::move(addr));
    }
  }
  string uuid;
  ifstream fs;
  fs.open("/etc/fstab", std::ios_base::in);
  columns_iterator end;
  auto i = find_if(columns_iterator{&fs}, end, [](const vector<string>& cols) {
    return cols.size() == 6 && cols[1] == "/";
  });
  if (i != end) {
    uuid = move((*i)[0]);
    const char cstr[] = {"UUID="};
    auto slen = sizeof(cstr) - 1;
    if (uuid.compare(0, slen, cstr) == 0) {
      uuid.erase(0, slen);
    }
    // UUIDs are formatted as 8-4-4-4-12 hex digits groups
    auto cpy = uuid;
    replace_if(cpy.begin(), cpy.end(), ::isxdigit, 'F');
    // discard invalid UUID
    if (cpy != uuid_format) {
      uuid.clear();
    }
    // "\\?\Volume{5ec70abf-058c-11e1-bdda-806e6f6e6963}\"
  }
  return uuid;
}

} // namespace detail
} // namespace caf

#elif defined(CAF_WINDOWS)

#include <string>
#include <iostream>
#include <algorithm>

#include <windows.h>
#include <tchar.h>

using namespace std;

namespace caf {
namespace detail {

namespace {
constexpr size_t max_drive_name = MAX_PATH;
}

// if TCHAR is indeed a char, we can simply move rhs
void mv(std::string& lhs, std::string&& rhs) { lhs = std::move(rhs); }

// if TCHAR is defined as WCHAR, we have to do unicode conversion
void mv(std::string& lhs, const std::basic_string<WCHAR>& rhs) {
  auto size_needed = WideCharToMultiByte(CP_UTF8, 0, rhs.c_str(),
                                         static_cast<int>(rhs.size()),
                                         nullptr, 0, nullptr, nullptr);
  lhs.resize(size_needed);
  WideCharToMultiByte(CP_UTF8, 0, rhs.c_str(), static_cast<int>(rhs.size()),
                      &lhs[0], size_needed, nullptr, nullptr);
}

std::string get_root_uuid() {
  using tchar_str = std::basic_string<TCHAR>;
  string uuid;
  TCHAR buf[max_drive_name];      // temporary buffer for volume name
  tchar_str drive = TEXT("c:\\"); // string "template" for drive specifier
  // walk through legal drive letters, skipping floppies
  for (TCHAR i = TEXT('c'); i < TEXT('z'); i++) {
    // Stamp the drive for the appropriate letter.
    drive[0] = i;
    if (GetVolumeNameForVolumeMountPoint(drive.c_str(), buf, max_drive_name)) {
      tchar_str drive_name = buf;
      auto first = drive_name.find(TEXT("Volume{"));
      if (first != std::string::npos) {
        first += 7;
        auto last = drive_name.find(TEXT("}"), first);
        if (last != std::string::npos && last > first) {
          mv(uuid, drive_name.substr(first, last - first));
          // UUIDs are formatted as 8-4-4-4-12 hex digits groups
          auto cpy = uuid;
          replace_if(cpy.begin(), cpy.end(), ::isxdigit, 'F');
          // discard invalid UUID
          if (cpy != uuid_format)
            uuid.clear();
          else
            return uuid; // return first valid UUID we get
        }
      }
    }
  }
  return uuid;
}

} // namespace detail
} // namespace caf

#endif // CAF_WINDOWS
<commit_msg>Remove unused code.<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2014                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#include "caf/config.hpp"
#include "caf/detail/get_root_uuid.hpp"

#ifndef CAF_MACOS // not needed on Mac OS X
namespace {
constexpr char uuid_format[] = "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF";
} // namespace <anonmyous>
#endif // CAF_MACOS

#ifdef CAF_MACOS

namespace {

inline void erase_trailing_newline(std::string& str) {
  while (!str.empty() && (*str.rbegin()) == '\n') {
    str.resize(str.size() - 1);
  }
}

constexpr const char* s_get_uuid =
  "/usr/sbin/diskutil info / | "
  "/usr/bin/awk '$0 ~ /UUID/ { print $3 }'";

} // namespace <anonymous>

namespace caf {
namespace detail {

std::string get_root_uuid() {
  char cbuf[100];
  // fetch hd serial
  std::string uuid;
  FILE* get_uuid_cmd = popen(s_get_uuid, "r");
  while (fgets(cbuf, 100, get_uuid_cmd) != 0) {
    uuid += cbuf;
  }
  pclose(get_uuid_cmd);
  erase_trailing_newline(uuid);
  return uuid;
}

} // namespace detail
} // namespace caf

#elif defined(CAF_LINUX)

#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <iostream>

#include "caf/string_algorithms.hpp"

using std::vector;
using std::string;
using std::ifstream;

namespace caf {
namespace detail {

namespace {

struct columns_iterator : std::iterator<std::forward_iterator_tag,
                                        vector<string>> {
  columns_iterator(ifstream* s = nullptr) : fs(s) {
    // nop
  }
  vector<string>& operator*() {
    return cols;
  }
  columns_iterator& operator++() {
    string line;
    if (!std::getline(*fs, line)) {
      fs = nullptr;
    } else {
      split(cols, line, is_any_of(" "), token_compress_on);
    }
    return *this;
  }
  ifstream* fs;
  vector<string> cols;
};

bool operator==(const columns_iterator& lhs, const columns_iterator& rhs) {
  return lhs.fs == rhs.fs;
}

bool operator!=(const columns_iterator& lhs, const columns_iterator& rhs) {
  return !(lhs == rhs);
}

} // namespace <anonymous>

std::string get_root_uuid() {
  string uuid;
  ifstream fs;
  fs.open("/etc/fstab", std::ios_base::in);
  columns_iterator end;
  auto i = find_if(columns_iterator{&fs}, end, [](const vector<string>& cols) {
    return cols.size() == 6 && cols[1] == "/";
  });
  if (i != end) {
    uuid = move((*i)[0]);
    const char cstr[] = {"UUID="};
    auto slen = sizeof(cstr) - 1;
    if (uuid.compare(0, slen, cstr) == 0) {
      uuid.erase(0, slen);
    }
    // UUIDs are formatted as 8-4-4-4-12 hex digits groups
    auto cpy = uuid;
    replace_if(cpy.begin(), cpy.end(), ::isxdigit, 'F');
    // discard invalid UUID
    if (cpy != uuid_format) {
      uuid.clear();
    }
    // "\\?\Volume{5ec70abf-058c-11e1-bdda-806e6f6e6963}\"
  }
  return uuid;
}

} // namespace detail
} // namespace caf

#elif defined(CAF_WINDOWS)

#include <string>
#include <iostream>
#include <algorithm>

#include <windows.h>
#include <tchar.h>

using namespace std;

namespace caf {
namespace detail {

namespace {
constexpr size_t max_drive_name = MAX_PATH;
}

// if TCHAR is indeed a char, we can simply move rhs
void mv(std::string& lhs, std::string&& rhs) { lhs = std::move(rhs); }

// if TCHAR is defined as WCHAR, we have to do unicode conversion
void mv(std::string& lhs, const std::basic_string<WCHAR>& rhs) {
  auto size_needed = WideCharToMultiByte(CP_UTF8, 0, rhs.c_str(),
                                         static_cast<int>(rhs.size()),
                                         nullptr, 0, nullptr, nullptr);
  lhs.resize(size_needed);
  WideCharToMultiByte(CP_UTF8, 0, rhs.c_str(), static_cast<int>(rhs.size()),
                      &lhs[0], size_needed, nullptr, nullptr);
}

std::string get_root_uuid() {
  using tchar_str = std::basic_string<TCHAR>;
  string uuid;
  TCHAR buf[max_drive_name];      // temporary buffer for volume name
  tchar_str drive = TEXT("c:\\"); // string "template" for drive specifier
  // walk through legal drive letters, skipping floppies
  for (TCHAR i = TEXT('c'); i < TEXT('z'); i++) {
    // Stamp the drive for the appropriate letter.
    drive[0] = i;
    if (GetVolumeNameForVolumeMountPoint(drive.c_str(), buf, max_drive_name)) {
      tchar_str drive_name = buf;
      auto first = drive_name.find(TEXT("Volume{"));
      if (first != std::string::npos) {
        first += 7;
        auto last = drive_name.find(TEXT("}"), first);
        if (last != std::string::npos && last > first) {
          mv(uuid, drive_name.substr(first, last - first));
          // UUIDs are formatted as 8-4-4-4-12 hex digits groups
          auto cpy = uuid;
          replace_if(cpy.begin(), cpy.end(), ::isxdigit, 'F');
          // discard invalid UUID
          if (cpy != uuid_format)
            uuid.clear();
          else
            return uuid; // return first valid UUID we get
        }
      }
    }
  }
  return uuid;
}

} // namespace detail
} // namespace caf

#endif // CAF_WINDOWS
<|endoftext|>


<commit_before>/******************************************************************************
* Zowi Battery Reader Library
*
* @version 20150824
* @author Raul de Pablos Martin
*
******************************************************************************/

#include "BatReader.h"

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

BatReader::BatReader() {
}

double BatReader::readBatVoltage(void) {
	double readed = (double)(analogRead(BAT_PIN)*ANA_REF)/1024;
	if(readed > BAT_MAX) return BAT_MAX;
	else return readed;
}

double BatReader::readBatPercent(void) {
	return (SLOPE*readBatVoltage()) - OFFSET;
}

<commit_msg>Avoid negative percentage values<commit_after>/******************************************************************************
* Zowi Battery Reader Library
*
* @version 20150831
* @author Raul de Pablos Martin
*
******************************************************************************/

#include "BatReader.h"

#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

BatReader::BatReader() {
}

double BatReader::readBatVoltage(void) {
	double readed = (double)(analogRead(BAT_PIN)*ANA_REF)/1024;
	if(readed > BAT_MAX) return BAT_MAX;
	else return readed;
}

double BatReader::readBatPercent(void) {
	double value = (SLOPE*readBatVoltage()) - OFFSET;
	if(value < 0) return 0;
	else return value;
}

<|endoftext|>


<commit_before>#pragma once

#include <util/DynamicArray.hpp>
#include <util/List.hpp>

/**
 * An ArrayList is an ordered list where the elements are stored in a contiguous
 * array, which is dynamically resized as needed.
 *
 * ArrayLists excel at random access due to the contents being stored in a
 * contiguous block of memory, compared to LinkedLists, which need to traverse
 * node by node to get to any one element. ArrayLists are also faster to iterate
 * though for the same reason. When the needed space is available, insertion and
 * removal of elements at the end of the ArrayList is very fast and requires no
 * further heap allocations.
 *
 * ArrayLists suffer in insertion and removal of elements anywhere far from the
 * end of the list, as the contents need to be shifted to maintain order and
 * contiguousness. Additionally, once reaching the allocated capacity, the
 * memory block needs to be grown if any new elements are to be inserted. This
 * requires allocating a new, larger memory block and copying over the old
 * contents, which is expensive. This is mitigated somewhat by the ArrayList's
 * default behavior of allocating a new block double the size of the current
 * block, allowing many insertions before the next resizing event. This comes at
 * the expense of memory efficiency, as the list takes up more space than
 * strictly necessary. This can be further mitigated if the creator of the list
 * knows beforehand roughly how much space will be needed and can then pre-
 * allocate an appropriate amount of space.
 *
 * @tparam T The type of object the ArrayList holds.
 */
template <typename T>
class ArrayList : public List<T>
{
  public:
    using Iterator = typename Iterable<T>::Iterator;

    /** Constructs an ArrayList with the default pre-allocation. */
    ArrayList() : ArrayList(8) {}

    /**
     * Constructs an ArrayList, pre-allocating space for `reserve` number of
     * elements.
     * @param reserve The number of elements to pre-allocate space for.
     */
    ArrayList(size_t reserve) : _data(reserve) {}

    /**
     * Adds an element to the top of the ArrayList.
     * @note This is an O(n) operation! If you're doing this often, consider
     *       the ordering of your data, or use a different List implementation.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool push(const T &obj) override
    {
        shiftOrResize(1);
        _data[0] = obj;
        ++_size;
        return true;
    }

    /**
     * Adds an element to the top of the ArrayList.
     * @note This is an O(n) operation! If you're doing this often, consider
     *       the ordering of your data, or use a different List implementation.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool push(T &&obj) override
    {
        shiftOrResize(1);
        _data[0] = std::move(obj);
        ++_size;
        return true;
    }

    /**
     * Adds an element to the back of the ArrayList.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool enqueue(const T &obj) override
    {
        if (_size == capacity()) {
            _data.resize();
        }

        _data[_size] = obj;
        ++_size;
        return true;
    }

    /**
     * Adds an element to the back of the ArrayList.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool enqueue(T &&obj) override
    {
        if (_size == capacity()) {
            _data.resize();
        }

        _data[_size] = std::move(obj);
        ++_size;
        return true;
    }

    /**
     * Removes an element from the top of the ArrayList.
     * @note This is an O(n) operation! If you're doing this often, consider
     *       the ordering of your data, or use a different List implementation.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    T pop() override
    {
        T ret = peek();
        _data.shift(1, true);
        --_size;
        return ret;
    }

    /**
     * Removes an element from the back of the ArrayList.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    T popBack() override { --_size; return _data[_size]; }

    /**
     * Returns the element at the top of the ArrayList without removing it.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    const T &peek() const override { return _data[0]; }

    /**
     * Returns the element at the back of the ArrayList without removing it.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    const T &peekBack() const override { return _data[_size-1]; }

    /**
     * Returns whether or not the ArrayList is empty.
     * @return `true` if empty, `false` otherwise.
     */
    bool isEmpty() const override { return _size == 0; }

    /**
     * The number of elements in the ArrayList.
     * @return A size_t equal to the number of elements.
     */
    size_t size() const override { return _size; }

    /**
     * Adds the object to the ArrayList, growing its size.
     *
     * @param object The object to add.
     * @return `true` if the ArrayList changed. `false` otherwise.
     */
    bool insert(const T &object) override { return enqueue(object); }

    /**
     * Adds the object to the ArrayList at the given index.
     * @note This is an O(n) operation.
     * @param object The object to add.
     * @param idx The index to add it to. Existing elements from idx onward will
     *            be shifted one to the right.
     * @return `true` if the ArrayList changed. `false` otherwise.
     */
    bool insert(const T &object, size_t idx)
    {
        if (idx == _size) {
            return enqueue(object);
        } else if (idx == 0) {
            return push(object);
        }

        // TODO: think about an override for hash tables, or if we just allow it
        if (idx > _size) {
            return false;
        }

        // TODO: this is inefficient, as we slide things over twice.
        if (_size == capacity()) {
            _data.resize();
        }

        // move everything at and beyond idx right one.
        for (size_t i = _size; i > idx; --i) {
            _data[i] = _data[i-1];
        }

        _data[idx] = object;
        ++_size;
        return true;
    }

    /**
     * Removes the first instance of the object from the ArrayList.
     * @note This is O(n). If you're doing this often, consider using some other
     *       collection.
     * @param object The object to remove.
     * @return `true` if the ArrayList changed. `false` otherwise.
     */
    bool remove(const T &object) override
    {
        size_t removalIdx = SIZE_MAX;
        for (size_t i = 0; i < _size; ++i) {
            if (_data[i] == object) {
                removalIdx = i;
                break;
            }
        }

        return remove(removalIdx);
    }

    /**
     * Removes the object at the given index.
     * @note This is O(n), where n is distance from the end of the ArrayList.
     * @param idx The index to remove from.
     * @return
     */
    bool remove(size_t idx)
    {
        if (idx >= _size) {
            return false;
        }

        --_size;
        // move everything right of idx left one.
        for (size_t i = idx; i < _size; ++i) {
            _data[i] = _data[i+1];
        }

        return true;
    }

    /**
     * Returns the element at the given index.  No bounds checking is performed.
     * @param idx The index of the object.
     * @return The object at that index. If the index is out of bounds, the
     *         return value is undefined.
     */
    T& operator[](size_t idx) const override { return _data[idx]; }

    /** An iterator pointing to the first element in the list. */
    Iterator begin() const override
    {
        auto *llit = new ALIterator{0, this};
        autorelease(llit);
        return Iterable<T>::newIterator(llit);
    }

    /**
     * An Iterator "past the end" of the list. When encountered, it means there
     * is nothing else to read and iteration should stop.
     *
     * @return An iterator signifying the end of this ArrayList.
     */
    Iterator end() const override
    {
        auto *llit = new ALIterator{npos, this};
        autorelease(llit);
        return Iterable<T>::newIterator(llit);
    }

    /**
     * The maximum capacity of the currently allocated block.
     * @return The size of the underlying memory block.
     */
    size_t capacity() const { return _data.capacity(); }

  private:
    static constexpr size_t npos = -1;
    /**
     * Shifts the data back. Resizes if necessary so no data gets lost.
     * @param offset The amount to shift the data right by.
     */
    void shiftOrResize(size_t offset)
    {
        // if there's nothing, don't waste time.
        if (_size == 0) return;

        if (offset + _size > capacity()) {
            auto minCapacity = capacity() + offset;
            auto doubleCapacity = capacity() * 2;
            auto newSize = minCapacity < doubleCapacity ? doubleCapacity
                                                        : minCapacity;
            _data.resize(offset, newSize);
        } else {
            _data.shift(offset);
        }
    }

    class ALIterator : public Iterable<T>::IteratorImpl
    {
        friend class ArrayList;
        using Iterable<T>::IteratorImpl::publicInstance;
        using Iterable<T>::IteratorImpl::implOf;
      public:
        /**
         * (pre-increment) Advances the iterator one element forward.
         * @return A reference to the next Iterator in the Collection.
         */
        Iterator& operator++() override
        {
            ++_index;
            if (_index == _parent->size()) {
                _index = npos;
            }

            return *publicInstance();
        }

        /**
         * (post-increment) Advances the Iterator one element forward.
         * @return An Iterator equal to this before the increment.
         */
        Iterator operator++(int) override
        {
            ALIterator *it = new ALIterator(*this);
            autorelease(it);
            this->operator++();
            return Iterable<T>::newIterator(it);
        }

        /**
         * Retrieves a reference to the pointed-to element.
         * @return A reference to the element the Iterator is pointing at. If it
         *         isn't pointing to anything (e.g. end of the Collection), the
         *         result is undefined.
         */
        T& operator*() const override { return (*_parent)[_index]; }

        /**
         * Equality operator.
         * @param rhs The iterator to compare to.
         * @return `true` if they are equal, `false` otherwise.
         */
        bool operator==(Iterator const &rhs) const override
        {
            if (classId() != rhs.classId()) {
                return false;
            }

            ALIterator *iterator = reinterpret_cast<ALIterator *>(implOf(rhs));
            if (!iterator) {
                return false;
            }

            if (iterator == this) {
                return true;
            }

            return _index == iterator->_index && _parent == iterator->_parent;
        }

        size_t classId() const override { return 0xA88A1757; }

      private:
        ALIterator(size_t index, ArrayList const *parent)
                : _index(index), _parent(parent)
        {}

        size_t _index;
        ArrayList const *_parent;
    };

    DynamicArray<T> _data;
    size_t _size = 0;
};
<commit_msg>Added reserve() function.<commit_after>#pragma once

#include <util/DynamicArray.hpp>
#include <util/List.hpp>

/**
 * An ArrayList is an ordered list where the elements are stored in a contiguous
 * array, which is dynamically resized as needed.
 *
 * ArrayLists excel at random access due to the contents being stored in a
 * contiguous block of memory, compared to LinkedLists, which need to traverse
 * node by node to get to any one element. ArrayLists are also faster to iterate
 * though for the same reason. When the needed space is available, insertion and
 * removal of elements at the end of the ArrayList is very fast and requires no
 * further heap allocations.
 *
 * ArrayLists suffer in insertion and removal of elements anywhere far from the
 * end of the list, as the contents need to be shifted to maintain order and
 * contiguousness. Additionally, once reaching the allocated capacity, the
 * memory block needs to be grown if any new elements are to be inserted. This
 * requires allocating a new, larger memory block and copying over the old
 * contents, which is expensive. This is mitigated somewhat by the ArrayList's
 * default behavior of allocating a new block double the size of the current
 * block, allowing many insertions before the next resizing event. This comes at
 * the expense of memory efficiency, as the list takes up more space than
 * strictly necessary. This can be further mitigated if the creator of the list
 * knows beforehand roughly how much space will be needed and can then pre-
 * allocate an appropriate amount of space.
 *
 * @tparam T The type of object the ArrayList holds.
 */
template <typename T>
class ArrayList : public List<T>
{
  public:
    using Iterator = typename Iterable<T>::Iterator;

    /** Constructs an ArrayList with the default pre-allocation. */
    ArrayList() : ArrayList(8) {}

    /**
     * Constructs an ArrayList, pre-allocating space for `reserve` number of
     * elements.
     * @param reserve The number of elements to pre-allocate space for.
     */
    ArrayList(size_t reserve) : _data(reserve) {}

    /**
     * Reserves enough room to hold the given amount.
     * This function can only grow the ArrayList. If reserve <= capacity, no
     * action is performed.
     * @param reserve The number of elements to make room for.
     */
    void reserve(size_t reserve)
    {
        if (reserve > capacity()) {
            _data.resize(reserve);
        }
    }

    /**
     * Adds an element to the top of the ArrayList.
     * @note This is an O(n) operation! If you're doing this often, consider
     *       the ordering of your data, or use a different List implementation.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool push(const T &obj) override
    {
        shiftOrResize(1);
        _data[0] = obj;
        ++_size;
        return true;
    }

    /**
     * Adds an element to the top of the ArrayList.
     * @note This is an O(n) operation! If you're doing this often, consider
     *       the ordering of your data, or use a different List implementation.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool push(T &&obj) override
    {
        shiftOrResize(1);
        _data[0] = std::move(obj);
        ++_size;
        return true;
    }

    /**
     * Adds an element to the back of the ArrayList.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool enqueue(const T &obj) override
    {
        if (_size == capacity()) {
            _data.resize();
        }

        _data[_size] = obj;
        ++_size;
        return true;
    }

    /**
     * Adds an element to the back of the ArrayList.
     * @param obj The object to add.
     * @return `true` if an object was added. `false` otherwise.
     */
    bool enqueue(T &&obj) override
    {
        if (_size == capacity()) {
            _data.resize();
        }

        _data[_size] = std::move(obj);
        ++_size;
        return true;
    }

    /**
     * Removes an element from the top of the ArrayList.
     * @note This is an O(n) operation! If you're doing this often, consider
     *       the ordering of your data, or use a different List implementation.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    T pop() override
    {
        T ret = peek();
        _data.shift(1, true);
        --_size;
        return ret;
    }

    /**
     * Removes an element from the back of the ArrayList.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    T popBack() override { --_size; return _data[_size]; }

    /**
     * Returns the element at the top of the ArrayList without removing it.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    const T &peek() const override { return _data[0]; }

    /**
     * Returns the element at the back of the ArrayList without removing it.
     * @return The object. If the ArrayList is empty, the return value is undefined.
     */
    const T &peekBack() const override { return _data[_size-1]; }

    /**
     * Returns whether or not the ArrayList is empty.
     * @return `true` if empty, `false` otherwise.
     */
    bool isEmpty() const override { return _size == 0; }

    /**
     * The number of elements in the ArrayList.
     * @return A size_t equal to the number of elements.
     */
    size_t size() const override { return _size; }

    /**
     * Adds the object to the ArrayList, growing its size.
     *
     * @param object The object to add.
     * @return `true` if the ArrayList changed. `false` otherwise.
     */
    bool insert(const T &object) override { return enqueue(object); }

    /**
     * Adds the object to the ArrayList at the given index.
     * @note This is an O(n) operation.
     * @param object The object to add.
     * @param idx The index to add it to. Existing elements from idx onward will
     *            be shifted one to the right.
     * @return `true` if the ArrayList changed. `false` otherwise.
     */
    bool insert(const T &object, size_t idx)
    {
        if (idx == _size) {
            return enqueue(object);
        } else if (idx == 0) {
            return push(object);
        }

        // TODO: think about an override for hash tables, or if we just allow it
        if (idx > _size) {
            return false;
        }

        // TODO: this is inefficient, as we slide things over twice.
        if (_size == capacity()) {
            _data.resize();
        }

        // move everything at and beyond idx right one.
        for (size_t i = _size; i > idx; --i) {
            _data[i] = _data[i-1];
        }

        _data[idx] = object;
        ++_size;
        return true;
    }

    /**
     * Removes the first instance of the object from the ArrayList.
     * @note This is O(n). If you're doing this often, consider using some other
     *       collection.
     * @param object The object to remove.
     * @return `true` if the ArrayList changed. `false` otherwise.
     */
    bool remove(const T &object) override
    {
        size_t removalIdx = SIZE_MAX;
        for (size_t i = 0; i < _size; ++i) {
            if (_data[i] == object) {
                removalIdx = i;
                break;
            }
        }

        return remove(removalIdx);
    }

    /**
     * Removes the object at the given index.
     * @note This is O(n), where n is distance from the end of the ArrayList.
     * @param idx The index to remove from.
     * @return
     */
    bool remove(size_t idx)
    {
        if (idx >= _size) {
            return false;
        }

        --_size;
        // move everything right of idx left one.
        for (size_t i = idx; i < _size; ++i) {
            _data[i] = _data[i+1];
        }

        return true;
    }

    /**
     * Returns the element at the given index.  No bounds checking is performed.
     * @param idx The index of the object.
     * @return The object at that index. If the index is out of bounds, the
     *         return value is undefined.
     */
    T& operator[](size_t idx) const override { return _data[idx]; }

    /** An iterator pointing to the first element in the list. */
    Iterator begin() const override
    {
        auto *llit = new ALIterator{0, this};
        autorelease(llit);
        return Iterable<T>::newIterator(llit);
    }

    /**
     * An Iterator "past the end" of the list. When encountered, it means there
     * is nothing else to read and iteration should stop.
     *
     * @return An iterator signifying the end of this ArrayList.
     */
    Iterator end() const override
    {
        auto *llit = new ALIterator{npos, this};
        autorelease(llit);
        return Iterable<T>::newIterator(llit);
    }

    /**
     * The maximum capacity of the currently allocated block.
     * @return The size of the underlying memory block.
     */
    size_t capacity() const { return _data.capacity(); }

  private:
    static constexpr size_t npos = -1;
    /**
     * Shifts the data back. Resizes if necessary so no data gets lost.
     * @param offset The amount to shift the data right by.
     */
    void shiftOrResize(size_t offset)
    {
        // if there's nothing, don't waste time.
        if (_size == 0) return;

        if (offset + _size > capacity()) {
            auto minCapacity = capacity() + offset;
            auto doubleCapacity = capacity() * 2;
            auto newSize = minCapacity < doubleCapacity ? doubleCapacity
                                                        : minCapacity;
            _data.resize(offset, newSize);
        } else {
            _data.shift(offset);
        }
    }

    class ALIterator : public Iterable<T>::IteratorImpl
    {
        friend class ArrayList;
        using Iterable<T>::IteratorImpl::publicInstance;
        using Iterable<T>::IteratorImpl::implOf;
      public:
        /**
         * (pre-increment) Advances the iterator one element forward.
         * @return A reference to the next Iterator in the Collection.
         */
        Iterator& operator++() override
        {
            ++_index;
            if (_index == _parent->size()) {
                _index = npos;
            }

            return *publicInstance();
        }

        /**
         * (post-increment) Advances the Iterator one element forward.
         * @return An Iterator equal to this before the increment.
         */
        Iterator operator++(int) override
        {
            ALIterator *it = new ALIterator(*this);
            autorelease(it);
            this->operator++();
            return Iterable<T>::newIterator(it);
        }

        /**
         * Retrieves a reference to the pointed-to element.
         * @return A reference to the element the Iterator is pointing at. If it
         *         isn't pointing to anything (e.g. end of the Collection), the
         *         result is undefined.
         */
        T& operator*() const override { return (*_parent)[_index]; }

        /**
         * Equality operator.
         * @param rhs The iterator to compare to.
         * @return `true` if they are equal, `false` otherwise.
         */
        bool operator==(Iterator const &rhs) const override
        {
            if (classId() != rhs.classId()) {
                return false;
            }

            ALIterator *iterator = reinterpret_cast<ALIterator *>(implOf(rhs));
            if (!iterator) {
                return false;
            }

            if (iterator == this) {
                return true;
            }

            return _index == iterator->_index && _parent == iterator->_parent;
        }

        size_t classId() const override { return 0xA88A1757; }

      private:
        ALIterator(size_t index, ArrayList const *parent)
                : _index(index), _parent(parent)
        {}

        size_t _index;
        ArrayList const *_parent;
    };

    DynamicArray<T> _data;
    size_t _size = 0;
};
<|endoftext|>


<commit_before>// This file is part of SWGANH which is released under the MIT license.
// See file LICENSE or go to http://swganh.com/LICENSE

#include "player_service.h"

#include "swganh/logger.h"
#include "swganh/event_dispatcher.h"
#include "swganh/service/service_description.h"
#include "swganh/service/service_manager.h"
#include "swganh_core/connection/connection_client_interface.h"
#include "swganh_core/object/player/player.h"
#include "swganh_core/object/creature/creature.h"
#include "swganh_core/object/object_controller.h"
#include "swganh_core/messages/system_message.h"
#include "swganh_core/messages/out_of_band.h"
#include "swganh_core/messages/opened_container_message.h"
#include "swganh_core/simulation/simulation_service_interface.h"
#include "swganh_core/equipment/equipment_service.h"

#include "swganh_core/messages/controllers/add_buff.h"
#include "swganh_core/combat/buff_interface.h"

#include "swganh/database/database_manager.h"
#include <cppconn/exception.h>
#include <cppconn/connection.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/sqlstring.h>

using namespace std;
using namespace swganh;
using namespace swganh::service;
using namespace swganh::player;
using namespace swganh::object;
using namespace swganh::messages;

PlayerService::PlayerService(swganh::app::SwganhKernel* kernel)
	: kernel_(kernel)
{
	kernel_->GetEventDispatcher()->Subscribe(
		"ObjectReadyEvent",
		[this] (shared_ptr<EventInterface> incoming_event)
	{
		auto creature = static_pointer_cast<ValueEvent<shared_ptr<Creature>>>(incoming_event)->Get();

		//Reload buffs from last login
		auto controller = creature->GetController();
		auto object_id = creature->GetObjectId();

		//Resend buffs we current have left over
		creature->ViewBuffs([&, this] (std::pair<boost::posix_time::ptime, std::shared_ptr<swganh::combat::BuffInterface>> entry) {
			uint32_t duration = (entry.first - boost::posix_time::second_clock::local_time()).total_seconds();

			swganh::messages::controllers::AddBuffMessage msg;
			msg.buff = entry.second->GetName();
			msg.duration = static_cast<float>(duration);
			controller->Notify(&msg);
		});

		//Re-Add buffs from the db we still need.
		auto conn = kernel_->GetDatabaseManager()->getConnection("galaxy");
		auto statement = shared_ptr<sql::Statement>(conn->createStatement());

        stringstream ss;
        ss << "SELECT b.name, b.duration FROM buffs b WHERE b.id=" << object_id << ";" ;
        statement->execute(ss.str());

		unique_ptr<sql::ResultSet> result(statement->getResultSet());

		while(result->next())
		{
			creature->AddBuff(result->getString(1), result->getUInt(2));
		}
	});

	player_removed_ = kernel_->GetEventDispatcher()->Subscribe(
		"Connection::PlayerRemoved",
		[this] (shared_ptr<EventInterface> incoming_event)
	{
		const auto& player = static_pointer_cast<ValueEvent<shared_ptr<Player>>>(incoming_event)->Get();
		OnPlayerExit(player);
	});

    SetServiceDescription(ServiceDescription(
        "PlayerService",
        "player",
        "0.1",
        "127.0.0.1",
        0,
        0,
        0));
}

PlayerService::~PlayerService()
{}

void PlayerService::Initialize()
{
	simulation_service_ = kernel_->GetServiceManager()->
		GetService<swganh::simulation::SimulationServiceInterface>("SimulationService");

	equipment_service_ = kernel_->GetServiceManager()->
		GetService<swganh::equipment::EquipmentService>("EquipmentService");
}

void PlayerService::Startup()
{}

void PlayerService::OnPlayerEnter(shared_ptr<swganh::object::Player> player)
{
    if (player)
    {
	    player->ClearStatusFlags();
    }
}

void PlayerService::OnPlayerExit(shared_ptr<swganh::object::Player> player)
{
    if (player)
    {
	    player->ClearStatusFlags();
	    player->AddStatusFlag(swganh::object::LD);
	    // set a timer to 30 seconds to destroy the object, unless logged back in.
        auto deadline_timer = std::make_shared<boost::asio::deadline_timer>(kernel_->GetCpuThreadPool(), boost::posix_time::seconds(30));
		auto parent = std::static_pointer_cast<swganh::object::Object>(player->GetContainer());

		auto object_controller = std::static_pointer_cast<swganh::object::ObjectController>(parent->GetController());
		if(object_controller != nullptr)
		{
			deadline_timer->async_wait(boost::bind(&PlayerService::RemoveClientTimerHandler_, this, boost::asio::placeholders::error, deadline_timer, 30, object_controller));
		}
    }
}

void PlayerService::SendTip(
	const shared_ptr<Creature>& from,
	const shared_ptr<Creature>& to,
	uint32_t amount, bool bank)
{
	// Check to see if we even have the proper amount
	if (amount < 1 || amount > 1000000)
	{
		SystemMessage::Send(from, L"Invalid tip amount, set amount between 1 and 1,000,000");
		return;
	}

	if (bank)
	{
		int32_t total_amount = (int32_t)(amount * 1.05); // 5% tip charge
		int32_t from_amount = from->GetBankCredits();
		if ( from_amount - total_amount > 0)
		{
			from->SetBankCredits( from_amount - total_amount );
			int32_t to_amount = to->GetBankCredits();
			to->SetBankCredits( to_amount + amount );
			SystemMessage::Send(from, OutOfBand("base_player", "prose_wire_pass_self",0,0,to->GetObjectId(),amount), false, false);
			SystemMessage::Send(to, OutOfBand("base_player", "prose_wire_pass_target",0,0,from->GetObjectId(),amount), false, false);
		}
		else
		{
			SystemMessage::Send(from, OutOfBand("base_player", "prose_tip_nsf_bank",0,to->GetObjectId(),0,total_amount), false, false);
		}
	}
	else
	{
		int32_t total_amount = (int32_t)(amount * 1.05); // 5% tip charge
		int32_t from_amount = from->GetCashCredits();
		if ( from_amount - total_amount > 0)
		{
			from->SetCashCredits( from_amount - total_amount );
			int32_t to_amount = to->GetBankCredits();
			to->SetCashCredits( to_amount + amount );
			SystemMessage::Send(from, OutOfBand("base_player", "prose_tip_pass_self",0,to->GetObjectId(),0,amount), false, false);
			SystemMessage::Send(to, OutOfBand("base_player", "prose_tip_pass_target",0,from->GetObjectId(),0,amount), false, false);
		}
		else
		{
			SystemMessage::Send(from, OutOfBand("base_player", "prose_tip_nsf_cash",0,to->GetObjectId(),0,total_amount), false, false);
		}
	}
}

void PlayerService::OpenContainer(const std::shared_ptr<swganh::object::Creature>& owner, std::shared_ptr<swganh::object::Object> object)
{
	// Send Open Container
	OpenedContainerMessage opened_container;
	opened_container.container_object_id = object->GetObjectId();
	owner->NotifyObservers(&opened_container);
}

bool PlayerService::HasCalledMount(std::shared_ptr<swganh::object::Creature> owner)
{
	auto equipment = kernel_->GetServiceManager()->GetService<swganh::equipment::EquipmentServiceInterface>("EquipmentService");
	auto datapad = equipment->GetEquippedObject(owner, "datapad");
	bool result = false;
	if(datapad)
	{
		datapad->ViewObjects(nullptr, 0, true, [&] (std::shared_ptr<Object> object) {
			if(!result && object->HasAttribute("is_mount") && !object->HasContainedObjects())
			{
				result = true;
			}
		});
	}
	return result;
}

void PlayerService::StoreAllCalledMounts(std::shared_ptr<swganh::object::Creature> owner)
{
	auto simulation = kernel_->GetServiceManager()->GetService<swganh::simulation::SimulationServiceInterface>("SimulationService");
	auto equipment = kernel_->GetServiceManager()->GetService<swganh::equipment::EquipmentServiceInterface>("EquipmentService");
	auto datapad = equipment->GetEquippedObject(owner, "datapad");
	if(datapad)
	{
		std::list<std::shared_ptr<Object>> objects = datapad->GetObjects(nullptr, 1, true);
		for(auto& object : objects) {
			if(object->HasAttribute("is_mount") && !object->HasContainedObjects())
			{
				auto mobile = simulation->GetObjectById((uint64_t)object->GetAttribute<int64_t>("mobile_id"));
				if(mobile)
				{
					mobile->GetContainer()->TransferObject(owner, mobile, object, glm::vec3(0, 0, 0));
				}
			}
		}
	}
}

void PlayerService::StoreAllCalledObjects(std::shared_ptr<swganh::object::Creature> owner)
{
	auto simulation = kernel_->GetServiceManager()->GetService<swganh::simulation::SimulationServiceInterface>("SimulationService");
	auto equipment = kernel_->GetServiceManager()->GetService<swganh::equipment::EquipmentServiceInterface>("EquipmentService");
	auto datapad = equipment->GetEquippedObject(owner, "datapad");
	if(datapad)
	{
		datapad->ViewObjects(nullptr, 0, true, [&] (std::shared_ptr<Object> object) {
			if(object->HasAttribute("mobile_id") && !object->HasContainedObjects())
			{
				auto mobile = simulation->GetObjectById((uint64_t)object->GetAttribute<int64_t>("mobile_id"));
				if(mobile)
				{
					mobile->GetContainer()->TransferObject(owner, mobile, object, glm::vec3(0, 0, 0));
				}
			}
		});
	}
}

void PlayerService::RemoveClientTimerHandler_(
    const boost::system::error_code& e,
    shared_ptr<boost::asio::deadline_timer> timer,
    int delay_in_secs,
    shared_ptr<swganh::object::ObjectController> controller)
{
    if (controller)
    {
        // destroy if they haven't reconnected
        if (controller->GetRemoteClient() == nullptr || !controller->GetRemoteClient()->connected())
        {
            auto object = controller->GetObject();
            DLOG(info) << "Destroying Object " << object->GetObjectId() << " after " << delay_in_secs << " seconds.";

            simulation_service_->RemoveObject(object);

			//Persist buffs
			auto conn = kernel_->GetDatabaseManager()->getConnection("galaxy");
			auto object_id = object->GetObjectId();
			auto creature = std::static_pointer_cast<Creature>(object);
			creature->ViewBuffs([this,&conn,&object_id] (std::pair<boost::posix_time::ptime, std::shared_ptr<swganh::combat::BuffInterface>> entry) {
				std::shared_ptr<sql::PreparedStatement> statement(conn->prepareStatement("INSERT INTO buffs VALUES (?,?,?)"));

				uint32_t duration = (entry.first - boost::posix_time::second_clock::local_time()).total_seconds();

				statement->setUInt64(1, object_id);
				statement->setString(2, entry.second->filename);
				statement->setInt(3, duration);

				statement->execute();
			});

            StoreAllCalledMounts(creature);
			creature->CleanUpBuffs();

            kernel_->GetEventDispatcher()->Dispatch(
                make_shared<ValueEvent<shared_ptr<swganh::object::Object>>>("ObjectRemovedEvent", object));
        }
    }
}<commit_msg>Transfer the owner to the world when storing bikes. This functionality is duplicated in a few places and will be refactored to a dismount command<commit_after>// This file is part of SWGANH which is released under the MIT license.
// See file LICENSE or go to http://swganh.com/LICENSE

#include "player_service.h"

#include "swganh/logger.h"
#include "swganh/event_dispatcher.h"
#include "swganh/service/service_description.h"
#include "swganh/service/service_manager.h"
#include "swganh_core/connection/connection_client_interface.h"
#include "swganh_core/object/player/player.h"
#include "swganh_core/object/creature/creature.h"
#include "swganh_core/object/object_controller.h"
#include "swganh_core/messages/system_message.h"
#include "swganh_core/messages/out_of_band.h"
#include "swganh_core/messages/opened_container_message.h"
#include "swganh_core/simulation/simulation_service_interface.h"
#include "swganh_core/equipment/equipment_service.h"

#include "swganh_core/messages/controllers/add_buff.h"
#include "swganh_core/combat/buff_interface.h"

#include "swganh/database/database_manager.h"
#include <cppconn/exception.h>
#include <cppconn/connection.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/sqlstring.h>

using namespace std;
using namespace swganh;
using namespace swganh::service;
using namespace swganh::player;
using namespace swganh::object;
using namespace swganh::messages;

PlayerService::PlayerService(swganh::app::SwganhKernel* kernel)
	: kernel_(kernel)
{
	kernel_->GetEventDispatcher()->Subscribe(
		"ObjectReadyEvent",
		[this] (shared_ptr<EventInterface> incoming_event)
	{
		auto creature = static_pointer_cast<ValueEvent<shared_ptr<Creature>>>(incoming_event)->Get();

		//Reload buffs from last login
		auto controller = creature->GetController();
		auto object_id = creature->GetObjectId();

		//Resend buffs we current have left over
		creature->ViewBuffs([&, this] (std::pair<boost::posix_time::ptime, std::shared_ptr<swganh::combat::BuffInterface>> entry) {
			uint32_t duration = (entry.first - boost::posix_time::second_clock::local_time()).total_seconds();

			swganh::messages::controllers::AddBuffMessage msg;
			msg.buff = entry.second->GetName();
			msg.duration = static_cast<float>(duration);
			controller->Notify(&msg);
		});

		//Re-Add buffs from the db we still need.
		auto conn = kernel_->GetDatabaseManager()->getConnection("galaxy");
		auto statement = shared_ptr<sql::Statement>(conn->createStatement());

        stringstream ss;
        ss << "SELECT b.name, b.duration FROM buffs b WHERE b.id=" << object_id << ";" ;
        statement->execute(ss.str());

		unique_ptr<sql::ResultSet> result(statement->getResultSet());

		while(result->next())
		{
			creature->AddBuff(result->getString(1), result->getUInt(2));
		}
	});

	player_removed_ = kernel_->GetEventDispatcher()->Subscribe(
		"Connection::PlayerRemoved",
		[this] (shared_ptr<EventInterface> incoming_event)
	{
		const auto& player = static_pointer_cast<ValueEvent<shared_ptr<Player>>>(incoming_event)->Get();
		OnPlayerExit(player);
	});

    SetServiceDescription(ServiceDescription(
        "PlayerService",
        "player",
        "0.1",
        "127.0.0.1",
        0,
        0,
        0));
}

PlayerService::~PlayerService()
{}

void PlayerService::Initialize()
{
	simulation_service_ = kernel_->GetServiceManager()->
		GetService<swganh::simulation::SimulationServiceInterface>("SimulationService");

	equipment_service_ = kernel_->GetServiceManager()->
		GetService<swganh::equipment::EquipmentService>("EquipmentService");
}

void PlayerService::Startup()
{}

void PlayerService::OnPlayerEnter(shared_ptr<swganh::object::Player> player)
{
    if (player)
    {
	    player->ClearStatusFlags();
    }
}

void PlayerService::OnPlayerExit(shared_ptr<swganh::object::Player> player)
{
    if (player)
    {
	    player->ClearStatusFlags();
	    player->AddStatusFlag(swganh::object::LD);
	    // set a timer to 30 seconds to destroy the object, unless logged back in.
        auto deadline_timer = std::make_shared<boost::asio::deadline_timer>(kernel_->GetCpuThreadPool(), boost::posix_time::seconds(30));
		auto parent = std::static_pointer_cast<swganh::object::Object>(player->GetContainer());

		auto object_controller = std::static_pointer_cast<swganh::object::ObjectController>(parent->GetController());
		if(object_controller != nullptr)
		{
			deadline_timer->async_wait(boost::bind(&PlayerService::RemoveClientTimerHandler_, this, boost::asio::placeholders::error, deadline_timer, 30, object_controller));
		}
    }
}

void PlayerService::SendTip(
	const shared_ptr<Creature>& from,
	const shared_ptr<Creature>& to,
	uint32_t amount, bool bank)
{
	// Check to see if we even have the proper amount
	if (amount < 1 || amount > 1000000)
	{
		SystemMessage::Send(from, L"Invalid tip amount, set amount between 1 and 1,000,000");
		return;
	}

	if (bank)
	{
		int32_t total_amount = (int32_t)(amount * 1.05); // 5% tip charge
		int32_t from_amount = from->GetBankCredits();
		if ( from_amount - total_amount > 0)
		{
			from->SetBankCredits( from_amount - total_amount );
			int32_t to_amount = to->GetBankCredits();
			to->SetBankCredits( to_amount + amount );
			SystemMessage::Send(from, OutOfBand("base_player", "prose_wire_pass_self",0,0,to->GetObjectId(),amount), false, false);
			SystemMessage::Send(to, OutOfBand("base_player", "prose_wire_pass_target",0,0,from->GetObjectId(),amount), false, false);
		}
		else
		{
			SystemMessage::Send(from, OutOfBand("base_player", "prose_tip_nsf_bank",0,to->GetObjectId(),0,total_amount), false, false);
		}
	}
	else
	{
		int32_t total_amount = (int32_t)(amount * 1.05); // 5% tip charge
		int32_t from_amount = from->GetCashCredits();
		if ( from_amount - total_amount > 0)
		{
			from->SetCashCredits( from_amount - total_amount );
			int32_t to_amount = to->GetBankCredits();
			to->SetCashCredits( to_amount + amount );
			SystemMessage::Send(from, OutOfBand("base_player", "prose_tip_pass_self",0,to->GetObjectId(),0,amount), false, false);
			SystemMessage::Send(to, OutOfBand("base_player", "prose_tip_pass_target",0,from->GetObjectId(),0,amount), false, false);
		}
		else
		{
			SystemMessage::Send(from, OutOfBand("base_player", "prose_tip_nsf_cash",0,to->GetObjectId(),0,total_amount), false, false);
		}
	}
}

void PlayerService::OpenContainer(const std::shared_ptr<swganh::object::Creature>& owner, std::shared_ptr<swganh::object::Object> object)
{
	// Send Open Container
	OpenedContainerMessage opened_container;
	opened_container.container_object_id = object->GetObjectId();
	owner->NotifyObservers(&opened_container);
}

bool PlayerService::HasCalledMount(std::shared_ptr<swganh::object::Creature> owner)
{
	auto equipment = kernel_->GetServiceManager()->GetService<swganh::equipment::EquipmentServiceInterface>("EquipmentService");
	auto datapad = equipment->GetEquippedObject(owner, "datapad");
	bool result = false;
	if(datapad)
	{
		datapad->ViewObjects(nullptr, 0, true, [&] (std::shared_ptr<Object> object) {
			if(!result && object->HasAttribute("is_mount") && !object->HasContainedObjects())
			{
				result = true;
			}
		});
	}
	return result;
}

void PlayerService::StoreAllCalledMounts(std::shared_ptr<swganh::object::Creature> owner)
{
	auto simulation = kernel_->GetServiceManager()->GetService<swganh::simulation::SimulationServiceInterface>("SimulationService");
	auto equipment = kernel_->GetServiceManager()->GetService<swganh::equipment::EquipmentServiceInterface>("EquipmentService");
	auto datapad = equipment->GetEquippedObject(owner, "datapad");
	if(datapad)
	{
		std::list<std::shared_ptr<Object>> objects = datapad->GetObjects(nullptr, 1, true);
		for(auto& object : objects)
        {
			if(object->HasAttribute("is_mount") && !object->HasContainedObjects())
			{
				if(auto mobile = simulation->GetObjectById((uint64_t)object->GetAttribute<int64_t>("mobile_id")))
				{
                    if (owner->GetContainer()->GetObjectId() == mobile->GetObjectId())
                    {
                        mobile->TransferObject(owner, owner, mobile->GetContainer(), mobile->GetPosition());
                    }

					mobile->GetContainer()->TransferObject(owner, mobile, object, glm::vec3(0, 0, 0));
				}
			}
		}
	}
}

void PlayerService::StoreAllCalledObjects(std::shared_ptr<swganh::object::Creature> owner)
{
	auto simulation = kernel_->GetServiceManager()->GetService<swganh::simulation::SimulationServiceInterface>("SimulationService");
	auto equipment = kernel_->GetServiceManager()->GetService<swganh::equipment::EquipmentServiceInterface>("EquipmentService");
	auto datapad = equipment->GetEquippedObject(owner, "datapad");
	if(datapad)
	{
		datapad->ViewObjects(nullptr, 0, true, [&] (std::shared_ptr<Object> object)
        {
			if(object->HasAttribute("mobile_id") && !object->HasContainedObjects())
			{
				if(auto mobile = simulation->GetObjectById((uint64_t)object->GetAttribute<int64_t>("mobile_id")))
				{
                    if (owner->GetContainer()->GetObjectId() == mobile->GetObjectId())
                    {
                        mobile->TransferObject(owner, owner, mobile->GetContainer(), mobile->GetPosition());
                    }

					mobile->GetContainer()->TransferObject(owner, mobile, object, glm::vec3(0, 0, 0));
				}
			}
		});
	}
}

void PlayerService::RemoveClientTimerHandler_(
    const boost::system::error_code& e,
    shared_ptr<boost::asio::deadline_timer> timer,
    int delay_in_secs,
    shared_ptr<swganh::object::ObjectController> controller)
{
    if (controller)
    {
        // destroy if they haven't reconnected
        if (controller->GetRemoteClient() == nullptr || !controller->GetRemoteClient()->connected())
        {
            auto object = controller->GetObject();
            DLOG(info) << "Destroying Object " << object->GetObjectId() << " after " << delay_in_secs << " seconds.";

			//Persist buffs
			auto conn = kernel_->GetDatabaseManager()->getConnection("galaxy");
			auto object_id = object->GetObjectId();
			auto creature = std::static_pointer_cast<Creature>(object);
			creature->ViewBuffs([this,&conn,&object_id] (std::pair<boost::posix_time::ptime, std::shared_ptr<swganh::combat::BuffInterface>> entry) {
				std::shared_ptr<sql::PreparedStatement> statement(conn->prepareStatement("INSERT INTO buffs VALUES (?,?,?)"));

				uint32_t duration = (entry.first - boost::posix_time::second_clock::local_time()).total_seconds();

				statement->setUInt64(1, object_id);
				statement->setString(2, entry.second->filename);
				statement->setInt(3, duration);

				statement->execute();
			});

            StoreAllCalledMounts(creature);
			creature->CleanUpBuffs();

            simulation_service_->RemoveObject(object);

            kernel_->GetEventDispatcher()->Dispatch(
                make_shared<ValueEvent<shared_ptr<swganh::object::Object>>>("ObjectRemovedEvent", object));
        }
    }
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// This file is part of Swift2D.                                              //
//                                                                            //
// Copyright: (c) 2011-2014 Simon Schneegans & Felix Lauer                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// includes  -------------------------------------------------------------------
#include <swift2d/materials/ShaderIncludes.hpp>
#include <swift2d/utils/Logger.hpp>

namespace swift {

////////////////////////////////////////////////////////////////////////////////

ShaderIncludes::ShaderIncludes() {

  // ---------------------------------------------------------------------------
  add_include("version", R"(
    #version 330
  )");

  add_include("camera_uniforms", R"(
    uniform mat3  projection;
    uniform float parallax;
  )");

  // ---------------------------------------------------------------------------
  add_include("quad_vertex_shader", R"(
    @include "version"

    // input
    layout(location=0) in vec2 position;

    // uniforms
    @include "camera_uniforms"
    uniform mat3  transform;
    uniform float depth;

    // varyings
    out vec2 texcoords;

    void main(void) {
      vec3 pos    = projection * transform * vec3(position, 1.0) * pow(parallax, depth);
      texcoords   = vec2(position.x + 1.0, 1.0 - position.y) * 0.5;
      gl_Position = vec4(pos.xy, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("instanced_quad_vertex_shader", R"(
    @include "version"

    // input
    layout(location=0) in vec2 position;

    // uniforms
    @include "camera_uniforms"
    uniform mat3  transform[100];
    uniform float depth;

    // varyings
    out vec2 texcoords;
    flat out int instance_id;

    void main(void) {
      vec3 pos    = projection * transform[gl_InstanceID] * vec3(position, 1.0) * pow(parallax, depth);
      texcoords   = vec2(position.x + 1.0, 1.0 - position.y) * 0.5;
      instance_id = gl_InstanceID;
      gl_Position = vec4(pos.xy, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("shifted_instanced_quad_vertex_shader", R"(
    @include "version"

    // input
    layout(location=0) in vec2 position;

    // uniforms
    @include "camera_uniforms"
    uniform mat3  transform[100];
    uniform float depth;
    uniform vec4  texcoord_offset_scale;

    // varyings
    out vec2 texcoords;
    flat out int instance_id;

    void main(void) {
      vec3 pos    = projection * transform[gl_InstanceID] * vec3(position, 1.0) * pow(parallax, depth);
      texcoords   = (vec2(position.x + 1.0, 1.0 - position.y) * 0.5 + texcoord_offset_scale.xy) * texcoord_offset_scale.zw;
      instance_id = gl_InstanceID;
      gl_Position = vec4(pos.xy, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("fullscreen_quad_vertex_shader", R"(
    @include "version"

    layout(location=0) in vec2 position;

    // varyings
    out vec2 texcoords;

    void main(void){
      texcoords   = vec2(position.x + 1.0, position.y + 1.0) * 0.5;
      gl_Position = vec4(position, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("write_gbuffer", R"(
    layout (location = 0) out vec4 fragColor;
    layout (location = 1) out vec4 fragNormal;
    layout (location = 2) out vec4 fragLight;

    void write_gbuffer(vec4 color, vec4 normal, float emit, float glow, float shinyness) {
      fragColor   = color;
      fragNormal  = vec4(normal.xyz*0.5 + 0.5, normal.a);
      fragLight   = vec4(emit, shinyness, glow, color.a);
    }

    void write_gbuffer(vec4 color, float glow) {
      fragColor   = color;
      fragNormal  = vec4(0.5, 0.5, 0, 0);
      fragLight   = vec4(1.0, 0.0, glow, color.a);
    }

    void write_gbuffer(vec4 color) {
      fragColor   = color;
      fragNormal  = vec4(0.5, 0.5, 0, 0);
      fragLight   = vec4(1.0, 0.0, 0.0, color.a);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("gbuffer_input", R"(
    uniform sampler2D g_buffer_diffuse;
    uniform sampler2D g_buffer_normal;
    uniform sampler2D g_buffer_light;

    vec3 get_normal(vec2 texcoords) {
      return normalize(texture(g_buffer_normal, texcoords).rgb * 2 - 1);
    }

    vec3 get_diffuse(vec2 texcoords) {
      return texture(g_buffer_diffuse, texcoords).rgb;
    }

    vec3 get_light_info(vec2 texcoords) {
      return texture(g_buffer_light, texcoords).rgb;
    }

  )");

  // ---------------------------------------------------------------------------
  add_include("get_light", R"(
    vec4 get_light(vec2 texcoords, vec3 dir, vec4 color, float gloss, float emit, float attenuation) {
      vec3  normal      = get_normal(texcoords);
      float specular    = pow(max(0, dot(normal, normalize(dir + vec3(0, 0, -1)))), gloss*100 + 1) * gloss;
      float diffuse     = max(0, dot(dir, normal));
      vec3  light       = diffuse * color.rgb;
      return (1.0-emit) * attenuation * vec4(light, specular) * color.a;
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("three_way_mix", R"(
    vec4 three_way_mix(vec4 a, vec4 b, vec4 c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }

    vec3 three_way_mix(vec3 a, vec3 b, vec3 c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }

    vec2 three_way_mix(vec2 a, vec2 b, vec2 c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }

    float three_way_mix(float a, float b, float c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("emit_quad", R"(
    void emit_quad(vec2 position, vec2 scale, float rotation) {
      const float yo[2] = float[2](0.5, -0.5);
      const float xo[2] = float[2](0.5, -0.5);

      for(int j=0; j!=2; ++j) {
        for(int i=0; i!=2; ++i) {

          vec2 pos = vec2(xo[i], yo[j]) * scale;

          pos = vec2(
            pos.x * cos(rotation) - pos.y * sin(rotation),
            pos.y * cos(rotation) + pos.x * sin(rotation)
          );

          pos = position - pos;
          pos = (projection * vec3(pos, 1.0)).xy;

          gl_Position = vec4(pos, 0.0, 1.0);
          age         = varying_age[0];
          texcoords   = vec2(-xo[i], yo[j]) + 0.5;

          EmitVertex();
        }
      }
      EndPrimitive();
    }

    void emit_quad(vec2 position, vec2 scale) {
      const float yo[2] = float[2](0.5, -0.5);
      const float xo[2] = float[2](0.5, -0.5);

      for(int j=0; j!=2; ++j) {
        for(int i=0; i!=2; ++i) {

          vec2 pos = vec2(xo[i], yo[j]) * scale;
          pos = position - pos;
          pos = (projection * vec3(pos, 1.0)).xy;

          gl_Position = vec4(pos, 0.0, 1.0);
          age         = varying_age[0];
          texcoords   = vec2(-xo[i], yo[j]) + 0.5;

          EmitVertex();
        }
      }
      EndPrimitive();
    }
  )");
}

////////////////////////////////////////////////////////////////////////////////

void ShaderIncludes::process(std::string& input) const {
  while (process_impl(input));
}

////////////////////////////////////////////////////////////////////////////////

void ShaderIncludes::add_include(std::string const& identifier,
                                 std::string const& code) {
  snippets_[identifier] = code;
}

////////////////////////////////////////////////////////////////////////////////

bool ShaderIncludes::process_impl(std::string& input) const {
  std::size_t search_pos(0);
  std::string search("@include");

  bool replaced_something(false);

  while(search_pos != std::string::npos) {

    // find include
    search_pos = input.find(search, search_pos);

    if (search_pos != std::string::npos) {

      // get file name
      std::size_t start(input.find('\"', search_pos)+1);
      std::size_t end (input.find('\"', start));

      std::string snippet(input.substr(start, end-start));

      // get included file
      std::string include;

      auto code = snippets_.find(snippet);
      if (code != snippets_.end()) {
        include = code->second;
      } else {
        LOG_WARNING << "Failed to resolve shader include \""
                            << snippet << "\": No such snippet!" << std::endl;
      }

      // include it
      input.replace(search_pos, end-search_pos + 2, include);

      // advance search pos
      search_pos = search_pos + include.length();

      replaced_something = true;
    }
  }

  return replaced_something;
}

////////////////////////////////////////////////////////////////////////////////

}
<commit_msg>fixed bug in shifted_instanced_quad_vertex_shader: texcoord_offset_scale is a uniform array now<commit_after>////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// This file is part of Swift2D.                                              //
//                                                                            //
// Copyright: (c) 2011-2014 Simon Schneegans & Felix Lauer                    //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// includes  -------------------------------------------------------------------
#include <swift2d/materials/ShaderIncludes.hpp>
#include <swift2d/utils/Logger.hpp>

namespace swift {

////////////////////////////////////////////////////////////////////////////////

ShaderIncludes::ShaderIncludes() {

  // ---------------------------------------------------------------------------
  add_include("version", R"(
    #version 330
  )");

  add_include("camera_uniforms", R"(
    uniform mat3  projection;
    uniform float parallax;
  )");

  // ---------------------------------------------------------------------------
  add_include("quad_vertex_shader", R"(
    @include "version"

    // input
    layout(location=0) in vec2 position;

    // uniforms
    @include "camera_uniforms"
    uniform mat3  transform;
    uniform float depth;

    // varyings
    out vec2 texcoords;

    void main(void) {
      vec3 pos    = projection * transform * vec3(position, 1.0) * pow(parallax, depth);
      texcoords   = vec2(position.x + 1.0, 1.0 - position.y) * 0.5;
      gl_Position = vec4(pos.xy, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("instanced_quad_vertex_shader", R"(
    @include "version"

    // input
    layout(location=0) in vec2 position;

    // uniforms
    @include "camera_uniforms"
    uniform mat3  transform[100];
    uniform float depth;

    // varyings
    out vec2 texcoords;
    flat out int instance_id;

    void main(void) {
      vec3 pos    = projection * transform[gl_InstanceID] * vec3(position, 1.0) * pow(parallax, depth);
      texcoords   = vec2(position.x + 1.0, 1.0 - position.y) * 0.5;
      instance_id = gl_InstanceID;
      gl_Position = vec4(pos.xy, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("shifted_instanced_quad_vertex_shader", R"(
    @include "version"

    // input
    layout(location=0) in vec2 position;

    // uniforms
    @include "camera_uniforms"
    uniform mat3  transform[100];
    uniform float depth;
    uniform vec4  texcoord_offset_scale[100];

    // varyings
    out vec2 texcoords;
    flat out int instance_id;

    void main(void) {
      vec3 pos    = projection * transform[gl_InstanceID] * vec3(position, 1.0) * pow(parallax, depth);
      texcoords   = (vec2(position.x + 1.0, 1.0 - position.y) * 0.5 + texcoord_offset_scale[gl_InstanceID].xy) * texcoord_offset_scale[gl_InstanceID].zw;
      instance_id = gl_InstanceID;
      gl_Position = vec4(pos.xy, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("fullscreen_quad_vertex_shader", R"(
    @include "version"

    layout(location=0) in vec2 position;

    // varyings
    out vec2 texcoords;

    void main(void){
      texcoords   = vec2(position.x + 1.0, position.y + 1.0) * 0.5;
      gl_Position = vec4(position, 0.0, 1.0);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("write_gbuffer", R"(
    layout (location = 0) out vec4 fragColor;
    layout (location = 1) out vec4 fragNormal;
    layout (location = 2) out vec4 fragLight;

    void write_gbuffer(vec4 color, vec4 normal, float emit, float glow, float shinyness) {
      fragColor   = color;
      fragNormal  = vec4(normal.xyz*0.5 + 0.5, normal.a);
      fragLight   = vec4(emit, shinyness, glow, color.a);
    }

    void write_gbuffer(vec4 color, float glow) {
      fragColor   = color;
      fragNormal  = vec4(0.5, 0.5, 0, 0);
      fragLight   = vec4(1.0, 0.0, glow, color.a);
    }

    void write_gbuffer(vec4 color) {
      fragColor   = color;
      fragNormal  = vec4(0.5, 0.5, 0, 0);
      fragLight   = vec4(1.0, 0.0, 0.0, color.a);
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("gbuffer_input", R"(
    uniform sampler2D g_buffer_diffuse;
    uniform sampler2D g_buffer_normal;
    uniform sampler2D g_buffer_light;

    vec3 get_normal(vec2 texcoords) {
      return normalize(texture(g_buffer_normal, texcoords).rgb * 2 - 1);
    }

    vec3 get_diffuse(vec2 texcoords) {
      return texture(g_buffer_diffuse, texcoords).rgb;
    }

    vec3 get_light_info(vec2 texcoords) {
      return texture(g_buffer_light, texcoords).rgb;
    }

  )");

  // ---------------------------------------------------------------------------
  add_include("get_light", R"(
    vec4 get_light(vec2 texcoords, vec3 dir, vec4 color, float gloss, float emit, float attenuation) {
      vec3  normal      = get_normal(texcoords);
      float specular    = pow(max(0, dot(normal, normalize(dir + vec3(0, 0, -1)))), gloss*100 + 1) * gloss;
      float diffuse     = max(0, dot(dir, normal));
      vec3  light       = diffuse * color.rgb;
      return (1.0-emit) * attenuation * vec4(light, specular) * color.a;
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("three_way_mix", R"(
    vec4 three_way_mix(vec4 a, vec4 b, vec4 c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }

    vec3 three_way_mix(vec3 a, vec3 b, vec3 c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }

    vec2 three_way_mix(vec2 a, vec2 b, vec2 c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }

    float three_way_mix(float a, float b, float c, float mid, float alpha) {
      return (alpha < mid ? mix(a, b, alpha/(mid+0.0001)) : mix(b, c, (alpha-mid)/(1.0-mid+0.0001)));
    }
  )");

  // ---------------------------------------------------------------------------
  add_include("emit_quad", R"(
    void emit_quad(vec2 position, vec2 scale, float rotation) {
      const float yo[2] = float[2](0.5, -0.5);
      const float xo[2] = float[2](0.5, -0.5);

      for(int j=0; j!=2; ++j) {
        for(int i=0; i!=2; ++i) {

          vec2 pos = vec2(xo[i], yo[j]) * scale;

          pos = vec2(
            pos.x * cos(rotation) - pos.y * sin(rotation),
            pos.y * cos(rotation) + pos.x * sin(rotation)
          );

          pos = position - pos;
          pos = (projection * vec3(pos, 1.0)).xy;

          gl_Position = vec4(pos, 0.0, 1.0);
          age         = varying_age[0];
          texcoords   = vec2(-xo[i], yo[j]) + 0.5;

          EmitVertex();
        }
      }
      EndPrimitive();
    }

    void emit_quad(vec2 position, vec2 scale) {
      const float yo[2] = float[2](0.5, -0.5);
      const float xo[2] = float[2](0.5, -0.5);

      for(int j=0; j!=2; ++j) {
        for(int i=0; i!=2; ++i) {

          vec2 pos = vec2(xo[i], yo[j]) * scale;
          pos = position - pos;
          pos = (projection * vec3(pos, 1.0)).xy;

          gl_Position = vec4(pos, 0.0, 1.0);
          age         = varying_age[0];
          texcoords   = vec2(-xo[i], yo[j]) + 0.5;

          EmitVertex();
        }
      }
      EndPrimitive();
    }
  )");
}

////////////////////////////////////////////////////////////////////////////////

void ShaderIncludes::process(std::string& input) const {
  while (process_impl(input));
}

////////////////////////////////////////////////////////////////////////////////

void ShaderIncludes::add_include(std::string const& identifier,
                                 std::string const& code) {
  snippets_[identifier] = code;
}

////////////////////////////////////////////////////////////////////////////////

bool ShaderIncludes::process_impl(std::string& input) const {
  std::size_t search_pos(0);
  std::string search("@include");

  bool replaced_something(false);

  while(search_pos != std::string::npos) {

    // find include
    search_pos = input.find(search, search_pos);

    if (search_pos != std::string::npos) {

      // get file name
      std::size_t start(input.find('\"', search_pos)+1);
      std::size_t end (input.find('\"', start));

      std::string snippet(input.substr(start, end-start));

      // get included file
      std::string include;

      auto code = snippets_.find(snippet);
      if (code != snippets_.end()) {
        include = code->second;
      } else {
        LOG_WARNING << "Failed to resolve shader include \""
                            << snippet << "\": No such snippet!" << std::endl;
      }

      // include it
      input.replace(search_pos, end-search_pos + 2, include);

      // advance search pos
      search_pos = search_pos + include.length();

      replaced_something = true;
    }
  }

  return replaced_something;
}

////////////////////////////////////////////////////////////////////////////////

}
<|endoftext|>


<commit_before>/*
QWebSockets implements the WebSocket protocol as defined in RFC 6455.
Copyright (C) 2013 Kurt Pattyn (pattyn.kurt@gmail.com)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "qwebsocketprotocol.h"
#include <QString>
#include <QSet>
#include <QtEndian>

/*!
    \enum WebSocketProtocol::CloseCode

    The close codes supported by WebSockets V13
    \sa WebSocket::close()
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_NORMAL
    Normal closure
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_GOING_AWAY
    Going away
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_PROTOCOL_ERROR
    Protocol error
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_DATATYPE_NOT_SUPPORTED
    Unsupported data
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_RESERVED_1004
    Reserved
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_MISSING_STATUS_CODE
    No status received
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_ABNORMAL_DISCONNECTION
    Abnormal closure
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_WRONG_DATATYPE
    Invalid frame payload data
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_POLICY_VIOLATED
    Policy violation
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_TOO_MUCH_DATA
    Message too big
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_MISSING_EXTENSION
    Mandatory extension missing
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_BAD_OPERATION
    Internal server error
*/
/*!
    \var WebSocketProtocol::CloseCode::CC_TLS_HANDSHAKE_FAILED
    TLS handshake failed
*/
/*!
    \enum WebSocketProtocol::Version

    \brief The different defined versions of the Websocket protocol.

    For an overview of the differences between the different protocols, see
    <http://code.google.com/p/pywebsocket/wiki/WebSocketProtocolSpec>
*/
/*!
    \var WebSocketProtocol::Version::V_Unknow
*/
/*!
    \var WebSocketProtocol::Version::V_0
    hixie76: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 & hybi-00: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00.
    Works with key1, key2 and a key in the payload.\n
    Attribute: Sec-WebSocket-Draft value 0.
*/
/*!
    \var WebSocketProtocol::Version::V_4
    hybi-04: http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-04.txt.
    Changed handshake: key1, key2, key3 ==> Sec-WebSocket-Key, Sec-WebSocket-Nonce, Sec-WebSocket-Accept\n
    Sec-WebSocket-Draft renamed to Sec-WebSocket-Version\n
    Sec-WebSocket-Version = 4
*/
/*!
    \var WebSocketProtocol::Version::V_5
    hybi-05: http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-05.txt.
    Sec-WebSocket-Version = 5\n
    Removed Sec-WebSocket-Nonce\n
    Added Sec-WebSocket-Accept\n
*/
/*!
    \var WebSocketProtocol::Version::V_6
    Sec-WebSocket-Version = 6.
*/
/*!
    \var WebSocketProtocol::Version::V_7
    hybi-07: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07.
    Sec-WebSocket-Version = 7
*/
/*!
    \var WebSocketProtocol::Version::V_8
    hybi-8, hybi-9, hybi-10, hybi-11 and hybi-12.
    Status codes 1005 and 1006 are added and all codes are now unsigned\n
    Internal error results in 1006
*/
/*!
    \var WebSocketProtocol::Version::V_13
    hybi-13, hybi14, hybi-15, hybi-16, hybi-17 and RFC 6455.
    Sec-WebSocket-Version = 13\n
    Status code 1004 is now reserved\n
    Added 1008, 1009 and 1010\n
    Must support TLS\n
    Clarify multiple version support
*/
/*!
    \var WebSocketProtocol::Version::V_LATEST
    Refers to the latest know version to QWebSockets.
*/

/*!
  \fn WebSocketProtocol::isOpCodeReserved(OpCode code)
  Checks if \a code is a valid OpCode
  \internal
*/

/*!
  \fn WebSocketProtocol::isCloseCodeValid(int closeCode)
  Checks if \a closeCode is a valid web socket close code
  \internal
*/

/*!
  \fn WebSocketProtocol::getCurrentVersion()
  Returns the latest version that WebSocket is supporting
  \internal
*/

QT_BEGIN_NAMESPACE

/**
 * @brief Contains constants related to the WebSocket standard.
 */
namespace QWebSocketProtocol
{
/*!
        Parses the \a versionString and converts it to a Version value
        \internal
    */
Version versionFromString(const QString &versionString)
{
    bool ok = false;
    Version version = V_Unknow;
    int ver = versionString.toInt(&ok);
    QSet<Version> supportedVersions;
    supportedVersions << V_0 << V_4 << V_5 << V_6 << V_7 << V_8 << V_13;
    if (ok)
    {
        if (supportedVersions.contains(static_cast<Version>(ver)))
        {
            version = static_cast<Version>(ver);
        }
    }
    return version;
}

/*!
      Mask the \a payload with the given \a maskingKey and stores the result back in \a payload.
      \internal
    */
void mask(QByteArray *payload, quint32 maskingKey)
{
    quint32 *payloadData = reinterpret_cast<quint32 *>(payload->data());
    quint32 numIterations = static_cast<quint32>(payload->size()) / sizeof(quint32);
    quint32 remainder = static_cast<quint32>(payload->size()) % sizeof(quint32);
    quint32 i;
    for (i = 0; i < numIterations; ++i)
    {
        *(payloadData + i) ^= maskingKey;
    }
    if (remainder)
    {
        const quint32 offset = i * static_cast<quint32>(sizeof(quint32));
        char *payloadBytes = payload->data();
        uchar *mask = reinterpret_cast<uchar *>(&maskingKey);
        for (quint32 i = 0; i < remainder; ++i)
        {
            *(payloadBytes + offset + i) ^= static_cast<char>(mask[(i + offset) % 4]);
        }
    }
}

/*!
      Masks the \a payload of length \a size with the given \a maskingKey and stores the result back in \a payload.
      \internal
    */
void mask(char *payload, quint64 size, quint32 maskingKey)
{
    quint32 *payloadData = reinterpret_cast<quint32 *>(payload);
    quint32 numIterations = static_cast<quint32>(size / sizeof(quint32));
    quint32 remainder = size % sizeof(quint32);
    quint32 i;
    for (i = 0; i < numIterations; ++i)
    {
        *(payloadData + i) ^= maskingKey;
    }
    if (remainder)
    {
        const quint32 offset = i * static_cast<quint32>(sizeof(quint32));
        uchar *mask = reinterpret_cast<uchar *>(&maskingKey);
        for (quint32 i = 0; i < remainder; ++i)
        {
            *(payload + offset + i) ^= static_cast<char>(mask[(i + offset) % 4]);
        }
    }
}
}	//end namespace WebSocketProtocol

QT_END_NAMESPACE
<commit_msg>Adapted documentation to qDoc style<commit_after>/*
QWebSockets implements the WebSocket protocol as defined in RFC 6455.
Copyright (C) 2013 Kurt Pattyn (pattyn.kurt@gmail.com)

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "qwebsocketprotocol.h"
#include <QString>
#include <QSet>
#include <QtEndian>

/*!
    \enum WebSocketProtocol::CloseCode

    The close codes supported by WebSockets V13

    \value CC_NORMAL                    Normal closure
    \value CC_GOING_AWAY                Going away
    \value CC_PROTOCOL_ERROR            Protocol error
    \value CC_DATATYPE_NOT_SUPPORTED    Unsupported data
    \value CC_RESERVED_1004             Reserved
    \value CC_MISSING_STATUS_CODE       No status received
    \value CC_ABNORMAL_DISCONNECTION    Abnormal closure
    \value CC_WRONG_DATATYPE            Invalid frame payload data
    \value CC_POLICY_VIOLATED           Policy violation
    \value CC_TOO_MUCH_DATA             Message too big
    \value CC_MISSING_EXTENSION         Mandatory extension missing
    \value CC_BAD_OPERATION             Internal server error
    \value CC_TLS_HANDSHAKE_FAILED      TLS handshake failed

    \sa \l{QWebSocket::} {close()}
*/
/*!
    \enum WebSocketProtocol::Version

    \brief The different defined versions of the Websocket protocol.

    For an overview of the differences between the different protocols, see
    <http://code.google.com/p/pywebsocket/wiki/WebSocketProtocolSpec>

    \value V_Unknow
    \value V_0          hixie76: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76 & hybi-00: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00.
                        Works with key1, key2 and a key in the payload.
                        Attribute: Sec-WebSocket-Draft value 0.
    \value V_4          hybi-04: http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-04.txt.
                        Changed handshake: key1, key2, key3 ==> Sec-WebSocket-Key, Sec-WebSocket-Nonce, Sec-WebSocket-Accept
                        Sec-WebSocket-Draft renamed to Sec-WebSocket-Version
                        Sec-WebSocket-Version = 4
    \value V_5          hybi-05: http://tools.ietf.org/id/draft-ietf-hybi-thewebsocketprotocol-05.txt.
                        Sec-WebSocket-Version = 5
                        Removed Sec-WebSocket-Nonce
                        Added Sec-WebSocket-Accept
    \value V_6          Sec-WebSocket-Version = 6.
    \value V_7          hybi-07: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07.
                        Sec-WebSocket-Version = 7
    \value V_8          hybi-8, hybi-9, hybi-10, hybi-11 and hybi-12.
                        Status codes 1005 and 1006 are added and all codes are now unsigned
                        Internal error results in 1006
    \value V_13         hybi-13, hybi14, hybi-15, hybi-16, hybi-17 and RFC 6455.
                        Sec-WebSocket-Version = 13
                        Status code 1004 is now reserved
                        Added 1008, 1009 and 1010
                        Must support TLS
                        Clarify multiple version support
    \value V_LATEST     Refers to the latest know version to QWebSockets.
*/

/*!
  \fn WebSocketProtocol::isOpCodeReserved(OpCode code)
  Checks if \a code is a valid OpCode
  \internal
*/

/*!
  \fn WebSocketProtocol::isCloseCodeValid(int closeCode)
  Checks if \a closeCode is a valid web socket close code
  \internal
*/

/*!
  \fn WebSocketProtocol::getCurrentVersion()
  Returns the latest version that WebSocket is supporting
  \internal
*/

QT_BEGIN_NAMESPACE

/**
 * @brief Contains constants related to the WebSocket standard.
 */
namespace QWebSocketProtocol
{
/*!
        Parses the \a versionString and converts it to a Version value
        \internal
    */
Version versionFromString(const QString &versionString)
{
    bool ok = false;
    Version version = V_Unknow;
    int ver = versionString.toInt(&ok);
    QSet<Version> supportedVersions;
    supportedVersions << V_0 << V_4 << V_5 << V_6 << V_7 << V_8 << V_13;
    if (ok)
    {
        if (supportedVersions.contains(static_cast<Version>(ver)))
        {
            version = static_cast<Version>(ver);
        }
    }
    return version;
}

/*!
      Mask the \a payload with the given \a maskingKey and stores the result back in \a payload.
      \internal
    */
void mask(QByteArray *payload, quint32 maskingKey)
{
    quint32 *payloadData = reinterpret_cast<quint32 *>(payload->data());
    quint32 numIterations = static_cast<quint32>(payload->size()) / sizeof(quint32);
    quint32 remainder = static_cast<quint32>(payload->size()) % sizeof(quint32);
    quint32 i;
    for (i = 0; i < numIterations; ++i)
    {
        *(payloadData + i) ^= maskingKey;
    }
    if (remainder)
    {
        const quint32 offset = i * static_cast<quint32>(sizeof(quint32));
        char *payloadBytes = payload->data();
        uchar *mask = reinterpret_cast<uchar *>(&maskingKey);
        for (quint32 i = 0; i < remainder; ++i)
        {
            *(payloadBytes + offset + i) ^= static_cast<char>(mask[(i + offset) % 4]);
        }
    }
}

/*!
      Masks the \a payload of length \a size with the given \a maskingKey and stores the result back in \a payload.
      \internal
    */
void mask(char *payload, quint64 size, quint32 maskingKey)
{
    quint32 *payloadData = reinterpret_cast<quint32 *>(payload);
    quint32 numIterations = static_cast<quint32>(size / sizeof(quint32));
    quint32 remainder = size % sizeof(quint32);
    quint32 i;
    for (i = 0; i < numIterations; ++i)
    {
        *(payloadData + i) ^= maskingKey;
    }
    if (remainder)
    {
        const quint32 offset = i * static_cast<quint32>(sizeof(quint32));
        uchar *mask = reinterpret_cast<uchar *>(&maskingKey);
        for (quint32 i = 0; i < remainder; ++i)
        {
            *(payload + offset + i) ^= static_cast<char>(mask[(i + offset) % 4]);
        }
    }
}
}	//end namespace WebSocketProtocol

QT_END_NAMESPACE
<|endoftext|>