<commit_before>/*
 * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
 */

#include "base/os.h"
#include "testing/gunit.h"

#include <base/logging.h>
#include <io/event_manager.h>
#include <io/test/event_manager_test.h>
#include <tbb/task.h>
#include <base/task.h>

#include <cmn/agent_cmn.h>

#include "cfg/cfg_init.h"
#include "cfg/cfg_interface.h"
#include "pkt/pkt_init.h"
#include "services/services_init.h"
#include "vrouter/ksync/ksync_init.h"
#include "oper/interface_common.h"
#include "oper/nexthop.h"
#include "oper/tunnel_nh.h"
#include "route/route.h"
#include "oper/vrf.h"
#include "oper/mpls.h"
#include "oper/vm.h"
#include "oper/vn.h"
#include "filter/acl.h"
#include "openstack/instance_service_server.h"
#include "test_cmn_util.h"
#include "vr_types.h"

#include "openstack/instance_service_server.h"
#include "xmpp/xmpp_init.h"
#include "xmpp/test/xmpp_test_util.h"
#include "vr_types.h"
#include "control_node_mock.h"
#include "xml/xml_pugi.h"
#include "controller/controller_peer.h"
#include "controller/controller_export.h"
#include "controller/controller_vrf_export.h"

#include "ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h"
#include "ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.h"
#include "ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.h"
#include "ovs_tor_agent/ovsdb_client/physical_port_ovsdb.h"
#include "ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.h"
#include "test_ovs_agent_init.h"
#include "test-xml/test_xml.h"
#include "test-xml/test_xml_oper.h"
#include "test_xml_physical_device.h"
#include "test_xml_ovsdb.h"

#include "test_ovs_agent_util.h"

#include <ovsdb_types.h>

using namespace pugi;
using namespace OVSDB;
using namespace boost::uuids;

EventManager evm1;
ServerThread *thread1;
test::ControlNodeMock *bgp_peer1;

EventManager evm2;
ServerThread *thread2;
test::ControlNodeMock *bgp_peer2;

void RouterIdDepInit(Agent *agent) {
    Agent::GetInstance()->controller()->Connect();
}

class UnicastLocalRouteTest : public ::testing::Test {
protected:
    UnicastLocalRouteTest() {
    }

    UnicastMacLocalEntry *FindUcastLocal(const string &logical_switch,
                                         const string &mac) {
        UnicastMacLocalOvsdb *table =
            tcp_session_->client_idl()->unicast_mac_local_ovsdb();
        UnicastMacLocalEntry key(table, logical_switch, mac);
        UnicastMacLocalEntry *entry =
            static_cast<UnicastMacLocalEntry *> (table->Find(&key));
        return entry;
    }

    virtual void SetUp() {
        agent_ = Agent::GetInstance();
        init_ = static_cast<TestOvsAgentInit *>(client->agent_init());
        peer_manager_ = init_->ovs_peer_manager();
        WAIT_FOR(100, 10000,
                 (tcp_session_ = static_cast<OvsdbClientTcpSession *>
                  (init_->ovsdb_client()->NextSession(NULL))) != NULL);
        WAIT_FOR(100, 10000,
                 (tcp_session_->client_idl() != NULL));
        WAIT_FOR(100, 10000, (tcp_session_->status() == string("Established")));

        AgentUtXmlTest test("controller/src/vnsw/agent/ovs_tor_agent/ovsdb_"
                            "client/test/xml/ucast-local-test-setup.xml");
        // set current session in test context
        OvsdbTestSetSessionContext(tcp_session_);
        AgentUtXmlOperInit(&test);
        AgentUtXmlPhysicalDeviceInit(&test);
        AgentUtXmlOvsdbInit(&test);
        if (test.Load() == true) {
            test.ReadXml();
            string str;
            test.ToString(&str);
            cout << str << endl;
            test.Run();
        }
    }

    virtual void TearDown() {
        AgentUtXmlTest test("controller/src/vnsw/agent/ovs_tor_agent/ovsdb_"
                            "client/test/xml/ucast-local-test-teardown.xml");
        // set current session in test context
        AgentUtXmlOperInit(&test);
        AgentUtXmlPhysicalDeviceInit(&test);
        AgentUtXmlOvsdbInit(&test);
        if (test.Load() == true) {
            test.ReadXml();
            string str;
            test.ToString(&str);
            cout << str << endl;
            test.Run();
        }
        client->WaitForIdle();
    }

    Agent *agent_;
    TestOvsAgentInit *init_;
    OvsPeerManager *peer_manager_;
    OvsdbClientTcpSession *tcp_session_;
};

TEST_F(UnicastLocalRouteTest, UnicastLocalBasic) {
    LogicalSwitchTable *table =
        tcp_session_->client_idl()->logical_switch_table();
    LogicalSwitchEntry key(table, UuidToString(MakeUuid(1)));
    LogicalSwitchEntry *entry = static_cast<LogicalSwitchEntry *>
        (table->Find(&key));
    EXPECT_TRUE((entry != NULL));
    if (entry != NULL) {
        WAIT_FOR(10, 10000,
                 (true == add_ucast_mac_local(entry->name(),
                                              "00:00:00:00:01:01",
                                              "11.11.11.11")));
        // Wait for entry to add
        WAIT_FOR(100, 10000,
                 (NULL != FindUcastLocal(entry->name(), "00:00:00:00:01:01")));

        OvsdbUnicastMacLocalReq *req = new OvsdbUnicastMacLocalReq();
        req->HandleRequest();
        client->WaitForIdle();
        req->Release();

        WAIT_FOR(10, 10000,
                 (true == del_ucast_mac_local(entry->name(),
                                              "00:00:00:00:01:01")));
        // Wait for entry to del
        WAIT_FOR(100, 10000,
                 (NULL == FindUcastLocal(entry->name(), "00:00:00:00:01:01")));
    }
}

TEST_F(UnicastLocalRouteTest, tunnel_nh_1) {
    IpAddress server = Ip4Address::from_string("1.1.1.1");
    OvsPeer *peer = peer_manager_->Allocate(server);
    EXPECT_TRUE(peer->export_to_controller());

    MacAddress mac("00:00:00:00:00:01");
    Ip4Address tor_ip = Ip4Address::from_string("2.2.2.1");
    Ip4Address server_ip = Ip4Address::from_string("0.0.0.0");
    AddVrf("vrf1", 1);
    client->WaitForIdle();

    VrfEntry *vrf = VrfGet("vrf1");
    WAIT_FOR(100, 100, (vrf->GetBridgeRouteTable() != NULL));
    peer->AddOvsRoute(vrf, 100, "dummy", mac, tor_ip, true);
    WAIT_FOR(1000, 100, (EvpnRouteGet("vrf1", mac, server_ip, 100) != NULL));
    client->WaitForIdle();

    EvpnRouteEntry *rt = EvpnRouteGet("vrf1", mac, server_ip, 100);
    const AgentPath *path = rt->GetActivePath();
    EXPECT_TRUE(path->tunnel_dest() == tor_ip);
    const TunnelNH *nh = dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(*nh->GetDip() == tor_ip);

    AddEncapList("MPLSoUDP", "vxlan", NULL);
    client->WaitForIdle();
    WAIT_FOR(1000, 100, (EvpnRouteGet("vrf1", mac, server_ip, 100) != NULL));

    rt = EvpnRouteGet("vrf1", mac, server_ip, 100);
    path = rt->GetActivePath();
    EXPECT_TRUE(path->tunnel_dest() == tor_ip);
    nh = dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(*nh->GetDip() == tor_ip);

    peer->DeleteOvsRoute(vrf, 100, mac, true);
    client->WaitForIdle();
    // Change tunnel-type order
    peer_manager_->Free(peer);
    client->WaitForIdle();
}

int main(int argc, char *argv[]) {
    GETUSERARGS();
    // override with true to initialize ovsdb server and client
    ksync_init = true;
    client = OvsTestInit(init_file, ksync_init);
    int ret = RUN_ALL_TESTS();
    TestShutdown();
    return ret;
}
<commit_msg>Fix test_ovs_unicast_local UT<commit_after>/*
 * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
 */

#include "base/os.h"
#include "testing/gunit.h"

#include <base/logging.h>
#include <io/event_manager.h>
#include <io/test/event_manager_test.h>
#include <tbb/task.h>
#include <base/task.h>

#include <cmn/agent_cmn.h>

#include "cfg/cfg_init.h"
#include "cfg/cfg_interface.h"
#include "pkt/pkt_init.h"
#include "services/services_init.h"
#include "vrouter/ksync/ksync_init.h"
#include "oper/interface_common.h"
#include "oper/nexthop.h"
#include "oper/tunnel_nh.h"
#include "route/route.h"
#include "oper/vrf.h"
#include "oper/mpls.h"
#include "oper/vm.h"
#include "oper/vn.h"
#include "filter/acl.h"
#include "openstack/instance_service_server.h"
#include "test_cmn_util.h"
#include "vr_types.h"

#include "openstack/instance_service_server.h"
#include "xmpp/xmpp_init.h"
#include "xmpp/test/xmpp_test_util.h"
#include "vr_types.h"
#include "control_node_mock.h"
#include "xml/xml_pugi.h"
#include "controller/controller_peer.h"
#include "controller/controller_export.h"
#include "controller/controller_vrf_export.h"

#include "ovs_tor_agent/ovsdb_client/ovsdb_route_peer.h"
#include "ovs_tor_agent/ovsdb_client/physical_switch_ovsdb.h"
#include "ovs_tor_agent/ovsdb_client/logical_switch_ovsdb.h"
#include "ovs_tor_agent/ovsdb_client/physical_port_ovsdb.h"
#include "ovs_tor_agent/ovsdb_client/unicast_mac_local_ovsdb.h"
#include "test_ovs_agent_init.h"
#include "test-xml/test_xml.h"
#include "test-xml/test_xml_oper.h"
#include "test_xml_physical_device.h"
#include "test_xml_ovsdb.h"

#include "test_ovs_agent_util.h"

#include <ovsdb_types.h>

using namespace pugi;
using namespace OVSDB;
using namespace boost::uuids;

EventManager evm1;
ServerThread *thread1;
test::ControlNodeMock *bgp_peer1;

EventManager evm2;
ServerThread *thread2;
test::ControlNodeMock *bgp_peer2;

void RouterIdDepInit(Agent *agent) {
    Agent::GetInstance()->controller()->Connect();
}

class UnicastLocalRouteTest : public ::testing::Test {
protected:
    UnicastLocalRouteTest() {
    }

    UnicastMacLocalEntry *FindUcastLocal(const string &logical_switch,
                                         const string &mac) {
        UnicastMacLocalOvsdb *table =
            tcp_session_->client_idl()->unicast_mac_local_ovsdb();
        UnicastMacLocalEntry key(table, logical_switch, mac);
        UnicastMacLocalEntry *entry =
            static_cast<UnicastMacLocalEntry *> (table->Find(&key));
        return entry;
    }

    virtual void SetUp() {
        agent_ = Agent::GetInstance();
        init_ = static_cast<TestOvsAgentInit *>(client->agent_init());
        peer_manager_ = init_->ovs_peer_manager();
        WAIT_FOR(100, 10000,
                 (tcp_session_ = static_cast<OvsdbClientTcpSession *>
                  (init_->ovsdb_client()->NextSession(NULL))) != NULL);
        WAIT_FOR(100, 10000,
                 (tcp_session_->client_idl() != NULL));
        WAIT_FOR(100, 10000, (tcp_session_->status() == string("Established")));

        AgentUtXmlTest test("controller/src/vnsw/agent/ovs_tor_agent/ovsdb_"
                            "client/test/xml/ucast-local-test-setup.xml");
        // set current session in test context
        OvsdbTestSetSessionContext(tcp_session_);
        AgentUtXmlOperInit(&test);
        AgentUtXmlPhysicalDeviceInit(&test);
        AgentUtXmlOvsdbInit(&test);
        if (test.Load() == true) {
            test.ReadXml();
            string str;
            test.ToString(&str);
            cout << str << endl;
            test.Run();
        }
    }

    virtual void TearDown() {
        AgentUtXmlTest test("controller/src/vnsw/agent/ovs_tor_agent/ovsdb_"
                            "client/test/xml/ucast-local-test-teardown.xml");
        // set current session in test context
        AgentUtXmlOperInit(&test);
        AgentUtXmlPhysicalDeviceInit(&test);
        AgentUtXmlOvsdbInit(&test);
        if (test.Load() == true) {
            test.ReadXml();
            string str;
            test.ToString(&str);
            cout << str << endl;
            test.Run();
        }
        client->WaitForIdle();
    }

    Agent *agent_;
    TestOvsAgentInit *init_;
    OvsPeerManager *peer_manager_;
    OvsdbClientTcpSession *tcp_session_;
};

