<commit_before>/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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 "OpenGLProgram.h"

#include "OpenGLDriver.h"

#include <utils/Log.h>
#include <utils/compiler.h>
#include <utils/Panic.h>
#include <utils/debug.h>

#include <private/backend/BackendUtils.h>

#include <ctype.h>

namespace filament {

using namespace filament::math;
using namespace utils;
using namespace backend;

static void logCompilationError(utils::io::ostream& out,
        backend::Program::Shader shaderType, const char* name,
        GLuint shaderId, std::string_view source) noexcept;

static void logProgramLinkError(utils::io::ostream& out,
        const char* name, GLuint program) noexcept;

OpenGLProgram::OpenGLProgram(OpenGLDriver* gl, const Program& programBuilder) noexcept
        :  HwProgram(programBuilder.getName()), mIsValid(false) {

    using Shader = Program::Shader;

    const auto& shadersSource = programBuilder.getShadersSource();
    OpenGLContext& context = gl->getContext();

    // build all shaders
    #pragma nounroll
    for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
        GLenum glShaderType;
        Shader type = (Shader)i;
        switch (type) {
            case Shader::VERTEX:
                glShaderType = GL_VERTEX_SHADER;
                break;
            case Shader::FRAGMENT:
                glShaderType = GL_FRAGMENT_SHADER;
                break;
        }

        if (!shadersSource[i].empty()) {
            GLint status;
            Program::ShaderBlob shader = shadersSource[i];
            std::string temp;
            std::string_view shaderView((const char*)shader.data(), shader.size());

            if (!context.ext.GOOGLE_cpp_style_line_directive) {
                // If usages of the Google-style line directive are present, remove them, as some
                // drivers don't allow the quotation marks.
                if (UTILS_UNLIKELY(requestsGoogleLineDirectivesExtension(shaderView.data(), shaderView.size()))) {
                    temp = shaderView; // copy string
                    removeGoogleLineDirectives(temp.data(), temp.size()); // length is unaffected
                    shaderView = temp;
                }
            }

            if (UTILS_UNLIKELY(context.getShaderModel() == ShaderModel::GL_CORE_41 &&
                !context.ext.ARB_shading_language_packing)) {
                // Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 and
                // MacOS doesn't support GL_ARB_shading_language_packing
                if (temp.empty()) {
                    temp = shaderView; // copy string
                }

                std::string unpackHalf2x16{ R"(

// these don't handle denormals, NaNs or inf
float u16tofp32(highp uint v) {
    v <<= 16u;
    highp uint s = v & 0x80000000u;
    highp uint n = v & 0x7FFFFFFFu;
    highp uint nz = n == 0u ? 0u : 0xFFFFFFFF;
    return uintBitsToFloat(s | ((((n >> 3u) + (0x70u << 23))) & nz));
}
vec2 unpackHalf2x16(highp uint v) {
    return vec2(u16tofp32(v&0xFFFFu), u16tofp32(v>>16u));
}
uint fp32tou16(float val) {
    uint f32 = floatBitsToUint(val);
    uint f16 = 0u;
    uint sign = (f32 >> 16) & 0x8000u;
    int exponent = int((f32 >> 23) & 0xFFu) - 127;
    uint mantissa = f32 & 0x007FFFFFu;
    if (exponent > 15) {
        f16 = sign | (0x1Fu << 10);
    } else if (exponent > -15) {
        exponent += 15;
        mantissa >>= 13;
        f16 = sign | uint(exponent << 10) | mantissa;
    } else {
        f16 = sign;
    }
    return f16;
}
highp uint packHalf2x16(vec2 v) {
    highp uint x = fp32tou16(v.x);
    highp uint y = fp32tou16(v.y);
    return (y << 16) | x;
}
)"};
                // a good point for insertion is just before the first occurrence of an uniform block
                auto pos = temp.find("layout(std140)");
                if (pos != std::string_view::npos) {
                    temp.insert(pos, unpackHalf2x16);
                }
                shaderView = temp;
            }

            GLuint shaderId = glCreateShader(glShaderType);
            { // scope for source/length (we don't want them to leak out)
                const char* const source = shaderView.data();
                const GLint length = (GLint)shaderView.length();
                glShaderSource(shaderId, 1, &source, &length);
                glCompileShader(shaderId);
            }

            glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
            if (UTILS_UNLIKELY(status != GL_TRUE)) {
                logCompilationError(slog.e, type,
                        programBuilder.getName().c_str_safe(), shaderId, shaderView);
                glDeleteShader(shaderId);
                return;
            }
            this->gl.shaders[i] = shaderId;
            mValidShaderSet |= 1U << i;
        }
    }

    // we need at least a vertex and fragment program
    const uint8_t validShaderSet = mValidShaderSet;
    const uint8_t mask = VERTEX_SHADER_BIT | FRAGMENT_SHADER_BIT;
    if (UTILS_LIKELY((mValidShaderSet & mask) == mask)) {
        GLint status;
        GLuint program = glCreateProgram();
        for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
            if (validShaderSet & (1U << i)) {
                glAttachShader(program, this->gl.shaders[i]);
            }
        }
        glLinkProgram(program);

        glGetProgramiv(program, GL_LINK_STATUS, &status);
        if (UTILS_UNLIKELY(status != GL_TRUE)) {
            logProgramLinkError(slog.e, programBuilder.getName().c_str_safe(), program);
            glDeleteProgram(program);
            return;
        }

        this->gl.program = program;

        // Associate each UniformBlock in the program to a known binding.
        auto const& uniformBlockInfo = programBuilder.getUniformBlockInfo();
        #pragma nounroll
        for (GLuint binding = 0, n = uniformBlockInfo.size(); binding < n; binding++) {
            auto const& name = uniformBlockInfo[binding];
            if (!name.empty()) {
                GLint index = glGetUniformBlockIndex(program, name.c_str());
                if (index >= 0) {
                    glUniformBlockBinding(program, GLuint(index), binding);
                }
                CHECK_GL_ERROR(utils::slog.e)
            }
        }

        if (programBuilder.hasSamplers()) {
            // if we have samplers, we need to do a bit of extra work
            // activate this program so we can set all its samplers once and for all (glUniform1i)
            context.useProgram(program);

            auto const& samplerGroupInfo = programBuilder.getSamplerGroupInfo();
            auto& indicesRun = mIndicesRuns;
            uint8_t numUsedBindings = 0;
            uint8_t tmu = 0;

            #pragma nounroll
            for (size_t i = 0, c = samplerGroupInfo.size(); i < c; i++) {
                auto const& groupInfo = samplerGroupInfo[i];
                if (!groupInfo.empty()) {
                    // Cache the sampler uniform locations for each interface block
                    BlockInfo& info = mBlockInfos[numUsedBindings];
                    info.binding = uint8_t(i);
                    uint8_t count = 0;
                    for (uint8_t j = 0, m = uint8_t(groupInfo.size()); j < m; ++j) {
                        // find its location and associate a TMU to it
                        GLint loc = glGetUniformLocation(program, groupInfo[j].name.c_str());
                        if (loc >= 0) {
                            glUniform1i(loc, tmu);
                            indicesRun[tmu] = j;
                            count++;
                            tmu++;
                        } else {
                            // glGetUniformLocation could fail if the uniform is not used
                            // in the program. We should just ignore the error in that case.
                        }
                    }
                    if (count > 0) {
                        numUsedBindings++;
                        info.count = uint8_t(count - 1);
                    }
                }
            }
            mUsedBindingsCount = numUsedBindings;
        }
        mIsValid = true;
    }

    // Failing to compile a program can't be fatal, because this will happen a lot in
    // the material tools. We need to have a better way to handle these errors and
    // return to the editor. Also note the early "return" statements in this function.
    if (UTILS_UNLIKELY(!isValid())) {
        PANIC_LOG("Failed to compile GLSL program.");
    }
}

OpenGLProgram::~OpenGLProgram() noexcept {
    const size_t validShaderSet = mValidShaderSet;
    const bool isValid = mIsValid;
    GLuint program = gl.program;
    if (validShaderSet) {
        #pragma nounroll
        for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
            if (validShaderSet & (1U << i)) {
                const GLuint shader = gl.shaders[i];
                if (isValid) {
                    glDetachShader(program, shader);
                }
                glDeleteShader(shader);
            }
        }
    }
    if (isValid) {
        glDeleteProgram(program);
    }
}

void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
    using GLTexture = OpenGLDriver::GLTexture;

    // cache a few member variable locally, outside of the loop
    OpenGLContext& glc = gld->getContext();
    const bool anisotropyWorkaround = glc.ext.EXT_texture_filter_anisotropic &&
                                      glc.bugs.texture_filter_anisotropic_broken_on_sampler;
    auto const& UTILS_RESTRICT samplerBindings = gld->getSamplerBindings();
    auto const& UTILS_RESTRICT indicesRun = mIndicesRuns;
    auto const& UTILS_RESTRICT blockInfos = mBlockInfos;

    UTILS_ASSUME(mUsedBindingsCount > 0);
    for (uint8_t i = 0, tmu = 0, n = mUsedBindingsCount; i < n; i++) {
        BlockInfo blockInfo = blockInfos[i];
        HwSamplerGroup const * const UTILS_RESTRICT hwsb = samplerBindings[blockInfo.binding];
        if (UTILS_UNLIKELY(!hwsb)) {
#ifndef NDEBUG
            slog.w << "In material " << name.c_str()
                   << ": no sampler group to " << (uint32_t) blockInfo.binding << io::endl;
#endif
            continue;
        }
        SamplerGroup const& UTILS_RESTRICT sb = *(hwsb->sb);
        SamplerGroup::Sampler const* const UTILS_RESTRICT samplers = sb.getSamplers();
        for (uint8_t j = 0, m = blockInfo.count ; j <= m; ++j, ++tmu) { // "<=" on purpose here
            const uint8_t index = indicesRun[tmu];
            assert_invariant(index < sb.getSize());

            Handle<HwTexture> th = samplers[index].t;
            if (UTILS_UNLIKELY(!th)) {
#ifndef NDEBUG
                slog.w << "In material " << name.c_str()
                       << ": no texture bound to unit " << +index << io::endl;
#endif
                continue;
            }

            const GLTexture* const UTILS_RESTRICT t = gld->handle_cast<const GLTexture*>(th);
            if (UTILS_UNLIKELY(t->gl.fence)) {
                glWaitSync(t->gl.fence, 0, GL_TIMEOUT_IGNORED);
                glDeleteSync(t->gl.fence);
                t->gl.fence = nullptr;
            }

            SamplerParams params{ samplers[index].s };
            if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) {
                // From OES_EGL_image_external spec:
                // "The default s and t wrap modes are CLAMP_TO_EDGE and it is an INVALID_ENUM
                //  error to set the wrap mode to any other value."
                params.wrapS = SamplerWrapMode::CLAMP_TO_EDGE;
                params.wrapT = SamplerWrapMode::CLAMP_TO_EDGE;
                params.wrapR = SamplerWrapMode::CLAMP_TO_EDGE;
            }

            gld->bindTexture(tmu, t);
            gld->bindSampler(tmu, params);

#if defined(GL_EXT_texture_filter_anisotropic)
            if (UTILS_UNLIKELY(anisotropyWorkaround)) {
                // Driver claims to support anisotropic filtering, but it fails when set on
                // the sampler, we have to set it on the texture instead.
                // The texture is already bound here.
                GLfloat anisotropy = float(1u << params.anisotropyLog2);
                glTexParameterf(t->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
                        std::min(glc.gets.max_anisotropy, anisotropy));
            }
#endif
        }
    }
    CHECK_GL_ERROR(utils::slog.e)
}

UTILS_NOINLINE
void logCompilationError(io::ostream& out, Program::Shader shaderType,
        const char* name, GLuint shaderId, std::string_view shader) noexcept {

    auto to_string = [](Program::Shader type) -> const char* {
        switch (type) {
            case Program::Shader::VERTEX:       return "vertex";
            case Program::Shader::FRAGMENT:     return "fragment";
        }
    };

    char error[1024];
    glGetShaderInfoLog(shaderId, sizeof(error), nullptr, error);

    out << "Compilation error in " << to_string(shaderType) << " shader \"" << name << "\":\n"
        << "\"" << error << "\""
        << io::endl;

    size_t lc = 1;
    size_t start = 0;
    std::string line;
    while (true) {
        size_t end = shader.find('\n', start);
        if (end == std::string::npos) {
            line = shader.substr(start);
        } else {
            line = shader.substr(start, end - start);
        }
        out << lc++ << ":   "<< line.c_str() << '\n';
        if (end == std::string::npos) {
            break;
        }
        start = end + 1;
    }
    out << io::endl;
}

