<commit_before>#ifndef __FUTURE_HPP__
#define __FUTURE_HPP__

#include "SoftXMT.hpp"
#include "Delegate.hpp"
#include "Cache.hpp"

//TODO: special ArgsCache acquire, which
//uses args pointer field as a global address
//to the future and either
//1. flip the started bit
//2. or simply acquire RW instead of RO (and Cached not Incoherent)

// idea: if we had a need for futures that
// only mutate their arguments (essentially functional but could change the inputs as well)
// then we could allow multiple copies of
// the future to execute RW-shared mode, where only the first release writeback wins

// TODO: do something like this to force users to have
// the future fields but make them invisible
/*
class FutureArgs {
    private:
    GlobalAddress<Future> futurePtr;
    void (* user_fn_p)(A *);
};
class MyArgs : public FutureArgs {
    int i;
    int j;
}
// Additional possibility is method #2 above
    */

//////////////////////////////////////////
#if DEBUG
static int64_t count_ = 0;
#endif

template < typename ArgsStruct >
class Future {
    private:
        int64_t started;
        Thread * waiter;
        bool done;
        ArgsStruct * userArgs_lp;

        struct future_args {
            GlobalAddress<Future> futureAddr;
            void (* user_fn_p)(ArgsStruct *);
            GlobalAddress< ArgsStruct > userArgs;

            future_args( Future< ArgsStruct > * future, ArgsStruct * userArgs, void (* fn_p)(ArgsStruct *) )
                : futureAddr( make_global( future ) )
                , userArgs( make_global( userArgs ) )
                , user_fn_p( fn_p )
            { }
        };

        future_args task_args;

        struct future_done_args {
            Future< ArgsStruct > * futurePtr;
        };

        static void future_done_am( future_done_args * args, size_t args_size, void * payload, size_t payload_size ) {
            args->futurePtr->done = true;
            if ( args->futurePtr->waiter != NULL ) {
                SoftXMT_wake( args->futurePtr->waiter );
                args->futurePtr->waiter = NULL;
            }
        }

        /////////////////
        //Custom delegate operation
        //TODO: use a generalized mechanism that abstracts all but function
        /////////////////
        struct started_memory_descriptor {
            Thread * t;
            GlobalAddress< Future<ArgsStruct> > address;
            int64_t data;
            bool done;
        };

        struct started_reply_args {
            GlobalAddress<started_memory_descriptor> descriptor;
        };

        static void started_reply_am( started_reply_args * args, size_t size, void * payload, size_t payload_size ) {
            assert( payload_size == sizeof(int64_t ) );
            args->descriptor.pointer()->data = *(static_cast<int64_t*>(payload));
            args->descriptor.pointer()->done = true;
            SoftXMT_wake( args->descriptor.pointer()->t );
        }

        struct started_request_args {
            GlobalAddress<started_memory_descriptor> descriptor;
            GlobalAddress< Future<ArgsStruct> > address;
        };

        static void started_request_am( started_request_args * args, size_t size, void * payload, size_t payload_size ) {
            Future< ArgsStruct > * fptr = args->address.pointer();

            DVLOG(5) << "Future(IN_AM) FID "<< fptr->getId();

            CHECK((int64_t)fptr>0x1000) << "dequeued request (descriptor gaddress:" << args->descriptor
                    << "): future ptr:" << (void*)fptr
                    << "(future gaddress:"<<args->address;
            int64_t data = fptr->started;
            fptr->started = data + 1;

            // If future was already started in this case, it must have been started by touching thread.
            // Incrementing started again will tell the touching thread it can deallocate the Future
            if ( data > 0 ) {
                DVLOG(5) << "already started:(id:"<<fptr->getId();
                if ( fptr->done ) { //if it is done then toucher is waiting for the dequeue
                    DVLOG(5) << "need to wake:(id:"<<fptr->getId();
                    CHECK ( fptr->waiter!=NULL ) << "future ptr:" << (void*)fptr <<"\n done="<<fptr->done<<" (id:"<<fptr->getId()<<") data="<<data<< " (AM from "<<args->descriptor.node();
                    SoftXMT_wake( fptr->waiter );
                    fptr->waiter = NULL;
                } else {
                    DVLOG(5) << "not need to wake:(id:"<<fptr->getId();
                }
            } else {
                DVLOG(5) << "not already started:(id:"<<fptr->getId();
            }

            started_reply_args reply_args;
            reply_args.descriptor = args->descriptor;
            SoftXMT_call_on( args->descriptor.node(), &started_reply_am,
                    &reply_args, sizeof(reply_args),
                    &data, sizeof(data) );
        }

        static int64_t future_delegate_started( GlobalAddress< Future<ArgsStruct> > address ) {
            started_memory_descriptor md;
            md.address = address;
            md.data = 0;
            md.done = false;
            md.t = CURRENT_THREAD;
            started_request_args args;
            args.descriptor = make_global(&md);
            args.address = address;
            SoftXMT_call_on( address.node(), &started_request_am, &args );
            while( !md.done ) {
                SoftXMT_suspend();
            }
            return md.data;
        }
        //////////////////////////////////////

        static void future_function( future_args * args ) {
            DVLOG(4) << "Future(other) "<< args->futureAddr;
            // TODO #1: the make_global is just calculating location of Future->started
            //if ( SoftXMT_delegate_fetch_and_add_word( make_global( args->startedAddr, args->futureAddr.node() ), 1 ) == 0 ) {
            DVLOG(5) << CURRENT_THREAD->id << "args("<<(void*)args<<") will call started am " << args->futureAddr.pointer();
            if ( future_delegate_started( args->futureAddr ) == 0 ) {
                DVLOG(5) << CURRENT_THREAD->id << "user_args="<<args->userArgs<<" for ftraddr="<< args->futureAddr.pointer();
                // grab the user arguments
                size_t args_size = sizeof(ArgsStruct);
                ArgsStruct argsbuf;
                typename Incoherent<ArgsStruct>::RO cached_args( args->userArgs, args_size, &argsbuf );
                cached_args.block_until_acquired();

                // call the user task
                args->user_fn_p( &argsbuf );
                cached_args.block_until_released();

                // call wake up AM on Node that has the Future
                future_done_args done_args = { args->futureAddr.pointer() };
                SoftXMT_call_on( args->futureAddr.node(), &future_done_am, &done_args );
            }
        }

        int64_t getId() {
#if DEBUG
            return id;
#else
            return -1;
#endif
        }

    public:
#if DEBUG
        int64_t id;
#endif

        // TODO: NOTE that this does not copy user arguments because we want to
        // preserve the same semantics as normal tasks.
        // --Unfortunately this means there are three communications to start
        // 1) Task.execute fetches args
        // 2) Future atomic started
        // 3) Bring in user arguments and start
        Future ( void (* fn_p)(ArgsStruct *), ArgsStruct * userArgs )
            : started( 0 )
              , waiter( NULL )
              , done( false )
              , userArgs_lp( userArgs )
#if DEBUG
              , id( SoftXMT_mynode() + ((count_++)*SoftXMT_nodes() ) )
#endif
              , task_args( this, userArgs, fn_p ) {

           DVLOG(5) << CURRENT_THREAD->id << " creates Future:"<< (void*)this << " id:"<< getId() << " args:"<< &task_args;
        }

        void touch( ) {
            DVLOG(4) << "Future(touch) FID "<< this->getId() << " ga:"<<task_args.futureAddr;
            // start if not started
            if ( SoftXMT_delegate_fetch_and_add_word( make_global(&started), 1 )==0 ) {
                DVLOG(5) << CURRENT_THREAD->id << " gets to touch-go " << getId();
                task_args.user_fn_p( userArgs_lp );
                CHECK( started <= 2 ) << "started=" << started << " (at most one additional increment should occur)";
                done = true;
                while ( started < 2 ) { // wait until dequeued
                    DVLOG(5) << CURRENT_THREAD->id << " has to wait on dequeue " << getId();
                    waiter = CURRENT_THREAD;
                    SoftXMT_suspend( );
                    DVLOG(5) << CURRENT_THREAD->id << " has woke on dequeue " << getId();
                }
            } else  {
                // otherwise block on done event
                while ( !done ) {
                    waiter = CURRENT_THREAD;
                    SoftXMT_suspend( );
                }
            }
        }

        void addAsPublicTask( ) {
            DVLOG(4) << "Future(spawn) " << this->getId() << " ga:"<<task_args.futureAddr;
            SoftXMT_publicTask( &future_function, &task_args );
        }
};

#endif
<commit_msg>FIXED: future was fetching count:args_size, instead of count=1 userArgs<commit_after>#ifndef __FUTURE_HPP__
#define __FUTURE_HPP__

#include "SoftXMT.hpp"
#include "Delegate.hpp"
#include "Cache.hpp"

//TODO: special ArgsCache acquire, which
//uses args pointer field as a global address
//to the future and either
//1. flip the started bit
//2. or simply acquire RW instead of RO (and Cached not Incoherent)

// idea: if we had a need for futures that
// only mutate their arguments (essentially functional but could change the inputs as well)
// then we could allow multiple copies of
// the future to execute RW-shared mode, where only the first release writeback wins

// TODO: do something like this to force users to have
// the future fields but make them invisible
/*
class FutureArgs {
    private:
    GlobalAddress<Future> futurePtr;
    void (* user_fn_p)(A *);
};
class MyArgs : public FutureArgs {
    int i;
    int j;
}
// Additional possibility is method #2 above
    */

//////////////////////////////////////////
#if DEBUG
static int64_t count_ = 0;
#endif

template < typename ArgsStruct >
class Future {
    private:
        int64_t started;
        Thread * waiter;
        bool done;
        ArgsStruct * userArgs_lp;

        struct future_args {
            GlobalAddress<Future> futureAddr;
            void (* user_fn_p)(ArgsStruct *);
            GlobalAddress< ArgsStruct > userArgs;

            future_args( Future< ArgsStruct > * future, ArgsStruct * userArgs, void (* fn_p)(ArgsStruct *) )
                : futureAddr( make_global( future ) )
                , userArgs( make_global( userArgs ) )
                , user_fn_p( fn_p )
            { }
        };

        future_args task_args;

        struct future_done_args {
            Future< ArgsStruct > * futurePtr;
        };

        static void future_done_am( future_done_args * args, size_t args_size, void * payload, size_t payload_size ) {
            args->futurePtr->done = true;
            if ( args->futurePtr->waiter != NULL ) {
                SoftXMT_wake( args->futurePtr->waiter );
                args->futurePtr->waiter = NULL;
            }
        }

        /////////////////
        //Custom delegate operation
        //TODO: use a generalized mechanism that abstracts all but function
        /////////////////
        struct started_memory_descriptor {
            Thread * t;
            GlobalAddress< Future<ArgsStruct> > address;
            int64_t data;
            bool done;
        };

        struct started_reply_args {
            GlobalAddress<started_memory_descriptor> descriptor;
        };

        static void started_reply_am( started_reply_args * args, size_t size, void * payload, size_t payload_size ) {
            assert( payload_size == sizeof(int64_t ) );
            args->descriptor.pointer()->data = *(static_cast<int64_t*>(payload));
            args->descriptor.pointer()->done = true;
            SoftXMT_wake( args->descriptor.pointer()->t );
        }

        struct started_request_args {
            GlobalAddress<started_memory_descriptor> descriptor;
            GlobalAddress< Future<ArgsStruct> > address;
        };

