<commit_before>#include <cstdlib> // srand
#include <ctime> // time

#include <improbable/standard_library.h>
#include <improbable/worker.h>
#include <shoveler.h>

#include "canvas.h"
#include "chunk.h"
#include "connect.h"
#include "drawable.h"
#include "interest.h"
#include "light.h"
#include "material.h"
#include "metadata.h"
#include "model.h"
#include "position.h"
#include "resource.h"
#include "texture.h"
#include "tile_sprite.h"
#include "tile_sprite_animation.h"
#include "tilemap.h"
#include "tilemap_tiles.h"
#include "tileset.h"

extern "C" {
#include <shoveler/camera/perspective.h>
#include <shoveler/resources/image_png.h>
#include <shoveler/view/client.h>
#include <shoveler/view/resources.h>
#include <shoveler/constants.h>
#include <shoveler/game.h>
#include <shoveler/global.h>
#include <shoveler/log.h>
#include <shoveler/resources.h>
#include <shoveler/scene.h>
#include <shoveler/view.h>
}

using improbable::ComponentInterest;
using improbable::EntityAcl;
using improbable::Interest;
using improbable::Metadata;
using improbable::Persistence;
using improbable::Position;
using shoveler::Bootstrap;
using shoveler::Canvas;
using shoveler::Chunk;
using shoveler::Client;
using shoveler::Drawable;
using shoveler::Light;
using shoveler::LightType;
using shoveler::Material;
using shoveler::Model;
using shoveler::Resource;
using shoveler::Texture;
using shoveler::Tilemap;
using shoveler::TilemapTiles;
using shoveler::Tileset;
using shoveler::TileSprite;
using shoveler::TileSpriteAnimation;
using worker::Connection;
using worker::ConnectionParameters;
using worker::EntityId;

using CreateClientEntity = Bootstrap::Commands::CreateClientEntity;
using ClientPing = Bootstrap::Commands::ClientPing;
using ClientSpawnCube = Bootstrap::Commands::ClientSpawnCube;

struct ClientPingTickContext {
	Connection *connection;
	EntityId bootstrapEntityId;
	EntityId clientEntityId;
};

struct MouseButtonEventContext {
	Connection *connection;
	ShovelerCamera *camera;
	EntityId *bootstrapEntityId;
	EntityId *clientEntityId;
};

struct ViewDependencyCallbackContext {
	bool viewDependenciesUpdated;
};

static const int64_t clientPingTimeoutMs = 1000;

static void updateGame(ShovelerGame *game, double dt);
static void clientPingTick(void *clientPingTickContextPointer);
static void mouseButtonEvent(ShovelerInput *input, int button, int action, int mods, void *mouseButtonEventContextPointer);
static void viewDependencyCallbackFunction(ShovelerView *view, const ShovelerViewQualifiedComponent *dependencySource, const ShovelerViewQualifiedComponent *dependencyTarget, bool added, void *contextPointer);
static void updateInterest(Connection& connection, EntityId clientEntityId, ShovelerView *view);

int main(int argc, char **argv) {
	srand(time(NULL));

	ShovelerGameWindowSettings windowSettings;
	windowSettings.windowTitle = "ShovelerClient";
	windowSettings.fullscreen = false;
	windowSettings.vsync = true;
	windowSettings.samples = 4;
	windowSettings.windowedWidth = 640;
	windowSettings.windowedHeight = 480;

	ShovelerGameControllerSettings controllerSettings;
	controllerSettings.position = shovelerVector3(0, 0, -1);
	controllerSettings.direction = shovelerVector3(0, 0, 1);
	controllerSettings.up = shovelerVector3(0, 1, 0);
	controllerSettings.moveFactor = 2.0f;
	controllerSettings.tiltFactor = 0.0005f;

	float fov = 2.0f * SHOVELER_PI * 50.0f / 360.0f;
	float aspectRatio = (float) windowSettings.windowedWidth / windowSettings.windowedHeight;

	ShovelerCoordinateMapping positionMappingX = SHOVELER_COORDINATE_MAPPING_NEGATIVE_X;
	ShovelerCoordinateMapping positionMappingY = SHOVELER_COORDINATE_MAPPING_POSITIVE_Y;
	ShovelerCoordinateMapping positionMappingZ = SHOVELER_COORDINATE_MAPPING_POSITIVE_Z;

	shovelerLogInit("shoveler-spatialos/workers/cmake/", SHOVELER_LOG_LEVEL_INFO_UP, stdout);
	shovelerGlobalInit();

	if (argc != 1 && argc != 2 && argc != 4) {
		shovelerLogError("Usage:\n\t%s\n\t%s <launcher link>\n\t%s <worker ID> <hostname> <port>", argv[0], argv[0]);
		return EXIT_FAILURE;
	}

	ShovelerCamera *camera = shovelerCameraPerspectiveCreate(controllerSettings.position, controllerSettings.direction, controllerSettings.up, fov, aspectRatio, 0.01, 1000);

	ShovelerGame *game = shovelerGameCreate(camera, updateGame, &windowSettings, &controllerSettings);
	if(game == NULL) {
		return EXIT_FAILURE;
	}
	ShovelerView *view = game->view;

	const worker::ComponentRegistry& components = worker::Components<
		Bootstrap,
		Canvas,
		Chunk,
		Client,
		Drawable,
		EntityAcl,
		Interest,
		Light,
		Metadata,
		Material,
		Model,
		Persistence,
		Position,
		Resource,
		Texture,
		Tilemap,
		TilemapTiles,
		Tileset,
		TileSprite,
        TileSpriteAnimation>{};

	ConnectionParameters connectionParameters;
	connectionParameters.WorkerType = "ShovelerClient";
	connectionParameters.Network.ConnectionType = worker::NetworkConnectionType::kTcp;

	worker::Option<Connection> connectionOption = connect(argc, argv, connectionParameters, components);
	if(!connectionOption || !connectionOption->IsConnected()) {
		return EXIT_FAILURE;
	}
	Connection& connection = *connectionOption;
	shovelerLogInfo("Connected to SpatialOS deployment!");

	worker::Dispatcher dispatcher{components};
	bool disconnected = false;
	EntityId bootstrapEntityId = 0;
	EntityId clientEntityId = 0;
	ClientPingTickContext clientPingTickContext;
	ViewDependencyCallbackContext viewDependencyCallbackContext{false};
	ShovelerExecutorCallback *clientPingTickCallback = NULL;
	bool clientInterestAuthoritative = false;

	MouseButtonEventContext mouseButtonEventContext{&connection, game->camera, &bootstrapEntityId, &clientEntityId};
	ShovelerInputMouseButtonCallback *mouseButtonCallback = shovelerInputAddMouseButtonCallback(game->input, mouseButtonEvent, &mouseButtonEventContext);

	shovelerCameraPerspectiveAttachController(camera, game->controller);

	ShovelerResources *resources = shovelerResourcesCreate(/* TODO: on demand resource loading */ NULL, NULL);
	shovelerResourcesImagePngRegister(resources);

	shovelerViewAddDependencyCallback(view, viewDependencyCallbackFunction, &viewDependencyCallbackContext);
	shovelerViewSetTarget(view, shovelerViewResourcesTargetName, resources);

	dispatcher.OnDisconnect([&](const worker::DisconnectOp& op) {
		shovelerLogError("Disconnected from SpatialOS: %s", op.Reason.c_str());
		disconnected = true;
	});

	dispatcher.OnMetrics([&](const worker::MetricsOp& op) {
		auto metrics = op.Metrics;
		connection.SendMetrics(metrics);
	});

	dispatcher.OnLogMessage([&](const worker::LogMessageOp& op) {
		switch(op.Level) {
			case worker::LogLevel::kDebug:
				shovelerLogTrace(op.Message.c_str());
				break;
			case worker::LogLevel::kInfo:
				shovelerLogInfo(op.Message.c_str());
				break;
			case worker::LogLevel::kWarn:
				shovelerLogWarning(op.Message.c_str());
				break;
			case worker::LogLevel::kError:
				shovelerLogError(op.Message.c_str());
				break;
			case worker::LogLevel::kFatal:
				shovelerLogError(op.Message.c_str());
				std::terminate();
			default:
				shovelerLogWarning("SpatialOS SDK logged message with unknown log level %d: %s", op.Level, op.Message.c_str());
				break;
		}
	});

	dispatcher.OnAddEntity([&](const worker::AddEntityOp& op) {
		shovelerLogInfo("Adding entity %lld.", op.EntityId);
		shovelerViewAddEntity(view, op.EntityId);
	});

	dispatcher.OnRemoveEntity([&](const worker::RemoveEntityOp& op) {
		shovelerLogInfo("Removing entity %lld.", op.EntityId);
		shovelerViewRemoveEntity(view, op.EntityId);
	});

	dispatcher.OnAddComponent<Client>([&](const worker::AddComponentOp<Client>& op) {
		shovelerLogInfo("Adding client to entity %lld.", op.EntityId);
		ShovelerViewEntity *entity = shovelerViewGetEntity(view, op.EntityId);

		ShovelerViewClientConfiguration clientConfiguration;
		clientConfiguration.positionEntityId = op.EntityId;
		clientConfiguration.modelEntityId = op.EntityId;
		clientConfiguration.disableModelVisibility = true;
		shovelerViewEntityAddClient(entity, &clientConfiguration);
	});

	dispatcher.OnAuthorityChange<Client>([&](const worker::AuthorityChangeOp& op) {
		shovelerLogInfo("Changing client authority for entity %lld to %d.", op.EntityId, op.Authority);
		ShovelerViewEntity *entity = shovelerViewGetEntity(view, op.EntityId);
		if (op.Authority == worker::Authority::kAuthoritative) {
			shovelerViewEntityDelegateClient(entity);
			clientPingTickContext = ClientPingTickContext{&connection, bootstrapEntityId, op.EntityId};
			clientPingTickCallback = shovelerExecutorSchedulePeriodic(game->updateExecutor, 0, clientPingTimeoutMs, clientPingTick, &clientPingTickContext);
			clientEntityId = op.EntityId;
		} else if (op.Authority == worker::Authority::kNotAuthoritative) {
			shovelerViewEntityUndelegateClient(entity);
			shovelerExecutorRemoveCallback(game->updateExecutor, clientPingTickCallback);
			clientEntityId = 0;
		}
	});

	dispatcher.OnRemoveComponent<Client>([&](const worker::RemoveComponentOp& op) {
		shovelerLogInfo("Removing client from entity %lld.", op.EntityId);
		ShovelerViewEntity *entity = shovelerViewGetEntity(view, op.EntityId);
		shovelerViewEntityRemoveClient(entity);
	});

	dispatcher.OnAuthorityChange<Interest>([&](const worker::AuthorityChangeOp& op) {
		if(op.EntityId == clientEntityId) {
			if(op.Authority == worker::Authority::kAuthoritative) {
				shovelerLogInfo("Received authority over interest component of client entity %lld.", op.EntityId);
				clientInterestAuthoritative = true;
				viewDependencyCallbackContext.viewDependenciesUpdated = true;
			} else {
				clientInterestAuthoritative = false;
			}
		}
	});

	worker::query::EntityQuery bootstrapEntityQuery{worker::query::ComponentConstraint{Bootstrap::ComponentId}, worker::query::SnapshotResultType{{{Bootstrap::ComponentId}}}};
	worker::RequestId<worker::EntityQueryRequest> bootstrapQueryRequestId = connection.SendEntityQueryRequest(bootstrapEntityQuery, {});

	dispatcher.OnEntityQueryResponse([&](const worker::EntityQueryResponseOp& op) {
		shovelerLogInfo("Received entity query response for request %u with status code %d.", op.RequestId.Id, op.StatusCode);
		if(op.RequestId == bootstrapQueryRequestId && op.Result.size() > 0) {
			bootstrapEntityId = op.Result.begin()->first;
			shovelerLogInfo("Received bootstrap query response containing entity %lld.", bootstrapEntityId);
			worker::RequestId<worker::OutgoingCommandRequest<CreateClientEntity>> createClientEntityRequestId = connection.SendCommandRequest<CreateClientEntity>(bootstrapEntityId, {}, {});
			shovelerLogInfo("Sent create client entity request with id %u.", createClientEntityRequestId.Id);
		}
	});

	dispatcher.OnCommandResponse<CreateClientEntity>([&](const worker::CommandResponseOp<CreateClientEntity>& op) {
		shovelerLogInfo("Received create client entity command response %u with status code %d.", op.RequestId.Id, op.StatusCode);
	});

	registerPositionCallbacks(connection, dispatcher, view, positionMappingX, positionMappingY, positionMappingZ);
	registerMetadataCallbacks(dispatcher, view);
	registerResourceCallbacks(dispatcher, view);
	registerTextureCallbacks(dispatcher, view);
	registerTilesetCallbacks(dispatcher, view);
	registerTilemapTilesCallbacks(dispatcher, view);
	registerTilemapCallbacks(dispatcher, view);
	registerTileSpriteCallbacks(dispatcher, view);
	registerTileSpriteAnimationCallbacks(dispatcher, view);
	registerCanvasCallbacks(dispatcher, view);
	registerChunkCallbacks(dispatcher, view);
	registerDrawableCallbacks(dispatcher, view);
	registerMaterialCallbacks(dispatcher, view);
	registerModelCallbacks(dispatcher, view);
	registerLightCallbacks(dispatcher, view);

	while(shovelerGameIsRunning(game) && !disconnected) {
		viewDependencyCallbackContext.viewDependenciesUpdated = false;

		dispatcher.Process(connection.GetOpList(0));
		shovelerGameRenderFrame(game);

		if(clientInterestAuthoritative && viewDependencyCallbackContext.viewDependenciesUpdated) {
			updateInterest(connection, clientEntityId, view);
		}
	}
	shovelerLogInfo("Exiting main loop, goodbye.");

	shovelerInputRemoveMouseButtonCallback(game->input, mouseButtonCallback);

	shovelerCameraPerspectiveDetachController(camera);
	shovelerGameFree(game);
	shovelerResourcesFree(resources);
	shovelerCameraFree(camera);
	shovelerGlobalUninit();
	shovelerLogTerminate();

	return EXIT_SUCCESS;
}