UTILS_NOINLINE
void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept {
    char error[1024];
    glGetProgramInfoLog(program, sizeof(error), nullptr, error);

    out << "Link error in \"" << name << "\":\n"
        << "\"" << error << "\""
        << io::endl;
}

} // namespace filament
<commit_msg>Remove an useless log<commit_after>/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * 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 "OpenGLProgram.h"

#include "OpenGLDriver.h"

#include <utils/Log.h>
#include <utils/compiler.h>
#include <utils/Panic.h>
#include <utils/debug.h>

#include <private/backend/BackendUtils.h>

#include <ctype.h>

namespace filament {

using namespace filament::math;
using namespace utils;
using namespace backend;

static void logCompilationError(utils::io::ostream& out,
        backend::Program::Shader shaderType, const char* name,
        GLuint shaderId, std::string_view source) noexcept;

static void logProgramLinkError(utils::io::ostream& out,
        const char* name, GLuint program) noexcept;

OpenGLProgram::OpenGLProgram(OpenGLDriver* gl, const Program& programBuilder) noexcept
        :  HwProgram(programBuilder.getName()), mIsValid(false) {

    using Shader = Program::Shader;

    const auto& shadersSource = programBuilder.getShadersSource();
    OpenGLContext& context = gl->getContext();

    // build all shaders
    #pragma nounroll
    for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
        GLenum glShaderType;
        Shader type = (Shader)i;
        switch (type) {
            case Shader::VERTEX:
                glShaderType = GL_VERTEX_SHADER;
                break;
            case Shader::FRAGMENT:
                glShaderType = GL_FRAGMENT_SHADER;
                break;
        }

        if (!shadersSource[i].empty()) {
            GLint status;
            Program::ShaderBlob shader = shadersSource[i];
            std::string temp;
            std::string_view shaderView((const char*)shader.data(), shader.size());

            if (!context.ext.GOOGLE_cpp_style_line_directive) {
                // If usages of the Google-style line directive are present, remove them, as some
                // drivers don't allow the quotation marks.
                if (UTILS_UNLIKELY(requestsGoogleLineDirectivesExtension(shaderView.data(), shaderView.size()))) {
                    temp = shaderView; // copy string
                    removeGoogleLineDirectives(temp.data(), temp.size()); // length is unaffected
                    shaderView = temp;
                }
            }

            if (UTILS_UNLIKELY(context.getShaderModel() == ShaderModel::GL_CORE_41 &&
                !context.ext.ARB_shading_language_packing)) {
                // Tragically, OpenGL 4.1 doesn't support unpackHalf2x16 and
                // MacOS doesn't support GL_ARB_shading_language_packing
                if (temp.empty()) {
                    temp = shaderView; // copy string
                }

                std::string unpackHalf2x16{ R"(

// these don't handle denormals, NaNs or inf
float u16tofp32(highp uint v) {
    v <<= 16u;
    highp uint s = v & 0x80000000u;
    highp uint n = v & 0x7FFFFFFFu;
    highp uint nz = n == 0u ? 0u : 0xFFFFFFFF;
    return uintBitsToFloat(s | ((((n >> 3u) + (0x70u << 23))) & nz));
}
vec2 unpackHalf2x16(highp uint v) {
    return vec2(u16tofp32(v&0xFFFFu), u16tofp32(v>>16u));
}
uint fp32tou16(float val) {
    uint f32 = floatBitsToUint(val);
    uint f16 = 0u;
    uint sign = (f32 >> 16) & 0x8000u;
    int exponent = int((f32 >> 23) & 0xFFu) - 127;
    uint mantissa = f32 & 0x007FFFFFu;
    if (exponent > 15) {
        f16 = sign | (0x1Fu << 10);
    } else if (exponent > -15) {
        exponent += 15;
        mantissa >>= 13;
        f16 = sign | uint(exponent << 10) | mantissa;
    } else {
        f16 = sign;
    }
    return f16;
}
highp uint packHalf2x16(vec2 v) {
    highp uint x = fp32tou16(v.x);
    highp uint y = fp32tou16(v.y);
    return (y << 16) | x;
}
)"};
                // a good point for insertion is just before the first occurrence of an uniform block
                auto pos = temp.find("layout(std140)");
                if (pos != std::string_view::npos) {
                    temp.insert(pos, unpackHalf2x16);
                }
                shaderView = temp;
            }

            GLuint shaderId = glCreateShader(glShaderType);
            { // scope for source/length (we don't want them to leak out)
                const char* const source = shaderView.data();
                const GLint length = (GLint)shaderView.length();
                glShaderSource(shaderId, 1, &source, &length);
                glCompileShader(shaderId);
            }

            glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
            if (UTILS_UNLIKELY(status != GL_TRUE)) {
                logCompilationError(slog.e, type,
                        programBuilder.getName().c_str_safe(), shaderId, shaderView);
                glDeleteShader(shaderId);
                return;
            }
            this->gl.shaders[i] = shaderId;
            mValidShaderSet |= 1U << i;
        }
    }

    // we need at least a vertex and fragment program
    const uint8_t validShaderSet = mValidShaderSet;
    const uint8_t mask = VERTEX_SHADER_BIT | FRAGMENT_SHADER_BIT;
    if (UTILS_LIKELY((mValidShaderSet & mask) == mask)) {
        GLint status;
        GLuint program = glCreateProgram();
        for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
            if (validShaderSet & (1U << i)) {
                glAttachShader(program, this->gl.shaders[i]);
            }
        }
        glLinkProgram(program);

        glGetProgramiv(program, GL_LINK_STATUS, &status);
        if (UTILS_UNLIKELY(status != GL_TRUE)) {
            logProgramLinkError(slog.e, programBuilder.getName().c_str_safe(), program);
            glDeleteProgram(program);
            return;
        }

        this->gl.program = program;

        // Associate each UniformBlock in the program to a known binding.
        auto const& uniformBlockInfo = programBuilder.getUniformBlockInfo();
        #pragma nounroll
        for (GLuint binding = 0, n = uniformBlockInfo.size(); binding < n; binding++) {
            auto const& name = uniformBlockInfo[binding];
            if (!name.empty()) {
                GLint index = glGetUniformBlockIndex(program, name.c_str());
                if (index >= 0) {
                    glUniformBlockBinding(program, GLuint(index), binding);
                }
                CHECK_GL_ERROR(utils::slog.e)
            }
        }

        if (programBuilder.hasSamplers()) {
            // if we have samplers, we need to do a bit of extra work
            // activate this program so we can set all its samplers once and for all (glUniform1i)
            context.useProgram(program);

            auto const& samplerGroupInfo = programBuilder.getSamplerGroupInfo();
            auto& indicesRun = mIndicesRuns;
            uint8_t numUsedBindings = 0;
            uint8_t tmu = 0;

            #pragma nounroll
            for (size_t i = 0, c = samplerGroupInfo.size(); i < c; i++) {
                auto const& groupInfo = samplerGroupInfo[i];
                if (!groupInfo.empty()) {
                    // Cache the sampler uniform locations for each interface block
                    BlockInfo& info = mBlockInfos[numUsedBindings];
                    info.binding = uint8_t(i);
                    uint8_t count = 0;
                    for (uint8_t j = 0, m = uint8_t(groupInfo.size()); j < m; ++j) {
                        // find its location and associate a TMU to it
                        GLint loc = glGetUniformLocation(program, groupInfo[j].name.c_str());
                        if (loc >= 0) {
                            glUniform1i(loc, tmu);
                            indicesRun[tmu] = j;
                            count++;
                            tmu++;
                        } else {
                            // glGetUniformLocation could fail if the uniform is not used
                            // in the program. We should just ignore the error in that case.
                        }
                    }
                    if (count > 0) {
                        numUsedBindings++;
                        info.count = uint8_t(count - 1);
                    }
                }
            }
            mUsedBindingsCount = numUsedBindings;
        }
        mIsValid = true;
    }

    // Failing to compile a program can't be fatal, because this will happen a lot in
    // the material tools. We need to have a better way to handle these errors and
    // return to the editor. Also note the early "return" statements in this function.
    if (UTILS_UNLIKELY(!isValid())) {
        PANIC_LOG("Failed to compile GLSL program.");
    }
}

OpenGLProgram::~OpenGLProgram() noexcept {
    const size_t validShaderSet = mValidShaderSet;
    const bool isValid = mIsValid;
    GLuint program = gl.program;
    if (validShaderSet) {
        #pragma nounroll
        for (size_t i = 0; i < Program::SHADER_TYPE_COUNT; i++) {
            if (validShaderSet & (1U << i)) {
                const GLuint shader = gl.shaders[i];
                if (isValid) {
                    glDetachShader(program, shader);
                }
                glDeleteShader(shader);
            }
        }
    }
    if (isValid) {
        glDeleteProgram(program);
    }
}

void OpenGLProgram::updateSamplers(OpenGLDriver* gld) noexcept {
    using GLTexture = OpenGLDriver::GLTexture;

    // cache a few member variable locally, outside of the loop
    OpenGLContext& glc = gld->getContext();
    const bool anisotropyWorkaround = glc.ext.EXT_texture_filter_anisotropic &&
                                      glc.bugs.texture_filter_anisotropic_broken_on_sampler;
    auto const& UTILS_RESTRICT samplerBindings = gld->getSamplerBindings();
    auto const& UTILS_RESTRICT indicesRun = mIndicesRuns;
    auto const& UTILS_RESTRICT blockInfos = mBlockInfos;

    UTILS_ASSUME(mUsedBindingsCount > 0);
    for (uint8_t i = 0, tmu = 0, n = mUsedBindingsCount; i < n; i++) {
        BlockInfo blockInfo = blockInfos[i];
        HwSamplerGroup const * const UTILS_RESTRICT hwsb = samplerBindings[blockInfo.binding];
        if (UTILS_UNLIKELY(!hwsb)) {
            continue;
        }
        SamplerGroup const& UTILS_RESTRICT sb = *(hwsb->sb);
        SamplerGroup::Sampler const* const UTILS_RESTRICT samplers = sb.getSamplers();
        for (uint8_t j = 0, m = blockInfo.count ; j <= m; ++j, ++tmu) { // "<=" on purpose here
            const uint8_t index = indicesRun[tmu];
            assert_invariant(index < sb.getSize());

            Handle<HwTexture> th = samplers[index].t;
            if (UTILS_UNLIKELY(!th)) {
#ifndef NDEBUG
                slog.w << "In material " << name.c_str()
                       << ": no texture bound to unit " << +index << io::endl;
#endif
                continue;
            }

            const GLTexture* const UTILS_RESTRICT t = gld->handle_cast<const GLTexture*>(th);
            if (UTILS_UNLIKELY(t->gl.fence)) {
                glWaitSync(t->gl.fence, 0, GL_TIMEOUT_IGNORED);
                glDeleteSync(t->gl.fence);
                t->gl.fence = nullptr;
            }

            SamplerParams params{ samplers[index].s };
            if (UTILS_UNLIKELY(t->target == SamplerType::SAMPLER_EXTERNAL)) {
                // From OES_EGL_image_external spec:
                // "The default s and t wrap modes are CLAMP_TO_EDGE and it is an INVALID_ENUM
                //  error to set the wrap mode to any other value."
                params.wrapS = SamplerWrapMode::CLAMP_TO_EDGE;
                params.wrapT = SamplerWrapMode::CLAMP_TO_EDGE;
                params.wrapR = SamplerWrapMode::CLAMP_TO_EDGE;
            }

            gld->bindTexture(tmu, t);
            gld->bindSampler(tmu, params);

#if defined(GL_EXT_texture_filter_anisotropic)
            if (UTILS_UNLIKELY(anisotropyWorkaround)) {
                // Driver claims to support anisotropic filtering, but it fails when set on
                // the sampler, we have to set it on the texture instead.
                // The texture is already bound here.
                GLfloat anisotropy = float(1u << params.anisotropyLog2);
                glTexParameterf(t->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT,
                        std::min(glc.gets.max_anisotropy, anisotropy));
            }
#endif
        }
    }
    CHECK_GL_ERROR(utils::slog.e)
}

UTILS_NOINLINE
void logCompilationError(io::ostream& out, Program::Shader shaderType,
        const char* name, GLuint shaderId, std::string_view shader) noexcept {

    auto to_string = [](Program::Shader type) -> const char* {
        switch (type) {
            case Program::Shader::VERTEX:       return "vertex";
            case Program::Shader::FRAGMENT:     return "fragment";
        }
    };

    char error[1024];
    glGetShaderInfoLog(shaderId, sizeof(error), nullptr, error);

    out << "Compilation error in " << to_string(shaderType) << " shader \"" << name << "\":\n"
        << "\"" << error << "\""
        << io::endl;

    size_t lc = 1;
    size_t start = 0;
    std::string line;
    while (true) {
        size_t end = shader.find('\n', start);
        if (end == std::string::npos) {
            line = shader.substr(start);
        } else {
            line = shader.substr(start, end - start);
        }
        out << lc++ << ":   "<< line.c_str() << '\n';
        if (end == std::string::npos) {
            break;
        }
        start = end + 1;
    }
    out << io::endl;
}

