<commit_before>/*
 * This file is part of Clockwork.
 *
 * Copyright (c) 2013-2016 Jeremy Othieno.
 *
 * The MIT License (MIT)
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef CLOCKWORK_POLYGON_RENDERER_HH
#define CLOCKWORK_POLYGON_RENDERER_HH

#include "Renderer.hh"
#include "RandomShadingShaderProgram.hh"
#include "FlatShadingShaderProgram.hh"
#include "GouraudShadingShaderProgram.hh"
#include "PhongShadingShaderProgram.hh"
#include "CelShadingShaderProgram.hh"
#include "DepthMapShaderProgram.hh"
#include "NormalMapShaderProgram.hh"
#include "BumpMapShaderProgram.hh"
#include "TextureMapShaderProgram.hh"

namespace clockwork {
/**
 *
 */
template<RenderingAlgorithm algorithm, class Implementation>
class PolygonRenderer : public Renderer<algorithm, Implementation> {
public:
	using Fragment = typename Renderer<algorithm, Implementation>::Fragment;
	using Varying = typename Renderer<algorithm, Implementation>::Varying;
	using Vertex = typename Renderer<algorithm, Implementation>::Vertex;
	using VertexArray = typename Renderer<algorithm, Implementation>::VertexArray;
	/**
	 * Sanitizes the rendering context and makes sure it is compatible with this renderer.
	 */
	static void sanitizeRenderingContext(RenderingContext&);
	/**
	 * Rearranges the specified set of vertices into a collection of geometric primitives.
	 */
	static void primitiveAssembly(const RenderingContext&, VertexArray&);
	/**
	 * Removes vertices that are not visible on the screen.
	 */
	static void clip(const RenderingContext&, VertexArray&);
	/**
	 * Converts the specified vertices into fragments that are written to the given framebuffer.
	 * @param context the rendering context.
	 * @param vertices the vertices to convert.
	 * @param framebuffer the framebuffer where fragments will be written to.
	 */
	static void rasterize(
		const RenderingContext& context,
		const VertexArray& vertices,
		Framebuffer& framebuffer
	);
};
/**
 *
 */
class RandomShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::RandomShading, RandomShadingRenderer> {};
/**
 *
 */
class FlatShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::FlatShading, FlatShadingRenderer> {};
/**
 *
 */
class GouraudShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::GouraudShading, GouraudShadingRenderer> {};
/**
 *
 */
class PhongShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::PhongShading, PhongShadingRenderer> {};
/**
 *
 */
class CelShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::CelShading, CelShadingRenderer> {};
/**
 *
 */
class DepthMapRenderer :
public PolygonRenderer<RenderingAlgorithm::DepthMapping, DepthMapRenderer> {};
/**
 *
 */
class NormalMapRenderer :
public PolygonRenderer<RenderingAlgorithm::NormalMapping, NormalMapRenderer> {};
/**
 *
 */
class BumpMapRenderer :
public PolygonRenderer<RenderingAlgorithm::BumpMapping, BumpMapRenderer> {};
/**
 *
 */
class TextureMapRenderer :
public PolygonRenderer<RenderingAlgorithm::TextureMapping, TextureMapRenderer> {};

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::sanitizeRenderingContext(RenderingContext& context) {
	// The Polygon renderer only draws triangle primitives so if the primitive topology
	// is not set to Triangle, TriangleStrip or TriangleFan, it will be set to TriangleStrip.
	auto& t = context.primitiveTopology;
	if (t != PrimitiveTopology::Triangle && t != PrimitiveTopology::TriangleStrip && t != PrimitiveTopology::TriangleFan) {
		t = PrimitiveTopology::TriangleStrip;
	}
}

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::primitiveAssembly(const RenderingContext&, VertexArray& vertices) {
	// TODO This will only generate triangle primitives. Implement TriangleStrip and
	// TriangleLoop generation.
	static const auto lessThan = [](const Vertex& a, const Vertex& b) {
		const auto& pa = a.position;
		const auto& pb = b.position;
		if (qFuzzyCompare(1.0 + pa.y(), 1.0 + pb.y())) {
			if (qFuzzyCompare(1.0 + pa.x(), 1.0 + pb.x())) {
				return pa.z() < pb.z();
			} else {
				return pa.x() < pb.x();
			}
		} else {
			return pa.y() < pb.y();
		}
	};
	// If the triangle primitive is not correctly formed for the scanline algorithm,
	// then tessellate two triangle primitives that fit our needs.
	for (auto it = vertices.begin(); it != vertices.end();) {
		const auto& from = it;
		const auto& to = it + 3;

		std::sort(from, to, lessThan); // Note: std::sort processes the range [first, last[.

		// Tessellate the primitive, if need be.
		const auto& V0 = it[0];
		const auto& V1 = it[1];
		const auto& V2 = it[2];

		const auto& p0 = V0.position;
		const auto& p1 = V1.position;
		const auto& p2 = V2.position;

		const bool tessellate = !qFuzzyCompare(1.0 + p0.y(), 1.0 + p1.y()) && !qFuzzyCompare(1.0 + p1.y(), 1.0 + p2.y());
		if (tessellate) {
			// Create a new output that will be used to create two new primitives.
			auto V = Vertex::lerp(V0, V2, (p1.y() - p0.y()) / (p2.y() - p0.y()));
			V.position.setY(p1.y());
			//V.position.z = 0; //FIXME Depth needs to be interpolated between V1 and O3.

			// Create two new triangle primitives: {V0, V1, V} and {V1, V, V2}. Since the
			// original array of outputs is {V0, V1, V2}, it becomes {V0, V1, V, V1, V, V2}.
			it = vertices.insert(it + 2, V);
			it = vertices.insert(it + 1, V1);
			it = vertices.insert(it + 1, V);
			it = std::next(it, 2);
		} else {
			it = to;
		}
	}
}

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::clip(const RenderingContext&, VertexArray&) {}

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::rasterize(
	const RenderingContext& context,
	const VertexArray& vertices,
	Framebuffer& framebuffer
) {
	for (auto it = vertices.begin(); it != vertices.end(); it += 3) {
		const auto* a = &it[1];
		const auto* b = &it[0];
		const auto* c = &it[2];
		if (qFuzzyCompare(1.0 + a->position.y(), 1.0 + b->position.y())) {
			a = &it[0];
			b = &it[2];
			c = &it[1];
		}

		const double ay = std::round(a->position.y());
		const double by = std::round(b->position.y());
		//const double cy = ay; // since a and c are colinear.
		const double dy = by - ay; // or by - cy.

		// If the dy is relatively small, all 3 points are considered colinear.
		constexpr double EPSILON = 1e-5;
		if (std::abs(dy) < EPSILON) {
			// TODO Handle cases where all 3 vertices are colinear.
		} else {
			auto ymin = static_cast<std::uint32_t>(ay);
			auto ymax = static_cast<std::uint32_t>(by);
			if (ymin > ymax) {
				std::swap(ymin, ymax);
			}
			for (auto y = ymin; y <= ymax; ++y) {
				const double p = (y - ay) / dy;
				const auto from = Vertex::lerp(*a, *b, p);
				const auto to = Vertex::lerp(*c, *b, p);

				const double Fx = std::round(from.position.x());
				const double Tx = std::round(to.position.x());
				const double dx = Tx - Fx;

				// If dx is relatively small, the 'from' and 'to' vertices are
				// considered identical so there's no need to interpolate any
				// new vertices between them.
				if (std::abs(dx) < EPSILON) {
					T::fragmentProcessing(context, Fragment(from), framebuffer);
				} else {
					auto xmin = static_cast<std::uint32_t>(Fx);
					auto xmax = static_cast<std::uint32_t>(Tx);
					if (xmin > xmax) {
						std::swap(xmin, xmax);
					}
					for (auto x = xmin; x <= xmax; ++x) {
						const double p = (x - Fx) / dx;
						const auto vertex = Vertex::lerp(from, to, p);
						Fragment fragment(vertex);
						fragment.x = x;
						fragment.y = y;
						T::fragmentProcessing(context, fragment, framebuffer);
					}
				}
			}
		}
	}
}
} // namespace clockwork

#endif // CLOCKWORK_POLYGON_RENDERER_HH
<commit_msg>Refactor the scanline algorithm implementation<commit_after>/*
 * This file is part of Clockwork.
 *
 * Copyright (c) 2013-2016 Jeremy Othieno.
 *
 * The MIT License (MIT)
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#ifndef CLOCKWORK_POLYGON_RENDERER_HH
#define CLOCKWORK_POLYGON_RENDERER_HH

#include "Renderer.hh"
#include "RandomShadingShaderProgram.hh"
#include "FlatShadingShaderProgram.hh"
#include "GouraudShadingShaderProgram.hh"
#include "PhongShadingShaderProgram.hh"
#include "CelShadingShaderProgram.hh"
#include "DepthMapShaderProgram.hh"
#include "NormalMapShaderProgram.hh"
#include "BumpMapShaderProgram.hh"
#include "TextureMapShaderProgram.hh"

namespace clockwork {
/**
 *
 */
template<RenderingAlgorithm algorithm, class Implementation>
class PolygonRenderer : public Renderer<algorithm, Implementation> {
public:
	using Fragment = typename Renderer<algorithm, Implementation>::Fragment;
	using Varying = typename Renderer<algorithm, Implementation>::Varying;
	using Vertex = typename Renderer<algorithm, Implementation>::Vertex;
	using VertexArray = typename Renderer<algorithm, Implementation>::VertexArray;
	/**
	 * Sanitizes the rendering context and makes sure it is compatible with this renderer.
	 */
	static void sanitizeRenderingContext(RenderingContext&);
	/**
	 * Rearranges the specified set of vertices into a collection of geometric primitives.
	 */
	static void primitiveAssembly(const RenderingContext&, VertexArray&);
	/**
	 * Removes vertices that are not visible on the screen.
	 */
	static void clip(const RenderingContext&, VertexArray&);
	/**
	 * Converts the specified vertices into fragments that are written to the given framebuffer.
	 * @param context the rendering context.
	 * @param vertices the vertices to convert.
	 * @param framebuffer the framebuffer where fragments will be written to.
	 */
	static void rasterize(
		const RenderingContext& context,
		const VertexArray& vertices,
		Framebuffer& framebuffer
	);
};
/**
 *
 */
class RandomShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::RandomShading, RandomShadingRenderer> {};
/**
 *
 */
class FlatShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::FlatShading, FlatShadingRenderer> {};
/**
 *
 */
class GouraudShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::GouraudShading, GouraudShadingRenderer> {};
/**
 *
 */
class PhongShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::PhongShading, PhongShadingRenderer> {};
/**
 *
 */
class CelShadingRenderer :
public PolygonRenderer<RenderingAlgorithm::CelShading, CelShadingRenderer> {};
/**
 *
 */
class DepthMapRenderer :
public PolygonRenderer<RenderingAlgorithm::DepthMapping, DepthMapRenderer> {};
/**
 *
 */
class NormalMapRenderer :
public PolygonRenderer<RenderingAlgorithm::NormalMapping, NormalMapRenderer> {};
/**
 *
 */
