<commit_before>/**
 * @file llfloatersearch.cpp
 * @author Martin Reddy
 * @brief Search floater - uses an embedded web browser control
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "llfloatersearch.h"
#include "llmediactrl.h"
#include "lllogininstance.h"
#include "lluri.h"
#include "llagent.h"
#include "llui.h"
#include "llviewercontrol.h"
#include "llweb.h"

// support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps
class LLSearchHandler : public LLCommandHandler
{
public:
	// requires trusted browser to trigger
	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { }
	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
	{
		const size_t parts = tokens.size();

		// get the (optional) category for the search
		std::string category;
		if (parts > 0)
		{
			category = tokens[0].asString();
		}

		// get the (optional) search string
		std::string search_text;
		if (parts > 1)
		{
			search_text = tokens[1].asString();
		}

		// create the LLSD arguments for the search floater
		LLSD args;
		args["category"] = category;
		args["id"] = LLURI::unescape(search_text);

		// open the search floater and perform the requested search
		LLFloaterReg::showInstance("search", args);
		return true;
	}
};
LLSearchHandler gSearchHandler;

LLFloaterSearch::LLFloaterSearch(const LLSD& key) :
	LLFloater(key),
	LLViewerMediaObserver(),
	mBrowser(NULL),
	mSearchGodLevel(0)
{
	// declare a map that transforms a category name into
	// the URL suffix that is used to search that category
	mCategoryPaths = LLSD::emptyMap();
	mCategoryPaths["all"]          = "search";
	mCategoryPaths["people"]       = "search/people";
	mCategoryPaths["places"]       = "search/places";
	mCategoryPaths["events"]       = "search/events";
	mCategoryPaths["groups"]       = "search/groups";
	mCategoryPaths["wiki"]         = "search/wiki";
	mCategoryPaths["destinations"] = "destinations";
	mCategoryPaths["classifieds"]  = "classifieds";
}

BOOL LLFloaterSearch::postBuild()
{
	mBrowser = getChild<LLMediaCtrl>("browser");
	mBrowser->addObserver(this);

	return TRUE;
}

void LLFloaterSearch::onOpen(const LLSD& key)
{
	search(key);
}

void LLFloaterSearch::onClose(bool app_quitting)
{
	// tear down the web view so we don't show the previous search
	// result when the floater is opened next time
	destroy();
}

void LLFloaterSearch::handleMediaEvent(LLPluginClassMedia *self, EMediaEvent event)
{
	switch (event)
	{
	case MEDIA_EVENT_NAVIGATE_BEGIN:
		getChild<LLUICtrl>("status_text")->setValue(getString("loading_text"));
		break;

	case MEDIA_EVENT_NAVIGATE_COMPLETE:
		getChild<LLUICtrl>("status_text")->setValue(getString("done_text"));
		break;

	default:
		break;
	}
}

void LLFloaterSearch::godLevelChanged(U8 godlevel)
{
	// search results can change based upon god level - if the user
	// changes god level, then give them a warning (we don't refresh
	// the search as this might undo any page navigation or
	// AJAX-driven changes since the last search).
	getChildView("refresh_search")->setVisible( (godlevel != mSearchGodLevel));
}

void LLFloaterSearch::search(const LLSD &key)
{
	if (! mBrowser)
	{
		return;
	}

	// reset the god level warning as we're sending the latest state
	getChildView("refresh_search")->setVisible(FALSE);
	mSearchGodLevel = gAgent.getGodLevel();

	// work out the subdir to use based on the requested category
	LLSD subs;
	std::string category = key.has("category") ? key["category"].asString() : "";
	if (mCategoryPaths.has(category))
	{
		subs["CATEGORY"] = mCategoryPaths[category].asString();
	}
	else
	{
		subs["CATEGORY"] = mCategoryPaths["all"].asString();
	}

	// add the search query string
	std::string search_text = key.has("id") ? key["id"].asString() : "";
	subs["QUERY"] = LLURI::escape(search_text);

	// add the permissions token that login.cgi gave us
	// We use "search_token", and fallback to "auth_token" if not present.
	LLSD search_token = LLLoginInstance::getInstance()->getResponse("search_token");
	if (search_token.asString().empty())
	{
		search_token = LLLoginInstance::getInstance()->getResponse("auth_token");
	}
	subs["AUTH_TOKEN"] = search_token.asString();

	// add the user's preferred maturity (can be changed via prefs)
	std::string maturity;
	if (gAgent.prefersAdult())
	{
		maturity = "42";  // PG,Mature,Adult
	}
	else if (gAgent.prefersMature())
	{
		maturity = "21";  // PG,Mature
	}
	else
	{
		maturity = "13";  // PG
	}
	subs["MATURITY"] = maturity;

	// add the user's god status
	subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0";

	// get the search URL and expand all of the substitutions
	// (also adds things like [LANGUAGE], [VERSION], [OS], etc.)
	std::string url = gSavedSettings.getString("SearchURL");
	url = LLWeb::expandURLSubstitutions(url, subs);

	// and load the URL in the web view
	mBrowser->navigateTo(url);
}
<commit_msg>SOCIAL-269 FIX Search floater in client should bypass the usual media MIME type detection<commit_after>/**
 * @file llfloatersearch.cpp
 * @author Martin Reddy
 * @brief Search floater - uses an embedded web browser control
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * 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;
 * version 2.1 of the License only.
 *
 * 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
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewerprecompiledheaders.h"

#include "llcommandhandler.h"
#include "llfloaterreg.h"
#include "llfloatersearch.h"
#include "llmediactrl.h"
#include "lllogininstance.h"
#include "lluri.h"
#include "llagent.h"
#include "llui.h"
#include "llviewercontrol.h"
#include "llweb.h"

// support secondlife:///app/search/{CATEGORY}/{QUERY} SLapps
class LLSearchHandler : public LLCommandHandler
{
public:
	// requires trusted browser to trigger
	LLSearchHandler() : LLCommandHandler("search", UNTRUSTED_THROTTLE) { }
	bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
	{
		const size_t parts = tokens.size();

		// get the (optional) category for the search
		std::string category;
		if (parts > 0)
		{
			category = tokens[0].asString();
		}

		// get the (optional) search string
		std::string search_text;
		if (parts > 1)
		{
			search_text = tokens[1].asString();
		}

		// create the LLSD arguments for the search floater
		LLSD args;
		args["category"] = category;
		args["id"] = LLURI::unescape(search_text);

		// open the search floater and perform the requested search
		LLFloaterReg::showInstance("search", args);
		return true;
	}
};
LLSearchHandler gSearchHandler;

LLFloaterSearch::LLFloaterSearch(const LLSD& key) :
	LLFloater(key),
	LLViewerMediaObserver(),
	mBrowser(NULL),
	mSearchGodLevel(0)
{
	// declare a map that transforms a category name into
	// the URL suffix that is used to search that category
	mCategoryPaths = LLSD::emptyMap();
	mCategoryPaths["all"]          = "search";
	mCategoryPaths["people"]       = "search/people";
	mCategoryPaths["places"]       = "search/places";
	mCategoryPaths["events"]       = "search/events";
	mCategoryPaths["groups"]       = "search/groups";
	mCategoryPaths["wiki"]         = "search/wiki";
	mCategoryPaths["destinations"] = "destinations";
	mCategoryPaths["classifieds"]  = "classifieds";
}

BOOL LLFloaterSearch::postBuild()
{
	mBrowser = getChild<LLMediaCtrl>("browser");
	mBrowser->addObserver(this);

	return TRUE;
}

void LLFloaterSearch::onOpen(const LLSD& key)
{
	search(key);
}

void LLFloaterSearch::onClose(bool app_quitting)
{
	// tear down the web view so we don't show the previous search
	// result when the floater is opened next time
	destroy();
}

void LLFloaterSearch::handleMediaEvent(LLPluginClassMedia *self, EMediaEvent event)
{
	switch (event)
	{
	case MEDIA_EVENT_NAVIGATE_BEGIN:
		getChild<LLUICtrl>("status_text")->setValue(getString("loading_text"));
		break;

	case MEDIA_EVENT_NAVIGATE_COMPLETE:
		getChild<LLUICtrl>("status_text")->setValue(getString("done_text"));
		break;

	default:
		break;
	}
}

void LLFloaterSearch::godLevelChanged(U8 godlevel)
{
	// search results can change based upon god level - if the user
	// changes god level, then give them a warning (we don't refresh
	// the search as this might undo any page navigation or
	// AJAX-driven changes since the last search).
	getChildView("refresh_search")->setVisible( (godlevel != mSearchGodLevel));
}

void LLFloaterSearch::search(const LLSD &key)
{
	if (! mBrowser)
	{
		return;
	}

	// reset the god level warning as we're sending the latest state
	getChildView("refresh_search")->setVisible(FALSE);
	mSearchGodLevel = gAgent.getGodLevel();

	// work out the subdir to use based on the requested category
	LLSD subs;
	std::string category = key.has("category") ? key["category"].asString() : "";
	if (mCategoryPaths.has(category))
	{
		subs["CATEGORY"] = mCategoryPaths[category].asString();
	}
	else
	{
		subs["CATEGORY"] = mCategoryPaths["all"].asString();
	}

	// add the search query string
	std::string search_text = key.has("id") ? key["id"].asString() : "";
	subs["QUERY"] = LLURI::escape(search_text);

	// add the permissions token that login.cgi gave us
	// We use "search_token", and fallback to "auth_token" if not present.
	LLSD search_token = LLLoginInstance::getInstance()->getResponse("search_token");
	if (search_token.asString().empty())
	{
		search_token = LLLoginInstance::getInstance()->getResponse("auth_token");
	}
	subs["AUTH_TOKEN"] = search_token.asString();

	// add the user's preferred maturity (can be changed via prefs)
	std::string maturity;
	if (gAgent.prefersAdult())
	{
		maturity = "42";  // PG,Mature,Adult
	}
	else if (gAgent.prefersMature())
	{
		maturity = "21";  // PG,Mature
	}
	else
	{
		maturity = "13";  // PG
	}
	subs["MATURITY"] = maturity;

	// add the user's god status
	subs["GODLIKE"] = gAgent.isGodlike() ? "1" : "0";

	// get the search URL and expand all of the substitutions
	// (also adds things like [LANGUAGE], [VERSION], [OS], etc.)
	std::string url = gSavedSettings.getString("SearchURL");
	url = LLWeb::expandURLSubstitutions(url, subs);

	// and load the URL in the web view
	mBrowser->navigateTo(url, "text/html");
}
<|endoftext|>


<commit_before>#ifndef KGR_KANGARU_INCLUDE_KANGARU_PREDICATE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_PREDICATE_HPP

#include "type_id.hpp"

namespace kgr {

/*
 * This predicate always returns true.
 *
 * This is the default predicate used by the container.
 */