UTILS_NOINLINE
void logProgramLinkError(io::ostream& out, char const* name, GLuint program) noexcept {
    char error[1024];
    glGetProgramInfoLog(program, sizeof(error), nullptr, error);

    out << "Link error in \"" << name << "\":\n"
        << "\"" << error << "\""
        << io::endl;
}

} // namespace filament
<|endoftext|>


<commit_before>#include <map>
#include <iostream>
#include <sstream>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/Text.h>
#include <Poco/DOM/AutoPtr.h>
#include <Poco/DOM/DOMWriter.h>
#include <Poco/XML/XMLWriter.h>
#include <Poco/XML/XMLStream.h>
#include <Poco/NumberFormatter.h>

#include "PurchaseServiceInformation.h"

using namespace Poco::Data::Keywords;

namespace ChoiceNet
{
namespace Eco
{

PurchaseServiceInformation::PurchaseServiceInformation()
{

}
PurchaseServiceInformation::~PurchaseServiceInformation()
{

	std::map<std::string,double>::iterator it;
	it = _summaries_by_bid.begin();
	while (it != _summaries_by_bid.end())
	{
		// std::cout << "Bid:" << it->first << " Quantity:" << it->second;
		++it;
	}

}

void PurchaseServiceInformation::addPurchase(Purchase * purchasePtr)
{
	// std::cout << "Starting add purchase" <<  std::endl;
	std::map<std::string,double>::iterator it;
	// std::cout << "Bid id:" <<  (*purchasePtr).getBid() << std::endl;
	it = _summaries_by_bid.find((*purchasePtr).getBid());
	if (it != _summaries_by_bid.end())
	{
		// std::cout << "Bid id found" << std::endl;
		it->second += (*purchasePtr).getQuantity();
	}
	else
	{
		 // std::cout << "Bid id inserted" << std::endl;
		_summaries_by_bid.insert(std::pair<std::string,double>((*purchasePtr).getBid(), (*purchasePtr).getQuantity() ));
	}
	_detail.push_back((*purchasePtr).getId());
}

void PurchaseServiceInformation::createBidNode(Poco::XML::AutoPtr<Poco::XML::Document> pDoc,
							 Poco::XML::AutoPtr<Poco::XML::Element> pParent,
							 std::string id, double quantity)
{

	// Puts the id for the bid
	Poco::XML::AutoPtr<Poco::XML::Element> pId =
							    pDoc->createElement("Id");
	Poco::XML::AutoPtr<Poco::XML::Text> pText1 = pDoc->createTextNode(id);
	pId->appendChild(pText1);

	// Puts the Quantity for the competitor
	Poco::XML::AutoPtr<Poco::XML::Element> pQuantity =
								pDoc->createElement("Quantity");
	std::string valueStr;
	Poco::NumberFormatter::append(valueStr, quantity);
	Poco::XML::AutoPtr<Poco::XML::Text> pText2 =
								pDoc->createTextNode(valueStr);
	pQuantity->appendChild(pText2);

	pParent->appendChild(pId);
	pParent->appendChild(pQuantity);

}
void PurchaseServiceInformation::createCompetitorBidNode(Poco::XML::AutoPtr<Poco::XML::Document> pDoc,
							 Poco::XML::AutoPtr<Poco::XML::Element> pParent,
							 std::string id, double quantity)
{
	Poco::XML::AutoPtr<Poco::XML::Element> proot_Competitor =
							pDoc->createElement("Cmp_Bid");

	// Puts the id for the competitor
	Poco::XML::AutoPtr<Poco::XML::Element> pId_Competitor =
							pDoc->createElement("Id_C");
	Poco::XML::AutoPtr<Poco::XML::Text> pText1 = pDoc->createTextNode(id);
	pId_Competitor->appendChild(pText1);

	// Puts the Quantity for the competitor
	Poco::XML::AutoPtr<Poco::XML::Element> pQuantity_Competitor =
							pDoc->createElement("Q_C");
	std::string valueStr;
	Poco::NumberFormatter::append(valueStr, quantity);
	Poco::XML::AutoPtr<Poco::XML::Text> pText2 =
							pDoc->createTextNode(valueStr);
	pQuantity_Competitor->appendChild(pText2);

	// Attach both nodes to competitor root.
	proot_Competitor->appendChild(pId_Competitor);
	proot_Competitor->appendChild(pQuantity_Competitor);
	pParent->appendChild(proot_Competitor);
}

void PurchaseServiceInformation::getPurchases(Poco::XML::AutoPtr<Poco::XML::Document> pDoc,
											  Poco::XML::AutoPtr<Poco::XML::Element> pParent,
											  std::map<std::string, std::vector<std::string> > & bids)
{
	std::map<std::string, std::vector<std::string> >::iterator it;
	it = bids.begin();
	while (it != bids.end())
	{
		 // std::cout << "Bid to send purchase:" << it->first << std::endl;

		 std::map<std::string, double>::iterator it_purchase;
		 it_purchase = _summaries_by_bid.find(it->first);
		 if (it_purchase != _summaries_by_bid.end())
		 {
				Poco::XML::AutoPtr<Poco::XML::Element> proot =
								pDoc->createElement("Bid");

				// std::cout << "Bid Node information to send" << it_purchase->first << " Quantity:" << it_purchase->second;
				createBidNode( pDoc, proot, it_purchase->first, it_purchase->second );

				// Iterate over the Bid of competitors
				std::vector<std::string>::iterator it_bid_competitors;
				for (it_bid_competitors = it->second.begin(); it_bid_competitors != it->second.end(); ++it_bid_competitors)
				{
					// std::cout << "Competitor Bid to send:" << std::endl;

					it_purchase = _summaries_by_bid.find(*it_bid_competitors);
					if (it_purchase != _summaries_by_bid.end())
					{
						createCompetitorBidNode(pDoc, proot, it_purchase->first, it_purchase->second);
					}
					else
					{
						createCompetitorBidNode(pDoc, proot, *it_bid_competitors, 0);
					}

				}
			    pParent->appendChild(proot);
		 }
		 else
		 {
			 	Poco::XML::AutoPtr<Poco::XML::Element> proot =
											pDoc->createElement("Bid");

				createBidNode( pDoc, proot, it->first, 0 );

				// Iterate over the Bid of competitors
				std::vector<std::string>::iterator it_bid_competitors;
				for (it_bid_competitors = it->second.begin(); it_bid_competitors != it->second.end(); ++it_bid_competitors)
				{
					// std::cout << "Competitor Bid to send:" << std::endl;

					it_purchase = _summaries_by_bid.find(*it_bid_competitors);
					if (it_purchase != _summaries_by_bid.end())
					{
						createCompetitorBidNode(pDoc, proot, it_purchase->first, it_purchase->second);
					}
					else
					{
						createCompetitorBidNode(pDoc, proot, *it_bid_competitors, 0);
					}

				}
			    pParent->appendChild(proot);
		 }
		++it;
	}

	// std::cout << "Finish getPurchases:" << std::endl;
}

void PurchaseServiceInformation::toDatabase(Poco::Data::SessionPool * _pool, int execution_count, int period, std::string serviceId)
{

	Poco::Data::Session session(_pool->get());
	Poco::Data::Statement insert(session);
	bool firstTime = true;
	PurchaseServiceBidStruct PurchaseServiceBidS;

	std::map<std::string, double>::iterator it_purchase;
	for (it_purchase = _summaries_by_bid.begin(); it_purchase != _summaries_by_bid.end(); ++it_purchase)
	{

		PurchaseServiceBidS._period =  period;
		PurchaseServiceBidS._serviceId =  serviceId;
		PurchaseServiceBidS._bidId =  it_purchase->first;
		PurchaseServiceBidS._quantity =  (double) it_purchase->second;
		PurchaseServiceBidS._execution_count = execution_count;

		if (firstTime == true){

			insert << "insert into simulation_bid_purchases(period, serviceId, bidId, quantity) values(?,?,?,?)",
						use(PurchaseServiceBidS._period),
						use(PurchaseServiceBidS._serviceId),
						use(PurchaseServiceBidS._bidId),
						use(PurchaseServiceBidS._quantity);

			insert.execute();
			firstTime = false;

		} else {
			insert.execute();
		}

	}
}

}  /// End Eco namespace

}  /// End ChoiceNet namespace

<commit_msg>Error in SQl Statement<commit_after>#include <map>
#include <iostream>
#include <sstream>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/Text.h>
#include <Poco/DOM/AutoPtr.h>
#include <Poco/DOM/DOMWriter.h>
#include <Poco/XML/XMLWriter.h>
#include <Poco/XML/XMLStream.h>
#include <Poco/NumberFormatter.h>

#include "PurchaseServiceInformation.h"

using namespace Poco::Data::Keywords;

namespace ChoiceNet
{
namespace Eco
{

PurchaseServiceInformation::PurchaseServiceInformation()
{

}
PurchaseServiceInformation::~PurchaseServiceInformation()
{

	std::map<std::string,double>::iterator it;
	it = _summaries_by_bid.begin();
	while (it != _summaries_by_bid.end())
	{
		// std::cout << "Bid:" << it->first << " Quantity:" << it->second;
		++it;
	}

}

void PurchaseServiceInformation::addPurchase(Purchase * purchasePtr)
{
	// std::cout << "Starting add purchase" <<  std::endl;
	std::map<std::string,double>::iterator it;
	// std::cout << "Bid id:" <<  (*purchasePtr).getBid() << std::endl;
	it = _summaries_by_bid.find((*purchasePtr).getBid());
	if (it != _summaries_by_bid.end())
	{
		// std::cout << "Bid id found" << std::endl;
		it->second += (*purchasePtr).getQuantity();
	}
	else
	{
		 // std::cout << "Bid id inserted" << std::endl;
		_summaries_by_bid.insert(std::pair<std::string,double>((*purchasePtr).getBid(), (*purchasePtr).getQuantity() ));
	}
	_detail.push_back((*purchasePtr).getId());
}

void PurchaseServiceInformation::createBidNode(Poco::XML::AutoPtr<Poco::XML::Document> pDoc,
							 Poco::XML::AutoPtr<Poco::XML::Element> pParent,
							 std::string id, double quantity)
{

	// Puts the id for the bid
	Poco::XML::AutoPtr<Poco::XML::Element> pId =
							    pDoc->createElement("Id");
	Poco::XML::AutoPtr<Poco::XML::Text> pText1 = pDoc->createTextNode(id);
	pId->appendChild(pText1);

	// Puts the Quantity for the competitor
	Poco::XML::AutoPtr<Poco::XML::Element> pQuantity =
								pDoc->createElement("Quantity");
	std::string valueStr;
	Poco::NumberFormatter::append(valueStr, quantity);
	Poco::XML::AutoPtr<Poco::XML::Text> pText2 =
								pDoc->createTextNode(valueStr);
	pQuantity->appendChild(pText2);

	pParent->appendChild(pId);
	pParent->appendChild(pQuantity);

}
void PurchaseServiceInformation::createCompetitorBidNode(Poco::XML::AutoPtr<Poco::XML::Document> pDoc,
							 Poco::XML::AutoPtr<Poco::XML::Element> pParent,
							 std::string id, double quantity)
{
	Poco::XML::AutoPtr<Poco::XML::Element> proot_Competitor =
							pDoc->createElement("Cmp_Bid");

	// Puts the id for the competitor
	Poco::XML::AutoPtr<Poco::XML::Element> pId_Competitor =
							pDoc->createElement("Id_C");
	Poco::XML::AutoPtr<Poco::XML::Text> pText1 = pDoc->createTextNode(id);
	pId_Competitor->appendChild(pText1);

	// Puts the Quantity for the competitor
	Poco::XML::AutoPtr<Poco::XML::Element> pQuantity_Competitor =
							pDoc->createElement("Q_C");
	std::string valueStr;
	Poco::NumberFormatter::append(valueStr, quantity);
	Poco::XML::AutoPtr<Poco::XML::Text> pText2 =
							pDoc->createTextNode(valueStr);
	pQuantity_Competitor->appendChild(pText2);

	// Attach both nodes to competitor root.
	proot_Competitor->appendChild(pId_Competitor);
	proot_Competitor->appendChild(pQuantity_Competitor);
	pParent->appendChild(proot_Competitor);
}

void PurchaseServiceInformation::getPurchases(Poco::XML::AutoPtr<Poco::XML::Document> pDoc,
											  Poco::XML::AutoPtr<Poco::XML::Element> pParent,
											  std::map<std::string, std::vector<std::string> > & bids)
{
	std::map<std::string, std::vector<std::string> >::iterator it;
	it = bids.begin();
	while (it != bids.end())
	{
		 // std::cout << "Bid to send purchase:" << it->first << std::endl;

		 std::map<std::string, double>::iterator it_purchase;
		 it_purchase = _summaries_by_bid.find(it->first);
		 if (it_purchase != _summaries_by_bid.end())
		 {
				Poco::XML::AutoPtr<Poco::XML::Element> proot =
								pDoc->createElement("Bid");

				// std::cout << "Bid Node information to send" << it_purchase->first << " Quantity:" << it_purchase->second;
				createBidNode( pDoc, proot, it_purchase->first, it_purchase->second );

				// Iterate over the Bid of competitors
				std::vector<std::string>::iterator it_bid_competitors;
				for (it_bid_competitors = it->second.begin(); it_bid_competitors != it->second.end(); ++it_bid_competitors)
				{
					// std::cout << "Competitor Bid to send:" << std::endl;

					it_purchase = _summaries_by_bid.find(*it_bid_competitors);
					if (it_purchase != _summaries_by_bid.end())
					{
						createCompetitorBidNode(pDoc, proot, it_purchase->first, it_purchase->second);
					}
					else
					{
						createCompetitorBidNode(pDoc, proot, *it_bid_competitors, 0);
					}

				}
			    pParent->appendChild(proot);
		 }
		 else
		 {
			 	Poco::XML::AutoPtr<Poco::XML::Element> proot =
											pDoc->createElement("Bid");

				createBidNode( pDoc, proot, it->first, 0 );

				// Iterate over the Bid of competitors
				std::vector<std::string>::iterator it_bid_competitors;
				for (it_bid_competitors = it->second.begin(); it_bid_competitors != it->second.end(); ++it_bid_competitors)
				{
					// std::cout << "Competitor Bid to send:" << std::endl;

					it_purchase = _summaries_by_bid.find(*it_bid_competitors);
					if (it_purchase != _summaries_by_bid.end())
					{
						createCompetitorBidNode(pDoc, proot, it_purchase->first, it_purchase->second);
					}
					else
					{
						createCompetitorBidNode(pDoc, proot, *it_bid_competitors, 0);
					}

				}
			    pParent->appendChild(proot);
		 }
		++it;
	}

	// std::cout << "Finish getPurchases:" << std::endl;
}

void PurchaseServiceInformation::toDatabase(Poco::Data::SessionPool * _pool, int execution_count, int period, std::string serviceId)
{

	Poco::Data::Session session(_pool->get());
	Poco::Data::Statement insert(session);
	bool firstTime = true;
	PurchaseServiceBidStruct PurchaseServiceBidS;

	std::map<std::string, double>::iterator it_purchase;
	for (it_purchase = _summaries_by_bid.begin(); it_purchase != _summaries_by_bid.end(); ++it_purchase)
	{

		PurchaseServiceBidS._period =  period;
		PurchaseServiceBidS._serviceId =  serviceId;
		PurchaseServiceBidS._bidId =  it_purchase->first;
		PurchaseServiceBidS._quantity =  (double) it_purchase->second;
		PurchaseServiceBidS._execution_count = execution_count;

		if (firstTime == true){

			insert << "insert into simulation_bid_purchases(period, serviceId, bidId, quantity, execution_count) values(?,?,?,?,?)",
						use(PurchaseServiceBidS._period),
						use(PurchaseServiceBidS._serviceId),
						use(PurchaseServiceBidS._bidId),
						use(PurchaseServiceBidS._quantity),
						use(PurchaseServiceBidS._execution_count);

			insert.execute();
			firstTime = false;

		} else {
			insert.execute();
		}

	}
}

}  /// End Eco namespace

}  /// End ChoiceNet namespace