static void updateGame(ShovelerGame *game, double dt)
{
	shovelerCameraUpdateView(game->camera);
}

static void clientPingTick(void *clientPingTickContextPointer)
{
	ClientPingTickContext *context = (ClientPingTickContext *) clientPingTickContextPointer;
	context->connection->SendCommandRequest<ClientPing>(context->bootstrapEntityId, {context->clientEntityId}, {});
}

static void mouseButtonEvent(ShovelerInput *input, int button, int action, int mods, void *mouseButtonEventContextPointer)
{
	MouseButtonEventContext *context = (MouseButtonEventContext *) mouseButtonEventContextPointer;

	if(button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
		shovelerLogInfo("Sending client cube spawn command...");
		ShovelerCameraPerspective *perspectiveCamera = (ShovelerCameraPerspective *) context->camera->data;
		context->connection->SendCommandRequest<ClientSpawnCube>(*context->bootstrapEntityId, {*context->clientEntityId, {-perspectiveCamera->direction.values[0], perspectiveCamera->direction.values[1], perspectiveCamera->direction.values[2]}, {0.0f, 0.0f, 0.0f}}, {});
	}
}

static void viewDependencyCallbackFunction(ShovelerView *view, const ShovelerViewQualifiedComponent *dependencySource, const ShovelerViewQualifiedComponent *dependencyTarget, bool added, void *contextPointer)
{
	ViewDependencyCallbackContext *context = (ViewDependencyCallbackContext *) contextPointer;
	context->viewDependenciesUpdated = true;
}

static void updateInterest(Connection& connection, EntityId clientEntityId, ShovelerView *view)
{
	ComponentInterest interest = computeViewInterest(view);

	Interest::Update interestUpdate;
	interestUpdate.set_component_interest({{Client::ComponentId, interest}});
	connection.SendComponentUpdate<Interest>(clientEntityId, interestUpdate);

	shovelerLogInfo("Sent interest update with %zu queries.", interest.queries().size());
}
<commit_msg>updated client to use latest shoveler camera creation API<commit_after>#include <cstdlib> // srand
#include <ctime> // time

#include <improbable/standard_library.h>
#include <improbable/worker.h>
#include <shoveler.h>

#include "canvas.h"
#include "chunk.h"
#include "connect.h"
#include "drawable.h"
#include "interest.h"
#include "light.h"
#include "material.h"
#include "metadata.h"
#include "model.h"
#include "position.h"
#include "resource.h"
#include "texture.h"
#include "tile_sprite.h"
#include "tile_sprite_animation.h"
#include "tilemap.h"
#include "tilemap_tiles.h"
#include "tileset.h"

extern "C" {
#include <shoveler/camera/perspective.h>
#include <shoveler/resources/image_png.h>
#include <shoveler/view/client.h>
#include <shoveler/view/resources.h>
#include <shoveler/constants.h>
#include <shoveler/game.h>
#include <shoveler/global.h>
#include <shoveler/log.h>
#include <shoveler/resources.h>
#include <shoveler/scene.h>
#include <shoveler/view.h>
}

using improbable::ComponentInterest;
using improbable::EntityAcl;
using improbable::Interest;
using improbable::Metadata;
using improbable::Persistence;
using improbable::Position;
using shoveler::Bootstrap;
using shoveler::Canvas;
using shoveler::Chunk;
using shoveler::Client;
using shoveler::Drawable;
using shoveler::Light;
using shoveler::LightType;
using shoveler::Material;
using shoveler::Model;
using shoveler::Resource;
using shoveler::Texture;
using shoveler::Tilemap;
using shoveler::TilemapTiles;
using shoveler::Tileset;
using shoveler::TileSprite;
using shoveler::TileSpriteAnimation;
using worker::Connection;
using worker::ConnectionParameters;
using worker::EntityId;

using CreateClientEntity = Bootstrap::Commands::CreateClientEntity;
using ClientPing = Bootstrap::Commands::ClientPing;
using ClientSpawnCube = Bootstrap::Commands::ClientSpawnCube;

struct ClientPingTickContext {
	Connection *connection;
	EntityId bootstrapEntityId;
	EntityId clientEntityId;
};

struct MouseButtonEventContext {
	Connection *connection;
	ShovelerCamera *camera;
	EntityId *bootstrapEntityId;
	EntityId *clientEntityId;
};

struct ViewDependencyCallbackContext {
	bool viewDependenciesUpdated;
};

static const int64_t clientPingTimeoutMs = 1000;

static void updateGame(ShovelerGame *game, double dt);
static void clientPingTick(void *clientPingTickContextPointer);
static void mouseButtonEvent(ShovelerInput *input, int button, int action, int mods, void *mouseButtonEventContextPointer);
static void viewDependencyCallbackFunction(ShovelerView *view, const ShovelerViewQualifiedComponent *dependencySource, const ShovelerViewQualifiedComponent *dependencyTarget, bool added, void *contextPointer);
static void updateInterest(Connection& connection, EntityId clientEntityId, ShovelerView *view);