struct All {
	constexpr inline bool operator()(type_id_t) const {
		return true;
	}
};

/*
 * This predicate returns true for all services except those specified.
 */
template<typename First, typename... Ts>
struct NoneOf {
	constexpr bool operator()(type_id_t id) const {
		return !compare<First, Ts...>(id);
	}

private:
	template<typename Compared, typename Second, typename... Rest>
	constexpr bool compare(type_id_t id) const {
		return id == type_id<Compared>() && compare<Second, Rest...>(id);
	}

	template<typename Compared>
	constexpr bool compare(type_id_t id) const {
		return id == type_id<Compared>();
	}
};

/*
 * Predicate that returns false for all services, except those passed as argument.
 */
template<typename First, typename... Ts>
struct AnyOf {
	constexpr bool operator()(type_id_t id) const {
		return compare<First, Ts...>(id);
	}

private:
	template<typename Compared, typename Second, typename... Rest>
	constexpr bool compare(type_id_t id) const {
		return id == type_id<Compared>() && compare<Second, Rest...>(id);
	}

	template<typename Compared>
	constexpr bool compare(type_id_t id) const {
		return id == type_id<Compared>();
	}
};

} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_PREDICATE_HPP
<commit_msg>Added noexcept in predicates<commit_after>#ifndef KGR_KANGARU_INCLUDE_KANGARU_PREDICATE_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_PREDICATE_HPP

#include "type_id.hpp"

namespace kgr {

/*
 * This predicate always returns true.
 *
 * This is the default predicate used by the container.
 */
struct All {
	constexpr inline bool operator()(type_id_t) const noexcept {
		return true;
	}
};

/*
 * This predicate returns true for all services except those specified.
 */
template<typename First, typename... Ts>
struct NoneOf {
	constexpr bool operator()(type_id_t id) const noexcept {
		return !compare<First, Ts...>(id);
	}

private:
	template<typename Compared, typename Second, typename... Rest>
	constexpr bool compare(type_id_t id) const noexcept {
		return id == type_id<Compared>() && compare<Second, Rest...>(id);
	}

	template<typename Compared>
	constexpr bool compare(type_id_t id) const noexcept {
		return id == type_id<Compared>();
	}
};

/*
 * Predicate that returns false for all services, except those passed as argument.
 */
template<typename First, typename... Ts>
struct AnyOf {
	constexpr bool operator()(type_id_t id) const noexcept {
		return compare<First, Ts...>(id);
	}

private:
	template<typename Compared, typename Second, typename... Rest>
	constexpr bool compare(type_id_t id) const noexcept {
		return id == type_id<Compared>() && compare<Second, Rest...>(id);
	}

	template<typename Compared>
	constexpr bool compare(type_id_t id) const noexcept {
		return id == type_id<Compared>();
	}
};

} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_PREDICATE_HPP
<|endoftext|>


<commit_before>// Copyright 2016-2021 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef MPPP_DETAIL_UTILS_HPP
#define MPPP_DETAIL_UTILS_HPP

#include <cassert>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>

#include <mp++/config.hpp>
#include <mp++/detail/type_traits.hpp>
#include <mp++/detail/visibility.hpp>
#include <mp++/type_name.hpp>

namespace mppp
{

namespace detail
{

#if defined(_MSC_VER)

// Disable some warnings for MSVC.
#pragma warning(push)
#pragma warning(disable : 4146)

#endif

// These are overloads useful to treat in a generic way mppp classes and standard numeric types.

// Sign function for integral types.
template <typename T, enable_if_t<is_integral<T>::value, int> = 0>
constexpr int sgn(const T &n)
{
    return n ? (n > T(0) ? 1 : -1) : 0;
}

// Zero detection for integral types.
template <typename T, enable_if_t<is_integral<T>::value, int> = 0>
constexpr bool is_zero(const T &n)
{
    return n == T(0);
}

// Small helper to convert the non-negative signed integer n
// into its unsigned counterpart.
template <typename T>
constexpr make_unsigned_t<T> make_unsigned(T n) noexcept
{
    static_assert(is_integral<T>::value && is_signed<T>::value, "Invalid type.");
#if MPPP_CPLUSPLUS >= 201703L
    // LCOV_EXCL_START
    assert(n >= T(0));
    // LCOV_EXCL_STOP
#endif
    return static_cast<make_unsigned_t<T>>(n);
}

// Generic string conversion utility - will use std::to_string() for arithmetic types,
// x.to_string() otherwise.
template <typename T, enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline std::string to_string(const T &x)
{
    return std::to_string(x);
}

template <typename T, enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
inline std::string to_string(const T &x)
{
    return x.to_string();
}

#if defined(MPPP_HAVE_GCC_INT128)

MPPP_DLL_PUBLIC std::string to_string(__uint128_t);
MPPP_DLL_PUBLIC std::string to_string(__int128_t);

#endif

// Compute the absolute value of a negative integer, returning the result as an instance
// of the corresponding unsigned type. Requires T to be a signed integral type and n
// to be negative.
// NOTE: here we are using cast to unsigned + unary minus to extract the abs value of a signed negative
// integral. See:
// http://stackoverflow.com/questions/4536095/unary-minus-and-signed-to-unsigned-conversion
// This technique is not 100% portable in C++ < 20: it requires an implementation
// of signed integers such that the absolute value of the minimum (negative) value is not greater than
// the maximum value of the unsigned counterpart. This is guaranteed on all computer architectures in use today,
// but in theory there could be architectures where the assumption is not respected. See for instance the
// discussion here:
// http://stackoverflow.com/questions/11372044/unsigned-vs-signed-range-guarantees
// Note that in any case we never run into UB, the only consequence is that for very large negative values
// we could init the integer with the wrong value, and we should be able to detect this in the unit tests.
// Let's keep this in mind in the remote case this ever becomes a problem.
// Since C++20, integers are guaranteed to be represented via two's complement, and thus
// this function is portable.
template <typename T>
constexpr make_unsigned_t<T> nint_abs(T n) noexcept
{
    // NOTE: we should assert about negative n, but this is guaranteed to work properly in
    // constexpr functions only from C++17:
    // https://stackoverflow.com/questions/26072709/alternative-to-asserts-for-constexpr-functions
#if MPPP_CPLUSPLUS >= 201703L
    // LCOV_EXCL_START
    assert(n < T(0));
    // LCOV_EXCL_STOP
#endif
    static_assert(is_integral<T>::value && is_signed<T>::value,
                  "The sint_abs() function can be used only with signed integral types.");
    using uT = make_unsigned_t<T>;
    // NOTE: the potential cast to "unsigned", rather than uT, is for when uT is a short integral type.
    // In such a case, the unary minus will trigger integral promotion to int/unsigned
    // int, and I am *not* 100% sure in this case the technique still works. Written like this, the cast
    // is never to a type narrower than "unsigned".
    return static_cast<uT>(
        -static_cast<typename std::conditional<(nl_max<uT>() <= nl_max<unsigned>()), unsigned, uT>::type>(n));
}

// constexpr max/min implementations with copy semantics.
template <typename T>
constexpr T c_max(T a, T b) noexcept
{
    return a > b ? a : b;
}

template <typename T>
constexpr T c_min(T a, T b) noexcept
{
    return a < b ? a : b;
}

// A small helper to convert the input unsigned n to -n, represented as the signed T.
template <typename T, typename U>
// NOTE: C++17 because we are using assert().
#if MPPP_CPLUSPLUS >= 201703L
constexpr
#else
inline
#endif
    std::pair<bool, T>
    unsigned_to_nsigned(U n)
{
    static_assert(is_integral<T>::value && is_signed<T>::value, "Invalid type.");
    static_assert(is_integral<U>::value && is_unsigned<U>::value, "Invalid type.");
    // Cache a couple of quantities.
    constexpr auto Tmax = make_unsigned(nl_max<T>());
    constexpr auto Tmin_abs = nint_abs(nl_min<T>());
    if (mppp_likely(n <= c_min(Tmax, Tmin_abs))) {
        // Optimise the case in which n fits both Tmax and Tmin_abs. This means
        // we can convert and negate safely.
        return std::make_pair(true, static_cast<T>(-static_cast<T>(n)));
    }
    // n needs to fit within the abs of min().
    if (n > Tmin_abs) {
        return std::make_pair(false, T(0));
    }
    // LCOV_EXCL_START
    if (Tmin_abs <= Tmax) {
        // The negative range of T is leq than the positive one: we can convert to T and negate safely.
        // NOTE: this is never hit on current architectures.
        return std::make_pair(true, static_cast<T>(-static_cast<T>(n)));
    }
    // LCOV_EXCL_STOP
    // NOTE: double check this, since:
    // - Tmin_abs > Tmax (as checked just above),
    // - n > c_min(Tmax, Tmin_abs) (as checked earlier).
    assert(n > Tmax);
    // The negative range is greater than the positive one and n larger than Tmax:
    // we cannot directly convert n to T. The idea then is to init retval to -Tmax
    // and then to subtract from it Tmax as many times as needed.
    auto retval = static_cast<T>(-static_cast<T>(Tmax));
    const auto q = static_cast<U>(n / Tmax), r = static_cast<U>(n % Tmax);
    for (U i = 0; i < q - 1u; ++i) {
        // LCOV_EXCL_START
        // NOTE: this is never hit on current archs, as Tmax differs from Tmin_abs
        // by just 1: we will use only the remainder r.
        retval = static_cast<T>(retval - static_cast<T>(Tmax));
        // LCOV_EXCL_STOP
    }
    retval = static_cast<T>(retval - static_cast<T>(r));
    return std::make_pair(true, retval);
}

// Like above, but throw on failure.
template <typename T, typename U>
#if MPPP_CPLUSPLUS >= 201703L
constexpr
#else
inline
#endif
    T
    negate_unsigned(U n)
{
    const auto retval = unsigned_to_nsigned<T>(n);
    // LCOV_EXCL_START
    return retval.first ? retval.second
                        : throw std::overflow_error(
                            "Error while trying to negate the unsigned integral value " + to_string(n)
                            + ": the result does not fit in the range of the target type '" + type_name<T>() + "'");
    // LCOV_EXCL_STOP
}

// Safe casting functionality between integral types. It will throw if the conversion overflows the range
// of the target type T.
template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_unsigned<T>, is_unsigned<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return n <= nl_max<T>()
               ? static_cast<T>(n)
               : throw std::overflow_error(
                   "Error in the safe conversion between unsigned integral types: the input value " + to_string(n)
                   + " does not fit in the range of the target type '" + type_name<T>() + "'");
}

template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_signed<T>, is_signed<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return (n <= nl_max<T>() && n >= nl_min<T>())
               ? static_cast<T>(n)
               : throw std::overflow_error(
                   "Error in the safe conversion between signed integral types: the input value " + to_string(n)
                   + " does not fit in the range of the target type '" + type_name<T>() + "'");
}