        static void started_request_am( started_request_args * args, size_t size, void * payload, size_t payload_size ) {
            Future< ArgsStruct > * fptr = args->address.pointer();

            DVLOG(5) << "Future(IN_AM) FID "<< fptr->getId();

            CHECK((int64_t)fptr>0x1000) << "dequeued request (descriptor gaddress:" << args->descriptor
                    << "): future ptr:" << (void*)fptr
                    << "(future gaddress:"<<args->address;
            int64_t data = fptr->started;
            fptr->started = data + 1;

            // If future was already started in this case, it must have been started by touching thread.
            // Incrementing started again will tell the touching thread it can deallocate the Future
            if ( data > 0 ) {
                DVLOG(5) << "already started:(id:"<<fptr->getId();
                if ( fptr->done ) { //if it is done then toucher is waiting for the dequeue
                    DVLOG(5) << "need to wake:(id:"<<fptr->getId();
                    CHECK ( fptr->waiter!=NULL ) << "future ptr:" << (void*)fptr <<"\n done="<<fptr->done<<" (id:"<<fptr->getId()<<") data="<<data<< " (AM from "<<args->descriptor.node();
                    SoftXMT_wake( fptr->waiter );
                    fptr->waiter = NULL;
                } else {
                    DVLOG(5) << "not need to wake:(id:"<<fptr->getId();
                }
            } else {
                DVLOG(5) << "not already started:(id:"<<fptr->getId();
            }

            started_reply_args reply_args;
            reply_args.descriptor = args->descriptor;
            SoftXMT_call_on( args->descriptor.node(), &started_reply_am,
                    &reply_args, sizeof(reply_args),
                    &data, sizeof(data) );
        }

        static int64_t future_delegate_started( GlobalAddress< Future<ArgsStruct> > address ) {
            started_memory_descriptor md;
            md.address = address;
            md.data = 0;
            md.done = false;
            md.t = CURRENT_THREAD;
            started_request_args args;
            args.descriptor = make_global(&md);
            args.address = address;
            SoftXMT_call_on( address.node(), &started_request_am, &args );
            while( !md.done ) {
                SoftXMT_suspend();
            }
            return md.data;
        }
        //////////////////////////////////////

        static void future_function( future_args * args ) {
            DVLOG(4) << "Future(other) "<< args->futureAddr;
            // TODO #1: the make_global is just calculating location of Future->started
            //if ( SoftXMT_delegate_fetch_and_add_word( make_global( args->startedAddr, args->futureAddr.node() ), 1 ) == 0 ) {
            DVLOG(5) << CURRENT_THREAD->id << "args("<<(void*)args<<") will call started am " << args->futureAddr.pointer();
            if ( future_delegate_started( args->futureAddr ) == 0 ) {
                DVLOG(5) << CURRENT_THREAD->id << "user_args="<<args->userArgs<<" for ftraddr="<< args->futureAddr.pointer();
                // grab the user arguments
                size_t args_size = sizeof(ArgsStruct);
                ArgsStruct argsbuf;
                typename Incoherent<ArgsStruct>::RO cached_args( args->userArgs, 1, &argsbuf );
                cached_args.block_until_acquired();

                // call the user task
                args->user_fn_p( &argsbuf );
                cached_args.block_until_released();

                // call wake up AM on Node that has the Future
                future_done_args done_args = { args->futureAddr.pointer() };
                SoftXMT_call_on( args->futureAddr.node(), &future_done_am, &done_args );
            }
        }

        int64_t getId() {
#if DEBUG
            return id;
#else
            return -1;
#endif
        }

    public:
#if DEBUG
        int64_t id;
#endif

        // TODO: NOTE that this does not copy user arguments because we want to
        // preserve the same semantics as normal tasks.
        // --Unfortunately this means there are three communications to start
        // 1) Task.execute fetches args
        // 2) Future atomic started
        // 3) Bring in user arguments and start
        Future ( void (* fn_p)(ArgsStruct *), ArgsStruct * userArgs )
            : started( 0 )
              , waiter( NULL )
              , done( false )
              , userArgs_lp( userArgs )
#if DEBUG
              , id( SoftXMT_mynode() + ((count_++)*SoftXMT_nodes() ) )
#endif
              , task_args( this, userArgs, fn_p ) {

           DVLOG(5) << CURRENT_THREAD->id << " creates Future:"<< (void*)this << " id:"<< getId() << " args:"<< &task_args;
        }

        void touch( ) {
            DVLOG(4) << "Future(touch) FID "<< this->getId() << " ga:"<<task_args.futureAddr;
            // start if not started
            if ( SoftXMT_delegate_fetch_and_add_word( make_global(&started), 1 )==0 ) {
                DVLOG(5) << CURRENT_THREAD->id << " gets to touch-go " << getId();
                task_args.user_fn_p( userArgs_lp );
                CHECK( started <= 2 ) << "started=" << started << " (at most one additional increment should occur)";
                done = true;
                while ( started < 2 ) { // wait until dequeued
                    DVLOG(5) << CURRENT_THREAD->id << " has to wait on dequeue " << getId();
                    waiter = CURRENT_THREAD;
                    SoftXMT_suspend( );
                    DVLOG(5) << CURRENT_THREAD->id << " has woke on dequeue " << getId();
                }
            } else  {
                // otherwise block on done event
                while ( !done ) {
                    waiter = CURRENT_THREAD;
                    SoftXMT_suspend( );
                }
            }
        }

        void addAsPublicTask( ) {
            DVLOG(4) << "Future(spawn) " << this->getId() << " ga:"<<task_args.futureAddr;
            SoftXMT_publicTask( &future_function, &task_args );
        }
};

#endif
<|endoftext|>


<commit_before>#include "pch.h"
#include "aiMeshOps.h"

namespace impl
{
    template<class Indices, class Counts>
    inline void BuildConnection(
        MeshConnectionInfo& connection, const Indices& indices, const Counts& counts, const IArray<float3>& vertices)
    {
        size_t num_points = vertices.size();
        size_t num_faces = counts.size();
        size_t num_indices = indices.size();

        connection.v2f_offsets.resize_discard(num_points);
        connection.v2f_faces.resize_discard(num_indices);
        connection.v2f_indices.resize_discard(num_indices);

        connection.v2f_counts.resize_zeroclear(num_points);
        {
            int ii = 0;
            for (size_t fi = 0; fi < num_faces; ++fi) {
                int c = counts[fi];
                for (int ci = 0; ci < c; ++ci) {
                    connection.v2f_counts[indices[ii + ci]]++;
                }
                ii += c;
            }

            int offset = 0;
            for (size_t i = 0; i < num_points; ++i) {
                connection.v2f_offsets[i] = offset;
                offset += connection.v2f_counts[i];
            }
        }

        connection.v2f_counts.zeroclear();
        {
            int i = 0;
            for (int fi = 0; fi < (int)num_faces; ++fi) {
                int c = counts[fi];
                for (int ci = 0; ci < c; ++ci) {
                    int vi = indices[i + ci];
                    int ti = connection.v2f_offsets[vi] + connection.v2f_counts[vi]++;
                    connection.v2f_faces[ti] = fi;
                    connection.v2f_indices[ti] = i + ci;
                }
                i += c;
            }
        }
    }
}

void MeshConnectionInfo::clear()
{
    v2f_counts.clear();
    v2f_offsets.clear();
    v2f_faces.clear();
    v2f_indices.clear();

    weld_map.clear();
    weld_counts.clear();
    weld_offsets.clear();
    weld_indices.clear();
}

void MeshConnectionInfo::buildConnection(
    const IArray<int>& indices, const IArray<int>& counts, const IArray<float3>& vertices)
{
    size_t num_points = vertices.size();
    size_t num_faces = counts.size();
    size_t num_indices = indices.size();

    v2f_offsets.resize_discard(num_points);
    v2f_faces.resize_discard(num_indices);
    v2f_indices.resize_discard(num_indices);

    v2f_counts.resize_zeroclear(num_points);
    {
        int ii = 0;
        for (size_t fi = 0; fi < num_faces; ++fi) {
            int c = counts[fi];
            for (int ci = 0; ci < c; ++ci) {
                v2f_counts[indices[ii + ci]]++;
            }
            ii += c;
        }

        int offset = 0;
        for (size_t i = 0; i < num_points; ++i) {
            v2f_offsets[i] = offset;
            offset += v2f_counts[i];
        }
    }

    v2f_counts.zeroclear();
    {
        int i = 0;
        for (int fi = 0; fi < (int)num_faces; ++fi) {
            int c = counts[fi];
            for (int ci = 0; ci < c; ++ci) {
                int vi = indices[i + ci];
                int ti = v2f_offsets[vi] + v2f_counts[vi]++;
                v2f_faces[ti] = fi;
                v2f_indices[ti] = i + ci;
            }
            i += c;
        }
    }
}

static inline int next_power_of_two(uint32_t v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    return v + (v == 0);
}

void MeshWelder::prepare(abcV3 * points, int count)
{
    m_points = points;
    m_count = count;

    m_hash_size = next_power_of_two(m_count);
    m_hash_table.resize_discard(m_hash_size + m_count);
    memset(m_hash_table.data(), NIL, m_hash_size * sizeof(int));

    m_remap.resize_discard(m_count);
}

const RawVector<int>& MeshWelder::getRemapTable() const
{
    return m_remap;
}

void MeshRefiner::triangulate(bool swap_faces, bool turn_quads)
{
    auto& dst = new_indices_triangulated;
    dst.resize(num_new_indices);

    const int i1 = swap_faces ? 2 : 1;
    const int i2 = swap_faces ? 1 : 2;
    size_t num_faces = counts.size();

    int n = 0;
    int i = 0;
    if (turn_quads) {
        for (size_t fi = 0; fi < num_faces; ++fi) {
            int count = counts[fi];
            if (count == 4) {
                int quad[4] = {
                    new_indices[n + 3],
                    new_indices[n + 0],
                    new_indices[n + 1],
                    new_indices[n + 2],
                };
                for (int ni = 0; ni < count - 2; ++ni) {
                    dst[i + 0] = quad[0];
                    dst[i + 1] = quad[ni + i1];
                    dst[i + 2] = quad[ni + i2];
                    i += 3;
                }
                n += count;
            }
            else {
                for (int ni = 0; ni < count - 2; ++ni) {
                    dst[i + 0] = new_indices[n + 0];
                    dst[i + 1] = new_indices[n + ni + i1];
                    dst[i + 2] = new_indices[n + ni + i2];
                    i += 3;
                }
                n += count;
            }
        }
    }
    else {
        for (size_t fi = 0; fi < num_faces; ++fi) {
            int count = counts[fi];
            for (int ni = 0; ni < count - 2; ++ni) {
                dst[i + 0] = new_indices[n + 0];
                dst[i + 1] = new_indices[n + ni + i1];
                dst[i + 2] = new_indices[n + ni + i2];
                i += 3;
            }
            n += count;
        }
    }
}

void MeshRefiner::genSubmeshes(IArray<int> material_ids)
{
    submeshes.clear();

    new_indices_submeshes.resize(new_indices_triangulated.size());
    const int *indices_read = new_indices_triangulated.data();
    int *indices_write = new_indices_submeshes.data();

    int num_splits = (int)splits.size();
    int offset_faces = 0;
    RawVector<Submesh> tmp_submeshes;

    for (int spi = 0; spi < num_splits; ++spi) {
        auto& split = splits[spi];
        int offset_vertices = split.vertex_offset;

        // count triangle indices
        for (int fi = 0; fi < split.face_count; ++fi) {
            int mid = material_ids[offset_faces + fi] + 1; // -1 == no material. adjust to zero based
            while (mid >= (int)tmp_submeshes.size()) {
                int id = (int)tmp_submeshes.size();
                tmp_submeshes.push_back({});
                tmp_submeshes.back().material_id = id - 1;
            }
            tmp_submeshes[mid].index_count += (counts[fi] - 2) * 3;
        }

        for (int mi = 0; mi < (int)tmp_submeshes.size(); ++mi) {
            auto& sm = tmp_submeshes[mi];
            sm.indices_write = indices_write;
            sm.index_offset = (int)std::distance(new_indices_submeshes.data(), indices_write);
            indices_write += sm.index_count;
        }

        // copy indices
        for (int fi = 0; fi < split.face_count; ++fi) {
            int mid = material_ids[offset_faces + fi] + 1;
            int count = counts[offset_faces + fi];
            int nidx = (count - 2) * 3;
            for (int i = 0; i < nidx; ++i) {
                *(tmp_submeshes[mid].indices_write++) = *(indices_read++) - offset_vertices;
            }
        }

        for (int mi = 0; mi < (int)tmp_submeshes.size(); ++mi) {
            auto& sm = tmp_submeshes[mi];
            if (sm.index_count > 0) {
                ++split.submesh_count;
                submeshes.push_back(sm);
            }
        }

        offset_faces += split.face_count;
        tmp_submeshes.clear();
    }
    setupSubmeshes();
}