<|endoftext|>


<commit_before>/*
 * SharedMemoryController.cpp
 *
 *  Created on: 31 May 2016
 *      Author: gnx91527
 */

#include <SharedMemoryController.h>

namespace FrameProcessor
{

/** Constructor.
 *
 * The constructor sets up logging used within the class. It also creates the
 * rxChannel_ subscribing IpcChannel and registers it with the IpcReactor reactor_.
 * Finally, the txChannel_ publishing IpcChannel is created. rxChannel_ is a ZeroMQ
 * subscriber (listening for frame ready notifications from the frame recevier) and
 * txChannel_ is a ZeroMQ plublisher that sends notifications (of released frames to
 * the frame receiver).
 *
 * \param[in] reactor - pointer to the IpcReactor object.
 * \param[in] rxEndPoint - string name of the subscribing endpoint for frame ready notifications.
 * \param[in] txEndPoint - string name of the publishing endpoint for frame release notifications.
 */
SharedMemoryController::SharedMemoryController(boost::shared_ptr<OdinData::IpcReactor> reactor,
                                               const std::string& rxEndPoint,
                                               const std::string& txEndPoint) :
    reactor_(reactor),
    rxChannel_(ZMQ_SUB),
    txChannel_(ZMQ_PUB)
{
  // Setup logging for the class
  logger_ = Logger::getLogger("FW.SharedMemoryController");
  logger_->setLevel(Level::getAll());
  LOG4CXX_TRACE(logger_, "SharedMemoryController constructor.");

  // Connect the frame ready channel
  try {
    LOG4CXX_DEBUG(logger_, "Connecting RX Channel to endpoint: " << rxEndPoint);
    rxChannel_.connect(rxEndPoint.c_str());
    rxChannel_.subscribe("");
  }
  catch (zmq::error_t& e) {
    //std::stringstream ss;
    //ss << "RX channel connect to endpoint " << config_.rx_channel_endpoint_ << " failed: " << e.what();
    // TODO: What to do here, I think throw it up
    throw std::runtime_error(e.what());
  }

  // Add the Frame Ready channel to the reactor
  reactor_->register_channel(rxChannel_, boost::bind(&SharedMemoryController::handleRxChannel, this));

  // Now connect the frame release response channel
  try {
    LOG4CXX_DEBUG(logger_, "Connecting TX Channel to endpoint: " << txEndPoint);
    txChannel_.connect(txEndPoint.c_str());
  }
  catch (zmq::error_t& e) {
    //std::stringstream ss;
    //ss << "RX channel connect to endpoint " << config_.rx_channel_endpoint_ << " failed: " << e.what();
    // TODO: What to do here, I think throw it up
    throw std::runtime_error(e.what());
  }
}

/**
 * Destructor.
 */
SharedMemoryController::~SharedMemoryController()
{
  LOG4CXX_TRACE(logger_, "Shutting down SharedMemoryController");
  // Close the IPC Channels
  reactor_->remove_channel(txChannel_);
  reactor_->remove_channel(rxChannel_);
  txChannel_.close();
  rxChannel_.close();
  // Stop the SharedMemoryController reactor
  reactor_->stop();
}

/** setSharedMemoryParser
 * Takes a shared pointer to a shared memory parser and stores it in
 * a member variable.
 *
 * \param[in] smp - shared pointer to a SharedMemoryParser object.
 */
void SharedMemoryController::setSharedBufferManager(boost::shared_ptr<OdinData::SharedBufferManager> sbm)
{
  sbm_ = sbm;
}

/** Called whenever a new IpcMessage is received to notify that a frame is ready.
 *
 * Reads the raw message bytes from the rxChannel_ and constructs an IpcMessage object
 * from the bytes. Verifies the IpcMessage type and value, and then uses the frame
 * number and buffer ID information to tell the SharedMemoryParser which frame is ready
 * for extraction from shared memory.
 * Loops over registered callbacks and passes the frame to the relevant WorkQueue objects,
 * before sending notifiation that the frame has been released for re-use.
 */
void SharedMemoryController::handleRxChannel()
{
  // Receive a message from the main thread channel
  std::string rxMsgEncoded = rxChannel_.recv();

  LOG4CXX_DEBUG(logger_, "RX thread called with message: " << rxMsgEncoded);

  // Parse and handle the message
  try {
    OdinData::IpcMessage rxMsg(rxMsgEncoded.c_str());

    if ((rxMsg.get_msg_type() == OdinData::IpcMessage::MsgTypeNotify) &&
        (rxMsg.get_msg_val()  == OdinData::IpcMessage::MsgValNotifyFrameReady)) {
      int bufferID = rxMsg.get_param<int>("buffer_id", -1);

      if (bufferID != -1) {
        // Create a frame object and copy in the raw frame data
        boost::shared_ptr<Frame> frame;
        frame = boost::shared_ptr<Frame>(new Frame("raw"));
        frame->wrap_shared_buffer(sbm_->get_buffer_address(bufferID),
                                  sbm_->get_buffer_size(),
                                  bufferID,rxMsg.get_param<int>("frame", 0),
                                  &txChannel_);

        // Set the frame number
        frame->set_frame_number(rxMsg.get_param<int>("frame", 0));

        // Loop over registered callbacks, placing the frame onto each queue
        std::map<std::string, boost::shared_ptr<IFrameCallback> >::iterator cbIter;
        for (cbIter = callbacks_.begin(); cbIter != callbacks_.end(); ++cbIter) {
          cbIter->second->getWorkQueue()->add(frame);
        }

      } else {
        LOG4CXX_ERROR(logger_, "RX thread received empty frame notification with buffer ID");
      }
    } else {
      LOG4CXX_ERROR(logger_, "RX thread got unexpected message: " << rxMsgEncoded);

      //IpcMessage rx_reply;

      //rx_reply.set_msg_type(IpcMessage::MsgTypeNack);
      //rx_reply.set_msg_val(rx_msg.get_msg_val());
      //TODO add error in params

      //rx_channel_.send(rx_reply.encode());
    }
  }
  catch (OdinData::IpcMessageException& e)
  {
    LOG4CXX_ERROR(logger_, "Error decoding control channel request: " << e.what());
  }
}

/** Register a callback for Frame updates with this class.
 *
 * The callback (IFrameCallback subclass) is added to the map of callbacks, indexed
 * by name. Whenever a new Frame object is received from the frame receiver then these
 * callbacks will be called and passed the Frame pointer.
 *
 * \param[in] name - string index of the callback.
 * \param[in] cb - IFrameCallback to register for updates.
 */
void SharedMemoryController::registerCallback(const std::string& name, boost::shared_ptr<IFrameCallback> cb)
{
  // Check if we own the callback already
  if (callbacks_.count(name) == 0) {
    // Record the callback pointer
    callbacks_[name] = cb;
    // Confirm registration
    cb->confirmRegistration("frame_receiver");
  }
}

/** Remove a callback from the callback map.
 *
 * The callback is removed from the map of callbacks.
 *
 * \param[in] name - string index of the callback.
 */
void SharedMemoryController::removeCallback(const std::string& name)
{
  boost::shared_ptr<IFrameCallback> cb;
  if (callbacks_.count(name) > 0) {
    // Get the pointer
    cb = callbacks_[name];
    // Remove the callback from the map
    callbacks_.erase(name);
    // Confirm removal
    cb->confirmRemoval("frame_receiver");
  }
}

} /* namespace FrameProcessor */
<commit_msg>Added handling of buffer configuration notification messages<commit_after>/*
 * SharedMemoryController.cpp
 *
 *  Created on: 31 May 2016
 *      Author: gnx91527
 */

#include <SharedMemoryController.h>