template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_unsigned<T>, is_signed<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return (n >= U(0) && make_unsigned(n) <= nl_max<T>())
               ? static_cast<T>(n)
               : throw std::overflow_error("Error in the safe conversion from a signed integral type to an unsigned "
                                           "integral type: the input value "
                                           + to_string(n) + " does not fit in the range of the target type '"
                                           + type_name<T>() + "'");
}

template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_signed<T>, is_unsigned<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return n <= make_unsigned(nl_max<T>())
               ? static_cast<T>(n)
               : throw std::overflow_error("Error in the safe conversion from an unsigned integral type to a signed "
                                           "integral type: the input value "
                                           + to_string(n) + " does not fit in the range of the target type '"
                                           + type_name<T>() + "'");
}

// Helper to ignore unused variables.
// NOTE: the return type has to be int, rather than void, for compatibility
// with C++11 constexpr.
template <typename... Args>
constexpr int ignore(Args &&...)
{
    return 0;
}

// Given an input unsigned integer n, this function will return
// a signed integer whose absolute value is n and whose sign is
// s (following the usual convention: s = 0 means zero,
// s = 1 means positive, s = -1 means negative).
// No overflow check is performed: if the value of the result
// does not fit in the return type, the behaviour will be undefined.
template <typename T>
inline make_signed_t<T> make_signed(const T &n, int s)
{
    static_assert(is_unsigned<T>::value, "make_signed() can be invoked only on unsigned integral types.");
    // NOTE: avoid integral promotion bullshit.
    static_assert(std::is_same<T, decltype(n + n)>::value, "make_signed() cannot be used with short integral types.");

    // Consistency checks: s must be one of [0, -1, 1], and, if s is zero,
    // then n must also be zero.
    assert(s == 0 || s == -1 || s == 1);
    assert(s != 0 || n == 0u);

    // NOTE: s_ex will be:
    // - 0 if s is 0 or 1,
    // - the max value representable by T if s is -1 (this is because the
    //   right shift produces the int -1, which is then converted to the
    //   unsigned T).
    // NOTE: the right shift behaviour for signed operands is standardised
    // only since C++20, but in practice it should work everywhere.
    const auto s_ex = static_cast<T>(s >> (std::numeric_limits<int>::digits - 1));

    // (n ^ s_ex) - s_ex returns n if s_ex is 0, -n (still represented
    // as an unsigned) otherwise.
    return static_cast<make_signed_t<T>>((n ^ s_ex) - s_ex);
}

#if defined(_MSC_VER)

#pragma warning(pop)

#endif
} // namespace detail
} // namespace mppp

#endif
<commit_msg>Add a hash combiner.<commit_after>// Copyright 2016-2021 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef MPPP_DETAIL_UTILS_HPP
#define MPPP_DETAIL_UTILS_HPP

#include <cassert>
#include <cstddef>
#include <functional>
#include <limits>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>

#include <mp++/config.hpp>
#include <mp++/detail/type_traits.hpp>
#include <mp++/detail/visibility.hpp>
#include <mp++/type_name.hpp>

namespace mppp
{

namespace detail
{

#if defined(_MSC_VER)

// Disable some warnings for MSVC.
#pragma warning(push)
#pragma warning(disable : 4146)

#endif

// These are overloads useful to treat in a generic way mppp classes and standard numeric types.

// Sign function for integral types.
template <typename T, enable_if_t<is_integral<T>::value, int> = 0>
constexpr int sgn(const T &n)
{
    return n ? (n > T(0) ? 1 : -1) : 0;
}

// Zero detection for integral types.
template <typename T, enable_if_t<is_integral<T>::value, int> = 0>
constexpr bool is_zero(const T &n)
{
    return n == T(0);
}

// Small helper to convert the non-negative signed integer n
// into its unsigned counterpart.
template <typename T>
constexpr make_unsigned_t<T> make_unsigned(T n) noexcept
{
    static_assert(is_integral<T>::value && is_signed<T>::value, "Invalid type.");
#if MPPP_CPLUSPLUS >= 201703L
    // LCOV_EXCL_START
    assert(n >= T(0));
    // LCOV_EXCL_STOP
#endif
    return static_cast<make_unsigned_t<T>>(n);
}

// Generic string conversion utility - will use std::to_string() for arithmetic types,
// x.to_string() otherwise.
template <typename T, enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline std::string to_string(const T &x)
{
    return std::to_string(x);
}

template <typename T, enable_if_t<!std::is_arithmetic<T>::value, int> = 0>
inline std::string to_string(const T &x)
{
    return x.to_string();
}

#if defined(MPPP_HAVE_GCC_INT128)

MPPP_DLL_PUBLIC std::string to_string(__uint128_t);
MPPP_DLL_PUBLIC std::string to_string(__int128_t);

#endif

// Compute the absolute value of a negative integer, returning the result as an instance
// of the corresponding unsigned type. Requires T to be a signed integral type and n
// to be negative.
// NOTE: here we are using cast to unsigned + unary minus to extract the abs value of a signed negative
// integral. See:
// http://stackoverflow.com/questions/4536095/unary-minus-and-signed-to-unsigned-conversion
// This technique is not 100% portable in C++ < 20: it requires an implementation
// of signed integers such that the absolute value of the minimum (negative) value is not greater than
// the maximum value of the unsigned counterpart. This is guaranteed on all computer architectures in use today,
// but in theory there could be architectures where the assumption is not respected. See for instance the
// discussion here:
// http://stackoverflow.com/questions/11372044/unsigned-vs-signed-range-guarantees
// Note that in any case we never run into UB, the only consequence is that for very large negative values
// we could init the integer with the wrong value, and we should be able to detect this in the unit tests.
// Let's keep this in mind in the remote case this ever becomes a problem.
// Since C++20, integers are guaranteed to be represented via two's complement, and thus
// this function is portable.
template <typename T>
constexpr make_unsigned_t<T> nint_abs(T n) noexcept
{
    // NOTE: we should assert about negative n, but this is guaranteed to work properly in
    // constexpr functions only from C++17:
    // https://stackoverflow.com/questions/26072709/alternative-to-asserts-for-constexpr-functions
#if MPPP_CPLUSPLUS >= 201703L
    // LCOV_EXCL_START
    assert(n < T(0));
    // LCOV_EXCL_STOP
#endif
    static_assert(is_integral<T>::value && is_signed<T>::value,
                  "The sint_abs() function can be used only with signed integral types.");
    using uT = make_unsigned_t<T>;
    // NOTE: the potential cast to "unsigned", rather than uT, is for when uT is a short integral type.
    // In such a case, the unary minus will trigger integral promotion to int/unsigned
    // int, and I am *not* 100% sure in this case the technique still works. Written like this, the cast
    // is never to a type narrower than "unsigned".
    return static_cast<uT>(
        -static_cast<typename std::conditional<(nl_max<uT>() <= nl_max<unsigned>()), unsigned, uT>::type>(n));
}

// constexpr max/min implementations with copy semantics.
template <typename T>
constexpr T c_max(T a, T b) noexcept
{
    return a > b ? a : b;
}

template <typename T>
constexpr T c_min(T a, T b) noexcept
{
    return a < b ? a : b;
}

// A small helper to convert the input unsigned n to -n, represented as the signed T.
template <typename T, typename U>
// NOTE: C++17 because we are using assert().
#if MPPP_CPLUSPLUS >= 201703L
constexpr
#else
inline
#endif
    std::pair<bool, T>
    unsigned_to_nsigned(U n)
{
    static_assert(is_integral<T>::value && is_signed<T>::value, "Invalid type.");
    static_assert(is_integral<U>::value && is_unsigned<U>::value, "Invalid type.");
    // Cache a couple of quantities.
    constexpr auto Tmax = make_unsigned(nl_max<T>());
    constexpr auto Tmin_abs = nint_abs(nl_min<T>());
    if (mppp_likely(n <= c_min(Tmax, Tmin_abs))) {
        // Optimise the case in which n fits both Tmax and Tmin_abs. This means
        // we can convert and negate safely.
        return std::make_pair(true, static_cast<T>(-static_cast<T>(n)));
    }
    // n needs to fit within the abs of min().
    if (n > Tmin_abs) {
        return std::make_pair(false, T(0));
    }
    // LCOV_EXCL_START
    if (Tmin_abs <= Tmax) {
        // The negative range of T is leq than the positive one: we can convert to T and negate safely.
        // NOTE: this is never hit on current architectures.
        return std::make_pair(true, static_cast<T>(-static_cast<T>(n)));
    }
    // LCOV_EXCL_STOP
    // NOTE: double check this, since:
    // - Tmin_abs > Tmax (as checked just above),
    // - n > c_min(Tmax, Tmin_abs) (as checked earlier).
    assert(n > Tmax);
    // The negative range is greater than the positive one and n larger than Tmax:
    // we cannot directly convert n to T. The idea then is to init retval to -Tmax
    // and then to subtract from it Tmax as many times as needed.
    auto retval = static_cast<T>(-static_cast<T>(Tmax));
    const auto q = static_cast<U>(n / Tmax), r = static_cast<U>(n % Tmax);
    for (U i = 0; i < q - 1u; ++i) {
        // LCOV_EXCL_START
        // NOTE: this is never hit on current archs, as Tmax differs from Tmin_abs
        // by just 1: we will use only the remainder r.
        retval = static_cast<T>(retval - static_cast<T>(Tmax));
        // LCOV_EXCL_STOP
    }
    retval = static_cast<T>(retval - static_cast<T>(r));
    return std::make_pair(true, retval);
}

// Like above, but throw on failure.
template <typename T, typename U>
#if MPPP_CPLUSPLUS >= 201703L
constexpr
#else
inline
#endif
    T
    negate_unsigned(U n)
{
    const auto retval = unsigned_to_nsigned<T>(n);
    // LCOV_EXCL_START
    return retval.first ? retval.second
                        : throw std::overflow_error(
                            "Error while trying to negate the unsigned integral value " + to_string(n)
                            + ": the result does not fit in the range of the target type '" + type_name<T>() + "'");
    // LCOV_EXCL_STOP
}

// Safe casting functionality between integral types. It will throw if the conversion overflows the range
// of the target type T.
template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_unsigned<T>, is_unsigned<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return n <= nl_max<T>()
               ? static_cast<T>(n)
               : throw std::overflow_error(
                   "Error in the safe conversion between unsigned integral types: the input value " + to_string(n)
                   + " does not fit in the range of the target type '" + type_name<T>() + "'");
}

template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_signed<T>, is_signed<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return (n <= nl_max<T>() && n >= nl_min<T>())
               ? static_cast<T>(n)
               : throw std::overflow_error(
                   "Error in the safe conversion between signed integral types: the input value " + to_string(n)
                   + " does not fit in the range of the target type '" + type_name<T>() + "'");
}