void MeshRefiner::genSubmeshes()
{
    submeshes.clear();

    new_indices_submeshes.resize(new_indices_triangulated.size());
    const int *indices_read = new_indices_triangulated.data();
    int *indices_write = new_indices_submeshes.data();

    int num_splits = (int)splits.size();
    for (int spi = 0; spi < num_splits; ++spi) {
        auto& split = splits[spi];
        int offset_vertices = split.vertex_offset;

        Submesh sm;
        sm.index_count = split.triangulated_index_count;
        sm.index_offset = (int)std::distance(new_indices_submeshes.data(), indices_write);
        for (int ii = 0; ii < sm.index_count; ++ii) {
            *(indices_write++) = *(indices_read++) - offset_vertices;
        }

        ++split.submesh_count;
        submeshes.push_back(sm);
    }
    setupSubmeshes();
}

void MeshRefiner::setupSubmeshes()
{
    int num_splits = (int)splits.size();
    int total_submeshes = 0;
    for (int spi = 0; spi < num_splits; ++spi) {
        auto& split = splits[spi];
        split.submesh_offset = total_submeshes;
        total_submeshes += split.submesh_count;
        for (int smi = 0; smi < split.submesh_count; ++smi) {
            auto& sm = submeshes[smi + split.submesh_offset];
            sm.split_index = spi;
            sm.submesh_index = smi;
        }
    }
}

void MeshRefiner::clear()
{
    split_unit = 0;
    counts.reset();
    indices.reset();
    points.reset();
    for (auto& attr : attributes) {
        attr->clear();
        // attributes are placement new-ed, so need to call destructor manually
        attr->~IAttribute();
    }
    attributes.clear();

    old2new_indices.clear();
    new2old_points.clear();

    new_indices.clear();
    new_indices_triangulated.clear();
    new_indices_submeshes.clear();

    new_points.clear();
    splits.clear();
    submeshes.clear();
    num_new_indices = 0;
}

void MeshRefiner::refine()
{
    if (connection.v2f_counts.size() != points.size()) {
        connection.buildConnection(indices, counts, points);
    }

    int num_indices = (int)indices.size();
    new_points.reserve(num_indices);
    new_indices.reserve(num_indices);
    for (auto& attr : attributes) { attr->prepare((int)points.size(), (int)indices.size()); }

    old2new_indices.resize(num_indices, -1);

    int num_faces_total = (int)counts.size();
    int offset_faces = 0;
    int offset_indices = 0;
    int offset_vertices = 0;
    int num_faces = 0;
    int num_indices_triangulated = 0;

    auto add_new_split = [&]() {
        auto split = Split{};
        split.face_offset = offset_faces;
        split.index_offset = offset_indices;
        split.vertex_offset = offset_vertices;
        split.face_count = num_faces;
        split.triangulated_index_count = num_indices_triangulated;
        split.vertex_count = (int)new_points.size() - offset_vertices;
        split.index_count = (int)new_indices.size() - offset_indices;
        splits.push_back(split);

        offset_faces += split.face_count;
        offset_indices += split.index_count;
        offset_vertices += split.vertex_count;

        num_new_indices += num_indices_triangulated;
        num_faces = 0;
        num_indices_triangulated = 0;
    };

    auto compare_all_attributes = [&](int ni, int ii) -> bool {
        for (auto& attr : attributes)
            if (!attr->compare(ni, ii)) { return false; }
        return true;
    };

    auto find_or_emit_vertex = [&](int vi, int ii) -> int {
        int offset = connection.v2f_offsets[vi];
        int connection_count = connection.v2f_counts[vi];
        for (int ci = 0; ci < connection_count; ++ci) {
            int& ni = old2new_indices[connection.v2f_indices[offset + ci]];
            if (ni != -1 && compare_all_attributes(ni, ii)) {
                return ni;
            }
            else if (ni == -1) {
                ni = (int)new_points.size();
                new_points.push_back(points[vi]);
                new2old_points.push_back(vi);
                for (auto& attr : attributes) { attr->emit(ii); }
                return ni;
            }
        }
        return 0;
    };

    int offset = 0;
    for (int fi = 0; fi < num_faces_total; ++fi) {
        int count = counts[fi];

        if (split_unit > 0 && (int)new_points.size() - offset_vertices + count > split_unit) {
            add_new_split();

            // clear vertex cache
            memset(old2new_indices.data(), -1, old2new_indices.size() * sizeof(int));
        }

        for (int ci = 0; ci < count; ++ci) {
            int ii = offset + ci;
            int vi = indices[ii];
            new_indices.push_back(find_or_emit_vertex(vi, ii));
        }
        ++num_faces;
        num_indices_triangulated += (count - 2) * 3;
        offset += count;
    }
    add_new_split();
}

<commit_msg>fix a bug in MeshRefiner #58<commit_after>#include "pch.h"
#include "aiMeshOps.h"

namespace impl
{
    template<class Indices, class Counts>
    inline void BuildConnection(
        MeshConnectionInfo& connection, const Indices& indices, const Counts& counts, const IArray<float3>& vertices)
    {
        size_t num_points = vertices.size();
        size_t num_faces = counts.size();
        size_t num_indices = indices.size();

        connection.v2f_offsets.resize_discard(num_points);
        connection.v2f_faces.resize_discard(num_indices);
        connection.v2f_indices.resize_discard(num_indices);

        connection.v2f_counts.resize_zeroclear(num_points);
        {
            int ii = 0;
            for (size_t fi = 0; fi < num_faces; ++fi) {
                int c = counts[fi];
                for (int ci = 0; ci < c; ++ci) {
                    connection.v2f_counts[indices[ii + ci]]++;
                }
                ii += c;
            }

            int offset = 0;
            for (size_t i = 0; i < num_points; ++i) {
                connection.v2f_offsets[i] = offset;
                offset += connection.v2f_counts[i];
            }
        }

        connection.v2f_counts.zeroclear();
        {
            int i = 0;
            for (int fi = 0; fi < (int)num_faces; ++fi) {
                int c = counts[fi];
                for (int ci = 0; ci < c; ++ci) {
                    int vi = indices[i + ci];
                    int ti = connection.v2f_offsets[vi] + connection.v2f_counts[vi]++;
                    connection.v2f_faces[ti] = fi;
                    connection.v2f_indices[ti] = i + ci;
                }
                i += c;
            }
        }
    }
}

void MeshConnectionInfo::clear()
{
    v2f_counts.clear();
    v2f_offsets.clear();
    v2f_faces.clear();
    v2f_indices.clear();

    weld_map.clear();
    weld_counts.clear();
    weld_offsets.clear();
    weld_indices.clear();
}

void MeshConnectionInfo::buildConnection(
    const IArray<int>& indices, const IArray<int>& counts, const IArray<float3>& vertices)
{
    size_t num_points = vertices.size();
    size_t num_faces = counts.size();
    size_t num_indices = indices.size();

    v2f_offsets.resize_discard(num_points);
    v2f_faces.resize_discard(num_indices);
    v2f_indices.resize_discard(num_indices);

    v2f_counts.resize_zeroclear(num_points);
    {
        int ii = 0;
        for (size_t fi = 0; fi < num_faces; ++fi) {
            int c = counts[fi];
            for (int ci = 0; ci < c; ++ci) {
                v2f_counts[indices[ii + ci]]++;
            }
            ii += c;
        }

        int offset = 0;
        for (size_t i = 0; i < num_points; ++i) {
            v2f_offsets[i] = offset;
            offset += v2f_counts[i];
        }
    }

    v2f_counts.zeroclear();
    {
        int i = 0;
        for (int fi = 0; fi < (int)num_faces; ++fi) {
            int c = counts[fi];
            for (int ci = 0; ci < c; ++ci) {
                int vi = indices[i + ci];
                int ti = v2f_offsets[vi] + v2f_counts[vi]++;
                v2f_faces[ti] = fi;
                v2f_indices[ti] = i + ci;
            }
            i += c;
        }
    }
}

static inline int next_power_of_two(uint32_t v)
{
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    return v + (v == 0);
}

void MeshWelder::prepare(abcV3 * points, int count)
{
    m_points = points;
    m_count = count;

    m_hash_size = next_power_of_two(m_count);
    m_hash_table.resize_discard(m_hash_size + m_count);
    memset(m_hash_table.data(), NIL, m_hash_size * sizeof(int));

    m_remap.resize_discard(m_count);
}

const RawVector<int>& MeshWelder::getRemapTable() const
{
    return m_remap;
}

void MeshRefiner::triangulate(bool swap_faces, bool turn_quads)
{
    auto& dst = new_indices_triangulated;
    dst.resize(num_new_indices);

    const int i1 = swap_faces ? 2 : 1;
    const int i2 = swap_faces ? 1 : 2;
    size_t num_faces = counts.size();

    int n = 0;
    int i = 0;
    if (turn_quads) {
        for (size_t fi = 0; fi < num_faces; ++fi) {
            int count = counts[fi];
            if (count == 4) {
                int quad[4] = {
                    new_indices[n + 3],
                    new_indices[n + 0],
                    new_indices[n + 1],
                    new_indices[n + 2],
                };
                for (int ni = 0; ni < count - 2; ++ni) {
                    dst[i + 0] = quad[0];
                    dst[i + 1] = quad[ni + i1];
                    dst[i + 2] = quad[ni + i2];
                    i += 3;
                }
                n += count;
            }
            else {
                for (int ni = 0; ni < count - 2; ++ni) {
                    dst[i + 0] = new_indices[n + 0];
                    dst[i + 1] = new_indices[n + ni + i1];
                    dst[i + 2] = new_indices[n + ni + i2];
                    i += 3;
                }
                n += count;
            }
        }
    }
    else {
        for (size_t fi = 0; fi < num_faces; ++fi) {
            int count = counts[fi];
            for (int ni = 0; ni < count - 2; ++ni) {
                dst[i + 0] = new_indices[n + 0];
                dst[i + 1] = new_indices[n + ni + i1];
                dst[i + 2] = new_indices[n + ni + i2];
                i += 3;
            }
            n += count;
        }
    }
}

void MeshRefiner::genSubmeshes(IArray<int> material_ids)
{
    submeshes.clear();

    new_indices_submeshes.resize(new_indices_triangulated.size());
    const int *indices_read = new_indices_triangulated.data();
    int *indices_write = new_indices_submeshes.data();

    int num_splits = (int)splits.size();
    int offset_faces = 0;
    RawVector<Submesh> tmp_submeshes;

    for (int spi = 0; spi < num_splits; ++spi) {
        auto& split = splits[spi];
        int offset_vertices = split.vertex_offset;

        // count triangle indices
        for (int fi = 0; fi < split.face_count; ++fi) {
            int mid = material_ids[offset_faces + fi] + 1; // -1 == no material. adjust to zero based
            while (mid >= (int)tmp_submeshes.size()) {
                int id = (int)tmp_submeshes.size();
                tmp_submeshes.push_back({});
                tmp_submeshes.back().material_id = id - 1;
            }
            tmp_submeshes[mid].index_count += (counts[fi] - 2) * 3;
        }

        for (int mi = 0; mi < (int)tmp_submeshes.size(); ++mi) {
            auto& sm = tmp_submeshes[mi];
            sm.indices_write = indices_write;
            sm.index_offset = (int)std::distance(new_indices_submeshes.data(), indices_write);
            indices_write += sm.index_count;
        }

        // copy indices
        for (int fi = 0; fi < split.face_count; ++fi) {
            int mid = material_ids[offset_faces + fi] + 1;
            int count = counts[offset_faces + fi];
            int nidx = (count - 2) * 3;
            for (int i = 0; i < nidx; ++i) {
                *(tmp_submeshes[mid].indices_write++) = *(indices_read++) - offset_vertices;
            }
        }

        for (int mi = 0; mi < (int)tmp_submeshes.size(); ++mi) {
            auto& sm = tmp_submeshes[mi];
            if (sm.index_count > 0) {
                ++split.submesh_count;
                submeshes.push_back(sm);
            }
        }

        offset_faces += split.face_count;
        tmp_submeshes.clear();
    }
    setupSubmeshes();
}