namespace FrameProcessor
{

/** Constructor.
 *
 * The constructor sets up logging used within the class. It also creates the
 * rxChannel_ subscribing IpcChannel and registers it with the IpcReactor reactor_.
 * Finally, the txChannel_ publishing IpcChannel is created. rxChannel_ is a ZeroMQ
 * subscriber (listening for frame ready notifications from the frame recevier) and
 * txChannel_ is a ZeroMQ plublisher that sends notifications (of released frames to
 * the frame receiver).
 *
 * \param[in] reactor - pointer to the IpcReactor object.
 * \param[in] rxEndPoint - string name of the subscribing endpoint for frame ready notifications.
 * \param[in] txEndPoint - string name of the publishing endpoint for frame release notifications.
 */
SharedMemoryController::SharedMemoryController(boost::shared_ptr<OdinData::IpcReactor> reactor,
                                               const std::string& rxEndPoint,
                                               const std::string& txEndPoint) :
    reactor_(reactor),
    rxChannel_(ZMQ_SUB),
    txChannel_(ZMQ_PUB)
{
  // Setup logging for the class
  logger_ = Logger::getLogger("FW.SharedMemoryController");
  logger_->setLevel(Level::getAll());
  LOG4CXX_TRACE(logger_, "SharedMemoryController constructor.");

  // Connect the frame ready channel
  try {
    LOG4CXX_DEBUG(logger_, "Connecting RX Channel to endpoint: " << rxEndPoint);
    rxChannel_.connect(rxEndPoint.c_str());
    rxChannel_.subscribe("");
  }
  catch (zmq::error_t& e) {
    //std::stringstream ss;
    //ss << "RX channel connect to endpoint " << config_.rx_channel_endpoint_ << " failed: " << e.what();
    // TODO: What to do here, I think throw it up
    throw std::runtime_error(e.what());
  }

  // Add the Frame Ready channel to the reactor
  reactor_->register_channel(rxChannel_, boost::bind(&SharedMemoryController::handleRxChannel, this));

  // Now connect the frame release response channel
  try {
    LOG4CXX_DEBUG(logger_, "Connecting TX Channel to endpoint: " << txEndPoint);
    txChannel_.connect(txEndPoint.c_str());
  }
  catch (zmq::error_t& e) {
    //std::stringstream ss;
    //ss << "RX channel connect to endpoint " << config_.rx_channel_endpoint_ << " failed: " << e.what();
    // TODO: What to do here, I think throw it up
    throw std::runtime_error(e.what());
  }
}

/**
 * Destructor.
 */
SharedMemoryController::~SharedMemoryController()
{
  LOG4CXX_TRACE(logger_, "Shutting down SharedMemoryController");
  // Close the IPC Channels
  reactor_->remove_channel(txChannel_);
  reactor_->remove_channel(rxChannel_);
  txChannel_.close();
  rxChannel_.close();
  // Stop the SharedMemoryController reactor
  reactor_->stop();
}

/** setSharedMemoryParser
 * Takes a shared pointer to a shared memory parser and stores it in
 * a member variable.
 *
 * \param[in] smp - shared pointer to a SharedMemoryParser object.
 */
void SharedMemoryController::setSharedBufferManager(boost::shared_ptr<OdinData::SharedBufferManager> sbm)
{
  sbm_ = sbm;
}

/** Called whenever a new IpcMessage is received to notify that a frame is ready.
 *
 * Reads the raw message bytes from the rxChannel_ and constructs an IpcMessage object
 * from the bytes. Verifies the IpcMessage type and value, and then uses the frame
 * number and buffer ID information to tell the SharedMemoryParser which frame is ready
 * for extraction from shared memory.
 * Loops over registered callbacks and passes the frame to the relevant WorkQueue objects,
 * before sending notifiation that the frame has been released for re-use.
 */
void SharedMemoryController::handleRxChannel()
{
  // Receive a message from the main thread channel
  std::string rxMsgEncoded = rxChannel_.recv();

  LOG4CXX_DEBUG(logger_, "RX thread called with message: " << rxMsgEncoded);

  // Parse and handle the message
  try {
    OdinData::IpcMessage rxMsg(rxMsgEncoded.c_str());

    if ((rxMsg.get_msg_type() == OdinData::IpcMessage::MsgTypeNotify) &&
        (rxMsg.get_msg_val()  == OdinData::IpcMessage::MsgValNotifyFrameReady)) {
      int bufferID = rxMsg.get_param<int>("buffer_id", -1);

      if (bufferID != -1) {
        // Create a frame object and copy in the raw frame data
        boost::shared_ptr<Frame> frame;
        frame = boost::shared_ptr<Frame>(new Frame("raw"));
        frame->wrap_shared_buffer(sbm_->get_buffer_address(bufferID),
                                  sbm_->get_buffer_size(),
                                  bufferID,rxMsg.get_param<int>("frame", 0),
                                  &txChannel_);

        // Set the frame number
        frame->set_frame_number(rxMsg.get_param<int>("frame", 0));

        // Loop over registered callbacks, placing the frame onto each queue
        std::map<std::string, boost::shared_ptr<IFrameCallback> >::iterator cbIter;
        for (cbIter = callbacks_.begin(); cbIter != callbacks_.end(); ++cbIter) {
          cbIter->second->getWorkQueue()->add(frame);
        }

      } else {
        LOG4CXX_ERROR(logger_, "RX thread received empty frame notification with buffer ID");
      }
    } else if ((rxMsg.get_msg_type() == OdinData::IpcMessage::MsgTypeNotify) &&
               (rxMsg.get_msg_val()  == OdinData::IpcMessage::MsgValNotifyBufferConfig))
    {
      try
      {
        std::string shared_buffer_name = rxMsg.get_param<std::string>("shared_buffer_name");
        LOG4CXX_DEBUG(logger_, "Shared buffer config notification received for " << shared_buffer_name);
        if (sbm_) {
          sbm_.reset();
        }
        sbm_ = boost::shared_ptr<OdinData::SharedBufferManager>(
            new OdinData::SharedBufferManager(shared_buffer_name)
        );
      }
      catch (OdinData::IpcMessageException& e)
      {
        LOG4CXX_ERROR(logger_, "Received shared buffer config notification with no name parameter");
      }
    } else {
      LOG4CXX_ERROR(logger_, "RX thread got unexpected message: " << rxMsgEncoded);

      //IpcMessage rx_reply;

      //rx_reply.set_msg_type(IpcMessage::MsgTypeNack);
      //rx_reply.set_msg_val(rx_msg.get_msg_val());
      //TODO add error in params

      //rx_channel_.send(rx_reply.encode());
    }
  }
  catch (OdinData::IpcMessageException& e)
  {
    LOG4CXX_ERROR(logger_, "Error decoding control channel request: " << e.what());
  }
}

/** Register a callback for Frame updates with this class.
 *
 * The callback (IFrameCallback subclass) is added to the map of callbacks, indexed
 * by name. Whenever a new Frame object is received from the frame receiver then these
 * callbacks will be called and passed the Frame pointer.
 *
 * \param[in] name - string index of the callback.
 * \param[in] cb - IFrameCallback to register for updates.
 */
void SharedMemoryController::registerCallback(const std::string& name, boost::shared_ptr<IFrameCallback> cb)
{
  // Check if we own the callback already
  if (callbacks_.count(name) == 0) {
    // Record the callback pointer
    callbacks_[name] = cb;
    // Confirm registration
    cb->confirmRegistration("frame_receiver");
  }
}

/** Remove a callback from the callback map.
 *
 * The callback is removed from the map of callbacks.
 *
 * \param[in] name - string index of the callback.
 */
void SharedMemoryController::removeCallback(const std::string& name)
{
  boost::shared_ptr<IFrameCallback> cb;
  if (callbacks_.count(name) > 0) {
    // Get the pointer
    cb = callbacks_[name];
    // Remove the callback from the map
    callbacks_.erase(name);
    // Confirm removal
    cb->confirmRemoval("frame_receiver");
  }
}

} /* namespace FrameProcessor */
<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName         :    NFCPVPModule.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2017-02-02
//    @Module           :    NFCPVPModule
//
// -------------------------------------------------------------------------

#include "NFCPVPModule.h"
#include "NFComm/NFPluginModule/NFINetModule.h"
#include "NFComm/NFMessageDefine/NFMsgShare.pb.h"
#include "NFComm/NFMessageDefine/NFProtocolDefine.hpp"

bool NFCPVPModule::Init()
{

	m_pTileModule = pPluginManager->FindModule<NFITileModule>();
	m_pElementModule = pPluginManager->FindModule<NFIElementModule>();
	m_pClassModule = pPluginManager->FindModule<NFIClassModule>();
	m_pNetModule = pPluginManager->FindModule<NFINetModule>();
	m_pKernelModule = pPluginManager->FindModule<NFIKernelModule>();
	m_pLogModule = pPluginManager->FindModule<NFILogModule>();
	m_pSceneProcessModule = pPluginManager->FindModule<NFISceneProcessModule>();
	m_pPlayerRedisModule = pPluginManager->FindModule<NFIPlayerRedisModule>();
	m_pSceneAOIModule = pPluginManager->FindModule<NFISceneAOIModule>();
	m_pPropertyModule = pPluginManager->FindModule<NFIPropertyModule>();
	m_pGameServerNet_ServerModule = pPluginManager->FindModule<NFIGameServerNet_ServerModule>();

    return true;
}

bool NFCPVPModule::Shut()
{
    return true;
}

bool NFCPVPModule::Execute()
{

    return true;
}

bool NFCPVPModule::AfterInit()
{
	FindAllTileScene();

	m_pSceneAOIModule->AddEnterSceneConditionCallBack(this, &NFCPVPModule::EnterSceneConditionEvent);

	m_pSceneAOIModule->AddBeforeEnterSceneGroupCallBack(this, &NFCPVPModule::BeforeEnterSceneGroupEvent);
	m_pSceneAOIModule->AddAfterEnterSceneGroupCallBack(this, &NFCPVPModule::AfterEnterSceneGroupEvent);
	m_pSceneAOIModule->AddBeforeLeaveSceneGroupCallBack(this, &NFCPVPModule::BeforeLeaveSceneGroupEvent);
	m_pSceneAOIModule->AddAfterLeaveSceneGroupCallBack(this, &NFCPVPModule::AfterLeaveSceneGroupEvent);

	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_SEARCH_OPPNENT, this, &NFCPVPModule::OnReqSearchOppnentProcess)) { return false; }
	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_SWAP_HOME_SCENE, this, &NFCPVPModule::OnReqSwapHomeSceneProcess)) { return false; }
	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_START_OPPNENT, this, &NFCPVPModule::OnReqStartPVPOppnentProcess)) { return false; }
	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_END_OPPNENT, this, &NFCPVPModule::OnReqEndPVPOppnentProcess)) { return false; }

    return true;
}

bool NFCPVPModule::ReadyExecute()
{
	m_pSceneAOIModule->RemoveSwapSceneEventCallBack();
	m_pSceneAOIModule->AddSwapSceneEventCallBack(this, &NFCPVPModule::OnSceneEvent);

	return false;
}

void NFCPVPModule::OnReqSearchOppnentProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqSearchOppnent);
	//find a tile map and swap scene

	int nSceneID = RandomTileScene();
	std::string strTileData;
	NFGUID xViewOppnent;
	if (m_pPlayerRedisModule->LoadPlayerTileRandom(nSceneID, xViewOppnent, strTileData))
	{
		NFMsg::AckMiningTitle xTileData;
		if (xTileData.ParseFromString(strTileData))
		{
			m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent(), xViewOppnent);
			m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), NFGUID());

			m_pSceneProcessModule->RequestEnterScene(nPlayerID, nSceneID, 0, NFDataList());

			//tell client u shoud adjust tile
			//m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGEC_ACK_MINING_TITLE, xTileData, nPlayerID);
			//tell client u should load resources
			NFMsg::AckSearchOppnent xAckData;
			xAckData.set_scene_id(nSceneID);
			m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_SEARCH_OPPNENT, xAckData, nPlayerID);

			return;
		}
		else
		{
			//failed
			NFMsg::AckSearchOppnent xAckData;
			xAckData.set_scene_id(0);
			m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_SEARCH_OPPNENT, xAckData, nPlayerID);

		}
	}

	m_pLogModule->LogNormal(NFILogModule::NLL_ERROR_NORMAL, nPlayerID, "ERROR TO FIND A OPPNENT!", "",  __FUNCTION__, __LINE__);
}

void NFCPVPModule::OnReqSwapHomeSceneProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqAckHomeScene);
	int nHomeSceneID = m_pKernelModule->GetPropertyInt(nPlayerID, NFrame::Player::HomeSceneID());

	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent(), nPlayerID);
	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), NFGUID());

	m_pSceneProcessModule->RequestEnterScene(nPlayerID, nHomeSceneID, 0, NFDataList());
	/*
	//send tile's data to client
	std::string strTileData;
	if (m_pPlayerRedisModule->LoadPlayerTile(nHomeSceneID, nPlayerID, strTileData))
	{
		m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGEC_ACK_MINING_TITLE, strTileData, nPlayerID);
	}
	*/
}

void NFCPVPModule::OnReqStartPVPOppnentProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqAckStartBattle);

	NFGUID xViewOppnent = m_pKernelModule->GetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent());
	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), xViewOppnent);

	int nGambleGold = xMsg.gold();
	int nGambleDiamond = xMsg.diamond();
	if (nGambleGold > 0)
	{
		m_pKernelModule->SetPropertyInt(nPlayerID, NFrame::Player::GambleGold(), nGambleGold);
	}
	if (nGambleDiamond > 0)
	{
		m_pKernelModule->SetPropertyInt(nPlayerID, NFrame::Player::GambleDiamond(), nGambleDiamond);
	}

	NFMsg::ReqAckStartBattle xReqAckStartBattle;
	xReqAckStartBattle.set_gold(nGambleGold);
	xReqAckStartBattle.set_diamond(nGambleDiamond);
	m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_START_OPPNENT, xReqAckStartBattle, nPlayerID);
}