class BumpMapRenderer :
public PolygonRenderer<RenderingAlgorithm::BumpMapping, BumpMapRenderer> {};
/**
 *
 */
class TextureMapRenderer :
public PolygonRenderer<RenderingAlgorithm::TextureMapping, TextureMapRenderer> {};

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::sanitizeRenderingContext(RenderingContext& context) {
	// The Polygon renderer only draws triangle primitives so if the primitive topology
	// is not set to Triangle, TriangleStrip or TriangleFan, it will be set to TriangleStrip.
	auto& t = context.primitiveTopology;
	if (t != PrimitiveTopology::Triangle && t != PrimitiveTopology::TriangleStrip && t != PrimitiveTopology::TriangleFan) {
		t = PrimitiveTopology::TriangleStrip;
	}
}

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::primitiveAssembly(const RenderingContext&, VertexArray& vertices) {
	// TODO This will only generate triangle primitives. Implement TriangleStrip and
	// TriangleLoop generation.
	static const auto lessThan = [](const Vertex& a, const Vertex& b) {
		const auto& pa = a.position;
		const auto& pb = b.position;
		if (qFuzzyCompare(1.0 + pa.y(), 1.0 + pb.y())) {
			if (qFuzzyCompare(1.0 + pa.x(), 1.0 + pb.x())) {
				return pa.z() < pb.z();
			} else {
				return pa.x() < pb.x();
			}
		} else {
			return pa.y() < pb.y();
		}
	};
	// If the triangle primitive is not correctly formed for the scanline algorithm,
	// then tessellate two triangle primitives that fit our needs.
	for (auto it = vertices.begin(); it != vertices.end();) {
		const auto& from = it;
		const auto& to = it + 3;

		std::sort(from, to, lessThan); // Note: std::sort processes the range [first, last[.

		// Tessellate the primitive, if need be.
		const auto& V0 = it[0];
		const auto& V1 = it[1];
		const auto& V2 = it[2];

		const auto& p0 = V0.position;
		const auto& p1 = V1.position;
		const auto& p2 = V2.position;

		const bool tessellate = !qFuzzyCompare(1.0 + p0.y(), 1.0 + p1.y()) && !qFuzzyCompare(1.0 + p1.y(), 1.0 + p2.y());
		if (tessellate) {
			// Create a new output that will be used to create two new primitives.
			auto V = Vertex::lerp(V0, V2, (p1.y() - p0.y()) / (p2.y() - p0.y()));
			V.position.setY(p1.y());
			//V.position.z = 0; //FIXME Depth needs to be interpolated between V1 and O3.

			// Create two new triangle primitives: {V0, V1, V} and {V1, V, V2}. Since the
			// original array of outputs is {V0, V1, V2}, it becomes {V0, V1, V, V1, V, V2}.
			it = vertices.insert(it + 2, V);
			it = vertices.insert(it + 1, V1);
			it = vertices.insert(it + 1, V);
			it = std::next(it, 2);
		} else {
			it = to;
		}
	}
}

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::clip(const RenderingContext&, VertexArray&) {}

template<RenderingAlgorithm A, class T> void
PolygonRenderer<A, T>::rasterize(
	const RenderingContext& context,
	const VertexArray& vertices,
	Framebuffer& framebuffer
) {
	for (auto it = vertices.begin(); it != vertices.end(); it += 3) {
		const auto* a = &it[1];
		const auto* b = &it[0];
		const auto* c = &it[2];
		if (qFuzzyCompare(1.0 + a->position.y(), 1.0 + b->position.y())) {
			a = &it[0];
			b = &it[2];
			c = &it[1];
		}

		const int ay = qRound(a->position.y());
		const int by = qRound(b->position.y());
//		const int cy = ay; // since a and c are colinear.
		const int dy = by - ay; // or by - cy.

		int ymin = ay;
		int ymax = by;
		if (ymax < ymin) {
			std::swap(ymin, ymax);
		}
		for (int y = ymin; y <= ymax; ++y) {
			const qreal p = (y - ay) / static_cast<qreal>(dy);
			const Vertex from(Vertex::lerp(*a, *b, p));
			const Vertex to(Vertex::lerp(*c, *b, p));

			const int Fx = qRound(from.position.x());
			const int Tx = qRound(to.position.x());
			const int dx = Tx - Fx;

			// If dx is equal to zero, the 'from' and 'to' vertices are
			// considered identical so there's no need to interpolate any
			// new vertices between them.
			if (dx == 0) {
				T::fragmentProcessing(context, Fragment(from), framebuffer);
			} else {
				int xmin = Fx;
				int xmax = Tx;
				if (xmax < xmin) {
					std::swap(xmin, xmax);
				}
				for (int x = xmin; x <= xmax; ++x) {
					const qreal p = (x - Fx) / static_cast<qreal>(dx);
					Fragment fragment(Vertex::lerp(from, to, p));
					fragment.x = x;
					fragment.y = y;
					T::fragmentProcessing(context, fragment, framebuffer);
				}
			}
		}
	}
}
} // namespace clockwork

#endif // CLOCKWORK_POLYGON_RENDERER_HH
<|endoftext|>


<commit_before>/* Twofold-Qt
 * (C) Copyright 2014 HicknHack Software GmbH
 *
 * The original code can be found at:
 *     https://github.com/hicknhack-software/Twofold-Qt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "Twofold/Engine.h"

#include <QObject>
#include <QString>
#include <QtTest>

class TestBenchmark : public QObject
{
    Q_OBJECT

public:
    TestBenchmark();

private Q_SLOTS:
    void prepare();
    void execute_data();
    void execute();
    void calls();
    void exceptions();

private:
    Twofold::Engine engine;
    QVariantHash context;
    Twofold::PreparedTemplate prepared;
    Twofold::Target target;
};

#include "TestBenchmark.moc"

#define TEMPLATE_REPETITION 1000

class FakeTextLoader : public Twofold::TextLoader
{
public:
    Result load(const QString &name) const
    {
        static const QString templateText1 = QString::fromLatin1(R"EXAMPLE(
for(var i = 0; i <= 10000; i++) {
    | Das ist ein kurzer Text! #{i}
    # include "lib.twofold"
}
|---------------------------------
|
function structFieldHeader(type) {
  |#{ type.name }
  |struct #{ type.name } {
  |};
}

if (type.isArray) {
    | // #{ type.name } Type is an Array #{type.text}"
    = structFieldHeader(type);
}

    |class #{ name } {
     for(var i = 0; i < baseNames.length; i++) {
    |  #{ (i==0 ? ':' : ',') } public #{ baseNames[i] }
     }
|};
)EXAMPLE"
        ).arg(TEMPLATE_REPETITION);

        static const QString templateText2 = R"EXAMPLE(
|Line 1 included
|Line 2 incldued
)EXAMPLE";

        return (name != "lib.twofold")
                ? Result { Success, QString(), templateText1 }
                : Result { Success, QString(), templateText2 };
    }
};

TestBenchmark::TestBenchmark()
    : engine(std::make_shared<Twofold::MessageHandler>(),
             std::make_shared<FakeTextLoader>())
#if defined(_MSC_VER) && _MSC_VER < 1900
    , prepared({})
    , target({})
#endif
{
    QObject* pType = new QObject();
    pType->setProperty( "isArray", true );
    pType->setProperty( "name", "TestArray" );

    QStringList baseNames;
    baseNames.append( "base1" );
    baseNames.append( "base2" );
    baseNames.append( "base3" );

    context.insert( "type", QVariant::fromValue(pType) );
    context.insert( "baseNames", baseNames );
    context.insert( "name", "Main" );
}

void TestBenchmark::prepare()
{
    QBENCHMARK {
        engine.prepare("TextTemplate.twofold");
    }
}

void TestBenchmark::execute_data()
{
    prepared = engine.prepare("TextTemplate.twofold");
}

void TestBenchmark::execute()
{
    QBENCHMARK {
        engine.exec(prepared, context);
    }
}

extern int func(int x, int y);
extern int func_except(int x, int y);

int func(int x, int y) {
    return (x + y);
}

int func_except(int x, int y) {
    throw (x + y);
}

void TestBenchmark::calls()
{
    int r = 1;
    QBENCHMARK {
        r *= func(49, 430);
    }
}

void TestBenchmark::exceptions()
{
    int r = 1;
    QBENCHMARK {
        try {
            func_except(49, 430);
        }
        catch(int x) {
            r *= x;
        }
    }
}

QTEST_GUILESS_MAIN(TestBenchmark)
<commit_msg>added missing string argument<commit_after>/* Twofold-Qt
 * (C) Copyright 2014 HicknHack Software GmbH
 *
 * The original code can be found at:
 *     https://github.com/hicknhack-software/Twofold-Qt
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "Twofold/Engine.h"

#include <QObject>
#include <QString>
#include <QtTest>

class TestBenchmark : public QObject
{
    Q_OBJECT

public:
    TestBenchmark();

private Q_SLOTS:
    void prepare();
    void execute_data();
    void execute();
    void calls();
    void exceptions();

private:
    Twofold::Engine engine;
    QVariantHash context;
    Twofold::PreparedTemplate prepared;
    Twofold::Target target;
};

#include "TestBenchmark.moc"

#define TEMPLATE_REPETITION 1000

class FakeTextLoader : public Twofold::TextLoader
{
public:
    Result load(const QString &name) const
    {
        static const QString templateText1 = QString::fromLatin1(R"EXAMPLE(
for(var i = 0; i <= %1; i++) {
    | Das ist ein kurzer Text! #{i}
    # include "lib.twofold"
}
|---------------------------------
|
function structFieldHeader(type) {
  |#{ type.name }
  |struct #{ type.name } {
  |};
}

if (type.isArray) {
    | // #{ type.name } Type is an Array #{type.text}"
    = structFieldHeader(type);
}

    |class #{ name } {
     for(var i = 0; i < baseNames.length; i++) {
    |  #{ (i==0 ? ':' : ',') } public #{ baseNames[i] }
     }
|};
)EXAMPLE"
        ).arg(TEMPLATE_REPETITION);

        static const QString templateText2 = R"EXAMPLE(
|Line 1 included
|Line 2 incldued
)EXAMPLE";

        return (name != "lib.twofold")
                ? Result { Success, QString(), templateText1 }
                : Result { Success, QString(), templateText2 };
    }
};

TestBenchmark::TestBenchmark()
    : engine(std::make_shared<Twofold::MessageHandler>(),
             std::make_shared<FakeTextLoader>())
#if defined(_MSC_VER) && _MSC_VER < 1900
    , prepared({})
    , target({})
#endif
{
    QObject* pType = new QObject();
    pType->setProperty( "isArray", true );
    pType->setProperty( "name", "TestArray" );

    QStringList baseNames;
    baseNames.append( "base1" );
    baseNames.append( "base2" );
    baseNames.append( "base3" );

    context.insert( "type", QVariant::fromValue(pType) );
    context.insert( "baseNames", baseNames );
    context.insert( "name", "Main" );
}

void TestBenchmark::prepare()
{
    QBENCHMARK {
        engine.prepare("TextTemplate.twofold");
    }
}

void TestBenchmark::execute_data()
{
    prepared = engine.prepare("TextTemplate.twofold");
}

void TestBenchmark::execute()
{
    QBENCHMARK {
        engine.exec(prepared, context);
    }
}

extern int func(int x, int y);
extern int func_except(int x, int y);

int func(int x, int y) {
    return (x + y);
}

int func_except(int x, int y) {
    throw (x + y);
}

void TestBenchmark::calls()
{
    int r = 1;
    QBENCHMARK {
        r *= func(49, 430);
    }
}

void TestBenchmark::exceptions()
{
    int r = 1;
    QBENCHMARK {
        try {
            func_except(49, 430);
        }
        catch(int x) {
            r *= x;
        }
    }
}

QTEST_GUILESS_MAIN(TestBenchmark)
<|endoftext|>


<commit_before>//
// created by : Timothée Feuillet
// date: 2021-12-11
//
//
// Copyright (c) 2021 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#pragma once

#include <type_traits>
#include <ntools/ct_string.hpp>
#include <ntools/ct_list.hpp>

#define N_METADATA_STRUCT(Struct) template<> struct n_metadata_member_definitions<Struct> : public ::neam::metadata::internal::member_definition_base<Struct>

#define N_MEMBER_DEF_EX(Struct, Member) ::neam::metadata::internal::member_definition<decltype(Struct::Member), offsetof(Struct, Member), #Member>

/// \brief Entry in the member_list type of serializable structs
#define N_MEMBER_DEF(Member) ::neam::metadata::internal::member_definition<decltype(struct_type::Member), offsetof(struct_type, Member), #Member>

namespace neam::metadata::internal
{
  template<typename T>
  struct member_definition_base
  {
    using struct_type = T;
  };

  template<typename Type, size_t Offset, ct::string_holder Name>
  struct member_definition
  {
    static constexpr size_t size = sizeof(Type);
    static constexpr size_t offset = Offset;
    using type = Type;
    static constexpr ct::string_holder name = Name;
  };
}

template<typename T> struct n_metadata_member_definitions {static_assert(!std::is_same_v<T, void>, "No member definition for type T");};

template<typename T> using n_metadata_member_list = typename n_metadata_member_definitions<T>::member_list;

namespace neam::metadata::concepts
{
  /// \brief A struct with metadata allows for an easy and semi-automatic serialization of compound types
  ///
  /// Here is a serializable struct:
  ///
  /// struct MyAwesomeStruct
  /// {
  ///   unsigned some_member = 0;
  ///   std::vector< std::map< int, SomeOtherStruct > > stuff;
  ///   raw_data binary_blob;
  /// };
  /// N_METADATA_STRUCT(MyAwesomeStruct)
  /// {
  ///   using member_list = ct::list
  ///   <
  ///     N_MEMBER(some_member),
  ///     N_MEMBER(stuff),
  ///     N_MEMBER(binary_blob),
  ///   >;
  /// };
  template<typename T>
  concept StructWithMetadata = requires(T v)
  {
    ct::list::size<typename n_metadata_member_definitions<T>::member_list>;
  };
}

<commit_msg>Add support for template types<commit_after>//
// created by : Timothée Feuillet
// date: 2021-12-11
//
//
// Copyright (c) 2021 Timothée Feuillet
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//

#pragma once

#include <type_traits>
#include <ntools/ct_string.hpp>
#include <ntools/ct_list.hpp>

#define N_METADATA_STRUCT(Struct) template<> struct n_metadata_member_definitions<Struct> : public ::neam::metadata::internal::member_definition_base<Struct>

#define N_METADATA_STRUCT_TPL(Struct, ...) struct n_metadata_member_definitions<Struct<__VA_ARGS__>> : public ::neam::metadata::internal::member_definition_base<Struct<__VA_ARGS__>>

#define N_DECLARE_STRUCT_TYPE_TPL(Struct, ...) using struct_type = Struct<__VA_ARGS__>

#define N_MEMBER_DEF_EX(Struct, Member) ::neam::metadata::internal::member_definition<decltype(Struct::Member), offsetof(Struct, Member), #Member>

/// \brief Entry in the member_list type of serializable structs
#define N_MEMBER_DEF(Member) ::neam::metadata::internal::member_definition<decltype(struct_type::Member), offsetof(struct_type, Member), #Member>

namespace neam::metadata::internal
{
  template<typename T>
  struct member_definition_base
  {
    using struct_type = T;
  };

  template<typename Type, size_t Offset, ct::string_holder Name>
  struct member_definition
  {
    static constexpr size_t size = sizeof(Type);
    static constexpr size_t offset = Offset;
    using type = Type;
    static constexpr ct::string_holder name = Name;
  };
}

template<typename T> struct n_metadata_member_definitions {static_assert(!std::is_same_v<T, void>, "No member definition for type T");};

template<typename T> using n_metadata_member_list = typename n_metadata_member_definitions<T>::member_list;

namespace neam::metadata::concepts
{
  /// \brief A struct with metadata allows for an easy and semi-automatic serialization of compound types
  ///
  /// Here is a serializable struct:
  ///
  /// struct MyAwesomeStruct
  /// {
  ///   unsigned some_member = 0;
  ///   std::vector< std::map< int, SomeOtherStruct > > stuff;
  ///   raw_data binary_blob;
  /// };
  /// N_METADATA_STRUCT(MyAwesomeStruct)
  /// {
  ///   using member_list = ct::list
  ///   <
  ///     N_MEMBER(some_member),
  ///     N_MEMBER(stuff),
  ///     N_MEMBER(binary_blob),
  ///   >;
  /// };
  template<typename T>
  concept StructWithMetadata = requires(T v)
  {
    ct::list::size<typename n_metadata_member_definitions<T>::member_list>;
  };
}

<|endoftext|>


<commit_before>/*
An Botan example application which emulates a poorly written version of bzip2

Written by Jack Lloyd (lloyd@randombit.net), Jun 9, 2001

This file is in the public domain
*/
#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <iostream>
#include <botan/botan.h>