template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_unsigned<T>, is_signed<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return (n >= U(0) && make_unsigned(n) <= nl_max<T>())
               ? static_cast<T>(n)
               : throw std::overflow_error("Error in the safe conversion from a signed integral type to an unsigned "
                                           "integral type: the input value "
                                           + to_string(n) + " does not fit in the range of the target type '"
                                           + type_name<T>() + "'");
}

template <typename T, typename U,
          enable_if_t<conjunction<is_integral<T>, is_integral<U>, is_signed<T>, is_unsigned<U>>::value, int> = 0>
constexpr T safe_cast(const U &n)
{
    return n <= make_unsigned(nl_max<T>())
               ? static_cast<T>(n)
               : throw std::overflow_error("Error in the safe conversion from an unsigned integral type to a signed "
                                           "integral type: the input value "
                                           + to_string(n) + " does not fit in the range of the target type '"
                                           + type_name<T>() + "'");
}

// Helper to ignore unused variables.
// NOTE: the return type has to be int, rather than void, for compatibility
// with C++11 constexpr.
template <typename... Args>
constexpr int ignore(Args &&...)
{
    return 0;
}

// Given an input unsigned integer n, this function will return
// a signed integer whose absolute value is n and whose sign is
// s (following the usual convention: s = 0 means zero,
// s = 1 means positive, s = -1 means negative).
// No overflow check is performed: if the value of the result
// does not fit in the return type, the behaviour will be undefined.
template <typename T>
inline make_signed_t<T> make_signed(const T &n, int s)
{
    static_assert(is_unsigned<T>::value, "make_signed() can be invoked only on unsigned integral types.");
    // NOTE: avoid integral promotion bullshit.
    static_assert(std::is_same<T, decltype(n + n)>::value, "make_signed() cannot be used with short integral types.");

    // Consistency checks: s must be one of [0, -1, 1], and, if s is zero,
    // then n must also be zero.
    assert(s == 0 || s == -1 || s == 1);
    assert(s != 0 || n == 0u);

    // NOTE: s_ex will be:
    // - 0 if s is 0 or 1,
    // - the max value representable by T if s is -1 (this is because the
    //   right shift produces the int -1, which is then converted to the
    //   unsigned T).
    // NOTE: the right shift behaviour for signed operands is standardised
    // only since C++20, but in practice it should work everywhere.
    const auto s_ex = static_cast<T>(s >> (std::numeric_limits<int>::digits - 1));

    // (n ^ s_ex) - s_ex returns n if s_ex is 0, -n (still represented
    // as an unsigned) otherwise.
    return static_cast<make_signed_t<T>>((n ^ s_ex) - s_ex);
}

// The hash combiner. This is lifted directly from Boost. See also:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
template <typename T>
inline void hash_combine(std::size_t &seed, const T &val)
{
    seed ^= std::hash<T>{}(val) + static_cast<std::size_t>(0x9e3779b9ull) + (seed << 6) + (seed >> 2);
}

#if defined(_MSC_VER)

#pragma warning(pop)

#endif
} // namespace detail
} // namespace mppp

#endif
<|endoftext|>


<commit_before><commit_msg>print error when loading<commit_after><|endoftext|>


<commit_before>#line 2 "togo/game/resource/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Resource types.
@ingroup lib_game_types
@ingroup lib_game_resource
*/

#pragma once

#include <togo/game/config.hpp>
#include <togo/core/types.hpp>
#include <togo/core/utility/traits.hpp>
#include <togo/core/memory/types.hpp>
#include <togo/core/collection/types.hpp>
#include <togo/core/string/types.hpp>
#include <togo/core/hash/types.hpp>
#include <togo/core/hash/hash.hpp>
#include <togo/core/io/types.hpp>
#include <togo/core/io/file_stream.hpp>