void NFCPVPModule::OnReqEndPVPOppnentProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqEndBattle);

	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent(), NFGUID());
	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), NFGUID());
	//get oppnent
	//calculate how many monster has been killed
	//calculate how many building has been destroyed
	//calculate how much experice and how many money

	//tell client the end information
	//set oppnent 0
	int nGambleGold = m_pKernelModule->GetPropertyInt(nPlayerID, NFrame::Player::GambleGold());
	int nGambleDiamond = m_pKernelModule->GetPropertyInt(nPlayerID, NFrame::Player::GambleDiamond());

	m_pPropertyModule->AddGold(nPlayerID, nGambleGold);
	m_pPropertyModule->AddDiamond(nPlayerID, nGambleDiamond);

	NFMsg::AckEndBattle xReqAckEndBattle;
	xReqAckEndBattle.set_win(1);
	xReqAckEndBattle.set_star(2);
	xReqAckEndBattle.set_gold(nGambleGold);
	xReqAckEndBattle.set_exp(0);
	xReqAckEndBattle.set_diamond(nGambleDiamond);

	m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_END_OPPNENT, xReqAckEndBattle, nPlayerID);
}

void NFCPVPModule::FindAllTileScene()
{
	//Tile
	//mxTileSceneIDList
	NF_SHARE_PTR<NFIClass> xLogicClass = m_pClassModule->GetElement(NFrame::Scene::ThisName());
	if (xLogicClass)
	{
		NFList<std::string>& strIdList = xLogicClass->GetIdList();
		std::string strId;
		for (bool bRet = strIdList.First(strId); bRet; bRet = strIdList.Next(strId))
		{
			const int nServerType = m_pElementModule->GetPropertyInt(strId, NFrame::Scene::Tile());
			if (nServerType == 1)
			{
				mxTileSceneIDList.push_back(lexical_cast<int>(strId));
			}
		}
	}
}

void NFCPVPModule::InitAllTileSceneRobot()
{
	for (int i = 0; i < mxTileSceneIDList.size(); ++i)
	{
		int nSceneID = mxTileSceneIDList[i];

	}
}

int NFCPVPModule::OnSceneEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	std::string strTileData;
	NFVector3 vRelivePos = m_pSceneAOIModule->GetRelivePosition(nSceneID, 0);
	NFGUID xViewOppnent = m_pKernelModule->GetPropertyObject(self, NFrame::Player::ViewOppnent());

	NFMsg::ReqAckSwapScene xAckSwapScene;
	xAckSwapScene.set_scene_id(nSceneID);
	xAckSwapScene.set_transfer_type(NFMsg::ReqAckSwapScene::EGameSwapType::ReqAckSwapScene_EGameSwapType_EGST_NARMAL);
	xAckSwapScene.set_line_id(0);
	xAckSwapScene.set_x(vRelivePos.X());
	xAckSwapScene.set_y(vRelivePos.Y());
	xAckSwapScene.set_z(vRelivePos.Z());

	if (self == xViewOppnent)
	{
		m_pKernelModule->SetPropertyObject(self, NFrame::Player::ViewOppnent(), NFGUID());

		if (m_pTileModule->GetOnlinePlayerTileData(self, strTileData))
		{
			xAckSwapScene.set_data(strTileData.c_str());
		}
	}
	else
	{
		if (m_pPlayerRedisModule->LoadPlayerTileRandomCache(xViewOppnent, strTileData))
		{
			xAckSwapScene.set_data(strTileData.c_str());
		}
	}

	//attach tile data
	m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_SWAP_SCENE, xAckSwapScene, self);

	return 0;
}

int NFCPVPModule::EnterSceneConditionEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::BeforeEnterSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::AfterEnterSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::BeforeLeaveSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::AfterLeaveSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::RandomTileScene()
{
	return mxTileSceneIDList.at(m_pKernelModule->Random(0, mxTileSceneIDList.size()));
}
<commit_msg>fixed for data length when set char* data<commit_after>// -------------------------------------------------------------------------
//    @FileName         :    NFCPVPModule.cpp
//    @Author           :    LvSheng.Huang
//    @Date             :    2017-02-02
//    @Module           :    NFCPVPModule
//
// -------------------------------------------------------------------------

#include "NFCPVPModule.h"
#include "NFComm/NFPluginModule/NFINetModule.h"
#include "NFComm/NFMessageDefine/NFMsgShare.pb.h"
#include "NFComm/NFMessageDefine/NFProtocolDefine.hpp"

bool NFCPVPModule::Init()
{

	m_pTileModule = pPluginManager->FindModule<NFITileModule>();
	m_pElementModule = pPluginManager->FindModule<NFIElementModule>();
	m_pClassModule = pPluginManager->FindModule<NFIClassModule>();
	m_pNetModule = pPluginManager->FindModule<NFINetModule>();
	m_pKernelModule = pPluginManager->FindModule<NFIKernelModule>();
	m_pLogModule = pPluginManager->FindModule<NFILogModule>();
	m_pSceneProcessModule = pPluginManager->FindModule<NFISceneProcessModule>();
	m_pPlayerRedisModule = pPluginManager->FindModule<NFIPlayerRedisModule>();
	m_pSceneAOIModule = pPluginManager->FindModule<NFISceneAOIModule>();
	m_pPropertyModule = pPluginManager->FindModule<NFIPropertyModule>();
	m_pGameServerNet_ServerModule = pPluginManager->FindModule<NFIGameServerNet_ServerModule>();

    return true;
}

bool NFCPVPModule::Shut()
{
    return true;
}

bool NFCPVPModule::Execute()
{

    return true;
}

bool NFCPVPModule::AfterInit()
{
	FindAllTileScene();

	m_pSceneAOIModule->AddEnterSceneConditionCallBack(this, &NFCPVPModule::EnterSceneConditionEvent);

	m_pSceneAOIModule->AddBeforeEnterSceneGroupCallBack(this, &NFCPVPModule::BeforeEnterSceneGroupEvent);
	m_pSceneAOIModule->AddAfterEnterSceneGroupCallBack(this, &NFCPVPModule::AfterEnterSceneGroupEvent);
	m_pSceneAOIModule->AddBeforeLeaveSceneGroupCallBack(this, &NFCPVPModule::BeforeLeaveSceneGroupEvent);
	m_pSceneAOIModule->AddAfterLeaveSceneGroupCallBack(this, &NFCPVPModule::AfterLeaveSceneGroupEvent);

	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_SEARCH_OPPNENT, this, &NFCPVPModule::OnReqSearchOppnentProcess)) { return false; }
	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_SWAP_HOME_SCENE, this, &NFCPVPModule::OnReqSwapHomeSceneProcess)) { return false; }
	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_START_OPPNENT, this, &NFCPVPModule::OnReqStartPVPOppnentProcess)) { return false; }
	if (!m_pNetModule->AddReceiveCallBack(NFMsg::EGMI_REQ_END_OPPNENT, this, &NFCPVPModule::OnReqEndPVPOppnentProcess)) { return false; }

    return true;
}

bool NFCPVPModule::ReadyExecute()
{
	m_pSceneAOIModule->RemoveSwapSceneEventCallBack();
	m_pSceneAOIModule->AddSwapSceneEventCallBack(this, &NFCPVPModule::OnSceneEvent);

	return false;
}

void NFCPVPModule::OnReqSearchOppnentProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqSearchOppnent);
	//find a tile map and swap scene

	int nSceneID = RandomTileScene();
	std::string strTileData;
	NFGUID xViewOppnent;
	if (m_pPlayerRedisModule->LoadPlayerTileRandom(nSceneID, xViewOppnent, strTileData))
	{
		NFMsg::AckMiningTitle xTileData;
		if (xTileData.ParseFromString(strTileData))
		{
			m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent(), xViewOppnent);
			m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), NFGUID());

			m_pSceneProcessModule->RequestEnterScene(nPlayerID, nSceneID, 0, NFDataList());

			//tell client u shoud adjust tile
			//m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGEC_ACK_MINING_TITLE, xTileData, nPlayerID);
			//tell client u should load resources
			NFMsg::AckSearchOppnent xAckData;
			xAckData.set_scene_id(nSceneID);
			m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_SEARCH_OPPNENT, xAckData, nPlayerID);

			return;
		}
		else
		{
			//failed
			NFMsg::AckSearchOppnent xAckData;
			xAckData.set_scene_id(0);
			m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_SEARCH_OPPNENT, xAckData, nPlayerID);

		}
	}

	m_pLogModule->LogNormal(NFILogModule::NLL_ERROR_NORMAL, nPlayerID, "ERROR TO FIND A OPPNENT!", "",  __FUNCTION__, __LINE__);
}

void NFCPVPModule::OnReqSwapHomeSceneProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqAckHomeScene);
	int nHomeSceneID = m_pKernelModule->GetPropertyInt(nPlayerID, NFrame::Player::HomeSceneID());

	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent(), nPlayerID);
	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), NFGUID());

	m_pSceneProcessModule->RequestEnterScene(nPlayerID, nHomeSceneID, 0, NFDataList());
	/*
	//send tile's data to client
	std::string strTileData;
	if (m_pPlayerRedisModule->LoadPlayerTile(nHomeSceneID, nPlayerID, strTileData))
	{
		m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGEC_ACK_MINING_TITLE, strTileData, nPlayerID);
	}
	*/
}

void NFCPVPModule::OnReqStartPVPOppnentProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqAckStartBattle);

	NFGUID xViewOppnent = m_pKernelModule->GetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent());
	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), xViewOppnent);

	int nGambleGold = xMsg.gold();
	int nGambleDiamond = xMsg.diamond();
	if (nGambleGold > 0)
	{
		m_pKernelModule->SetPropertyInt(nPlayerID, NFrame::Player::GambleGold(), nGambleGold);
	}
	if (nGambleDiamond > 0)
	{
		m_pKernelModule->SetPropertyInt(nPlayerID, NFrame::Player::GambleDiamond(), nGambleDiamond);
	}

	NFMsg::ReqAckStartBattle xReqAckStartBattle;
	xReqAckStartBattle.set_gold(nGambleGold);
	xReqAckStartBattle.set_diamond(nGambleDiamond);
	m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_START_OPPNENT, xReqAckStartBattle, nPlayerID);
}

void NFCPVPModule::OnReqEndPVPOppnentProcess(const int nSockIndex, const int nMsgID, const char * msg, const uint32_t nLen)
{
	CLIENT_MSG_PROCESS(nSockIndex, nMsgID, msg, nLen, NFMsg::ReqEndBattle);

	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::ViewOppnent(), NFGUID());
	m_pKernelModule->SetPropertyObject(nPlayerID, NFrame::Player::FightOppnent(), NFGUID());
	//get oppnent
	//calculate how many monster has been killed
	//calculate how many building has been destroyed
	//calculate how much experice and how many money

	//tell client the end information
	//set oppnent 0
	int nGambleGold = m_pKernelModule->GetPropertyInt(nPlayerID, NFrame::Player::GambleGold());
	int nGambleDiamond = m_pKernelModule->GetPropertyInt(nPlayerID, NFrame::Player::GambleDiamond());

	m_pPropertyModule->AddGold(nPlayerID, nGambleGold);
	m_pPropertyModule->AddDiamond(nPlayerID, nGambleDiamond);

	NFMsg::AckEndBattle xReqAckEndBattle;
	xReqAckEndBattle.set_win(1);
	xReqAckEndBattle.set_star(2);
	xReqAckEndBattle.set_gold(nGambleGold);
	xReqAckEndBattle.set_exp(0);
	xReqAckEndBattle.set_diamond(nGambleDiamond);

	m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_END_OPPNENT, xReqAckEndBattle, nPlayerID);
}

void NFCPVPModule::FindAllTileScene()
{
	//Tile
	//mxTileSceneIDList
	NF_SHARE_PTR<NFIClass> xLogicClass = m_pClassModule->GetElement(NFrame::Scene::ThisName());
	if (xLogicClass)
	{
		NFList<std::string>& strIdList = xLogicClass->GetIdList();
		std::string strId;
		for (bool bRet = strIdList.First(strId); bRet; bRet = strIdList.Next(strId))
		{
			const int nServerType = m_pElementModule->GetPropertyInt(strId, NFrame::Scene::Tile());
			if (nServerType == 1)
			{
				mxTileSceneIDList.push_back(lexical_cast<int>(strId));
			}
		}
	}
}

void NFCPVPModule::InitAllTileSceneRobot()
{
	for (int i = 0; i < mxTileSceneIDList.size(); ++i)
	{
		int nSceneID = mxTileSceneIDList[i];

	}
}