void MeshRefiner::genSubmeshes()
{
    submeshes.clear();

    new_indices_submeshes.resize(new_indices_triangulated.size());
    const int *indices_read = new_indices_triangulated.data();
    int *indices_write = new_indices_submeshes.data();

    int num_splits = (int)splits.size();
    for (int spi = 0; spi < num_splits; ++spi) {
        auto& split = splits[spi];
        int offset_vertices = split.vertex_offset;

        Submesh sm;
        sm.index_count = split.triangulated_index_count;
        sm.index_offset = (int)std::distance(new_indices_submeshes.data(), indices_write);
        for (int ii = 0; ii < sm.index_count; ++ii) {
            *(indices_write++) = *(indices_read++) - offset_vertices;
        }

        ++split.submesh_count;
        submeshes.push_back(sm);
    }
    setupSubmeshes();
}

void MeshRefiner::setupSubmeshes()
{
    int num_splits = (int)splits.size();
    int total_submeshes = 0;
    for (int spi = 0; spi < num_splits; ++spi) {
        auto& split = splits[spi];
        split.submesh_offset = total_submeshes;
        total_submeshes += split.submesh_count;
        for (int smi = 0; smi < split.submesh_count; ++smi) {
            auto& sm = submeshes[smi + split.submesh_offset];
            sm.split_index = spi;
            sm.submesh_index = smi;
        }
    }
}

void MeshRefiner::clear()
{
    split_unit = 0;
    counts.reset();
    indices.reset();
    points.reset();
    for (auto& attr : attributes) {
        attr->clear();
        // attributes are placement new-ed, so need to call destructor manually
        attr->~IAttribute();
    }
    attributes.clear();

    old2new_indices.clear();
    new2old_points.clear();

    new_indices.clear();
    new_indices_triangulated.clear();
    new_indices_submeshes.clear();

    new_points.clear();
    splits.clear();
    submeshes.clear();
    num_new_indices = 0;
}

void MeshRefiner::refine()
{
    if (connection.v2f_counts.size() != points.size()) {
        connection.buildConnection(indices, counts, points);
    }

    int num_indices = (int)indices.size();
    new_points.reserve(num_indices);
    new_indices.reserve(num_indices);
    for (auto& attr : attributes) { attr->prepare((int)points.size(), (int)indices.size()); }

    old2new_indices.resize(num_indices, -1);

    int num_faces_total = (int)counts.size();
    int offset_faces = 0;
    int offset_indices = 0;
    int offset_vertices = 0;
    int num_faces = 0;
    int num_indices_triangulated = 0;

    auto add_new_split = [&]() {
        auto split = Split{};
        split.face_offset = offset_faces;
        split.index_offset = offset_indices;
        split.vertex_offset = offset_vertices;
        split.face_count = num_faces;
        split.triangulated_index_count = num_indices_triangulated;
        split.vertex_count = (int)new_points.size() - offset_vertices;
        split.index_count = (int)new_indices.size() - offset_indices;
        splits.push_back(split);

        offset_faces += split.face_count;
        offset_indices += split.index_count;
        offset_vertices += split.vertex_count;

        num_new_indices += num_indices_triangulated;
        num_faces = 0;
        num_indices_triangulated = 0;
    };

    auto compare_all_attributes = [&](int ni, int ii) -> bool {
        for (auto& attr : attributes)
            if (!attr->compare(ni, ii)) { return false; }
        return true;
    };

    auto find_or_emit_vertex = [&](int vi, int ii) -> int {
        int offset = connection.v2f_offsets[vi];
        int connection_count = connection.v2f_counts[vi];
        for (int ci = 0; ci < connection_count; ++ci) {
            int& ni = old2new_indices[connection.v2f_indices[offset + ci]];
            if (ni != -1 && compare_all_attributes(ni, ii)) {
                return ni;
            }
            else {
                ni = (int)new_points.size();
                new_points.push_back(points[vi]);
                new2old_points.push_back(vi);
                for (auto& attr : attributes) { attr->emit(ii); }
                return ni;
            }
        }
        return 0;
    };

    int offset = 0;
    for (int fi = 0; fi < num_faces_total; ++fi) {
        int count = counts[fi];

        if (split_unit > 0 && (int)new_points.size() - offset_vertices + count > split_unit) {
            add_new_split();

            // clear vertex cache
            memset(old2new_indices.data(), -1, old2new_indices.size() * sizeof(int));
        }

        for (int ci = 0; ci < count; ++ci) {
            int ii = offset + ci;
            int vi = indices[ii];
            new_indices.push_back(find_or_emit_vertex(vi, ii));
        }
        ++num_faces;
        num_indices_triangulated += (count - 2) * 3;
        offset += count;
    }
    add_new_split();
}

<|endoftext|>


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

#include "globals.h"
#include "os/os.h"

Error AudioDriverAO::init() {

	active = false;
	thread_exited = false;
	exit_thread = false;
	pcm_open = false;
	samples_in = NULL;

	mix_rate = 44100;
	output_format = OUTPUT_STEREO;
	channels = 2;

	ao_sample_format format;

	format.bits = 16;
	format.rate = mix_rate;
	format.channels = channels;
	format.byte_format = AO_FMT_LITTLE;
	format.matrix = "L,R";

	device = ao_open_live(ao_default_driver_id(), &format, NULL);
	ERR_FAIL_COND_V(device == NULL, ERR_CANT_OPEN);

	int latency = GLOBAL_DEF("audio/output_latency", 25);
	buffer_size = nearest_power_of_2( latency * mix_rate / 1000 );

	samples_in = memnew_arr(int32_t, buffer_size * channels);

	mutex = Mutex::create();
	thread = Thread::create(AudioDriverAO::thread_func, this);

	return OK;
};

void AudioDriverAO::thread_func(void* p_udata) {
	AudioDriverAO* ad = (AudioDriverAO*)p_udata;

	int16_t* samples_out = ad->samples_in; // Overwrite samples on conversion
	unsigned int n_samples = ad->buffer_size * ad->channels;
	unsigned int n_bytes = n_samples * sizeof(int16_t);

	while (!ad->exit_thread) {
		if (ad->active) {
			ad->lock();
			ad->audio_server_process(ad->buffer_size, ad->samples_in);
			ad->unlock();

			for (unsigned int i = 0; i < n_samples; i++) {
				samples_out[i] = ad->samples_in[i] >> 16;
			}
		} else {
			memset(samples_out, 0, n_bytes);
		}

		if (ad->exit_thread)
			break;

		if (!ao_play(ad->device, reinterpret_cast<char*>(samples_out), n_bytes)) {
			ERR_PRINT("ao_play() failed");
		}
	};

	ad->thread_exited = true;
};

void AudioDriverAO::start() {
	active = true;
};

int AudioDriverAO::get_mix_rate() const {
	return mix_rate;
};

AudioDriverSW::OutputFormat AudioDriverAO::get_output_format() const {
	return output_format;
};

void AudioDriverAO::lock() {
	if (!thread || !mutex)
		return;
	mutex->lock();
};

void AudioDriverAO::unlock() {
	if (!thread || !mutex)
		return;
	mutex->unlock();
};

void AudioDriverAO::finish() {
	if (!thread)
		return;

	exit_thread = true;
	Thread::wait_to_finish(thread);

	if (samples_in) {
		memdelete_arr(samples_in);
	};

	memdelete(thread);
	if (mutex)
		memdelete(mutex);

	if (device)
		ao_close(device);

	thread = NULL;
};

AudioDriverAO::AudioDriverAO() {
	mutex = NULL;
	thread = NULL;

	ao_initialize();
};

AudioDriverAO::~AudioDriverAO() {
	ao_shutdown();
};
<commit_msg>Cast samples_in to samples_out with reinterpret_cast<int16_t*><commit_after>/*************************************************************************/
/*  audio_driver_ao.cpp                                                  */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                    http://www.godotengine.org                         */
/*************************************************************************/
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                 */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "audio_driver_ao.h"

#include "globals.h"
#include "os/os.h"

Error AudioDriverAO::init() {

	active = false;
	thread_exited = false;
	exit_thread = false;
	pcm_open = false;
	samples_in = NULL;

	mix_rate = 44100;
	output_format = OUTPUT_STEREO;
	channels = 2;

	ao_sample_format format;

	format.bits = 16;
	format.rate = mix_rate;
	format.channels = channels;
	format.byte_format = AO_FMT_LITTLE;
	format.matrix = "L,R";

	device = ao_open_live(ao_default_driver_id(), &format, NULL);
	ERR_FAIL_COND_V(device == NULL, ERR_CANT_OPEN);

	int latency = GLOBAL_DEF("audio/output_latency", 25);
	buffer_size = nearest_power_of_2( latency * mix_rate / 1000 );

	samples_in = memnew_arr(int32_t, buffer_size * channels);

	mutex = Mutex::create();
	thread = Thread::create(AudioDriverAO::thread_func, this);

	return OK;
};

void AudioDriverAO::thread_func(void* p_udata) {
	AudioDriverAO* ad = (AudioDriverAO*)p_udata;

	// Overwrite samples on conversion
	int16_t* samples_out = reinterpret_cast<int16_t*>(ad->samples_in);
	unsigned int n_samples = ad->buffer_size * ad->channels;
	unsigned int n_bytes = n_samples * sizeof(int16_t);

	while (!ad->exit_thread) {
		if (ad->active) {
			ad->lock();
			ad->audio_server_process(ad->buffer_size, ad->samples_in);
			ad->unlock();

			for (unsigned int i = 0; i < n_samples; i++) {
				samples_out[i] = ad->samples_in[i] >> 16;
			}
		} else {
			memset(samples_out, 0, n_bytes);
		}

		if (ad->exit_thread)
			break;

		if (!ao_play(ad->device, reinterpret_cast<char*>(samples_out), n_bytes)) {
			ERR_PRINT("ao_play() failed");
		}
	};

	ad->thread_exited = true;
};

void AudioDriverAO::start() {
	active = true;
};

int AudioDriverAO::get_mix_rate() const {
	return mix_rate;
};

AudioDriverSW::OutputFormat AudioDriverAO::get_output_format() const {
	return output_format;
};

void AudioDriverAO::lock() {
	if (!thread || !mutex)
		return;
	mutex->lock();
};

void AudioDriverAO::unlock() {
	if (!thread || !mutex)
		return;
	mutex->unlock();
};

void AudioDriverAO::finish() {
	if (!thread)
		return;

	exit_thread = true;
	Thread::wait_to_finish(thread);

	if (samples_in) {
		memdelete_arr(samples_in);
	};

	memdelete(thread);
	if (mutex)
		memdelete(mutex);

	if (device)
		ao_close(device);

	thread = NULL;
};

AudioDriverAO::AudioDriverAO() {
	mutex = NULL;
	thread = NULL;

	ao_initialize();
};

AudioDriverAO::~AudioDriverAO() {
	ao_shutdown();
};
<|endoftext|>