namespace togo {

/**
	@addtogroup lib_game_resource
	@{
*/

/// Format versions.
enum : u32 {
	/// ResourcePackage manifest format version.
	SER_FORMAT_VERSION_PKG_MANIFEST = 3,
};

/// Resource type.
using ResourceType = hash32;

/// Resource name hash.
using ResourceNameHash = hash64;

/// Combined resource tags hash.
using ResourceTagsHash = hash64;

/// Combined resource tags hash combiner.
using ResourceTagsHashCombiner = HashCombiner64;

/// Package name hash.
using ResourcePackageNameHash = hash32;

/** @cond INTERNAL */
static_assert(
	is_same<ResourceType, hash32>::value,
	"changed ResourceType type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceNameHash, hash64>::value,
	"changed ResourceNameHash type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceTagsHash, hash64>::value,
	"changed ResourceTagsHash type breaks binary formats,"
	" hash functions, and likely other things"
);
/** @endcond */ // INTERNAL

/// Resource type hash literal.
inline constexpr ResourceType
operator"" _resource_type(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource name hash literal.
inline constexpr ResourceNameHash
operator"" _resource_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Combined resource tags hash literal.
///
/// Note that this only takes a single string. Tags should be sorted
/// and separator-less for the return value of this literal to be
/// compatible with the runtime combiner-based hash function.
inline constexpr ResourceTagsHash
operator"" _resource_tags(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Package name hash literal.
inline constexpr ResourcePackageNameHash
operator"" _resource_package_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource types.
enum : ResourceType {
	/// Non-type.
	RES_TYPE_NULL = ""_resource_type,

	/// TestResource.
	RES_TYPE_TEST = "test"_resource_type,

	/// gfx::ShaderDef.
	RES_TYPE_SHADER_PRELUDE = "shader_prelude"_resource_type,

	/// gfx::ShaderID.
	RES_TYPE_SHADER = "shader"_resource_type,

	/// gfx::RenderConfig.
	RES_TYPE_RENDER_CONFIG = "render_config"_resource_type,
};

/// Resource names.
enum : ResourceNameHash {
	/// Null name.
	RES_NAME_NULL = ""_resource_name,

	/// Shared shader configuration shader_prelude.
	RES_NAME_SHADER_CONFIG = "togo/game/gfx/shader-config"_resource_name,
};

/// Combined resource tags.
enum : ResourceTagsHash {
	/// Null tags.
	RES_TAGS_NULL = ""_resource_tags,
};

/// Resource package names.
enum : ResourcePackageNameHash {
	/// Null name.
	PKG_NAME_NULL = ""_resource_package_name,
};

/// Resource path parts.
struct ResourcePathParts {
	struct Tag {
		StringRef name{};
		hash32 hash;
	};

	ResourceType type_hash;
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	StringRef type{};
	StringRef name{};
	FixedArray<Tag, 8> tags;
};

/// Path to compiled resource.
struct ResourceCompiledPath {
	u32 id;
	FixedArray<char, 24> _data{};

	~ResourceCompiledPath() = default;

	ResourceCompiledPath(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath(ResourceCompiledPath&&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath&&) = delete;

	ResourceCompiledPath();

	operator StringRef() const;

	u32 size() const;
	char const* data() const;
};

/// Resource metadata.
struct ResourceMetadata {
	u32 id;

	// Serial
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	ResourceType type;
	u32 data_format_version;
	u32 data_offset;
	u32 data_size;
};

/// Resource value.
union ResourceValue {
	void* pointer;
	u32 uinteger;

	~ResourceValue() = default;
	ResourceValue() = default;
	ResourceValue(ResourceValue const&) = default;
	ResourceValue(ResourceValue&&) = default;
	ResourceValue& operator=(ResourceValue const&) = default;
	ResourceValue& operator=(ResourceValue&&) = default;

	/// Construct with pointer.
	ResourceValue(void* const pointer) : pointer(pointer) {}

	/// Construct with 32-bit unsigned integer.
	ResourceValue(u32 const uinteger) : uinteger(uinteger) {}

	/// Whether pointer is valid.
	bool valid() const {
		return pointer != nullptr;
	}
};

/// Test resource.
struct TestResource {
	s64 x;
};

// Forward declarations
struct ResourceHandler;
struct ResourcePackage;
struct ResourceManager;

/// Resource stream lock.
///
/// This class opens a resource stream from a package on
/// initialization and closes it on deinitialization.
struct ResourceStreamLock {
	ResourcePackage& _package;
	IReader* _stream;

	ResourceStreamLock() = delete;
	ResourceStreamLock(ResourceStreamLock const&) = delete;
	ResourceStreamLock(ResourceStreamLock&&) = delete;
	ResourceStreamLock& operator=(ResourceStreamLock const&) = delete;
	ResourceStreamLock& operator=(ResourceStreamLock&&) = delete;

	/// Close resource stream.
	~ResourceStreamLock();

	/// Open resource stream.
	ResourceStreamLock(
		ResourcePackage& package,
		u32 id
	);

	/// Resource stream.
	IReader& stream();
};

/**
	@addtogroup lib_game_resource_handler
	@{
*/

/// Resource handler.
struct ResourceHandler {
	/// Load a resource.
	///
	/// Returns pointer to resource, or nullptr on error.
	using load_func_type = ResourceValue (
		void* const type_data,
		ResourceManager& manager,
		ResourcePackage& package,
		ResourceMetadata const& metadata
	);

	/// Unload a resource.
	using unload_func_type = void (
		void* const type_data,
		ResourceManager& manager,
		ResourceValue const resource
	);

	ResourceType type;
	u32 format_version;
	void* type_data;
	load_func_type* func_load;
	unload_func_type* func_unload;
};

/** @} */ // end of doc-group lib_game_resource_handler

/**
	@addtogroup lib_game_resource_package
	@{
*/

/// Resource package.
struct ResourcePackage {
	using LookupNode = HashMapNode<ResourceNameHash, u32>;

	ResourcePackageNameHash _name_hash;
	u32 _open_resource_id;
	FileReader _stream;
	HashMap<ResourceNameHash, u32> _lookup;
	Array<ResourceMetadata> _manifest;
	FixedArray<char, 48> _name;
	FixedArray<char, 256> _path;

	ResourcePackage() = delete;
	ResourcePackage(ResourcePackage const&) = delete;
	ResourcePackage(ResourcePackage&&) = delete;
	ResourcePackage& operator=(ResourcePackage const&) = delete;
	ResourcePackage& operator=(ResourcePackage&&) = delete;

	~ResourcePackage() = default;

	ResourcePackage(
		StringRef const& name,
		StringRef const& path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group lib_game_resource_package

/**
	@addtogroup lib_game_resource_manager
	@{
*/

/// Resource manager.
struct ResourceManager {
	struct TypedResourceValue {
		ResourceValue value;
		ResourceType type;
	};

	using ActiveNode = HashMapNode<ResourceNameHash, TypedResourceValue>;

	HashMap<ResourceType, ResourceHandler> _handlers;
	HashMap<ResourceNameHash, TypedResourceValue> _resources;
	Array<ResourcePackage*> _packages;
	FixedArray<char, 128> _base_path;

	ResourceManager() = delete;
	ResourceManager(ResourceManager const&) = delete;
	ResourceManager(ResourceManager&&) = delete;
	ResourceManager& operator=(ResourceManager const&) = delete;
	ResourceManager& operator=(ResourceManager&&) = delete;

	~ResourceManager();
	ResourceManager(
		StringRef const base_path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group lib_game_resource_manager

/** @} */ // end of doc-group lib_game_resource

} // namespace togo
<commit_msg>lib/game/resource: corrected RES_NAME_SHADER_CONFIG.¹<commit_after>#line 2 "togo/game/resource/types.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Resource types.
@ingroup lib_game_types
@ingroup lib_game_resource
*/

#pragma once

#include <togo/game/config.hpp>
#include <togo/core/types.hpp>
#include <togo/core/utility/traits.hpp>
#include <togo/core/memory/types.hpp>
#include <togo/core/collection/types.hpp>
#include <togo/core/string/types.hpp>
#include <togo/core/hash/types.hpp>
#include <togo/core/hash/hash.hpp>
#include <togo/core/io/types.hpp>
#include <togo/core/io/file_stream.hpp>

namespace togo {

/**
	@addtogroup lib_game_resource
	@{
*/

/// Format versions.
enum : u32 {
	/// ResourcePackage manifest format version.
	SER_FORMAT_VERSION_PKG_MANIFEST = 3,
};

/// Resource type.
using ResourceType = hash32;

/// Resource name hash.
using ResourceNameHash = hash64;

/// Combined resource tags hash.
using ResourceTagsHash = hash64;

/// Combined resource tags hash combiner.
using ResourceTagsHashCombiner = HashCombiner64;

/// Package name hash.
using ResourcePackageNameHash = hash32;

/** @cond INTERNAL */
static_assert(
	is_same<ResourceType, hash32>::value,
	"changed ResourceType type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceNameHash, hash64>::value,
	"changed ResourceNameHash type breaks binary formats,"
	" hash functions, and likely other things"
);
static_assert(
	is_same<ResourceTagsHash, hash64>::value,
	"changed ResourceTagsHash type breaks binary formats,"
	" hash functions, and likely other things"
);
/** @endcond */ // INTERNAL

/// Resource type hash literal.
inline constexpr ResourceType
operator"" _resource_type(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource name hash literal.
inline constexpr ResourceNameHash
operator"" _resource_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Combined resource tags hash literal.
///
/// Note that this only takes a single string. Tags should be sorted
/// and separator-less for the return value of this literal to be
/// compatible with the runtime combiner-based hash function.
inline constexpr ResourceTagsHash
operator"" _resource_tags(
	char const* const data,
	std::size_t const size
) {
	return hash::calc64_ce(data, size);
}

/// Package name hash literal.
inline constexpr ResourcePackageNameHash
operator"" _resource_package_name(
	char const* const data,
	std::size_t const size
) {
	return hash::calc32_ce(data, size);
}

/// Resource types.
enum : ResourceType {
	/// Non-type.
	RES_TYPE_NULL = ""_resource_type,

	/// TestResource.
	RES_TYPE_TEST = "test"_resource_type,

	/// gfx::ShaderDef.
	RES_TYPE_SHADER_PRELUDE = "shader_prelude"_resource_type,

	/// gfx::ShaderID.
	RES_TYPE_SHADER = "shader"_resource_type,

	/// gfx::RenderConfig.
	RES_TYPE_RENDER_CONFIG = "render_config"_resource_type,
};

/// Resource names.
enum : ResourceNameHash {
	/// Null name.
	RES_NAME_NULL = ""_resource_name,

	/// Shared shader configuration shader_prelude.
	RES_NAME_SHADER_CONFIG = "togo/gfx/shader-config"_resource_name,
};

/// Combined resource tags.
enum : ResourceTagsHash {
	/// Null tags.
	RES_TAGS_NULL = ""_resource_tags,
};

/// Resource package names.
enum : ResourcePackageNameHash {
	/// Null name.
	PKG_NAME_NULL = ""_resource_package_name,
};

/// Resource path parts.
struct ResourcePathParts {
	struct Tag {
		StringRef name{};
		hash32 hash;
	};

	ResourceType type_hash;
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	StringRef type{};
	StringRef name{};
	FixedArray<Tag, 8> tags;
};

/// Path to compiled resource.
struct ResourceCompiledPath {
	u32 id;
	FixedArray<char, 24> _data{};

	~ResourceCompiledPath() = default;

	ResourceCompiledPath(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath(ResourceCompiledPath&&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath const&) = delete;
	ResourceCompiledPath& operator=(ResourceCompiledPath&&) = delete;

	ResourceCompiledPath();

	operator StringRef() const;

	u32 size() const;
	char const* data() const;
};

/// Resource metadata.
struct ResourceMetadata {
	u32 id;

	// Serial
	ResourceNameHash name_hash;
	ResourceTagsHash tags_hash;
	ResourceType type;
	u32 data_format_version;
	u32 data_offset;
	u32 data_size;
};

/// Resource value.
union ResourceValue {
	void* pointer;
	u32 uinteger;

	~ResourceValue() = default;
	ResourceValue() = default;
	ResourceValue(ResourceValue const&) = default;
	ResourceValue(ResourceValue&&) = default;
	ResourceValue& operator=(ResourceValue const&) = default;
	ResourceValue& operator=(ResourceValue&&) = default;

	/// Construct with pointer.
	ResourceValue(void* const pointer) : pointer(pointer) {}

	/// Construct with 32-bit unsigned integer.
	ResourceValue(u32 const uinteger) : uinteger(uinteger) {}

	/// Whether pointer is valid.
	bool valid() const {
		return pointer != nullptr;
	}
};

/// Test resource.
struct TestResource {
	s64 x;
};

// Forward declarations
struct ResourceHandler;
struct ResourcePackage;
struct ResourceManager;

/// Resource stream lock.
///
/// This class opens a resource stream from a package on
/// initialization and closes it on deinitialization.
struct ResourceStreamLock {
	ResourcePackage& _package;
	IReader* _stream;

	ResourceStreamLock() = delete;
	ResourceStreamLock(ResourceStreamLock const&) = delete;
	ResourceStreamLock(ResourceStreamLock&&) = delete;
	ResourceStreamLock& operator=(ResourceStreamLock const&) = delete;
	ResourceStreamLock& operator=(ResourceStreamLock&&) = delete;

	/// Close resource stream.
	~ResourceStreamLock();

	/// Open resource stream.
	ResourceStreamLock(
		ResourcePackage& package,
		u32 id
	);

	/// Resource stream.
	IReader& stream();
};

/**
	@addtogroup lib_game_resource_handler
	@{
*/

/// Resource handler.
struct ResourceHandler {
	/// Load a resource.
	///
	/// Returns pointer to resource, or nullptr on error.
	using load_func_type = ResourceValue (
		void* const type_data,
		ResourceManager& manager,
		ResourcePackage& package,
		ResourceMetadata const& metadata
	);

	/// Unload a resource.
	using unload_func_type = void (
		void* const type_data,
		ResourceManager& manager,
		ResourceValue const resource
	);

	ResourceType type;
	u32 format_version;
	void* type_data;
	load_func_type* func_load;
	unload_func_type* func_unload;
};

/** @} */ // end of doc-group lib_game_resource_handler

/**
	@addtogroup lib_game_resource_package
	@{
*/

/// Resource package.
struct ResourcePackage {
	using LookupNode = HashMapNode<ResourceNameHash, u32>;

	ResourcePackageNameHash _name_hash;
	u32 _open_resource_id;
	FileReader _stream;
	HashMap<ResourceNameHash, u32> _lookup;
	Array<ResourceMetadata> _manifest;
	FixedArray<char, 48> _name;
	FixedArray<char, 256> _path;

	ResourcePackage() = delete;
	ResourcePackage(ResourcePackage const&) = delete;
	ResourcePackage(ResourcePackage&&) = delete;
	ResourcePackage& operator=(ResourcePackage const&) = delete;
	ResourcePackage& operator=(ResourcePackage&&) = delete;

	~ResourcePackage() = default;

	ResourcePackage(
		StringRef const& name,
		StringRef const& path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group lib_game_resource_package

/**
	@addtogroup lib_game_resource_manager
	@{
*/

/// Resource manager.
struct ResourceManager {
	struct TypedResourceValue {
		ResourceValue value;
		ResourceType type;
	};

	using ActiveNode = HashMapNode<ResourceNameHash, TypedResourceValue>;

	HashMap<ResourceType, ResourceHandler> _handlers;
	HashMap<ResourceNameHash, TypedResourceValue> _resources;
	Array<ResourcePackage*> _packages;
	FixedArray<char, 128> _base_path;

	ResourceManager() = delete;
	ResourceManager(ResourceManager const&) = delete;
	ResourceManager(ResourceManager&&) = delete;
	ResourceManager& operator=(ResourceManager const&) = delete;
	ResourceManager& operator=(ResourceManager&&) = delete;

	~ResourceManager();
	ResourceManager(
		StringRef const base_path,
		Allocator& allocator
	);
};

/** @} */ // end of doc-group lib_game_resource_manager

/** @} */ // end of doc-group lib_game_resource

} // namespace togo
<|endoftext|>


<commit_before>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

// implementation wrapers for all the bza_ API functions
#include "bzfsAPI.h"

#include "common.h"
#include "bzfs.h"
#include "WorldWeapons.h"
#include "WorldEventManager.h"
#include "GameKeeper.h"
#include "FlagInfo.h"

#include "commands.h"
#include "SpawnPosition.h"
#include "WorldInfo.h"

#include "BzMaterial.h"

TimeKeeper synct = TimeKeeper::getCurrent();

extern void sendMessage(int playerIndex, PlayerId dstPlayer, const char *message);
extern void removePlayer(int playerIndex, const char *reason, bool notify);
extern void zapFlagByPlayer(int playerIndex);

extern CmdLineOptions *clOptions;
extern uint16_t curMaxPlayers;
extern WorldInfo *world;
extern float pluginWorldSize;
extern float pluginWorldHeight;
extern float pluginMaxWait;

// utility
void setBZMatFromAPIMat (BzMaterial &bzmat, bz_MaterialInfo* material )
{
	if (!material)
		return;

	bzmat.setName(material->name);
	bzmat.setAmbient(material->ambient);
	bzmat.setDiffuse(material->diffuse);
	bzmat.setSpecular(material->specular);
	bzmat.setEmission(material->emisive);
	bzmat.setShininess(material->shine);

	bzmat.setNoCulling(!material->culling);
	bzmat.setNoSorting(!material->sorting);
	bzmat.setAlphaThreshold(material->alphaThresh);

	for( unsigned int i = 0; i < material->textures.size();i++ )
	{
		bzmat.addTexture(material->textures[i].texture);
		bzmat.setCombineMode(material->textures[i].combineMode);
		bzmat.setUseTextureAlpha(material->textures[i].useAlpha);
		bzmat.setUseColorOnTexture(material->textures[i].useColorOnTexture);
		bzmat.setUseSphereMap(material->textures[i].useSphereMap);
	}
}

// versioning
BZF_API int bz_APIVersion ( void )
{
	return BZ_API_VERSION;
}

BZF_API bool bz_registerEvent ( bz_teEventType eventType, int team, bz_EventHandler* eventHandler )
{
	if (!eventHandler)
		return false;

	worldEventManager.addEvent((teEventType)eventType,team,(BaseEventHandler*)eventHandler);
	return true;
}

BZF_API bool bz_registerGeneralEvent ( bz_teEventType eventType, bz_EventHandler* eventHandler )
{
	return bz_registerEvent(eventType,-1,eventHandler);
}

BZF_API bool bz_removeEvent ( bz_teEventType eventType, int team, bz_EventHandler* eventHandler )
{
	if (!eventHandler)
		return false;

	worldEventManager.removeEvent((teEventType)eventType,team,(BaseEventHandler*)eventHandler);
	return true;
}

BZF_API bool bz_updatePlayerData ( bz_PlayerRecord *playerRecord )
{
	if (!playerRecord)
		return false;

	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playerRecord->playerID);
	if (!player)
		return false;

	memcpy(playerRecord->pos,player->lastState->pos,sizeof(float)*3);

	playerRecord->rot = player->lastState->azimuth;

	int flagid = player->player.getFlag();
	FlagInfo *flagInfo = FlagInfo::get(flagid);

	playerRecord->currentFlag = flagInfo->flag.type->label();

	std::vector<FlagType*>	flagHistoryList = player->flagHistory.get();

	playerRecord->flagHistory.clear();
	for ( unsigned int i = 0; i < flagHistoryList.size(); i ++)
		playerRecord->flagHistory.push_back(flagHistoryList[i]->label());

	playerRecord->groups.clear();
	playerRecord->groups = player->accessInfo.groups;

	playerRecord->admin = player->accessInfo.isVerified();

	playerRecord->wins = player->score.getWins();
	playerRecord->losses = player->score.getLosses();

	return true;
}

BZF_API bool bz_getPlayerIndexList ( std::vector<int> *playerList )
{
	playerList->clear();

	for (int i = 0; i < curMaxPlayers; i++)
	{
		GameKeeper::Player *p = GameKeeper::Player::getPlayerByIndex(i);
		if ((p == NULL))
			continue;

		playerList->push_back(i);
	}
	return playerList->size() > 0;
}

BZF_API bool bz_getPlayerByIndex ( int index, bz_PlayerRecord *playerRecord )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(index);

	if (!player || !playerRecord)
		return false;

	playerRecord->callsign = player->player.getCallSign();
	playerRecord->playerID = index;
	playerRecord->team = player->player.getTeam();

	playerRecord->spawned = player->player.isAlive();
	playerRecord->verified = player->accessInfo.isVerified();
	playerRecord->globalUser = player->authentication.isGlobal();

	playerRecord->ipAddress = player->netHandler->getTargetIP();
	playerRecord->update();
	return true;
}

BZF_API bool bz_sendTextMessage(int from, int to, const char* message)
{
	if (!message)
		return false;

	int playerIndex;
	PlayerId dstPlayer;

	if (to == BZ_ALL_USERS)
		dstPlayer = AllPlayers;
	else
		dstPlayer = (PlayerId)to;

	if (from == BZ_SERVER)
		playerIndex = ServerPlayer;
	else
		playerIndex = from;

	sendMessage(playerIndex, dstPlayer, message);
	return true;
}

BZF_API bool bz_fireWorldWep ( std::string flagType, float lifetime, int fromPlayer, float *pos, float tilt, float direction, int shotID, float dt )
{
	if (!pos || !flagType.size())
		return false;

	FlagTypeMap &flagMap = FlagType::getFlagMap();
	if (flagMap.find(flagType) == flagMap.end())
		return false;

	FlagType *flag = flagMap.find(flagType)->second;

	PlayerId player;
	if ( fromPlayer == BZ_SERVER )
		player = ServerPlayer;
	else
		player = fromPlayer;

	return fireWorldWep(flag,lifetime,player,pos,tilt,direction,shotID,dt) == shotID;
}

// time API
BZF_API double bz_getCurrentTime ( void )
{
	return TimeKeeper::getCurrent().getSeconds();
}

BZF_API float bz_getMaxWaitTime ( void )
{
	return pluginMaxWait;
}

BZF_API void bz_setMaxWaitTime ( float time )
{
	if ( pluginMaxWait > time)
		pluginMaxWait = time;
}

// info
BZF_API double bz_getBZDBDouble ( const char* variable )
{
	if (!variable)
		return 0.0;

	return BZDB.eval(std::string(variable));
}

BZF_API std::string bz_getBZDString( const char* variable )
{
	if (!variable)
		return std::string("");

	return BZDB.get(std::string(variable));
}

BZF_API bool bz_getBZDBool( const char* variable )
{
	if (!variable)
		return false;

	return BZDB.eval(std::string(variable)) > 0.0;
}

BZF_API int bz_getBZDInt( const char* variable )
{
	return (int)BZDB.eval(std::string(variable));
}

// loging
BZF_API void bz_debugMessage ( int _debugLevel, const char* message )
{
	if (!message)
		return;

	if (debugLevel >= _debugLevel)
		formatDebug("%s\n",message);
}

// admin
BZF_API bool bz_kickUser ( int playerIndex, const char* reason, bool notify )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playerIndex);
	if (!player || !reason)
		return false;

	removePlayer(playerIndex,reason,notify);
	return true;
}

BZF_API bool bz_IPBanUser ( int playerIndex, const char* ip, int time, const char* reason )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playerIndex);
	if (!player || !reason || !ip)
		return false;

	// reload the banlist in case anyone else has added
	clOptions->acl.load();

	if (clOptions->acl.ban(ip, player->player.getCallSign(), time,reason))
		clOptions->acl.save();
	else
		return false;

	return true;
}

BZF_API bool bz_registerCustomSlashCommand ( const char* command, bz_CustomSlashCommandHandler *handler )
{
	if (!command || !handler)
		return false;

	registerCustomSlashCommand(std::string(command),(CustomSlashCommandHandler*)handler);
	return true;
}

BZF_API bool bz_removeCustomSlashCommand ( const char* command )
{
	if (!command)
		return false;

	removeCustomSlashCommand(std::string(command));
	return true;
}

BZF_API bool bz_getStandardSpawn ( int playeID, float pos[3], float *rot )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playeID);
	if (!player)
		return false;

	// get the spawn position
	SpawnPosition* spawnPosition = new SpawnPosition(playeID,
		(!clOptions->respawnOnBuildings) || (player->player.isBot()),
		clOptions->gameStyle & TeamFlagGameStyle);

	pos[0] = spawnPosition->getX();
	pos[1] = spawnPosition->getY();
	pos[2] = spawnPosition->getZ();
	if (rot)
		*rot = spawnPosition->getAzimuth();

	return true;
}

BZF_API bool bz_killPlayer ( int playeID, bool spawnOnBase )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playeID);
	if (!player)
		return false;

	if (!player->player.isAlive())
		return false;

	player->player.setDead();
	player->player.setRestartOnBase(spawnOnBase);
	zapFlagByPlayer(playeID);

	return true;
}

BZF_API bool bz_removePlayerFlag ( int playeID )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playeID);
	if (!player)
		return false;

	if (!player->player.isAlive())
		return false;

	zapFlagByPlayer(playeID);

	return true;
}