TEST_F(UnicastLocalRouteTest, UnicastLocalBasic) {
    LogicalSwitchTable *table =
        tcp_session_->client_idl()->logical_switch_table();
    LogicalSwitchEntry key(table, UuidToString(MakeUuid(1)));
    LogicalSwitchEntry *entry = static_cast<LogicalSwitchEntry *>
        (table->Find(&key));
    EXPECT_TRUE((entry != NULL));
    if (entry != NULL) {
        WAIT_FOR(10, 10000,
                 (true == add_ucast_mac_local(entry->name(),
                                              "00:00:00:00:01:01",
                                              "11.11.11.11")));
        // Wait for entry to add
        WAIT_FOR(100, 10000,
                 (NULL != FindUcastLocal(entry->name(), "00:00:00:00:01:01")));

        OvsdbUnicastMacLocalReq *req = new OvsdbUnicastMacLocalReq();
        req->HandleRequest();
        client->WaitForIdle();
        req->Release();

        WAIT_FOR(10, 10000,
                 (true == del_ucast_mac_local(entry->name(),
                                              "00:00:00:00:01:01")));
        // Wait for entry to del
        WAIT_FOR(100, 10000,
                 (NULL == FindUcastLocal(entry->name(), "00:00:00:00:01:01")));
    }
}

TEST_F(UnicastLocalRouteTest, tunnel_nh_1) {
    IpAddress server = Ip4Address::from_string("1.1.1.1");
    OvsPeer *peer = peer_manager_->Allocate(server);
    EXPECT_TRUE(peer->export_to_controller());

    MacAddress mac("00:00:00:00:00:01");
    Ip4Address tor_ip = Ip4Address::from_string("2.2.2.1");
    Ip4Address server_ip = Ip4Address::from_string("0.0.0.0");
    AddVrf("vrf1", 1);
    client->WaitForIdle();

    VrfEntry *vrf = VrfGet("vrf1");
    WAIT_FOR(100, 100, (vrf->GetBridgeRouteTable() != NULL));
    peer->AddOvsRoute(vrf, 100, "dummy", mac, tor_ip, true);
    WAIT_FOR(1000, 100, (EvpnRouteGet("vrf1", mac, server_ip, 100) != NULL));
    client->WaitForIdle();

    EvpnRouteEntry *rt = EvpnRouteGet("vrf1", mac, server_ip, 100);
    const AgentPath *path = rt->GetActivePath();
    EXPECT_TRUE(path->tunnel_dest() == tor_ip);
    const TunnelNH *nh = dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(*nh->GetDip() == tor_ip);

    AddEncapList("MPLSoUDP", "vxlan", NULL);
    client->WaitForIdle();
    WAIT_FOR(1000, 100, (EvpnRouteGet("vrf1", mac, server_ip, 100) != NULL));

    rt = EvpnRouteGet("vrf1", mac, server_ip, 100);
    path = rt->GetActivePath();
    EXPECT_TRUE(path->tunnel_dest() == tor_ip);
    nh = dynamic_cast<const TunnelNH *>(rt->GetActiveNextHop());
    EXPECT_TRUE(nh != NULL);
    EXPECT_TRUE(*nh->GetDip() == tor_ip);

    peer->DeleteOvsRoute(vrf, 100, mac, true);
    client->WaitForIdle();
    // Change tunnel-type order
    peer_manager_->Free(peer);
    client->WaitForIdle();
}

int main(int argc, char *argv[]) {
    GETUSERARGS();
    // override with true to initialize ovsdb server and client
    ksync_init = true;
    client = OvsTestInit(init_file, ksync_init);

    // override signal handler to default for SIGCHLD, for system() api
    // to work and return exec status appropriately
    signal(SIGCHLD, SIG_DFL);

    int ret = RUN_ALL_TESTS();
    TestShutdown();
    return ret;
}
<|endoftext|>


<commit_before>#include "ngraph.h"
#include <cstdlib>
#include <stdint.h>
#include <iostream>
#include <PCU.h>
namespace agi {

Ngraph::Ngraph() {
  isHyperGraph=false;
  num_global_verts=0;
  num_local_verts=0;
  num_ghost_verts=0;

  num_types=0;
  local_weights=NULL;
  local_coords=NULL;
  for (int i=0;i<MAX_TYPES;i++) {
    edge_ids[i] = NULL;
    edge_weights[i] = NULL;
    num_global_edges[i]=0;
    num_local_edges[i]=0;
    degree_list[i]=NULL;
    edge_list[i]=NULL;
    num_global_pins[i]=0;
    num_local_pins[i]=0;
    pin_degree_list[i]=NULL;
    pin_list[i]=NULL;
  }

  local_unmap = NULL;
  ghost_unmap=NULL;
  owners = NULL;
}

Ngraph::~Ngraph() {
  if (local_weights)
    delete [] local_weights;
  if (local_coords)
    delete [] local_coords;
  for (int i=0;i<MAX_TYPES;i++) {
    if (edge_ids[i])
      delete [] edge_ids[i];
    if (edge_weights[i])
      delete [] edge_weights[i];
    if (degree_list[i])
      delete [] degree_list[i];
    if (edge_list[i])
      delete [] edge_list[i];
    if (pin_degree_list[i])
      delete [] pin_degree_list[i];
    if (pin_list[i])
      delete [] pin_list[i];
  }
  if (local_unmap)
    delete [] local_unmap;
  if (ghost_unmap)
    delete [] ghost_unmap;
  if (owners)
    delete [] owners;
}

const wgt_t& Ngraph::weight(GraphVertex* vtx) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  if (index>=numTotalVtxs()){
    printf("[ERROR] invalid vertex given to weight(vtx)\n");
    throw 1;
  }
  else if (index>=num_local_verts) {
    printf("[ERROR] weights unknown for ghost vertices\n");
    throw 2;
  }
  return local_weights[index];
}
const coord_t& Ngraph::coord(GraphVertex* vtx) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  if (index>=numTotalVtxs()){
    printf("[ERROR] invalid vertex given to coord(vtx)\n");
    throw 1;
  }
  else if (index>=num_local_verts) {
    printf("[ERROR] coordinates unknown for ghost vertices\n");
    throw 2;
  }
  return local_coords[index];
}

int Ngraph::owner(GraphVertex* vtx) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  if (index>=num_local_verts+num_ghost_verts) {
    fprintf(stderr,"[ERROR] invalid vertex given to owner(vtx)\n");
    return -1;
  }
  if (index<num_local_verts)
    return PCU_Comm_Self();
  index-=num_local_verts;
  return owners[index];
}

lid_t Ngraph::localID(GraphVertex* vtx) const {
  return  (uintptr_t)(vtx)-1;

}
gid_t Ngraph::globalID(GraphVertex* vtx) const {
  return  local_unmap[(uintptr_t)(vtx)-1];
}

GraphVertex* Ngraph::find(GraphVertex* vtx) const {
  return findGID(globalID(vtx));
}

wgt_t Ngraph::weight(GraphEdge* edge) const {
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  return edge_weights[type][edge_list[type][id]];
}

lid_t Ngraph::u(lid_t e) const {
  bool found = false;
  lid_t index = 0;
  lid_t bound_low=0;
  lid_t bound_high = numLocalVtxs();
  while (!found) {
    index = (bound_high+bound_low)/2;
    if (degree_list[0][index]<= e&& degree_list[0][index+1]>e)
      found=true;
    else if (degree_list[0][index]<=e)
      bound_low=index;
    else
      bound_high=index;

  }
  return index;
}

GraphVertex* Ngraph::v(GraphEdge* edge) const {
  if (isHyperGraph) {
    fprintf(stderr,"v(edge) not supported in hypergraph mode");
    return NULL;
  }
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  return reinterpret_cast<GraphVertex*>(edge_list[type][id]+1);
}

lid_t  Ngraph::degree(GraphVertex* vtx,etype type) const {
  uintptr_t index =(uintptr_t)(vtx)-1;
  return degree_list[type][index+1]-degree_list[type][index];
}

EdgeIterator* Ngraph::edges(GraphVertex* vtx,etype type) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  EdgeIterator* eitr = new EdgeIterator(type,num_types,(lid_t*)degree_list[type][index],degree(vtx,type));
  return eitr;
}

lid_t  Ngraph::degree(GraphEdge* edge) const {
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  lid_t index = edge_list[type][id];
  return pin_degree_list[type][index+1]-pin_degree_list[type][index];
}

PinIterator* Ngraph::pins(GraphEdge* edge) const {
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  lid_t index = edge_list[type][id];
  return reinterpret_cast<PinIterator*>(pin_list[type]+
                                        pin_degree_list[type][index]);
}

VertexIterator* Ngraph::begin() const {
  return reinterpret_cast<VertexIterator*>((char*)1);
}
GraphVertex* Ngraph::findGID(gid_t gid) const {
  return reinterpret_cast<GraphVertex*>((char*)(vtx_mapping.find(gid)->second));
}

EdgeIterator* Ngraph::begin(etype t) const {
  return new EdgeIterator(t,num_types,edge_list[t],num_local_edges[t]);
}

GraphVertex* Ngraph::iterate(VertexIterator*& itr) const {
  uintptr_t index = (uintptr_t)(itr);
  if (index==num_local_verts+1)  {
    itr=NULL;
    return NULL;
  }
  GraphVertex* vtx = reinterpret_cast<GraphVertex*>((lid_t*)index);
  itr = reinterpret_cast<VertexIterator*>((char*)(index+1));
  return vtx;
}
GraphEdge* Ngraph::iterate(EdgeIterator*& itr) const {
  if (itr->loc>=itr->end)
    return NULL;
  uintptr_t index = (uintptr_t)itr->loc;
  itr->loc = (gid_t*)(index+num_types);
  return (GraphEdge*)(index);
}
GraphVertex* Ngraph::iterate(PinIterator*& itr) const {
  lid_t* e = reinterpret_cast<lid_t*>(itr);
  uintptr_t id = *e+1;
  GraphVertex* vtx = reinterpret_cast<GraphVertex*>((char*)id);
  itr = reinterpret_cast<PinIterator*>(++e);
  return vtx;
}

void Ngraph::destroy(EdgeIterator* itr) const {
  delete itr;
}

bool Ngraph::isEqual(GraphVertex* u,GraphVertex* v) const {
  return u==v;
}

//Protected functions

void Ngraph::makeEdgeArray(etype t, int count) {
  edge_ids[t] = new gid_t[count];
  edge_weights[t] = new wgt_t[count];
}

void Ngraph::setEdge(lid_t lid,gid_t gid, wgt_t w,etype t) {
  edge_ids[t][lid] = gid;
  edge_weights[t][lid] = w;
  edge_mapping[t][gid]=lid;

}
  /*
void Ngraph::create_csr(int nv, int ne, int* srcs,
                          int* dsts, int* wgts) {
  num_verts = nv;
  num_edges = ne;
  weights = new double[num_verts];
  out_vertices = new int[num_edges];
  out_weights = new double[num_edges];
  out_degree_list = new int[num_verts+1];

  for (size_t i = 0; i < num_edges; ++i)
    out_vertices[i] = 0;
  for (size_t i = 0; i < num_edges; ++i)
    out_weights[i] = 0;
  for (size_t i = 0; i < num_verts+1; ++i)
    out_degree_list[i] = 0;

  int* temp_counts = new int[num_verts];
  for (size_t i = 0; i < num_verts; ++i)
    temp_counts[i] = 0;
  for (size_t i = 0; i < num_edges; ++i)
    ++temp_counts[srcs[i]];
  for (size_t i = 0; i < num_verts; ++i)
    out_degree_list[i+1] = out_degree_list[i] + temp_counts[i];
  std::copy(out_degree_list, out_degree_list + num_verts, temp_counts);
  for (size_t i = 0; i < num_edges; ++i) {
    out_vertices[temp_counts[srcs[i]]] = dsts[i];
    out_weights[temp_counts[srcs[i]]++] = wgts[i];
  }

  delete [] temp_counts;

}
  */