#if defined(BOTAN_EXT_COMPRESSOR_BZIP2)
  #include <botan/bzip2.h>
#else
  #error "You didn't compile the bzip module into Botan"
#endif

const std::string SUFFIX = ".bz2";

int main(int argc, char* argv[])
   {
   if(argc < 2)
      {
      std::cout << "Usage: " << argv[0]
                << " [-s] [-d] [-1...9] <filenames>" << std::endl;
      return 1;
      }

   std::vector<std::string> files;
   bool decompress = false, small = false;
   int level = 9;

   for(int j = 1; argv[j] != 0; j++)
      {
      if(std::strcmp(argv[j], "-d") == 0) { decompress = true; continue; }
      if(std::strcmp(argv[j], "-s") == 0) { small = true; continue; }
      if(std::strcmp(argv[j], "-1") == 0) { level = 1; continue; }
      if(std::strcmp(argv[j], "-2") == 0) { level = 2; continue; }
      if(std::strcmp(argv[j], "-3") == 0) { level = 3; continue; }
      if(std::strcmp(argv[j], "-4") == 0) { level = 4; continue; }
      if(std::strcmp(argv[j], "-5") == 0) { level = 5; continue; }
      if(std::strcmp(argv[j], "-6") == 0) { level = 6; continue; }
      if(std::strcmp(argv[j], "-7") == 0) { level = 7; continue; }
      if(std::strcmp(argv[j], "-8") == 0) { level = 8; continue; }
      if(std::strcmp(argv[j], "-9") == 0) { level = 9; continue; }
      files.push_back(argv[j]);
      }

   try {

      Botan::Filter* bzip;
      if(decompress)
         bzip = new Botan::Bzip_Decompression(small);
      else
         bzip = new Botan::Bzip_Compression(level);

      Botan::Pipe pipe(bzip);

      for(unsigned int j = 0; j != files.size(); j++)
         {
         std::string infile = files[j], outfile = files[j];
         if(!decompress)
            outfile = outfile += SUFFIX;
         else
            outfile = outfile.replace(outfile.find(SUFFIX),
                                      SUFFIX.length(), "");

         std::ifstream in(infile.c_str());
         std::ofstream out(outfile.c_str());
         if(!in)
            {
            std::cout << "ERROR: could not read " << infile << std::endl;
            continue;
            }
         if(!out)
            {
            std::cout << "ERROR: could not write " << outfile << std::endl;
            continue;
            }

         pipe.start_msg();
         in >> pipe;
         pipe.end_msg();
         pipe.set_default_msg(j);
         out << pipe;

         in.close();
         out.close();
         }
   }
   catch(std::exception& e)
      {
      std::cout << "Exception caught: " << e.what() << std::endl;
      return 1;
      }
   return 0;
   }
<commit_msg>Fail at runtime if bzip2 is not compiled in, instead of compile time<commit_after>/*
An Botan example application which emulates a poorly written version of bzip2

Written by Jack Lloyd (lloyd@randombit.net), Jun 9, 2001

This file is in the public domain
*/
#include <string>
#include <cstring>
#include <vector>
#include <fstream>
#include <iostream>
#include <botan/botan.h>

#if defined(BOTAN_EXT_COMPRESSOR_BZIP2)
  #include <botan/bzip2.h>
#endif

const std::string SUFFIX = ".bz2";

int main(int argc, char* argv[])
   {
   if(argc < 2)
      {
      std::cout << "Usage: " << argv[0]
                << " [-s] [-d] [-1...9] <filenames>" << std::endl;
      return 1;
      }

   std::vector<std::string> files;
   bool decompress = false, small = false;
   int level = 9;

   for(int j = 1; argv[j] != 0; j++)
      {
      if(std::strcmp(argv[j], "-d") == 0) { decompress = true; continue; }
      if(std::strcmp(argv[j], "-s") == 0) { small = true; continue; }
      if(std::strcmp(argv[j], "-1") == 0) { level = 1; continue; }
      if(std::strcmp(argv[j], "-2") == 0) { level = 2; continue; }
      if(std::strcmp(argv[j], "-3") == 0) { level = 3; continue; }
      if(std::strcmp(argv[j], "-4") == 0) { level = 4; continue; }
      if(std::strcmp(argv[j], "-5") == 0) { level = 5; continue; }
      if(std::strcmp(argv[j], "-6") == 0) { level = 6; continue; }
      if(std::strcmp(argv[j], "-7") == 0) { level = 7; continue; }
      if(std::strcmp(argv[j], "-8") == 0) { level = 8; continue; }
      if(std::strcmp(argv[j], "-9") == 0) { level = 9; continue; }
      files.push_back(argv[j]);
      }

   try {

      Botan::Filter* bzip = 0;
#ifdef BOTAN_EXT_COMPRESSOR_BZIP2
      if(decompress)
         bzip = new Botan::Bzip_Decompression(small);
      else
         bzip = new Botan::Bzip_Compression(level);
#endif

      if(!bzip)
         {
         std::cout << "Sorry, support for bzip2 not compiled into Botan\n";
         return 1;
         }

      Botan::Pipe pipe(bzip);

      for(unsigned int j = 0; j != files.size(); j++)
         {
         std::string infile = files[j], outfile = files[j];
         if(!decompress)
            outfile = outfile += SUFFIX;
         else
            outfile = outfile.replace(outfile.find(SUFFIX),
                                      SUFFIX.length(), "");

         std::ifstream in(infile.c_str());
         std::ofstream out(outfile.c_str());
         if(!in)
            {
            std::cout << "ERROR: could not read " << infile << std::endl;
            continue;
            }
         if(!out)
            {
            std::cout << "ERROR: could not write " << outfile << std::endl;
            continue;
            }

         pipe.start_msg();
         in >> pipe;
         pipe.end_msg();
         pipe.set_default_msg(j);
         out << pipe;

         in.close();
         out.close();
         }
   }
   catch(std::exception& e)
      {
      std::cout << "Exception caught: " << e.what() << std::endl;
      return 1;
      }
   return 0;
   }