BZF_API bool bz_addWorldBox ( float *pos, float rot, float* scale, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addBox(pos[0],pos[1],pos[2],rot,scale[0],scale[1],scale[2],options.driveThru,options.shootThru);
	return true;
}

BZF_API bool bz_addWorldPyramid ( float *pos, float rot, float* scale, bool fliped, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addPyramid(pos[0],pos[1],pos[2],rot,scale[0],scale[1],scale[2],options.driveThru,options.shootThru,fliped);
	return true;
}

BZF_API bool bz_addWorldBase( float *pos, float rot, float* scale, int team, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addBase(pos,rot,scale,team,options.driveThru,options.shootThru);
	return true;
}

BZF_API bool bz_addWorldTeleporter ( float *pos, float rot, float* scale, float border, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addTeleporter(pos[0],pos[1],pos[2],rot,scale[0],scale[1],scale[2],border,false,options.driveThru,options.shootThru);
	return true;
}

BZF_API bool bz_addWorldLink( int from, int to )
{
	if (!world || world->isFinisihed() )
		return false;

	world->addLink(from,to);
	return true;
}

BZF_API bool bz_addWorldWaterLevel( float level, bz_MaterialInfo *material )
{
	if (!world || world->isFinisihed() )
		return false;

	if (!material)
	{
		world->addWaterLevel(level,NULL);
		return true;
	}

	BzMaterial	bzmat;
	setBZMatFromAPIMat(bzmat,material);
	world->addWaterLevel(level,MATERIALMGR.addMaterial(&bzmat));
	return true;
}

BZF_API bool bz_addWorldWeapon( std::string flagType, float *pos, float rot, float tilt, float initDelay, std::vector<float> delays )
{
	if (!world || world->isFinisihed() )
		return false;

	FlagTypeMap &flagMap = FlagType::getFlagMap();
	if (flagMap.find(flagType) == flagMap.end())
		return false;

	FlagType *flag = flagMap.find(flagType)->second;

	world->addWeapon(flag, pos, rot, tilt, initDelay, delays, synct);
	return true;
}

