Go Back   EQEmulator Home > EQEmulator Forums > Support > Spell Support

Spell Support Broken Spells? Want them Fixed? Request it here.

Reply
 
Thread Tools Display Modes
  #1  
Old 01-25-2014, 11:44 PM
Taurinus2
Sarnak
 
Join Date: Nov 2009
Posts: 45
Default SpellGap : Native Utility to find unused spell ids

Greetings.

This is something I whipped up real quick in C++ to find unused spell ids in spells_us.txt.

It produces a list of the ids, as well as an sql file to verify the results with. The only requirements are "spells_us.txt" and a recent-ish compiler (C++ 11 compliance required). Just drop the executable once built into the same folder as your spell file and execute.

Code:
/*
main.cpp
implements entry point and all program logic.

SpellGap
Finds and records unused spell ids in spells_us.txt

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>

*/

#if defined(_MSC_VER)
#pragma warning (disable : 996)
#endif
/*This header is a non standard header that can be found at:
http://codereview.stackexchange.com/questions/13176/infix-iterator-code
*/
#include "infix_iterator.h"


#include <iostream>
using std::cout;
using std::endl;

#include <string>
using std::string;

#include <fstream>
using std::ifstream;
using std::ofstream;

#include <cstdlib>

#include <vector>
using std::vector;

#include <algorithm>
using std::for_each;
using std::copy;
#include <iterator>

/*
assumes:  the last valid id is the upper bound for ids
requires: spells_us.txt
*/

int main()
{
    string spellFile = "spells_us.txt";
    string spell_id_str;

    cout << "Recording valid spell ids...\n";

    ifstream infile(spellFile.c_str());

    if (infile.is_open())
    {
        vector<int> spell_ids;

        while (std::getline(infile, spell_id_str, '^').good())
        {
            int spell_id = atoi(spell_id_str.c_str());
            spell_ids.push_back(spell_id);
            // not interested in the other fields, discard them
            string junk;
            std::getline(infile, junk);
        }

        infile.close();
        cout << "Done!\n";

        cout << "Finding unused ids...\n";
        int previd = 0;

        vector<int> unused_ids;
        // iterate over the valid id range, while pushing missing ids into 'unused_ids'
        for_each(spell_ids.begin(), spell_ids.end(),
                 [&previd, &unused_ids](int& id)
        {
            // detect the gap and record it
            if (id > previd + 1)
            {
                for (int i = previd + 1; i < id; i++)
                {
                    unused_ids.push_back(i);
                }
            }

            previd = id;
        });
        spell_ids.clear();
        spell_ids.shrink_to_fit();

        // write unused ids as a list to 'unused_spell_ids.txt'
        cout << "Found " << unused_ids.size() << " unused ids.  Writing them to file...\n";
        ofstream outfile("unused_spell_ids.txt");
        copy(unused_ids.begin(), unused_ids.end(), std::ostream_iterator<int>(outfile, "\n"));
        cout << "Done!\n";
        outfile.close();

        cout << "Writing 'unused_ids_verify.sql' for verification...\n";
        /* write a quick query to file to verify that we are not snagging valid ids*/
        ofstream sqlfile("unused_ids_verify.sql");

        sqlfile << "SELECT name FROM spells_new WHERE id=";
        copy(unused_ids.begin(), unused_ids.end(), infix_ostream_iterator<int>(sqlfile, " OR id="));

        sqlfile << ";\n";
        sqlfile.close();
        cout << "Done!\n";
        cout << "Use mysql: 'source unused_ids_verify.sql;' to verify this process.\n";
        cout << "Goodbye.\n";
    }

    else
    {
        cout << "spells_us.txt not found! Aborting...\n";
    }

    return 0;
}
It employs a non-standard header located here:

http://codereview.stackexchange.com/...-iterator-code

Enjoy!
Reply With Quote
  #2  
Old 01-26-2014, 02:20 AM
Kayen
Developer
 
Join Date: Mar 2009
Location: -
Posts: 228
Default

Good work.

Alternatively, SQL query to return gaps in spell file.

Code:
SELECT a.id+1 AS start, MIN(b.id) - 1 AS end
    FROM spells_new AS a, spells_new AS b
    WHERE a.id < b.id
    GROUP BY a.id
    HAVING start < MIN(b.id);
Kayen
GM Storm Haven
Reply With Quote
  #3  
Old 01-26-2014, 02:31 AM
Dunge0nMastr
Hill Giant
 
Join Date: Oct 2002
Location: Rockville, MD
Posts: 124
Default