<|endoftext|>


<commit_before>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"

#include "SkColorPriv.h"
#include "SkShader.h"

namespace skiagm {

class BigMatrixGM : public GM {
public:
    BigMatrixGM() {
        this->setBGColor(0xFF66AA99);
    }

protected:
    virtual SkString onShortName() {
        return SkString("bigmatrix");
    }

    virtual SkISize onISize() {
        return make_isize(50, 50);
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkMatrix m;
        m.reset();
        m.setRotate(33 * SK_Scalar1);
        m.postScale(3000 * SK_Scalar1, 3000 * SK_Scalar1);
        m.postTranslate(6000 * SK_Scalar1, -5000 * SK_Scalar1);
        canvas->concat(m);

        SkPaint paint;
        paint.setColor(SK_ColorRED);
        paint.setAntiAlias(true);

        m.invert(&m);

        SkPath path;

        SkPoint pt = {10 * SK_Scalar1, 10 * SK_Scalar1};
        SkScalar small = 1 / (500 * SK_Scalar1);

        m.mapPoints(&pt, 1);
        path.addCircle(pt.fX, pt.fY, small);
        canvas->drawPath(path, paint);

        pt.set(30 * SK_Scalar1, 10 * SK_Scalar1);
        m.mapPoints(&pt, 1);
        SkRect rect = {pt.fX - small, pt.fY - small,
                       pt.fX + small, pt.fY + small};
        canvas->drawRect(rect, paint);

        SkBitmap bmp;
        bmp.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
        bmp.allocPixels();
        bmp.lockPixels();
        uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels());
        pixels[0] = SkPackARGB32(0xFF, 0xFF, 0x00, 0x00);
        pixels[1] = SkPackARGB32(0xFF, 0x00, 0xFF, 0x00);
        pixels[2] = SkPackARGB32(0x80, 0x00, 0x00, 0x00);
        pixels[3] = SkPackARGB32(0xFF, 0x00, 0x00, 0xFF);
        bmp.unlockPixels();
        pt.set(30 * SK_Scalar1, 30 * SK_Scalar1);
        m.mapPoints(&pt, 1);
        SkShader* shader = SkShader::CreateBitmapShader(
                                            bmp,
                                            SkShader::kRepeat_TileMode,
                                            SkShader::kRepeat_TileMode);
        SkMatrix s;
        s.reset();
        s.setScale(SK_Scalar1 / 1000, SK_Scalar1 / 1000);
        shader->setLocalMatrix(s);
        paint.setShader(shader)->unref();
        paint.setAntiAlias(false);
        paint.setFilterBitmap(true);
        rect.setLTRB(pt.fX - small, pt.fY - small,
                     pt.fX + small, pt.fY + small);
        canvas->drawRect(rect, paint);
    }

private:
    typedef GM INHERITED;
};

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

static GM* MyFactory(void*) { return new BigMatrixGM; }
static GMRegistry reg(MyFactory);

}

<commit_msg>silence warning<commit_after>
/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"

#include "SkColorPriv.h"
#include "SkShader.h"

namespace skiagm {

class BigMatrixGM : public GM {
public:
    BigMatrixGM() {
        this->setBGColor(0xFF66AA99);
    }

protected:
    virtual SkString onShortName() {
        return SkString("bigmatrix");
    }

    virtual SkISize onISize() {
        return make_isize(50, 50);
    }

    virtual void onDraw(SkCanvas* canvas) {
        SkMatrix m;
        m.reset();
        m.setRotate(33 * SK_Scalar1);
        m.postScale(3000 * SK_Scalar1, 3000 * SK_Scalar1);
        m.postTranslate(6000 * SK_Scalar1, -5000 * SK_Scalar1);
        canvas->concat(m);

        SkPaint paint;
        paint.setColor(SK_ColorRED);
        paint.setAntiAlias(true);

        bool success = m.invert(&m);

        SkPath path;

        SkPoint pt = {10 * SK_Scalar1, 10 * SK_Scalar1};
        SkScalar small = 1 / (500 * SK_Scalar1);

        m.mapPoints(&pt, 1);
        path.addCircle(pt.fX, pt.fY, small);
        canvas->drawPath(path, paint);

        pt.set(30 * SK_Scalar1, 10 * SK_Scalar1);
        m.mapPoints(&pt, 1);
        SkRect rect = {pt.fX - small, pt.fY - small,
                       pt.fX + small, pt.fY + small};
        canvas->drawRect(rect, paint);

        SkBitmap bmp;
        bmp.setConfig(SkBitmap::kARGB_8888_Config, 2, 2);
        bmp.allocPixels();
        bmp.lockPixels();
        uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels());
        pixels[0] = SkPackARGB32(0xFF, 0xFF, 0x00, 0x00);
        pixels[1] = SkPackARGB32(0xFF, 0x00, 0xFF, 0x00);
        pixels[2] = SkPackARGB32(0x80, 0x00, 0x00, 0x00);
        pixels[3] = SkPackARGB32(0xFF, 0x00, 0x00, 0xFF);
        bmp.unlockPixels();
        pt.set(30 * SK_Scalar1, 30 * SK_Scalar1);
        m.mapPoints(&pt, 1);
        SkShader* shader = SkShader::CreateBitmapShader(
                                            bmp,
                                            SkShader::kRepeat_TileMode,
                                            SkShader::kRepeat_TileMode);
        SkMatrix s;
        s.reset();
        s.setScale(SK_Scalar1 / 1000, SK_Scalar1 / 1000);
        shader->setLocalMatrix(s);
        paint.setShader(shader)->unref();
        paint.setAntiAlias(false);
        paint.setFilterBitmap(true);
        rect.setLTRB(pt.fX - small, pt.fY - small,
                     pt.fX + small, pt.fY + small);
        canvas->drawRect(rect, paint);
    }

private:
    typedef GM INHERITED;
};

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

static GM* MyFactory(void*) { return new BigMatrixGM; }
static GMRegistry reg(MyFactory);

}

<|endoftext|>


<commit_before>#include <Windows.h>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>

#include "shared.hpp"
#include "controller.hpp"
#include "logging.hpp"
#include "invoker.hpp"
#include "export.hpp"
#include "client\client.hpp"
#include "extensions.hpp"
#include "shared\functions.hpp"

INITIALIZE_EASYLOGGINGPP

extern "C"
{
    __declspec(dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);
};

static char version[] = "1.0";

std::string get_command(const std::string & input) {
    size_t cmd_end;
    std::string command;

    cmd_end = input.find(':');
    if (cmd_end < 1) {
        return "";
    }

    return input.substr(0, cmd_end);
}

std::atomic_bool _threaded = false;

void __stdcall RVExtension(char *output, int outputSize, const char *function) {
    DebugBreak();
    ZERO_OUTPUT();

    // Get the command, then the command args
    std::string input = function;

    std::string command = get_command(input);
    bool block_execute = false;

    std::string argument_str;
    if (command.length() > 1 && input.length() > command.length() + 1) {
        argument_str = input.substr(command.length() + 1, (input.length() + 1 - command.length()));
    }
    intercept::arguments _args(argument_str);

    std::string result = "-1";
    _threaded = false;
    if (command.size() < 1) {
        output[0] = 0x00;
        return;
    }
    if (command == "version") {
        result = version;
    }
    else if (command == "echo") {
        result = function;
    }
    else if (command == "async") {
        _threaded = true;
        result = "0";
    }
    else if (command == "stop") {
        _threaded = false;
    }

    if (command == "init_patch") {
        uintptr_t game_state_addr = (uintptr_t)*(uintptr_t *)((uintptr_t)output + outputSize + 8);
        intercept::loader::get().do_function_walk(game_state_addr);
        return;
    }

    if (command == "block_execute") {
        block_execute = true;
        command = _args.as_string(0);
        _threaded = false;
    }
    if (block_execute) {
        intercept::invoker::get().allow_access();
    }
    intercept::controller::get().call(command, _args, result, _threaded);
    if (block_execute) {
        intercept::invoker::get().deny_access();
    }
    if (result.length() > 0) {
        sprintf_s(output, outputSize, "%s", result.c_str());
    }
    EXTENSION_RETURN();
}

intercept::client_functions intercept::client::host::functions;

void Init(void) {
    intercept::client::host::functions = intercept::extensions::get().functions;
    el::Configurations conf;

    conf.setGlobally(el::ConfigurationType::Filename, "logs/intercept_dll.log");
    conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "10240");
#ifdef _DEBUG
    el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Format, "[%datetime] - %level - {%loc}t:%thread- %msg");
    conf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
#else
    el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Format, "%datetime-{%level}- %msg");
#endif
    el::Loggers::setDefaultConfigurations(conf, true);

    LOG(INFO) << "Intercept DLL Loaded";
}

void Cleanup(void) {

}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
    )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        Init();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        Cleanup();
        break;
    }
    return TRUE;
}
<commit_msg>Don't commit DebugBreaks!<commit_after>#include <Windows.h>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <unordered_set>

#include "shared.hpp"
#include "controller.hpp"
#include "logging.hpp"
#include "invoker.hpp"
#include "export.hpp"
#include "client\client.hpp"
#include "extensions.hpp"
#include "shared\functions.hpp"

INITIALIZE_EASYLOGGINGPP

extern "C"
{
    __declspec(dllexport) void __stdcall RVExtension(char *output, int outputSize, const char *function);
};

static char version[] = "1.0";

std::string get_command(const std::string & input) {
    size_t cmd_end;
    std::string command;

    cmd_end = input.find(':');
    if (cmd_end < 1) {
        return "";
    }

    return input.substr(0, cmd_end);
}

std::atomic_bool _threaded = false;