<commit_before>{
   //
   //This macro produces the flowchart of TFormula::Analyze
   //Author: Rene Brun

   gROOT->Reset();
   c1 = new TCanvas("c1","Analyze.mac",620,790);
   c1->Range(-1,0,19,30);
   TPaveLabel pl1(0,27,3.5,29,"Analyze");
   pl1.SetFillColor(42);
   pl1.Draw();
   TPaveText pt1(0,22.8,4,25.2);
   TText *t1=pt1.AddText("Parenthesis matching");
   TText *t2=pt1.AddText("Remove unnecessary");
   TText *t2a=pt1.AddText("parenthesis");
   pt1.Draw();
   TPaveText pt2(6,23,10,25);
   TText *t3=pt2.AddText("break of");
   TText *t4=pt2.AddText("Analyze");
   pt2.Draw();
   TPaveText pt3(0,19,4,21);
   TText *t4=pt3.AddText("look for simple");
   TText *t5=pt3.AddText("operators");
   pt3.Draw();
   TPaveText pt4(0,15,4,17);
   TText *t6=pt4.AddText("look for an already");
   TText *t7=pt4.AddText("defined expression");
   pt4.Draw();
   TPaveText pt5(0,11,4,13);
   TText *t8=pt5.AddText("look for usual");
   TText *t9=pt5.AddText("functions :cos sin ..");
   pt5.Draw();
   TPaveText pt6(0,7,4,9);
   TText *t10=pt6.AddText("look for a");
   TText *t11=pt6.AddText("numeric value");
   pt6.Draw();
   TPaveText pt7(6,18.5,10,21.5);
   TText *t12=pt7.AddText("Analyze left and");
   TText *t13=pt7.AddText("right part of");
   TText *t14=pt7.AddText("the expression");
   pt7.Draw();
   TPaveText pt8(6,15,10,17);
   TText *t15=pt8.AddText("Replace expression");
   pt8.Draw();
   TPaveText pt9(6,11,10,13);
   TText *t16=pt9.AddText("Analyze");
   pt9.SetFillColor(42);
   pt9.Draw();
   TPaveText pt10(6,7,10,9);
   TText *t17=pt10.AddText("Error");
   TText *t18=pt10.AddText("Break of Analyze");
   pt10.Draw();
   TPaveText pt11(14,22,17,24);
   pt11.SetFillColor(42);
   TText *t19=pt11.AddText("Analyze");
   TText *t19a=pt11.AddText("Left");
   pt11.Draw();
   TPaveText pt12(14,19,17,21);
   pt12.SetFillColor(42);
   TText *t20=pt12.AddText("Analyze");
   TText *t20a=pt12.AddText("Right");
   pt12.Draw();
   TPaveText pt13(14,15,18,18);
   TText *t21=pt13.AddText("StackNumber++");
   TText *t22=pt13.AddText("operator[StackNumber]");
   TText *t23=pt13.AddText("= operator found");
   pt13.Draw();
   TPaveText pt14(12,10.8,17,13.2);
   TText *t24=pt14.AddText("StackNumber++");
   TText *t25=pt14.AddText("operator[StackNumber]");
   TText *t26=pt14.AddText("= function found");
   pt14.Draw();
   TPaveText pt15(6,7,10,9);
   TText *t27=pt15.AddText("Error");
   TText *t28=pt15.AddText("break of Analyze");
   pt15.Draw();
   TPaveText pt16(0,2,7,5);
   TText *t29=pt16.AddText("StackNumber++");
   TText *t30=pt16.AddText("operator[StackNumber] = 0");
   TText *t31=pt16.AddText("value[StackNumber] = value found");
   pt16.Draw();
   TArrow ar(2,27,2,25.4,0.012,"|>");
   ar.SetFillColor(1);
   ar.Draw();
   ar.DrawArrow(2,22.8,2,21.2,0.012,"|>");
   ar.DrawArrow(2,19,2,17.2,0.012,"|>");
   ar.DrawArrow(2,15,2,13.2,0.012,"|>");
   ar.DrawArrow(2,11,2, 9.2,0.012,"|>");
   ar.DrawArrow(2, 7,2, 5.2,0.012,"|>");
   ar.DrawArrow(4,24,6,24,0.012,"|>");
   ar.DrawArrow(4,20,6,20,0.012,"|>");
   ar.DrawArrow(4,16,6,16,0.012,"|>");
   ar.DrawArrow(4,12,6,12,0.012,"|>");
   ar.DrawArrow(4, 8,6, 8,0.012,"|>");
   ar.DrawArrow(10,20,14,20,0.012,"|>");
   ar.DrawArrow(12,23,14,23,0.012,"|>");
   ar.DrawArrow(12,16.5,14,16.5,0.012,"|>");
   ar.DrawArrow(10,12,12,12,0.012,"|>");
   TText ta(2.2,22.2,"err = 0");
   ta.SetTextFont(71);
   ta.SetTextSize(0.015);
   ta.SetTextColor(4);
   ta.SetTextAlign(12);
   ta.Draw();
   ta.DrawText(2.2,18.2,"not found");
   ta.DrawText(2.2,6.2,"found");
   TText tb(4.2,24.1,"err != 0");
   tb.SetTextFont(71);
   tb.SetTextSize(0.015);
   tb.SetTextColor(4);
   tb.SetTextAlign(11);
   tb.Draw();
   tb.DrawText(4.2,20.1,"found");
   tb.DrawText(4.2,16.1,"found");
   tb.DrawText(4.2,12.1,"found");
   tb.DrawText(4.2, 8.1,"not found");
   TLine l1(12,16.5,12,23);
   l1.Draw();
}
<commit_msg>Fix a redefinition.<commit_after>{
   //
   //This macro produces the flowchart of TFormula::Analyze
   //Author: Rene Brun

   gROOT->Reset();
   c1 = new TCanvas("c1","Analyze.mac",620,790);
   c1->Range(-1,0,19,30);
   TPaveLabel pl1(0,27,3.5,29,"Analyze");
   pl1.SetFillColor(42);
   pl1.Draw();
   TPaveText pt1(0,22.8,4,25.2);
   TText *t1=pt1.AddText("Parenthesis matching");
   TText *t2=pt1.AddText("Remove unnecessary");
   TText *t2a=pt1.AddText("parenthesis");
   pt1.Draw();
   TPaveText pt2(6,23,10,25);
   TText *t3=pt2.AddText("break of");
   TText *t4=pt2.AddText("Analyze");
   pt2.Draw();
   TPaveText pt3(0,19,4,21);
   t4=pt3.AddText("look for simple");
   TText *t5=pt3.AddText("operators");
   pt3.Draw();
   TPaveText pt4(0,15,4,17);
   TText *t6=pt4.AddText("look for an already");
   TText *t7=pt4.AddText("defined expression");
   pt4.Draw();
   TPaveText pt5(0,11,4,13);
   TText *t8=pt5.AddText("look for usual");
   TText *t9=pt5.AddText("functions :cos sin ..");
   pt5.Draw();
   TPaveText pt6(0,7,4,9);
   TText *t10=pt6.AddText("look for a");
   TText *t11=pt6.AddText("numeric value");
   pt6.Draw();
   TPaveText pt7(6,18.5,10,21.5);
   TText *t12=pt7.AddText("Analyze left and");
   TText *t13=pt7.AddText("right part of");
   TText *t14=pt7.AddText("the expression");
   pt7.Draw();
   TPaveText pt8(6,15,10,17);
   TText *t15=pt8.AddText("Replace expression");
   pt8.Draw();
   TPaveText pt9(6,11,10,13);
   TText *t16=pt9.AddText("Analyze");
   pt9.SetFillColor(42);
   pt9.Draw();
   TPaveText pt10(6,7,10,9);
   TText *t17=pt10.AddText("Error");
   TText *t18=pt10.AddText("Break of Analyze");
   pt10.Draw();
   TPaveText pt11(14,22,17,24);
   pt11.SetFillColor(42);
   TText *t19=pt11.AddText("Analyze");
   TText *t19a=pt11.AddText("Left");
   pt11.Draw();
   TPaveText pt12(14,19,17,21);
   pt12.SetFillColor(42);
   TText *t20=pt12.AddText("Analyze");
   TText *t20a=pt12.AddText("Right");
   pt12.Draw();
   TPaveText pt13(14,15,18,18);
   TText *t21=pt13.AddText("StackNumber++");
   TText *t22=pt13.AddText("operator[StackNumber]");
   TText *t23=pt13.AddText("= operator found");
   pt13.Draw();
   TPaveText pt14(12,10.8,17,13.2);
   TText *t24=pt14.AddText("StackNumber++");
   TText *t25=pt14.AddText("operator[StackNumber]");
   TText *t26=pt14.AddText("= function found");
   pt14.Draw();
   TPaveText pt15(6,7,10,9);
   TText *t27=pt15.AddText("Error");
   TText *t28=pt15.AddText("break of Analyze");
   pt15.Draw();
   TPaveText pt16(0,2,7,5);
   TText *t29=pt16.AddText("StackNumber++");
   TText *t30=pt16.AddText("operator[StackNumber] = 0");
   TText *t31=pt16.AddText("value[StackNumber] = value found");
   pt16.Draw();
   TArrow ar(2,27,2,25.4,0.012,"|>");
   ar.SetFillColor(1);
   ar.Draw();
   ar.DrawArrow(2,22.8,2,21.2,0.012,"|>");
   ar.DrawArrow(2,19,2,17.2,0.012,"|>");
   ar.DrawArrow(2,15,2,13.2,0.012,"|>");
   ar.DrawArrow(2,11,2, 9.2,0.012,"|>");
   ar.DrawArrow(2, 7,2, 5.2,0.012,"|>");
   ar.DrawArrow(4,24,6,24,0.012,"|>");
   ar.DrawArrow(4,20,6,20,0.012,"|>");
   ar.DrawArrow(4,16,6,16,0.012,"|>");
   ar.DrawArrow(4,12,6,12,0.012,"|>");
   ar.DrawArrow(4, 8,6, 8,0.012,"|>");
   ar.DrawArrow(10,20,14,20,0.012,"|>");
   ar.DrawArrow(12,23,14,23,0.012,"|>");
   ar.DrawArrow(12,16.5,14,16.5,0.012,"|>");
   ar.DrawArrow(10,12,12,12,0.012,"|>");
   TText ta(2.2,22.2,"err = 0");
   ta.SetTextFont(71);
   ta.SetTextSize(0.015);
   ta.SetTextColor(4);
   ta.SetTextAlign(12);
   ta.Draw();
   ta.DrawText(2.2,18.2,"not found");
   ta.DrawText(2.2,6.2,"found");
   TText tb(4.2,24.1,"err != 0");
   tb.SetTextFont(71);
   tb.SetTextSize(0.015);
   tb.SetTextColor(4);
   tb.SetTextAlign(11);
   tb.Draw();
   tb.DrawText(4.2,20.1,"found");
   tb.DrawText(4.2,16.1,"found");
   tb.DrawText(4.2,12.1,"found");
   tb.DrawText(4.2, 8.1,"not found");
   TLine l1(12,16.5,12,23);
   l1.Draw();
}
<|endoftext|>


<commit_before>/// \file
/// \ingroup tutorial_math
/// Demo for quantiles (with highlight mode)
///
/// \macro_image
/// \macro_code
///
/// \authors Rene Brun, Eddy Offermann

TList *lq = 0;
TGraph *gr = 0;