int NFCPVPModule::OnSceneEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	std::string strTileData;
	NFVector3 vRelivePos = m_pSceneAOIModule->GetRelivePosition(nSceneID, 0);
	NFGUID xViewOppnent = m_pKernelModule->GetPropertyObject(self, NFrame::Player::ViewOppnent());

	NFMsg::ReqAckSwapScene xAckSwapScene;
	xAckSwapScene.set_scene_id(nSceneID);
	xAckSwapScene.set_transfer_type(NFMsg::ReqAckSwapScene::EGameSwapType::ReqAckSwapScene_EGameSwapType_EGST_NARMAL);
	xAckSwapScene.set_line_id(0);
	xAckSwapScene.set_x(vRelivePos.X());
	xAckSwapScene.set_y(vRelivePos.Y());
	xAckSwapScene.set_z(vRelivePos.Z());

	if (self == xViewOppnent)
	{
		m_pKernelModule->SetPropertyObject(self, NFrame::Player::ViewOppnent(), NFGUID());

		if (m_pTileModule->GetOnlinePlayerTileData(self, strTileData))
		{
			xAckSwapScene.set_data(strTileData.c_str(), strTileData.length());
		}
	}
	else
	{
		if (m_pPlayerRedisModule->LoadPlayerTileRandomCache(xViewOppnent, strTileData))
		{
			xAckSwapScene.set_data(strTileData.c_str(), strTileData.length());
		}
	}

	//attach tile data
	m_pGameServerNet_ServerModule->SendMsgPBToGate(NFMsg::EGMI_ACK_SWAP_SCENE, xAckSwapScene, self);

	return 0;
}

int NFCPVPModule::EnterSceneConditionEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::BeforeEnterSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::AfterEnterSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::BeforeLeaveSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::AfterLeaveSceneGroupEvent(const NFGUID & self, const int nSceneID, const int nGroupID, const int nType, const NFDataList & argList)
{
	return 0;
}

int NFCPVPModule::RandomTileScene()
{
	return mxTileSceneIDList.at(m_pKernelModule->Random(0, mxTileSceneIDList.size()));
}
<|endoftext|>


<commit_before>/*-------------------------------
PASA LA CALCULADORA
Autores:
Jaime Sevilla Molina
Victor Gonzalez
Fecha
2014/11
Version: 1.0
---------------------------------*/

//BIBLIOTECAS
#include <iostream>
#include <cstdlib>
#include <string>
#include <ctime>

typedef enum tJugador
{
	Nadie,
	Jugador,
	Automata
};

//FUNCIONES
//FUNCIONES DE JUEGO

void saludar ();//Implementada

//Dependiendo de quien gane, la despedida sera distinta
void despedirse (tJugador ganador);//Implementada

//Conduce el desarrollo del juego y devuelve el ganador.
//Si se abandona devuelve Nadie.
tJugador pasaCalculadora();

//Decide aleatoriamente quien empieza.
tJugador quienEmpieza();//Implementada
//Devuelve true si nuevo está en la misma fila que ultimo
bool mismaFila(int ultimo, int nuevo);//Implementada

//Devuelve true si nuevo está en la misma columna que ultimo
bool mismaColumna(int ultimo, int nuevo);//Implementada

//Devuelve true si nuevo cumple las reglas del juego con respecto a ultimo
//Si ultimo == 0, este es el primer digito de la partida, y devuelve true
bool digitoValido(int ultimo, int nuevo);//Implementada

//FUNCIONES DE IA NIVEL 1
//Devuelve un dígito del 1 al 9
int digitoAleatorio();//Implementada

//Devuelve un digito que cumpla las reglas del juego con respecto a ultimo.
int digitoAutomata(int ultimo);

//FUNCIONES DE JUGADOR
//Pide un dígito al jugador. Sólo devolverá un valor válido (entre 0 y 9).
//Para un valor no válido, mostrará un error.
int digitoPersona(); //to do Jaime

//Pide un digito al jugador mostrando el teclado. Solo devolvera un valor
//que cumpla las reglas del juego o 0. Para un valor no valido, mostrara un error.
int digitoPersona(int ultimo); //to do Jaime

//Determina si el numero de la calculadora se muestra o no, en funcion de si es valido
char mNumero(int ultimo, int n);

//Muestra los botones de la calculadora (solo los que se pueden pulsar en cada turno)
void mostrarCalculadora(ultimo);

/* Las funciones a continuacion se implementaran en un futuro
//FUNCIONES DE MENÚ
//Muestra el menu, pide la opcion y la devuelve como resultado. Solo
//devolvera una opción valida. Para cada valor no valido, mostrará un error.
int menu();

//Muestra en la consola el contenido del archivo de texto nombArch.
//Si el archivo no se encuentra, devuelve false, en otro caso true.
bool mostrar(string nombArch);

//FUNCIONES DE INFORME
//Actualiza el archivo informePC.txt con los tres argumentos. En caso de no encontrar
//el archivo, lo crea y devuelve false; en otro caso devuelve true.
bool actInforme(int jugadas, int ganadas, int abandonos);

//FUNCIONES DE DIFICULTAD AVANZADA
int botDificil(int ultimo);

-----------------------------------------------------------------------------------*/

int main(){
	tJugador ganador;

	saludar();
	ganador = pasaCalculadora();
	despedirse(ganador)
	return 0;
	}
//Saluda al jugador y le pregunta su nombre
void saludar{
	string nombre;
	std::cout << "¡Bienvenido a Pasa la calculadora!" << endl;
	std::cout << "¿Como te llamas?";
	std::cin >> nombre;
	std::cout << "Hola" << nombre;
}
//Se despide del jugador, la despedida varia segun gane el jugador, el autómata o ninguno de ellos (el jugador abandone)
void despedirse{
	string nombre;
	if (ganador == Nadie){
		std::cout << "¿Abandonas? Ohhh..." << endl;
		std::cout << "Hasta la proxima " << nombre << "(pulsa una tecla)";
	}
	else if (ganador == jugador){
		std::cout << "Enhorabuena, has ganado" << endl;
		std::cout << "Hasta la proxima " << nombre << "(pulsa una tecla)";
	}
	else{
		std::cout << "Lo siento, he ganado" << endl;
		std::cout << "Hasta la proxima " << nombre << "(pulsa una tecla)";
	}
}
//Conduce el desarrollo del juego y devuelve el ganador.
//Si se abandona devuelve Nadie.
tJugador pasaCalculadora(){
	//Variables
	tJugador turno;
	int total = 0, ultimoDigito = 0;
	const int META=31;
		//Inicializar partida
	cstlib::srand(time(NULL))//Semilla
	turno = quienEmpieza();

	//Bucle de juego
	do{
		//Turno jugador
		if (turno == Jugador){
			ultimoDigito = digitoPersona(ultimoDigito);
			turno = Automata;
		}
		//Turno bot
		else /*if (turno == Automata)*/{
			ultimoDigito = digitoAutomata(ultimoDigito);
			turno = Jugador;
		}
		total += ultimoDigito;
		std::cout << "Total = " << total;
	}while ((total < META) && (ultimoDigito != 0));

	if (ultimoDigito == 0) turno = Nadie;
	//Si el jugador abandona, no gana nadie

	return turno;
}

//Decide aleatoriamente quien empieza la partida, si el automata o el jugador
tJugador quienEmpieza(){
	if (cstlib::rand() % 2){
		cout << "Tu empiezas";
		return Jugador;
	}
	else{
		cout"Empiezo yo";
		return Automata;
	}
}
//Define que números se encuentran en la misma fila que el ultimo pulsado
bool mismaFila(int ultimo, int nuevo){
	double filaUltimo, filaNuevo;
	filaUltimo = (ultimo/3);
	filaNuevo = (nuevo/3);
	return ceil(filaUltimo) == ceil(filaNuevo);
}
//Define que números se encuentran en la misma columna que el ultimo
bool mismaColumna(int ultimo, int nuevo){
	int columnaUltimo, columnaNuevo;
	columnaUltimo = (ultimo % 3);
	columnaNuevo = (nuevo % 3);
	return columnaUltimo == columnaNuevo;
}
//Determina que digitos se pueden pulsar en función de las reglas del juego
bool digitoValido(int ultimo, int nuevo){
	return ((mismaFila(int ultimo, int nuevo))||(mismaColumna(int ultimo, int nuevo)))&&(ultimo!=nuevo);
}
//Genera un dígito aleatorio
int digitoAleatorio(){
	return (cstlib::rand() % 9) + 1;
}
//Devuelve un digito que cumpla las reglas del juego con respecto a ultimo.
int digitoAutomata(int ultimo){
	int digito;

	do{
	digito = digitoAleatorio();
	}while (!digitoValido(ultimo, digito));

	std::cout << "Elijo el numero " << digito;

	return digito;
}

//Pide un digito al jugador. Solo devolvera un valor valido (entre 0 y 9).
//Para un valor no válido, mostrará un error.
int digitoPersona(){
	int digito = -1;

	mostrarCalculadora();

	while (digito == -1){
		try{
			std::cin.sync(); //Por si quedan datos basura en el buffer
			std::cin >> digito;
			if (digito < 0 || digito > 9) throw;
		}catch(...){
			std::cout << "Error! Introduce un digito entre 0-9";
			digito = -1;
		}
	}

	return digito;
}

//Pide un digito al jugador mostrando el teclado. Solo devolvera un valor
//que cumpla las reglas del juego o 0. Para un valor no valido, mostrara un error.
int digitoPersona(int ultimo){
	int digito = -1; //-1 es mi error flag

	while (digito == -1){
		try{
			digito = digitoPersona();
			if (!digitoValido(ultimo, digito)) throw;
		}catch(...){
			std::cout << "Error! El digito debe estar en la misma fila y columna que el ultimo";
			digito = -1;
		}
	}

	std::cout << "Has elegido el" << digito;

	return digito;
}

