From 6bfcc1283f99af4e3577ccf169c19e00c4aa02cc Mon Sep 17 00:00:00 2001 From: Carlos Fernandez Date: Wed, 10 Nov 2010 23:37:16 -0500 Subject: [PATCH] Implemented Metagames attached to Generations --- nbproject/project.xml | 37 ++-- resources/metagames.xml | 232 +++++++++++---------- src/database/DatabaseRegistry.cpp | 9 +- src/database/DatabaseRegistry.h | 2 +- src/main/main.cpp | 6 +- src/matchmaking/MetagameList.cpp | 180 +++++++++++++--- src/matchmaking/MetagameList.h | 31 ++- src/network/NetworkBattle.cpp | 11 +- src/network/NetworkBattle.h | 2 +- src/network/network.cpp | 328 ++++++++++++++++++------------ src/network/network.h | 7 +- src/scripting/FieldObject.cpp | 11 +- src/shoddybattle/BattleField.cpp | 10 +- src/shoddybattle/BattleField.h | 10 +- 14 files changed, 556 insertions(+), 320 deletions(-) diff --git a/nbproject/project.xml b/nbproject/project.xml index 1fb77ee..9539d75 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -1,15 +1,22 @@ - - - org.netbeans.modules.cnd.makeproject - - - ShoddyBattle2 - 0 - c - cpp - h - UTF-8 - - - - + + + org.netbeans.modules.cnd.makeproject + + + ShoddyBattle2 + 0 + c + cpp + h + UTF-8 + + + src + + + Debug + Release + + + + diff --git a/resources/metagames.xml b/resources/metagames.xml index 816675a..93ba6df 100644 --- a/resources/metagames.xml +++ b/resources/metagames.xml @@ -2,111 +2,131 @@ This file specifies the definitions for the various metagames that can be played using the matchmaking facility on the server. --> + + + + Generation 4 + + + Standard + Standard OU metagame. + 1 + 6 + + Arceus + Darkrai + Deoxys + Deoxys-e + Deoxys-l + Deoxys-f + Dialga + Garchomp + Giratina + Giratina-o + Groudon + Ho-oh + Kyogre + Latios + Lugia + Manaphy + Mew + Mewtwo + Palkia + Rayquaza + Shaymin-s + Wobbuffet + Wynaut + + + Classic Sleep Clause + OHKO Clause + Classic Freeze Clause + Strict Damage Clause + Evasion Clause + Griseous Orb Limitation + + + 300 + 3 + 30 + + - + + Uber + Uber metagame. + 1 + 6 + + + + Classic Sleep Clause + OHKO Clause + Classic Freeze Clause + Strict Damage Clause + Evasion Clause + Griseous Orb Limitation + + + 300 + 3 + 30 + + - - Standard - standard - Standard OU metagame with Uber pokemon banned. - 1 - 6 - - Arceus - Darkrai - Deoxys - Deoxys-e - Deoxys-l - Deoxys-f - Dialga - Garchomp - Giratina - Giratina-o - Groudon - Ho-oh - Kyogre - Latios - Lugia - Manaphy - Mew - Mewtwo - Palkia - Rayquaza - Shaymin-s - Wobbuffet - Wynaut - - - Classic Sleep Clause - OHKO Clause - Classic Freeze Clause - Strict Damage Clause - Evasion Clause - Griseous Orb Limitation - - - 300 - 3 - 30 - - - - - Uber - uber - Uber metagame. - 1 - 6 - - - - Classic Sleep Clause - OHKO Clause - Classic Freeze Clause - Strict Damage Clause - Evasion Clause - Griseous Orb Limitation - - - 300 - 3 - 30 - - - - - - VGC - vgc - Basic VGC rules - 2 - 4 - - Arceus - Celebi - Darkrai - Deoxys - Deoxys-e - Deoxys-l - Deoxys-f - Jirachi - Manaphy - Phione - Shaymin - Mew - - - Species Clause - Item Clause - Soul Dew Clause - Strict Damage Clause - Griseous Orb Limitation - - - 300 - 3 - 30 - - - - + + VGC + Basic VGC rules + 2 + 4 + + Arceus + Celebi + Darkrai + Deoxys + Deoxys-e + Deoxys-l + Deoxys-f + Jirachi + Manaphy + Phione + Shaymin + Mew + + + Species Clause + Item Clause + Soul Dew Clause + Strict Damage Clause + Griseous Orb Limitation + + + 300 + 3 + 30 + + + + + + Super Test + + + Best Uber + BEST Uber metagame. + 1 + 6 + + + + OHKO Clause + + + 300 + 3 + 30 + + + + + \ No newline at end of file diff --git a/src/database/DatabaseRegistry.cpp b/src/database/DatabaseRegistry.cpp index 2f74569..65d6671 100644 --- a/src/database/DatabaseRegistry.cpp +++ b/src/database/DatabaseRegistry.cpp @@ -377,14 +377,9 @@ double DatabaseRegistry::getRatingEstimate(const int id, const std::string &ladd } DatabaseRegistry::ESTIMATE_LIST DatabaseRegistry::getEstimates(const int id, - const std::vector &metagames) { + const std::vector &metagames) { ESTIMATE_LIST list; - vector::const_iterator i = metagames.begin(); - for(; i != metagames.end(); ++i) { - MetagamePtr p = *i; - double estimate = getRatingEstimate(id, p->getId()); - list.push_back(ESTIMATE_ELEMENT(p->getIdx(), estimate)); - } + // TODO: Think on the format of ladder stats. Until then, return blank return list; } diff --git a/src/database/DatabaseRegistry.h b/src/database/DatabaseRegistry.h index bc30f98..dba7bff 100644 --- a/src/database/DatabaseRegistry.h +++ b/src/database/DatabaseRegistry.h @@ -202,7 +202,7 @@ class DatabaseRegistry { * Get a user's ladder estimates */ ESTIMATE_LIST getEstimates(const int id, - const std::vector &metagames); + const std::vector &metagames); /** * Initialise the tables required for a ladder. diff --git a/src/main/main.cpp b/src/main/main.cpp index 0b8eb57..0765ff5 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -284,6 +284,7 @@ int initialise(int argc, char **argv, bool &daemon) { network::Server server(port, userLimit); server.installSignalHandlers(); + server.readMetagames("resources/metagames.xml"); ScriptMachine *machine = server.getMachine(); machine->acquireContext()->runFile("resources/main.js"); @@ -306,10 +307,11 @@ int initialise(int argc, char **argv, bool &daemon) { } registry->createDefaultDatabase(); - + server.initialiseWelcomeMessage(serverName, welcomeMessage); server.initialiseChannels(); - server.initialiseMatchmaking("resources/metagames.xml"); + server.initialiseMetagames(); + server.initialiseMatchmaking(); server.initialiseClauses(); network::NetworkBattle::startTimerThread(); diff --git a/src/matchmaking/MetagameList.cpp b/src/matchmaking/MetagameList.cpp index 6996072..9924331 100644 --- a/src/matchmaking/MetagameList.cpp +++ b/src/matchmaking/MetagameList.cpp @@ -48,36 +48,94 @@ struct Metagame::MetagameImpl { string m_id; int m_idx; string m_description; - int m_generation; + Generation *m_generation; int m_partySize; int m_maxTeamLength; set m_banList; + set m_banListProto; vector m_clauses; network::TimerOptions m_timerOptions; - void getMetagame(SpeciesDatabase *, DOMElement *); + void getMetagame(DOMElement *); + + void initialise(SpeciesDatabase *species) { + set::iterator i = m_banListProto.begin(); + for (; i != m_banListProto.end(); ++i) { + string name = *i; + const PokemonSpecies *p = species->getSpecies(name); + if (!p) { + Log::out() << "Unknown species: " << name << endl; + } else { + m_banList.insert(p->getSpeciesId()); + } + } + } +}; + +struct Generation::GenerationImpl { + Generation *m_owner; + string m_id; + string m_name; + int m_idx; + vector m_metagames; + + void getGeneration(DOMElement *); + + void getMetagameClauses(const int idx, vector &ret) { + const int metagamesize = m_metagames.size(); + if ((idx < 0) || (idx > metagamesize)) { + return; + } + + MetagamePtr p = m_metagames[idx]; + const vector &clauses = p->getClauses(); + const int size = clauses.size(); + for (int i = 0; i < size; ++i) { + ret.push_back(clauses[i]); + } + } + + void getMetagameBans(const int idx, set &ret) { + const int metagameSize = m_metagames.size(); + if ((idx < 0) || (idx > metagameSize)) { + return; + } + + MetagamePtr p = m_metagames[idx]; + const set &bans = p->getBanList(); + set::const_iterator i = bans.begin(); + for (; i != bans.end(); ++i) { + ret.insert(*i); + } + } + + void initialiseMetagames(SpeciesDatabase *species) { + vector::iterator i = m_metagames.begin(); + for (; i != m_metagames.end(); ++i) { + (*i)->initialise(species); + } + } }; int getIntNodeValue(DOMNode *node); string getStringNodeValue(DOMNode *node, bool text = false); string getTextFromElement(DOMElement *element, bool text = false); -void Metagame::MetagameImpl::getMetagame(SpeciesDatabase *species, - DOMElement *node) { +void Metagame::MetagameImpl::getMetagame(DOMElement *node) { XMLCh tempStr[20]; + XMLString::transcode("id", tempStr, 19); + DOMNode *p = node->getAttributes()->getNamedItem(tempStr); + if (p) { + m_id = getStringNodeValue(p); + } + XMLString::transcode("name", tempStr, 19); DOMNodeList *list = node->getElementsByTagName(tempStr); if (list->getLength() != 0) { m_name = getTextFromElement((DOMElement *)list->item(0)); } - XMLString::transcode("id", tempStr, 19); - list = node->getElementsByTagName(tempStr); - if (list->getLength() != 0) { - m_id = getTextFromElement((DOMElement *)list->item(0)); - } - XMLString::transcode("description", tempStr, 19); list = node->getElementsByTagName(tempStr); if (list->getLength() != 0) { @@ -108,12 +166,7 @@ void Metagame::MetagameImpl::getMetagame(SpeciesDatabase *species, for (int i = 0; i < length; ++i) { DOMElement *pokemon = (DOMElement *)list->item(i); string txt = getTextFromElement(pokemon); - const PokemonSpecies *p = species->getSpecies(txt); - if (!p) { - Log::out() << "Unknown species: " << txt << endl; - } else { - m_banList.insert(p->getSpeciesId()); - } + m_banListProto.insert(txt); } } @@ -161,8 +214,39 @@ void Metagame::MetagameImpl::getMetagame(SpeciesDatabase *species, m_timerOptions.periods = periods; m_timerOptions.periodLength = periodLength; } +} + +void Generation::GenerationImpl::getGeneration(DOMElement *node) { + XMLCh tempStr[20]; + + XMLString::transcode("id", tempStr, 19); + DOMNode *p = node->getAttributes()->getNamedItem(tempStr); + if (p) { + m_id = getStringNodeValue(p); + } - m_generation = GEN_PLATINUM; // TODO + XMLString::transcode("name", tempStr, 19); + DOMNodeList *list = node->getElementsByTagName(tempStr); + if (list->getLength() != 0) { + m_name = getTextFromElement((DOMElement *)list->item(0)); + } + + XMLString::transcode("metagames", tempStr, 19); + list = node->getElementsByTagName(tempStr); + if (list->getLength() != 0) { + DOMElement *metagames = (DOMElement *)list->item(0); + XMLString::transcode("metagame", tempStr, 19); + list = metagames->getElementsByTagName(tempStr); + const int length = list->getLength(); + for (int i = 0; i < length; ++i) { + DOMElement *item = (DOMElement *)list->item(i); + MetagamePtr metagame(new Metagame()); + metagame.get()->m_impl->getMetagame(item); + metagame.get()->m_impl->m_idx = i; + metagame.get()->m_impl->m_generation = m_owner; + m_metagames.push_back(metagame); + } + } } string Metagame::getName() const { @@ -181,7 +265,7 @@ string Metagame::getDescription() const { return m_impl->m_description; } -int Metagame::getGeneration() const { +Generation *Metagame::getGeneration() const { return m_impl->m_generation; } @@ -205,7 +289,17 @@ const network::TimerOptions &Metagame::getTimerOptions() const { return m_impl->m_timerOptions; } -class MetagameErrorHandler : public HandlerBase { +void Metagame::initialise(SpeciesDatabase *species) { + m_impl->initialise(species); +} + +Metagame::Metagame(): + m_impl(boost::shared_ptr(new MetagameImpl())) { } + +Generation::Generation(): + m_impl(boost::shared_ptr(new GenerationImpl())) { } + +class GenerationErrorHandler : public HandlerBase { void error(const SAXParseException& e) { fatalError(e); } @@ -219,15 +313,12 @@ class MetagameErrorHandler : public HandlerBase { } }; -Metagame::Metagame(): - m_impl(boost::shared_ptr(new MetagameImpl())) { } - -void Metagame::readMetagames(const string &file, SpeciesDatabase *species, - vector &metagames) { +void Generation::readGenerations(const string &file, + vector &generations) { XMLPlatformUtils::Initialize(); XercesDOMParser parser; - MetagameErrorHandler handler; + GenerationErrorHandler handler; parser.setErrorHandler(&handler); parser.setEntityResolver(&handler); @@ -237,18 +328,47 @@ void Metagame::readMetagames(const string &file, SpeciesDatabase *species, DOMElement *root = doc->getDocumentElement(); XMLCh tempStr[12]; - XMLString::transcode("metagame", tempStr, 11); + XMLString::transcode("generation", tempStr, 11); DOMNodeList *list = root->getElementsByTagName(tempStr); int length = list->getLength(); for (int i = 0; i < length; ++i) { DOMElement *item = (DOMElement *)list->item(i); - MetagamePtr metagame(new Metagame()); - metagame.get()->m_impl->getMetagame(species, item); - metagame.get()->m_impl->m_idx = i; - metagames.push_back(metagame); + GenerationPtr generation(new Generation()); + generation->m_impl->m_owner = generation.get(); + generation->m_impl->getGeneration(item); + generation->m_impl->m_idx = i; + generations.push_back(generation); } } +string Generation::getId() const { + return m_impl->m_id; +} + +string Generation::getName() const { + return m_impl->m_name; +} + +int Generation::getIdx() const { + return m_impl->m_idx; +} + +const vector &Generation::getMetagames() const { + return m_impl->m_metagames; +} + +void Generation::getMetagameClauses(const int meta, vector &clauses) { + m_impl->getMetagameClauses(meta, clauses); +} + +void Generation::getMetagameBans(const int metagame, set &bans) { + m_impl->getMetagameBans(metagame, bans); +} + +void Generation::initialiseMetagames(SpeciesDatabase *species) { + m_impl->initialiseMetagames(species); +} + } diff --git a/src/matchmaking/MetagameList.h b/src/matchmaking/MetagameList.h index b9dc13a..abb09c8 100644 --- a/src/matchmaking/MetagameList.h +++ b/src/matchmaking/MetagameList.h @@ -33,32 +33,55 @@ namespace shoddybattle { +class Generation; class Metagame; typedef boost::shared_ptr MetagamePtr; +typedef boost::shared_ptr GenerationPtr; class SpeciesDatabase; class Metagame { public: - static void readMetagames(const std::string &, SpeciesDatabase *, - std::vector &); - Metagame(); std::string getName() const; std::string getId() const; int getIdx() const; std::string getDescription() const; - int getGeneration() const; + Generation *getGeneration() const; int getActivePartySize() const; int getMaxTeamLength() const; const std::set &getBanList() const; const std::vector &getClauses() const; const network::TimerOptions &getTimerOptions() const; + void initialise(SpeciesDatabase *); + private: class MetagameImpl; boost::shared_ptr m_impl; + friend class Generation; +}; + +class Generation { +public: + static void readGenerations(const std::string &, + std::vector &); + + Generation(); + + std::string getId() const; + std::string getName() const; + int getIdx() const; + const std::vector &getMetagames() const; + void getMetagameClauses(const int idx, std::vector &clauses); + void getMetagameBans(const int idx, std::set &bans); + + void initialiseMetagames(SpeciesDatabase *); + +private: + class GenerationImpl; + boost::shared_ptr m_impl; }; } // namespace shoddybattle diff --git a/src/network/NetworkBattle.cpp b/src/network/NetworkBattle.cpp index 2564eb4..ed5c3ac 100644 --- a/src/network/NetworkBattle.cpp +++ b/src/network/NetworkBattle.cpp @@ -668,6 +668,7 @@ struct NetworkBattleImpl { * int32 : field id * string : opponent * byte : party + * byte : generation * int16 : metagame (-1 for a direct challenge) * byte : rated * string : unique battle ID @@ -678,6 +679,7 @@ struct NetworkBattleImpl { OutMessage msg(OutMessage::BATTLE_BEGIN); msg << id << opponent << ((unsigned char)party); + msg << (unsigned char)m_field->getGeneration()->getIdx(); msg << (int16_t)m_metagame; msg << (unsigned char)m_rated; msg << m_log->getId(); @@ -993,7 +995,7 @@ void NetworkBattle::terminate() { NetworkBattle::NetworkBattle(Server *server, ClientPtr *clients, Pokemon::ARRAY *teams, - const GENERATION generation, + Generation *generation, const int partySize, const int maxTeamLength, vector &clauses, @@ -1027,7 +1029,7 @@ NetworkBattle::NetworkBattle(Server *server, // Encode some metadata into the channel topic. const string topic = m_impl->m_trainer[0] + "," + m_impl->m_trainer[1] + "," - + boost::lexical_cast(generation) + "," + + boost::lexical_cast(generation->getIdx()) + "," + boost::lexical_cast(partySize) + "," + boost::lexical_cast(maxTeamLength) + "," + boost::lexical_cast(metagame) + "," @@ -1181,8 +1183,9 @@ void NetworkBattle::informVictory(const int party) { m_impl->broadcast(msg.getMsg()); if (m_impl->m_rated) { - m_impl->m_server->postLadderMatch(m_impl->m_metagame, - m_impl->m_clients, party); + MetagamePtr meta = getGeneration()->getMetagames()[m_impl->m_metagame]; + string ladder = meta->getId(); + m_impl->m_server->postLadderMatch(ladder, m_impl->m_clients, party); } // terminate this battle diff --git a/src/network/NetworkBattle.h b/src/network/NetworkBattle.h index c362039..e049882 100644 --- a/src/network/NetworkBattle.h +++ b/src/network/NetworkBattle.h @@ -53,7 +53,7 @@ class NetworkBattle : public BattleField, NetworkBattle(Server *server, boost::shared_ptr *clients, Pokemon::ARRAY *teams, - const GENERATION generation, + Generation *generation, const int partySize, const int maxTeamLength, std::vector &clauses, diff --git a/src/network/network.cpp b/src/network/network.cpp index ad683fe..dfd64fb 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -435,7 +435,7 @@ void readTeam(SpeciesDatabase *speciesData, struct Challenge { mutex mx; Pokemon::ARRAY teams[TEAM_COUNT]; - GENERATION generation; + int generation; int partySize; int teamLength; int metagame; @@ -601,18 +601,21 @@ class MetagameQueue { typedef pair QUEUE_ENTRY; typedef variate_generator > GENERATOR; - MetagameQueue(MetagamePtr metagame, bool rated, ServerImpl *server): + MetagameQueue(int generation, int metagame, bool rated, ServerImpl *server): + m_generation(generation), m_metagame(metagame), m_rated(rated), m_server(server), m_rand(mt11213b(time(NULL))) { } - + + MetagamePtr getMetagame(); bool queueClient(ClientImplPtr, Pokemon::ARRAY &); void removeClient(ClientImplPtr); void startMatches(); private: - MetagamePtr m_metagame; + int m_generation; + int m_metagame; bool m_rated; CLIENT_LIST m_clients; vector m_queue; @@ -623,7 +626,8 @@ class MetagameQueue { }; typedef shared_ptr MetagameQueuePtr; -typedef pair METAGAME_PAIR; +typedef pair METAGAME; +typedef pair METAGAME_PAIR; typedef pair CLAUSE_PAIR; class ServerImpl { @@ -635,10 +639,15 @@ class ServerImpl { void stop(); void removeClient(ClientImplPtr client); void broadcast(const OutMessage &msg); + + void readMetagames(const string &); + void initialiseMetagames(); + void initialiseWelcomeMessage(const std::string &, const std::string &); void initialiseChannels(); - void initialiseMatchmaking(const string &); + void initialiseMatchmaking(); void initialiseClauses(); + bool validateTeam(ScriptContextPtr, Pokemon::ARRAY &, vector &, vector &, const set &); database::DatabaseRegistry *getRegistry() { return &m_registry; } @@ -646,24 +655,27 @@ class ServerImpl { ChannelPtr getMainChannel() const { return m_mainChannel; } void sendChannelList(ClientImplPtr client); void sendMetagameList(ClientImplPtr client); - void getMetagameClauses(const int metagame, vector &clauses); - const vector &getMetagames() const { return m_metagames; } + const vector &getGenerations() const { + return m_generations; + } void sendClauseList(ClientImplPtr client); - void fetchClauses(ScriptContextPtr scx, vector &clauses, - vector &ret); - void fetchClauses(ScriptContextPtr scx, const int metagame, - vector &ret); - void getMetagameBans(const int metagame, set &bans); + void fetchClauses(ScriptContextPtr scx, vector &clauses, + vector &ret); + void fetchClauses(ScriptContextPtr scx, MetagamePtr metagame, + vector &ret); + void fetchClauses(ScriptContextPtr scx, const int metagame, + const int generation, vector &ret); ChannelPtr getChannel(const string &); ClientImplPtr getClient(const string &); bool authenticateClient(ClientImplPtr client); void addChannel(ChannelPtr); void removeChannel(ChannelPtr); - MetagameQueuePtr getMetagameQueue(const int metagame, const bool rated) { - return m_queues[METAGAME_PAIR(metagame, rated)]; + MetagameQueuePtr getMetagameQueue(const int generation, const int metagame, + const bool rated) { + return m_queues[METAGAME_PAIR(METAGAME(generation, metagame), rated)]; } - void postLadderMatch(const int, vector &, const int); + void postLadderMatch(const string &, vector &, const int); bool commitBan(const int, const string &, const int, const int, const bool = false); void commitPersonalMessage(const string& user, const string& msg); @@ -685,7 +697,7 @@ class ServerImpl { class MetagameList : public OutMessage { public: - MetagameList(const vector &); + MetagameList(const vector &); }; class ClauseList : public OutMessage { @@ -704,7 +716,7 @@ class ServerImpl { tcp::acceptor m_acceptor; database::DatabaseRegistry m_registry; ScriptMachine m_machine; - vector m_metagames; + vector m_generations; map m_queues; thread m_matchmaking; thread m_phantomClientWorker; @@ -739,6 +751,14 @@ ScriptMachine *Server::getMachine() { return m_impl->getMachine(); } +void Server::readMetagames(const string &file) { + m_impl->readMetagames(file); +} + +void Server::initialiseMetagames() { + m_impl->initialiseMetagames(); +} + void Server::initialiseWelcomeMessage(const string &name, const string &welcome) { m_impl->initialiseWelcomeMessage(name, welcome); @@ -748,8 +768,8 @@ void Server::initialiseChannels() { m_impl->initialiseChannels(); } -void Server::initialiseMatchmaking(const string &file) { - m_impl->initialiseMatchmaking(file); +void Server::initialiseMatchmaking() { + m_impl->initialiseMatchmaking(); } void Server::initialiseClauses() { @@ -1141,17 +1161,25 @@ class ClientImpl : public Client, public enable_shared_from_this { int teamLength; msg >> opponent >> generation >> partySize >> teamLength; int metagame; - msg >> metagame; + msg >> metagame; // Check for bad challenge info - const vector &metagames = m_server->getMetagames(); - const int metagameCount = metagames.size(); - if ((partySize < 1) || (teamLength < 1) || (metagame < -1) || - (metagame >= metagameCount)) { + const vector &generations = m_server->getGenerations(); + const int generationCount = generations.size(); + if ((generation >= generationCount) || (partySize < 1) || + (teamLength < 1)) { sendMessage(ErrorMessage(ErrorMessage::BAD_CHALLENGE, opponent)); return; } + GenerationPtr gen = generations[generation]; + const vector &metagames = gen->getMetagames(); + const int metagameCount = metagames.size(); + if ((metagame < -1) || (metagame >= metagameCount)) { + sendMessage(ErrorMessage(ErrorMessage::BAD_CHALLENGE, opponent)); + return; + } + if (metagame == -1) { unsigned char clauseCount; msg >> clauseCount; @@ -1180,11 +1208,11 @@ class ClientImpl : public Client, public enable_shared_from_this { } } - challenge->generation = (GENERATION)generation; + challenge->generation = generation; challenge->partySize = partySize; challenge->teamLength = teamLength; challenge->metagame = metagame; - + lock_guard lock(m_challengeMutex); @@ -1239,15 +1267,17 @@ class ClientImpl : public Client, public enable_shared_from_this { // created - ScriptContextLock is necessary!! ScriptContextLock cxLock(cx); vector clauses; + int generation = challenge->generation; int metagame = challenge->metagame; if (metagame == -1) { m_server->fetchClauses(cx, challenge->clauses, clauses); } else { - m_server->fetchClauses(cx, metagame, clauses); + m_server->fetchClauses(cx, generation, metagame, clauses); } set bans; - m_server->getMetagameBans(metagame, bans); + GenerationPtr gen = m_server->getGenerations()[generation]; + gen->getMetagameBans(metagame, bans); vector violations; if (!m_server->validateTeam(cx, team, clauses, violations, bans)) { @@ -1273,13 +1303,16 @@ class ClientImpl : public Client, public enable_shared_from_this { if (!client) { return; } + ChallengePtr challenge = m_challenges[opponent]; - unique_lock lock2(challenge->mx); if (challenge->teams[1].empty()) { return; } - + + const vector &generations = m_server->getGenerations(); + GenerationPtr generation = generations[challenge->generation]; + ScriptMachine *machine = m_server->getMachine(); readTeam(machine->getSpeciesDatabase(), machine->getMoveDatabase(), @@ -1296,15 +1329,16 @@ class ClientImpl : public Client, public enable_shared_from_this { // created - ScriptContextLock is necessary!! ScriptContextLock cxLock(cx); vector clauses; + int generationId = challenge->generation; int metagame = challenge->metagame; if (metagame == -1) { m_server->fetchClauses(cx, challenge->clauses, clauses); } else { - m_server->fetchClauses(cx, metagame, clauses); + m_server->fetchClauses(cx, generationId, metagame, clauses); } set bans; - m_server->getMetagameBans(metagame, bans); + generation->getMetagameBans(metagame, bans); vector violations; if (!m_server->validateTeam(cx, challenge->teams[0], clauses, @@ -1316,7 +1350,7 @@ class ClientImpl : public Client, public enable_shared_from_this { TimerOptions timerOpts = TimerOptions(); bool validMetagame = false; if (metagame >= 0) { - const vector &metagames = m_server->getMetagames(); + const vector &metagames = generation->getMetagames(); const int size = metagames.size(); if (metagame >= size) { validMetagame = false; @@ -1337,7 +1371,7 @@ class ClientImpl : public Client, public enable_shared_from_this { NetworkBattle::PTR field(new NetworkBattle(m_server->getServer(), clients, challenge->teams, - challenge->generation, + generation.get(), challenge->partySize, challenge->teamLength, clauses, @@ -1414,15 +1448,18 @@ class ClientImpl : public Client, public enable_shared_from_this { } /** + * byte : generation id * byte : metagame id * byte : rated * team : the pokemon team to queue */ void handleQueueTeam(InMessage &msg) { + unsigned char generation; unsigned char metagame; unsigned char rated; - msg >> metagame >> rated; - MetagameQueuePtr queue = m_server->getMetagameQueue(metagame, rated); + msg >> generation >> metagame >> rated; + MetagameQueuePtr queue = m_server->getMetagameQueue(generation, + metagame, rated); if (!queue) { return; } @@ -1450,9 +1487,9 @@ class ClientImpl : public Client, public enable_shared_from_this { ClientImplPtr client = m_server->getClient(user); if (client) { const int id = client->getId(); - const vector &metagames = m_server->getMetagames(); + const vector &gens = m_server->getGenerations(); database::DatabaseRegistry::ESTIMATE_LIST estimates = - m_server->getRegistry()->getEstimates(id, metagames); + m_server->getRegistry()->getEstimates(id, gens); sendMessage(UserPersonalMessage(user, client->getPersonalMessage(), estimates)); } @@ -1463,10 +1500,12 @@ class ClientImpl : public Client, public enable_shared_from_this { } void handleCancelQueue(InMessage &msg) { + unsigned char generation; unsigned char metagame; unsigned char rated; - msg >> metagame >> rated; - MetagameQueuePtr queue = m_server->getMetagameQueue(metagame, rated); + msg >> generation >> metagame >> rated; + MetagameQueuePtr queue = m_server->getMetagameQueue(generation, + metagame, rated); if (!queue) { return; } @@ -1854,24 +1893,31 @@ bool ServerImpl::commitBan(const int channel, const string &user, return m_registry.setBan(channel, user, bannerId, date, ipBan); } -void ServerImpl::postLadderMatch(const int metagame, +void ServerImpl::postLadderMatch(const string &ladder, vector &clients, const int victor) { ClientImpl *impl0 = dynamic_cast(clients[0].get()); ClientImpl *impl1 = dynamic_cast(clients[1].get()); if (!impl0 || !impl1) return; - const string ladder = m_metagames[metagame]->getId(); m_registry.postLadderMatch(ladder, impl0->getId(), impl1->getId(), victor); impl0->updateLadderStats(ladder); impl1->updateLadderStats(ladder); } +MetagamePtr MetagameQueue::getMetagame() { + const vector &generations = m_server->getGenerations(); + GenerationPtr generation = generations[m_generation]; + return generation->getMetagames()[m_metagame]; +} + bool MetagameQueue::queueClient(ClientImplPtr client, Pokemon::ARRAY &team) { lock_guard lock(m_mutex); if (m_clients.find(client) != m_clients.end()) return false; + + MetagamePtr metagame = getMetagame(); const int size = team.size(); - if (size > m_metagame->getMaxTeamLength()) + if (size > metagame->getMaxTeamLength()) return false; ScriptContextPtr scx = m_server->getMachine()->acquireContext(); @@ -1879,15 +1925,15 @@ bool MetagameQueue::queueClient(ClientImplPtr client, Pokemon::ARRAY &team) { // created - ScriptContextLock is necessary!! ScriptContextLock cxLock(scx); vector clauses; - m_server->fetchClauses(scx, m_metagame->getIdx(), clauses); + m_server->fetchClauses(scx, metagame, clauses); vector violations; if (!m_server->validateTeam(scx, team, clauses, violations, - m_metagame->getBanList())) { + metagame->getBanList())) { client->sendMessage(InvalidTeamMessage(string(), size, violations)); return false; } if (m_rated) { - client->joinLadder(m_metagame->getId()); + client->joinLadder(metagame->getId()); } m_clients.insert(client); m_queue.push_back(QUEUE_ENTRY(client, team)); @@ -1916,7 +1962,9 @@ void MetagameQueue::startMatches() { GENERATOR generator(m_rand, uniform_int<>()); random_shuffle(m_queue.begin(), m_queue.end(), generator); } + // TODO: Use the generations map to prevent rematches. + MetagamePtr metagame = getMetagame(); QUEUE_ENTRY remainder; int size = m_queue.size(); const bool hasRemainder = size % 2; @@ -1930,18 +1978,19 @@ void MetagameQueue::startMatches() { ClientPtr clients[] = { q1.first, q2.first }; Pokemon::ARRAY teams[] = { q1.second, q2.second }; vector clauses; - m_server->fetchClauses(m_server->getMachine()->acquireContext(), - m_metagame->getIdx(), clauses); + m_server->fetchClauses(m_server->getMachine()->acquireContext(), + metagame, clauses); shared_ptr monitor; - NetworkBattle::PTR field(new NetworkBattle(m_server->getServer(), + NetworkBattle::PTR field(new NetworkBattle( + m_server->getServer(), clients, teams, - (GENERATION)m_metagame->getGeneration(), - m_metagame->getActivePartySize(), - m_metagame->getMaxTeamLength(), + metagame->getGeneration(), + metagame->getActivePartySize(), + metagame->getMaxTeamLength(), clauses, - m_metagame->getTimerOptions(), - m_metagame->getIdx(), + metagame->getTimerOptions(), + metagame->getIdx(), m_rated, monitor)); field->beginBattle(); @@ -1965,18 +2014,6 @@ void ServerImpl::sendMetagameList(ClientImplPtr client) { client->sendMessage(*m_metagameList); } -void ServerImpl::getMetagameClauses(const int idx, vector &ret) { - const int metagamesize = m_metagames.size(); - if ((idx < 0) || (idx > metagamesize)) - return; - MetagamePtr p = m_metagames[idx]; - const vector &clauses = p->getClauses(); - const int size = clauses.size(); - for (int i = 0; i < size; ++i) { - ret.push_back(clauses[i]); - } -} - void ServerImpl::sendClauseList(ClientImplPtr client) { client->sendMessage(ClauseList(m_clauses)); } @@ -1994,27 +2031,20 @@ void ServerImpl::fetchClauses(ScriptContextPtr scx, vector &clauses, } } -void ServerImpl::fetchClauses(ScriptContextPtr scx, const int metagame, - vector &ret) { - vector clauses; - getMetagameClauses(metagame, clauses); - vector::iterator i = clauses.begin(); +void ServerImpl::fetchClauses(ScriptContextPtr scx, MetagamePtr metagame, + vector &ret) { + const vector &clauses = metagame->getClauses(); + vector::const_iterator i = clauses.begin(); for (; i != clauses.end(); ++i) { ret.push_back(scx->getClause(*i)); } } -void ServerImpl::getMetagameBans(const int metagame, set &ret) { - const int metagameSize = m_metagames.size(); - if ((metagame < 0) || (metagame > metagameSize)) { - return; - } - MetagamePtr p = m_metagames[metagame]; - const set &bans = p->getBanList(); - set::const_iterator i = bans.begin(); - for (; i != bans.end(); ++i) { - ret.insert(*i); - } +void ServerImpl::fetchClauses(ScriptContextPtr scx, const int generation, + const int metagame, vector &ret) { + GenerationPtr gen = m_generations[generation]; + MetagamePtr meta = gen->getMetagames()[metagame]; + fetchClauses(scx, meta, ret); } void ServerImpl::addChannel(ChannelPtr p) { @@ -2035,9 +2065,9 @@ void Server::removeChannel(ChannelPtr p) { m_impl->removeChannel(p); } -void Server::postLadderMatch(const int metagame, - vector &clients, const int victor) { - m_impl->postLadderMatch(metagame, clients, victor); +void Server::postLadderMatch(const string &ladder, vector &clients, + const int victor) { + m_impl->postLadderMatch(ladder, clients, victor); } ServerImpl::ChannelList::ChannelList(ServerImpl *server): @@ -2055,38 +2085,47 @@ ServerImpl::ChannelList::ChannelList(ServerImpl *server): finalise(); } -ServerImpl::MetagameList::MetagameList(const vector &metagames): - OutMessage(METAGAME_LIST) { - const int size = metagames.size(); - *this << (int16_t)size; - for (int i = 0; i < size; ++i) { - MetagamePtr p = metagames[i]; - *this << (unsigned char)p->getIdx(); - *this << p->getName(); - *this << p->getId(); - *this << p->getDescription(); - *this << (unsigned char)p->getActivePartySize(); - *this << (unsigned char)p->getMaxTeamLength(); - const set &banList = p->getBanList(); - *this << (int16_t)banList.size(); - set::const_iterator j = banList.begin(); - for (; j != banList.end(); ++j) { - *this << (int16_t)(*j); - } - const vector &clauses = p->getClauses(); - const int size2 = clauses.size(); - *this << (int16_t)size2; - for (int k = 0; k < size2; ++k) { - *this << clauses[k]; - } - const TimerOptions ops = p->getTimerOptions(); - if (ops.enabled) { - *this << (unsigned char)1; - *this << (int16_t)ops.pool; - *this << (unsigned char)ops.periods; - *this << (int16_t)ops.periodLength; - } else { - *this << (unsigned char)0; +ServerImpl::MetagameList::MetagameList(const vector + &generations): OutMessage(METAGAME_LIST) { + *this << (unsigned char)generations.size(); + + vector::const_iterator i = generations.begin(); + for (; i != generations.end(); ++i) { + GenerationPtr generation = *i; + const vector &metagames = generation->getMetagames(); + *this << generation->getId(); + *this << generation->getName(); + *this << (unsigned char)metagames.size(); + + vector::const_iterator j = metagames.begin(); + for (; j != metagames.end(); ++j) { + MetagamePtr p = *j; + *this << p->getId(); + *this << p->getName(); + *this << p->getDescription(); + *this << (unsigned char)p->getActivePartySize(); + *this << (unsigned char)p->getMaxTeamLength(); + const set &banList = p->getBanList(); + *this << (int16_t)banList.size(); + set::const_iterator j = banList.begin(); + for (; j != banList.end(); ++j) { + *this << (int16_t)(*j); + } + const vector &clauses = p->getClauses(); + const int size2 = clauses.size(); + *this << (int16_t)size2; + for (int k = 0; k < size2; ++k) { + *this << clauses[k]; + } + const TimerOptions ops = p->getTimerOptions(); + if (ops.enabled) { + *this << (unsigned char)1; + *this << (int16_t)ops.pool; + *this << (unsigned char)ops.periods; + *this << (int16_t)ops.periodLength; + } else { + *this << (unsigned char)0; + } } } finalise(); @@ -2162,6 +2201,18 @@ ChannelPtr ServerImpl::getChannel(const string &name) { return ChannelPtr(); } +void ServerImpl::readMetagames(const string& file) { + Generation::readGenerations(file, m_generations); +} + +void ServerImpl::initialiseMetagames() { + SpeciesDatabase *species = m_machine.getSpeciesDatabase(); + vector::iterator i = m_generations.begin(); + for (; i != m_generations.end(); ++i) { + (*i)->initialiseMetagames(species); + } +} + void ServerImpl::initialiseWelcomeMessage(const string &name, const string &welcome) { shared_ptr auth = m_registry.getAuthenticator(); @@ -2198,21 +2249,28 @@ void ServerImpl::initialiseChannels() { assert(m_mainChannel); } -void ServerImpl::initialiseMatchmaking(const string &file) { - SpeciesDatabase *species = m_machine.getSpeciesDatabase(); - Metagame::readMetagames(file, species, m_metagames); - vector::const_iterator i = m_metagames.begin(); - for (; i != m_metagames.end(); ++i) { - m_registry.initialiseLadder((*i)->getId()); - const int idx = (*i)->getIdx(); - // rated queue - m_queues[METAGAME_PAIR(idx, true)] = - MetagameQueuePtr(new MetagameQueue(*i, true, this)); - // unrated queue - m_queues[METAGAME_PAIR(idx, false)] = - MetagameQueuePtr(new MetagameQueue(*i, false, this)); - } - m_metagameList = shared_ptr(new MetagameList(m_metagames)); +void ServerImpl::initialiseMatchmaking() { + vector::const_iterator i = m_generations.begin(); + for (; i != m_generations.end(); ++i) { + GenerationPtr generation = *i; + const vector &metagames = generation->getMetagames(); + vector::const_iterator j = metagames.begin(); + for (; j != metagames.end(); ++j) { + m_registry.initialiseLadder((*j)->getId()); + + int genIdx = generation->getIdx(); + int metaIdx = (*j)->getIdx(); + METAGAME meta(genIdx, metaIdx); + // rated queue + m_queues[METAGAME_PAIR(meta, true)] = MetagameQueuePtr( + new MetagameQueue(genIdx, metaIdx, true, this)); + // unrated queue + m_queues[METAGAME_PAIR(meta, false)] = MetagameQueuePtr( + new MetagameQueue(genIdx, metaIdx, false, this)); + } + } + + m_metagameList = shared_ptr(new MetagameList(m_generations)); m_matchmaking = thread(boost::bind(&ServerImpl::handleMatchmaking, this)); } @@ -2283,7 +2341,7 @@ bool ServerImpl::validateTeam(ScriptContextPtr scx, Pokemon::ARRAY &team, void ServerImpl::handleMatchmaking() { while (true) { this_thread::sleep(posix_time::seconds(15)); - map, MetagameQueuePtr>::iterator i = m_queues.begin(); + map::iterator i = m_queues.begin(); for (; i != m_queues.end(); ++i) { i->second->startMatches(); } @@ -2347,7 +2405,7 @@ void ServerImpl::stop() { */ void ServerImpl::removeClient(ClientImplPtr client) { // Remove the client from any metagame queues that the client may be in. - map, MetagameQueuePtr>::iterator i = m_queues.begin(); + map::iterator i = m_queues.begin(); for (; i != m_queues.end(); ++i) { i->second->removeClient(client); } diff --git a/src/network/network.h b/src/network/network.h index 6e7d656..3781096 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -74,14 +74,17 @@ class Server { void run(); database::DatabaseRegistry *getRegistry(); ScriptMachine *getMachine(); + void readMetagames(const std::string &); + void initialiseMetagames(); void initialiseWelcomeMessage(const std::string &, const std::string &); void initialiseChannels(); - void initialiseMatchmaking(const std::string &); + void initialiseMatchmaking(); void initialiseClauses(); boost::shared_ptr getMainChannel() const; void addChannel(boost::shared_ptr); void removeChannel(boost::shared_ptr); - void postLadderMatch(const int, std::vector &, const int); + void postLadderMatch(const std::string &, std::vector &, + const int); bool commitBan(const int, const std::string &, const int, const int); private: diff --git a/src/scripting/FieldObject.cpp b/src/scripting/FieldObject.cpp index 95ff8fa..f3577e6 100644 --- a/src/scripting/FieldObject.cpp +++ b/src/scripting/FieldObject.cpp @@ -54,6 +54,7 @@ JSClass fieldClass = { enum FIELD_TINYID { FTI_GENERATION, + FTI_GENERATION_ID, FTI_LAST_MOVE, FTI_PARTY_SIZE, FTI_NARRATION, @@ -580,7 +581,14 @@ JSBool fieldGet(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { int tid = JSVAL_TO_INT(id); switch (tid) { case FTI_GENERATION: { - *vp = INT_TO_JSVAL(p->getGeneration()); + *vp = INT_TO_JSVAL(0); + // TODO: Return the actual object itself + } break; + case FTI_GENERATION_ID: { + string id = p->getGeneration()->getId(); + char *pstr = JS_strdup(cx, id.c_str()); + JSString *str = JS_NewString(cx, pstr, id.length()); + *vp = STRING_TO_JSVAL(str); } break; case FTI_LAST_MOVE: { MoveObjectPtr move = p->getLastMove(); @@ -622,6 +630,7 @@ JSBool fieldGet(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { JSPropertySpec fieldProperties[] = { { "damage", 0, JSPROP_PERMANENT, NULL, NULL }, { "generation", FTI_GENERATION, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL }, + { "generationId", FTI_GENERATION_ID, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL }, { "lastMove", FTI_LAST_MOVE, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL }, { "partySize", FTI_PARTY_SIZE, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, NULL }, { "narration", FTI_NARRATION, JSPROP_PERMANENT | JSPROP_SHARED, fieldGet, fieldSet }, diff --git a/src/shoddybattle/BattleField.cpp b/src/shoddybattle/BattleField.cpp index d095db8..a21543a 100644 --- a/src/shoddybattle/BattleField.cpp +++ b/src/shoddybattle/BattleField.cpp @@ -41,7 +41,7 @@ namespace shoddybattle { struct BattleFieldImpl { FieldObjectPtr object; const BattleMechanics *mech; - GENERATION generation; + Generation *generation; ScriptMachine *machine; ScriptContext *context; ScriptContextPtr contextRef; @@ -105,7 +105,7 @@ struct BattleFieldImpl { void initialise(BattleField *field, const BattleMechanics *mech, - GENERATION generation, + Generation *generation, ScriptMachine *machine, Pokemon::ARRAY teams[TEAM_COUNT], const std::string trainer[TEAM_COUNT], @@ -163,7 +163,7 @@ void BattleField::popExecution() { m_impl->executing.pop(); } -GENERATION BattleField::getGeneration() const { +Generation *BattleField::getGeneration() const { return m_impl->generation; } @@ -1358,7 +1358,7 @@ ScriptContext *BattleField::getContext() { } void BattleField::initialise(const BattleMechanics *mech, - GENERATION generation, + Generation *generation, ScriptMachine *machine, Pokemon::ARRAY teams[TEAM_COUNT], const std::string trainer[TEAM_COUNT], @@ -1375,7 +1375,7 @@ void BattleField::initialise(const BattleMechanics *mech, void BattleFieldImpl::initialise(BattleField *field, const BattleMechanics *mech, - GENERATION generation, + Generation *generation, ScriptMachine *machine, Pokemon::ARRAY teams[TEAM_COUNT], const std::string trainer[TEAM_COUNT], diff --git a/src/shoddybattle/BattleField.h b/src/shoddybattle/BattleField.h index cc879bb..acd1ca3 100644 --- a/src/shoddybattle/BattleField.h +++ b/src/shoddybattle/BattleField.h @@ -30,17 +30,13 @@ #include #include #include "Pokemon.h" +#include "../matchmaking/MetagameList.h" #include "../scripting/ObjectWrapper.h" namespace shoddybattle { const int TEAM_COUNT = 2; -enum GENERATION { - GEN_DP, // Diamond and Pearl - GEN_PLATINUM, // Platinum -}; - class BattleFieldImpl; class PokemonSlotImpl; @@ -147,7 +143,7 @@ class BattleField : public ObjectWrapper { * no equilvalent mode in the real game. */ void initialise(const BattleMechanics *mech, - const GENERATION, + Generation *, ScriptMachine *machine, Pokemon::ARRAY teams[TEAM_COUNT], const std::string trainer[TEAM_COUNT], @@ -365,7 +361,7 @@ class BattleField : public ObjectWrapper { ScriptObject *getObject(); - GENERATION getGeneration() const; + Generation *getGeneration() const; /** * Begin the battle.