Thanks for both! Will save us a ton of time lol.
__________________
Bront -Server Admin/Owner and Lead Quest Dev for Kildrukaun's Prophecy
http://kpemu.com/
Reply With Quote
  #4  
Old 01-26-2014, 09:36 AM
Tabasco's Avatar
Tabasco
Discordant
 
Join Date: Sep 2009
Posts: 269
Default

You can also look for name like '%test%' or name like '%placeholder%'
__________________
http://dungeoncrawl.us.to
Reply With Quote
  #5  
Old 01-30-2014, 01:36 PM
Taurinus2
Sarnak
 
Join Date: Nov 2009
Posts: 45
Default

I've updated the source for those interested to now offer a command line parameter to filter out 'test' and 'placeholder' spells.

Code:
/*
main.cpp
implements entry point and all program logic.

SpellGap
Finds and records unused spell ids in spells_us.txt

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>

*/

#if defined(_MSC_VER)
#pragma warning (disable : 996)
#endif
/*This header is a non standard header that can be found at:
http://codereview.stackexchange.com/questions/13176/infix-iterator-code
*/
#include "infix_iterator.h"

#include <iostream>
using std::cout;
using std::endl;

#include <string>
using std::string;

#include <fstream>
using std::ifstream;
using std::ofstream;

#include <cstdlib>

#include <vector>
using std::vector;

#include <algorithm>
using std::for_each;
using std::copy;
#include <iterator>

/*
assumes:  the last valid id is the upper bound for ids
requires: spells_us.txt
*/

int main(int argc, char*argv[])
{
    // filter out 'test' and 'placeholder' spells
    bool useFilter = (argc >= 2 && ((strcmp(argv[1], "-f") == 0) || (strcmp(argv[1], "-F") == 0))) ? true : false;

    string spellFile = "spells_us.txt";
    string spell_id_str;

    cout << "Recording valid spell ids...\n";

    ifstream infile(spellFile.c_str());

    if (infile.is_open())
    {
        vector<int> spell_ids;

        while (std::getline(infile, spell_id_str, '^').good())
        {
            string spell_name;
            std::getline(infile, spell_name, '^');


            if (useFilter)
            {
                std::transform(spell_name.begin(), spell_name.end(), spell_name.begin(), ::toupper);

                // conditional insert
                if (spell_name.find("TEST") == string::npos && spell_name.find("PLACEHOLDER") == string::npos)
                {
                    spell_ids.push_back(atoi(spell_id_str.c_str()));
                }
            }

            else
            {
                // unconditional insert
                spell_ids.push_back(atoi(spell_id_str.c_str()));
            }

            // not interested in the other fields, discard them
            string junk;
            std::getline(infile, junk);
            

        }

        infile.close();
        cout << "Done!\n";

        cout << "Finding unused ids...\n";
        int previd = 0;

        vector<int> unused_ids;
        // iterate over the valid id range, while pushing missing ids into 'unused_ids'
        for_each(spell_ids.begin(), spell_ids.end(),
                 [&previd, &unused_ids](int& id)
        {
            // detect the gap and record it

            if (id > previd + 1)
            {
                for (int i = previd + 1; i < id; i++)
                {
                    unused_ids.push_back(i);
                }
            }

            previd = id;
        });
        spell_ids.clear();
        spell_ids.shrink_to_fit();

        // write unused ids as a list to 'unused_spell_ids.txt'
        cout << "Found " << unused_ids.size() << " unused ids.  Writing them to file...\n";
        ofstream outfile("unused_spell_ids.txt");
        copy(unused_ids.begin(), unused_ids.end(), std::ostream_iterator<int>(outfile, "\n"));
        cout << "Done!\n";
        outfile.close();

        cout << "Writing 'unused_ids_verify.sql' for verification...\n";
        /* write a quick query to file to verify that we are not snagging valid ids*/
        ofstream sqlfile("unused_ids_verify.sql");

        sqlfile << "SELECT name FROM spells_new WHERE id=";
        copy(unused_ids.begin(), unused_ids.end(), infix_ostream_iterator<int>(sqlfile, " OR id="));

        sqlfile << ";\n";
        sqlfile.close();
        cout << "Done!\n";
        cout << "Use mysql: 'source unused_ids_verify.sql;' to verify this process.\n";
        cout << "Goodbye.\n";
    }

    else
    {
        cout << "spells_us.txt not found! Aborting...\n";
    }

    return 0;
}
Enjoy.
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 10:31 AM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3