int main(int argc, char **argv) {
	srand(time(NULL));

	ShovelerGameWindowSettings windowSettings;
	windowSettings.windowTitle = "ShovelerClient";
	windowSettings.fullscreen = false;
	windowSettings.vsync = true;
	windowSettings.samples = 4;
	windowSettings.windowedWidth = 640;
	windowSettings.windowedHeight = 480;

	ShovelerGameControllerSettings controllerSettings;
	controllerSettings.frame.position = shovelerVector3(0, 0, -1);
	controllerSettings.frame.direction = shovelerVector3(0, 0, 1);
	controllerSettings.frame.up = shovelerVector3(0, 1, 0);
	controllerSettings.moveFactor = 2.0f;
	controllerSettings.tiltFactor = 0.0005f;

	ShovelerProjectionPerspective projection;
	projection.fieldOfViewY = 2.0f * SHOVELER_PI * 50.0f / 360.0f;
	projection.aspectRatio = (float) windowSettings.windowedWidth / windowSettings.windowedHeight;
	projection.nearClippingPlane = 0.01;
	projection.farClippingPlane = 1000;

	ShovelerCoordinateMapping positionMappingX = SHOVELER_COORDINATE_MAPPING_NEGATIVE_X;
	ShovelerCoordinateMapping positionMappingY = SHOVELER_COORDINATE_MAPPING_POSITIVE_Y;
	ShovelerCoordinateMapping positionMappingZ = SHOVELER_COORDINATE_MAPPING_POSITIVE_Z;

	shovelerLogInit("shoveler-spatialos/workers/cmake/", SHOVELER_LOG_LEVEL_INFO_UP, stdout);
	shovelerGlobalInit();

	if (argc != 1 && argc != 2 && argc != 4) {
		shovelerLogError("Usage:\n\t%s\n\t%s <launcher link>\n\t%s <worker ID> <hostname> <port>", argv[0], argv[0]);
		return EXIT_FAILURE;
	}

	ShovelerCamera *camera = shovelerCameraPerspectiveCreate(&controllerSettings.frame, &projection);

	ShovelerGame *game = shovelerGameCreate(camera, updateGame, &windowSettings, &controllerSettings);
	if(game == NULL) {
		return EXIT_FAILURE;
	}
	ShovelerView *view = game->view;

	const worker::ComponentRegistry& components = worker::Components<
		Bootstrap,
		Canvas,
		Chunk,
		Client,
		Drawable,
		EntityAcl,
		Interest,
		Light,
		Metadata,
		Material,
		Model,
		Persistence,
		Position,
		Resource,
		Texture,
		Tilemap,
		TilemapTiles,
		Tileset,
		TileSprite,
        TileSpriteAnimation>{};

	ConnectionParameters connectionParameters;
	connectionParameters.WorkerType = "ShovelerClient";
	connectionParameters.Network.ConnectionType = worker::NetworkConnectionType::kTcp;

	worker::Option<Connection> connectionOption = connect(argc, argv, connectionParameters, components);
	if(!connectionOption || !connectionOption->IsConnected()) {
		return EXIT_FAILURE;
	}
	Connection& connection = *connectionOption;
	shovelerLogInfo("Connected to SpatialOS deployment!");

	worker::Dispatcher dispatcher{components};
	bool disconnected = false;
	EntityId bootstrapEntityId = 0;
	EntityId clientEntityId = 0;
	ClientPingTickContext clientPingTickContext;
	ViewDependencyCallbackContext viewDependencyCallbackContext{false};
	ShovelerExecutorCallback *clientPingTickCallback = NULL;
	bool clientInterestAuthoritative = false;

	MouseButtonEventContext mouseButtonEventContext{&connection, game->camera, &bootstrapEntityId, &clientEntityId};
	ShovelerInputMouseButtonCallback *mouseButtonCallback = shovelerInputAddMouseButtonCallback(game->input, mouseButtonEvent, &mouseButtonEventContext);

	shovelerCameraPerspectiveAttachController(camera, game->controller);

	ShovelerResources *resources = shovelerResourcesCreate(/* TODO: on demand resource loading */ NULL, NULL);
	shovelerResourcesImagePngRegister(resources);

	shovelerViewAddDependencyCallback(view, viewDependencyCallbackFunction, &viewDependencyCallbackContext);
	shovelerViewSetTarget(view, shovelerViewResourcesTargetName, resources);

	dispatcher.OnDisconnect([&](const worker::DisconnectOp& op) {
		shovelerLogError("Disconnected from SpatialOS: %s", op.Reason.c_str());
		disconnected = true;
	});

	dispatcher.OnMetrics([&](const worker::MetricsOp& op) {
		auto metrics = op.Metrics;
		connection.SendMetrics(metrics);
	});

	dispatcher.OnLogMessage([&](const worker::LogMessageOp& op) {
		switch(op.Level) {
			case worker::LogLevel::kDebug:
				shovelerLogTrace(op.Message.c_str());
				break;
			case worker::LogLevel::kInfo:
				shovelerLogInfo(op.Message.c_str());
				break;
			case worker::LogLevel::kWarn:
				shovelerLogWarning(op.Message.c_str());
				break;
			case worker::LogLevel::kError:
				shovelerLogError(op.Message.c_str());
				break;
			case worker::LogLevel::kFatal:
				shovelerLogError(op.Message.c_str());
				std::terminate();
			default:
				shovelerLogWarning("SpatialOS SDK logged message with unknown log level %d: %s", op.Level, op.Message.c_str());
				break;
		}
	});

	dispatcher.OnAddEntity([&](const worker::AddEntityOp& op) {
		shovelerLogInfo("Adding entity %lld.", op.EntityId);
		shovelerViewAddEntity(view, op.EntityId);
	});

	dispatcher.OnRemoveEntity([&](const worker::RemoveEntityOp& op) {
		shovelerLogInfo("Removing entity %lld.", op.EntityId);
		shovelerViewRemoveEntity(view, op.EntityId);
	});

	dispatcher.OnAddComponent<Client>([&](const worker::AddComponentOp<Client>& op) {
		shovelerLogInfo("Adding client to entity %lld.", op.EntityId);
		ShovelerViewEntity *entity = shovelerViewGetEntity(view, op.EntityId);

		ShovelerViewClientConfiguration clientConfiguration;
		clientConfiguration.positionEntityId = op.EntityId;
		clientConfiguration.modelEntityId = op.EntityId;
		clientConfiguration.disableModelVisibility = true;
		shovelerViewEntityAddClient(entity, &clientConfiguration);
	});

	dispatcher.OnAuthorityChange<Client>([&](const worker::AuthorityChangeOp& op) {
		shovelerLogInfo("Changing client authority for entity %lld to %d.", op.EntityId, op.Authority);
		ShovelerViewEntity *entity = shovelerViewGetEntity(view, op.EntityId);
		if (op.Authority == worker::Authority::kAuthoritative) {
			shovelerViewEntityDelegateClient(entity);
			clientPingTickContext = ClientPingTickContext{&connection, bootstrapEntityId, op.EntityId};
			clientPingTickCallback = shovelerExecutorSchedulePeriodic(game->updateExecutor, 0, clientPingTimeoutMs, clientPingTick, &clientPingTickContext);
			clientEntityId = op.EntityId;
		} else if (op.Authority == worker::Authority::kNotAuthoritative) {
			shovelerViewEntityUndelegateClient(entity);
			shovelerExecutorRemoveCallback(game->updateExecutor, clientPingTickCallback);
			clientEntityId = 0;
		}
	});

	dispatcher.OnRemoveComponent<Client>([&](const worker::RemoveComponentOp& op) {
		shovelerLogInfo("Removing client from entity %lld.", op.EntityId);
		ShovelerViewEntity *entity = shovelerViewGetEntity(view, op.EntityId);
		shovelerViewEntityRemoveClient(entity);
	});

	dispatcher.OnAuthorityChange<Interest>([&](const worker::AuthorityChangeOp& op) {
		if(op.EntityId == clientEntityId) {
			if(op.Authority == worker::Authority::kAuthoritative) {
				shovelerLogInfo("Received authority over interest component of client entity %lld.", op.EntityId);
				clientInterestAuthoritative = true;
				viewDependencyCallbackContext.viewDependenciesUpdated = true;
			} else {
				clientInterestAuthoritative = false;
			}
		}
	});

	worker::query::EntityQuery bootstrapEntityQuery{worker::query::ComponentConstraint{Bootstrap::ComponentId}, worker::query::SnapshotResultType{{{Bootstrap::ComponentId}}}};
	worker::RequestId<worker::EntityQueryRequest> bootstrapQueryRequestId = connection.SendEntityQueryRequest(bootstrapEntityQuery, {});

	dispatcher.OnEntityQueryResponse([&](const worker::EntityQueryResponseOp& op) {
		shovelerLogInfo("Received entity query response for request %u with status code %d.", op.RequestId.Id, op.StatusCode);
		if(op.RequestId == bootstrapQueryRequestId && op.Result.size() > 0) {
			bootstrapEntityId = op.Result.begin()->first;
			shovelerLogInfo("Received bootstrap query response containing entity %lld.", bootstrapEntityId);
			worker::RequestId<worker::OutgoingCommandRequest<CreateClientEntity>> createClientEntityRequestId = connection.SendCommandRequest<CreateClientEntity>(bootstrapEntityId, {}, {});
			shovelerLogInfo("Sent create client entity request with id %u.", createClientEntityRequestId.Id);
		}
	});

	dispatcher.OnCommandResponse<CreateClientEntity>([&](const worker::CommandResponseOp<CreateClientEntity>& op) {
		shovelerLogInfo("Received create client entity command response %u with status code %d.", op.RequestId.Id, op.StatusCode);
	});

	registerPositionCallbacks(connection, dispatcher, view, positionMappingX, positionMappingY, positionMappingZ);
	registerMetadataCallbacks(dispatcher, view);
	registerResourceCallbacks(dispatcher, view);
	registerTextureCallbacks(dispatcher, view);
	registerTilesetCallbacks(dispatcher, view);
	registerTilemapTilesCallbacks(dispatcher, view);
	registerTilemapCallbacks(dispatcher, view);
	registerTileSpriteCallbacks(dispatcher, view);
	registerTileSpriteAnimationCallbacks(dispatcher, view);
	registerCanvasCallbacks(dispatcher, view);
	registerChunkCallbacks(dispatcher, view);
	registerDrawableCallbacks(dispatcher, view);
	registerMaterialCallbacks(dispatcher, view);
	registerModelCallbacks(dispatcher, view);
	registerLightCallbacks(dispatcher, view);

	while(shovelerGameIsRunning(game) && !disconnected) {
		viewDependencyCallbackContext.viewDependenciesUpdated = false;

		dispatcher.Process(connection.GetOpList(0));
		shovelerGameRenderFrame(game);

		if(clientInterestAuthoritative && viewDependencyCallbackContext.viewDependenciesUpdated) {
			updateInterest(connection, clientEntityId, view);
		}
	}
	shovelerLogInfo("Exiting main loop, goodbye.");

	shovelerInputRemoveMouseButtonCallback(game->input, mouseButtonCallback);

	shovelerCameraPerspectiveDetachController(camera);
	shovelerGameFree(game);
	shovelerResourcesFree(resources);
	shovelerCameraFree(camera);
	shovelerGlobalUninit();
	shovelerLogTerminate();

	return EXIT_SUCCESS;
}

static void updateGame(ShovelerGame *game, double dt)
{
	shovelerCameraUpdateView(game->camera);
}

static void clientPingTick(void *clientPingTickContextPointer)
{
	ClientPingTickContext *context = (ClientPingTickContext *) clientPingTickContextPointer;
	context->connection->SendCommandRequest<ClientPing>(context->bootstrapEntityId, {context->clientEntityId}, {});
}

static void mouseButtonEvent(ShovelerInput *input, int button, int action, int mods, void *mouseButtonEventContextPointer)
{
	MouseButtonEventContext *context = (MouseButtonEventContext *) mouseButtonEventContextPointer;

	if(button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
		shovelerLogInfo("Sending client cube spawn command...");
		ShovelerCameraPerspective *perspectiveCamera = (ShovelerCameraPerspective *) context->camera->data;
		context->connection->SendCommandRequest<ClientSpawnCube>(*context->bootstrapEntityId, {*context->clientEntityId, {-perspectiveCamera->direction.values[0], perspectiveCamera->direction.values[1], perspectiveCamera->direction.values[2]}, {0.0f, 0.0f, 0.0f}}, {});
	}
}

static void viewDependencyCallbackFunction(ShovelerView *view, const ShovelerViewQualifiedComponent *dependencySource, const ShovelerViewQualifiedComponent *dependencyTarget, bool added, void *contextPointer)
{
	ViewDependencyCallbackContext *context = (ViewDependencyCallbackContext *) contextPointer;
	context->viewDependenciesUpdated = true;
}

static void updateInterest(Connection& connection, EntityId clientEntityId, ShovelerView *view)
{
	ComponentInterest interest = computeViewInterest(view);

	Interest::Update interestUpdate;
	interestUpdate.set_component_interest({{Client::ComponentId, interest}});
	connection.SendComponentUpdate<Interest>(clientEntityId, interestUpdate);

	shovelerLogInfo("Sent interest update with %zu queries.", interest.queries().size());
}
<|endoftext|>


<commit_before>/*=============================================================================

  Library: CppMicroServices

  Copyright (c) The CppMicroServices developers. See the COPYRIGHT
  file at the top-level directory of this distribution and at
  https://github.com/saschazelzer/CppMicroServices/COPYRIGHT .

  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 "usLDAPFilter.h"
#include "usLDAPExpr_p.h"
#include "usServicePropertiesImpl_p.h"
#include "usServiceReference.h"
#include "usServiceReferenceBasePrivate.h"

#include <stdexcept>

namespace us {

class LDAPFilterData : public SharedData
{
public:

  LDAPFilterData() : ldapExpr()
  {}

  LDAPFilterData(const std::string& filter)
    : ldapExpr(filter)
  {}

  LDAPFilterData(const LDAPFilterData& other)
    : SharedData(other), ldapExpr(other.ldapExpr)
  {}

  LDAPExpr ldapExpr;
};

LDAPFilter::LDAPFilter()
  : d(0)
{
}

LDAPFilter::LDAPFilter(const std::string& filter)
  : d(0)
{
  try
  {
    d = new LDAPFilterData(filter);
  }
  catch (const std::exception& e)
  {
    throw std::invalid_argument(e.what());
  }
}

LDAPFilter::LDAPFilter(const LDAPFilter& other)
  : d(other.d)
{
}

LDAPFilter::~LDAPFilter()
{
}

LDAPFilter::operator bool() const
{
  return d;
}

bool LDAPFilter::Match(const ServiceReferenceBase& reference) const
{
  return d->ldapExpr.Evaluate(reference.d.load()->GetProperties(), true);
}

bool LDAPFilter::Match(const ServiceProperties& dictionary) const
{
  return d->ldapExpr.Evaluate(ServicePropertiesHandle(ServicePropertiesImpl(dictionary), false), false);
}

bool LDAPFilter::MatchCase(const ServiceProperties& dictionary) const
{
  return d->ldapExpr.Evaluate(ServicePropertiesHandle(ServicePropertiesImpl(dictionary), false), true);
}

std::string LDAPFilter::ToString() const
{
  return d->ldapExpr.ToString();
}

bool LDAPFilter::operator==(const LDAPFilter& other) const
{
  return d->ldapExpr.ToString() == other.d->ldapExpr.ToString();
}

LDAPFilter& LDAPFilter::operator=(const LDAPFilter& filter)
{
  d = filter.d;

  return *this;
}

std::ostream& operator<<(std::ostream& os, const LDAPFilter& filter)
{
  return os << filter.ToString();
}

}
<commit_msg>Fixed Windows performance warning.<commit_after>/*=============================================================================

  Library: CppMicroServices

  Copyright (c) The CppMicroServices developers. See the COPYRIGHT
  file at the top-level directory of this distribution and at
  https://github.com/saschazelzer/CppMicroServices/COPYRIGHT .

  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 "usLDAPFilter.h"
#include "usLDAPExpr_p.h"
#include "usServicePropertiesImpl_p.h"
#include "usServiceReference.h"
#include "usServiceReferenceBasePrivate.h"

#include <stdexcept>

namespace us {

class LDAPFilterData : public SharedData
{
public:

  LDAPFilterData() : ldapExpr()
  {}

  LDAPFilterData(const std::string& filter)
    : ldapExpr(filter)
  {}

  LDAPFilterData(const LDAPFilterData& other)
    : SharedData(other), ldapExpr(other.ldapExpr)
  {}

  LDAPExpr ldapExpr;
};

LDAPFilter::LDAPFilter()
  : d(0)
{
}

LDAPFilter::LDAPFilter(const std::string& filter)
  : d(0)
{
  try
  {
    d = new LDAPFilterData(filter);
  }
  catch (const std::exception& e)
  {
    throw std::invalid_argument(e.what());
  }
}

LDAPFilter::LDAPFilter(const LDAPFilter& other)
  : d(other.d)
{
}

LDAPFilter::~LDAPFilter()
{
}

LDAPFilter::operator bool() const
{
  return d != nullptr;
}

bool LDAPFilter::Match(const ServiceReferenceBase& reference) const
{
  return d->ldapExpr.Evaluate(reference.d.load()->GetProperties(), true);
}

bool LDAPFilter::Match(const ServiceProperties& dictionary) const
{
  return d->ldapExpr.Evaluate(ServicePropertiesHandle(ServicePropertiesImpl(dictionary), false), false);
}

bool LDAPFilter::MatchCase(const ServiceProperties& dictionary) const
{
  return d->ldapExpr.Evaluate(ServicePropertiesHandle(ServicePropertiesImpl(dictionary), false), true);
}

std::string LDAPFilter::ToString() const
{
  return d->ldapExpr.ToString();
}

bool LDAPFilter::operator==(const LDAPFilter& other) const
{
  return d->ldapExpr.ToString() == other.d->ldapExpr.ToString();
}

LDAPFilter& LDAPFilter::operator=(const LDAPFilter& filter)
{
  d = filter.d;

  return *this;
}

std::ostream& operator<<(std::ostream& os, const LDAPFilter& filter)
{
  return os << filter.ToString();
}

}
<|endoftext|>


<commit_before>// test explicit generation of a simple template function

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

template <class T> T my_max(T a, T b) {
    return a > b ? a : b;
}

template int my_max(int a, int b);

int main(int argc, char *argv[]) {
    assert(argc == 3);
    int a = atoi(argv[1]);
    int b = atoi(argv[2]);
    printf("%d %d %d\n", a, b, my_max<int>(a, b));
    return 0;
}
<commit_msg>refs #6184 put an assert in a simple template test<commit_after>// test explicit generation of a simple template function

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <assert.h>

template <class T> T my_max(T a, T b) {
    return a > b ? a : b;
}

template int my_max(int a, int b);

int main(int argc, char *argv[]) {
    assert(argc == 3);
    int a = atoi(argv[1]);
    int b = atoi(argv[2]);
    int m = my_max<int>(a, b);
    printf("%d %d %d\n", a, b, m);
    assert(m == (a > b ? a : b));
    return 0;
}
<|endoftext|>


<commit_before>/* JEBTest: A C++ unit testing framework
 * Copyright 2013 Jan Erik Breimo
 * All rights reserved.
 *
 * This file is distributed under the BSD License.
 * License text is included with the source distribution.
 */