void destroyGraph(Ngraph* g) {delete g;}
}
<commit_msg>Fix iterations over edges starting at begin()<commit_after>#include "ngraph.h"
#include <cstdlib>
#include <stdint.h>
#include <iostream>
#include <PCU.h>
namespace agi {

Ngraph::Ngraph() {
  isHyperGraph=false;
  num_global_verts=0;
  num_local_verts=0;
  num_ghost_verts=0;

  num_types=0;
  local_weights=NULL;
  local_coords=NULL;
  for (int i=0;i<MAX_TYPES;i++) {
    edge_ids[i] = NULL;
    edge_weights[i] = NULL;
    num_global_edges[i]=0;
    num_local_edges[i]=0;
    degree_list[i]=NULL;
    edge_list[i]=NULL;
    num_global_pins[i]=0;
    num_local_pins[i]=0;
    pin_degree_list[i]=NULL;
    pin_list[i]=NULL;
  }

  local_unmap = NULL;
  ghost_unmap=NULL;
  owners = NULL;
}

Ngraph::~Ngraph() {
  if (local_weights)
    delete [] local_weights;
  if (local_coords)
    delete [] local_coords;
  for (int i=0;i<MAX_TYPES;i++) {
    if (edge_ids[i])
      delete [] edge_ids[i];
    if (edge_weights[i])
      delete [] edge_weights[i];
    if (degree_list[i])
      delete [] degree_list[i];
    if (edge_list[i])
      delete [] edge_list[i];
    if (pin_degree_list[i])
      delete [] pin_degree_list[i];
    if (pin_list[i])
      delete [] pin_list[i];
  }
  if (local_unmap)
    delete [] local_unmap;
  if (ghost_unmap)
    delete [] ghost_unmap;
  if (owners)
    delete [] owners;
}

const wgt_t& Ngraph::weight(GraphVertex* vtx) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  if (index>=numTotalVtxs()){
    printf("[ERROR] invalid vertex given to weight(vtx)\n");
    throw 1;
  }
  else if (index>=num_local_verts) {
    printf("[ERROR] weights unknown for ghost vertices\n");
    throw 2;
  }
  return local_weights[index];
}
const coord_t& Ngraph::coord(GraphVertex* vtx) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  if (index>=numTotalVtxs()){
    printf("[ERROR] invalid vertex given to coord(vtx)\n");
    throw 1;
  }
  else if (index>=num_local_verts) {
    printf("[ERROR] coordinates unknown for ghost vertices\n");
    throw 2;
  }
  return local_coords[index];
}

int Ngraph::owner(GraphVertex* vtx) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  if (index>=num_local_verts+num_ghost_verts) {
    fprintf(stderr,"[ERROR] invalid vertex given to owner(vtx)\n");
    return -1;
  }
  if (index<num_local_verts)
    return PCU_Comm_Self();
  index-=num_local_verts;
  return owners[index];
}

lid_t Ngraph::localID(GraphVertex* vtx) const {
  return  (uintptr_t)(vtx)-1;

}
gid_t Ngraph::globalID(GraphVertex* vtx) const {
  return  local_unmap[(uintptr_t)(vtx)-1];
}

GraphVertex* Ngraph::find(GraphVertex* vtx) const {
  return findGID(globalID(vtx));
}

wgt_t Ngraph::weight(GraphEdge* edge) const {
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  return edge_weights[type][edge_list[type][id]];
}

lid_t Ngraph::u(lid_t e) const {
  bool found = false;
  lid_t index = 0;
  lid_t bound_low=0;
  lid_t bound_high = numLocalVtxs();
  while (!found) {
    index = (bound_high+bound_low)/2;
    if (degree_list[0][index]<= e&& degree_list[0][index+1]>e)
      found=true;
    else if (degree_list[0][index]<=e)
      bound_low=index;
    else
      bound_high=index;

  }
  return index;
}

GraphVertex* Ngraph::v(GraphEdge* edge) const {
  if (isHyperGraph) {
    fprintf(stderr,"v(edge) not supported in hypergraph mode");
    return NULL;
  }
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  return reinterpret_cast<GraphVertex*>(edge_list[type][id]+1);
}

lid_t  Ngraph::degree(GraphVertex* vtx,etype type) const {
  uintptr_t index =(uintptr_t)(vtx)-1;
  return degree_list[type][index+1]-degree_list[type][index];
}

EdgeIterator* Ngraph::edges(GraphVertex* vtx,etype type) const {
  uintptr_t index = (uintptr_t)(vtx)-1;
  EdgeIterator* eitr = new EdgeIterator(type,num_types,(lid_t*)degree_list[type][index],degree(vtx,type));
  return eitr;
}

lid_t  Ngraph::degree(GraphEdge* edge) const {
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  lid_t index = edge_list[type][id];
  return pin_degree_list[type][index+1]-pin_degree_list[type][index];
}

PinIterator* Ngraph::pins(GraphEdge* edge) const {
  uintptr_t id = (uintptr_t)(edge)-1;
  etype type = id%num_types;
  id/=num_types;
  lid_t index = edge_list[type][id];
  return reinterpret_cast<PinIterator*>(pin_list[type]+
                                        pin_degree_list[type][index]);
}

VertexIterator* Ngraph::begin() const {
  return reinterpret_cast<VertexIterator*>((char*)1);
}
GraphVertex* Ngraph::findGID(gid_t gid) const {
  return reinterpret_cast<GraphVertex*>((char*)(vtx_mapping.find(gid)->second));
}

EdgeIterator* Ngraph::begin(etype t) const {
  return new EdgeIterator(t,num_types,0,num_local_edges[t]);
}

GraphVertex* Ngraph::iterate(VertexIterator*& itr) const {
  uintptr_t index = (uintptr_t)(itr);
  if (index==num_local_verts+1)  {
    itr=NULL;
    return NULL;
  }
  GraphVertex* vtx = reinterpret_cast<GraphVertex*>((lid_t*)index);
  itr = reinterpret_cast<VertexIterator*>((char*)(index+1));
  return vtx;
}
GraphEdge* Ngraph::iterate(EdgeIterator*& itr) const {
  if (itr->loc>=itr->end)
    return NULL;
  uintptr_t index = (uintptr_t)itr->loc;
  itr->loc = (gid_t*)(index+num_types);
  return (GraphEdge*)(index);
}
GraphVertex* Ngraph::iterate(PinIterator*& itr) const {
  lid_t* e = reinterpret_cast<lid_t*>(itr);
  uintptr_t id = *e+1;
  GraphVertex* vtx = reinterpret_cast<GraphVertex*>((char*)id);
  itr = reinterpret_cast<PinIterator*>(++e);
  return vtx;
}

void Ngraph::destroy(EdgeIterator* itr) const {
  delete itr;
}

bool Ngraph::isEqual(GraphVertex* u,GraphVertex* v) const {
  return u==v;
}

//Protected functions

void Ngraph::makeEdgeArray(etype t, int count) {
  edge_ids[t] = new gid_t[count];
  edge_weights[t] = new wgt_t[count];
}

void Ngraph::setEdge(lid_t lid,gid_t gid, wgt_t w,etype t) {
  edge_ids[t][lid] = gid;
  edge_weights[t][lid] = w;
  edge_mapping[t][gid]=lid;

}
  /*
void Ngraph::create_csr(int nv, int ne, int* srcs,
                          int* dsts, int* wgts) {
  num_verts = nv;
  num_edges = ne;
  weights = new double[num_verts];
  out_vertices = new int[num_edges];
  out_weights = new double[num_edges];
  out_degree_list = new int[num_verts+1];

  for (size_t i = 0; i < num_edges; ++i)
    out_vertices[i] = 0;
  for (size_t i = 0; i < num_edges; ++i)
    out_weights[i] = 0;
  for (size_t i = 0; i < num_verts+1; ++i)
    out_degree_list[i] = 0;

  int* temp_counts = new int[num_verts];
  for (size_t i = 0; i < num_verts; ++i)
    temp_counts[i] = 0;
  for (size_t i = 0; i < num_edges; ++i)
    ++temp_counts[srcs[i]];
  for (size_t i = 0; i < num_verts; ++i)
    out_degree_list[i+1] = out_degree_list[i] + temp_counts[i];
  std::copy(out_degree_list, out_degree_list + num_verts, temp_counts);
  for (size_t i = 0; i < num_edges; ++i) {
    out_vertices[temp_counts[srcs[i]]] = dsts[i];
    out_weights[temp_counts[srcs[i]]++] = wgts[i];
  }

  delete [] temp_counts;

}
  */

void destroyGraph(Ngraph* g) {delete g;}
}
<|endoftext|>


<commit_before>/// \file ROOT/THistDrawingOpts.h
/// \ingroup HistDraw ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-09-04
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_THistDrawingOpts
#define ROOT7_THistDrawingOpts

#include <ROOT/TDrawingAttrs.hxx>
#include <ROOT/TStringEnumAttr.hxx>

namespace ROOT {
namespace Experimental {

template <int DIMENSION>
class THistDrawingOpts {
   static_assert(DIMENSION != 0, "Cannot draw 0-dimensional histograms!");
   static_assert(DIMENSION > 3, "Cannot draw histograms with more than 3 dimensions!");
   static_assert(DIMENSION < 3, "This should have been handled by the specializations below?!");
};

/** \class THistDrawingOpts<1>
 Drawing options for a 1D histogram.
 */
template <>
class THistDrawingOpts<1> {
   enum class EStyle { kBar, kText };
   static const TStringEnumAttrSet fgStyles;
   TDrawingAttrOrRef<TStringEnumAttr> fStyle{"Hist.1D.Style", 0, fgStyles};
   TDrawingAttrOrRef<TColor> fLineColor{"Hist.1D.Line.Color"};
   TDrawingAttrOrRef<int> fLineWidth{"Hist.1D.Line.Width"};
public:
   THistDrawingOpts() = default;
};

const TStringEnumAttrSet THistDrawingOpts<1>::fgStyles{"hist", "bar", "text"};

/** \class THistDrawingOpts<2>
 Drawing options for a 1D histogram.
 */
template <>
class THistDrawingOpts<2> {
   enum class EStyle { kBox, kSurf, kText };
   static const TStringEnumAttrSet fgStyles;
   TDrawingAttrOrRef<TStringEnumAttr> fStyle{"Hist.2D.Style", 0, fgStyles};
   TDrawingAttrOrRef<TColor> fLineColor{"Hist.2D.Line.Color"};
   TDrawingAttrOrRef<int> fLineWidth{"Hist.2D.Line.Width"};
public:
   THistDrawingOpts() = default;
};

const TStringEnumAttrSet THistDrawingOpts<2>::fgStyles{"box", "surf", "text"};

/** \class THistDrawingOpts<3>
 Drawing options for a 1D histogram.
 */
template <>
class THistDrawingOpts<3> {
   enum class EStyle { kBox, kIso };
   static const TStringEnumAttrSet fgStyles;
   TDrawingAttrOrRef<TStringEnumAttr> fStyle{"Hist.3D.Style", 0, fgStyles};
   TDrawingAttrOrRef<TColor> fLineColor{"Hist.3D.Line.Color"};
   TDrawingAttrOrRef<int> fLineWidth{"Hist.3D.Line.Width"};
public:
   THistDrawingOpts() = default;
};

const TStringEnumAttrSet THistDrawingOpts<3>::fgStyles{"box", "iso"};

} // namespace Experimental
} // namespace ROOT

#endif
<commit_msg>Use function to "hold" style strings.<commit_after>/// \file ROOT/THistDrawingOpts.h
/// \ingroup HistDraw ROOT7
/// \author Axel Naumann <axel@cern.ch>
/// \date 2015-09-04
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_THistDrawingOpts
#define ROOT7_THistDrawingOpts

#include <ROOT/TDrawingAttrs.hxx>
#include <ROOT/TStringEnumAttr.hxx>

namespace ROOT {
namespace Experimental {

template <int DIMENSION>
class THistDrawingOpts {
   static_assert(DIMENSION != 0, "Cannot draw 0-dimensional histograms!");
   static_assert(DIMENSION > 3, "Cannot draw histograms with more than 3 dimensions!");
   static_assert(DIMENSION < 3, "This should have been handled by the specializations below?!");
};

/** \class THistDrawingOpts<1>
 Drawing options for a 1D histogram.
 */
template <>
class THistDrawingOpts<1> {
   enum class EStyle { kBar, kText };
   static const TStringEnumAttrSet &Styles() {
      static const TStringEnumAttrSet styles{"hist", "bar", "text"};
      return styles;
   }
   TDrawingAttrOrRef<TStringEnumAttr> fStyle{"Hist.1D.Style", 0, Styles()};
   TDrawingAttrOrRef<TColor> fLineColor{"Hist.1D.Line.Color"};
   TDrawingAttrOrRef<int> fLineWidth{"Hist.1D.Line.Width"};
public:
   THistDrawingOpts() = default;
};

/** \class THistDrawingOpts<2>
 Drawing options for a 1D histogram.
 */
template <>
class THistDrawingOpts<2> {
   enum class EStyle { kBox, kSurf, kText };
   static const TStringEnumAttrSet fgStyles;
   static const TStringEnumAttrSet &Styles() {
      static const TStringEnumAttrSet styles{"box", "surf", "text"};
      return styles;
   }
   TDrawingAttrOrRef<TStringEnumAttr> fStyle{"Hist.2D.Style", 0, Styles()};
   TDrawingAttrOrRef<TColor> fLineColor{"Hist.2D.Line.Color"};
   TDrawingAttrOrRef<int> fLineWidth{"Hist.2D.Line.Width"};
public:
   THistDrawingOpts() = default;
};

/** \class THistDrawingOpts<3>
 Drawing options for a 1D histogram.
 */
template <>
class THistDrawingOpts<3> {
   enum class EStyle { kBox, kIso };
   static const TStringEnumAttrSet &Styles() {
      static const TStringEnumAttrSet styles{"box", "iso"};
      return styles;
   }
   TDrawingAttrOrRef<TStringEnumAttr> fStyle{"Hist.3D.Style", 0, Styles()};
   TDrawingAttrOrRef<TColor> fLineColor{"Hist.3D.Line.Color"};
   TDrawingAttrOrRef<int> fLineWidth{"Hist.3D.Line.Width"};
public:
   THistDrawingOpts() = default;
};

} // namespace Experimental
} // namespace ROOT