char mNumero(int ultimo, int n){
	if(digitoValido(ultimo, n) return char (n+int('0'));
	else return ' ';
}

void mostrarCalculadora(ultimo){
	for (int i = 7; i<10; i++){
		cout << setw(3) << mNumero(ultimo, i);
	}
	cout << endl;
	for (int i = 4; i<7; i++){
		cout << setw(3) << mNumero(ultimo, i);
	}
	cout << endl;
	for (int i = 1; i<4; i++){
		cout << setw(3) << mNumero(ultimo, i);
	}
	cout << endl;
}
<commit_msg>using namespace std;<commit_after>/*-------------------------------
PASA LA CALCULADORA
Autores:
Jaime Sevilla Molina
Victor Gonzalez
Fecha
2014/11
Version: 1.0
---------------------------------*/

//BIBLIOTECAS
#include <iostream>
#include <cstdlib>
#include <string>
#include <ctime>

using namespace std;

typedef enum tJugador
{
	Nadie,
	Jugador,
	Automata
};

//FUNCIONES
//FUNCIONES DE JUEGO

void saludar ();//Implementada

//Dependiendo de quien gane, la despedida sera distinta
void despedirse (tJugador ganador);//Implementada

//Conduce el desarrollo del juego y devuelve el ganador.
//Si se abandona devuelve Nadie.
tJugador pasaCalculadora();

//Decide aleatoriamente quien empieza.
tJugador quienEmpieza();//Implementada
//Devuelve true si nuevo está en la misma fila que ultimo
bool mismaFila(int ultimo, int nuevo);//Implementada

//Devuelve true si nuevo está en la misma columna que ultimo
bool mismaColumna(int ultimo, int nuevo);//Implementada

//Devuelve true si nuevo cumple las reglas del juego con respecto a ultimo
//Si ultimo == 0, este es el primer digito de la partida, y devuelve true
bool digitoValido(int ultimo, int nuevo);//Implementada

//FUNCIONES DE IA NIVEL 1
//Devuelve un dígito del 1 al 9
int digitoAleatorio();//Implementada

//Devuelve un digito que cumpla las reglas del juego con respecto a ultimo.
int digitoAutomata(int ultimo);

//FUNCIONES DE JUGADOR
//Pide un dígito al jugador. Sólo devolverá un valor válido (entre 0 y 9).
//Para un valor no válido, mostrará un error.
int digitoPersona(); //to do Jaime

//Pide un digito al jugador mostrando el teclado. Solo devolvera un valor
//que cumpla las reglas del juego o 0. Para un valor no valido, mostrara un error.
int digitoPersona(int ultimo); //to do Jaime

//Determina si el numero de la calculadora se muestra o no, en funcion de si es valido
char mNumero(int ultimo, int n);

//Muestra los botones de la calculadora (solo los que se pueden pulsar en cada turno)
void mostrarCalculadora(ultimo);

/* Las funciones a continuacion se implementaran en un futuro
//FUNCIONES DE MENÚ
//Muestra el menu, pide la opcion y la devuelve como resultado. Solo
//devolvera una opción valida. Para cada valor no valido, mostrará un error.
int menu();

//Muestra en la consola el contenido del archivo de texto nombArch.
//Si el archivo no se encuentra, devuelve false, en otro caso true.
bool mostrar(string nombArch);

//FUNCIONES DE INFORME
//Actualiza el archivo informePC.txt con los tres argumentos. En caso de no encontrar
//el archivo, lo crea y devuelve false; en otro caso devuelve true.
bool actInforme(int jugadas, int ganadas, int abandonos);

//FUNCIONES DE DIFICULTAD AVANZADA
int botDificil(int ultimo);

-----------------------------------------------------------------------------------*/

int main(){
	tJugador ganador;

	saludar();
	ganador = pasaCalculadora();
	despedirse(ganador)
	return 0;
	}
//Saluda al jugador y le pregunta su nombre
void saludar{
	string nombre;
	cout << "¡Bienvenido a Pasa la calculadora!" << endl;
	cout << "¿Como te llamas?";
	cin >> nombre;
	cout << "Hola" << nombre;
}
//Se despide del jugador, la despedida varia segun gane el jugador, el autómata o ninguno de ellos (el jugador abandone)
void despedirse{
	string nombre;
	if (ganador == Nadie){
		cout << "¿Abandonas? Ohhh..." << endl;
		cout << "Hasta la proxima " << nombre << "(pulsa una tecla)";
	}
	else if (ganador == jugador){
		cout << "Enhorabuena, has ganado" << endl;
		cout << "Hasta la proxima " << nombre << "(pulsa una tecla)";
	}
	else{
		cout << "Lo siento, he ganado" << endl;
		cout << "Hasta la proxima " << nombre << "(pulsa una tecla)";
	}
}
//Conduce el desarrollo del juego y devuelve el ganador.
//Si se abandona devuelve Nadie.
tJugador pasaCalculadora(){
	//Variables
	tJugador turno;
	int total = 0, ultimoDigito = 0;
	const int META=31;
		//Inicializar partida
	srand(time(NULL))//Semilla
	turno = quienEmpieza();

	//Bucle de juego
	do{
		//Turno jugador
		if (turno == Jugador){
			ultimoDigito = digitoPersona(ultimoDigito);
			turno = Automata;
		}
		//Turno bot
		else /*if (turno == Automata)*/{
			ultimoDigito = digitoAutomata(ultimoDigito);
			turno = Jugador;
		}
		total += ultimoDigito;
		cout << "Total = " << total;
	}while ((total < META) && (ultimoDigito != 0));

	if (ultimoDigito == 0) turno = Nadie;
	//Si el jugador abandona, no gana nadie

	return turno;
}

//Decide aleatoriamente quien empieza la partida, si el automata o el jugador
tJugador quienEmpieza(){
	if (rand() % 2){
		cout << "Tu empiezas";
		return Jugador;
	}
	else{
		cout"Empiezo yo";
		return Automata;
	}
}
//Define que números se encuentran en la misma fila que el ultimo pulsado
bool mismaFila(int ultimo, int nuevo){
	double filaUltimo, filaNuevo;
	filaUltimo = (ultimo/3);
	filaNuevo = (nuevo/3);
	return ceil(filaUltimo) == ceil(filaNuevo);
}
//Define que números se encuentran en la misma columna que el ultimo
bool mismaColumna(int ultimo, int nuevo){
	int columnaUltimo, columnaNuevo;
	columnaUltimo = (ultimo % 3);
	columnaNuevo = (nuevo % 3);
	return columnaUltimo == columnaNuevo;
}
//Determina que digitos se pueden pulsar en función de las reglas del juego
bool digitoValido(int ultimo, int nuevo){
	return ((mismaFila(int ultimo, int nuevo))||(mismaColumna(int ultimo, int nuevo)))&&(ultimo!=nuevo);
}
//Genera un dígito aleatorio
int digitoAleatorio(){
	return (rand() % 9) + 1;
}
//Devuelve un digito que cumpla las reglas del juego con respecto a ultimo.
int digitoAutomata(int ultimo){
	int digito;

	do{
	digito = digitoAleatorio();
	}while (!digitoValido(ultimo, digito));

	cout << "Elijo el numero " << digito;

	return digito;
}

//Pide un digito al jugador. Solo devolvera un valor valido (entre 0 y 9).
//Para un valor no válido, mostrará un error.
int digitoPersona(){
	int digito = -1;

	mostrarCalculadora();

	while (digito == -1){
		try{
			cin.sync(); //Por si quedan datos basura en el buffer
			cin >> digito;
			if (digito < 0 || digito > 9) throw;
		}catch(...){
			cout << "Error! Introduce un digito entre 0-9";
			digito = -1;
		}
	}

	return digito;
}

//Pide un digito al jugador mostrando el teclado. Solo devolvera un valor
//que cumpla las reglas del juego o 0. Para un valor no valido, mostrara un error.
int digitoPersona(int ultimo){
	int digito = -1; //-1 es mi error flag

	while (digito == -1){
		try{
			digito = digitoPersona();
			if (!digitoValido(ultimo, digito)) throw;
		}catch(...){
			cout << "Error! El digito debe estar en la misma fila y columna que el ultimo";
			digito = -1;
		}
	}

	cout << "Has elegido el" << digito;

	return digito;
}

char mNumero(int ultimo, int n){
	if(digitoValido(ultimo, n) return char (n+int('0'));
	else return ' ';
}

void mostrarCalculadora(ultimo){
	for (int i = 7; i<10; i++){
		cout << setw(3) << mNumero(ultimo, i);
	}
	cout << endl;
	for (int i = 4; i<7; i++){
		cout << setw(3) << mNumero(ultimo, i);
	}
	cout << endl;
	for (int i = 1; i<4; i++){
		cout << setw(3) << mNumero(ultimo, i);
	}
	cout << endl;
}
<|endoftext|>


<commit_before>/*
 *  RBCourseData.cpp
 *  golf
 *
 *  Created by Robert Rose on 10/30/08.
 *  Copyright 2008 Bork 3D LLC. All rights reserved.
 *
 */

#include "RBCourseData.h"

RBCourseEntry sCourseData[kNumCourses] = {
{ "Creekside Country Club", "Amateur Classic", "Front 9 ~ Short Tee", "ui_wreath_bronze",		0,		6,	0, kCourseFront9, kCourseShortTee, kCourseLowWind },
{ "Creekside Country Club", "Amateur Cup", "Back 9 ~ Short Tee", "ui_wreath_silver",			0,		5,	0, kCourseBack9, kCourseShortTee, kCourseLowWind },
{ "Creekside Country Club", "Amateur Invitational", "18 Holes ~ Short Tee", "ui_trophy_gold",			0,		4,	0, kCourseAll18, kCourseShortTee, kCourseLowWind },
{ "Creekside Country Club", "Pro-am Classic", "Front 9 ~ Long Tee", "ui_wreath_gold",		0,		4,	0, kCourseFront9, kCourseLongTee, kCourseHighWind },
{ "Creekside Country Club", "Masters Qualifier", "Back 9 ~ Long Tee", "ui_wreath_gold",			0,		2,	0, kCourseBack9, kCourseLongTee, kCourseHighWind },
{ "Creekside Country Club", "Masters Cup", "18 Holes ~ Long Tee", "ui_trophy_platinum",			0,	0,	0, kCourseAll18, kCourseLongTee, kCourseHighWind },
{ "Creekside Driving Range", "Driving Range", "Driving Range", "",								0,		0,	1, kCourseDrivingRange, kCourseShortTee, kCourseHighWind },
};

RBCourseHole sCourseHoleData[kNumPhysicalCourses][18] = {
{
	{ 1, 4, "parflat"},
	{ 2, 5, "par5_A" },
	{ 3, 3, "par3_A" },
	{ 4, 4, "par4_E" },
	{ 5, 5, "par5_B" },
	{ 6, 4, "par4_G" },
	{ 7, 3, "par3_B" },
	{ 8, 5, "par5_C" },
	{ 9, 4, "par4_B" },
	{ 10, 4, "par4_H" },
	{ 11, 3, "par3_C" },
	{ 12, 5, "par5_D" },
	{ 13, 4, "par4_C" },
	{ 14, 3, "par3_D" },
	{ 15, 4, "par4_D" },
	{ 16, 3, "par3_E" },
	{ 17, 5, "par5_E" },
	{ 18, 4, "par4_F" }
},

{
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
}

};

RBCourseEntry * GetCourseData(int course)
{
	RUDE_ASSERT(course >= 0 && course < kNumCourses, "Invalid course number");

	return &sCourseData[course];
}

RBCourseHole * GetCourseHole(int course, eCourseHoles holeset, int hole)
{
	RUDE_ASSERT(course >= 0 && course < kNumCourses, "Invalid course number");
	RUDE_ASSERT(hole >= 0, "Invalid hole number");

	int actualhole = 0;

	switch(holeset)
	{
		case kCourseFront9:
		{
			if(hole >= 9)
				return 0;

			actualhole = hole;
		}
			break;
		case kCourseBack9:
		{
			if(hole >= 18)
				return 0;

			actualhole = hole;
		}
			break;
		case kCourseAll18:
		{
			if(hole >= 18)
				return 0;

			actualhole = hole;
		}
			break;
		case kCourseDrivingRange:
		{
			actualhole = 0;
		}
			break;
	}

	return &sCourseHoleData[sCourseData[course].m_physicalCourse][actualhole];
}
<commit_msg>Made par4a the first hole again<commit_after>/*
 *  RBCourseData.cpp
 *  golf
 *
 *  Created by Robert Rose on 10/30/08.
 *  Copyright 2008 Bork 3D LLC. All rights reserved.
 *
 */

#include "RBCourseData.h"

RBCourseEntry sCourseData[kNumCourses] = {
{ "Creekside Country Club", "Amateur Classic", "Front 9 ~ Short Tee", "ui_wreath_bronze",		0,		6,	0, kCourseFront9, kCourseShortTee, kCourseLowWind },
{ "Creekside Country Club", "Amateur Cup", "Back 9 ~ Short Tee", "ui_wreath_silver",			0,		5,	0, kCourseBack9, kCourseShortTee, kCourseLowWind },
{ "Creekside Country Club", "Amateur Invitational", "18 Holes ~ Short Tee", "ui_trophy_gold",			0,		4,	0, kCourseAll18, kCourseShortTee, kCourseLowWind },
{ "Creekside Country Club", "Pro-am Classic", "Front 9 ~ Long Tee", "ui_wreath_gold",		0,		4,	0, kCourseFront9, kCourseLongTee, kCourseHighWind },
{ "Creekside Country Club", "Masters Qualifier", "Back 9 ~ Long Tee", "ui_wreath_gold",			0,		2,	0, kCourseBack9, kCourseLongTee, kCourseHighWind },
{ "Creekside Country Club", "Masters Cup", "18 Holes ~ Long Tee", "ui_trophy_platinum",			0,	0,	0, kCourseAll18, kCourseLongTee, kCourseHighWind },
{ "Creekside Driving Range", "Driving Range", "Driving Range", "",								0,		0,	1, kCourseDrivingRange, kCourseShortTee, kCourseHighWind },
};

RBCourseHole sCourseHoleData[kNumPhysicalCourses][18] = {
{
	{ 1, 4, "par4_A"},
	{ 2, 5, "par5_A" },
	{ 3, 3, "par3_A" },
	{ 4, 4, "par4_E" },
	{ 5, 5, "par5_B" },
	{ 6, 4, "par4_G" },
	{ 7, 3, "par3_B" },
	{ 8, 5, "par5_C" },
	{ 9, 4, "par4_B" },
	{ 10, 4, "par4_H" },
	{ 11, 3, "par3_C" },
	{ 12, 5, "par5_D" },
	{ 13, 4, "par4_C" },
	{ 14, 3, "par3_D" },
	{ 15, 4, "par4_D" },
	{ 16, 3, "par3_E" },
	{ 17, 5, "par5_E" },
	{ 18, 4, "par4_F" }
},

{
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
	{ 1, 1, "driving_range" },
}

};

RBCourseEntry * GetCourseData(int course)
{
	RUDE_ASSERT(course >= 0 && course < kNumCourses, "Invalid course number");

	return &sCourseData[course];
}

RBCourseHole * GetCourseHole(int course, eCourseHoles holeset, int hole)
{
	RUDE_ASSERT(course >= 0 && course < kNumCourses, "Invalid course number");
	RUDE_ASSERT(hole >= 0, "Invalid hole number");

	int actualhole = 0;

	switch(holeset)
	{
		case kCourseFront9:
		{
			if(hole >= 9)
				return 0;

			actualhole = hole;
		}
			break;
		case kCourseBack9:
		{
			if(hole >= 18)
				return 0;

			actualhole = hole;
		}
			break;
		case kCourseAll18:
		{
			if(hole >= 18)
				return 0;

			actualhole = hole;
		}
			break;
		case kCourseDrivingRange:
		{
			actualhole = 0;
		}
			break;
	}

	return &sCourseHoleData[sCourseData[course].m_physicalCourse][actualhole];
}
<|endoftext|>


<commit_before><commit_msg>Add an assert and make sure we're not using the unallocated parts of the hashmap.<commit_after><|endoftext|>


<commit_before><commit_msg>Removed unnecessary `#include` lines.<commit_after><|endoftext|>