#ifndef JEBTEST_TEST_FORMATTERS_HPP
#define JEBTEST_TEST_FORMATTERS_HPP

#include <sstream>

namespace JEBTest {

template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, const std::pair<T, U>& p)
{
    return os << "{" << p.first << ", " << p.second << "}";
}

std::ostream& operator<<(std::ostream& os, const std::wstring& s);
std::ostream& operator<<(std::ostream& os, const wchar_t* s);

template <typename T, typename U>
std::string formatComparison(const T& t, const char* tName,
                             const U& u, const char* uName,
                             const char* operat)
{
    std::ostringstream ss;
    ss.precision(17);
    ss << tName << " " << operat << " " << uName
       << ":  \"" << t << "\" " << operat << " \"" << u << "\".";
    return ss.str();
}

template <typename T, typename U>
std::string formatComparison(T* t, const char* tName,
                             U* u, const char* uName,
                             const char* operat)
{
    std::ostringstream ss;
    ss << tName << " " << operat << " " << uName
       << ":  \"" << (t ? t : (void*)t) << "\" " << operat << " \""
       << (u ? u : (void*)u) << "\".";
    return ss.str();
}

}

#endif
<commit_msg>Improved(?) output when assertions fail.<commit_after>/* JEBTest: A C++ unit testing framework
 * Copyright 2013 Jan Erik Breimo
 * All rights reserved.
 *
 * This file is distributed under the BSD License.
 * License text is included with the source distribution.
 */
#ifndef JEBTEST_TEST_FORMATTERS_HPP
#define JEBTEST_TEST_FORMATTERS_HPP

#include <sstream>
#include <typeinfo>

namespace JEBTest {

template <typename T, typename U>
std::ostream& operator<<(std::ostream& os, const std::pair<T, U>& p)
{
    return os << "{" << p.first << ", " << p.second << "}";
}

std::ostream& operator<<(std::ostream& os, const std::wstring& s);
std::ostream& operator<<(std::ostream& os, const wchar_t* s);

template <typename T, typename U>
std::string formatComparison(const T& t, const char* tName,
                             const U& u, const char* uName,
                             const char* operat)
{
    std::ostringstream ss;
    ss.precision(17);
    ss << tName << " " << operat << " " << uName
       << ":  \"" << t << "\" " << operat << " \"" << u << "\".";
    return ss.str();
}

template <typename T, typename U>
std::string formatComparison(T* t, const char* tName,
                             U* u, const char* uName,
                             const char* operat)
{
    std::ostringstream ss;
    ss << tName << " " << operat << " " << uName
       << ":  (" << typeid(T*).name() << ")\"";
    if (t)
        ss << t;
    else
        ss << "nullptr";
    ss << "\" " << operat << " (" << typeid(U*).name() << ")\"";
    if (u)
        ss << u;
    else
        ss << "nullptr";
    ss << "\".";
    return ss.str();
}

}

#endif
<|endoftext|>


<commit_before>//
//
//

#include "SkeletonOptPass.hpp"

#include "llvm/Pass.h"
// using llvm::RegisterPass

#include "llvm/IR/Type.h"
// using llvm::Type

#include "llvm/IR/Instruction.h"
// using llvm::Instruction

#include "llvm/IR/Function.h"
// using llvm::Function

#include "llvm/Support/Casting.h"
// using llvm::dyn_cast

#include "llvm/Support/raw_ostream.h"
// using llvm::errs

#include "llvm/IR/LegacyPassManager.h"
// using llvm::PassManagerBase

#include "llvm/Transforms/IPO/PassManagerBuilder.h"
// using llvm::PassManagerBuilder
// using llvm::RegisterStandardPasses

// plugin registration for opt

char SkeletonOptPass::ID = 0;
static llvm::RegisterPass<SkeletonOptPass> X("skeleton-opt-pass", "skeleton pass", false, false);

// plugin registration for clang

// the solution was at the bottom of the header file
// 'llvm/Transforms/IPO/PassManagerBuilder.h'
// create a static free-floating callback that uses the legacy pass manager to
// add an instance of this pass and a static instance of the
// RegisterStandardPasses class

static void registerSkeletonOptPass(const llvm::PassManagerBuilder &Builder,
                                    llvm::legacy::PassManagerBase &PM)
{
  PM.add(new SkeletonOptPass());

  return;
}

static llvm::RegisterStandardPasses
RegisterSkeletonOptPass(llvm::PassManagerBuilder::EP_EarlyAsPossible, registerSkeletonOptPass);

//

namespace {

bool
SkeletonOptPass::runOnFunction(llvm::Function &f) {
  llvm::errs() << "skeleton pass : ";
  llvm::errs() << " function name : ";
  llvm::errs().write_escaped(f.getName());
  auto ret_type = f.getReturnType();
  llvm::errs() << "\twith ret type : ";
  ret_type->print(llvm::errs());

  llvm::errs() << "\n-----------------\n";

  for (auto bi = f.begin(); f.end() != bi; ++bi)
    for (auto ii = bi->begin(); bi->end() != ii; ++ii) {
      llvm::errs() << "users of : " << *ii;
      for (auto user : ii->users()) {
        if (auto user_inst = llvm::dyn_cast<llvm::Instruction>(user))
          llvm::errs() << "\t" << *user_inst << "\n";
      }
    }

  return false;
}

} // namespace unnamed end

<commit_msg>add use-def chain code<commit_after>//
//
//

#include "SkeletonOptPass.hpp"

#include "llvm/Pass.h"
// using llvm::RegisterPass

#include "llvm/IR/Type.h"
// using llvm::Type

#include "llvm/IR/Instruction.h"
// using llvm::Instruction

#include "llvm/IR/Function.h"
// using llvm::Function

#include "llvm/Support/Casting.h"
// using llvm::dyn_cast

#include "llvm/Support/raw_ostream.h"
// using llvm::errs

#include "llvm/IR/LegacyPassManager.h"
// using llvm::PassManagerBase

#include "llvm/Transforms/IPO/PassManagerBuilder.h"
// using llvm::PassManagerBuilder
// using llvm::RegisterStandardPasses

// plugin registration for opt

char SkeletonOptPass::ID = 0;
static llvm::RegisterPass<SkeletonOptPass> X("skeleton-opt-pass", "skeleton pass", false, false);

// plugin registration for clang

// the solution was at the bottom of the header file
// 'llvm/Transforms/IPO/PassManagerBuilder.h'
// create a static free-floating callback that uses the legacy pass manager to
// add an instance of this pass and a static instance of the
// RegisterStandardPasses class

static void registerSkeletonOptPass(const llvm::PassManagerBuilder &Builder,
                                    llvm::legacy::PassManagerBase &PM)
{
  PM.add(new SkeletonOptPass());

  return;
}

static llvm::RegisterStandardPasses
RegisterSkeletonOptPass(llvm::PassManagerBuilder::EP_EarlyAsPossible, registerSkeletonOptPass);

//

namespace {

bool
SkeletonOptPass::runOnFunction(llvm::Function &f) {
  llvm::errs() << "skeleton pass : ";
  llvm::errs() << " function name : ";
  llvm::errs().write_escaped(f.getName());
  auto ret_type = f.getReturnType();
  llvm::errs() << "\twith ret type : ";
  ret_type->print(llvm::errs());

  llvm::errs() << "\n---\n";

  for (auto bi = f.begin(); f.end() != bi; ++bi)
    for (auto ii = bi->begin(); bi->end() != ii; ++ii) {
      llvm::errs() << "users of : " << *ii << "\n";
      for (auto user : ii->users()) {
        // TODO what about other users?
        if (auto user_inst = llvm::dyn_cast<llvm::Instruction>(user))
          llvm::errs() << "\t" << *user_inst << "\n\n";

      }

      llvm::errs() << "\twhich uses:\n";

      for (auto &use : ii->operands()) {
        auto v = use.get();
        llvm::errs() << "\t";
        v->print(llvm::errs());
        llvm::errs() << "\n";
      }

      llvm::errs() << "\n---\n";
    }

  return false;
}

} // namespace unnamed end

<|endoftext|>


<commit_before>// Copyright 2004-present Facebook. All Rights Reserved.

#include <boost/thread.hpp>

#include <glog/logging.h>

#include <osquery/config.h>
#include <osquery/config/plugin.h>
#include <osquery/core.h>
#include <osquery/database.h>
#include <osquery/events.h>
#include <osquery/logger/plugin.h>
#include <osquery/scheduler.h>

int main(int argc, char* argv[]) {
  osquery::initOsquery(argc, argv, osquery::OSQUERY_TOOL_DAEMON);

  auto pid_status = osquery::createPidFile();
  if (!pid_status.ok()) {
    LOG(ERROR) << "Could not create osquery pidfile: " << pid_status.toString();
    ::exit(-1);
  }

  try {
    osquery::DBHandle::getInstance();
  } catch (std::exception& e) {
    LOG(ERROR) << "osqueryd failed to start: " << e.what();
    ::exit(1);
  }

  LOG(INFO) << "Listing all plugins";

  LOG(INFO) << "Logger plugins:";
  for (const auto& it : REGISTERED_LOGGER_PLUGINS) {
    LOG(INFO) << "  - " << it.first;
  }

  LOG(INFO) << "Config plugins:";
  for (const auto& it : REGISTERED_CONFIG_PLUGINS) {
    LOG(INFO) << "  - " << it.first;
  }

  LOG(INFO) << "Event Publishers:";
  for (const auto& it : REGISTERED_EVENTPUBLISHERS) {
    LOG(INFO) << "  - " << it.first;
  }

  LOG(INFO) << "Event Subscribers:";
  for (const auto& it : REGISTERED_EVENTSUBSCRIBERS) {
    LOG(INFO) << "  - " << it.first;
  }

  // Start a thread for each appropriate event type
  osquery::registries::faucet(REGISTERED_EVENTPUBLISHERS,
                              REGISTERED_EVENTSUBSCRIBERS);
  osquery::EventFactory::delay();

  boost::thread scheduler_thread(osquery::initializeScheduler);
  scheduler_thread.join();

  // End any event type run loops.
  osquery::EventFactory::end();

  return 0;
}
<commit_msg>Change exit(-1) to exit(EXIT_FAILURE)<commit_after>// Copyright 2004-present Facebook. All Rights Reserved.

#include <boost/thread.hpp>

#include <glog/logging.h>

#include <osquery/config.h>
#include <osquery/config/plugin.h>
#include <osquery/core.h>
#include <osquery/database.h>
#include <osquery/events.h>
#include <osquery/logger/plugin.h>
#include <osquery/scheduler.h>