#endif
<|endoftext|>


<commit_before>#include "singletons/ircmanager.hpp"
#include "asyncexec.hpp"
#include "channel.hpp"
#include "debug/log.hpp"
#include "messages/messageparseargs.hpp"
#include "singletons/accountmanager.hpp"
#include "singletons/channelmanager.hpp"
#include "singletons/emotemanager.hpp"
#include "singletons/helper/ircmessagehandler.hpp"
#include "singletons/resourcemanager.hpp"
#include "singletons/settingsmanager.hpp"
#include "singletons/windowmanager.hpp"
#include "twitch/twitchmessagebuilder.hpp"
#include "twitch/twitchuser.hpp"
#include "util/urlfetch.hpp"

#include <irccommand.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkRequest>

#include <future>

using namespace chatterino::messages;

namespace chatterino {
namespace singletons {

IrcManager::IrcManager(ChannelManager &_channelManager, ResourceManager &_resources,
                       AccountManager &_accountManager)
    : channelManager(_channelManager)
    , resources(_resources)
    , accountManager(_accountManager)
{
    this->messageSuffix.append(' ');
    this->messageSuffix.append(QChar(0x206D));

    this->account = accountManager.Twitch.getCurrent();
    accountManager.Twitch.userChanged.connect([this]() {
        this->setUser(accountManager.Twitch.getCurrent());

        debug::Log("[IrcManager] Reconnecting to Twitch IRC as new user {}",
                   this->account->getUserName());

        postToThread([this] { this->connect(); });
    });

    // Initialize the connections
    this->writeConnection.reset(new Communi::IrcConnection);
    this->writeConnection->moveToThread(QCoreApplication::instance()->thread());

    QObject::connect(this->writeConnection.get(), &Communi::IrcConnection::messageReceived, this,
                     &IrcManager::writeConnectionMessageReceived);

    this->readConnection.reset(new Communi::IrcConnection);
    this->readConnection->moveToThread(QCoreApplication::instance()->thread());

    // Listen to read connection message signals
    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::messageReceived, this,
                     &IrcManager::messageReceived);
    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::privateMessageReceived,
                     this, &IrcManager::privateMessageReceived);

    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::connected, this,
                     &IrcManager::onConnected);
    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::disconnected, this,
                     &IrcManager::onDisconnected);

    // join and part chats on event
    ChannelManager::getInstance().ircJoin.connect(
        [this](const QString &name) { this->joinChannel(name); });
    ChannelManager::getInstance().ircPart.connect(
        [this](const QString &name) { this->partChannel(name); });
}

IrcManager &IrcManager::getInstance()
{
    static IrcManager instance(ChannelManager::getInstance(),
                               singletons::ResourceManager::getInstance(),
                               AccountManager::getInstance());
    return instance;
}

void IrcManager::setUser(std::shared_ptr<twitch::TwitchUser> newAccount)
{
    this->account = newAccount;
}

void IrcManager::connect()
{
    this->disconnect();

    this->initializeConnection(this->writeConnection, false);
    this->initializeConnection(this->readConnection, true);

    // XXX(pajlada): Disabled the async_exec for now, because if we happen to run the
    // `beginConnecting` function in a different thread than last time, we won't be able to connect
    // because we can't clean up the previous connection properly
    // async_exec([this] { beginConnecting(); });
    this->beginConnecting();
}

void IrcManager::initializeConnection(const std::unique_ptr<Communi::IrcConnection> &connection,
                                      bool isReadConnection)
{
    assert(this->account);

    QString username = this->account->getUserName();
    QString oauthClient = this->account->getOAuthClient();
    QString oauthToken = this->account->getOAuthToken();
    if (!oauthToken.startsWith("oauth:")) {
        oauthToken.prepend("oauth:");
    }

    connection->setUserName(username);
    connection->setNickName(username);
    connection->setRealName(username);

    if (!this->account->isAnon()) {
        connection->setPassword(oauthToken);

        this->refreshIgnoredUsers(username, oauthClient, oauthToken);
    }

    if (isReadConnection) {
        connection->sendCommand(
            Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership"));
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/commands"));
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/tags"));
    } else {
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/tags"));

        connection->sendCommand(
            Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership"));
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/commands"));
    }

    connection->setHost("irc.chat.twitch.tv");
    connection->setPort(6667);
}

void IrcManager::refreshIgnoredUsers(const QString &username, const QString &oauthClient,
                                     const QString &oauthToken)
{
    QString nextLink = "https://api.twitch.tv/kraken/users/" + username + "/blocks?limit=" + 100 +
                       "&client_id=" + oauthClient;

    QNetworkAccessManager *manager = new QNetworkAccessManager();
    QNetworkRequest req(QUrl(nextLink + "&oauth_token=" + oauthToken));
    QNetworkReply *reply = manager->get(req);

    QObject::connect(reply, &QNetworkReply::finished, [=] {
        this->twitchBlockedUsersMutex.lock();
        this->twitchBlockedUsers.clear();
        this->twitchBlockedUsersMutex.unlock();

        QByteArray data = reply->readAll();
        QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
        QJsonObject root = jsonDoc.object();

        // nextLink =
        // root.value("this->links").toObject().value("next").toString();

        auto blocks = root.value("blocks").toArray();

        this->twitchBlockedUsersMutex.lock();
        for (QJsonValue block : blocks) {
            QJsonObject user = block.toObject().value("user").toObject();
            // displaythis->name
            this->twitchBlockedUsers.insert(user.value("name").toString().toLower(), true);
        }
        this->twitchBlockedUsersMutex.unlock();

        manager->deleteLater();
    });
}

void IrcManager::beginConnecting()
{
    std::lock_guard<std::mutex> locker(this->connectionMutex);

    for (auto &channel : this->channelManager.getItems()) {
        this->writeConnection->sendRaw("JOIN #" + channel->name);
        this->readConnection->sendRaw("JOIN #" + channel->name);
    }

    this->writeConnection->open();
    this->readConnection->open();
}

void IrcManager::disconnect()
{
    std::lock_guard<std::mutex> locker(this->connectionMutex);

    this->readConnection->close();
    this->writeConnection->close();
}

void IrcManager::sendMessage(const QString &channelName, QString message)
{
    this->connectionMutex.lock();
    static int i = 0;

    if (this->writeConnection) {
        if (singletons::SettingManager::getInstance().allowDuplicateMessages && (++i % 2) == 0) {
            message.append(this->messageSuffix);
        }
        this->writeConnection->sendRaw("PRIVMSG #" + channelName + " :" + message);
    }

    this->connectionMutex.unlock();
}

void IrcManager::joinChannel(const QString &channelName)
{
    this->connectionMutex.lock();

    if (this->readConnection && this->writeConnection) {
        this->readConnection->sendRaw("JOIN #" + channelName);
        this->writeConnection->sendRaw("JOIN #" + channelName);
    }

    this->connectionMutex.unlock();
}

void IrcManager::partChannel(const QString &channelName)
{
    this->connectionMutex.lock();

    if (this->readConnection && this->writeConnection) {
        this->readConnection->sendRaw("PART #" + channelName);
        this->writeConnection->sendRaw("PART #" + channelName);
    }

    this->connectionMutex.unlock();
}

void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message)
{
    this->onPrivateMessage.invoke(message);
    auto c = this->channelManager.getTwitchChannel(message->target().mid(1));

    if (!c) {
        return;
    }

    messages::MessageParseArgs args;

    twitch::TwitchMessageBuilder builder(c.get(), message, args);

    c->addMessage(builder.parse());
}

void IrcManager::messageReceived(Communi::IrcMessage *message)
{
    if (message->type() == Communi::IrcMessage::Type::Private) {
        // We already have a handler for private messages
        return;
    }

    const QString &command = message->command();

    if (command == "ROOMSTATE") {
        helper::IrcMessageHandler::getInstance().handleRoomStateMessage(message);
    } else if (command == "CLEARCHAT") {
        helper::IrcMessageHandler::getInstance().handleClearChatMessage(message);
    } else if (command == "USERSTATE") {
        helper::IrcMessageHandler::getInstance().handleUserStateMessage(message);
    } else if (command == "WHISPER") {
        helper::IrcMessageHandler::getInstance().handleWhisperMessage(message);
    } else if (command == "USERNOTICE") {
        helper::IrcMessageHandler::getInstance().handleUserNoticeMessage(message);
    } else if (command == "MODE") {
        helper::IrcMessageHandler::getInstance().handleModeMessage(message);
    } else if (command == "NOTICE") {
        helper::IrcMessageHandler::getInstance().handleNoticeMessage(
            static_cast<Communi::IrcNoticeMessage *>(message));
    }
}

void IrcManager::writeConnectionMessageReceived(Communi::IrcMessage *message)
{
    switch (message->type()) {
        case Communi::IrcMessage::Type::Notice: {
            helper::IrcMessageHandler::getInstance().handleWriteConnectionNoticeMessage(
                static_cast<Communi::IrcNoticeMessage *>(message));
        } break;
    }
}

// XXX: This does not fit in IrcManager
bool IrcManager::isTwitchUserBlocked(QString const &username)
{
    QMutexLocker locker(&this->twitchBlockedUsersMutex);

    auto iterator = this->twitchBlockedUsers.find(username);

    return iterator != this->twitchBlockedUsers.end();
}

// XXX: This does not fit in IrcManager
bool IrcManager::tryAddIgnoredUser(QString const &username, QString &errorMessage)
{
    assert(this->account);

    QUrl url("https://api.twitch.tv/kraken/users/" + this->account->getUserName() + "/blocks/" +
             username + "?oauth_token=" + this->account->getOAuthToken() +
             "&client_id=" + this->account->getOAuthClient());

    QNetworkRequest request(url);
    auto reply = this->networkAccessManager.put(request, QByteArray());
    reply->waitForReadyRead(10000);

    if (reply->error() == QNetworkReply::NoError) {
        this->twitchBlockedUsersMutex.lock();
        this->twitchBlockedUsers.insert(username, true);
        this->twitchBlockedUsersMutex.unlock();

        return true;
    }

    reply->deleteLater();

    errorMessage = "Error while ignoring user \"" + username + "\": " + reply->errorString();

    return false;
}

// XXX: This does not fit in IrcManager
void IrcManager::addIgnoredUser(QString const &username)
{
    QString errorMessage;
    if (!tryAddIgnoredUser(username, errorMessage)) {
        // TODO: Implement IrcManager::addIgnoredUser
    }
}

// XXX: This does not fit in IrcManager
bool IrcManager::tryRemoveIgnoredUser(QString const &username, QString &errorMessage)
{
    assert(this->account);

    QUrl url("https://api.twitch.tv/kraken/users/" + this->account->getUserName() + "/blocks/" +
             username + "?oauth_token=" + this->account->getOAuthToken() +
             "&client_id=" + this->account->getOAuthClient());

    QNetworkRequest request(url);
    auto reply = this->networkAccessManager.deleteResource(request);
    reply->waitForReadyRead(10000);

    if (reply->error() == QNetworkReply::NoError) {
        this->twitchBlockedUsersMutex.lock();
        this->twitchBlockedUsers.remove(username);
        this->twitchBlockedUsersMutex.unlock();

        return true;
    }

    reply->deleteLater();

    errorMessage = "Error while unignoring user \"" + username + "\": " + reply->errorString();

    return false;
}

// XXX: This does not fit in IrcManager
void IrcManager::removeIgnoredUser(QString const &username)
{
    QString errorMessage;
    if (!tryRemoveIgnoredUser(username, errorMessage)) {
        // TODO: Implement IrcManager::removeIgnoredUser
    }
}

void IrcManager::onConnected()
{
    std::shared_ptr<Message> msg(Message::createSystemMessage("connected to chat"));

    this->channelManager.doOnAll([msg](std::shared_ptr<Channel> channel) {
        assert(channel);
        channel->addMessage(msg);
    });
}

void IrcManager::onDisconnected()
{
    std::shared_ptr<Message> msg(Message::createSystemMessage("disconnected from chat"));

    this->channelManager.doOnAll([msg](std::shared_ptr<Channel> channel) {
        assert(channel);
        channel->addMessage(msg);
    });
}

Communi::IrcConnection *IrcManager::getReadConnection()
{
    return this->readConnection.get();
}

}  // namespace chatterino
}
<commit_msg>Disable empty-string sending<commit_after>#include "singletons/ircmanager.hpp"
#include "asyncexec.hpp"
#include "channel.hpp"
#include "debug/log.hpp"
#include "messages/messageparseargs.hpp"
#include "singletons/accountmanager.hpp"
#include "singletons/channelmanager.hpp"
#include "singletons/emotemanager.hpp"
#include "singletons/helper/ircmessagehandler.hpp"
#include "singletons/resourcemanager.hpp"
#include "singletons/settingsmanager.hpp"
#include "singletons/windowmanager.hpp"
#include "twitch/twitchmessagebuilder.hpp"
#include "twitch/twitchuser.hpp"
#include "util/urlfetch.hpp"