void __stdcall RVExtension(char *output, int outputSize, const char *function) {
    ZERO_OUTPUT();

    // Get the command, then the command args
    std::string input = function;

    std::string command = get_command(input);
    bool block_execute = false;

    std::string argument_str;
    if (command.length() > 1 && input.length() > command.length() + 1) {
        argument_str = input.substr(command.length() + 1, (input.length() + 1 - command.length()));
    }
    intercept::arguments _args(argument_str);

    std::string result = "-1";
    _threaded = false;
    if (command.size() < 1) {
        output[0] = 0x00;
        return;
    }
    if (command == "version") {
        result = version;
    }
    else if (command == "echo") {
        result = function;
    }
    else if (command == "async") {
        _threaded = true;
        result = "0";
    }
    else if (command == "stop") {
        _threaded = false;
    }

    if (command == "init_patch") {
        uintptr_t game_state_addr = (uintptr_t)*(uintptr_t *)((uintptr_t)output + outputSize + 8);
        intercept::loader::get().do_function_walk(game_state_addr);
        return;
    }

    if (command == "block_execute") {
        block_execute = true;
        command = _args.as_string(0);
        _threaded = false;
    }
    if (block_execute) {
        intercept::invoker::get().allow_access();
    }
    intercept::controller::get().call(command, _args, result, _threaded);
    if (block_execute) {
        intercept::invoker::get().deny_access();
    }
    if (result.length() > 0) {
        sprintf_s(output, outputSize, "%s", result.c_str());
    }
    EXTENSION_RETURN();
}

intercept::client_functions intercept::client::host::functions;

void Init(void) {
    intercept::client::host::functions = intercept::extensions::get().functions;
    el::Configurations conf;

    conf.setGlobally(el::ConfigurationType::Filename, "logs/intercept_dll.log");
    conf.setGlobally(el::ConfigurationType::MaxLogFileSize, "10240");
#ifdef _DEBUG
    el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Format, "[%datetime] - %level - {%loc}t:%thread- %msg");
    conf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
#else
    el::Loggers::reconfigureAllLoggers(el::ConfigurationType::Format, "%datetime-{%level}- %msg");
#endif
    el::Loggers::setDefaultConfigurations(conf, true);

    LOG(INFO) << "Intercept DLL Loaded";
}

void Cleanup(void) {

}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
    )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        Init();
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        Cleanup();
        break;
    }
    return TRUE;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <sys/types.h>
#include <QUuid>
#include <QFileInfo>
#include <TWebApplication>
#include <TSystemGlobal>
#include <THttpHeader>
#include "tepollsocket.h"
#include "tepollhttpsocket.h"
#include "tepoll.h"
#include "tsendbuffer.h"
#include "tfcore.h"

class SendData;

static int sendBufSize = 0;
static int recvBufSize = 0;

TEpollSocket *TEpollSocket::accept(int listeningSocket)
{
    struct sockaddr_storage addr;
    socklen_t addrlen = sizeof(addr);

    int actfd = tf_accept4(listeningSocket, (sockaddr *)&addr, &addrlen, SOCK_CLOEXEC | SOCK_NONBLOCK);
    int err = errno;
    if (Q_UNLIKELY(actfd < 0)) {
        if (err != EAGAIN) {
            tSystemWarn("Failed accept.  errno:%d", err);
        }
        return NULL;
    }

    return create(actfd, QHostAddress((sockaddr *)&addr));
}

TEpollSocket *TEpollSocket::create(int socketDescriptor, const QHostAddress &address)
{
    TEpollSocket *sock = 0;

    if (Q_LIKELY(socketDescriptor > 0)) {
        sock  = new TEpollHttpSocket(socketDescriptor, address);
        sock->moveToThread(Tf::app()->thread());

        initBuffer(socketDescriptor);
    }

    return sock;
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &header, const QFileInfo &file, bool autoRemove, const TAccessLogger &logger)
{
    return new TSendBuffer(header, file, autoRemove, logger);
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &data)
{
    return new TSendBuffer(data);
}

void TEpollSocket::initBuffer(int socketDescriptor)
{
    const int BUF_SIZE = 128 * 1024;

    if (Q_UNLIKELY(sendBufSize == 0)) {
        // Creates a common buffer
        int res;
        socklen_t optlen;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_SNDBUF, &sendBufSize, &optlen);
        if (res < 0)
            sendBufSize = BUF_SIZE;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &recvBufSize, &optlen);
        if (res < 0)
            recvBufSize = BUF_SIZE;

    }
}

TEpollSocket::TEpollSocket(int socketDescriptor, const QHostAddress &address)
    : deleting(false), myWorkerCounter(0), pollIn(false), pollOut(false),
      sd(socketDescriptor), uuid(), clientAddr(address)
{
    uuid = QUuid::createUuid().toByteArray();  // not thread safe
    uuid = uuid.mid(1, uuid.length() - 2);
    tSystemDebug("TEpollSocket  id:%s", uuid.data());
}

TEpollSocket::~TEpollSocket()
{
    tSystemDebug("TEpollSocket::destructor");

    close();

    for (auto p : sendBuf) {
        delete p;
    }
    sendBuf.clear();
}

/*!
  Receives data
  @return  0:success  -1:error
 */
int TEpollSocket::recv()
{
    int ret = 0;
    int err = 0;
    int len;

    for (;;) {
        void *buf = getRecvBuffer(recvBufSize);
        errno = 0;
        len = tf_recv(sd, buf, recvBufSize, 0);
        err = errno;

        if (len <= 0) {
            break;
        }

        // Read successfully
        seekRecvBuffer(len);
    }

    if (len < 0) {
        switch (err) {
        case EAGAIN:
            break;

        case ECONNRESET:
            tSystemDebug("Socket disconnected : sd:%d  errno:%d", sd, err);
            ret = -1;
            break;

        default:
            tSystemError("Failed recv : sd:%d  errno:%d", sd, err);
            ret = -1;
            break;
        }
    }
    return ret;
}

/*!
  Sends data
  @return  0:success  -1:error
 */
int TEpollSocket::send()
{
    if (sendBuf.isEmpty()) {
        pollOut = true;
        return 0;
    }
    pollOut = false;

    if (deleting.load()) {
        return 0;
    }

    int ret = 0;
    int err = 0;
    int len;

    while (!sendBuf.isEmpty()) {
        TSendBuffer *buf = sendBuf.first();
        TAccessLogger &logger = buf->accessLogger();

        err = 0;
        for (;;) {
            len = sendBufSize;
            void *data = buf->getData(len);
            if (len == 0) {
                break;
            }

            errno = 0;
            len = tf_send(sd, data, len, MSG_NOSIGNAL);
            err = errno;

            if (len <= 0) {
                break;
            }

            // Sent successfully
            buf->seekData(len);
            logger.setResponseBytes(logger.responseBytes() + len);
        }

        if (buf->atEnd()) {
            logger.write();  // Writes access log
            delete sendBuf.dequeue(); // delete send-buffer obj
        }

        if (len < 0) {
            switch (err) {
            case EAGAIN:
                break;

            case EPIPE:   // FALL THROUGH
            case ECONNRESET:
                tSystemDebug("Socket disconnected : sd:%d  errno:%d", sd, err);
                logger.setResponseBytes(-1);
                ret = -1;
                break;

            default:
                tSystemError("Failed send : sd:%d  errno:%d  len:%d", sd, err, len);
                logger.setResponseBytes(-1);
                ret = -1;
                break;
            }

            break;
        }
    }
    return ret;
}

void TEpollSocket::enqueueSendData(TSendBuffer *buffer)
{
    sendBuf << buffer;
}

void TEpollSocket::setSocketDescpriter(int socketDescriptor)
{
    sd = socketDescriptor;
}

void TEpollSocket::close()
{
    if (sd > 0) {
        tf_close(sd);
        sd = 0;
    }
}

void TEpollSocket::sendData(const QByteArray &header, QIODevice *body, bool autoRemove, const TAccessLogger &accessLogger)
{
    if (!deleting.load()) {
        TEpoll::instance()->setSendData(this, header, body, autoRemove, accessLogger);
    }
}

void TEpollSocket::sendData(const QByteArray &data)
{
    if (!deleting.load()) {
        TEpoll::instance()->setSendData(this, data);
    }
}

void TEpollSocket::disconnect()
{
    if (!deleting.load())
        TEpoll::instance()->setDisconnect(this);
}

void TEpollSocket::switchToWebSocket(const THttpRequestHeader &header)
{
    if (!deleting.load())
        TEpoll::instance()->setSwitchToWebSocket(this, header);
}

qint64 TEpollSocket::bufferedBytes() const
{
    qint64 ret = 0;
    for (auto &d : sendBuf) {
        ret += d->arrayBuffer.size();
        if (d->bodyFile) {
            ret += d->bodyFile->size();
        }
    }
    return ret;
}

int TEpollSocket::bufferedListCount() const
{
    return sendBuf.count();
}

void TEpollSocket::deleteLater()
{
    tSystemDebug("TEpollSocket::deleteLater  countWorker:%d", (int)myWorkerCounter);
    deleting = true;
    if ((int)myWorkerCounter == 0) {
        QObject::deleteLater();
    }
}
<commit_msg>bugfix of recv of TEpollSocket.<commit_after>/* Copyright (c) 2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <sys/types.h>
#include <QUuid>
#include <QFileInfo>
#include <TWebApplication>
#include <TSystemGlobal>
#include <THttpHeader>
#include "tepollsocket.h"
#include "tepollhttpsocket.h"
#include "tepoll.h"
#include "tsendbuffer.h"
#include "tfcore.h"

class SendData;

static int sendBufSize = 0;
static int recvBufSize = 0;

TEpollSocket *TEpollSocket::accept(int listeningSocket)
{
    struct sockaddr_storage addr;
    socklen_t addrlen = sizeof(addr);

    int actfd = tf_accept4(listeningSocket, (sockaddr *)&addr, &addrlen, SOCK_CLOEXEC | SOCK_NONBLOCK);
    int err = errno;
    if (Q_UNLIKELY(actfd < 0)) {
        if (err != EAGAIN) {
            tSystemWarn("Failed accept.  errno:%d", err);
        }
        return NULL;
    }

    return create(actfd, QHostAddress((sockaddr *)&addr));
}

TEpollSocket *TEpollSocket::create(int socketDescriptor, const QHostAddress &address)
{
    TEpollSocket *sock = 0;

    if (Q_LIKELY(socketDescriptor > 0)) {
        sock  = new TEpollHttpSocket(socketDescriptor, address);
        sock->moveToThread(Tf::app()->thread());

        initBuffer(socketDescriptor);
    }

    return sock;
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &header, const QFileInfo &file, bool autoRemove, const TAccessLogger &logger)
{
    return new TSendBuffer(header, file, autoRemove, logger);
}

TSendBuffer *TEpollSocket::createSendBuffer(const QByteArray &data)
{
    return new TSendBuffer(data);
}

void TEpollSocket::initBuffer(int socketDescriptor)
{
    const int BUF_SIZE = 128 * 1024;

    if (Q_UNLIKELY(sendBufSize == 0)) {
        // Creates a common buffer
        int res;
        socklen_t optlen;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_SNDBUF, &sendBufSize, &optlen);
        if (res < 0)
            sendBufSize = BUF_SIZE;

        optlen = sizeof(int);
        res = getsockopt(socketDescriptor, SOL_SOCKET, SO_RCVBUF, &recvBufSize, &optlen);
        if (res < 0)
            recvBufSize = BUF_SIZE;

    }
}

TEpollSocket::TEpollSocket(int socketDescriptor, const QHostAddress &address)
    : deleting(false), myWorkerCounter(0), pollIn(false), pollOut(false),
      sd(socketDescriptor), uuid(), clientAddr(address)
{
    uuid = QUuid::createUuid().toByteArray();  // not thread safe
    uuid = uuid.mid(1, uuid.length() - 2);
    tSystemDebug("TEpollSocket  id:%s", uuid.data());
}

TEpollSocket::~TEpollSocket()
{
    tSystemDebug("TEpollSocket::destructor");

    close();

    for (auto p : sendBuf) {
        delete p;
    }
    sendBuf.clear();
}

/*!
  Receives data
  @return  0:success  -1:error
 */