BZF_API bool bz_setWorldSize( float size, float wallHeight )
{
	pluginWorldHeight = wallHeight;
	pluginWorldSize = size;

	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>less crashy<commit_after>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

// implementation wrapers for all the bza_ API functions
#include "bzfsAPI.h"

#include "common.h"
#include "bzfs.h"
#include "WorldWeapons.h"
#include "WorldEventManager.h"
#include "GameKeeper.h"
#include "FlagInfo.h"

#include "commands.h"
#include "SpawnPosition.h"
#include "WorldInfo.h"

#include "BzMaterial.h"

TimeKeeper synct = TimeKeeper::getCurrent();

extern void sendMessage(int playerIndex, PlayerId dstPlayer, const char *message);
extern void removePlayer(int playerIndex, const char *reason, bool notify);
extern void zapFlagByPlayer(int playerIndex);

extern CmdLineOptions *clOptions;
extern uint16_t curMaxPlayers;
extern WorldInfo *world;
extern float pluginWorldSize;
extern float pluginWorldHeight;
extern float pluginMaxWait;

// utility
void setBZMatFromAPIMat (BzMaterial &bzmat, bz_MaterialInfo* material )
{
	if (!material)
		return;

	bzmat.setName(material->name);
	bzmat.setAmbient(material->ambient);
	bzmat.setDiffuse(material->diffuse);
	bzmat.setSpecular(material->specular);
	bzmat.setEmission(material->emisive);
	bzmat.setShininess(material->shine);

	bzmat.setNoCulling(!material->culling);
	bzmat.setNoSorting(!material->sorting);
	bzmat.setAlphaThreshold(material->alphaThresh);

	for( unsigned int i = 0; i < material->textures.size();i++ )
	{
		bzmat.addTexture(material->textures[i].texture);
		bzmat.setCombineMode(material->textures[i].combineMode);
		bzmat.setUseTextureAlpha(material->textures[i].useAlpha);
		bzmat.setUseColorOnTexture(material->textures[i].useColorOnTexture);
		bzmat.setUseSphereMap(material->textures[i].useSphereMap);
	}
}

// versioning
BZF_API int bz_APIVersion ( void )
{
	return BZ_API_VERSION;
}

BZF_API bool bz_registerEvent ( bz_teEventType eventType, int team, bz_EventHandler* eventHandler )
{
	if (!eventHandler)
		return false;

	worldEventManager.addEvent((teEventType)eventType,team,(BaseEventHandler*)eventHandler);
	return true;
}

BZF_API bool bz_registerGeneralEvent ( bz_teEventType eventType, bz_EventHandler* eventHandler )
{
	return bz_registerEvent(eventType,-1,eventHandler);
}

BZF_API bool bz_removeEvent ( bz_teEventType eventType, int team, bz_EventHandler* eventHandler )
{
	if (!eventHandler)
		return false;

	worldEventManager.removeEvent((teEventType)eventType,team,(BaseEventHandler*)eventHandler);
	return true;
}

BZF_API bool bz_updatePlayerData ( bz_PlayerRecord *playerRecord )
{
	if (!playerRecord)
		return false;

	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playerRecord->playerID);
	if (!player)
		return false;

	memcpy(playerRecord->pos,player->lastState->pos,sizeof(float)*3);

	playerRecord->rot = player->lastState->azimuth;

	int flagid = player->player.getFlag();
	FlagInfo *flagInfo = FlagInfo::get(flagid);

	if (flagInfo != NULL)
		playerRecord->currentFlag = flagInfo->flag.type->label();
	else
		playerRecord->currentFlag = std::string("");

	std::vector<FlagType*>	flagHistoryList = player->flagHistory.get();

	playerRecord->flagHistory.clear();
	for ( unsigned int i = 0; i < flagHistoryList.size(); i ++)
		playerRecord->flagHistory.push_back(flagHistoryList[i]->label());

	playerRecord->groups.clear();
	playerRecord->groups = player->accessInfo.groups;

	playerRecord->admin = player->accessInfo.isVerified();

	playerRecord->wins = player->score.getWins();
	playerRecord->losses = player->score.getLosses();

	return true;
}

BZF_API bool bz_getPlayerIndexList ( std::vector<int> *playerList )
{
	playerList->clear();

	for (int i = 0; i < curMaxPlayers; i++)
	{
		GameKeeper::Player *p = GameKeeper::Player::getPlayerByIndex(i);
		if ((p == NULL))
			continue;

		playerList->push_back(i);
	}
	return playerList->size() > 0;
}

BZF_API bool bz_getPlayerByIndex ( int index, bz_PlayerRecord *playerRecord )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(index);

	if (!player || !playerRecord)
		return false;

	playerRecord->callsign = player->player.getCallSign();
	playerRecord->playerID = index;
	playerRecord->team = player->player.getTeam();

	playerRecord->spawned = player->player.isAlive();
	playerRecord->verified = player->accessInfo.isVerified();
	playerRecord->globalUser = player->authentication.isGlobal();

	playerRecord->ipAddress = player->netHandler->getTargetIP();
	playerRecord->update();
	return true;
}

BZF_API bool bz_sendTextMessage(int from, int to, const char* message)
{
	if (!message)
		return false;

	int playerIndex;
	PlayerId dstPlayer;

	if (to == BZ_ALL_USERS)
		dstPlayer = AllPlayers;
	else
		dstPlayer = (PlayerId)to;

	if (from == BZ_SERVER)
		playerIndex = ServerPlayer;
	else
		playerIndex = from;

	sendMessage(playerIndex, dstPlayer, message);
	return true;
}

BZF_API bool bz_fireWorldWep ( std::string flagType, float lifetime, int fromPlayer, float *pos, float tilt, float direction, int shotID, float dt )
{
	if (!pos || !flagType.size())
		return false;

	FlagTypeMap &flagMap = FlagType::getFlagMap();
	if (flagMap.find(flagType) == flagMap.end())
		return false;

	FlagType *flag = flagMap.find(flagType)->second;

	PlayerId player;
	if ( fromPlayer == BZ_SERVER )
		player = ServerPlayer;
	else
		player = fromPlayer;

	return fireWorldWep(flag,lifetime,player,pos,tilt,direction,shotID,dt) == shotID;
}

// time API
BZF_API double bz_getCurrentTime ( void )
{
	return TimeKeeper::getCurrent().getSeconds();
}

BZF_API float bz_getMaxWaitTime ( void )
{
	return pluginMaxWait;
}

BZF_API void bz_setMaxWaitTime ( float time )
{
	if ( pluginMaxWait > time)
		pluginMaxWait = time;
}

// info
BZF_API double bz_getBZDBDouble ( const char* variable )
{
	if (!variable)
		return 0.0;

	return BZDB.eval(std::string(variable));
}

BZF_API std::string bz_getBZDString( const char* variable )
{
	if (!variable)
		return std::string("");

	return BZDB.get(std::string(variable));
}

BZF_API bool bz_getBZDBool( const char* variable )
{
	if (!variable)
		return false;

	return BZDB.eval(std::string(variable)) > 0.0;
}

BZF_API int bz_getBZDInt( const char* variable )
{
	return (int)BZDB.eval(std::string(variable));
}

// loging
BZF_API void bz_debugMessage ( int _debugLevel, const char* message )
{
	if (!message)
		return;

	if (debugLevel >= _debugLevel)
		formatDebug("%s\n",message);
}

// admin
BZF_API bool bz_kickUser ( int playerIndex, const char* reason, bool notify )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playerIndex);
	if (!player || !reason)
		return false;

	removePlayer(playerIndex,reason,notify);
	return true;
}

BZF_API bool bz_IPBanUser ( int playerIndex, const char* ip, int time, const char* reason )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playerIndex);
	if (!player || !reason || !ip)
		return false;

	// reload the banlist in case anyone else has added
	clOptions->acl.load();

	if (clOptions->acl.ban(ip, player->player.getCallSign(), time,reason))
		clOptions->acl.save();
	else
		return false;

	return true;
}

BZF_API bool bz_registerCustomSlashCommand ( const char* command, bz_CustomSlashCommandHandler *handler )
{
	if (!command || !handler)
		return false;

	registerCustomSlashCommand(std::string(command),(CustomSlashCommandHandler*)handler);
	return true;
}

BZF_API bool bz_removeCustomSlashCommand ( const char* command )
{
	if (!command)
		return false;

	removeCustomSlashCommand(std::string(command));
	return true;
}

BZF_API bool bz_getStandardSpawn ( int playeID, float pos[3], float *rot )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playeID);
	if (!player)
		return false;

	// get the spawn position
	SpawnPosition* spawnPosition = new SpawnPosition(playeID,
		(!clOptions->respawnOnBuildings) || (player->player.isBot()),
		clOptions->gameStyle & TeamFlagGameStyle);

	pos[0] = spawnPosition->getX();
	pos[1] = spawnPosition->getY();
	pos[2] = spawnPosition->getZ();
	if (rot)
		*rot = spawnPosition->getAzimuth();

	return true;
}

BZF_API bool bz_killPlayer ( int playeID, bool spawnOnBase )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playeID);
	if (!player)
		return false;

	if (!player->player.isAlive())
		return false;

	player->player.setDead();
	player->player.setRestartOnBase(spawnOnBase);
	zapFlagByPlayer(playeID);

	return true;
}

BZF_API bool bz_removePlayerFlag ( int playeID )
{
	GameKeeper::Player *player = GameKeeper::Player::getPlayerByIndex(playeID);
	if (!player)
		return false;

	if (!player->player.isAlive())
		return false;

	zapFlagByPlayer(playeID);

	return true;
}

BZF_API bool bz_addWorldBox ( float *pos, float rot, float* scale, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addBox(pos[0],pos[1],pos[2],rot,scale[0],scale[1],scale[2],options.driveThru,options.shootThru);
	return true;
}

BZF_API bool bz_addWorldPyramid ( float *pos, float rot, float* scale, bool fliped, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addPyramid(pos[0],pos[1],pos[2],rot,scale[0],scale[1],scale[2],options.driveThru,options.shootThru,fliped);
	return true;
}

BZF_API bool bz_addWorldBase( float *pos, float rot, float* scale, int team, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addBase(pos,rot,scale,team,options.driveThru,options.shootThru);
	return true;
}

BZF_API bool bz_addWorldTeleporter ( float *pos, float rot, float* scale, float border, bz_WorldObjectOptions options )
{
	if (!world || world->isFinisihed() || !pos || !scale)
		return false;

	world->addTeleporter(pos[0],pos[1],pos[2],rot,scale[0],scale[1],scale[2],border,false,options.driveThru,options.shootThru);
	return true;
}

BZF_API bool bz_addWorldLink( int from, int to )
{
	if (!world || world->isFinisihed() )
		return false;

	world->addLink(from,to);
	return true;
}