#include <irccommand.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkRequest>

#include <future>

using namespace chatterino::messages;

namespace chatterino {
namespace singletons {

IrcManager::IrcManager(ChannelManager &_channelManager, ResourceManager &_resources,
                       AccountManager &_accountManager)
    : channelManager(_channelManager)
    , resources(_resources)
    , accountManager(_accountManager)
{
    this->messageSuffix.append(' ');
    this->messageSuffix.append(QChar(0x206D));

    this->account = accountManager.Twitch.getCurrent();
    accountManager.Twitch.userChanged.connect([this]() {
        this->setUser(accountManager.Twitch.getCurrent());

        debug::Log("[IrcManager] Reconnecting to Twitch IRC as new user {}",
                   this->account->getUserName());

        postToThread([this] { this->connect(); });
    });

    // Initialize the connections
    this->writeConnection.reset(new Communi::IrcConnection);
    this->writeConnection->moveToThread(QCoreApplication::instance()->thread());

    QObject::connect(this->writeConnection.get(), &Communi::IrcConnection::messageReceived, this,
                     &IrcManager::writeConnectionMessageReceived);

    this->readConnection.reset(new Communi::IrcConnection);
    this->readConnection->moveToThread(QCoreApplication::instance()->thread());

    // Listen to read connection message signals
    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::messageReceived, this,
                     &IrcManager::messageReceived);
    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::privateMessageReceived,
                     this, &IrcManager::privateMessageReceived);

    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::connected, this,
                     &IrcManager::onConnected);
    QObject::connect(this->readConnection.get(), &Communi::IrcConnection::disconnected, this,
                     &IrcManager::onDisconnected);

    // join and part chats on event
    ChannelManager::getInstance().ircJoin.connect(
        [this](const QString &name) { this->joinChannel(name); });
    ChannelManager::getInstance().ircPart.connect(
        [this](const QString &name) { this->partChannel(name); });
}

IrcManager &IrcManager::getInstance()
{
    static IrcManager instance(ChannelManager::getInstance(),
                               singletons::ResourceManager::getInstance(),
                               AccountManager::getInstance());
    return instance;
}

void IrcManager::setUser(std::shared_ptr<twitch::TwitchUser> newAccount)
{
    this->account = newAccount;
}

void IrcManager::connect()
{
    this->disconnect();

    this->initializeConnection(this->writeConnection, false);
    this->initializeConnection(this->readConnection, true);

    // XXX(pajlada): Disabled the async_exec for now, because if we happen to run the
    // `beginConnecting` function in a different thread than last time, we won't be able to connect
    // because we can't clean up the previous connection properly
    // async_exec([this] { beginConnecting(); });
    this->beginConnecting();
}

void IrcManager::initializeConnection(const std::unique_ptr<Communi::IrcConnection> &connection,
                                      bool isReadConnection)
{
    assert(this->account);

    QString username = this->account->getUserName();
    QString oauthClient = this->account->getOAuthClient();
    QString oauthToken = this->account->getOAuthToken();
    if (!oauthToken.startsWith("oauth:")) {
        oauthToken.prepend("oauth:");
    }

    connection->setUserName(username);
    connection->setNickName(username);
    connection->setRealName(username);

    if (!this->account->isAnon()) {
        connection->setPassword(oauthToken);

        this->refreshIgnoredUsers(username, oauthClient, oauthToken);
    }

    if (isReadConnection) {
        connection->sendCommand(
            Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership"));
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/commands"));
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/tags"));
    } else {
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/tags"));

        connection->sendCommand(
            Communi::IrcCommand::createCapability("REQ", "twitch.tv/membership"));
        connection->sendCommand(Communi::IrcCommand::createCapability("REQ", "twitch.tv/commands"));
    }

    connection->setHost("irc.chat.twitch.tv");
    connection->setPort(6667);
}

void IrcManager::refreshIgnoredUsers(const QString &username, const QString &oauthClient,
                                     const QString &oauthToken)
{
    QString nextLink = "https://api.twitch.tv/kraken/users/" + username + "/blocks?limit=" + 100 +
                       "&client_id=" + oauthClient;

    QNetworkAccessManager *manager = new QNetworkAccessManager();
    QNetworkRequest req(QUrl(nextLink + "&oauth_token=" + oauthToken));
    QNetworkReply *reply = manager->get(req);

    QObject::connect(reply, &QNetworkReply::finished, [=] {
        this->twitchBlockedUsersMutex.lock();
        this->twitchBlockedUsers.clear();
        this->twitchBlockedUsersMutex.unlock();

        QByteArray data = reply->readAll();
        QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
        QJsonObject root = jsonDoc.object();

        // nextLink =
        // root.value("this->links").toObject().value("next").toString();

        auto blocks = root.value("blocks").toArray();

        this->twitchBlockedUsersMutex.lock();
        for (QJsonValue block : blocks) {
            QJsonObject user = block.toObject().value("user").toObject();
            // displaythis->name
            this->twitchBlockedUsers.insert(user.value("name").toString().toLower(), true);
        }
        this->twitchBlockedUsersMutex.unlock();

        manager->deleteLater();
    });
}

void IrcManager::beginConnecting()
{
    std::lock_guard<std::mutex> locker(this->connectionMutex);

    for (auto &channel : this->channelManager.getItems()) {
        this->writeConnection->sendRaw("JOIN #" + channel->name);
        this->readConnection->sendRaw("JOIN #" + channel->name);
    }

    this->writeConnection->open();
    this->readConnection->open();
}

void IrcManager::disconnect()
{
    std::lock_guard<std::mutex> locker(this->connectionMutex);

    this->readConnection->close();
    this->writeConnection->close();
}

void IrcManager::sendMessage(const QString &channelName, QString message)
{
    QString trimmedMessage = message.trimmed();
    if (trimmedMessage.isEmpty()) {
        return;
    }

    this->connectionMutex.lock();
    static int i = 0;

    if (this->writeConnection) {
        if (singletons::SettingManager::getInstance().allowDuplicateMessages && (++i % 2) == 0) {
            trimmedMessage.append(this->messageSuffix);
        }
        this->writeConnection->sendRaw("PRIVMSG #" + channelName + " :" + trimmedMessage);
    }

    this->connectionMutex.unlock();
}

void IrcManager::joinChannel(const QString &channelName)
{
    this->connectionMutex.lock();

    if (this->readConnection && this->writeConnection) {
        this->readConnection->sendRaw("JOIN #" + channelName);
        this->writeConnection->sendRaw("JOIN #" + channelName);
    }

    this->connectionMutex.unlock();
}

void IrcManager::partChannel(const QString &channelName)
{
    this->connectionMutex.lock();

    if (this->readConnection && this->writeConnection) {
        this->readConnection->sendRaw("PART #" + channelName);
        this->writeConnection->sendRaw("PART #" + channelName);
    }

    this->connectionMutex.unlock();
}

void IrcManager::privateMessageReceived(Communi::IrcPrivateMessage *message)
{
    this->onPrivateMessage.invoke(message);
    auto c = this->channelManager.getTwitchChannel(message->target().mid(1));

    if (!c) {
        return;
    }

    messages::MessageParseArgs args;

    twitch::TwitchMessageBuilder builder(c.get(), message, args);

    c->addMessage(builder.parse());
}

void IrcManager::messageReceived(Communi::IrcMessage *message)
{
    if (message->type() == Communi::IrcMessage::Type::Private) {
        // We already have a handler for private messages
        return;
    }

    const QString &command = message->command();

    if (command == "ROOMSTATE") {
        helper::IrcMessageHandler::getInstance().handleRoomStateMessage(message);
    } else if (command == "CLEARCHAT") {
        helper::IrcMessageHandler::getInstance().handleClearChatMessage(message);
    } else if (command == "USERSTATE") {
        helper::IrcMessageHandler::getInstance().handleUserStateMessage(message);
    } else if (command == "WHISPER") {
        helper::IrcMessageHandler::getInstance().handleWhisperMessage(message);
    } else if (command == "USERNOTICE") {
        helper::IrcMessageHandler::getInstance().handleUserNoticeMessage(message);
    } else if (command == "MODE") {
        helper::IrcMessageHandler::getInstance().handleModeMessage(message);
    } else if (command == "NOTICE") {
        helper::IrcMessageHandler::getInstance().handleNoticeMessage(
            static_cast<Communi::IrcNoticeMessage *>(message));
    }
}

void IrcManager::writeConnectionMessageReceived(Communi::IrcMessage *message)
{
    switch (message->type()) {
        case Communi::IrcMessage::Type::Notice: {
            helper::IrcMessageHandler::getInstance().handleWriteConnectionNoticeMessage(
                static_cast<Communi::IrcNoticeMessage *>(message));
        } break;
    }
}

// XXX: This does not fit in IrcManager
bool IrcManager::isTwitchUserBlocked(QString const &username)
{
    QMutexLocker locker(&this->twitchBlockedUsersMutex);

    auto iterator = this->twitchBlockedUsers.find(username);

    return iterator != this->twitchBlockedUsers.end();
}

// XXX: This does not fit in IrcManager
bool IrcManager::tryAddIgnoredUser(QString const &username, QString &errorMessage)
{
    assert(this->account);

    QUrl url("https://api.twitch.tv/kraken/users/" + this->account->getUserName() + "/blocks/" +
             username + "?oauth_token=" + this->account->getOAuthToken() +
             "&client_id=" + this->account->getOAuthClient());

    QNetworkRequest request(url);
    auto reply = this->networkAccessManager.put(request, QByteArray());
    reply->waitForReadyRead(10000);

    if (reply->error() == QNetworkReply::NoError) {
        this->twitchBlockedUsersMutex.lock();
        this->twitchBlockedUsers.insert(username, true);
        this->twitchBlockedUsersMutex.unlock();

        return true;
    }

    reply->deleteLater();

    errorMessage = "Error while ignoring user \"" + username + "\": " + reply->errorString();

    return false;
}

// XXX: This does not fit in IrcManager
void IrcManager::addIgnoredUser(QString const &username)
{
    QString errorMessage;
    if (!tryAddIgnoredUser(username, errorMessage)) {
        // TODO: Implement IrcManager::addIgnoredUser
    }
}

// XXX: This does not fit in IrcManager
bool IrcManager::tryRemoveIgnoredUser(QString const &username, QString &errorMessage)
{
    assert(this->account);

    QUrl url("https://api.twitch.tv/kraken/users/" + this->account->getUserName() + "/blocks/" +
             username + "?oauth_token=" + this->account->getOAuthToken() +
             "&client_id=" + this->account->getOAuthClient());

    QNetworkRequest request(url);
    auto reply = this->networkAccessManager.deleteResource(request);
    reply->waitForReadyRead(10000);

    if (reply->error() == QNetworkReply::NoError) {
        this->twitchBlockedUsersMutex.lock();
        this->twitchBlockedUsers.remove(username);
        this->twitchBlockedUsersMutex.unlock();

        return true;
    }

    reply->deleteLater();

    errorMessage = "Error while unignoring user \"" + username + "\": " + reply->errorString();

    return false;
}

// XXX: This does not fit in IrcManager
void IrcManager::removeIgnoredUser(QString const &username)
{
    QString errorMessage;
    if (!tryRemoveIgnoredUser(username, errorMessage)) {
        // TODO: Implement IrcManager::removeIgnoredUser
    }
}

void IrcManager::onConnected()
{
    std::shared_ptr<Message> msg(Message::createSystemMessage("connected to chat"));

    this->channelManager.doOnAll([msg](std::shared_ptr<Channel> channel) {
        assert(channel);
        channel->addMessage(msg);
    });
}

void IrcManager::onDisconnected()
{
    std::shared_ptr<Message> msg(Message::createSystemMessage("disconnected from chat"));

    this->channelManager.doOnAll([msg](std::shared_ptr<Channel> channel) {
        assert(channel);
        channel->addMessage(msg);
    });
}

Communi::IrcConnection *IrcManager::getReadConnection()
{
    return this->readConnection.get();
}

}  // namespace singletons
}  // namespace chatterino
<|endoftext|>