int TEpollSocket::recv()
{
    int ret = 0;
    int err = 0;
    int len;

    for (;;) {
        void *buf = getRecvBuffer(recvBufSize);
        errno = 0;
        len = tf_recv(sd, buf, recvBufSize, 0);
        err = errno;

        if (len <= 0) {
            break;
        }

        // Read successfully
        seekRecvBuffer(len);
    }

    if (len < 0 || err > 0) {
        switch (err) {
        case EAGAIN:
            break;

        case ECONNRESET:
            tSystemDebug("Socket disconnected : sd:%d  errno:%d", sd, err);
            ret = -1;
            break;

        default:
            tSystemError("Failed recv : sd:%d  errno:%d  len:%d", sd, err, len);
            ret = -1;
            break;
        }
    }
    return ret;
}

/*!
  Sends data
  @return  0:success  -1:error
 */
int TEpollSocket::send()
{
    if (sendBuf.isEmpty()) {
        pollOut = true;
        return 0;
    }
    pollOut = false;

    if (deleting.load()) {
        return 0;
    }

    int ret = 0;
    int err = 0;
    int len;

    while (!sendBuf.isEmpty()) {
        TSendBuffer *buf = sendBuf.first();
        TAccessLogger &logger = buf->accessLogger();

        err = 0;
        for (;;) {
            len = sendBufSize;
            void *data = buf->getData(len);
            if (len == 0) {
                break;
            }

            errno = 0;
            len = tf_send(sd, data, len, MSG_NOSIGNAL);
            err = errno;

            if (len <= 0) {
                break;
            }

            // Sent successfully
            buf->seekData(len);
            logger.setResponseBytes(logger.responseBytes() + len);
        }

        if (buf->atEnd()) {
            logger.write();  // Writes access log
            delete sendBuf.dequeue(); // delete send-buffer obj
        }

        if (len < 0) {
            switch (err) {
            case EAGAIN:
                break;

            case EPIPE:   // FALL THROUGH
            case ECONNRESET:
                tSystemDebug("Socket disconnected : sd:%d  errno:%d", sd, err);
                logger.setResponseBytes(-1);
                ret = -1;
                break;

            default:
                tSystemError("Failed send : sd:%d  errno:%d  len:%d", sd, err, len);
                logger.setResponseBytes(-1);
                ret = -1;
                break;
            }

            break;
        }
    }
    return ret;
}

void TEpollSocket::enqueueSendData(TSendBuffer *buffer)
{
    sendBuf << buffer;
}

void TEpollSocket::setSocketDescpriter(int socketDescriptor)
{
    sd = socketDescriptor;
}

void TEpollSocket::close()
{
    if (sd > 0) {
        tf_close(sd);
        sd = 0;
    }
}

void TEpollSocket::sendData(const QByteArray &header, QIODevice *body, bool autoRemove, const TAccessLogger &accessLogger)
{
    if (!deleting.load()) {
        TEpoll::instance()->setSendData(this, header, body, autoRemove, accessLogger);
    }
}

void TEpollSocket::sendData(const QByteArray &data)
{
    if (!deleting.load()) {
        TEpoll::instance()->setSendData(this, data);
    }
}

void TEpollSocket::disconnect()
{
    if (!deleting.load())
        TEpoll::instance()->setDisconnect(this);
}

void TEpollSocket::switchToWebSocket(const THttpRequestHeader &header)
{
    if (!deleting.load())
        TEpoll::instance()->setSwitchToWebSocket(this, header);
}

qint64 TEpollSocket::bufferedBytes() const
{
    qint64 ret = 0;
    for (auto &d : sendBuf) {
        ret += d->arrayBuffer.size();
        if (d->bodyFile) {
            ret += d->bodyFile->size();
        }
    }
    return ret;
}

int TEpollSocket::bufferedListCount() const
{
    return sendBuf.count();
}

void TEpollSocket::deleteLater()
{
    tSystemDebug("TEpollSocket::deleteLater  countWorker:%d", (int)myWorkerCounter);
    deleting = true;
    if ((int)myWorkerCounter == 0) {
        QObject::deleteLater();
    }
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "applications/include/makevolume_core.h"

TEST(Applications_Makevolume, indexing_single_entry_array) {
  long unsigned index[1] = {1};
  float array[100] = {5};

  ASSERT_EQ(index[0], indexing(1, array)[0]);
}

TEST(Applications_Makevolume, indexing_simple_array) {
  long unsigned index[5] = {1, 2, 3, 4, 5};
  float array[5] = {5, 6, 7, 8, 9};

  long unsigned* result = indexing(5, array);

  for (int i = 0; i < 5; i++)
    ASSERT_EQ(index[i], result[i]);
}

TEST(Applications_Makevolume, indexing_reverse_array) {
  long unsigned index[4] = {4, 3, 2, 1};
  float array[4] = {1000.97, 234.1, 200, 1.32435};

  long unsigned* result = indexing(4, array);

  for (int i = 0; i < 4; i++)
    ASSERT_EQ(index[i], result[i]);
}
<commit_msg>Added random test<commit_after>#include "gtest/gtest.h"
#include "applications/include/makevolume_core.h"

TEST(Applications_Makevolume, indexing_single_entry_array) {
  long unsigned index[1] = {1};
  float array[100] = {5};

  ASSERT_EQ(index[0], indexing(1, array)[0]);
}

TEST(Applications_Makevolume, indexing_simple_array) {
  long unsigned index[5] = {1, 2, 3, 4, 5};
  float array[5] = {5, 6, 7, 8, 9};

  long unsigned* result = indexing(5, array);

  for (int i = 0; i < 5; i++)
    ASSERT_EQ(index[i], result[i]);
}

TEST(Applications_Makevolume, indexing_reverse_array) {
  long unsigned index[4] = {4, 3, 2, 1};
  float array[4] = {1000.97, 234.1, 200, 1.32435};

  long unsigned* result = indexing(4, array);

  for (int i = 0; i < 4; i++)
    ASSERT_EQ(index[i], result[i]);
}

TEST(Applications_Makevolume, indexing_random_array) {
  long unsigned index[10] = {1, 3, 6, 4, 7, 2, 8, 5, 10, 9};
  float array[10] = {3.34, 8.234, 4.1, 6.1324, 10.354235, 5.12, 7.123, 9.2345, 12.32, 11.0};

  long unsigned* result = indexing(10, array);

  for (int i = 0; i < 10; i++)
    ASSERT_EQ(index[i], result[i]);
}
<|endoftext|>


<commit_before>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Creeper.h"
#include "../World.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/Player.h"

cCreeper::cCreeper(void) :
	super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8),
	m_bIsBlowing(false),
	m_bIsCharged(false),
	m_BurnedWithFlintAndSteel(false),
	m_ExplodingTimer(0)
{
}

void cCreeper::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);

	if (!TargetIsInRange() && !m_BurnedWithFlintAndSteel)
	{
		if (m_bIsBlowing)
		{
			m_ExplodingTimer = 0;
			m_bIsBlowing = false;
			m_World->BroadcastEntityMetadata(*this);
		}
	}
	else
	{
		if (m_bIsBlowing)
		{
			m_ExplodingTimer += 1;
		}

		if ((m_ExplodingTimer == 30) && (GetHealth() > 0.0))  // only explode when not already dead
		{
			m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
			Destroy();  // Just in case we aren't killed by the explosion
		}
	}
}

void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
	if (m_ExplodingTimer == 30)
	{
		// Exploded creepers drop naught but charred flesh, which Minecraft doesn't have
		return;
	}

	unsigned int LootingLevel = 0;
	if (a_Killer != nullptr)
	{
		LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
	}
	AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);

	// If the creeper was killed by a skeleton, add a random music disc drop:
	if (
		(a_Killer != nullptr) &&
		a_Killer->IsProjectile() &&
		((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID))
	{
		class cProjectileCreatorCallback : public cEntityCallback
		{
		public:
			cProjectileCreatorCallback(void) {}

			virtual bool Item(cEntity * a_Entity) override
			{
				if (a_Entity->IsMob() && ((reinterpret_cast<cMonster *>(a_Entity))->GetMobType() == mtSkeleton))
				{
					return true;
				}
				return false;
			}
		} PCC;
		if (GetWorld()->DoWithEntityByID((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID(), PCC))
		{
			AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC));
		}
	}
}

bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	if (!super::DoTakeDamage(a_TDI))
	{
		return false;
	}

	if (a_TDI.DamageType == dtLightning)
	{
		m_bIsCharged = true;
	}

	m_World->BroadcastEntityMetadata(*this);
	return true;
}

bool cCreeper::Attack(std::chrono::milliseconds a_Dt)
{
	UNUSED(a_Dt);

	if (!m_bIsBlowing)
	{
		m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (0.75f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
		m_bIsBlowing = true;
		m_World->BroadcastEntityMetadata(*this);

		return true;
	}
	return false;
}

void cCreeper::OnRightClicked(cPlayer & a_Player)
{
	if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_FLINT_AND_STEEL))
	{
		if (!a_Player.IsGameModeCreative())
		{
			a_Player.UseEquippedItem();
		}
		m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (0.75f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
		m_bIsBlowing = true;
		m_World->BroadcastEntityMetadata(*this);
		m_BurnedWithFlintAndSteel = true;
	}
}

<commit_msg>Fixed creeper calling TargetIsInRange with null m_Target<commit_after>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Creeper.h"
#include "../World.h"
#include "../Entities/ProjectileEntity.h"
#include "../Entities/Player.h"

cCreeper::cCreeper(void) :
	super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8),
	m_bIsBlowing(false),
	m_bIsCharged(false),
	m_BurnedWithFlintAndSteel(false),
	m_ExplodingTimer(0)
{
}

void cCreeper::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);

	if ((m_Target == nullptr) || (!TargetIsInRange() && !m_BurnedWithFlintAndSteel))
	{
		if (m_bIsBlowing)
		{
			m_ExplodingTimer = 0;
			m_bIsBlowing = false;
			m_World->BroadcastEntityMetadata(*this);
		}
	}
	else
	{
		if (m_bIsBlowing)
		{
			m_ExplodingTimer += 1;
		}

		if ((m_ExplodingTimer == 30) && (GetHealth() > 0.0))  // only explode when not already dead
		{
			m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
			Destroy();  // Just in case we aren't killed by the explosion
		}
	}
}