int main(int argc, char* argv[]) {
  osquery::initOsquery(argc, argv, osquery::OSQUERY_TOOL_DAEMON);

  auto pid_status = osquery::createPidFile();
  if (!pid_status.ok()) {
    LOG(ERROR) << "Could not create osquery pidfile: " << pid_status.toString();
    ::exit(EXIT_FAILURE);
  }

  try {
    osquery::DBHandle::getInstance();
  } catch (std::exception& e) {
    LOG(ERROR) << "osqueryd failed to start: " << e.what();
    ::exit(1);
  }

  LOG(INFO) << "Listing all plugins";

  LOG(INFO) << "Logger plugins:";
  for (const auto& it : REGISTERED_LOGGER_PLUGINS) {
    LOG(INFO) << "  - " << it.first;
  }

  LOG(INFO) << "Config plugins:";
  for (const auto& it : REGISTERED_CONFIG_PLUGINS) {
    LOG(INFO) << "  - " << it.first;
  }

  LOG(INFO) << "Event Publishers:";
  for (const auto& it : REGISTERED_EVENTPUBLISHERS) {
    LOG(INFO) << "  - " << it.first;
  }

  LOG(INFO) << "Event Subscribers:";
  for (const auto& it : REGISTERED_EVENTSUBSCRIBERS) {
    LOG(INFO) << "  - " << it.first;
  }

  // Start a thread for each appropriate event type
  osquery::registries::faucet(REGISTERED_EVENTPUBLISHERS,
                              REGISTERED_EVENTSUBSCRIBERS);
  osquery::EventFactory::delay();

  boost::thread scheduler_thread(osquery::initializeScheduler);
  scheduler_thread.join();

  // End any event type run loops.
  osquery::EventFactory::end();

  return 0;
}
<|endoftext|>


<commit_before>/*
 * AlgorandDatabaseTests
 *
 * Created by Hakim Aammar on 25/05/2020.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2020 Ledger
 *
 * 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.
 *
 */

#include "AlgorandTestFixtures.hpp"
#include <wallet/algorand/database/AlgorandTransactionDatabaseHelper.hpp>
#include <wallet/algorand/database/AlgorandAccountDatabaseHelper.hpp>
#include <wallet/algorand/operations/AlgorandOperation.hpp>
#include <wallet/algorand/AlgorandWalletFactory.hpp>
#include <wallet/algorand/AlgorandLikeCurrencies.hpp>
#include <wallet/algorand/AlgorandWallet.hpp>
#include <wallet/algorand/AlgorandAccount.hpp>

#include <wallet/common/OperationQuery.h>
#include <api/AccountCreationInfo.hpp>
#include <api/Address.hpp>

#include "../integration/WalletFixture.hpp" // No equivalent in v1 ?

#include <utility>

using namespace ledger::testing::algorand;
using namespace ledger::core::algorand;

class AlgorandDatabaseTest : public WalletFixture<WalletFactory> {

    public:

    void SetUp() override {
        WalletFixture::SetUp();

        auto const currency = currencies::ALGORAND;
        registerCurrency(currency);

        accountInfo = api::AccountCreationInfo(1, {}, {}, { algorand::Address::toPublicKey(OBELIX_ADDRESS) }, {});

        auto wallet = wait(pool->createWallet("algorand", currency.name, api::DynamicObject::newInstance()));
        auto account = createAlgorandAccount(wallet, accountInfo.index, accountInfo);

        accountUid = algorand::AccountDatabaseHelper::createAccountUid(wallet->getWalletUid(), accountInfo.index);
    }

    void TearDown() override {
        WalletFixture::TearDown();

        wallet.reset();
        account.reset();
    }

    std::shared_ptr<Wallet> wallet;
    std::shared_ptr<Account> account;

    api::AccountCreationInfo accountInfo;
    std::string accountUid;
};

TEST_F(AlgorandDatabaseTest, AccountDBTest) {

    // Test reading from DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());

        algorand::AccountDatabaseEntry accountFromDB;
        auto result = algorand::AccountDatabaseHelper::queryAccount(sql, accountUid, accountFromDB);

        EXPECT_EQ(result, true);
        EXPECT_EQ(accountInfo.index, accountFromDB.index);
        EXPECT_EQ(OBELIX_ADDRESS, accountFromDB.address) << "This test fails because SHA512-256 is not implemented yet!";
    }
}

TEST_F(AlgorandDatabaseTest, TransactionsDBTest) {

    auto paymentTxRef = paymentTransaction();
    auto assetConfigTxRef = assetConfigTransaction();
    auto assetTransferTxRef = assetTransferTransaction();

    // Test writing into DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());
        algorand::TransactionDatabaseHelper::putTransaction(sql, "test-account", paymentTxRef);
        algorand::TransactionDatabaseHelper::putTransaction(sql, "test-account", assetConfigTxRef);
        algorand::TransactionDatabaseHelper::putTransaction(sql, "test-account", assetTransferTxRef);
    }

    // Test reading from DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());

        model::Transaction paymentTxFromDB;
        auto result = algorand::TransactionDatabaseHelper::getTransactionByHash(sql, *paymentTxRef.header.id, paymentTxFromDB);
        EXPECT_TRUE(result);
        assertSameTransaction(paymentTxRef, paymentTxFromDB);

        model::Transaction assetConfigTxFromDB;
        result = algorand::TransactionDatabaseHelper::getTransactionByHash(sql, *assetConfigTxRef.header.id, assetConfigTxFromDB);
        EXPECT_TRUE(result);
        assertSameTransaction(assetConfigTxRef, assetConfigTxFromDB);

        model::Transaction assetTransferTxFromDB;
        result = algorand::TransactionDatabaseHelper::getTransactionByHash(sql, *assetTransferTxRef.header.id, assetTransferTxFromDB);
        EXPECT_TRUE(result);
        assertSameTransaction(assetTransferTxRef, assetTransferTxFromDB);
    }
}

TEST_F(AlgorandDatabaseTest, OperationsDBTest) {

    auto txRef = paymentTransaction();

    // Test writing into DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());
        account->putTransaction(sql, txRef);
    }

    // Test reading from DB
    {
        auto ops = wait(std::dynamic_pointer_cast<OperationQuery>(account->queryOperations()->complete())->execute());

        EXPECT_EQ(ops.size(), 1);
        auto op = std::dynamic_pointer_cast<algorand::Operation>(ops[0]);

        /* TODO ?
        EXPECT_EQ(op->getAccountIndex(), account->getIndex());
        EXPECT_EQ(op->getAmount(), ?);
        EXPECT_EQ(op->getBlockHeight(), ?);
        EXPECT_EQ(op->getCurrency(), ?);
        EXPECT_EQ(op->getDate(), ?);
        EXPECT_EQ(op->getFees(), ?);
        EXPECT_EQ(op->getOperationType(), ?);
        EXPECT_EQ(op->getPreferences(), ?);
        EXPECT_EQ(op->getRecipients(), ?);
        EXPECT_EQ(op->getSenders(), ?);
        EXPECT_EQ(op->getTrust(), ?);
        EXPECT_EQ(op->getUid(), ?);
        EXPECT_EQ(op->isComplete(), ?);
        */

        auto txRetrieved = op->getTransactionData();
        assertSameTransaction(txRef, txRetrieved);
    }
}<commit_msg> Need to implement v1 method asAlgorandOperation() for AlgorandDatabaseTest ?<commit_after>/*
 * AlgorandDatabaseTests
 *
 * Created by Hakim Aammar on 25/05/2020.
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2020 Ledger
 *
 * 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.
 *
 */

#include "AlgorandTestFixtures.hpp"
#include <wallet/algorand/database/AlgorandTransactionDatabaseHelper.hpp>
#include <wallet/algorand/database/AlgorandAccountDatabaseHelper.hpp>
#include <wallet/algorand/operations/AlgorandOperation.hpp>
#include <wallet/algorand/AlgorandWalletFactory.hpp>
#include <wallet/algorand/AlgorandLikeCurrencies.hpp>
#include <wallet/algorand/AlgorandWallet.hpp>
#include <wallet/algorand/AlgorandAccount.hpp>

#include <wallet/common/OperationQuery.h>
#include <api/AccountCreationInfo.hpp>
#include <api/Address.hpp>

#include "../integration/WalletFixture.hpp" // No equivalent in v1 ?

#include <utility>

using namespace ledger::testing::algorand;
using namespace ledger::core::algorand;

class AlgorandDatabaseTest : public WalletFixture<WalletFactory> {

    public:

    void SetUp() override {
        WalletFixture::SetUp();

        auto const currency = currencies::ALGORAND;
        registerCurrency(currency);

        accountInfo = api::AccountCreationInfo(1, {}, {}, { algorand::Address::toPublicKey(OBELIX_ADDRESS) }, {});

        auto wallet = wait(pool->createWallet("algorand", currency.name, api::DynamicObject::newInstance()));
        auto account = createAlgorandAccount(wallet, accountInfo.index, accountInfo);

        accountUid = algorand::AccountDatabaseHelper::createAccountUid(wallet->getWalletUid(), accountInfo.index);
    }

    void TearDown() override {
        WalletFixture::TearDown();

        wallet.reset();
        account.reset();
    }

    std::shared_ptr<Wallet> wallet;
    std::shared_ptr<Account> account;

    api::AccountCreationInfo accountInfo;
    std::string accountUid;
};

TEST_F(AlgorandDatabaseTest, AccountDBTest) {

    // Test reading from DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());

        algorand::AccountDatabaseEntry accountFromDB;
        auto result = algorand::AccountDatabaseHelper::queryAccount(sql, accountUid, accountFromDB);

        EXPECT_EQ(result, true);
        EXPECT_EQ(accountInfo.index, accountFromDB.index);
        EXPECT_EQ(OBELIX_ADDRESS, accountFromDB.address) << "This test fails because SHA512-256 is not implemented yet!";
    }
}

TEST_F(AlgorandDatabaseTest, TransactionsDBTest) {

    auto paymentTxRef = paymentTransaction();
    auto assetConfigTxRef = assetConfigTransaction();
    auto assetTransferTxRef = assetTransferTransaction();

    // Test writing into DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());
        algorand::TransactionDatabaseHelper::putTransaction(sql, "test-account", paymentTxRef);
        algorand::TransactionDatabaseHelper::putTransaction(sql, "test-account", assetConfigTxRef);
        algorand::TransactionDatabaseHelper::putTransaction(sql, "test-account", assetTransferTxRef);
    }

    // Test reading from DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());

        // FIXME : Need to implement v1 method asAlgorandOperation() ?

        model::Transaction paymentTxFromDB;
        auto result = algorand::TransactionDatabaseHelper::getTransactionByHash(sql, *paymentTxRef.header.id, paymentTxFromDB);
        EXPECT_TRUE(result);
        assertSameTransaction(paymentTxRef, paymentTxFromDB);

        model::Transaction assetConfigTxFromDB;
        result = algorand::TransactionDatabaseHelper::getTransactionByHash(sql, *assetConfigTxRef.header.id, assetConfigTxFromDB);
        EXPECT_TRUE(result);
        assertSameTransaction(assetConfigTxRef, assetConfigTxFromDB);

        model::Transaction assetTransferTxFromDB;
        result = algorand::TransactionDatabaseHelper::getTransactionByHash(sql, *assetTransferTxRef.header.id, assetTransferTxFromDB);
        EXPECT_TRUE(result);
        assertSameTransaction(assetTransferTxRef, assetTransferTxFromDB);
    }
}

TEST_F(AlgorandDatabaseTest, OperationsDBTest) {

    auto txRef = paymentTransaction();

    // Test writing into DB
    {
        soci::session sql(pool->getDatabaseSessionPool()->getPool());
        account->putTransaction(sql, txRef);
    }

    // Test reading from DB
    {
        auto ops = wait(std::dynamic_pointer_cast<OperationQuery>(account->queryOperations()->complete())->execute());

        EXPECT_EQ(ops.size(), 1);
        auto op = std::dynamic_pointer_cast<algorand::Operation>(ops[0]);

        /* TODO ?
        EXPECT_EQ(op->getAccountIndex(), account->getIndex());
        EXPECT_EQ(op->getAmount(), ?);
        EXPECT_EQ(op->getBlockHeight(), ?);
        EXPECT_EQ(op->getCurrency(), ?);
        EXPECT_EQ(op->getDate(), ?);
        EXPECT_EQ(op->getFees(), ?);
        EXPECT_EQ(op->getOperationType(), ?);
        EXPECT_EQ(op->getPreferences(), ?);
        EXPECT_EQ(op->getRecipients(), ?);
        EXPECT_EQ(op->getSenders(), ?);
        EXPECT_EQ(op->getTrust(), ?);
        EXPECT_EQ(op->getUid(), ?);
        EXPECT_EQ(op->isComplete(), ?);
        */

        auto txRetrieved = op->getTransactionData();
        assertSameTransaction(txRef, txRetrieved);
    }
}<|endoftext|>