<commit_before>#include <limits>
#include <boost/foreach.hpp>
#include "BasicOffense122.hpp"

using namespace std;
using namespace Geometry2d;

REGISTER_PLAY_CATEGORY(Gameplay::Plays::BasicOffense122, "Playing")

namespace Gameplay
{
	namespace Plays
	{
		REGISTER_CONFIGURABLE(BasicOffense122)
	}
}

ConfigDouble *Gameplay::Plays::BasicOffense122::_offense_hysteresis;
ConfigDouble *Gameplay::Plays::BasicOffense122::_support_backoff_thresh;
ConfigDouble *Gameplay::Plays::BasicOffense122::_mark_hysteresis_coeff;
ConfigDouble *Gameplay::Plays::BasicOffense122::_support_avoid_teammate_radius;
ConfigDouble *Gameplay::Plays::BasicOffense122::_support_avoid_shot;
ConfigDouble *Gameplay::Plays::BasicOffense122::_offense_support_ratio;
ConfigDouble *Gameplay::Plays::BasicOffense122::_defense_support_ratio;
ConfigBool   *Gameplay::Plays::BasicOffense122::_use_line_kick;

void Gameplay::Plays::BasicOffense122::createConfiguration(Configuration *cfg)
{
	_offense_hysteresis = new ConfigDouble(cfg, "BasicOffense122/Hystersis Coeff", 0.50);
	_support_backoff_thresh = new ConfigDouble(cfg, "BasicOffense122/Support Backoff Dist", 1.5);
	_mark_hysteresis_coeff = new ConfigDouble(cfg, "BasicOffense122/Mark Hystersis Coeff", 0.9);
	_support_avoid_teammate_radius = new ConfigDouble(cfg, "BasicOffense122/Support Avoid Teammate Dist", 0.5);
	_support_avoid_shot = new ConfigDouble(cfg, "BasicOffense122/Support Avoid Shot", 0.2);
	_offense_support_ratio = new ConfigDouble(cfg, "BasicOffense122/Offense Support Ratio", 0.7);
	_defense_support_ratio = new ConfigDouble(cfg, "BasicOffense122/Defense Support Ratio", 0.9);
	_use_line_kick = new ConfigBool(cfg, "BasicOffense122/Enable Line Kick", true);
}

Gameplay::Plays::BasicOffense122::BasicOffense122(GameplayModule *gameplay):
Play(gameplay),
_leftFullback(gameplay, Behaviors::Fullback::Left),
_rightFullback(gameplay, Behaviors::Fullback::Right),
_striker(gameplay),
_support1(gameplay),
_support2(gameplay)
{
	_leftFullback.otherFullbacks.insert(&_rightFullback);
	_rightFullback.otherFullbacks.insert(&_leftFullback);

	// use constant value of mark threshold for now
	_support1.markLineThresh(1.0);
	_support2.markLineThresh(1.0);
}

float Gameplay::Plays::BasicOffense122::score ( Gameplay::GameplayModule* gameplay )
{
	// only run if we are playing and not in a restart
	bool refApplicable = gameplay->state()->gameState.playing();
	return refApplicable ? 0 : INFINITY;
}

bool Gameplay::Plays::BasicOffense122::run()
{
	// handle assignments
	set<OurRobot *> available = _gameplay->playRobots();

	// project the ball forward (dampened)
	const float proj_time = 0.75; // seconds to project
	const float dampen_factor = 0.9; // accounts for slowing over time
	Geometry2d::Point ballProj = ball().pos + ball().vel * proj_time * dampen_factor;

	// Get a striker first to ensure there a robot that can kick
	assignNearestKicker(_striker.robot, available, ballProj);

	// defense first - get closest to goal to choose sides properly
	assignNearest(_leftFullback.robot, available, Geometry2d::Point(-Field_GoalWidth/2, 0.0));
	assignNearest(_rightFullback.robot, available, Geometry2d::Point(Field_GoalWidth/2, 0.0));

	// choose offense, we want closest robot to ball to be striker
	assignNearest(_support1.robot, available, ballProj);
	if (_support1.robot)
		_support1.robot->addText("Support 1");
	assignNearest(_support2.robot, available, ballProj);
	if (_support2.robot)
		_support2.robot->addText("Support 2");

	// determine whether to change offense players
	bool forward_reset = false;
	if (_striker.robot && _support1.robot && _support2.robot &&
			(_support1.robot->pos.distTo(ballProj) < *_offense_hysteresis * _striker.robot->pos.distTo(ballProj)
				|| _support2.robot->pos.distTo(ballProj) < *_offense_hysteresis * _striker.robot->pos.distTo(ballProj))) {
		_striker.robot = NULL;
		_support1.robot = NULL;
		_support2.robot = NULL;
		_striker.restart();
		forward_reset = true;
	}

	// find the nearest opponent to the striker
	OpponentRobot* closestRobotToStriker = 0;
	float closestDistToStriker = numeric_limits<float>::infinity();
	if (_striker.robot) {
		BOOST_FOREACH(OpponentRobot* opp, state()->opp) {
			if (opp) {
				float d = opp->pos.distTo(_striker.robot->pos);
				if (d < closestDistToStriker) {
					closestDistToStriker = d;
					closestRobotToStriker = opp;
				}
			}
		}
	}
	bool striker_engaged = _striker.robot && closestDistToStriker < *_support_backoff_thresh;

	// pick as a mark target the furthest back opposing robot
	// and adjust mark ratio based on field position
	// find *two* furthest back opp robots
	OpponentRobot* bestOpp1 = NULL, *bestOpp2 = NULL;
	float bestDist1 = numeric_limits<float>::infinity(), bestDist2 = bestDist1;
	size_t nrOppClose = 0;
	BOOST_FOREACH(OpponentRobot* opp, state()->opp)
	{
		// use distance from goal rather than just y coordinate to handle corners better
		const float oppDistSq = opp->pos.magsq();
		if (opp && opp->visible &&
				   oppDistSq > 0.1 &&
				   !(striker_engaged && opp == closestRobotToStriker)
				   ) {
			if (oppDistSq <= bestDist1) {
				bestDist2 = bestDist1;
				bestDist1 = oppDistSq;
				bestOpp2 = bestOpp1;
				bestOpp1 = opp;
			} else if (oppDistSq <= bestDist2) {
				bestDist2 = oppDistSq;
				bestOpp2 = opp;
			}

			if (oppDistSq < Field_Length * Field_Length / 4.0) {
				++nrOppClose;
			}
		}
	}
	if (!bestOpp1 && _support1.robot) {
		_support1.robot->addText("No mark target");
		if(_striker.robot){
			// if nothing to mark, hang behind the striker on other side of the field
			_support1.robot->addText("Static Support");
			Point support_goal = _striker.robot->pos;
			support_goal.x *= -1.0;
			if (fabs(support_goal.x) < 0.2)
			{
				support_goal.x = (support_goal.x < 0.0) ? -1.0 : 1.0;
			}

			if (ballProj.y > Field_Length/2.0 && nrOppClose)
				support_goal.y = max(support_goal.y * (double)*_offense_support_ratio, 0.3);
			else
				support_goal.y = max(support_goal.y * (double)*_defense_support_ratio, 0.3);

			_support1.robot->move(support_goal);
			_support1.robot->face(ballProj);
		}
	}
	if (!bestOpp2 && _support2.robot) {
		_support2.robot->addText("No mark target");
		//TODO: something useful like wait for a rebound kick
	}
	bool marking_active_1 = bestOpp1 != 0;
	bool marking_active_2 = bestOpp2 != 0;

	// use hysteresis for changing of the robot
	float cur_dist1 = (_support1.markRobot()) ?	_support1.markRobot()->pos.distTo(ballProj) : numeric_limits<float>::infinity();
	float cur_dist2 = (_support2.markRobot()) ?	_support2.markRobot()->pos.distTo(ballProj) : numeric_limits<float>::infinity();
	if (bestOpp1 && bestOpp1->visible && (forward_reset || bestDist1 < cur_dist1 * cur_dist1 * (float)*_mark_hysteresis_coeff))
		_support1.markRobot(bestOpp1);
	if (bestOpp2 && bestOpp2->visible && (forward_reset || bestDist2 < cur_dist2 * cur_dist2 * (float)*_mark_hysteresis_coeff))
		_support2.markRobot(bestOpp2);

	// if we are further away, we can mark further from robot
	if (ballProj.y > Field_Length/2.0 && nrOppClose) {
		_support1.ratio(*_offense_support_ratio);
		_support2.ratio(*_offense_support_ratio);
	}
	else {
		_support1.ratio(*_defense_support_ratio);
		_support2.ratio(*_defense_support_ratio);
	}

	// adjust obstacles on striker and support
	if (_striker.robot) {
		unsigned striker = _striker.robot->shell();
		if (_support1.robot)
			_support1.robot->avoidTeammateRadius(striker, *_support_avoid_teammate_radius);
		if (_support2.robot)
			_support2.robot->avoidTeammateRadius(striker, *_support_avoid_teammate_radius);

		// get out of ways of shots
		if (_striker.robot->pos.nearPoint(ballProj, *_support_avoid_shot)) {
			Polygon shot_obs;
			shot_obs.vertices.push_back(Geometry2d::Point(Field_GoalWidth / 2, Field_Length));
			shot_obs.vertices.push_back(Geometry2d::Point(-Field_GoalWidth / 2, Field_Length));
			shot_obs.vertices.push_back(ballProj);
			if(_support1.robot)
				_support1.robot->localObstacles(ObstaclePtr(new PolygonObstacle(shot_obs)));
			if(_support1.robot)
				_support2.robot->localObstacles(ObstaclePtr(new PolygonObstacle(shot_obs)));
		}
	}

	// manually reset any kickers so they keep kicking
	if (_striker.done())
		_striker.restart();

	// set flags for inner behaviors
	_striker.use_line_kick = *_use_line_kick;
	if (_striker.robot)
	{
		_striker.calculateChipPower(_striker.robot->pos.distTo(ball().pos));
	}

	// execute behaviors
	if (_striker.robot) _striker.run();
	if (marking_active_1 && _support1.robot) _support1.run();
	if (marking_active_2 && _support2.robot) _support2.run();
	if (_leftFullback.robot) _leftFullback.run();
	if (_rightFullback.robot) _rightFullback.run();

	return true;
}
<commit_msg>Fixed null check in BasicOffense122<commit_after>#include <limits>
#include <boost/foreach.hpp>
#include "BasicOffense122.hpp"

using namespace std;
using namespace Geometry2d;

REGISTER_PLAY_CATEGORY(Gameplay::Plays::BasicOffense122, "Playing")

namespace Gameplay
{
	namespace Plays
	{
		REGISTER_CONFIGURABLE(BasicOffense122)
	}
}

ConfigDouble *Gameplay::Plays::BasicOffense122::_offense_hysteresis;
ConfigDouble *Gameplay::Plays::BasicOffense122::_support_backoff_thresh;
ConfigDouble *Gameplay::Plays::BasicOffense122::_mark_hysteresis_coeff;
ConfigDouble *Gameplay::Plays::BasicOffense122::_support_avoid_teammate_radius;
ConfigDouble *Gameplay::Plays::BasicOffense122::_support_avoid_shot;
ConfigDouble *Gameplay::Plays::BasicOffense122::_offense_support_ratio;
ConfigDouble *Gameplay::Plays::BasicOffense122::_defense_support_ratio;
ConfigBool   *Gameplay::Plays::BasicOffense122::_use_line_kick;

void Gameplay::Plays::BasicOffense122::createConfiguration(Configuration *cfg)
{
	_offense_hysteresis = new ConfigDouble(cfg, "BasicOffense122/Hystersis Coeff", 0.50);
	_support_backoff_thresh = new ConfigDouble(cfg, "BasicOffense122/Support Backoff Dist", 1.5);
	_mark_hysteresis_coeff = new ConfigDouble(cfg, "BasicOffense122/Mark Hystersis Coeff", 0.9);
	_support_avoid_teammate_radius = new ConfigDouble(cfg, "BasicOffense122/Support Avoid Teammate Dist", 0.5);
	_support_avoid_shot = new ConfigDouble(cfg, "BasicOffense122/Support Avoid Shot", 0.2);
	_offense_support_ratio = new ConfigDouble(cfg, "BasicOffense122/Offense Support Ratio", 0.7);
	_defense_support_ratio = new ConfigDouble(cfg, "BasicOffense122/Defense Support Ratio", 0.9);
	_use_line_kick = new ConfigBool(cfg, "BasicOffense122/Enable Line Kick", true);
}