void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
	if (m_ExplodingTimer == 30)
	{
		// Exploded creepers drop naught but charred flesh, which Minecraft doesn't have
		return;
	}

	unsigned int LootingLevel = 0;
	if (a_Killer != nullptr)
	{
		LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
	}
	AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);

	// If the creeper was killed by a skeleton, add a random music disc drop:
	if (
		(a_Killer != nullptr) &&
		a_Killer->IsProjectile() &&
		((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID))
	{
		class cProjectileCreatorCallback : public cEntityCallback
		{
		public:
			cProjectileCreatorCallback(void) {}

			virtual bool Item(cEntity * a_Entity) override
			{
				if (a_Entity->IsMob() && ((reinterpret_cast<cMonster *>(a_Entity))->GetMobType() == mtSkeleton))
				{
					return true;
				}
				return false;
			}
		} PCC;
		if (GetWorld()->DoWithEntityByID((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID(), PCC))
		{
			AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC));
		}
	}
}

bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	if (!super::DoTakeDamage(a_TDI))
	{
		return false;
	}

	if (a_TDI.DamageType == dtLightning)
	{
		m_bIsCharged = true;
	}

	m_World->BroadcastEntityMetadata(*this);
	return true;
}

bool cCreeper::Attack(std::chrono::milliseconds a_Dt)
{
	UNUSED(a_Dt);

	if (!m_bIsBlowing)
	{
		m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (0.75f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
		m_bIsBlowing = true;
		m_World->BroadcastEntityMetadata(*this);

		return true;
	}
	return false;
}

void cCreeper::OnRightClicked(cPlayer & a_Player)
{
	if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_FLINT_AND_STEEL))
	{
		if (!a_Player.IsGameModeCreative())
		{
			a_Player.UseEquippedItem();
		}
		m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (0.75f + (static_cast<float>((GetUniqueID() * 23) % 32)) / 64));
		m_bIsBlowing = true;
		m_World->BroadcastEntityMetadata(*this);
		m_BurnedWithFlintAndSteel = true;
	}
}

<|endoftext|>


<commit_before><commit_msg>core: fix MSA build<commit_after><|endoftext|>


<commit_before>//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

//
// osdep.cc
//
// Provide definition of library functions that are missing on various
// systems.  The only reason this is a .cc file rather than a .c file
// is so that it can include bochs.h.  Bochs.h includes all the required
// system headers, with appropriate #ifdefs for different compilers and
// platforms.
//

#include "bochs.h"

//////////////////////////////////////////////////////////////////////
// Missing library functions.  These should work on any platform
// that needs them.
//////////////////////////////////////////////////////////////////////

#if !BX_HAVE_SNPRINTF
/* XXX use real snprintf */
/* if they don't have snprintf, just use sprintf */
int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vsprintf (s, format, arg);
  va_end (arg);

  return done;
}
#endif  /* !BX_HAVE_SNPRINTF */

#if (!BX_HAVE_STRTOULL && !BX_HAVE_STRTOUQ)
/* taken from glibc-2.2.2: strtod.c, and stripped down a lot.  There are
   still a few leftover references to decimal points and exponents,
   but it works for bases 10 and 16 */

#define RETURN(val,end)							      \
    do { if (endptr != NULL) *endptr = (char *) (end);		      \
	 return val; } while (0)