<commit_before>#include <iostream>
#include <sys/stat.h>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/gpu/gpu.hpp>

#include "CaffeClassifier.hpp"

using namespace std;
using namespace caffe;
using namespace cv;
using namespace cv::gpu;

static bool glogInit_ = false;

#if 0
#include <sys/time.h>
static double gtod_wrapper(void)
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
#endif

template <class MatT>
CaffeClassifier<MatT>::CaffeClassifier(const string& modelFile,
      const string& trainedFile,
      const string& zcaWeightFile,
      const string& labelFile,
      const size_t  batchSize) :
	Classifier<MatT>(modelFile, trainedFile, zcaWeightFile, labelFile, batchSize),
	initialized_(false)
{
#ifdef USE_CAFFE
	if (!Classifier<MatT>::initialized())
		return;
	if (!this->fileExists(modelFile))
	{
		cerr << "Could not find Caffe model " << modelFile << endl;
		return;
	}
	if (!this->fileExists(trainedFile))
	{
		cerr << "Could not find Caffe trained weights " << trainedFile << endl;
		return;
	}
	cout << "Loading Caffe model " << modelFile << " " << trainedFile << " " << zcaWeightFile << " " << labelFile << endl;

	if (IsGPU())
		Caffe::set_mode(Caffe::GPU);
	else
		Caffe::set_mode(Caffe::CPU);

	// Hopefully this turns off any logging
	if (!glogInit_)
	{
		::google::InitGoogleLogging("");
		::google::LogToStderr();
		::google::SetStderrLogging(3);
		glogInit_ = true;
	}

	/* Load the network - this includes model geometry and trained weights */
	net_.reset(new Net<float>(modelFile, TEST));
	net_->CopyTrainedLayersFrom(trainedFile);

	CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
	CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";

	Blob<float>* inputLayer = net_->input_blobs()[0];
	const int numChannels = inputLayer->channels();
	CHECK(numChannels == 3 || numChannels == 1) << "Input layer should have 1 or 3 channels.";
	if (this->inputGeometry_ != Size(inputLayer->width(), inputLayer->height()))
	{
		cerr << "Net size != ZCA size" << endl;
		return;
	}

	Blob<float>* outputLayer = net_->output_blobs()[0];
	CHECK_EQ(this->labels_.size(), outputLayer->channels())
		<< "Number of labels is different from the output layer dimension.";

	// Pre-process Mat wrapping
	inputLayer->Reshape(batchSize, numChannels,
			inputLayer->height(),
			inputLayer->width());

	/* Forward dimension change to all layers. */
	net_->Reshape();

	// The wrap code puts the buffer for one individual channel
	// input to the net (one color channel of one image) into
	// a separate Mat
	// The inner vector here will be one Mat per channel of the
	// input to the net. The outer vector is a vector of those
	// one for each of the batched inputs.
	// This allows an easy copy from the input images
	// into the input buffers for the net
	WrapBatchInputLayer();
	initialized_ = true;
#endif
}

template <class MatT>
CaffeClassifier<MatT>::~CaffeClassifier()
{
}

#ifdef USE_CAFFE
// Wrap input layer of the net into separate Mat objects
// This sets them up to be written with actual data
// in PreprocessBatch()
template <class MatT>
void CaffeClassifier<MatT>::WrapBatchInputLayer(void)
{
	Blob<float>* inputLayer = net_->input_blobs()[0];

	const int width  = inputLayer->width();
	const int height = inputLayer->height();
	const int num    = inputLayer->num();
	float* inputData = GetBlobData(inputLayer);

	inputBatch_.clear();

	for (int j = 0; j < num; j++)
	{
		vector<MatT> inputChannels;
		for (int i = 0; i < inputLayer->channels(); ++i)
		{
			MatT channel(height, width, CV_32FC1, inputData);
			inputChannels.push_back(channel);
			inputData += width * height;
		}
		inputBatch_.push_back(vector<MatT>(inputChannels));
	}
}
#endif

// Get the output values for a set of images in one flat vector
// These values will be in the same order as the labels for each
// image, and each set of labels for an image next adjacent to the
// one for the next image.
// That is, [0] = value for label 0 for the first image up to
// [n] = value for label n for the first image. It then starts again
// for the next image - [n+1] = label 0 for image #2.
template <class MatT>
vector<float> CaffeClassifier<MatT>::PredictBatch(const vector<MatT> &imgs)
{
#ifdef USE_CAFFE
	// Process each image so they match the format
	// expected by the net, then copy the images
	// into the net's input buffers
	//double start = gtod_wrapper();
	PreprocessBatch(imgs);
	//cout << "PreprocessBatch " << gtod_wrapper() - start << endl;
	//start = gtod_wrapper();
	// Run a forward pass with the data filled in from above
	net_->Forward();
	//cout << "Forward " << gtod_wrapper() - start << endl;

	//start = gtod_wrapper();
	/* Copy the output layer to a flat vector */
	Blob<float>* outputLayer = net_->output_blobs()[0];
	const float* begin = outputLayer->cpu_data();
	const float* end = begin + outputLayer->channels()*imgs.size();
	//cout << "Output " << gtod_wrapper() - start << endl;
	return vector<float>(begin, end);
#else
	return vector<float>(imgs.size() * this->labels_.size(), 0);
#endif
}

#ifdef USE_CAFFE

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <> template <>
float *CaffeClassifier<Mat>::GetBlobData(Blob<float> *blob)
{
	return blob->mutable_cpu_data();
}

template <> template <>
float *CaffeClassifier<GpuMat>::GetBlobData(Blob<float> *blob)
{
	return blob->mutable_gpu_data();
}

// Take each image in Mat, convert it to the correct image type,
// Then actually write the images to the net input memory buffers
template <>
void CaffeClassifier<Mat>::PreprocessBatch(const vector<Mat> &imgs)
{
	CHECK(imgs.size() <= this->batchSize_) <<
		"PreprocessBatch() : too many input images : batch size is " << this->batchSize_ << "imgs.size() = " << imgs.size();

#if 0
	for (size_t i = 0 ; i < imgs.size(); i++)
	{
		Mat img = imgs[i].clone();
		Mat wr;
		img.convertTo(wr, CV_8UC3, 255);
		stringstream s;
		s << "debug_ppb_before_" << i << ".png";
		imwrite(s.str(), wr);
	}
#endif
	vector<Mat> zcaImgs = this->zca_.Transform32FC3(imgs);
#if 0
	for (size_t i = 0 ; i < zcaImgs.size(); i++)
	{
		Mat img = zcaImgs[i].clone();
		Mat wr;
		img.convertTo(wr, CV_8UC3, 255, 127);
		stringstream s;
		s << "debug_ppb_after_" << i << ".png";
		imwrite(s.str(), wr);
	}
#endif

#if 0
	for (size_t i = 0 ; i < zcaImgs.size(); i++)
	{
		zcaImgs[i] *= 255.;
		zcaImgs[i] += 127.;
	}
#endif
	for (size_t i = 0 ; i < zcaImgs.size(); i++)
	{
		/* This operation will write the separate BGR planes directly to the
		 * input layer of the network because it is wrapped by the MatT
		 * objects in inputChannels. */
		vector<Mat> *inputChannels = &inputBatch_.at(i);
		split(zcaImgs[i], *inputChannels);

#if 1
		// TODO : CPU Mats + GPU Caffe fails if this isn't here, no idea why
		if (i == 0)
			CHECK(reinterpret_cast<float*>(inputChannels->at(0).data)
					== GetBlobData(net_->input_blobs()[0]))
				<< "Input channels are not wrapping the input layer of the network.";
#endif
	}
}

// Take each image in GpuMat, convert it to the correct image type,
// Then actually write the images to the net input memory buffers
template <>
void CaffeClassifier<GpuMat>::PreprocessBatch(const vector<GpuMat> &imgs)
{
	CHECK(imgs.size() <= this->batchSize_) <<
		"PreprocessBatch() : too many input images : batch size is " << this->batchSize_ << "imgs.size() = " << imgs.size();

	Blob<float>* inputLayer = net_->input_blobs()[0];
	float* inputData = GetBlobData(inputLayer);
	this->zca_.Transform32FC3(imgs, inputData);
}

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <>
bool CaffeClassifier<Mat>::IsGPU(void) const
{
	return true;
}

template <>
bool CaffeClassifier<GpuMat>::IsGPU(void) const
{
	return true;
}
#endif

template <class MatT>
bool CaffeClassifier<MatT>::initialized(void) const
{
	if (!Classifier<MatT>::initialized())
		return false;

	return initialized_;
}

template class CaffeClassifier<Mat>;
template class CaffeClassifier<GpuMat>;
<commit_msg>Weirdness with Caffe GPU support<commit_after>#include <iostream>
#include <sys/stat.h>

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/gpu/gpu.hpp>

#include "CaffeClassifier.hpp"

using namespace std;
using namespace caffe;
using namespace cv;
using namespace cv::gpu;

static bool glogInit_ = false;

#if 0
#include <sys/time.h>
static double gtod_wrapper(void)
{
    struct timeval tv;

    gettimeofday(&tv, NULL);
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}
#endif

template <class MatT>
CaffeClassifier<MatT>::CaffeClassifier(const string& modelFile,
      const string& trainedFile,
      const string& zcaWeightFile,
      const string& labelFile,
      const size_t  batchSize) :
	Classifier<MatT>(modelFile, trainedFile, zcaWeightFile, labelFile, batchSize),
	initialized_(false)
{
#ifdef USE_CAFFE
	if (!Classifier<MatT>::initialized())
		return;
	if (!this->fileExists(modelFile))
	{
		cerr << "Could not find Caffe model " << modelFile << endl;
		return;
	}
	if (!this->fileExists(trainedFile))
	{
		cerr << "Could not find Caffe trained weights " << trainedFile << endl;
		return;
	}
	cout << "Loading Caffe model " << modelFile << " " << trainedFile << " " << zcaWeightFile << " " << labelFile << endl;

	if (IsGPU())
		Caffe::set_mode(Caffe::GPU);
	else
		Caffe::set_mode(Caffe::CPU);

	// Hopefully this turns off any logging
	if (!glogInit_)
	{
		::google::InitGoogleLogging("");
		::google::LogToStderr();
		::google::SetStderrLogging(3);
		glogInit_ = true;
	}

	/* Load the network - this includes model geometry and trained weights */
	net_.reset(new Net<float>(modelFile, TEST));
	net_->CopyTrainedLayersFrom(trainedFile);

	CHECK_EQ(net_->num_inputs(), 1) << "Network should have exactly one input.";
	CHECK_EQ(net_->num_outputs(), 1) << "Network should have exactly one output.";

	Blob<float>* inputLayer = net_->input_blobs()[0];
	const int numChannels = inputLayer->channels();
	CHECK(numChannels == 3 || numChannels == 1) << "Input layer should have 1 or 3 channels.";
	if (this->inputGeometry_ != Size(inputLayer->width(), inputLayer->height()))
	{
		cerr << "Net size != ZCA size" << endl;
		return;
	}

	Blob<float>* outputLayer = net_->output_blobs()[0];
	CHECK_EQ(this->labels_.size(), outputLayer->channels())
		<< "Number of labels is different from the output layer dimension.";

	// Pre-process Mat wrapping
	inputLayer->Reshape(batchSize, numChannels,
			inputLayer->height(),
			inputLayer->width());

	/* Forward dimension change to all layers. */
	net_->Reshape();

	// The wrap code puts the buffer for one individual channel
	// input to the net (one color channel of one image) into
	// a separate Mat
	// The inner vector here will be one Mat per channel of the
	// input to the net. The outer vector is a vector of those
	// one for each of the batched inputs.
	// This allows an easy copy from the input images
	// into the input buffers for the net
	WrapBatchInputLayer();
	initialized_ = true;
#endif
}

template <class MatT>
CaffeClassifier<MatT>::~CaffeClassifier()
{
}