Gameplay::Plays::BasicOffense122::BasicOffense122(GameplayModule *gameplay):
Play(gameplay),
_leftFullback(gameplay, Behaviors::Fullback::Left),
_rightFullback(gameplay, Behaviors::Fullback::Right),
_striker(gameplay),
_support1(gameplay),
_support2(gameplay)
{
	_leftFullback.otherFullbacks.insert(&_rightFullback);
	_rightFullback.otherFullbacks.insert(&_leftFullback);

	// use constant value of mark threshold for now
	_support1.markLineThresh(1.0);
	_support2.markLineThresh(1.0);
}

float Gameplay::Plays::BasicOffense122::score ( Gameplay::GameplayModule* gameplay )
{
	// only run if we are playing and not in a restart
	bool refApplicable = gameplay->state()->gameState.playing();
	return refApplicable ? 0 : INFINITY;
}

bool Gameplay::Plays::BasicOffense122::run()
{
	// handle assignments
	set<OurRobot *> available = _gameplay->playRobots();

	// project the ball forward (dampened)
	const float proj_time = 0.75; // seconds to project
	const float dampen_factor = 0.9; // accounts for slowing over time
	Geometry2d::Point ballProj = ball().pos + ball().vel * proj_time * dampen_factor;

	// Get a striker first to ensure there a robot that can kick
	assignNearestKicker(_striker.robot, available, ballProj);

	// defense first - get closest to goal to choose sides properly
	assignNearest(_leftFullback.robot, available, Geometry2d::Point(-Field_GoalWidth/2, 0.0));
	assignNearest(_rightFullback.robot, available, Geometry2d::Point(Field_GoalWidth/2, 0.0));

	// choose offense, we want closest robot to ball to be striker
	assignNearest(_support1.robot, available, ballProj);
	if (_support1.robot)
		_support1.robot->addText("Support 1");
	assignNearest(_support2.robot, available, ballProj);
	if (_support2.robot)
		_support2.robot->addText("Support 2");

	// determine whether to change offense players
	bool forward_reset = false;
	if (_striker.robot && _support1.robot && _support2.robot &&
			(_support1.robot->pos.distTo(ballProj) < *_offense_hysteresis * _striker.robot->pos.distTo(ballProj)
				|| _support2.robot->pos.distTo(ballProj) < *_offense_hysteresis * _striker.robot->pos.distTo(ballProj))) {
		_striker.robot = NULL;
		_support1.robot = NULL;
		_support2.robot = NULL;
		_striker.restart();
		forward_reset = true;
	}

	// find the nearest opponent to the striker
	OpponentRobot* closestRobotToStriker = 0;
	float closestDistToStriker = numeric_limits<float>::infinity();
	if (_striker.robot) {
		BOOST_FOREACH(OpponentRobot* opp, state()->opp) {
			if (opp) {
				float d = opp->pos.distTo(_striker.robot->pos);
				if (d < closestDistToStriker) {
					closestDistToStriker = d;
					closestRobotToStriker = opp;
				}
			}
		}
	}
	bool striker_engaged = _striker.robot && closestDistToStriker < *_support_backoff_thresh;

	// pick as a mark target the furthest back opposing robot
	// and adjust mark ratio based on field position
	// find *two* furthest back opp robots
	OpponentRobot* bestOpp1 = NULL, *bestOpp2 = NULL;
	float bestDist1 = numeric_limits<float>::infinity(), bestDist2 = bestDist1;
	size_t nrOppClose = 0;
	BOOST_FOREACH(OpponentRobot* opp, state()->opp)
	{
		// use distance from goal rather than just y coordinate to handle corners better
		const float oppDistSq = opp->pos.magsq();
		if (opp && opp->visible &&
				   oppDistSq > 0.1 &&
				   !(striker_engaged && opp == closestRobotToStriker)
				   ) {
			if (oppDistSq <= bestDist1) {
				bestDist2 = bestDist1;
				bestDist1 = oppDistSq;
				bestOpp2 = bestOpp1;
				bestOpp1 = opp;
			} else if (oppDistSq <= bestDist2) {
				bestDist2 = oppDistSq;
				bestOpp2 = opp;
			}

			if (oppDistSq < Field_Length * Field_Length / 4.0) {
				++nrOppClose;
			}
		}
	}
	if (!bestOpp1 && _support1.robot) {
		_support1.robot->addText("No mark target");
		if(_striker.robot){
			// if nothing to mark, hang behind the striker on other side of the field
			_support1.robot->addText("Static Support");
			Point support_goal = _striker.robot->pos;
			support_goal.x *= -1.0;
			if (fabs(support_goal.x) < 0.2)
			{
				support_goal.x = (support_goal.x < 0.0) ? -1.0 : 1.0;
			}

			if (ballProj.y > Field_Length/2.0 && nrOppClose)
				support_goal.y = max(support_goal.y * (double)*_offense_support_ratio, 0.3);
			else
				support_goal.y = max(support_goal.y * (double)*_defense_support_ratio, 0.3);

			_support1.robot->move(support_goal);
			_support1.robot->face(ballProj);
		}
	}
	if (!bestOpp2 && _support2.robot) {
		_support2.robot->addText("No mark target");
		//TODO: something useful like wait for a rebound kick
	}
	bool marking_active_1 = bestOpp1 != 0;
	bool marking_active_2 = bestOpp2 != 0;

	// use hysteresis for changing of the robot
	float cur_dist1 = (_support1.markRobot()) ?	_support1.markRobot()->pos.distTo(ballProj) : numeric_limits<float>::infinity();
	float cur_dist2 = (_support2.markRobot()) ?	_support2.markRobot()->pos.distTo(ballProj) : numeric_limits<float>::infinity();
	if (bestOpp1 && bestOpp1->visible && (forward_reset || bestDist1 < cur_dist1 * cur_dist1 * (float)*_mark_hysteresis_coeff))
		_support1.markRobot(bestOpp1);
	if (bestOpp2 && bestOpp2->visible && (forward_reset || bestDist2 < cur_dist2 * cur_dist2 * (float)*_mark_hysteresis_coeff))
		_support2.markRobot(bestOpp2);

	// if we are further away, we can mark further from robot
	if (ballProj.y > Field_Length/2.0 && nrOppClose) {
		_support1.ratio(*_offense_support_ratio);
		_support2.ratio(*_offense_support_ratio);
	}
	else {
		_support1.ratio(*_defense_support_ratio);
		_support2.ratio(*_defense_support_ratio);
	}

	// adjust obstacles on striker and support
	if (_striker.robot) {
		unsigned striker = _striker.robot->shell();
		if (_support1.robot)
			_support1.robot->avoidTeammateRadius(striker, *_support_avoid_teammate_radius);
		if (_support2.robot)
			_support2.robot->avoidTeammateRadius(striker, *_support_avoid_teammate_radius);

		// get out of ways of shots
		if (_striker.robot->pos.nearPoint(ballProj, *_support_avoid_shot)) {
			Polygon shot_obs;
			shot_obs.vertices.push_back(Geometry2d::Point(Field_GoalWidth / 2, Field_Length));
			shot_obs.vertices.push_back(Geometry2d::Point(-Field_GoalWidth / 2, Field_Length));
			shot_obs.vertices.push_back(ballProj);
			if(_support1.robot)
				_support1.robot->localObstacles(ObstaclePtr(new PolygonObstacle(shot_obs)));
			if(_support2.robot)
				_support2.robot->localObstacles(ObstaclePtr(new PolygonObstacle(shot_obs)));
		}
	}

	// manually reset any kickers so they keep kicking
	if (_striker.done())
		_striker.restart();

	// set flags for inner behaviors
	_striker.use_line_kick = *_use_line_kick;
	if (_striker.robot)
	{
		_striker.calculateChipPower(_striker.robot->pos.distTo(ball().pos));
	}

	// execute behaviors
	if (_striker.robot) _striker.run();
	if (marking_active_1 && _support1.robot) _support1.run();
	if (marking_active_2 && _support2.robot) _support2.run();
	if (_leftFullback.robot) _leftFullback.run();
	if (_rightFullback.robot) _rightFullback.run();

	return true;
}
<|endoftext|>


<commit_before>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.04
 * @brief Implementation of NetworkConnection class
 */

#include <iostream>
#include <cstdlib>
#include <cassert>
#include <algorithm>

#include <SDL.h>

#include "network_connection.hxx"
#include "network_assembly.hxx"
#include "network_geraet.hxx"
#include "antenna.hxx"
#include "tuner.hxx"
#include "io.hxx"
#include "synchronous_control_geraet.hxx"
#include "async_ack_geraet.hxx"
#include "lat_disc_geraet.hxx"

#include "xxx/xnetobj.hxx"

#include "src/sim/game_field.hxx"
#include "src/sim/game_object.hxx"
#include "src/core/lxn.hxx"
#include "src/exit_conditions.hxx"

using namespace std;

/* How long to wait without hearing any response before
 * killing the connection.
 */
#define DISCONNECT_TIME 2048

/* Maximum distance between reference and transient where we
 * still export that transient.
 */
#define TRANSIENT_DIST 7.0f

NetworkConnection::geraetNumMap_t* NetworkConnection::geraetNumMap;

NetworkConnection::NetworkConnection(NetworkAssembly* assembly_,
                                     const Antenna::endpoint& endpoint_,
                                     bool incomming)
: field(assembly_->field->width, assembly_->field->height),
  nextOutSeq(incomming? 0 : 1),
  greatestSeq(0),
  latency(128),
  lastIncommingTime(SDL_GetTicks()),
  status(incomming? Established : Connecting),
  timeSinceRetriedTransients(0),
  endpoint(endpoint_),
  parent(assembly_),
  scg(new SynchronousControlGeraet(this, incomming)),
  aag(new AsyncAckGeraet(this)),
  ldg(new LatDiscGeraet(this))
{
  inchannels[0] = scg;
  outchannels[0] = scg;

  if (incomming)
    scg->transmitAck(0);

  //Open standard channels
  scg->openChannel(aag, aag->num);
  scg->openChannel(ldg, ldg->num);

  parent->getTuner()->connect(endpoint, this);
}

NetworkConnection::~NetworkConnection() {
  parent->getTuner()->disconnect(endpoint);

  for (inchannels_t::const_iterator it = inchannels.begin();
       it != inchannels.end(); ++it)
    if (it->second->deletionStrategy != InputNetworkGeraet::DSIntrinsic)
      delete it->second;
  for (outchannels_t::const_iterator it = outchannels.begin();
       it != outchannels.end(); ++it)
    if (it->second->deletionStrategy == OutputNetworkGeraet::DSNormal)
      delete it->second;

  delete aag;
  delete scg;
}

void NetworkConnection::update(unsigned et) noth {
  field.update(et);
  for (inchannels_t::const_iterator it = inchannels.begin();
       it != inchannels.end(); ++it)
    it->second->inputUpdate(et);
  for (outchannels_t::const_iterator it = outchannels.begin();
       it != outchannels.end(); ++it)
    it->second->update(et);

  //TODO: Only process objects if in Ready status
  timeSinceRetriedTransients += et;
  if (timeSinceRetriedTransients > 128) {
    candidateExports.insert(candidateExports.end(),
                            ignoredExports.begin(),
                            ignoredExports.end());
    ignoredExports.clear();
    timeSinceRetriedTransients = 0;
  }
  //Export candidates that are close enough or non-transient
  while (!candidateExports.empty()) {
    GameObject* go = candidateExports.front();
    candidateExports.pop_front();
    if (!go->isTransient || distanceOf(go) < TRANSIENT_DIST*TRANSIENT_DIST) {
      actualExports.insert(go);
      createObjectExport(this, go);
    } else {
      ignoredExports.insert(go);
    }
  }

  if (lastIncommingTime + DISCONNECT_TIME < SDL_GetTicks()) {
    scg->closeConnection("Timed out", "timed_out");
  }
}

void NetworkConnection::process(const Antenna::endpoint& source,
                                Antenna* antenna, Tuner* tuner,
                                const byte* data, unsigned datlen)