BZF_API bool bz_addWorldWaterLevel( float level, bz_MaterialInfo *material )
{
	if (!world || world->isFinisihed() )
		return false;

	if (!material)
	{
		world->addWaterLevel(level,NULL);
		return true;
	}

	BzMaterial	bzmat;
	setBZMatFromAPIMat(bzmat,material);
	world->addWaterLevel(level,MATERIALMGR.addMaterial(&bzmat));
	return true;
}

BZF_API bool bz_addWorldWeapon( std::string flagType, float *pos, float rot, float tilt, float initDelay, std::vector<float> delays )
{
	if (!world || world->isFinisihed() )
		return false;

	FlagTypeMap &flagMap = FlagType::getFlagMap();
	if (flagMap.find(flagType) == flagMap.end())
		return false;

	FlagType *flag = flagMap.find(flagType)->second;

	world->addWeapon(flag, pos, rot, tilt, initDelay, delays, synct);
	return true;
}

BZF_API bool bz_setWorldSize( float size, float wallHeight )
{
	pluginWorldHeight = wallHeight;
	pluginWorldSize = size;

	return true;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/* http_bidder_interface.cc
   Eric Robert, 2 April 2014
   Copyright (c) 2011 Datacratic.  All rights reserved.
*/

#include "http_bidder_interface.h"
#include "jml/db/persistent.h"
#include "soa/service/http_client.h"
#include "rtbkit/common/messages.h"
#include "rtbkit/plugins/bid_request/openrtb_bid_request.h"
#include "rtbkit/openrtb/openrtb_parsing.h"
#include "rtbkit/core/router/router.h"

using namespace Datacratic;
using namespace RTBKIT;

namespace {
    DefaultDescription<OpenRTB::BidRequest> desc;
}

HttpBidderInterface::HttpBidderInterface(std::string name,
                                         std::shared_ptr<ServiceProxies> proxies,
                                         Json::Value const & json) {
    host = json["host"].asString();
    path = json["path"].asString();
    httpClient.reset(new HttpClient(host));
    loop.addSource("HttpBidderInterface::httpClient", httpClient);
}

void HttpBidderInterface::sendAuctionMessage(std::shared_ptr<Auction> const & auction,
                                             double timeLeftMs,
                                             std::map<std::string, BidInfo> const & bidders) {
    for(auto & item : bidders) {
        auto & agent = item.first;
        auto & info = router->agents[agent];
        WinCostModel wcm = auction->exchangeConnector->getWinCostModel(*auction, *info.config);

        OpenRTB::BidRequest openRtbRequest = toOpenRtb(*auction->request);
        StructuredJsonPrintingContext context;
        desc.printJson(&openRtbRequest, context);
        auto requestStr = context.output.toString();

        auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
                [&](const HttpRequest &, HttpClientError errorCode,
                    int, const std::string &, const std::string &body)
                {
                    if (errorCode != HttpClientError::NONE) {
                        auto toErrorString = [](HttpClientError code) -> std::string {
                            switch (code) {
                                #define CASE(code) \
                                    case code: \
                                        return #code;
                                CASE(HttpClientError::NONE)
                                CASE(HttpClientError::UNKNOWN)
                                CASE(HttpClientError::TIMEOUT)
                                CASE(HttpClientError::HOST_NOT_FOUND)
                                CASE(HttpClientError::COULD_NOT_CONNECT)
                                #undef CASE
                            }
                            ExcCheck(false, "Invalid code path");
                            return "";
                        };
                        std::cerr << "Error requesting " << host
                                  << ": " << toErrorString(errorCode);
                      }
                      else {
                          std::cerr << "Response: " << body << std::endl;
                      }
                  });

        HttpRequest::Content reqContent { requestStr, "application/json" };
        RestParams headers { { "x-openrtb-version", "2.1" } };
        std::cerr << "Sending HTTP POST to: " << host << " " << path << std::endl;
        std::cerr << "Content " << reqContent.str << std::endl;

        httpClient->post(path, callbacks, reqContent,
                         { } /* queryParams */, headers);
    }
}

void HttpBidderInterface::sendWinMessage(std::string const & agent,
                                         std::string const & id,
                                         Amount price) {
}

void HttpBidderInterface::sendLossMessage(std::string const & agent,
                                          std::string const & id) {
}

void HttpBidderInterface::sendBidLostMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendBidDroppedMessage(std::string const & agent,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendBidInvalidMessage(std::string const & agent,
                                                std::string const & reason,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendNoBudgetMessage(std::string const & agent,
                                              std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendTooLateMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendMessage(std::string const & agent,
                                      std::string const & message) {
}

void HttpBidderInterface::sendErrorMessage(std::string const & agent,
                                           std::string const & error,
                                           std::vector<std::string> const & payload) {
}

void HttpBidderInterface::sendPingMessage(std::string const & agent,
                                          int ping) {
}

void HttpBidderInterface::send(std::shared_ptr<PostAuctionEvent> const & event) {
}

//
// factory
//

struct AtInit {
    AtInit()
    {
        BidderInterface::registerFactory("http", [](std::string const & name , std::shared_ptr<ServiceProxies> const & proxies, Json::Value const & json) {
            return new HttpBidderInterface(name, proxies, json);
        });
    }
} atInit;

<commit_msg>Added an extension field per-impression representing the allowed bidders<commit_after>/* http_bidder_interface.cc
   Eric Robert, 2 April 2014
   Copyright (c) 2011 Datacratic.  All rights reserved.
*/

#include "http_bidder_interface.h"
#include "jml/db/persistent.h"
#include "soa/service/http_client.h"
#include "rtbkit/common/messages.h"
#include "rtbkit/plugins/bid_request/openrtb_bid_request.h"
#include "rtbkit/openrtb/openrtb_parsing.h"
#include "rtbkit/core/router/router.h"

using namespace Datacratic;
using namespace RTBKIT;

namespace {
    DefaultDescription<OpenRTB::BidRequest> desc;

    void tagRequest(OpenRTB::BidRequest &request,
                    const std::map<std::string, BidInfo> &bidders)
    {

        for (const auto &bidder: bidders) {
            const auto &agentConfig = bidder.second.agentConfig;
            const auto &spots = bidder.second.imp;
            const auto &creatives = agentConfig->creatives;

            Json::Value creativesValue(Json::arrayValue);
            for (const auto &spot: spots) {
                const int adSpotIndex = spot.first;
                ExcCheck(adSpotIndex >= 0 && adSpotIndex < request.imp.size(),
                         "adSpotIndex out of range");
                auto &imp = request.imp[adSpotIndex];
                auto &ext = imp.ext;
                for (int creativeIndex: spot.second) {
                    ExcCheck(creativeIndex >= 0 && creativeIndex < creatives.size(),
                             "creativeIndex out of range");
                    const int creativeId = creatives[creativeIndex].id;
                    creativesValue.append(creativeId);
                }

                ext["allowed_ids"][std::to_string(agentConfig->externalId)] =
                    std::move(creativesValue);

            }

        }

    }
}

HttpBidderInterface::HttpBidderInterface(std::string name,
                                         std::shared_ptr<ServiceProxies> proxies,
                                         Json::Value const & json) {
    host = json["host"].asString();
    path = json["path"].asString();
    httpClient.reset(new HttpClient(host));
    loop.addSource("HttpBidderInterface::httpClient", httpClient);
}

void HttpBidderInterface::sendAuctionMessage(std::shared_ptr<Auction> const & auction,
                                             double timeLeftMs,
                                             std::map<std::string, BidInfo> const & bidders) {
    for(auto & item : bidders) {
        auto & agent = item.first;
        auto & info = router->agents[agent];
        WinCostModel wcm = auction->exchangeConnector->getWinCostModel(*auction, *info.config);

        OpenRTB::BidRequest openRtbRequest = toOpenRtb(*auction->request);
        StructuredJsonPrintingContext context;
        desc.printJson(&openRtbRequest, context);
        auto requestStr = context.output.toString();

        auto callbacks = std::make_shared<HttpClientSimpleCallbacks>(
                [&](const HttpRequest &, HttpClientError errorCode,
                    int, const std::string &, const std::string &body)
                {
                    if (errorCode != HttpClientError::NONE) {
                        auto toErrorString = [](HttpClientError code) -> std::string {
                            switch (code) {
                                #define CASE(code) \
                                    case code: \
                                        return #code;
                                CASE(HttpClientError::NONE)
                                CASE(HttpClientError::UNKNOWN)
                                CASE(HttpClientError::TIMEOUT)
                                CASE(HttpClientError::HOST_NOT_FOUND)
                                CASE(HttpClientError::COULD_NOT_CONNECT)
                                #undef CASE
                            }
                            ExcCheck(false, "Invalid code path");
                            return "";
                        };
                        std::cerr << "Error requesting " << host
                                  << ": " << toErrorString(errorCode);
                      }
                      else {
                          std::cerr << "Response: " << body << std::endl;
                      }
                  });

        HttpRequest::Content reqContent { requestStr, "application/json" };
        RestParams headers { { "x-openrtb-version", "2.1" } };
        std::cerr << "Sending HTTP POST to: " << host << " " << path << std::endl;
        std::cerr << "Content " << reqContent.str << std::endl;

        httpClient->post(path, callbacks, reqContent,
                         { } /* queryParams */, headers);
    }
}

void HttpBidderInterface::sendWinMessage(std::string const & agent,
                                         std::string const & id,
                                         Amount price) {
}

void HttpBidderInterface::sendLossMessage(std::string const & agent,
                                          std::string const & id) {
}

void HttpBidderInterface::sendBidLostMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendBidDroppedMessage(std::string const & agent,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendBidInvalidMessage(std::string const & agent,
                                                std::string const & reason,
                                                std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendNoBudgetMessage(std::string const & agent,
                                              std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendTooLateMessage(std::string const & agent,
                                             std::shared_ptr<Auction> const & auction) {
}

void HttpBidderInterface::sendMessage(std::string const & agent,
                                      std::string const & message) {
}

void HttpBidderInterface::sendErrorMessage(std::string const & agent,
                                           std::string const & error,
                                           std::vector<std::string> const & payload) {
}

void HttpBidderInterface::sendPingMessage(std::string const & agent,
                                          int ping) {
}

void HttpBidderInterface::send(std::shared_ptr<PostAuctionEvent> const & event) {
}

//
// factory
//

struct AtInit {
    AtInit()
    {
        BidderInterface::registerFactory("http", [](std::string const & name , std::shared_ptr<ServiceProxies> const & proxies, Json::Value const & json) {
            return new HttpBidderInterface(name, proxies, json);
        });
    }
} atInit;

<|endoftext|>