#ifdef USE_CAFFE
// Wrap input layer of the net into separate Mat objects
// This sets them up to be written with actual data
// in PreprocessBatch()
template <class MatT>
void CaffeClassifier<MatT>::WrapBatchInputLayer(void)
{
	Blob<float>* inputLayer = net_->input_blobs()[0];

	const int width  = inputLayer->width();
	const int height = inputLayer->height();
	const int num    = inputLayer->num();
	float* inputData = GetBlobData(inputLayer);

	inputBatch_.clear();

	for (int j = 0; j < num; j++)
	{
		vector<MatT> inputChannels;
		for (int i = 0; i < inputLayer->channels(); ++i)
		{
			MatT channel(height, width, CV_32FC1, inputData);
			inputChannels.push_back(channel);
			inputData += width * height;
		}
		inputBatch_.push_back(vector<MatT>(inputChannels));
	}
}
#endif

// Get the output values for a set of images in one flat vector
// These values will be in the same order as the labels for each
// image, and each set of labels for an image next adjacent to the
// one for the next image.
// That is, [0] = value for label 0 for the first image up to
// [n] = value for label n for the first image. It then starts again
// for the next image - [n+1] = label 0 for image #2.
template <class MatT>
vector<float> CaffeClassifier<MatT>::PredictBatch(const vector<MatT> &imgs)
{
#ifdef USE_CAFFE
	// Process each image so they match the format
	// expected by the net, then copy the images
	// into the net's input buffers
	//double start = gtod_wrapper();
	PreprocessBatch(imgs);
	//cout << "PreprocessBatch " << gtod_wrapper() - start << endl;
	//start = gtod_wrapper();
	// Run a forward pass with the data filled in from above
	net_->Forward();
	//cout << "Forward " << gtod_wrapper() - start << endl;

	//start = gtod_wrapper();
	/* Copy the output layer to a flat vector */
	Blob<float>* outputLayer = net_->output_blobs()[0];
	const float* begin = outputLayer->cpu_data();
	const float* end = begin + outputLayer->channels()*imgs.size();
	//cout << "Output " << gtod_wrapper() - start << endl;
	return vector<float>(begin, end);
#else
	return vector<float>(imgs.size() * this->labels_.size(), 0);
#endif
}

#ifdef USE_CAFFE

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <> template <>
float *CaffeClassifier<Mat>::GetBlobData(Blob<float> *blob)
{
	return blob->mutable_cpu_data();
}

template <> template <>
float *CaffeClassifier<GpuMat>::GetBlobData(Blob<float> *blob)
{
	return blob->mutable_gpu_data();
}

// Take each image in Mat, convert it to the correct image type,
// Then actually write the images to the net input memory buffers
template <>
void CaffeClassifier<Mat>::PreprocessBatch(const vector<Mat> &imgs)
{
	CHECK(imgs.size() <= this->batchSize_) <<
		"PreprocessBatch() : too many input images : batch size is " << this->batchSize_ << "imgs.size() = " << imgs.size();

#if 0
	for (size_t i = 0 ; i < imgs.size(); i++)
	{
		Mat img = imgs[i].clone();
		Mat wr;
		img.convertTo(wr, CV_8UC3, 255);
		stringstream s;
		s << "debug_ppb_before_" << i << ".png";
		imwrite(s.str(), wr);
	}
#endif
	vector<Mat> zcaImgs = this->zca_.Transform32FC3(imgs);
#if 0
	for (size_t i = 0 ; i < zcaImgs.size(); i++)
	{
		Mat img = zcaImgs[i].clone();
		Mat wr;
		img.convertTo(wr, CV_8UC3, 255, 127);
		stringstream s;
		s << "debug_ppb_after_" << i << ".png";
		imwrite(s.str(), wr);
	}
#endif

#if 0
	for (size_t i = 0 ; i < zcaImgs.size(); i++)
	{
		zcaImgs[i] *= 255.;
		zcaImgs[i] += 127.;
	}
#endif
	for (size_t i = 0 ; i < zcaImgs.size(); i++)
	{
		/* This operation will write the separate BGR planes directly to the
		 * input layer of the network because it is wrapped by the MatT
		 * objects in inputChannels. */
		vector<Mat> *inputChannels = &inputBatch_.at(i);
		split(zcaImgs[i], *inputChannels);

#if 1
		// TODO : CPU Mats + GPU Caffe fails if this isn't here, no idea why
		if (i == 0)
			CHECK(reinterpret_cast<float*>(inputChannels->at(0).data)
					== GetBlobData(net_->input_blobs()[0]))
				<< "Input channels are not wrapping the input layer of the network.";
#endif
	}
}

// Take each image in GpuMat, convert it to the correct image type,
// Then actually write the images to the net input memory buffers
template <>
void CaffeClassifier<GpuMat>::PreprocessBatch(const vector<GpuMat> &imgs)
{
	CHECK(imgs.size() <= this->batchSize_) <<
		"PreprocessBatch() : too many input images : batch size is " << this->batchSize_ << "imgs.size() = " << imgs.size();

	Blob<float>* inputLayer = net_->input_blobs()[0];
	float* inputData = GetBlobData(inputLayer);
	this->zca_.Transform32FC3(imgs, inputData);
}

// TODO : maybe don't specialize this one in case
// we use something other than Mat or GpuMat in the
// future?
template <>
bool CaffeClassifier<Mat>::IsGPU(void) const
{
	// TODO : change to unconditional false
	// eventually
	return (getCudaEnabledDeviceCount() > 0);
	return false;
}

template <>
bool CaffeClassifier<GpuMat>::IsGPU(void) const
{
	return true;
}
#endif

template <class MatT>
bool CaffeClassifier<MatT>::initialized(void) const
{
	if (!Classifier<MatT>::initialized())
		return false;

	return initialized_;
}

template class CaffeClassifier<Mat>;
template class CaffeClassifier<GpuMat>;
<|endoftext|>


<commit_before>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Archive.hpp"
#include "FileSystem.hpp"
#include "core/Engine.hpp"
#include "utils/Log.hpp"
#include "utils/Utils.hpp"

namespace ouzel
{
    Archive::Archive(const std::string& filename)
    {
        open(filename);
    }

    Archive::~Archive()
    {
        if (fileSystem) fileSystem->removeArchive(this);
    }

    bool Archive::open(const std::string& filename)
    {
        file.open(engine->getFileSystem()->getPath(filename, false), File::READ);

        for (;;)
        {
            uint32_t signature;

            file.readAll(&signature, sizeof(signature));

            if (decodeUInt32Little(&signature) == 0x02014b50) // central directory
                break;

            if (decodeUInt32Little(&signature) != 0x04034b50)
            {
                Log(Log::Level::ERR) << "Bad signature";
                return false;
            }

            uint8_t version[2];

            file.readAll(version, sizeof(version));

            uint16_t flags;

            file.readAll(&flags, sizeof(flags));

            uint16_t compression;
            file.readAll(&compression, sizeof(compression));

            if (compression != 0x00)
            {
                Log(Log::Level::ERR) << "Unsupported compression";
                return false;
            }

            file.seek(4, File::CURRENT); // skip modification time
            file.seek(4, File::CURRENT); // skip CRC-32

            uint32_t compressedSize;
            file.readAll(&compressedSize, sizeof(compressedSize));

            uint32_t uncompressedSize;
            file.readAll(&uncompressedSize, sizeof(uncompressedSize));

            uint16_t fileNameLength;
            file.readAll(&fileNameLength, sizeof(fileNameLength));

            uint16_t extraFieldLength;
            file.readAll(&extraFieldLength, sizeof(extraFieldLength));

            std::vector<char> name(decodeUInt16Little(&fileNameLength) + 1);

            file.readAll(name.data(), decodeUInt16Little(&fileNameLength));

            name[decodeUInt16Little(&fileNameLength)] = '\0';

            Entry& entry = entries[name.data()];
            entry.size = decodeUInt32Little(&uncompressedSize);

            file.seek(decodeUInt16Little(&extraFieldLength), File::CURRENT); // skip extra field

            entry.offset = file.getOffset();

            file.seek(decodeInt32Little(&uncompressedSize), File::CURRENT); // skip uncompressed size
        }

        return true;
    }

    bool Archive::readFile(const std::string& filename, std::vector<uint8_t>& data) const
    {
        auto i = entries.find(filename);

        if (i == entries.end()) return false;

        file.seek(static_cast<int32_t>(i->second.offset), File::BEGIN);

        data.resize(i->second.size);

        file.readAll(data.data(), i->second.size);

        return true;
    }

    bool Archive::fileExists(const std::string& filename) const
    {
        return entries.find(filename) != entries.end();
    }
}
<commit_msg>Search also resource paths for the archives<commit_after>// Copyright (C) 2018 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "Archive.hpp"
#include "FileSystem.hpp"
#include "core/Engine.hpp"
#include "utils/Log.hpp"
#include "utils/Utils.hpp"

namespace ouzel
{
    Archive::Archive(const std::string& filename)
    {
        open(filename);
    }

    Archive::~Archive()
    {
        if (fileSystem) fileSystem->removeArchive(this);
    }

    bool Archive::open(const std::string& filename)
    {
        file.open(engine->getFileSystem()->getPath(filename), File::READ);

        for (;;)
        {
            uint32_t signature;

            file.readAll(&signature, sizeof(signature));

            if (decodeUInt32Little(&signature) == 0x02014b50) // central directory
                break;

            if (decodeUInt32Little(&signature) != 0x04034b50)
            {
                Log(Log::Level::ERR) << "Bad signature";
                return false;
            }

            uint8_t version[2];

            file.readAll(version, sizeof(version));

            uint16_t flags;

            file.readAll(&flags, sizeof(flags));

            uint16_t compression;
            file.readAll(&compression, sizeof(compression));

            if (compression != 0x00)
            {
                Log(Log::Level::ERR) << "Unsupported compression";
                return false;
            }

            file.seek(4, File::CURRENT); // skip modification time
            file.seek(4, File::CURRENT); // skip CRC-32

            uint32_t compressedSize;
            file.readAll(&compressedSize, sizeof(compressedSize));

            uint32_t uncompressedSize;
            file.readAll(&uncompressedSize, sizeof(uncompressedSize));

            uint16_t fileNameLength;
            file.readAll(&fileNameLength, sizeof(fileNameLength));

            uint16_t extraFieldLength;
            file.readAll(&extraFieldLength, sizeof(extraFieldLength));

            std::vector<char> name(decodeUInt16Little(&fileNameLength) + 1);

            file.readAll(name.data(), decodeUInt16Little(&fileNameLength));

            name[decodeUInt16Little(&fileNameLength)] = '\0';

            Entry& entry = entries[name.data()];
            entry.size = decodeUInt32Little(&uncompressedSize);

            file.seek(decodeUInt16Little(&extraFieldLength), File::CURRENT); // skip extra field

            entry.offset = file.getOffset();

            file.seek(decodeInt32Little(&uncompressedSize), File::CURRENT); // skip uncompressed size
        }

        return true;
    }

    bool Archive::readFile(const std::string& filename, std::vector<uint8_t>& data) const
    {
        auto i = entries.find(filename);

        if (i == entries.end()) return false;

        file.seek(static_cast<int32_t>(i->second.offset), File::BEGIN);

        data.resize(i->second.size);

        file.readAll(data.data(), i->second.size);

        return true;
    }

    bool Archive::fileExists(const std::string& filename) const
    {
        return entries.find(filename) != entries.end();
    }
}
<|endoftext|>


<commit_before>
#include "stdafx.h"
#include "util/fixes.h"
#include "common.h"
#include "obj.h"
#include "turn_based.h"
#include "temple_functions.h"
#include "critter.h"
#include "condition.h"

class SizeColossalFix : public TempleFix {
public:
	const char* name() override {
		return "fixes size_colossal (was misspelled as size_clossal)";
	}

	void apply() override {
		writeHex(0x10278078, "73 69 7A 65 5F 63 6F 6C 6F 73 73 61 6C");
	}
} sizeColossalFix;

class KukriFix : public TempleFix {
public:
	const char* name() override {
		return "Makes Kukri Proficiency Martial";
	}

	void apply() override {
		writeHex(0x102BFD78 + 30*4, "00 09"); // marks Kukri as Martial in the sense that picking "Martial Weapons Proficiency" will now list Kukri
		// see rest of fix in weapon.cpp IsMartialWeapon
	}
} kukriFix;

objHndl __cdecl ItemWornAtModifiedForTumlbeCheck(objHndl objHnd, uint32_t itemWornSlot)
{
	if (critterSys.GetRace(objHnd) == race_dwarf)
	{
		return 0;
	}
	else
	{
		return objects.inventory.ItemWornAt(objHnd, itemWornSlot);
	}
}