void hlquantiles() {
   const Int_t nq = 100;
   const Int_t nshots = 10;
   Double_t xq[nq];  // position where to compute the quantiles in [0,1]
   Double_t yq[nq];  // array to contain the quantiles
   for (Int_t i=0;i<nq;i++) xq[i] = Float_t(i+1)/nq;

   TGraph *gr70 = new TGraph(nshots);
   TGraph *gr90 = new TGraph(nshots);
   TGraph *gr98 = new TGraph(nshots);
   TGraph *grq[nq];
   for (Int_t ig = 0; ig < nq; ig++) grq[ig] = new TGraph(nshots);
   TH1F *h = new TH1F("h","demo quantiles",50,-3,3);

   for (Int_t shot=0;shot<nshots;shot++) {
      h->FillRandom("gaus",50);
      h->GetQuantiles(nq,yq,xq);
      gr70->SetPoint(shot,shot+1,yq[70]);
      gr90->SetPoint(shot,shot+1,yq[90]);
      gr98->SetPoint(shot,shot+1,yq[98]);
      for (Int_t ig = 0; ig < nq; ig++)
         grq[ig]->SetPoint(shot,shot+1,yq[ig]);
   }

   //show the original histogram in the top pad
   TCanvas *c1 = new TCanvas("c1","demo quantiles",10,10,600,900);
   c1->SetFillColor(41);
   c1->Divide(1,3);
   c1->cd(1);
   h->SetFillColor(38);
   h->Draw();

   // show the final quantiles in the middle pad
   c1->cd(2);
   gPad->SetFrameFillColor(33);
   gPad->SetGrid();
   gr = new TGraph(nq,xq,yq);
   gr->SetTitle("final quantiles");
   gr->SetMarkerStyle(21);
   gr->SetMarkerColor(kRed);
   gr->SetMarkerSize(0.3);
   gr->Draw("ap");

   // prepare quantiles
   lq = new TList();
   for (Int_t ig = 0; ig < nq; ig++) {
      grq[ig]->SetMinimum(gr->GetYaxis()->GetXmin());
      grq[ig]->SetMaximum(gr->GetYaxis()->GetXmax());
      grq[ig]->SetMarkerStyle(23);
      grq[ig]->SetMarkerColor(ig%100);
      grq[ig]->SetTitle(TString::Format("q%02d", ig));
      lq->Add(grq[ig]);
   }

   TText *info = new TText(0.1, 2.4, "please move the mouse over the graph");
   info->SetTextSize(0.08);
   info->SetTextColor(gr->GetMarkerColor());
   info->SetBit(kCannotPick);
   info->Draw();

   gr->SetHighlight();
   c1->HighlightConnect("HighlightQuantile(TVirtualPad*,TObject*,Int_t,Int_t)");

   // show the evolution of some  quantiles in the bottom pad
   c1->cd(3);
   gPad->SetFrameFillColor(17);
   gPad->DrawFrame(0,0,nshots+1,3.2);
   gPad->SetGrid();
   gr98->SetMarkerStyle(22);
   gr98->SetMarkerColor(kRed);
   gr98->Draw("lp");
   gr90->SetMarkerStyle(21);
   gr90->SetMarkerColor(kBlue);
   gr90->Draw("lp");
   gr70->SetMarkerStyle(20);
   gr70->SetMarkerColor(kMagenta);
   gr70->Draw("lp");
   // add a legend
   TLegend *legend = new TLegend(0.85,0.74,0.95,0.95);
   legend->SetTextFont(72);
   legend->SetTextSize(0.05);
   legend->AddEntry(gr98," q98","lp");
   legend->AddEntry(gr90," q90","lp");
   legend->AddEntry(gr70," q70","lp");
   legend->Draw();
}

void HighlightQuantile(TVirtualPad *pad, TObject *obj, Int_t ihp, Int_t y)
{
   // show the evolution of all quantiles in the bottom pad
   if (obj != gr) return;
   if (ihp == -1) return;

   TVirtualPad *savepad = gPad;
   pad->GetCanvas()->cd(3);
   lq->At(ihp)->Draw("alp");
   gPad->Update();
   savepad->cd();
}
<commit_msg>Change authors<commit_after>/// \file
/// \ingroup tutorial_math
/// Demo for quantiles (with highlight mode)
///
/// \macro_image
/// \macro_code
///
/// \authors Rene Brun, Eddy Offermann, Jan Musinsky

TList *lq = 0;
TGraph *gr = 0;

void hlquantiles() {
   const Int_t nq = 100;
   const Int_t nshots = 10;
   Double_t xq[nq];  // position where to compute the quantiles in [0,1]
   Double_t yq[nq];  // array to contain the quantiles
   for (Int_t i=0;i<nq;i++) xq[i] = Float_t(i+1)/nq;

   TGraph *gr70 = new TGraph(nshots);
   TGraph *gr90 = new TGraph(nshots);
   TGraph *gr98 = new TGraph(nshots);
   TGraph *grq[nq];
   for (Int_t ig = 0; ig < nq; ig++) grq[ig] = new TGraph(nshots);
   TH1F *h = new TH1F("h","demo quantiles",50,-3,3);

   for (Int_t shot=0;shot<nshots;shot++) {
      h->FillRandom("gaus",50);
      h->GetQuantiles(nq,yq,xq);
      gr70->SetPoint(shot,shot+1,yq[70]);
      gr90->SetPoint(shot,shot+1,yq[90]);
      gr98->SetPoint(shot,shot+1,yq[98]);
      for (Int_t ig = 0; ig < nq; ig++)
         grq[ig]->SetPoint(shot,shot+1,yq[ig]);
   }

   //show the original histogram in the top pad
   TCanvas *c1 = new TCanvas("c1","demo quantiles",10,10,600,900);
   c1->SetFillColor(41);
   c1->Divide(1,3);
   c1->cd(1);
   h->SetFillColor(38);
   h->Draw();

   // show the final quantiles in the middle pad
   c1->cd(2);
   gPad->SetFrameFillColor(33);
   gPad->SetGrid();
   gr = new TGraph(nq,xq,yq);
   gr->SetTitle("final quantiles");
   gr->SetMarkerStyle(21);
   gr->SetMarkerColor(kRed);
   gr->SetMarkerSize(0.3);
   gr->Draw("ap");

   // prepare quantiles
   lq = new TList();
   for (Int_t ig = 0; ig < nq; ig++) {
      grq[ig]->SetMinimum(gr->GetYaxis()->GetXmin());
      grq[ig]->SetMaximum(gr->GetYaxis()->GetXmax());
      grq[ig]->SetMarkerStyle(23);
      grq[ig]->SetMarkerColor(ig%100);
      grq[ig]->SetTitle(TString::Format("q%02d", ig));
      lq->Add(grq[ig]);
   }

   TText *info = new TText(0.1, 2.4, "please move the mouse over the graph");
   info->SetTextSize(0.08);
   info->SetTextColor(gr->GetMarkerColor());
   info->SetBit(kCannotPick);
   info->Draw();

   gr->SetHighlight();
   c1->HighlightConnect("HighlightQuantile(TVirtualPad*,TObject*,Int_t,Int_t)");

   // show the evolution of some  quantiles in the bottom pad
   c1->cd(3);
   gPad->SetFrameFillColor(17);
   gPad->DrawFrame(0,0,nshots+1,3.2);
   gPad->SetGrid();
   gr98->SetMarkerStyle(22);
   gr98->SetMarkerColor(kRed);
   gr98->Draw("lp");
   gr90->SetMarkerStyle(21);
   gr90->SetMarkerColor(kBlue);
   gr90->Draw("lp");
   gr70->SetMarkerStyle(20);
   gr70->SetMarkerColor(kMagenta);
   gr70->Draw("lp");
   // add a legend
   TLegend *legend = new TLegend(0.85,0.74,0.95,0.95);
   legend->SetTextFont(72);
   legend->SetTextSize(0.05);
   legend->AddEntry(gr98," q98","lp");
   legend->AddEntry(gr90," q90","lp");
   legend->AddEntry(gr70," q70","lp");
   legend->Draw();
}

void HighlightQuantile(TVirtualPad *pad, TObject *obj, Int_t ihp, Int_t y)
{
   // show the evolution of all quantiles in the bottom pad
   if (obj != gr) return;
   if (ihp == -1) return;

   TVirtualPad *savepad = gPad;
   pad->GetCanvas()->cd(3);
   lq->At(ihp)->Draw("alp");
   gPad->Update();
   savepad->cd();
}
<|endoftext|>


<commit_before>#include "updaterbody.hpp"
#include "usbshell.hpp"

using namespace Updater;
using namespace UpdaterAPI;

UpdaterBody *GetBody(bool flag, UPDATER_ACTION_MODE mode, firmware_information_t::information *info)
{
    return new UpdaterBodyImpl;
}

void ReleaseBody(UpdaterBody *body)
{
    delete body;
}

bool UpdaterBodyImpl::Execute(RingBuffer *buffer, CallbackInterface *interface)
{
    usbshell_loop();
    return true;
}
<commit_msg>UpdaterBody: Catch exceptions<commit_after>#include "updaterbody.hpp"
#include "usbshell.hpp"

using namespace Updater;
using namespace UpdaterAPI;

UpdaterBody *GetBody(bool flag, UPDATER_ACTION_MODE mode, firmware_information_t::information *info)
{
    return new UpdaterBodyImpl;
}

void ReleaseBody(UpdaterBody *body)
{
    delete body;
}

bool UpdaterBodyImpl::Execute(RingBuffer *buffer, CallbackInterface *interface)
{
    try {
        usbshell_loop();
    } catch (...) {
        // ignore
    }

    return true;
}
<|endoftext|>


<commit_before>#include <fstream>
#include <cstring>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include "detectJumps.h"
#include "utils.h"

using namespace std;

uint64_t transformRegionInReadToHash(regionInRead region){
	hash<int> regionHash;
	return regionHash(region.read + region.firstWindow + region.lastWindow);
}

void detectJumps(const vector<pairOfIndexWindow>& vec, uint indexReadT, uint indexReadQ, unordered_map <regionInRead, vector<regionInRead>>& correspondance){
	uint indexT(0);
	uint indexQ(0);
	for (uint i(0); i<vec.size(); ++i){
		//~ cout << vec[i].target << " " << vec[i].query << endl;
		regionInRead regionTarget({indexT, vec[i].target, indexReadT});
		if (i != vec.size()-1 and absolute(int(vec[i].target)-int(vec[i+1].target))>2){
			cout << "jump" << endl;
			//~ if (correspondance.count(regionTarget)){
				//~ correspondance[regionTarget].push_back({indexQ, vec[i].query, indexReadQ});
			//~ } else {
				//~ regionInRead r({indexQ, vec[i].query, indexReadQ});
				//~ vector <regionInRead> v;
				//~ v.push_back(r);
				//~ correspondance[regionTarget] = v;
			//~ }
			//~ cout << "jump in target" << indexT << "to" << vec[i+1].target << endl;
			indexT = vec[i+1].target;
			indexQ = vec[i+1].query;
		} else if (i != vec.size()-1 and absolute(int(vec[i].query)-int(vec[i+1].query))>2){
			cout << "jump" << endl;
			//~ if (correspondance.count(regionTarget)){
				//~ correspondance[regionTarget].push_back({indexQ, vec[i].query, indexReadQ});
			//~ } else {
				//~ regionInRead r({indexQ, vec[i].query, indexReadQ});
				//~ vector <regionInRead> v;
				//~ v.push_back(r);
				//~ correspondance[regionTarget] = v;
			//~ }
			//~ cout << "jump in query" << indexQ <<  "to" << vec[i+1].query <<  endl;
			indexT = vec[i+1].target;
			indexQ = vec[i+1].query;
		}
	}
	if (indexT==0){
		cout << "no jump" << endl;
		//~ regionInRead regionTarget({vec[0].target, vec.back().target, indexReadT});
		//~ if (correspondance.count(regionTarget)){
				//~ correspondance[regionTarget].push_back({vec[0].query, vec.back().query, indexReadQ});
		//~ } else {
				//~ regionInRead r({vec[0].query, vec.back().query, indexReadQ});
				//~ vector <regionInRead> v;
				//~ v.push_back(r);
				//~ correspondance[regionTarget] = v;
		//~ }
	}
}
<commit_msg>first simple jump detection<commit_after>#include <fstream>
#include <cstring>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include "detectJumps.h"
#include "utils.h"

using namespace std;

uint64_t transformRegionInReadToHash(regionInRead region){
	hash<int> regionHash;
	return regionHash(region.read + region.firstWindow + region.lastWindow);
}