noth {
  if (datlen < 4) {
    //Packet does not even have a header
    #ifdef DEBUG
    cerr << "Warning: Dropping packet of length " << datlen
         << " from source " << source << endl;
    #endif
    return;
  }

  channel chan;
  seq_t seq;
  io::read(data, seq);
  io::read(data, chan);
  datlen -= 4;
  cout << "Receive seq=" << seq << " on chan=" << chan
       << " with length=" << datlen << " from " << source << endl;

  //Range check
  if (seq-greatestSeq < 1024 || greatestSeq-seq < 1024) {
    //Dupe check
    if (recentlyReceived.count(seq) == 0) {
      //Possibly update greatestSeq
      if (seq-greatestSeq < 1024)
        greatestSeq = seq;

      //OK, add to set and queue, possibly trim both
      recentlyReceived.insert(seq);
      recentlyReceivedQueue.push_back(seq);
      if (recentlyReceivedQueue.size() > 1024) {
        recentlyReceived.erase(recentlyReceivedQueue.front());
        recentlyReceivedQueue.pop_front();
      }

      //Update time of most recent receive
      lastIncommingTime = SDL_GetTicks();

      //Accept packet; does the channel exist?
      inchannels_t::const_iterator it = inchannels.find(chan);
      if (it != inchannels.end()) {
        it->second->receive(seq, data, datlen);
      } else {
        #ifdef DEBUG
        cerr << "Warning: Dropping packet to closed channel " << chan
             << " from source " << source << endl;
        #endif
      }
    }
  } else {
    #ifdef DEBUG
    cerr << "Warning: Dropping packet of seq " << seq
         << " due to range check; greatestSeq = " << greatestSeq
         << "; from source " << source << endl;
    #endif
  }
}

NetworkConnection::seq_t NetworkConnection::seq() noth {
  //Check for network collapse
  if (locked[nextOutSeq]) {
    //Kill the connection
    //First, unlock everything so infinite recursion does not result
    locked.reset();
    scg->closeConnection("Network collapse", "network_collapse");
  }
  return nextOutSeq++;
}

NetworkConnection::seq_t NetworkConnection::writeHeader(byte*& dst,
                                                        channel chan)
noth {
  seq_t s = seq();
  io::write(dst, s);
  io::write(dst, chan);
  return s;
}

void NetworkConnection::send(const byte* data, unsigned len) throw() {
  try {
    parent->antenna->send(endpoint, data, len);
  } catch (asio::system_error e) {
    cerr << "Network system error: " << e.what() << endl;
    status = Zombie;
    SL10N(disconnectReason, network, system_error);
  }
}

NetworkConnection::geraet_num
NetworkConnection::registerGeraetCreator(geraet_creator fun,
                                         geraet_num preferred) {
  static bool hasInitialised = false;
  static geraet_num nextAuto = 32768;
  //Allocate map if not done yet
  if (!hasInitialised) {
    geraetNumMap = new geraetNumMap_t;
    hasInitialised = true;
  }

  geraet_num number = preferred;

  if (number == (geraet_num)~(geraet_num)0)
    number = nextAuto++;

  if (geraetNumMap->count(number)) {
    cerr << "FATAL: Duplicate Geraet number: " << number << endl;
    exit(EXIT_PROGRAM_BUG);
  }

  geraetNumMap->insert(make_pair(number, fun));
  return number;
}

NetworkConnection::geraet_creator
NetworkConnection::getGeraetCreator(geraet_num num) {
  assert(geraetNumMap->count(num));
  return (*geraetNumMap)[num];
}

void NetworkConnection::setReference(GameObject* go) throw() {
  remoteReferences.push_back(go);
}

void NetworkConnection::unsetReference(GameObject* go) throw() {
  vector<GameObject*>::iterator it =
      find(remoteReferences.begin(), remoteReferences.end(), go);
  if (it != remoteReferences.end())
    remoteReferences.erase(it);
}

float NetworkConnection::distanceOf(const GameObject* go) const throw() {
  float mindist = INFINITY;
  for (unsigned i=0; i<remoteReferences.size(); ++i) {
    const GameObject* that = remoteReferences[i];
    float dx = go->getX() - that->getX();
    float dy = go->getY() - that->getY();
    float d = dx*dx + dy*dy;
    if (d < mindist)
      mindist = d;
  }
  return mindist;
}

void NetworkConnection::objectAdded(GameObject* go) throw() {
  candidateExports.push_back(go);
}

void NetworkConnection::objectRemoved(GameObject* go) throw() {
  deque<GameObject*>::iterator dit =
      find(candidateExports.begin(), candidateExports.end(), go);
  if (dit != candidateExports.end())
    candidateExports.erase(dit);

  actualExports.erase(go);
  ignoredExports.erase(go);
  unsetReference(go);
}
<commit_msg>Fix NetworkConnection leaking LatDiscGeraete.<commit_after>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.04
 * @brief Implementation of NetworkConnection class
 */

#include <iostream>
#include <cstdlib>
#include <cassert>
#include <algorithm>

#include <SDL.h>

#include "network_connection.hxx"
#include "network_assembly.hxx"
#include "network_geraet.hxx"
#include "antenna.hxx"
#include "tuner.hxx"
#include "io.hxx"
#include "synchronous_control_geraet.hxx"
#include "async_ack_geraet.hxx"
#include "lat_disc_geraet.hxx"

#include "xxx/xnetobj.hxx"

#include "src/sim/game_field.hxx"
#include "src/sim/game_object.hxx"
#include "src/core/lxn.hxx"
#include "src/exit_conditions.hxx"

using namespace std;

/* How long to wait without hearing any response before
 * killing the connection.
 */
#define DISCONNECT_TIME 2048

/* Maximum distance between reference and transient where we
 * still export that transient.
 */
#define TRANSIENT_DIST 7.0f

NetworkConnection::geraetNumMap_t* NetworkConnection::geraetNumMap;

NetworkConnection::NetworkConnection(NetworkAssembly* assembly_,
                                     const Antenna::endpoint& endpoint_,
                                     bool incomming)
: field(assembly_->field->width, assembly_->field->height),
  nextOutSeq(incomming? 0 : 1),
  greatestSeq(0),
  latency(128),
  lastIncommingTime(SDL_GetTicks()),
  status(incomming? Established : Connecting),
  timeSinceRetriedTransients(0),
  endpoint(endpoint_),
  parent(assembly_),
  scg(new SynchronousControlGeraet(this, incomming)),
  aag(new AsyncAckGeraet(this)),
  ldg(new LatDiscGeraet(this))
{
  inchannels[0] = scg;
  outchannels[0] = scg;

  if (incomming)
    scg->transmitAck(0);

  //Open standard channels
  scg->openChannel(aag, aag->num);
  scg->openChannel(ldg, ldg->num);

  parent->getTuner()->connect(endpoint, this);
}

NetworkConnection::~NetworkConnection() {
  parent->getTuner()->disconnect(endpoint);

  for (inchannels_t::const_iterator it = inchannels.begin();
       it != inchannels.end(); ++it)
    if (it->second->deletionStrategy != InputNetworkGeraet::DSIntrinsic)
      delete it->second;
  for (outchannels_t::const_iterator it = outchannels.begin();
       it != outchannels.end(); ++it)
    if (it->second->deletionStrategy == OutputNetworkGeraet::DSNormal)
      delete it->second;

  delete aag;
  delete scg;
  delete ldg;
}

void NetworkConnection::update(unsigned et) noth {
  field.update(et);
  for (inchannels_t::const_iterator it = inchannels.begin();
       it != inchannels.end(); ++it)
    it->second->inputUpdate(et);
  for (outchannels_t::const_iterator it = outchannels.begin();
       it != outchannels.end(); ++it)
    it->second->update(et);

  //TODO: Only process objects if in Ready status
  timeSinceRetriedTransients += et;
  if (timeSinceRetriedTransients > 128) {
    candidateExports.insert(candidateExports.end(),
                            ignoredExports.begin(),
                            ignoredExports.end());
    ignoredExports.clear();
    timeSinceRetriedTransients = 0;
  }
  //Export candidates that are close enough or non-transient
  while (!candidateExports.empty()) {
    GameObject* go = candidateExports.front();
    candidateExports.pop_front();
    if (!go->isTransient || distanceOf(go) < TRANSIENT_DIST*TRANSIENT_DIST) {
      actualExports.insert(go);
      createObjectExport(this, go);
    } else {
      ignoredExports.insert(go);
    }
  }

  if (lastIncommingTime + DISCONNECT_TIME < SDL_GetTicks()) {
    scg->closeConnection("Timed out", "timed_out");
  }
}

void NetworkConnection::process(const Antenna::endpoint& source,
                                Antenna* antenna, Tuner* tuner,
                                const byte* data, unsigned datlen)
noth {
  if (datlen < 4) {
    //Packet does not even have a header
    #ifdef DEBUG
    cerr << "Warning: Dropping packet of length " << datlen
         << " from source " << source << endl;
    #endif
    return;
  }

  channel chan;
  seq_t seq;
  io::read(data, seq);
  io::read(data, chan);
  datlen -= 4;
  //Suppress messages from channel 1 since it is not interesting
  if (chan != 1)
    cout << "Receive seq=" << seq << " on chan=" << chan
         << " with length=" << datlen << " from " << source
         << " (latency=" << latency << " ms)" << endl;

  //Range check
  if (seq-greatestSeq < 1024 || greatestSeq-seq < 1024) {
    //Dupe check
    if (recentlyReceived.count(seq) == 0) {
      //Possibly update greatestSeq
      if (seq-greatestSeq < 1024)
        greatestSeq = seq;

      //OK, add to set and queue, possibly trim both
      recentlyReceived.insert(seq);
      recentlyReceivedQueue.push_back(seq);
      if (recentlyReceivedQueue.size() > 1024) {
        recentlyReceived.erase(recentlyReceivedQueue.front());
        recentlyReceivedQueue.pop_front();
      }

      //Update time of most recent receive
      lastIncommingTime = SDL_GetTicks();

      //Accept packet; does the channel exist?
      inchannels_t::const_iterator it = inchannels.find(chan);
      if (it != inchannels.end()) {
        it->second->receive(seq, data, datlen);
      } else {
        #ifdef DEBUG
        cerr << "Warning: Dropping packet to closed channel " << chan
             << " from source " << source << endl;
        #endif
      }
    }
  } else {
    #ifdef DEBUG
    cerr << "Warning: Dropping packet of seq " << seq
         << " due to range check; greatestSeq = " << greatestSeq
         << "; from source " << source << endl;
    #endif
  }
}

NetworkConnection::seq_t NetworkConnection::seq() noth {
  //Check for network collapse
  if (locked[nextOutSeq]) {
    //Kill the connection
    //First, unlock everything so infinite recursion does not result
    locked.reset();
    scg->closeConnection("Network collapse", "network_collapse");
  }
  return nextOutSeq++;
}

NetworkConnection::seq_t NetworkConnection::writeHeader(byte*& dst,
                                                        channel chan)
noth {
  seq_t s = seq();
  io::write(dst, s);
  io::write(dst, chan);
  return s;
}

void NetworkConnection::send(const byte* data, unsigned len) throw() {
  try {
    parent->antenna->send(endpoint, data, len);
  } catch (asio::system_error e) {
    cerr << "Network system error: " << e.what() << endl;
    status = Zombie;
    SL10N(disconnectReason, network, system_error);
  }
}

NetworkConnection::geraet_num
NetworkConnection::registerGeraetCreator(geraet_creator fun,
                                         geraet_num preferred) {
  static bool hasInitialised = false;
  static geraet_num nextAuto = 32768;
  //Allocate map if not done yet
  if (!hasInitialised) {
    geraetNumMap = new geraetNumMap_t;
    hasInitialised = true;
  }

  geraet_num number = preferred;

  if (number == (geraet_num)~(geraet_num)0)
    number = nextAuto++;

  if (geraetNumMap->count(number)) {
    cerr << "FATAL: Duplicate Geraet number: " << number << endl;
    exit(EXIT_PROGRAM_BUG);
  }

  geraetNumMap->insert(make_pair(number, fun));
  return number;
}

NetworkConnection::geraet_creator
NetworkConnection::getGeraetCreator(geraet_num num) {
  assert(geraetNumMap->count(num));
  return (*geraetNumMap)[num];
}

void NetworkConnection::setReference(GameObject* go) throw() {
  remoteReferences.push_back(go);
}

void NetworkConnection::unsetReference(GameObject* go) throw() {
  vector<GameObject*>::iterator it =
      find(remoteReferences.begin(), remoteReferences.end(), go);
  if (it != remoteReferences.end())
    remoteReferences.erase(it);
}

float NetworkConnection::distanceOf(const GameObject* go) const throw() {
  float mindist = INFINITY;
  for (unsigned i=0; i<remoteReferences.size(); ++i) {
    const GameObject* that = remoteReferences[i];
    float dx = go->getX() - that->getX();
    float dy = go->getY() - that->getY();
    float d = dx*dx + dy*dy;
    if (d < mindist)
      mindist = d;
  }
  return mindist;
}

void NetworkConnection::objectAdded(GameObject* go) throw() {
  candidateExports.push_back(go);
}

void NetworkConnection::objectRemoved(GameObject* go) throw() {
  deque<GameObject*>::iterator dit =
      find(candidateExports.begin(), candidateExports.end(), go);
  if (dit != candidateExports.end())
    candidateExports.erase(dit);

  actualExports.erase(go);
  ignoredExports.erase(go);
  unsetReference(go);
}
<|endoftext|>