Bit64u
bx_strtoull (const char *nptr, char **endptr, int baseignore)
{
  int negative;			/* The sign of the number.  */
  int exponent;			/* Exponent of the number.  */

  /* Numbers starting `0X' or `0x' have to be processed with base 16.  */
  int base = 10;

  /* Number of bits currently in result value.  */
  int bits;

  /* Running pointer after the last character processed in the string.  */
  const char *cp, *tp;
  /* Start of significant part of the number.  */
  const char *startp, *start_of_digits;
  /* Total number of digit and number of digits in integer part.  */
  int dig_no;
  /* Contains the last character read.  */
  char c;

  long long n = 0;
  char const *p;

  /* Prepare number representation.  */
  exponent = 0;
  negative = 0;
  bits = 0;

  /* Parse string to get maximal legal prefix.  We need the number of
     characters of the integer part, the fractional part and the exponent.  */
  cp = nptr - 1;
  /* Ignore leading white space.  */
  do
    c = *++cp;
  while (isspace (c));

  /* Get sign of the result.  */
  if (c == '-')
    {
      negative = 1;
      c = *++cp;
    }
  else if (c == '+')
    c = *++cp;

  if (c < '0' || c > '9')
    {
      /* It is really a text we do not recognize.  */
      RETURN (0, nptr);
    }

  /* First look whether we are faced with a hexadecimal number.  */
  if (c == '0' && tolower (cp[1]) == 'x')
    {
      /* Okay, it is a hexa-decimal number.  Remember this and skip
	 the characters.  BTW: hexadecimal numbers must not be
	 grouped.  */
      base = 16;
      cp += 2;
      c = *cp;
    }

  /* Record the start of the digits, in case we will check their grouping.  */
  start_of_digits = startp = cp;

  /* Ignore leading zeroes.  This helps us to avoid useless computations.  */
  while (c == '0')
    c = *++cp;

  /* If no other digit but a '0' is found the result is 0.0.
     Return current read pointer.  */
  if ((c < '0' || c > '9')
      && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
      && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
      && (base != 16 && tolower (c) != 'e'))
    {
      tp = start_of_digits;
      /* If TP is at the start of the digits, there was no correctly
	 grouped prefix of the string; so no number found.  */
      RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
    }

  /* Remember first significant digit and read following characters until the
     decimal point, exponent character or any non-FP number character.  */
  startp = cp;
  dig_no = 0;
  while (1)
    {
      if ((c >= '0' && c <= '9')
	  || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
	++dig_no;
      else
	break;
      c = *++cp;
    }

  /* The whole string is parsed.  Store the address of the next character.  */
  if (endptr)
    *endptr = (char *) cp;

  if (dig_no == 0)
    return 0;

  for (p=start_of_digits; p!=cp; p++) {
    n = n * (long long)base;
    c = tolower (*p);
    c = (c >= 'a') ? (10+c-'a') : c-'0';
    n = n + (long long)c;
    //printf ("after shifting in digit %c, n is %lld\n", *p, n);
  }
  return negative? -n : n;
}
#endif  /* !BX_HAVE_STRTOULL */

#if BX_TEST_STRTOULL_MAIN
/* test driver for strtoull.  Do not compile by default. */
int main (int argc, char **argv)
{
  char buf[256], *endbuf;
  long l;
  long long ll;
  while (1) {
    printf ("Enter a long int: ");
    gets (buf);
    l = strtoul (buf, &endbuf, 10);
    printf ("As a long, %ld\n", l);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
    ll = bx_strtoull (buf, &endbuf, 10);
    printf ("As a long long, %lld\n", ll);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
  }
  return 0;
}
#endif  /* BX_TEST_STRTOULL_MAIN */

#if !BX_HAVE_STRDUP
/* XXX use real strdup */
char *bx_strdup(const char *str)
{
	char *temp;

	temp = malloc(strlen(str));
	sprintf(temp, "%s", str);
	return temp;

	// Well, I'm sure this isn't how strdup is REALLY implemented,
	// but it works...
}
#endif  /* !BX_HAVE_STRDUP */

//////////////////////////////////////////////////////////////////////
// Missing library functions, implemented for MacOS only
//////////////////////////////////////////////////////////////////////

#if BX_WITH_MACOS
// these functions are part of MacBochs.  They are not intended to be
// portable!
#include <Files.h>
#include <Disks.h>

int fd_read(char *buffer, Bit32u offset, Bit32u bytes)
{
	OSErr err;
	IOParam param;

	param.ioRefNum=-5; // Refnum of the floppy disk driver
	param.ioVRefNum=1;
	param.ioPosMode=fsFromStart;
	param.ioPosOffset=offset;
	param.ioBuffer=buffer;
	param.ioReqCount=bytes;
	err = PBReadSync((union ParamBlockRec *)(&param));
	return param.ioActCount;
}

int fd_write(char *buffer, Bit32u offset, Bit32u bytes)
{
	OSErr		err;
	IOParam	param;

	param.ioRefNum=-5; // Refnum of the floppy disk driver
	param.ioVRefNum=1;
	param.ioPosMode=fsFromStart;
	param.ioPosOffset=offset;
	param.ioBuffer=buffer;
	param.ioReqCount=bytes;
	err = PBWriteSync((union ParamBlockRec *)(&param));
	return param.ioActCount;
}

int fd_stat(struct stat *buf)
{
	OSErr		err;
	DrvSts	status;
	int			result;

	result = 0;
	err = DriveStatus(1, &status);
	if (status.diskInPlace <1 || status.diskInPlace > 2)
		result = -1;
	buf->st_mode = S_IFCHR;
	return result;
}
#endif /* BX_WITH_MACOS */
<commit_msg>- Patch from Mike Lerwill <mike@homemjl.freeserve.co.uk>   turn "long long" into Bit64s<commit_after>//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

//
// osdep.cc
//
// Provide definition of library functions that are missing on various
// systems.  The only reason this is a .cc file rather than a .c file
// is so that it can include bochs.h.  Bochs.h includes all the required
// system headers, with appropriate #ifdefs for different compilers and
// platforms.
//

#include "bochs.h"

//////////////////////////////////////////////////////////////////////
// Missing library functions.  These should work on any platform
// that needs them.
//////////////////////////////////////////////////////////////////////

#if !BX_HAVE_SNPRINTF
/* XXX use real snprintf */
/* if they don't have snprintf, just use sprintf */
int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
{
  va_list arg;
  int done;

  va_start (arg, format);
  done = vsprintf (s, format, arg);
  va_end (arg);

  return done;
}
#endif  /* !BX_HAVE_SNPRINTF */

#if (!BX_HAVE_STRTOULL && !BX_HAVE_STRTOUQ)
/* taken from glibc-2.2.2: strtod.c, and stripped down a lot.  There are
   still a few leftover references to decimal points and exponents,
   but it works for bases 10 and 16 */

#define RETURN(val,end)							      \
    do { if (endptr != NULL) *endptr = (char *) (end);		      \
	 return val; } while (0)

Bit64u
bx_strtoull (const char *nptr, char **endptr, int baseignore)
{
  int negative;			/* The sign of the number.  */
  int exponent;			/* Exponent of the number.  */

  /* Numbers starting `0X' or `0x' have to be processed with base 16.  */
  int base = 10;

  /* Number of bits currently in result value.  */
  int bits;

  /* Running pointer after the last character processed in the string.  */
  const char *cp, *tp;
  /* Start of significant part of the number.  */
  const char *startp, *start_of_digits;
  /* Total number of digit and number of digits in integer part.  */
  int dig_no;
  /* Contains the last character read.  */
  char c;

  Bit64s n = 0;
  char const *p;

  /* Prepare number representation.  */
  exponent = 0;
  negative = 0;
  bits = 0;

  /* Parse string to get maximal legal prefix.  We need the number of
     characters of the integer part, the fractional part and the exponent.  */
  cp = nptr - 1;
  /* Ignore leading white space.  */
  do
    c = *++cp;
  while (isspace (c));

  /* Get sign of the result.  */
  if (c == '-')
    {
      negative = 1;
      c = *++cp;
    }
  else if (c == '+')
    c = *++cp;

  if (c < '0' || c > '9')
    {
      /* It is really a text we do not recognize.  */
      RETURN (0, nptr);
    }

  /* First look whether we are faced with a hexadecimal number.  */
  if (c == '0' && tolower (cp[1]) == 'x')
    {
      /* Okay, it is a hexa-decimal number.  Remember this and skip
	 the characters.  BTW: hexadecimal numbers must not be
	 grouped.  */
      base = 16;
      cp += 2;
      c = *cp;
    }

  /* Record the start of the digits, in case we will check their grouping.  */
  start_of_digits = startp = cp;

  /* Ignore leading zeroes.  This helps us to avoid useless computations.  */
  while (c == '0')
    c = *++cp;

  /* If no other digit but a '0' is found the result is 0.0.
     Return current read pointer.  */
  if ((c < '0' || c > '9')
      && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
      && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
      && (base != 16 && tolower (c) != 'e'))
    {
      tp = start_of_digits;
      /* If TP is at the start of the digits, there was no correctly
	 grouped prefix of the string; so no number found.  */
      RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
    }

  /* Remember first significant digit and read following characters until the
     decimal point, exponent character or any non-FP number character.  */
  startp = cp;
  dig_no = 0;
  while (1)
    {
      if ((c >= '0' && c <= '9')
	  || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
	++dig_no;
      else
	break;
      c = *++cp;
    }

  /* The whole string is parsed.  Store the address of the next character.  */
  if (endptr)
    *endptr = (char *) cp;

  if (dig_no == 0)
    return 0;

  for (p=start_of_digits; p!=cp; p++) {
    n = n * (Bit64s)base;
    c = tolower (*p);
    c = (c >= 'a') ? (10+c-'a') : c-'0';
    n = n + (Bit64s)c;
    //printf ("after shifting in digit %c, n is %lld\n", *p, n);
  }
  return negative? -n : n;
}
#endif  /* !BX_HAVE_STRTOULL */

#if BX_TEST_STRTOULL_MAIN
/* test driver for strtoull.  Do not compile by default. */
int main (int argc, char **argv)
{
  char buf[256], *endbuf;
  long l;
  Bit64s ll;
  while (1) {
    printf ("Enter a long int: ");
    gets (buf);
    l = strtoul (buf, &endbuf, 10);
    printf ("As a long, %ld\n", l);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
    ll = bx_strtoull (buf, &endbuf, 10);
    printf ("As a long long, %lld\n", ll);
    printf ("Endbuf is at buf[%d]\n", endbuf-buf);
  }
  return 0;
}
#endif  /* BX_TEST_STRTOULL_MAIN */

#if !BX_HAVE_STRDUP
/* XXX use real strdup */
char *bx_strdup(const char *str)
{
	char *temp;

	temp = malloc(strlen(str));
	sprintf(temp, "%s", str);
	return temp;

	// Well, I'm sure this isn't how strdup is REALLY implemented,
	// but it works...
}
#endif  /* !BX_HAVE_STRDUP */

//////////////////////////////////////////////////////////////////////
// Missing library functions, implemented for MacOS only
//////////////////////////////////////////////////////////////////////

#if BX_WITH_MACOS
// these functions are part of MacBochs.  They are not intended to be
// portable!
#include <Files.h>
#include <Disks.h>

int fd_read(char *buffer, Bit32u offset, Bit32u bytes)
{
	OSErr err;
	IOParam param;

	param.ioRefNum=-5; // Refnum of the floppy disk driver
	param.ioVRefNum=1;
	param.ioPosMode=fsFromStart;
	param.ioPosOffset=offset;
	param.ioBuffer=buffer;
	param.ioReqCount=bytes;
	err = PBReadSync((union ParamBlockRec *)(&param));
	return param.ioActCount;
}

int fd_write(char *buffer, Bit32u offset, Bit32u bytes)
{
	OSErr		err;
	IOParam	param;

	param.ioRefNum=-5; // Refnum of the floppy disk driver
	param.ioVRefNum=1;
	param.ioPosMode=fsFromStart;
	param.ioPosOffset=offset;
	param.ioBuffer=buffer;
	param.ioReqCount=bytes;
	err = PBWriteSync((union ParamBlockRec *)(&param));
	return param.ioActCount;
}

int fd_stat(struct stat *buf)
{
	OSErr		err;
	DrvSts	status;
	int			result;

	result = 0;
	err = DriveStatus(1, &status);
	if (status.diskInPlace <1 || status.diskInPlace > 2)
		result = -1;
	buf->st_mode = S_IFCHR;
	return result;
}
#endif /* BX_WITH_MACOS */
<|endoftext|>


<commit_before>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2021 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef __YLIKUUTIO_CALLBACK_CALLBACK_ENGINE_HPP_INCLUDED
#define __YLIKUUTIO_CALLBACK_CALLBACK_ENGINE_HPP_INCLUDED

#include "input_parameters_and_any_value_to_any_value_callback_with_universe.hpp"
#include "code/ylikuutio/data/any_value.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include standard headers
#include <cstddef> // std::size_t
#include <memory>  // std::make_shared, std::shared_ptr
#include <queue>   // std::queue
#include <string>  // std::string
#include <vector>  // std::vector

namespace yli::ontology
{
    class Universe;
}

namespace yli::callback
{
    class CallbackObject;

    class CallbackEngine
    {
        // `CallbackEngine` is an object that contains some callbacks and hashmaps that are used for input and output parameters.
        // `CallbackEngine` provides a way to create callback chains.
        //
        // Hierarchy of callbacks:
        //
        //     CallbackEngine
        //           ^
        //     CallbackObject
        //           ^
        //   CallbackParameter
        //
        // How to use.
        // 1. Create a new `CallbackEngine`. No callbacks have been
        //    defined yet. Calling `CallbackEngine.execute(nullptr)` at this
        //    point will simply go through an empty vector and
        //    practically won't do anything interesting.
        // 2. Create a new `CallbackObject`, give pointer to the
        //    recently created `CallbackEngine` as input parameter.
        // 3. If the callback has parameter[s], create a new
        //    `CallbackParameter` for each parameter, give `CallbackObject`
        //    as input parameter for the `CallbackParameter` constructor.

        public:
            void bind_callback_object(yli::callback::CallbackObject* const callback_object);

            // constructor.
            CallbackEngine();

            // constructor.
            CallbackEngine(yli::ontology::Universe* const universe);

            // destructor.
            ~CallbackEngine();

            yli::callback::CallbackObject* create_callback_object();
            yli::callback::CallbackObject* create_callback_object(const InputParametersAndAnyValueToAnyValueCallbackWithUniverse callback);

            // execute all callbacks with a parameter.
            std::shared_ptr<yli::data::AnyValue> execute(std::shared_ptr<yli::data::AnyValue> any_value);

            std::size_t get_n_of_return_values() const;
            std::shared_ptr<yli::data::AnyValue> get_nth_return_value(std::size_t n) const;
            std::shared_ptr<yli::data::AnyValue> get_previous_return_value() const;

            yli::ontology::Universe* get_universe() const;

        private:
            // `CallbackEngine` is not an `Entity`.
            // Therefore they are not descendants of the `Universe`.
            // Some `CallbackEngine`s just have a pointer to the `Universe`.
            yli::ontology::Universe* universe { nullptr };

            // this method sets a callback object pointer.
            void set_callback_object_pointer(const std::size_t childID, yli::callback::CallbackObject* const child_pointer);

            std::vector<yli::callback::CallbackObject*> callback_object_pointer_vector;
            std::queue<std::size_t> free_callback_objectID_queue;
            std::size_t number_of_callback_objects { 0 };

            std::vector<std::shared_ptr<yli::data::AnyValue>> return_values;
    };
}

#endif
<commit_msg>`CallbackEngine`: make 1 parameter constructor `explicit`.<commit_after>// Ylikuutio - A 3D game and simulation engine.
//
// Copyright (C) 2015-2021 Antti Nuortimo.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

#ifndef __YLIKUUTIO_CALLBACK_CALLBACK_ENGINE_HPP_INCLUDED
#define __YLIKUUTIO_CALLBACK_CALLBACK_ENGINE_HPP_INCLUDED

#include "input_parameters_and_any_value_to_any_value_callback_with_universe.hpp"
#include "code/ylikuutio/data/any_value.hpp"
#include "code/ylikuutio/hierarchy/hierarchy_templates.hpp"

// Include standard headers
#include <cstddef> // std::size_t
#include <memory>  // std::make_shared, std::shared_ptr
#include <queue>   // std::queue
#include <string>  // std::string
#include <vector>  // std::vector

namespace yli::ontology
{
    class Universe;
}

namespace yli::callback
{
    class CallbackObject;

    class CallbackEngine
    {
        // `CallbackEngine` is an object that contains some callbacks and hashmaps that are used for input and output parameters.
        // `CallbackEngine` provides a way to create callback chains.
        //
        // Hierarchy of callbacks:
        //
        //     CallbackEngine
        //           ^
        //     CallbackObject
        //           ^
        //   CallbackParameter
        //
        // How to use.
        // 1. Create a new `CallbackEngine`. No callbacks have been
        //    defined yet. Calling `CallbackEngine.execute(nullptr)` at this
        //    point will simply go through an empty vector and
        //    practically won't do anything interesting.
        // 2. Create a new `CallbackObject`, give pointer to the
        //    recently created `CallbackEngine` as input parameter.
        // 3. If the callback has parameter[s], create a new
        //    `CallbackParameter` for each parameter, give `CallbackObject`
        //    as input parameter for the `CallbackParameter` constructor.

        public:
            void bind_callback_object(yli::callback::CallbackObject* const callback_object);

            // constructor.
            CallbackEngine();

            // constructor.
            explicit CallbackEngine(yli::ontology::Universe* const universe);

            // destructor.
            ~CallbackEngine();

            yli::callback::CallbackObject* create_callback_object();
            yli::callback::CallbackObject* create_callback_object(const InputParametersAndAnyValueToAnyValueCallbackWithUniverse callback);

            // execute all callbacks with a parameter.
            std::shared_ptr<yli::data::AnyValue> execute(std::shared_ptr<yli::data::AnyValue> any_value);

            std::size_t get_n_of_return_values() const;
            std::shared_ptr<yli::data::AnyValue> get_nth_return_value(std::size_t n) const;
            std::shared_ptr<yli::data::AnyValue> get_previous_return_value() const;

            yli::ontology::Universe* get_universe() const;

        private:
            // `CallbackEngine` is not an `Entity`.
            // Therefore they are not descendants of the `Universe`.
            // Some `CallbackEngine`s just have a pointer to the `Universe`.
            yli::ontology::Universe* universe { nullptr };

            // this method sets a callback object pointer.
            void set_callback_object_pointer(const std::size_t childID, yli::callback::CallbackObject* const child_pointer);

            std::vector<yli::callback::CallbackObject*> callback_object_pointer_vector;
            std::queue<std::size_t> free_callback_objectID_queue;
            std::size_t number_of_callback_objects { 0 };

            std::vector<std::shared_ptr<yli::data::AnyValue>> return_values;
    };
}

#endif
<|endoftext|>