class DwarfTumbleFix : public TempleFix
{
public:
	const char* name() override {
		return "Allows Dwarves to tumble in heavy armor";
	}

	void apply() override {
		redirectCall(0x1008AB49, ItemWornAtModifiedForTumlbeCheck);
	}

	//
} dwarfTumbleFix;

class SpellSlingerGeneralFixes : public TempleFix
{
public:
	const char* name() override{
		return "Putting SpellSlinger's small fixes concentrated here :)";
	}

	void apply() override{
		// breakfree_on_entanglement_fix.txt
		writeHex(0x100D4259, "90 90 90 90  90 90");

		// caravan_encounter_fix.txt // looks like it has been updated since then too! 13D6 instead of 13D5
		writeHex(0x1006ED1E, "04");

		writeHex(0x1006FE1B + 1, "D6 13");
		writeHex(0x1007173C + 1, "D6 13");
		writeHex(0x1012BDF2 + 1, "D6 13");
		writeHex(0x1012C1EC + 1, "D6 13");
		writeHex(0x1012C361 + 1, "D6 13");

		// D20STDF_fix.txt

		writeHex(0x100B8454, "BA 00000000");
		writeHex(0x100B8471     , "8D4A 0D");

		// heavy_armor_prof_fix.txt

		writeHex(0x1007C49F, "6A 06");

		// NPC_usePotion_AoO_fix.txt

		writeHex(0x10098DE7+6, "44000000");

		// rep fallen paladin fix

		writeHex(0x1005481A, "00");

		// rgr_fav_enemy_fix.txt

		writeHex(0x101AD9BE, "90 90");

		// sp125_discern_lies_fix.txt // looks like this was actually forgotten to be implemented in the Co8 DLL
		writeHex(0x102D5454, "1E 00 00 00  22 00 00 00  00 2B 0D 10   00 00 00 00");
	}
};

static uint32_t (__cdecl *OrgFragarachAnswering)(DispatcherCallbackArgs);

uint32_t __cdecl HookedFragarachAnswering(DispatcherCallbackArgs args) {
	// checks if the current TB actor is the same as the "attachee" (critter taking damage)
	// if so, aborts the answering (you can have an AoO on your turn!)
	auto dispIO = args.dispIO;
	auto curActor = tbSys.turnBasedGetCurrentActor();
	auto attachee = args.objHndCaller;
	auto tgtObj = *(objHndl*)(dispIO + 2);
	//hooked_print_debug_message("Prevented Scather AoO bug! TB Actor is %s , Attachee is %s,  target is %s", description.getDisplayName(curActor), description.getDisplayName(attachee), description.getDisplayName(tgtObj));
	if (!tgtObj || !objects.IsCritter(tgtObj) || curActor == attachee)
	{
		hooked_print_debug_message("Prevented Scather AoO bug! TB Actor is %s , Attachee is %s,  target is %s", description.getDisplayName(curActor), description.getDisplayName(attachee), description.getDisplayName(tgtObj) );
		return 0;
	}
	auto result = OrgFragarachAnswering(args); // Call original method
	return result;
}

class FragarachAoOFix : public TempleFix
{
public:
	const char* name() override {
		return "Fixes the Fragarach hang that is caused by attacking a fire creature (which deals damage to the caster -> triggers the answering ability - > attempts an AoO -> but there is no one to AoO!)";
	}

	void apply() override {
		OrgFragarachAnswering = (uint32_t(__cdecl*)(DispatcherCallbackArgs)) replaceFunction(0x10104330, HookedFragarachAnswering);

	}
} fragarachAoOFix;

uint32_t GetCourageBonus(objHndl objHnd)
{
	auto bardLvl = (int32_t)objects.StatLevelGet(objHnd, stat_level_bard);
	if (bardLvl < 8) return 1;
	if (bardLvl < 14) return 2;
	if (bardLvl < 20) return 3;
	return 4;
};

uint32_t __cdecl BardicInspiredCourageInitArgs(DispatcherCallbackArgs args)
{
	conds.CondNodeSetArg(args.subDispNode->condNode, 0, 5);
	conds.CondNodeSetArg(args.subDispNode->condNode, 1, 0);
	auto courageBonus = 1;
	if ( objects.IsCritter(args.objHndCaller) )
	{
		courageBonus = GetCourageBonus(args.objHndCaller);
	}
	else
	{
		hooked_print_debug_message("Bardic Inspired Courage dispatched from non-critter! Mon seigneur %s", description.getDisplayName(args.objHndCaller));
	}
	conds.CondNodeSetArg(args.subDispNode->condNode, 3, courageBonus);
	return 0;
};

class BardicInspireCourageFix : public TempleFix
{
	public: const char* name() override {
		return "Bardic Inspire Courage Function Replacements";
	};
	void apply() override
	{
		replaceFunction(0x100EA5C0, BardicInspiredCourageInitArgs);
	}
} bardicInspireCourageFix;

class SorcererFailureDoubleChargeFix : public TempleFix
{
public: const char* name() override {
	return "Sorcerer Spell Failure Double Debit Fix";
};
		void apply() override
		{
			writeHex(0x1008D80E, "90 90 90 90 90");
		}
} sorcererSpellFailureFix;
<commit_msg>Fix for dual wielding Answering Swords hang<commit_after>
#include "stdafx.h"
#include "util/fixes.h"
#include "common.h"
#include "obj.h"
#include "turn_based.h"
#include "temple_functions.h"
#include "critter.h"
#include "condition.h"

class SizeColossalFix : public TempleFix {
public:
	const char* name() override {
		return "fixes size_colossal (was misspelled as size_clossal)";
	}

	void apply() override {
		writeHex(0x10278078, "73 69 7A 65 5F 63 6F 6C 6F 73 73 61 6C");
	}
} sizeColossalFix;

class KukriFix : public TempleFix {
public:
	const char* name() override {
		return "Makes Kukri Proficiency Martial";
	}

	void apply() override {
		writeHex(0x102BFD78 + 30*4, "00 09"); // marks Kukri as Martial in the sense that picking "Martial Weapons Proficiency" will now list Kukri
		// see rest of fix in weapon.cpp IsMartialWeapon
	}
} kukriFix;

objHndl __cdecl ItemWornAtModifiedForTumlbeCheck(objHndl objHnd, uint32_t itemWornSlot)
{
	if (critterSys.GetRace(objHnd) == race_dwarf)
	{
		return 0;
	}
	else
	{
		return objects.inventory.ItemWornAt(objHnd, itemWornSlot);
	}
}

class DwarfTumbleFix : public TempleFix
{
public:
	const char* name() override {
		return "Allows Dwarves to tumble in heavy armor";
	}

	void apply() override {
		redirectCall(0x1008AB49, ItemWornAtModifiedForTumlbeCheck);
	}

	//
} dwarfTumbleFix;

class SpellSlingerGeneralFixes : public TempleFix
{
public:
	const char* name() override{
		return "Putting SpellSlinger's small fixes concentrated here :)";
	}

	void apply() override{
		// breakfree_on_entanglement_fix.txt
		writeHex(0x100D4259, "90 90 90 90  90 90");

		// caravan_encounter_fix.txt // looks like it has been updated since then too! 13D6 instead of 13D5
		writeHex(0x1006ED1E, "04");

		writeHex(0x1006FE1B + 1, "D6 13");
		writeHex(0x1007173C + 1, "D6 13");
		writeHex(0x1012BDF2 + 1, "D6 13");
		writeHex(0x1012C1EC + 1, "D6 13");
		writeHex(0x1012C361 + 1, "D6 13");

		// D20STDF_fix.txt

		writeHex(0x100B8454, "BA 00000000");
		writeHex(0x100B8471     , "8D4A 0D");

		// heavy_armor_prof_fix.txt

		writeHex(0x1007C49F, "6A 06");

		// NPC_usePotion_AoO_fix.txt

		writeHex(0x10098DE7+6, "44000000");

		// rep fallen paladin fix

		writeHex(0x1005481A, "00");

		// rgr_fav_enemy_fix.txt

		writeHex(0x101AD9BE, "90 90");

		// sp125_discern_lies_fix.txt // looks like this was actually forgotten to be implemented in the Co8 DLL
		writeHex(0x102D5454, "1E 00 00 00  22 00 00 00  00 2B 0D 10   00 00 00 00");
	}
};

static uint32_t (__cdecl *OrgFragarachAnswering)(DispatcherCallbackArgs);

uint32_t __cdecl HookedFragarachAnswering(DispatcherCallbackArgs args) {
	// checks if the current TB actor is the same as the "attachee" (critter taking damage)
	// if so, aborts the answering (you can have an AoO on your turn!)
	auto dispIO = args.dispIO;
	auto curActor = tbSys.turnBasedGetCurrentActor();
	auto attachee = args.objHndCaller;
	auto tgtObj = *(objHndl*)(dispIO + 2);
	//hooked_print_debug_message("Prevented Scather AoO bug! TB Actor is %s , Attachee is %s,  target is %s", description.getDisplayName(curActor), description.getDisplayName(attachee), description.getDisplayName(tgtObj));
	if (!tgtObj || !objects.IsCritter(tgtObj) || curActor == attachee)
	{
		hooked_print_debug_message("Prevented Scather AoO bug! TB Actor is %s , Attachee is %s,  target is %s", description.getDisplayName(curActor), description.getDisplayName(attachee), description.getDisplayName(tgtObj) );
		return 0;
	}

	/*
	disable AoO effect for other identical conditions (so you don't get the 2 AoO Hang) // TODO: Makes this work like Great Cleave for maximum munchkinism
	*/
	if (conds.CondNodeGetArg(args.subDispNode->condNode, 0) == 1)
	{
		auto dispatcher = objects.GetDispatcher(args.objHndCaller);
		auto cond = &dispatcher->itemConds;
		while (*cond)
		{
			if ((*cond)->condStruct->condName == args.subDispNode->condNode->condStruct->condName
				&& (*cond) != args.subDispNode->condNode)
			{
				(*cond)->args[0] = 0;
			}
			cond = &(*cond)->nextCondNode;
		}
		auto result = OrgFragarachAnswering(args); // Call original method
		return result;
	}

	return 0;

}

class FragarachAoOFix : public TempleFix
{
public:
	const char* name() override {
		return "Fixes the Fragarach hang that is caused by attacking a fire creature (which deals damage to the caster -> triggers the answering ability - > attempts an AoO -> but there is no one to AoO!)";
	}

	void apply() override {
		OrgFragarachAnswering = (uint32_t(__cdecl*)(DispatcherCallbackArgs)) replaceFunction(0x10104330, HookedFragarachAnswering);

	}
} fragarachAoOFix;

uint32_t GetCourageBonus(objHndl objHnd)
{
	auto bardLvl = (int32_t)objects.StatLevelGet(objHnd, stat_level_bard);
	if (bardLvl < 8) return 1;
	if (bardLvl < 14) return 2;
	if (bardLvl < 20) return 3;
	return 4;
};

uint32_t __cdecl BardicInspiredCourageInitArgs(DispatcherCallbackArgs args)
{
	conds.CondNodeSetArg(args.subDispNode->condNode, 0, 5);
	conds.CondNodeSetArg(args.subDispNode->condNode, 1, 0);
	auto courageBonus = 1;
	if ( objects.IsCritter(args.objHndCaller) )
	{
		courageBonus = GetCourageBonus(args.objHndCaller);
	}
	else
	{
		hooked_print_debug_message("Bardic Inspired Courage dispatched from non-critter! Mon seigneur %s", description.getDisplayName(args.objHndCaller));
	}
	conds.CondNodeSetArg(args.subDispNode->condNode, 3, courageBonus);
	return 0;
};

class BardicInspireCourageFix : public TempleFix
{
	public: const char* name() override {
		return "Bardic Inspire Courage Function Replacements";
	};
	void apply() override
	{
		replaceFunction(0x100EA5C0, BardicInspiredCourageInitArgs);
	}
} bardicInspireCourageFix;

class SorcererFailureDoubleChargeFix : public TempleFix
{
public: const char* name() override {
	return "Sorcerer Spell Failure Double Debit Fix";
};
		void apply() override
		{
			writeHex(0x1008D80E, "90 90 90 90 90");
		}
} sorcererSpellFailureFix;
<|endoftext|>