void detectJumps(const vector<pairOfIndexWindow>& vec, uint indexReadT, uint indexReadQ, unordered_map <regionInRead, vector<regionInRead>>& correspondance){
	uint indexT(0);
	uint indexQ(0);
	for (uint i(0); i<vec.size(); ++i){
		//~ cout << vec[i].target << " " << vec[i].query << endl;
		regionInRead regionTarget({indexT, vec[i].target, indexReadT});
		if (i != vec.size()-1 and absolute(int(vec[i].target)-int(vec[i+1].target))>2){
			//~ cout << "jump" << endl;
			//~ if (correspondance.count(regionTarget)){
				//~ correspondance[regionTarget].push_back({indexQ, vec[i].query, indexReadQ});
			//~ } else {
				//~ regionInRead r({indexQ, vec[i].query, indexReadQ});
				//~ vector <regionInRead> v;
				//~ v.push_back(r);
				//~ correspondance[regionTarget] = v;
			//~ }
			cout << "jump in target" << indexT << "to" << vec[i+1].target << endl;
			indexT = vec[i+1].target;
			indexQ = vec[i+1].query;
		} else if (i != vec.size()-1 and absolute(int(vec[i].query)-int(vec[i+1].query))>2){
			//~ cout << "jump" << endl;
			//~ if (correspondance.count(regionTarget)){
				//~ correspondance[regionTarget].push_back({indexQ, vec[i].query, indexReadQ});
			//~ } else {
				//~ regionInRead r({indexQ, vec[i].query, indexReadQ});
				//~ vector <regionInRead> v;
				//~ v.push_back(r);
				//~ correspondance[regionTarget] = v;
			//~ }
			cout << "jump in query" << indexQ <<  "to" << vec[i+1].query <<  endl;
			indexT = vec[i+1].target;
			indexQ = vec[i+1].query;
		}
	}
	if (indexT==0){
		cout << "no jump" << endl;
		//~ regionInRead regionTarget({vec[0].target, vec.back().target, indexReadT});
		//~ if (correspondance.count(regionTarget)){
				//~ correspondance[regionTarget].push_back({vec[0].query, vec.back().query, indexReadQ});
		//~ } else {
				//~ regionInRead r({vec[0].query, vec.back().query, indexReadQ});
				//~ vector <regionInRead> v;
				//~ v.push_back(r);
				//~ correspondance[regionTarget] = v;
		//~ }
	}
}
<|endoftext|>


<commit_before>#include "combat/combat.h"

#include "random.h"
#include "logconsole.h"
#include "dataconsts.h"
#include "entity_system.h"

#include "srv_attack.h"
#include "srv_damage.h"
#include "srv_hp_reply.h"

#include "components/basic_info.h"
#include "components/destination.h"
#include "components/life.h"
#include "components/magic.h"
#include "components/player_spawn.h"
#include "components/position.h"
#include "components/target.h"
#include "components/damage.h"
#include "components/skills.h"
#include "components/stamina.h"
#include "components/stats.h"

#include <cmath>

using namespace RoseCommon;
using namespace RoseCommon::Packet;

void Combat::hp_request(EntitySystem& entitySystem, Entity entity, const CliHpReq& packet) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  if (packet.get_targetId()) {
    Entity t = entitySystem.get_entity_from_id(packet.get_targetId());
    if (t != entt::null) {
      const auto& life = entitySystem.get_component<Component::Life>(t);

      auto p = SrvHpReply::create(packet.get_targetId(), life.hp);
      entitySystem.send_to(entity, p);
    }
  }
}

std::pair<float, float> Combat::get_range_position(const EntitySystem& entitySystem, Entity character, Entity target, float range) {
  const auto& char_pos = entitySystem.get_component<Component::Position>(character);
  const auto& target_pos = entitySystem.get_component<Component::Position>(target);
  std::pair<float, float> vector{char_pos.x - target_pos.x, char_pos.y - target_pos.y};
  const float length = sqrt(vector.first * vector.first + vector.second * vector.second);
  vector.first /= length;
  vector.second /= length;
  return {vector.first * range, vector.second * range};
}

float Combat::get_range_to(const EntitySystem& entitySystem, Entity character, Entity target) {
  const auto& char_pos = entitySystem.get_component<Component::Position>(character);
  const auto& target_pos = entitySystem.get_component<Component::Position>(target);

  const float dx = char_pos.x - target_pos.x;
  const float dy = char_pos.y - target_pos.y;

  return std::sqrt(dx * dx + dy * dy);
}

void Combat::attack(EntitySystem& entitySystem, Entity entity, const CliAttack& packet) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::attack");
  logger->trace("entity {}, target {}", entity, packet.get_targetId());

  const auto& basicInfo = entitySystem.get_component<Component::BasicInfo>(entity);
  const auto& pos = entitySystem.get_component<Component::Position>(entity);
  const auto& stats = entitySystem.get_component<Component::Stats>(entity);

  if (packet.get_targetId()) {
    Entity t = entitySystem.get_entity_from_id(packet.get_targetId());
    if (t != entt::null) {
      auto& target = entitySystem.add_or_replace_component<Component::Target>(entity);
      target.target = t;

      //TODO: Check distance to target, if not in attack range, move into max attack range
      if(get_range_to(entitySystem, entity, t) > 1)
      {
        auto& dest = entitySystem.add_or_replace_component<Component::Destination>(entity);
        auto npos = get_range_position(entitySystem, entity, t);
        dest.x = npos.first;
        dest.y = npos.second;
        dest.z = 0;

        const float dx = pos.x - dest.x;
        const float dy = pos.y - dest.y;
        dest.dist = std::sqrt(dx * dx + dy * dy);
      }

      // This packet acts as an attack and mouse_cmd all in one, we don't want the mouse_cmd portion
      // of it as it can cause some issues with attack animations going off before it should
      // auto p = SrvAttack::create(basicInfo.id, packet.get_targetId());
      // p.set_x(dest.x);
      // p.set_y(dest.y);
      // p.set_distance(dest.dist);
      // entitySystem.send_nearby(entity, p);
    }
  }
}

void Combat::update(EntitySystem& entitySystem, Entity entity) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  const auto& basicInfo = entitySystem.get_component<Component::BasicInfo>(entity);
  const auto& pos = entitySystem.get_component<Component::Position>(entity);
  auto& life = entitySystem.get_component<Component::Life>(entity);

  //TODO:: Update buffs
  //TODO:: Update HP

  if(entitySystem.has_component<Component::Damage>(entity) == true)
  {
    auto& queuedDamage = entitySystem.get_component<Component::Damage>(entity);
    int32_t adjusted_hp = life.hp;
    uint32_t total_applied_damage = 0;

    for(auto attack : queuedDamage.damage_)
    {
      if(attack.apply_) {
        // We waited at least one update before applying damage, apply it now
        //TODO:: Apply damage to this entity
        Entity attacker = entitySystem.get_entity_from_id(attack.attacker_);
        logger->debug("Applying damage to entity {} {}", basicInfo.name, basicInfo.id);

        if((adjusted_hp - attack.value_) <= 0) {
          logger->debug("Entity {} {} will die from {} damage", basicInfo.name, basicInfo.id, attack.value_);
          total_applied_damage = attack.value_ + adjusted_hp;
          adjusted_hp = 0;
          //TODO: Credit this attacker as the one who killed this entity.
        } else {
          total_applied_damage += attack.value_;
          adjusted_hp -= attack.value_;
        }

        if(adjusted_hp <= 0) {
          //TODO: Get dropped item data here and send it with the DAMAGE packet
          attack.action_ &= ~DAMAGE_ACTION_HIT;
          attack.action_ |= DAMAGE_ACTION_DEAD;
          auto p = SrvDamage::create(attack.attacker_, basicInfo.id, attack.value_ + 30000, attack.action_);
          entitySystem.send_nearby(entity, p);

          // remove components that we can't have if we are dead!
          entitySystem.remove_component<Component::Damage>(entity);
          entitySystem.remove_component<Component::Destination>(entity);
          entitySystem.remove_component<Component::Target>(entity);
        } else {
          logger->debug("applied {} damage to entity {} {}.", attack.value_, basicInfo.name, basicInfo.id);

          auto p = SrvDamage::create(attack.attacker_, basicInfo.id, attack.value_, attack.action_);
          entitySystem.send_to(entity, p);
          entitySystem.send_to(attacker, p);
        }

        // Reset the damage value to 0 for next pass
        attack.value_ = 0;
      } else {
        // Apply any new damage on next update
        attack.apply_ = true;
      }
    }
  }

  // Check to see if we have a target component
  if(entitySystem.has_component<Component::Target>(entity) == true)
  {
    auto& target = entitySystem.get_component<Component::Target>(entity);
    // Are we in attack range?
    //TODO:: Update apply damage to target
  }
}

RoseCommon::Entity Combat::get_closest_spawn(EntitySystem& entitySystem, RoseCommon::Entity player) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::get_closest_spawn start");
  const auto& position = entitySystem.get_component<Component::Position>(player);

  RoseCommon::Entity closest = {};
  float closestDist = 999999999999;

  for (RoseCommon::Entity entity : entitySystem.get_entities_with_components<Component::BasicInfo, Component::Position, Component::PlayerSpawn>()) {
    const auto& spawnPosition = entitySystem.get_component<Component::Position>(entity);

    if(spawnPosition.map != position.map) continue;

    float dx = spawnPosition.x - position.x;
    float dy = spawnPosition.y - position.y;
    float distance = std::sqrt(dx * dx + dy * dy);

    if(distance < closestDist) {
      closest = entity;
      closestDist = distance;
    }
  }
  logger->trace("Combat::get_closest_spawn end");
  return closest;
}

RoseCommon::Entity Combat::get_saved_spawn(EntitySystem& entitySystem, RoseCommon::Entity player) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::get_saved_spawn start");
  const auto& position = entitySystem.get_component<Component::Position>(player);

  for (RoseCommon::Entity entity : entitySystem.get_entities_with_components<Component::BasicInfo, Component::Position, Component::PlayerSpawn>()) {
    const auto& spawninfo = entitySystem.get_component<Component::PlayerSpawn>(entity);
    if(spawninfo.type == Component::PlayerSpawn::RESPAWN_POINT) {
      const auto& spawnPosition = entitySystem.get_component<Component::Position>(entity);

      if(spawnPosition.map == position.spawn)
        return entity;
    }
  }

  logger->trace("Combat::get_saved_spawn unable to find the saved spawn point");
  return {};
}

RoseCommon::Entity Combat::get_start_spawn(EntitySystem& entitySystem) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::get_start_spawn start");
  for (RoseCommon::Entity entity : entitySystem.get_entities_with_components<Component::BasicInfo, Component::Position, Component::PlayerSpawn>()) {
    const auto& spawninfo = entitySystem.get_component<Component::PlayerSpawn>(entity);

    if(spawninfo.type == Component::PlayerSpawn::START_POINT)
      return entity;
  }

  return {};
}

void Combat::revive(EntitySystem& entitySystem, Entity entity, const RoseCommon::Packet::CliReviveReq& packet) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::revive");

  const auto& basicInfo = entitySystem.get_component<Component::BasicInfo>(entity);
  const auto& pos = entitySystem.get_component<Component::Position>(entity);
  auto& life = entitySystem.get_component<Component::Life>(entity);
  auto& magic = entitySystem.get_component<Component::Magic>(entity);

  uint16_t map_id = pos.map;
  float x = 0.f, y = 0.f;

  switch(packet.get_reviveType())
  {
    case CliReviveReq::ReviveRequest::REVIVE_POSITION:
    {
      if (Entity e = get_closest_spawn(entitySystem, entity); e) {
        auto& dest = entitySystem.get_component<Component::Position>(e);
        x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
        y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
      }
      break;
    }
    case CliReviveReq::ReviveRequest::SAVE_POSITION:
    {
      if (Entity e = get_saved_spawn(entitySystem, entity); e) {
        auto& dest = entitySystem.get_component<Component::Position>(e);

        if(dest.map == 20 && basicInfo.job) {
          if (Entity e = get_closest_spawn(entitySystem, entity); e) {
            auto& dest = entitySystem.get_component<Component::Position>(e);
            x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
            y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
          }
          break;
        }

        if(pos.map != dest.map) {
          map_id = dest.map;
        }
        x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
        y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
      }
      break;
    }
    case CliReviveReq::ReviveRequest::START_POSITION:
    {
      if (Entity e = get_start_spawn(entitySystem); e) {
        auto& dest = entitySystem.get_component<Component::Position>(e);
        x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
        y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
      }
      break;
    }
    case CliReviveReq::ReviveRequest::CURRENT_POSITION:
    {
      x = pos.x;
      y = pos.y;
      break;
    }
    default:
    {
        logger->warn("Combat::revive player {} sent a revive type that doesn't exist...", basicInfo.name);
      break;
    }
  }

  life.hp = (life.maxHp * 0.3f);
  magic.mp = 0;

  entitySystem.teleport_entity(entity, x, y, map_id);
}<commit_msg>Cleanup queued damage that has been applied already<commit_after>#include <algorithm>
#include "combat/combat.h"

#include "random.h"
#include "logconsole.h"
#include "dataconsts.h"
#include "entity_system.h"

#include "srv_attack.h"
#include "srv_damage.h"
#include "srv_hp_reply.h"

#include "components/basic_info.h"
#include "components/destination.h"
#include "components/life.h"
#include "components/magic.h"
#include "components/player_spawn.h"
#include "components/position.h"
#include "components/target.h"
#include "components/damage.h"
#include "components/skills.h"
#include "components/stamina.h"
#include "components/stats.h"

#include <cmath>

using namespace RoseCommon;
using namespace RoseCommon::Packet;

void Combat::hp_request(EntitySystem& entitySystem, Entity entity, const CliHpReq& packet) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  if (packet.get_targetId()) {
    Entity t = entitySystem.get_entity_from_id(packet.get_targetId());
    if (t != entt::null) {
      const auto& life = entitySystem.get_component<Component::Life>(t);

      auto p = SrvHpReply::create(packet.get_targetId(), life.hp);
      entitySystem.send_to(entity, p);
    }
  }
}

std::pair<float, float> Combat::get_range_position(const EntitySystem& entitySystem, Entity character, Entity target, float range) {
  const auto& char_pos = entitySystem.get_component<Component::Position>(character);
  const auto& target_pos = entitySystem.get_component<Component::Position>(target);
  std::pair<float, float> vector{char_pos.x - target_pos.x, char_pos.y - target_pos.y};
  const float length = sqrt(vector.first * vector.first + vector.second * vector.second);
  vector.first /= length;
  vector.second /= length;
  return {vector.first * range, vector.second * range};
}

float Combat::get_range_to(const EntitySystem& entitySystem, Entity character, Entity target) {
  const auto& char_pos = entitySystem.get_component<Component::Position>(character);
  const auto& target_pos = entitySystem.get_component<Component::Position>(target);

  const float dx = char_pos.x - target_pos.x;
  const float dy = char_pos.y - target_pos.y;

  return std::sqrt(dx * dx + dy * dy);
}

void Combat::attack(EntitySystem& entitySystem, Entity entity, const CliAttack& packet) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::attack");
  logger->trace("entity {}, target {}", entity, packet.get_targetId());

  const auto& basicInfo = entitySystem.get_component<Component::BasicInfo>(entity);
  const auto& pos = entitySystem.get_component<Component::Position>(entity);
  const auto& stats = entitySystem.get_component<Component::Stats>(entity);

  if (packet.get_targetId()) {
    Entity t = entitySystem.get_entity_from_id(packet.get_targetId());
    if (t != entt::null) {
      auto& target = entitySystem.add_or_replace_component<Component::Target>(entity);
      target.target = t;

      //TODO: Check distance to target, if not in attack range, move into max attack range
      if(get_range_to(entitySystem, entity, t) > 1)
      {
        auto& dest = entitySystem.add_or_replace_component<Component::Destination>(entity);
        auto npos = get_range_position(entitySystem, entity, t);
        dest.x = npos.first;
        dest.y = npos.second;
        dest.z = 0;

        const float dx = pos.x - dest.x;
        const float dy = pos.y - dest.y;
        dest.dist = std::sqrt(dx * dx + dy * dy);
      }

      // This packet acts as an attack and mouse_cmd all in one, we don't want the mouse_cmd portion
      // of it as it can cause some issues with attack animations going off before it should
      // auto p = SrvAttack::create(basicInfo.id, packet.get_targetId());
      // p.set_x(dest.x);
      // p.set_y(dest.y);
      // p.set_distance(dest.dist);
      // entitySystem.send_nearby(entity, p);
    }
  }
}

void Combat::update(EntitySystem& entitySystem, Entity entity) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  const auto& basicInfo = entitySystem.get_component<Component::BasicInfo>(entity);
  const auto& pos = entitySystem.get_component<Component::Position>(entity);
  auto& life = entitySystem.get_component<Component::Life>(entity);

  //TODO:: Update buffs
  //TODO:: Update HP

  if(entitySystem.has_component<Component::Damage>(entity) == true)
  {
    auto& queuedDamage = entitySystem.get_component<Component::Damage>(entity);
    int32_t adjusted_hp = life.hp;
    uint32_t total_applied_damage = 0;

    for(auto attack : queuedDamage.damage_)
    {
      if(attack.apply_) {
        // We waited at least one update before applying damage, apply it now
        //TODO:: Apply damage to this entity
        Entity attacker = entitySystem.get_entity_from_id(attack.attacker_);
        logger->debug("Applying damage to entity {} {}", basicInfo.name, basicInfo.id);

        if((adjusted_hp - attack.value_) <= 0) {
          logger->debug("Entity {} {} will die from {} damage", basicInfo.name, basicInfo.id, attack.value_);
          total_applied_damage = attack.value_ + adjusted_hp;
          adjusted_hp = 0;
          //TODO: Credit this attacker as the one who killed this entity.
        } else {
          total_applied_damage += attack.value_;
          adjusted_hp -= attack.value_;
        }

        if(adjusted_hp <= 0) {
          //TODO: Get dropped item data here and send it with the DAMAGE packet
          attack.action_ &= ~DAMAGE_ACTION_HIT;
          attack.action_ |= DAMAGE_ACTION_DEAD;
          auto p = SrvDamage::create(attack.attacker_, basicInfo.id, attack.value_ + 30000, attack.action_);
          entitySystem.send_nearby(entity, p);

          // remove components that we can't have if we are dead!
          entitySystem.remove_component<Component::Damage>(entity);
          entitySystem.remove_component<Component::Destination>(entity);
          entitySystem.remove_component<Component::Target>(entity);
        } else {
          logger->debug("applied {} damage to entity {} {}.", attack.value_, basicInfo.name, basicInfo.id);

          auto p = SrvDamage::create(attack.attacker_, basicInfo.id, attack.value_, attack.action_);
          entitySystem.send_to(entity, p);
          entitySystem.send_to(attacker, p);
        }

        // Reset the damage value to 0 for next pass
        attack.value_ = 0;
      } else {
        // Apply any new damage on next update
        attack.apply_ = true;
      }
    }

    std::remove_if(queuedDamage.damage_.begin(), queuedDamage.damage_.end(), [] (auto &i) { return (true == i.apply_ && 0 == i.value_); });
  }

  // Check to see if we have a target component
  if(entitySystem.has_component<Component::Target>(entity) == true)
  {
    auto& target = entitySystem.get_component<Component::Target>(entity);
    // Are we in attack range?
    //TODO:: Update apply damage to target
  }
}

RoseCommon::Entity Combat::get_closest_spawn(EntitySystem& entitySystem, RoseCommon::Entity player) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::get_closest_spawn start");
  const auto& position = entitySystem.get_component<Component::Position>(player);

  RoseCommon::Entity closest = {};
  float closestDist = 999999999999;

  for (RoseCommon::Entity entity : entitySystem.get_entities_with_components<Component::BasicInfo, Component::Position, Component::PlayerSpawn>()) {
    const auto& spawnPosition = entitySystem.get_component<Component::Position>(entity);

    if(spawnPosition.map != position.map) continue;

    float dx = spawnPosition.x - position.x;
    float dy = spawnPosition.y - position.y;
    float distance = std::sqrt(dx * dx + dy * dy);

    if(distance < closestDist) {
      closest = entity;
      closestDist = distance;
    }
  }
  logger->trace("Combat::get_closest_spawn end");
  return closest;
}

RoseCommon::Entity Combat::get_saved_spawn(EntitySystem& entitySystem, RoseCommon::Entity player) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::get_saved_spawn start");
  const auto& position = entitySystem.get_component<Component::Position>(player);

  for (RoseCommon::Entity entity : entitySystem.get_entities_with_components<Component::BasicInfo, Component::Position, Component::PlayerSpawn>()) {
    const auto& spawninfo = entitySystem.get_component<Component::PlayerSpawn>(entity);
    if(spawninfo.type == Component::PlayerSpawn::RESPAWN_POINT) {
      const auto& spawnPosition = entitySystem.get_component<Component::Position>(entity);

      if(spawnPosition.map == position.spawn)
        return entity;
    }
  }

  logger->trace("Combat::get_saved_spawn unable to find the saved spawn point");
  return {};
}

RoseCommon::Entity Combat::get_start_spawn(EntitySystem& entitySystem) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::get_start_spawn start");
  for (RoseCommon::Entity entity : entitySystem.get_entities_with_components<Component::BasicInfo, Component::Position, Component::PlayerSpawn>()) {
    const auto& spawninfo = entitySystem.get_component<Component::PlayerSpawn>(entity);

    if(spawninfo.type == Component::PlayerSpawn::START_POINT)
      return entity;
  }

  return {};
}

void Combat::revive(EntitySystem& entitySystem, Entity entity, const RoseCommon::Packet::CliReviveReq& packet) {
  auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
  logger->trace("Combat::revive");

  const auto& basicInfo = entitySystem.get_component<Component::BasicInfo>(entity);
  const auto& pos = entitySystem.get_component<Component::Position>(entity);
  auto& life = entitySystem.get_component<Component::Life>(entity);
  auto& magic = entitySystem.get_component<Component::Magic>(entity);

  uint16_t map_id = pos.map;
  float x = 0.f, y = 0.f;

  switch(packet.get_reviveType())
  {
    case CliReviveReq::ReviveRequest::REVIVE_POSITION:
    {
      if (Entity e = get_closest_spawn(entitySystem, entity); e) {
        auto& dest = entitySystem.get_component<Component::Position>(e);
        x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
        y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
      }
      break;
    }
    case CliReviveReq::ReviveRequest::SAVE_POSITION:
    {
      if (Entity e = get_saved_spawn(entitySystem, entity); e) {
        auto& dest = entitySystem.get_component<Component::Position>(e);

        if(dest.map == 20 && basicInfo.job) {
          if (Entity e = get_closest_spawn(entitySystem, entity); e) {
            auto& dest = entitySystem.get_component<Component::Position>(e);
            x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
            y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
          }
          break;
        }

        if(pos.map != dest.map) {
          map_id = dest.map;
        }
        x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
        y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
      }
      break;
    }
    case CliReviveReq::ReviveRequest::START_POSITION:
    {
      if (Entity e = get_start_spawn(entitySystem); e) {
        auto& dest = entitySystem.get_component<Component::Position>(e);
        x = dest.x + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
        y = dest.y + (Core::Random::getInstance().get_uniform(0, 1001) - 500);
      }
      break;
    }
    case CliReviveReq::ReviveRequest::CURRENT_POSITION:
    {
      x = pos.x;
      y = pos.y;
      break;
    }
    default:
    {
        logger->warn("Combat::revive player {} sent a revive type that doesn't exist...", basicInfo.name);
      break;
    }
  }

  life.hp = (life.maxHp * 0.3f);
  magic.mp = 0;

  entitySystem.teleport_entity(entity, x, y, map_id);
}<|endoftext|>